From e7b4051634da2af7b01d1ca7ae2f15d127330b80 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Thu, 25 Jun 2026 22:07:07 +0200 Subject: [PATCH 01/17] feat(krea2): add Krea-2-Turbo model + LoRA support (WIP) Integrate Krea-2-Turbo (krea/Krea-2-Turbo) text-to-image per NEW_MODEL_INTEGRATION.md: Krea2Transformer2DModel (single-stream MMDiT) + Qwen3-VL text encoder (12-layer hidden-state tap, 4D prompt_embeds) + reused Qwen-Image VAE + FlowMatchEulerDiscrete scheduler. Backend: - taxonomy: BaseModelType.Krea2, ModelType/ModelFormat.Qwen3VLEncoder, Krea2VariantType (Turbo = "krea2_turbo" to avoid Z-Image collision) - config probes: Main_Diffusers/Checkpoint_Krea2, Qwen3VLEncoder, LoRA_LyCORIS_Krea2 (text_fusion/time_mod_proj signature; excluded from the Qwen-Image probe to avoid double-match) - loaders for the diffusers pipeline + standalone Qwen3-VL encoder, with runtime workarounds for the HF model's version mismatches (AutoTokenizer, extra_special_tokens={}, rope_parameters->rope_scaling) - native sampling (pack/unpack, position_ids, linear-mu shift) and hand-written Euler denoise loop; reuses qwen_image l2i/i2l - invocations: model_loader, text_encoder, denoise, lora_loader, plus two ecosystem enhancers (conditioning rebalance, seed variance) - LoRA conversion for diffusers PEFT (lora_transformer- prefix) Frontend: - 'krea-2' base + qwen3_vl_encoder type/format across model maps, buildKrea2Graph, addKrea2LoRAs, graph-builder denoise/base lists, optimal dimension 1024, regenerated schema.ts Fixes: - estimate transformer working memory in krea2_denoise so the cache reserves activation headroom and offloads more model under partial loading; fixes fp8 + LoRA OOM at 1024 (model was placed before LoRA patches were applied, leaving no room for their activations) WIP: requires diffusers main (>=0.39 dev) for Krea2Transformer2DModel; pyproject.toml temporarily pins diffusers to git main. --- invokeai/app/api/dependencies.py | 2 + invokeai/app/invocations/fields.py | 8 + .../krea2_conditioning_rebalance.py | 74 + invokeai/app/invocations/krea2_denoise.py | 400 ++++++ invokeai/app/invocations/krea2_lora_loader.py | 136 ++ .../app/invocations/krea2_model_loader.py | 111 ++ .../app/invocations/krea2_seed_variance.py | 69 + .../app/invocations/krea2_text_encoder.py | 120 ++ invokeai/app/invocations/metadata.py | 4 + invokeai/app/invocations/model.py | 8 + invokeai/app/invocations/primitives.py | 12 + .../model_records/model_records_base.py | 2 + invokeai/app/util/step_callback.py | 3 +- invokeai/backend/krea2/__init__.py | 0 invokeai/backend/krea2/sampling_utils.py | 97 ++ .../backend/model_manager/configs/factory.py | 26 +- .../backend/model_manager/configs/lora.py | 44 +- .../backend/model_manager/configs/main.py | 125 +- .../model_manager/configs/qwen3_vl_encoder.py | 65 + .../model_manager/load/model_loaders/krea2.py | 230 +++ .../model_manager/load/model_loaders/lora.py | 7 + .../backend/model_manager/starter_models.py | 12 + invokeai/backend/model_manager/taxonomy.py | 17 + .../lora_conversions/krea2_lora_constants.py | 8 + .../krea2_lora_conversion_utils.py | 124 ++ .../diffusion/conditioning_data.py | 23 + invokeai/frontend/web/public/locales/en.json | 46 + .../InformationalPopover/constants.ts | 6 + .../controlLayers/store/paramsSlice.ts | 33 + .../src/features/controlLayers/store/types.ts | 13 + .../web/src/features/modelManagerV2/models.ts | 12 + .../ModelManagerPanel/ModelFormatBadge.tsx | 2 + .../web/src/features/nodes/types/common.ts | 6 + .../util/graph/generation/addImageToImage.ts | 1 + .../nodes/util/graph/generation/addInpaint.ts | 1 + .../util/graph/generation/addKrea2LoRAs.ts | 68 + .../util/graph/generation/addOutpaint.ts | 1 + .../util/graph/generation/addTextToImage.ts | 1 + .../util/graph/generation/buildKrea2Graph.ts | 231 +++ .../nodes/util/graph/graphBuilderUtils.ts | 3 +- .../src/features/nodes/util/graph/types.ts | 2 + .../ParamKrea2EnhancersSettings.tsx | 38 + .../ParamKrea2RebalanceEnabled.tsx | 31 + .../ParamKrea2RebalanceMultiplier.tsx | 54 + .../ParamKrea2RebalanceWeights.tsx | 31 + .../ParamKrea2SeedVarianceEnabled.tsx | 31 + ...ParamKrea2SeedVarianceRandomizePercent.tsx | 57 + .../ParamKrea2SeedVarianceStrength.tsx | 57 + .../parameters/util/optimalDimension.ts | 2 + .../features/queue/hooks/useEnqueueCanvas.ts | 3 + .../queue/hooks/useEnqueueGenerate.ts | 3 + .../AdvancedSettingsAccordion.tsx | 69 +- .../GenerationSettingsAccordion.tsx | 4 + .../frontend/web/src/services/api/schema.ts | 1245 ++++++++++++++--- .../frontend/web/src/services/api/types.ts | 5 + pyproject.toml | 5 +- 56 files changed, 3535 insertions(+), 253 deletions(-) create mode 100644 invokeai/app/invocations/krea2_conditioning_rebalance.py create mode 100644 invokeai/app/invocations/krea2_denoise.py create mode 100644 invokeai/app/invocations/krea2_lora_loader.py create mode 100644 invokeai/app/invocations/krea2_model_loader.py create mode 100644 invokeai/app/invocations/krea2_seed_variance.py create mode 100644 invokeai/app/invocations/krea2_text_encoder.py create mode 100644 invokeai/backend/krea2/__init__.py create mode 100644 invokeai/backend/krea2/sampling_utils.py create mode 100644 invokeai/backend/model_manager/configs/qwen3_vl_encoder.py create mode 100644 invokeai/backend/model_manager/load/model_loaders/krea2.py create mode 100644 invokeai/backend/patches/lora_conversions/krea2_lora_constants.py create mode 100644 invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py create mode 100644 invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.ts create mode 100644 invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2EnhancersSettings.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceEnabled.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceMultiplier.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceEnabled.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceRandomizePercent.tsx create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceStrength.tsx diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index e7468c1bca4..4b1c37cf4a1 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -59,6 +59,7 @@ CogView4ConditioningInfo, ConditioningFieldData, FLUXConditioningInfo, + Krea2ConditioningInfo, QwenImageConditioningInfo, SD3ConditioningInfo, SDXLConditioningInfo, @@ -151,6 +152,7 @@ def initialize( CogView4ConditioningInfo, ZImageConditioningInfo, QwenImageConditioningInfo, + Krea2ConditioningInfo, AnimaConditioningInfo, ], ephemeral=True, diff --git a/invokeai/app/invocations/fields.py b/invokeai/app/invocations/fields.py index e53aeb417b2..1350ccb163d 100644 --- a/invokeai/app/invocations/fields.py +++ b/invokeai/app/invocations/fields.py @@ -155,6 +155,7 @@ class FieldDescriptions: t5_encoder = "T5 tokenizer and text encoder" glm_encoder = "GLM (THUDM) tokenizer and text encoder" qwen3_encoder = "Qwen3 tokenizer and text encoder" + qwen3_vl_encoder = "Qwen3-VL tokenizer and text encoder" clip_embed_model = "CLIP Embed loader" clip_g_model = "CLIP-G Embed loader" unet = "UNet (scheduler, LoRAs)" @@ -171,6 +172,7 @@ class FieldDescriptions: sd3_model = "SD3 model (MMDiTX) to load" cogview4_model = "CogView4 model (Transformer) to load" z_image_model = "Z-Image model (Transformer) to load" + krea2_model = "Krea-2 model (Transformer) to load" qwen_image_model = "Qwen Image Edit model (Transformer) to load" qwen_vl_encoder = "Qwen2.5-VL tokenizer, processor and text/vision encoder" sdxl_main_model = "SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load" @@ -349,6 +351,12 @@ class QwenImageConditioningField(BaseModel): conditioning_name: str = Field(description="The name of conditioning tensor") +class Krea2ConditioningField(BaseModel): + """A Krea-2 conditioning tensor primitive value""" + + conditioning_name: str = Field(description="The name of conditioning tensor") + + class AnimaConditioningField(BaseModel): """An Anima conditioning tensor primitive value. diff --git a/invokeai/app/invocations/krea2_conditioning_rebalance.py b/invokeai/app/invocations/krea2_conditioning_rebalance.py new file mode 100644 index 00000000000..c4aa7e78381 --- /dev/null +++ b/invokeai/app/invocations/krea2_conditioning_rebalance.py @@ -0,0 +1,74 @@ +import torch + +from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation +from invokeai.app.invocations.fields import FieldDescriptions, Input, InputField, Krea2ConditioningField +from invokeai.app.invocations.primitives import Krea2ConditioningOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.krea2.sampling_utils import KREA2_SELECT_LAYERS +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ( + ConditioningFieldData, + Krea2ConditioningInfo, +) + +_NUM_TEXT_LAYERS = len(KREA2_SELECT_LAYERS) # 12 + + +@invocation( + "krea2_conditioning_rebalance", + title="Conditioning Rebalance - Krea-2", + tags=["conditioning", "krea2", "krea-2"], + category="conditioning", + version="1.0.0", + classification=Classification.Prototype, +) +class Krea2ConditioningRebalanceInvocation(BaseInvocation): + """Per-layer rebalancing of Krea-2 text conditioning (improves prompt adherence). + + Krea-2 conditioning stacks 12 Qwen3-VL hidden-state layers per token. Weighting those layers + individually (and applying an overall multiplier) lets you push the model harder toward the prompt, + counteracting the quality-dilution from distillation. Ported from the ComfyUI + `ConditioningKrea2Rebalance` node. This is an optional pass between the text encoder and denoise. + """ + + conditioning: Krea2ConditioningField = InputField( + description=FieldDescriptions.cond, input=Input.Connection, title="Conditioning" + ) + per_layer_weights: str = InputField( + default="1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0", + description=f"Comma-separated gains for the {_NUM_TEXT_LAYERS} tapped encoder layers (exactly " + f"{_NUM_TEXT_LAYERS} values).", + ) + multiplier: float = InputField( + default=4.0, + description="Overall multiplier applied to the conditioning after per-layer weighting.", + ) + + def _parse_weights(self) -> list[float]: + try: + weights = [float(x.strip()) for x in self.per_layer_weights.split(",") if x.strip() != ""] + except ValueError as e: + raise ValueError(f"per_layer_weights must be comma-separated numbers: {e}") from e + if len(weights) != _NUM_TEXT_LAYERS: + raise ValueError(f"per_layer_weights must have exactly {_NUM_TEXT_LAYERS} values, got {len(weights)}.") + return weights + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> Krea2ConditioningOutput: + weights = self._parse_weights() + + cond_data = context.conditioning.load(self.conditioning.conditioning_name) + assert len(cond_data.conditionings) == 1 + conditioning = cond_data.conditionings[0] + assert isinstance(conditioning, Krea2ConditioningInfo) + + embeds = conditioning.prompt_embeds # (B, seq, 12, hidden) + gains = torch.tensor(weights, dtype=embeds.dtype, device=embeds.device).view(1, 1, _NUM_TEXT_LAYERS, 1) + embeds = embeds * gains * self.multiplier + + new_data = ConditioningFieldData( + conditionings=[ + Krea2ConditioningInfo(prompt_embeds=embeds, prompt_embeds_mask=conditioning.prompt_embeds_mask) + ] + ) + conditioning_name = context.conditioning.save(new_data) + return Krea2ConditioningOutput.build(conditioning_name) diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py new file mode 100644 index 00000000000..a5b0c5635e4 --- /dev/null +++ b/invokeai/app/invocations/krea2_denoise.py @@ -0,0 +1,400 @@ +import json +from contextlib import ExitStack +from pathlib import Path +from typing import Callable, Iterator, Optional, Tuple + +import torch +import torchvision.transforms as tv_transforms +from torchvision.transforms.functional import resize as tv_resize +from tqdm import tqdm + +from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation +from invokeai.app.invocations.constants import LATENT_SCALE_FACTOR +from invokeai.app.invocations.fields import ( + DenoiseMaskField, + FieldDescriptions, + Input, + InputField, + Krea2ConditioningField, + LatentsField, + WithBoard, + WithMetadata, +) +from invokeai.app.invocations.model import TransformerField +from invokeai.app.invocations.primitives import LatentsOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.krea2.sampling_utils import ( + KREA2_DISTILLED_MU, + build_sigmas, + calculate_shift, + pack_latents, + prepare_position_ids, + unpack_latents, +) +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat +from invokeai.backend.patches.layer_patcher import LayerPatcher +from invokeai.backend.patches.lora_conversions.krea2_lora_constants import KREA2_LORA_TRANSFORMER_PREFIX +from invokeai.backend.patches.model_patch_raw import ModelPatchRaw +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.diffusion.conditioning_data import Krea2ConditioningInfo +from invokeai.backend.util.devices import TorchDevice + +# Krea-2 latent channels (Qwen-Image VAE z_dim). The packed transformer in_channels is 16 * patch_size**2 = 64. +KREA2_LATENT_CHANNELS = 16 + + +@invocation( + "krea2_denoise", + title="Denoise - Krea-2", + tags=["image", "krea2", "krea-2"], + category="image", + version="1.0.0", + classification=Classification.Prototype, +) +class Krea2DenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): + """Run the denoising process with a Krea-2 model.""" + + # If latents is provided, this means we are doing image-to-image. + latents: Optional[LatentsField] = InputField( + default=None, description=FieldDescriptions.latents, input=Input.Connection + ) + # denoise_mask is used for image-to-image inpainting. Only the masked region is modified. + denoise_mask: Optional[DenoiseMaskField] = InputField( + default=None, description=FieldDescriptions.denoise_mask, input=Input.Connection + ) + denoising_start: float = InputField(default=0.0, ge=0, le=1, description=FieldDescriptions.denoising_start) + denoising_end: float = InputField(default=1.0, ge=0, le=1, description=FieldDescriptions.denoising_end) + transformer: TransformerField = InputField( + description=FieldDescriptions.krea2_model, input=Input.Connection, title="Transformer" + ) + positive_conditioning: Krea2ConditioningField = InputField( + description=FieldDescriptions.positive_cond, input=Input.Connection + ) + negative_conditioning: Optional[Krea2ConditioningField] = InputField( + default=None, description=FieldDescriptions.negative_cond, input=Input.Connection + ) + # CFG uses the standard formulation (uncond + cfg_scale*(cond-uncond)); cfg_scale <= 1 disables it. + # Krea-2-Turbo is distilled and runs with CFG disabled (cfg_scale=1.0). + cfg_scale: float | list[float] = InputField(default=1.0, description=FieldDescriptions.cfg_scale, title="CFG Scale") + width: int = InputField(default=1024, multiple_of=16, description="Width of the generated image.") + height: int = InputField(default=1024, multiple_of=16, description="Height of the generated image.") + steps: int = InputField(default=8, gt=0, description=FieldDescriptions.steps) + seed: int = InputField(default=0, description="Randomness seed for reproducibility.") + shift: Optional[float] = InputField( + default=None, + description="Override the resolution-aware timestep shift (mu). Leave unset to use the model default " + "(mu=1.15 for the distilled Turbo checkpoint).", + ) + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> LatentsOutput: + latents = self._run_diffusion(context) + latents = latents.detach().to("cpu") + name = context.tensors.save(tensor=latents) + return LatentsOutput.build(latents_name=name, latents=latents, seed=None) + + def _prep_inpaint_mask(self, context: InvocationContext, latents: torch.Tensor) -> torch.Tensor | None: + if self.denoise_mask is None: + return None + mask = context.tensors.load(self.denoise_mask.mask_name) + mask = 1.0 - mask + _, _, latent_height, latent_width = latents.shape + mask = tv_resize( + img=mask, + size=[latent_height, latent_width], + interpolation=tv_transforms.InterpolationMode.BILINEAR, + antialias=False, + ) + mask = mask.to(device=latents.device, dtype=latents.dtype) + return mask + + def _load_text_conditioning( + self, + context: InvocationContext, + conditioning_name: str, + dtype: torch.dtype, + device: torch.device, + ) -> tuple[torch.Tensor, torch.Tensor | None]: + cond_data = context.conditioning.load(conditioning_name) + assert len(cond_data.conditionings) == 1 + conditioning = cond_data.conditionings[0] + assert isinstance(conditioning, Krea2ConditioningInfo) + conditioning = conditioning.to(dtype=dtype, device=device) + return conditioning.prompt_embeds, conditioning.prompt_embeds_mask + + def _get_noise(self, height: int, width: int, dtype: torch.dtype, device: torch.device, seed: int) -> torch.Tensor: + rand_device = "cpu" + return torch.randn( + 1, + KREA2_LATENT_CHANNELS, + int(height) // LATENT_SCALE_FACTOR, + int(width) // LATENT_SCALE_FACTOR, + device=rand_device, + dtype=torch.float32, + generator=torch.Generator(device=rand_device).manual_seed(seed), + ).to(device=device, dtype=dtype) + + def _prepare_cfg_scale(self, num_timesteps: int) -> list[float]: + if isinstance(self.cfg_scale, float): + return [self.cfg_scale] * num_timesteps + if isinstance(self.cfg_scale, list): + assert len(self.cfg_scale) == num_timesteps + return self.cfg_scale + raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}") + + def _is_distilled(self, context: InvocationContext) -> bool: + """Read is_distilled from the model's model_index.json (pipeline-level flag).""" + try: + model_path = context.models.get_absolute_path(context.models.get_config(self.transformer.transformer)) + model_index = model_path / "model_index.json" + if model_index.is_file(): + with open(model_index) as f: + return bool(json.load(f).get("is_distilled", False)) + except Exception: + pass + # Only the distilled Turbo checkpoint is currently supported. + return True + + def _run_diffusion(self, context: InvocationContext): + from diffusers.schedulers.scheduling_flow_match_euler_discrete import FlowMatchEulerDiscreteScheduler + + inference_dtype = torch.bfloat16 + device = TorchDevice.choose_torch_device() + + transformer_info = context.models.load(self.transformer.transformer) + + pos_prompt_embeds, pos_prompt_mask = self._load_text_conditioning( + context, self.positive_conditioning.conditioning_name, inference_dtype, device + ) + + # CFG: standard formulation, enabled only when cfg_scale > 1 and negative conditioning is provided. + if isinstance(self.cfg_scale, list): + any_cfg_above_one = any(v > 1.0 for v in self.cfg_scale) + else: + any_cfg_above_one = self.cfg_scale > 1.0 + do_cfg = self.negative_conditioning is not None and any_cfg_above_one + neg_prompt_embeds = None + neg_prompt_mask = None + if do_cfg: + neg_prompt_embeds, neg_prompt_mask = self._load_text_conditioning( + context, self.negative_conditioning.conditioning_name, inference_dtype, device + ) + + latent_height = self.height // LATENT_SCALE_FACTOR + latent_width = self.width // LATENT_SCALE_FACTOR + grid_height = latent_height // 2 + grid_width = latent_width // 2 + image_seq_len = grid_height * grid_width + + # Scheduler: load from the model's scheduler/ dir if present, else construct with Krea-2 defaults. + model_path = context.models.get_absolute_path(context.models.get_config(self.transformer.transformer)) + scheduler_path = Path(model_path) / "scheduler" + if scheduler_path.is_dir() and (scheduler_path / "scheduler_config.json").exists(): + scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(str(scheduler_path), local_files_only=True) + else: + scheduler = FlowMatchEulerDiscreteScheduler( + use_dynamic_shifting=True, + base_shift=0.5, + max_shift=1.15, + base_image_seq_len=256, + max_image_seq_len=6400, + num_train_timesteps=1000, + time_shift_type="exponential", + ) + + if self.shift is not None: + mu = self.shift + elif self._is_distilled(context): + mu = KREA2_DISTILLED_MU + else: + mu = calculate_shift(image_seq_len) + + init_sigmas = build_sigmas(self.steps) + scheduler.set_timesteps(sigmas=init_sigmas, mu=mu, device=device) + + # Clip the schedule based on denoising_start/denoising_end for img2img strength. + sigmas_sched = scheduler.sigmas # (N+1,) including terminal 0 + if self.denoising_start > 0 or self.denoising_end < 1: + total_sigmas = len(sigmas_sched) - 1 + start_idx = int(round(self.denoising_start * total_sigmas)) + end_idx = int(round(self.denoising_end * total_sigmas)) + sigmas_sched = sigmas_sched[start_idx : end_idx + 1] + timesteps_sched = sigmas_sched[:-1] * scheduler.config.num_train_timesteps + else: + timesteps_sched = scheduler.timesteps + + total_steps = len(timesteps_sched) + cfg_scale = self._prepare_cfg_scale(total_steps) + + # Load initial latents (img2img). + init_latents = context.tensors.load(self.latents.latents_name) if self.latents else None + if init_latents is not None: + init_latents = init_latents.to(device=device, dtype=inference_dtype) + if init_latents.dim() == 5: + init_latents = init_latents.squeeze(2) + + noise = self._get_noise(self.height, self.width, inference_dtype, device, self.seed) + + if init_latents is not None: + s_0 = sigmas_sched[0].item() + latents = s_0 * noise + (1.0 - s_0) * init_latents + else: + if self.denoising_start > 1e-5: + raise ValueError("denoising_start should be 0 when initial latents are not provided.") + latents = noise + + if total_steps <= 0: + return latents.unsqueeze(2) + + # Pack latents into 2x2 patches: (B, C, H, W) -> (B, grid_h*grid_w, C*4). + latents = pack_latents(latents, 1, KREA2_LATENT_CHANNELS, latent_height, latent_width) + + # Position ids: text tokens at origin, image tokens carry their grid coords. + text_seq_len = pos_prompt_embeds.shape[1] + position_ids = prepare_position_ids(text_seq_len, grid_height, grid_width, device) + + # Inpaint extension operates in 4D, so unpack/repack around each merge. + inpaint_mask = self._prep_inpaint_mask(context, noise) + inpaint_extension: RectifiedFlowInpaintExtension | None = None + if inpaint_mask is not None: + assert init_latents is not None + inpaint_extension = RectifiedFlowInpaintExtension( + init_latents=init_latents, inpaint_mask=inpaint_mask, noise=noise + ) + + step_callback = self._build_step_callback(context) + step_callback( + PipelineIntermediateState( + step=0, + order=1, + total_steps=total_steps, + timestep=int(timesteps_sched[0].item()) if total_steps > 0 else 0, + latents=unpack_latents(latents, latent_height, latent_width), + ), + ) + + transformer_config = context.models.get_config(self.transformer.transformer) + model_is_quantized = transformer_config.format in (ModelFormat.GGUFQuantized,) + num_train_timesteps = scheduler.config.num_train_timesteps + + # Estimate the peak working memory (activations) the transformer forward needs and ask the model + # cache to keep that much VRAM free. The cache offloads as much of the (resident) model to RAM as + # required to honor this — only consequential at higher resolutions, where the activation footprint + # over text+image tokens grows enough that a fully-resident ~12B model would otherwise leave no + # headroom. Without this hint the cache reserves only the small default working memory and places + # the model before LoRA patches are applied, so a model+LoRA combination that just fits the base + # forward OOMs once the LoRA's extra activations are added. + estimated_working_memory = self._estimate_working_memory( + image_seq_len=image_seq_len, + do_cfg=do_cfg, + num_loras=len(self.transformer.loras), + ) + + with ExitStack() as exit_stack: + (cached_weights, transformer) = exit_stack.enter_context( + transformer_info.model_on_device(working_mem_bytes=estimated_working_memory) + ) + + exit_stack.enter_context( + LayerPatcher.apply_smart_model_patches( + model=transformer, + patches=self._lora_iterator(context), + prefix=KREA2_LORA_TRANSFORMER_PREFIX, + dtype=inference_dtype, + cached_weights=cached_weights, + force_sidecar_patching=model_is_quantized, + ) + ) + + for step_idx, t in enumerate(tqdm(timesteps_sched)): + # The pipeline passes timestep / num_train_timesteps to the transformer. + timestep = (t / num_train_timesteps).expand(latents.shape[0]).to(inference_dtype) + + noise_pred_cond = transformer( + hidden_states=latents, + encoder_hidden_states=pos_prompt_embeds, + encoder_attention_mask=pos_prompt_mask, + timestep=timestep, + position_ids=position_ids, + return_dict=False, + )[0] + + if do_cfg and neg_prompt_embeds is not None: + noise_pred_uncond = transformer( + hidden_states=latents, + encoder_hidden_states=neg_prompt_embeds, + encoder_attention_mask=neg_prompt_mask, + timestep=timestep, + position_ids=position_ids, + return_dict=False, + )[0] + noise_pred = noise_pred_uncond + cfg_scale[step_idx] * (noise_pred_cond - noise_pred_uncond) + else: + noise_pred = noise_pred_cond + + # Euler step using the (possibly clipped) sigma schedule. + sigma_curr = sigmas_sched[step_idx] + sigma_next = sigmas_sched[step_idx + 1] + dt = sigma_next - sigma_curr + latents = latents.to(torch.float32) + dt * noise_pred.to(torch.float32) + latents = latents.to(inference_dtype) + + if inpaint_extension is not None: + sigma_next_f = sigmas_sched[step_idx + 1].item() + latents_4d = unpack_latents(latents, latent_height, latent_width) + latents_4d = inpaint_extension.merge_intermediate_latents_with_init_latents( + latents_4d, sigma_next_f + ) + latents = pack_latents(latents_4d, 1, KREA2_LATENT_CHANNELS, latent_height, latent_width) + + step_callback( + PipelineIntermediateState( + step=step_idx + 1, + order=1, + total_steps=total_steps, + timestep=int(t.item()), + latents=unpack_latents(latents, latent_height, latent_width), + ), + ) + + # Unpack to 4D then add a frame dim for the Qwen-Image VAE: (B, C, 1, H, W). + latents = unpack_latents(latents, latent_height, latent_width) + latents = latents.unsqueeze(2) + return latents + + def _estimate_working_memory(self, image_seq_len: int, do_cfg: bool, num_loras: int) -> int: + """Estimate peak transformer activation memory (bytes) so the model cache reserves enough headroom. + + The MMDiT activation footprint scales with the number of image tokens. The per-token figure is + calibrated empirically against the Krea-2-Turbo transformer in bf16 (~2.6 MiB/token covers the + attention + feed-forward intermediates and the transient fp8->bf16 weight casts). LoRA sidecar + patches add their own (small) weights plus an extra activation branch per patched layer, so we add + a fixed margin per LoRA on top. + """ + GB = 1024**3 + per_token_bytes = int(2.6 * 1024 * 1024) + estimated = image_seq_len * per_token_bytes + if do_cfg: + # Conditional/unconditional passes are sequential, but the larger combined sequence and extra + # transient buffers warrant a modest bump. + estimated = int(estimated * 1.1) + if num_loras > 0: + estimated += int((1.5 + 0.5 * num_loras) * GB) + return estimated + + def _build_step_callback(self, context: InvocationContext) -> Callable[[PipelineIntermediateState], None]: + def step_callback(state: PipelineIntermediateState) -> None: + context.util.sd_step_callback(state, BaseModelType.Krea2) + + return step_callback + + def _lora_iterator(self, context: InvocationContext) -> Iterator[Tuple[ModelPatchRaw, float]]: + for lora in self.transformer.loras: + lora_info = context.models.load(lora.lora) + if not isinstance(lora_info.model, ModelPatchRaw): + raise TypeError( + f"Expected ModelPatchRaw for LoRA '{lora.lora.key}', got {type(lora_info.model).__name__}." + ) + yield (lora_info.model, lora.weight) + del lora_info diff --git a/invokeai/app/invocations/krea2_lora_loader.py b/invokeai/app/invocations/krea2_lora_loader.py new file mode 100644 index 00000000000..0bacf45ffee --- /dev/null +++ b/invokeai/app/invocations/krea2_lora_loader.py @@ -0,0 +1,136 @@ +from typing import Optional + +from invokeai.app.invocations.baseinvocation import ( + BaseInvocation, + BaseInvocationOutput, + invocation, + invocation_output, +) +from invokeai.app.invocations.fields import FieldDescriptions, Input, InputField, OutputField +from invokeai.app.invocations.model import LoRAField, ModelIdentifierField, Qwen3VLEncoderField, TransformerField +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType + + +@invocation_output("krea2_lora_loader_output") +class Krea2LoRALoaderOutput(BaseInvocationOutput): + """Krea-2 LoRA Loader Output""" + + transformer: Optional[TransformerField] = OutputField( + default=None, description=FieldDescriptions.transformer, title="Krea-2 Transformer" + ) + qwen3_vl_encoder: Optional[Qwen3VLEncoderField] = OutputField( + default=None, description=FieldDescriptions.qwen3_vl_encoder, title="Qwen3-VL Encoder" + ) + + +@invocation( + "krea2_lora_loader", + title="Apply LoRA - Krea-2", + tags=["lora", "model", "krea2", "krea-2"], + category="model", + version="1.0.0", +) +class Krea2LoRALoaderInvocation(BaseInvocation): + """Apply a LoRA model to a Krea-2 transformer and/or Qwen3-VL text encoder.""" + + lora: ModelIdentifierField = InputField( + description=FieldDescriptions.lora_model, + title="LoRA", + ui_model_base=BaseModelType.Krea2, + ui_model_type=ModelType.LoRA, + ) + weight: float = InputField(default=0.75, description=FieldDescriptions.lora_weight) + transformer: TransformerField | None = InputField( + default=None, + description=FieldDescriptions.transformer, + input=Input.Connection, + title="Krea-2 Transformer", + ) + qwen3_vl_encoder: Qwen3VLEncoderField | None = InputField( + default=None, + title="Qwen3-VL Encoder", + description=FieldDescriptions.qwen3_vl_encoder, + input=Input.Connection, + ) + + def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: + lora_key = self.lora.key + + if not context.models.exists(lora_key): + raise ValueError(f"Unknown lora: {lora_key}!") + + if self.transformer and any(lora.lora.key == lora_key for lora in self.transformer.loras): + raise ValueError(f'LoRA "{lora_key}" already applied to transformer.') + if self.qwen3_vl_encoder and any(lora.lora.key == lora_key for lora in self.qwen3_vl_encoder.loras): + raise ValueError(f'LoRA "{lora_key}" already applied to Qwen3-VL encoder.') + + output = Krea2LoRALoaderOutput() + + if self.transformer is not None: + output.transformer = self.transformer.model_copy(deep=True) + output.transformer.loras.append(LoRAField(lora=self.lora, weight=self.weight)) + if self.qwen3_vl_encoder is not None: + output.qwen3_vl_encoder = self.qwen3_vl_encoder.model_copy(deep=True) + output.qwen3_vl_encoder.loras.append(LoRAField(lora=self.lora, weight=self.weight)) + + return output + + +@invocation( + "krea2_lora_collection_loader", + title="Apply LoRA Collection - Krea-2", + tags=["lora", "model", "krea2", "krea-2"], + category="model", + version="1.0.0", +) +class Krea2LoRACollectionLoader(BaseInvocation): + """Applies a collection of LoRAs to a Krea-2 transformer and/or Qwen3-VL encoder.""" + + loras: Optional[LoRAField | list[LoRAField]] = InputField( + default=None, description="LoRA models and weights. May be a single LoRA or collection.", title="LoRAs" + ) + transformer: Optional[TransformerField] = InputField( + default=None, + description=FieldDescriptions.transformer, + input=Input.Connection, + title="Transformer", + ) + qwen3_vl_encoder: Qwen3VLEncoderField | None = InputField( + default=None, + title="Qwen3-VL Encoder", + description=FieldDescriptions.qwen3_vl_encoder, + input=Input.Connection, + ) + + def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: + output = Krea2LoRALoaderOutput() + loras = self.loras if isinstance(self.loras, list) else [self.loras] + added_loras: list[str] = [] + + if self.transformer is not None: + output.transformer = self.transformer.model_copy(deep=True) + if self.qwen3_vl_encoder is not None: + output.qwen3_vl_encoder = self.qwen3_vl_encoder.model_copy(deep=True) + + for lora in loras: + if lora is None: + continue + if lora.lora.key in added_loras: + continue + if not context.models.exists(lora.lora.key): + raise Exception(f"Unknown lora: {lora.lora.key}!") + if lora.lora.base is not BaseModelType.Krea2: + raise ValueError( + f"LoRA '{lora.lora.key}' is for {lora.lora.base.value if lora.lora.base else 'unknown'} models, " + "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." + ) + + added_loras.append(lora.lora.key) + + if self.transformer is not None and output.transformer is not None: + output.transformer.loras.append(lora) + if self.qwen3_vl_encoder is not None and output.qwen3_vl_encoder is not None: + output.qwen3_vl_encoder.loras.append(lora) + + return output diff --git a/invokeai/app/invocations/krea2_model_loader.py b/invokeai/app/invocations/krea2_model_loader.py new file mode 100644 index 00000000000..1c3e21a00cb --- /dev/null +++ b/invokeai/app/invocations/krea2_model_loader.py @@ -0,0 +1,111 @@ +from typing import Optional + +from invokeai.app.invocations.baseinvocation import ( + BaseInvocation, + BaseInvocationOutput, + Classification, + invocation, + invocation_output, +) +from invokeai.app.invocations.fields import FieldDescriptions, Input, InputField, OutputField +from invokeai.app.invocations.model import ( + ModelIdentifierField, + Qwen3VLEncoderField, + TransformerField, + VAEField, +) +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType, SubModelType + + +@invocation_output("krea2_model_loader_output") +class Krea2ModelLoaderOutput(BaseInvocationOutput): + """Krea-2 base model loader output.""" + + transformer: TransformerField = OutputField(description=FieldDescriptions.transformer, title="Transformer") + qwen3_vl_encoder: Qwen3VLEncoderField = OutputField( + description=FieldDescriptions.qwen3_vl_encoder, title="Qwen3-VL Encoder" + ) + vae: VAEField = OutputField(description=FieldDescriptions.vae, title="VAE") + + +@invocation( + "krea2_model_loader", + title="Main Model - Krea-2", + tags=["model", "krea2", "krea-2"], + category="model", + version="1.0.0", + classification=Classification.Prototype, +) +class Krea2ModelLoaderInvocation(BaseInvocation): + """Loads a Krea-2 model, outputting its submodels. + + By default the VAE (Qwen-Image VAE) and Qwen3-VL text encoder are extracted from the Krea-2 + diffusers pipeline. Standalone overrides may be supplied (e.g. when the transformer is a + single-file checkpoint that has no bundled VAE / encoder). + """ + + model: ModelIdentifierField = InputField( + description=FieldDescriptions.krea2_model, + input=Input.Direct, + ui_model_base=BaseModelType.Krea2, + ui_model_type=ModelType.Main, + title="Transformer", + ) + + vae_model: Optional[ModelIdentifierField] = InputField( + default=None, + description="Standalone VAE model. Krea-2 uses the Qwen-Image VAE (16-channel). " + "If not provided, the VAE is loaded from the Krea-2 (diffusers) model.", + input=Input.Direct, + ui_model_base=BaseModelType.QwenImage, + ui_model_type=ModelType.VAE, + title="VAE", + ) + + qwen3_vl_encoder_model: Optional[ModelIdentifierField] = InputField( + default=None, + description="Standalone Qwen3-VL Encoder model. " + "If not provided, the encoder is loaded from the Krea-2 (diffusers) model.", + input=Input.Direct, + ui_model_type=ModelType.Qwen3VLEncoder, + title="Qwen3-VL Encoder", + ) + + def invoke(self, context: InvocationContext) -> Krea2ModelLoaderOutput: + # Transformer always comes from the main model. + transformer = self.model.model_copy(update={"submodel_type": SubModelType.Transformer}) + + # Determine VAE source. + if self.vae_model is not None: + vae = self.vae_model.model_copy(update={"submodel_type": SubModelType.VAE}) + else: + self._validate_diffusers_format(context, self.model, "Krea-2") + vae = self.model.model_copy(update={"submodel_type": SubModelType.VAE}) + + # Determine Qwen3-VL Encoder source. + if self.qwen3_vl_encoder_model is not None: + tokenizer = self.qwen3_vl_encoder_model.model_copy(update={"submodel_type": SubModelType.Tokenizer}) + text_encoder = self.qwen3_vl_encoder_model.model_copy(update={"submodel_type": SubModelType.TextEncoder}) + else: + self._validate_diffusers_format(context, self.model, "Krea-2") + tokenizer = self.model.model_copy(update={"submodel_type": SubModelType.Tokenizer}) + text_encoder = self.model.model_copy(update={"submodel_type": SubModelType.TextEncoder}) + + return Krea2ModelLoaderOutput( + transformer=TransformerField(transformer=transformer, loras=[]), + qwen3_vl_encoder=Qwen3VLEncoderField(tokenizer=tokenizer, text_encoder=text_encoder, loras=[]), + vae=VAEField(vae=vae), + ) + + def _validate_diffusers_format( + self, context: InvocationContext, model: ModelIdentifierField, model_name: str + ) -> None: + """Validate that a model is in Diffusers format (required to extract VAE / encoder submodels).""" + config = context.models.get_config(model) + if config.format != ModelFormat.Diffusers: + raise ValueError( + f"To extract the VAE and Qwen3-VL encoder, the {model_name} model must be in Diffusers format. " + f"The selected model '{config.name}' is in {config.format.value} format — provide a standalone " + "VAE and Qwen3-VL Encoder instead." + ) diff --git a/invokeai/app/invocations/krea2_seed_variance.py b/invokeai/app/invocations/krea2_seed_variance.py new file mode 100644 index 00000000000..39e05dfdb2a --- /dev/null +++ b/invokeai/app/invocations/krea2_seed_variance.py @@ -0,0 +1,69 @@ +import torch + +from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation +from invokeai.app.invocations.fields import FieldDescriptions, Input, InputField, Krea2ConditioningField +from invokeai.app.invocations.primitives import Krea2ConditioningOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ( + ConditioningFieldData, + Krea2ConditioningInfo, +) + + +@invocation( + "krea2_seed_variance", + title="Seed Variance - Krea-2", + tags=["conditioning", "krea2", "krea-2", "variance"], + category="conditioning", + version="1.0.0", + classification=Classification.Prototype, +) +class Krea2SeedVarianceInvocation(BaseInvocation): + """Inject per-seed diversity into Krea-2 text conditioning. + + Distilled few-step models (like Krea-2-Turbo) suffer from low seed variance — different seeds give + near-identical images. This adds seeded uniform noise to a random subset of the text-embedding + values, trading some prompt adherence for variety (the same idea as the Z-Image-Turbo + `SeedVarianceEnhancer`). Optional pass between the text encoder and denoise; the defaults are + aggressive and may need tuning for Krea-2. + """ + + conditioning: Krea2ConditioningField = InputField( + description=FieldDescriptions.cond, input=Input.Connection, title="Conditioning" + ) + strength: float = InputField( + default=20.0, + description="Magnitude of the uniform noise added to the embeddings (noise in [-strength, +strength]).", + ) + randomize_percent: float = InputField( + default=50.0, + ge=1.0, + le=100.0, + description="Percentage of embedding values that get perturbed (Bernoulli mask).", + ) + variance_seed: int = InputField(default=0, description="Seed for the variance noise (vary this to get variety).") + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> Krea2ConditioningOutput: + cond_data = context.conditioning.load(self.conditioning.conditioning_name) + assert len(cond_data.conditionings) == 1 + conditioning = cond_data.conditionings[0] + assert isinstance(conditioning, Krea2ConditioningInfo) + + embeds = conditioning.prompt_embeds # (B, seq, 12, hidden) + generator = torch.Generator(device=embeds.device).manual_seed(self.variance_seed) + noise = torch.rand(embeds.shape, generator=generator, dtype=torch.float32, device=embeds.device) * 2.0 - 1.0 + noise = noise * self.strength + mask = torch.bernoulli( + torch.full(embeds.shape, self.randomize_percent / 100.0, dtype=torch.float32, device=embeds.device), + generator=generator, + ) + embeds = (embeds.to(torch.float32) + noise * mask).to(embeds.dtype) + + new_data = ConditioningFieldData( + conditionings=[ + Krea2ConditioningInfo(prompt_embeds=embeds, prompt_embeds_mask=conditioning.prompt_embeds_mask) + ] + ) + conditioning_name = context.conditioning.save(new_data) + return Krea2ConditioningOutput.build(conditioning_name) diff --git a/invokeai/app/invocations/krea2_text_encoder.py b/invokeai/app/invocations/krea2_text_encoder.py new file mode 100644 index 00000000000..6464efc7234 --- /dev/null +++ b/invokeai/app/invocations/krea2_text_encoder.py @@ -0,0 +1,120 @@ +import torch + +from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation +from invokeai.app.invocations.fields import ( + FieldDescriptions, + Input, + InputField, + UIComponent, +) +from invokeai.app.invocations.model import Qwen3VLEncoderField +from invokeai.app.invocations.primitives import Krea2ConditioningOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.krea2.sampling_utils import ( + KREA2_MAX_SEQ_LEN, + KREA2_NUM_SUFFIX_TOKENS, + KREA2_SELECT_LAYERS, + KREA2_START_IDX, +) +from invokeai.backend.model_manager.load.model_cache.utils import get_effective_device +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ( + ConditioningFieldData, + Krea2ConditioningInfo, +) + +# Prompt template from diffusers Krea2Pipeline.get_text_hidden_states. The prefix (a system turn that +# instructs the model to describe the image) is the same "generate" template used by Qwen-Image, which +# is why the first KREA2_START_IDX (34) tokens are dropped from the encoder output. +_KREA2_PREFIX = ( + "<|im_start|>system\nDescribe the image by detailing the color, shape, size, texture, quantity, text, " + "spatial relationships of the objects and background:<|im_end|>\n<|im_start|>user\n" +) +_KREA2_SUFFIX = "<|im_end|>\n<|im_start|>assistant\n" + + +@invocation( + "krea2_text_encoder", + title="Prompt - Krea-2", + tags=["prompt", "conditioning", "krea2", "krea-2"], + category="conditioning", + version="1.0.0", + classification=Classification.Prototype, +) +class Krea2TextEncoderInvocation(BaseInvocation): + """Encodes a text prompt for Krea-2 using the Qwen3-VL text encoder. + + The encoder taps 12 decoder hidden-state layers and stacks them per token, producing a 4D + conditioning tensor (B, seq, 12, hidden) that the Krea-2 transformer's text-fusion stage consumes. + """ + + prompt: str = InputField(description="Text prompt describing the desired image.", ui_component=UIComponent.Textarea) + qwen3_vl_encoder: Qwen3VLEncoderField = InputField( + title="Qwen3-VL Encoder", + description=FieldDescriptions.qwen3_vl_encoder, + input=Input.Connection, + ) + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> Krea2ConditioningOutput: + prompt_embeds, prompt_mask = self._encode(context) + prompt_embeds = prompt_embeds.detach().to("cpu") + prompt_mask = prompt_mask.detach().to("cpu") if prompt_mask is not None else None + + conditioning_data = ConditioningFieldData( + conditionings=[Krea2ConditioningInfo(prompt_embeds=prompt_embeds, prompt_embeds_mask=prompt_mask)] + ) + conditioning_name = context.conditioning.save(conditioning_data) + return Krea2ConditioningOutput.build(conditioning_name) + + def _encode(self, context: InvocationContext) -> tuple[torch.Tensor, torch.Tensor | None]: + tokenizer_info = context.models.load(self.qwen3_vl_encoder.tokenizer) + text_encoder_info = context.models.load(self.qwen3_vl_encoder.text_encoder) + + text = _KREA2_PREFIX + self.prompt + _KREA2_SUFFIX + # diffusers caps the tokenizer length at max_sequence_length + start_idx - num_suffix_tokens. + max_length = KREA2_MAX_SEQ_LEN + KREA2_START_IDX - KREA2_NUM_SUFFIX_TOKENS + + context.util.signal_progress("Running Qwen3-VL text encoder") + + with tokenizer_info as tokenizer, text_encoder_info.model_on_device() as (_, text_encoder): + device = get_effective_device(text_encoder) + + model_inputs = tokenizer( + text, + max_length=max_length, + truncation=True, + return_tensors="pt", + ) + input_ids = model_inputs.input_ids.to(device=device) + attention_mask = model_inputs.attention_mask.to(device=device) + + outputs = text_encoder( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + use_cache=False, + return_dict=True, + ) + + # Some VL models nest the language-model output; fall back to that if needed. + hidden_states_tuple = getattr(outputs, "hidden_states", None) + if hidden_states_tuple is None: + lm_output = getattr(outputs, "language_model_outputs", None) + hidden_states_tuple = getattr(lm_output, "hidden_states", None) + if hidden_states_tuple is None: + raise RuntimeError("Qwen3-VL encoder did not return hidden_states; cannot build Krea-2 conditioning.") + + # Stack the selected layers along a new layer axis: (B, seq, 12, hidden). + stacked = torch.stack([hidden_states_tuple[i] for i in KREA2_SELECT_LAYERS], dim=2) + + # Drop the system-prompt prefix tokens. + prompt_embeds = stacked[:, KREA2_START_IDX:] + prompt_mask = attention_mask[:, KREA2_START_IDX:].bool() + + prompt_embeds = prompt_embeds.to(dtype=torch.bfloat16) + + # If every token is valid (no padding), the mask is unnecessary. + if prompt_mask is not None and bool(prompt_mask.all()): + prompt_mask = None + + return prompt_embeds, prompt_mask diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index da24d8802bb..26adaa04527 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -174,6 +174,10 @@ def invoke(self, context: InvocationContext) -> MetadataOutput: "anima_img2img", "anima_inpaint", "anima_outpaint", + "krea2_txt2img", + "krea2_img2img", + "krea2_inpaint", + "krea2_outpaint", ] diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 0c96cdb1d9d..7cd4d5e7b63 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -87,6 +87,14 @@ class Qwen3EncoderField(BaseModel): loras: List[LoRAField] = Field(default_factory=list, description="LoRAs to apply on model loading") +class Qwen3VLEncoderField(BaseModel): + """Field for the Qwen3-VL text encoder used by Krea-2 models.""" + + tokenizer: ModelIdentifierField = Field(description="Info to load tokenizer submodel") + text_encoder: ModelIdentifierField = Field(description="Info to load text_encoder submodel") + loras: List[LoRAField] = Field(default_factory=list, description="LoRAs to apply on model loading") + + class VAEField(BaseModel): vae: ModelIdentifierField = Field(description="Info to load vae submodel") seamless_axes: List[str] = Field(default_factory=list, description='Axes("x" and "y") to which apply seamless') diff --git a/invokeai/app/invocations/primitives.py b/invokeai/app/invocations/primitives.py index 7ec6c3dc149..1aefdfbec7a 100644 --- a/invokeai/app/invocations/primitives.py +++ b/invokeai/app/invocations/primitives.py @@ -23,6 +23,7 @@ ImageField, Input, InputField, + Krea2ConditioningField, LatentsField, OutputField, QwenImageConditioningField, @@ -486,6 +487,17 @@ def build(cls, conditioning_name: str) -> "QwenImageConditioningOutput": return cls(conditioning=QwenImageConditioningField(conditioning_name=conditioning_name)) +@invocation_output("krea2_conditioning_output") +class Krea2ConditioningOutput(BaseInvocationOutput): + """Base class for nodes that output a Krea-2 conditioning tensor.""" + + conditioning: Krea2ConditioningField = OutputField(description=FieldDescriptions.cond) + + @classmethod + def build(cls, conditioning_name: str) -> "Krea2ConditioningOutput": + return cls(conditioning=Krea2ConditioningField(conditioning_name=conditioning_name)) + + @invocation_output("anima_conditioning_output") class AnimaConditioningOutput(BaseInvocationOutput): """Base class for nodes that output an Anima text conditioning tensor.""" diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py index e06f8f2df91..86b81b0cf13 100644 --- a/invokeai/app/services/model_records/model_records_base.py +++ b/invokeai/app/services/model_records/model_records_base.py @@ -26,6 +26,7 @@ ClipVariantType, Flux2VariantType, FluxVariantType, + Krea2VariantType, ModelFormat, ModelSourceType, ModelType, @@ -135,6 +136,7 @@ def validate_source_url(cls, v: Any) -> Optional[str]: | ZImageVariantType | QwenImageVariantType | Qwen3VariantType + | Krea2VariantType ] = Field(description="The variant of the model.", default=None) prediction_type: Optional[SchedulerPredictionType] = Field( description="The prediction type of the model.", default=None diff --git a/invokeai/app/util/step_callback.py b/invokeai/app/util/step_callback.py index 08dc9a2265c..e8101e192e6 100644 --- a/invokeai/app/util/step_callback.py +++ b/invokeai/app/util/step_callback.py @@ -255,7 +255,8 @@ def diffusion_step_callback( latent_rgb_factors = SD3_5_LATENT_RGB_FACTORS elif base_model == BaseModelType.CogView4: latent_rgb_factors = COGVIEW4_LATENT_RGB_FACTORS - elif base_model == BaseModelType.QwenImage: + elif base_model in [BaseModelType.QwenImage, BaseModelType.Krea2]: + # Krea-2 decodes with the Qwen-Image VAE (16 latent channels), so it shares the preview factors. latent_rgb_factors = QWEN_IMAGE_LATENT_RGB_FACTORS latent_rgb_bias = QWEN_IMAGE_LATENT_RGB_BIAS elif base_model == BaseModelType.Flux: diff --git a/invokeai/backend/krea2/__init__.py b/invokeai/backend/krea2/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/invokeai/backend/krea2/sampling_utils.py b/invokeai/backend/krea2/sampling_utils.py new file mode 100644 index 00000000000..875c7cefd46 --- /dev/null +++ b/invokeai/backend/krea2/sampling_utils.py @@ -0,0 +1,97 @@ +"""Sampling/packing utilities for Krea-2 (Krea2Pipeline) inference. + +InvokeAI hand-writes its own denoise loop for Qwen-family models rather than calling the +diffusers pipeline ``__call__``. These helpers replicate the Krea-2 sampling math so the +``Krea2Transformer2DModel`` (loaded from diffusers) can be driven directly. + +Reference: ``diffusers/pipelines/krea2/pipeline_krea2.py`` (diffusers main / 0.39.0.dev0). +""" + +from typing import List + +import numpy as np +import torch + +# Krea-2 packs latents into 2x2 patches; the VAE (AutoencoderKLQwenImage) is f8. +PATCH_SIZE = 2 +VAE_SCALE_FACTOR = 8 + +# Hidden-state layers tapped from the Qwen3-VL text encoder (model_index.json +# text_encoder_select_layers). Stacked per token into prompt_embeds (B, seq, 12, hidden). +KREA2_SELECT_LAYERS = (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35) + +# Text template constants (diffusers Krea2Pipeline.get_text_hidden_states). +KREA2_MAX_SEQ_LEN = 512 +KREA2_START_IDX = 34 # drop the system-prompt prefix tokens +KREA2_NUM_SUFFIX_TOKENS = 5 + +# Resolution-aware time-shift parameters (scheduler_config.json). +KREA2_BASE_SHIFT = 0.5 +KREA2_MAX_SHIFT = 1.15 +KREA2_BASE_IMAGE_SEQ_LEN = 256 +KREA2_MAX_IMAGE_SEQ_LEN = 6400 +# Fixed timestep shift for the distilled (Turbo) checkpoint. +KREA2_DISTILLED_MU = 1.15 + + +def pack_latents(latents: torch.Tensor, batch_size: int, num_channels: int, height: int, width: int) -> torch.Tensor: + """Pack 4D latents (B, C, H, W) into 2x2-patched 3D (B, H/2*W/2, C*4). + + Identical to the Qwen-Image / Krea-2 ``_pack_latents`` (patch_size=2). + """ + p = PATCH_SIZE + latents = latents.view(batch_size, num_channels, height // p, p, width // p, p) + latents = latents.permute(0, 2, 4, 1, 3, 5) + latents = latents.reshape(batch_size, (height // p) * (width // p), num_channels * p * p) + return latents + + +def unpack_latents(latents: torch.Tensor, height: int, width: int) -> torch.Tensor: + """Unpack 3D patched latents (B, seq, C*4) back to 4D (B, C, H, W). + + ``height``/``width`` are in latent space (i.e. pixels // vae_scale_factor). + """ + p = PATCH_SIZE + batch_size, _num_patches, channels = latents.shape + h = p * (height // p) + w = p * (width // p) + latents = latents.view(batch_size, h // p, w // p, channels // (p * p), p, p) + latents = latents.permute(0, 3, 1, 4, 2, 5) + latents = latents.reshape(batch_size, channels // (p * p), h, w) + return latents + + +def prepare_position_ids(text_seq_len: int, grid_height: int, grid_width: int, device: torch.device) -> torch.Tensor: + """Build the (text_seq_len + grid_h*grid_w, 3) rotary coordinates. + + Text tokens sit at the origin (0, 0, 0); image tokens carry their (0, h, w) latent-grid + coordinates. Matches diffusers ``Krea2Pipeline.prepare_position_ids``. + """ + text_ids = torch.zeros(text_seq_len, 3, device=device) + image_ids = torch.zeros(grid_height, grid_width, 3, device=device) + image_ids[..., 1] = torch.arange(grid_height, device=device)[:, None] + image_ids[..., 2] = torch.arange(grid_width, device=device)[None, :] + image_ids = image_ids.reshape(grid_height * grid_width, 3) + return torch.cat([text_ids, image_ids], dim=0) + + +def calculate_shift( + image_seq_len: int, + base_image_seq_len: int = KREA2_BASE_IMAGE_SEQ_LEN, + max_image_seq_len: int = KREA2_MAX_IMAGE_SEQ_LEN, + base_shift: float = KREA2_BASE_SHIFT, + max_shift: float = KREA2_MAX_SHIFT, +) -> float: + """Resolution-aware mu (linear interpolation by sequence length). + + NOTE: mu is fed straight into ``FlowMatchEulerDiscreteScheduler.set_timesteps(..., mu=mu)``; + the exponential time-shift happens inside the scheduler. Do NOT ``exp()`` this value. + """ + m = (max_shift - base_shift) / (max_image_seq_len - base_image_seq_len) + b = base_shift - m * base_image_seq_len + return image_seq_len * m + b + + +def build_sigmas(steps: int) -> List[float]: + """Krea-2 sigma schedule: linspace(1.0, 1/steps, steps).""" + return np.linspace(1.0, 1.0 / steps, steps).tolist() diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index b176a6ff0b2..5b761316a40 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -50,6 +50,7 @@ LoRA_LyCORIS_Anima_Config, LoRA_LyCORIS_Flux2_Config, LoRA_LyCORIS_FLUX_Config, + LoRA_LyCORIS_Krea2_Config, LoRA_LyCORIS_QwenImage_Config, LoRA_LyCORIS_SD1_Config, LoRA_LyCORIS_SD2_Config, @@ -64,6 +65,7 @@ Main_Checkpoint_Anima_Config, Main_Checkpoint_Flux2_Config, Main_Checkpoint_FLUX_Config, + Main_Checkpoint_Krea2_Config, Main_Checkpoint_QwenImage_Config, Main_Checkpoint_SD1_Config, Main_Checkpoint_SD2_Config, @@ -73,6 +75,7 @@ Main_Diffusers_CogView4_Config, Main_Diffusers_Flux2_Config, Main_Diffusers_FLUX_Config, + Main_Diffusers_Krea2_Config, Main_Diffusers_QwenImage_Config, Main_Diffusers_SD1_Config, Main_Diffusers_SD2_Config, @@ -91,6 +94,9 @@ Qwen3Encoder_GGUF_Config, Qwen3Encoder_Qwen3Encoder_Config, ) +from invokeai.backend.model_manager.configs.qwen3_vl_encoder import ( + Qwen3VLEncoder_Qwen3VLEncoder_Config, +) from invokeai.backend.model_manager.configs.qwen_vl_encoder import ( QwenVLEncoder_Checkpoint_Config, QwenVLEncoder_Diffusers_Config, @@ -175,6 +181,7 @@ Annotated[Main_Diffusers_CogView4_Config, Main_Diffusers_CogView4_Config.get_tag()], Annotated[Main_Diffusers_QwenImage_Config, Main_Diffusers_QwenImage_Config.get_tag()], Annotated[Main_Diffusers_ZImage_Config, Main_Diffusers_ZImage_Config.get_tag()], + Annotated[Main_Diffusers_Krea2_Config, Main_Diffusers_Krea2_Config.get_tag()], # Main (Pipeline) - checkpoint format # IMPORTANT: FLUX.2 must be checked BEFORE FLUX.1 because FLUX.2 has specific validation # that will reject FLUX.1 models, but FLUX.1 validation may incorrectly match FLUX.2 models @@ -186,6 +193,7 @@ Annotated[Main_Checkpoint_FLUX_Config, Main_Checkpoint_FLUX_Config.get_tag()], Annotated[Main_Checkpoint_QwenImage_Config, Main_Checkpoint_QwenImage_Config.get_tag()], Annotated[Main_Checkpoint_ZImage_Config, Main_Checkpoint_ZImage_Config.get_tag()], + Annotated[Main_Checkpoint_Krea2_Config, Main_Checkpoint_Krea2_Config.get_tag()], Annotated[Main_Checkpoint_Anima_Config, Main_Checkpoint_Anima_Config.get_tag()], # Main (Pipeline) - quantized formats # IMPORTANT: FLUX.2 must be checked BEFORE FLUX.1 because FLUX.2 has specific validation @@ -227,6 +235,7 @@ Annotated[LoRA_LyCORIS_Flux2_Config, LoRA_LyCORIS_Flux2_Config.get_tag()], Annotated[LoRA_LyCORIS_FLUX_Config, LoRA_LyCORIS_FLUX_Config.get_tag()], Annotated[LoRA_LyCORIS_ZImage_Config, LoRA_LyCORIS_ZImage_Config.get_tag()], + Annotated[LoRA_LyCORIS_Krea2_Config, LoRA_LyCORIS_Krea2_Config.get_tag()], Annotated[LoRA_LyCORIS_QwenImage_Config, LoRA_LyCORIS_QwenImage_Config.get_tag()], Annotated[LoRA_LyCORIS_Anima_Config, LoRA_LyCORIS_Anima_Config.get_tag()], # LoRA - OMI format @@ -250,6 +259,8 @@ Annotated[Qwen3Encoder_Qwen3Encoder_Config, Qwen3Encoder_Qwen3Encoder_Config.get_tag()], Annotated[Qwen3Encoder_Checkpoint_Config, Qwen3Encoder_Checkpoint_Config.get_tag()], Annotated[Qwen3Encoder_GGUF_Config, Qwen3Encoder_GGUF_Config.get_tag()], + # Qwen3-VL Encoder (Qwen3-VL multimodal encoder for Krea-2) + Annotated[Qwen3VLEncoder_Qwen3VLEncoder_Config, Qwen3VLEncoder_Qwen3VLEncoder_Config.get_tag()], # Qwen VL Encoder (Qwen2.5-VL multimodal encoder for Qwen Image) Annotated[QwenVLEncoder_Diffusers_Config, QwenVLEncoder_Diffusers_Config.get_tag()], Annotated[QwenVLEncoder_Checkpoint_Config, QwenVLEncoder_Checkpoint_Config.get_tag()], @@ -402,6 +413,14 @@ def _validate_path_looks_like_model(path: Path) -> None: f"Expected one of: {', '.join(sorted(_MODEL_EXTENSIONS))}" ) else: + # A config file at the root (model_index.json / config.json) is an unambiguous + # diffusers/transformers model marker, so accept the directory regardless of file + # count. HF snapshots often bundle extra non-model assets (e.g. a model-card `images/` + # folder) that would otherwise trip the general-purpose-directory guard below. + has_root_config = any((path / config).exists() for config in _CONFIG_FILES) + if has_root_config: + return + # For directories, do a quick file count check with early exit total_files = 0 # Ignore hidden files and directories @@ -420,13 +439,6 @@ def _validate_path_looks_like_model(path: Path) -> None: "Please provide a path to a specific model file or model directory." ) - # Check if it has config files at root (diffusers/transformers marker) - has_root_config = any((path / config).exists() for config in _CONFIG_FILES) - - if has_root_config: - # Has a config file, looks like a valid model directory - return - # Otherwise, search for model files within depth limit def find_model_files(current_path: Path, depth: int) -> bool: if depth > _MAX_SEARCH_DEPTH: diff --git a/invokeai/backend/model_manager/configs/lora.py b/invokeai/backend/model_manager/configs/lora.py index 46606a3c0d5..4c66a368007 100644 --- a/invokeai/backend/model_manager/configs/lora.py +++ b/invokeai/backend/model_manager/configs/lora.py @@ -829,6 +829,9 @@ def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None: # (with the "transformer." prefix and "single_" variant) which would falsely match our check. # Flux Kohya LoRAs use lora_unet_double_blocks or lora_unet_single_blocks. has_z_image_keys = state_dict_has_any_keys_starting_with(state_dict, {"diffusion_model.layers."}) + # Krea-2 LoRAs also carry transformer.transformer_blocks. keys, but uniquely include the + # text-fusion stage. Exclude them here so they route to LoRA_LyCORIS_Krea2_Config. + has_krea2_keys = _has_krea2_lora_keys(state_dict) has_flux_keys = state_dict_has_any_keys_starting_with( state_dict, { @@ -842,7 +845,7 @@ def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None: }, ) - if has_qwen_ie_keys and has_lora_suffix and not has_z_image_keys and not has_flux_keys: + if has_qwen_ie_keys and has_lora_suffix and not has_z_image_keys and not has_krea2_keys and not has_flux_keys: return raise NotAMatchError("model does not match Qwen Image LoRA heuristics") @@ -855,6 +858,7 @@ def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType: {"transformer_blocks.", "transformer.transformer_blocks.", "lora_unet_transformer_blocks_"}, ) has_z_image_keys = state_dict_has_any_keys_starting_with(state_dict, {"diffusion_model.layers."}) + has_krea2_keys = _has_krea2_lora_keys(state_dict) has_flux_keys = state_dict_has_any_keys_starting_with( state_dict, { @@ -868,11 +872,47 @@ def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType: }, ) - if has_qwen_ie_keys and not has_z_image_keys and not has_flux_keys: + if has_qwen_ie_keys and not has_z_image_keys and not has_krea2_keys and not has_flux_keys: return BaseModelType.QwenImage raise NotAMatchError("model does not look like a Qwen Image Edit LoRA") +def _has_krea2_lora_keys(state_dict: dict[str | int, Any]) -> bool: + """True if the state dict targets Krea-2's distinctive text-fusion / time-mod-proj modules.""" + return any(isinstance(k, str) and ("text_fusion" in k or "time_mod_proj" in k) for k in state_dict.keys()) + + +class LoRA_LyCORIS_Krea2_Config(LoRA_LyCORIS_Config_Base, Config_Base): + """Model config for Krea-2 LoRA models in LyCORIS (single-file diffusers PEFT) format.""" + + base: Literal[BaseModelType.Krea2] = Field(default=BaseModelType.Krea2) + + @classmethod + def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None: + """Krea-2 LoRAs have keys like transformer.text_fusion.* / transformer.transformer_blocks.* with + a lora_A/lora_B (or lora_down/lora_up) suffix. The text-fusion stage is unique to Krea-2.""" + state_dict = mod.load_state_dict() + has_lora_suffix = state_dict_has_any_keys_ending_with( + state_dict, + { + "lora_A.weight", + "lora_B.weight", + "lora_down.weight", + "lora_up.weight", + "dora_scale", + }, + ) + if _has_krea2_lora_keys(state_dict) and has_lora_suffix: + return + raise NotAMatchError("model does not match Krea-2 LoRA heuristics") + + @classmethod + def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType: + if _has_krea2_lora_keys(mod.load_state_dict()): + return BaseModelType.Krea2 + raise NotAMatchError("model does not look like a Krea-2 LoRA") + + class LoRA_LyCORIS_Anima_Config(LoRA_LyCORIS_Config_Base, Config_Base): """Model config for Anima LoRA models in LyCORIS format.""" diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index 10835b389fc..918a9a01df5 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -27,6 +27,7 @@ BaseModelType, Flux2VariantType, FluxVariantType, + Krea2VariantType, ModelFormat, ModelType, ModelVariantType, @@ -65,7 +66,12 @@ class MainModelDefaultSettings(BaseModel): def from_base( cls, base: BaseModelType, - variant: Flux2VariantType | FluxVariantType | ModelVariantType | ZImageVariantType | None = None, + variant: Flux2VariantType + | FluxVariantType + | ModelVariantType + | ZImageVariantType + | Krea2VariantType + | None = None, ) -> Self | None: match base: case BaseModelType.StableDiffusion1: @@ -95,6 +101,10 @@ def from_base( return cls(steps=4, cfg_scale=1.0, width=1024, height=1024) case BaseModelType.QwenImage: return cls(steps=40, cfg_scale=4.0, width=1024, height=1024) + case BaseModelType.Krea2: + # Krea-2-Turbo is distilled: 8 steps, CFG disabled (guidance_scale=0). + # cfg_scale has a floor of 1 (ge=1); 1.0 means "no guidance" for the Krea-2 denoise loop. + return cls(steps=8, cfg_scale=1.0, width=1024, height=1024) case _: # TODO(psyche): Do we want defaults for other base types? return None @@ -190,6 +200,49 @@ def _has_z_image_keys(state_dict: dict[str | int, Any]) -> bool: return False +def _has_krea2_keys(state_dict: dict[str | int, Any]) -> bool: + """Check if state dict contains Krea-2 (Krea2Transformer2DModel) transformer keys. + + Krea-2's single-stream MMDiT has a distinctive text-fusion stage; the ``text_fusion.`` + prefix (with ``layerwise_blocks`` / ``refiner_blocks`` / ``projector``) is unique to it. + Returns True only for Krea-2 main models, not LoRAs. + """ + krea2_specific_keys = { + "text_fusion", # text-fusion stage (layerwise_blocks, refiner_blocks, projector) - unique to Krea-2 + "time_mod_proj", # timestep modulation projection + } + + lora_suffixes = ( + ".lora_down.weight", + ".lora_up.weight", + ".lora_A.weight", + ".lora_B.weight", + ".dora_scale", + ".alpha", + ) + + # If any key has a LoRA suffix, this is a LoRA, not a main model. + for key in state_dict.keys(): + if isinstance(key, int): + continue + if key.endswith(lora_suffixes): + return False + + has_text_fusion = False + has_img_in = False + for key in state_dict.keys(): + if isinstance(key, int): + continue + # Handle both direct keys and ComfyUI-style (model.diffusion_model.*) keys. + key_parts = key.split(".") + if any(part in krea2_specific_keys for part in key_parts): + has_text_fusion = True + if "img_in" in key_parts: + has_img_in = True + # Require the distinctive text-fusion stage; img_in is a corroborating signal. + return has_text_fusion and has_img_in + + class Main_SD_Checkpoint_Config_Base(Checkpoint_Config_Base, Main_Config_Base): """Model config for main checkpoint models.""" @@ -1285,6 +1338,76 @@ def _validate_looks_like_gguf_quantized(cls, mod: ModelOnDisk) -> None: raise NotAMatchError("state dict does not look like GGUF quantized") +class Main_Diffusers_Krea2_Config(Diffusers_Config_Base, Main_Config_Base, Config_Base): + """Model config for Krea-2 diffusers models (Krea-2-Turbo).""" + + base: Literal[BaseModelType.Krea2] = Field(BaseModelType.Krea2) + variant: Krea2VariantType = Field() + + @classmethod + def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self: + raise_if_not_dir(mod) + + raise_for_override_fields(cls, override_fields) + + # This check implies the base type - no further validation needed. + raise_for_class_name( + common_config_paths(mod.path), + { + "Krea2Pipeline", + }, + ) + + variant = override_fields.pop("variant", None) or cls._get_variant(mod) + + repo_variant = override_fields.pop("repo_variant", None) or cls._get_repo_variant_or_raise(mod) + + return cls( + **override_fields, + variant=variant, + repo_variant=repo_variant, + ) + + @classmethod + def _get_variant(cls, mod: ModelOnDisk) -> Krea2VariantType: + """Determine the Krea-2 variant. Only the distilled Turbo checkpoint is currently supported.""" + # The distilled (Turbo) checkpoint sets is_distilled=true in model_index.json. Base (midtrain) + # support is not yet implemented, so everything currently maps to Turbo. + return Krea2VariantType.Turbo + + +class Main_Checkpoint_Krea2_Config(Checkpoint_Config_Base, Main_Config_Base, Config_Base): + """Model config for Krea-2 single-file checkpoint models (safetensors, etc).""" + + base: Literal[BaseModelType.Krea2] = Field(default=BaseModelType.Krea2) + format: Literal[ModelFormat.Checkpoint] = Field(default=ModelFormat.Checkpoint) + variant: Krea2VariantType = Field() + + @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) + + cls._validate_looks_like_krea2_model(mod) + + cls._validate_does_not_look_like_gguf_quantized(mod) + + variant = override_fields.pop("variant", None) or Krea2VariantType.Turbo + + return cls(**override_fields, variant=variant) + + @classmethod + def _validate_looks_like_krea2_model(cls, mod: ModelOnDisk) -> None: + if not _has_krea2_keys(mod.load_state_dict()): + raise NotAMatchError("state dict does not look like a Krea-2 model") + + @classmethod + def _validate_does_not_look_like_gguf_quantized(cls, mod: ModelOnDisk) -> None: + if _has_ggml_tensors(mod.load_state_dict()): + raise NotAMatchError("state dict looks like GGUF quantized") + + class Main_Diffusers_QwenImage_Config(Diffusers_Config_Base, Main_Config_Base, Config_Base): """Model config for Qwen Image diffusers models (both txt2img and edit).""" diff --git a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py new file mode 100644 index 00000000000..48d116632de --- /dev/null +++ b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py @@ -0,0 +1,65 @@ +from typing import Any, Literal, Self + +from pydantic import Field + +from invokeai.backend.model_manager.configs.base import Config_Base +from invokeai.backend.model_manager.configs.identification_utils import ( + NotAMatchError, + raise_for_class_name, + raise_for_override_fields, + raise_if_not_dir, +) +from invokeai.backend.model_manager.model_on_disk import ModelOnDisk +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType + + +class Qwen3VLEncoder_Qwen3VLEncoder_Config(Config_Base): + """Configuration for standalone Qwen3-VL text encoder models (diffusers-like directory format). + + Used by Krea-2, whose text conditioning comes from a Qwen3-VL model (``Qwen3VLModel``). The model + weights are expected either in a ``text_encoder`` subfolder of the model directory or directly at the + root (standalone download). This is distinct from the text-only ``Qwen3Encoder`` (Z-Image / FLUX.2 + Klein) and the Qwen2.5-VL ``QwenVLEncoder`` (Qwen Image). + """ + + base: Literal[BaseModelType.Any] = Field(default=BaseModelType.Any) + type: Literal[ModelType.Qwen3VLEncoder] = Field(default=ModelType.Qwen3VLEncoder) + format: Literal[ModelFormat.Qwen3VLEncoder] = Field(default=ModelFormat.Qwen3VLEncoder) + cpu_only: bool | None = Field(default=None, description="Whether this model should run on CPU only") + + @classmethod + def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self: + raise_if_not_dir(mod) + + raise_for_override_fields(cls, override_fields) + + # Exclude full pipeline models - these should be matched as main models, not just encoders. + model_index_path = mod.path / "model_index.json" + transformer_path = mod.path / "transformer" + if model_index_path.exists() or transformer_path.exists(): + raise NotAMatchError( + "directory looks like a full diffusers pipeline (has model_index.json or transformer folder), " + "not a standalone Qwen3-VL encoder" + ) + + # Support both a nested text_encoder/config.json and a standalone config.json at the root. + config_path_nested = mod.path / "text_encoder" / "config.json" + config_path_direct = mod.path / "config.json" + + if config_path_nested.exists(): + expected_config_path = config_path_nested + elif config_path_direct.exists(): + expected_config_path = config_path_direct + else: + raise NotAMatchError(f"unable to load config file: {config_path_nested} does not exist") + + # Qwen3-VL uses the Qwen3VLModel / Qwen3VLForConditionalGeneration architecture. + raise_for_class_name( + expected_config_path, + { + "Qwen3VLModel", + "Qwen3VLForConditionalGeneration", + }, + ) + + return cls(**override_fields) diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py new file mode 100644 index 00000000000..0504374b44d --- /dev/null +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -0,0 +1,230 @@ +# Copyright (c) 2024, Lincoln D. Stein and the InvokeAI Development Team +"""Class for Krea-2 model loading in InvokeAI.""" + +from pathlib import Path +from typing import Any, Optional + +import accelerate +from transformers import AutoTokenizer + +from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Diffusers_Config_Base +from invokeai.backend.model_manager.configs.factory import AnyModelConfig +from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config +from invokeai.backend.model_manager.configs.qwen3_vl_encoder import Qwen3VLEncoder_Qwen3VLEncoder_Config +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.load.model_loaders.generic_diffusers import GenericDiffusersLoader +from invokeai.backend.model_manager.taxonomy import ( + AnyModel, + BaseModelType, + ModelFormat, + ModelType, + SubModelType, +) +from invokeai.backend.util.devices import TorchDevice + +# Default Krea2Transformer2DModel config (from the Krea-2-Turbo transformer/config.json). Used when +# loading a bare single-file checkpoint that has no accompanying config.json. +KREA2_TRANSFORMER_CONFIG = { + "attention_head_dim": 128, + "axes_dims_rope": [32, 48, 48], + "in_channels": 64, + "intermediate_size": 16384, + "norm_eps": 1e-05, + "num_attention_heads": 48, + "num_key_value_heads": 12, + "num_layers": 28, + "num_layerwise_text_blocks": 2, + "num_refiner_text_blocks": 2, + "num_text_layers": 12, + "rope_theta": 1000.0, + "text_hidden_dim": 2560, + "text_intermediate_size": 6912, + "text_num_attention_heads": 20, + "text_num_key_value_heads": 20, + "timestep_embed_dim": 256, +} + + +@ModelLoaderRegistry.register(base=BaseModelType.Krea2, type=ModelType.Main, format=ModelFormat.Diffusers) +class Krea2DiffusersModel(GenericDiffusersLoader): + """Class to load Krea-2 main models (Krea-2-Turbo) in diffusers format. + + Loads every submodel (transformer, vae, text_encoder, tokenizer, scheduler) from the diffusers + pipeline folder via the class names declared in model_index.json. The transformer resolves to + diffusers' ``Krea2Transformer2DModel`` (only available in diffusers main / >=0.39); the VAE to + ``AutoencoderKLQwenImage`` and the text encoder to ``Qwen3VLModel``. + """ + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + if isinstance(config, Checkpoint_Config_Base): + raise NotImplementedError("CheckpointConfigBase is not implemented for the Krea-2 diffusers loader.") + + if submodel_type is None: + raise Exception("A submodel type must be provided when loading main pipelines.") + + model_path = Path(config.path) + + # model_index.json declares the tokenizer as the slow `Qwen2Tokenizer`, which requires + # vocab.json/merges.txt. Krea-2 ships only a fast tokenizer.json, so load via AutoTokenizer + # (which resolves to Qwen2TokenizerFast from tokenizer.json). + # + # Krea-2's tokenizer_config.json stores `extra_special_tokens` as a list (the special tokens + # are already baked into tokenizer.json as added tokens). Newer transformers expects a dict and + # crashes on the list, so override it with an empty dict — the special tokens are still + # recognized from tokenizer.json. + if submodel_type is SubModelType.Tokenizer: + return AutoTokenizer.from_pretrained( + model_path / submodel_type.value, local_files_only=True, extra_special_tokens={} + ) + + load_class = self.get_hf_load_class(model_path, submodel_type) + repo_variant = config.repo_variant if isinstance(config, Diffusers_Config_Base) else None + variant = repo_variant.value if repo_variant else None + model_path = model_path / submodel_type.value + + # Krea-2 prefers bfloat16; use a safe dtype based on target device capabilities. + target_device = TorchDevice.choose_torch_device() + dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + + extra_kwargs: dict[str, Any] = {} + if submodel_type is SubModelType.TextEncoder: + # Krea-2's Qwen3-VL text_encoder config stores rope settings under `rope_parameters`, but the + # installed transformers' Qwen3VL rotary embedding reads `rope_scaling` (None here) → crash. + # Patch the config so rope_scaling mirrors rope_parameters before instantiating the model. + from transformers import AutoConfig + + te_config = AutoConfig.from_pretrained(model_path, local_files_only=True) + text_config = getattr(te_config, "text_config", None) + if text_config is not None: + rope_params = getattr(text_config, "rope_parameters", None) + if getattr(text_config, "rope_scaling", None) is None and rope_params is not None: + text_config.rope_scaling = rope_params + extra_kwargs["config"] = te_config + + try: + result: AnyModel = load_class.from_pretrained( + model_path, + torch_dtype=dtype, + variant=variant, + **extra_kwargs, + ) + except OSError as e: + if variant and "no file named" in str(e): + # try without the variant, just in case the user's preferences changed + result = load_class.from_pretrained(model_path, torch_dtype=dtype, **extra_kwargs) + else: + raise e + + result = self._apply_fp8_layerwise_casting(result, config, submodel_type) + return result + + +@ModelLoaderRegistry.register(base=BaseModelType.Krea2, type=ModelType.Main, format=ModelFormat.Checkpoint) +class Krea2CheckpointModel(ModelLoader): + """Class to load Krea-2 transformer models from single-file checkpoints (safetensors). + + NOTE: the official Krea-2-Turbo release ships only in (sharded) diffusers format. This single-file + path mirrors the Z-Image checkpoint loader and uses the known transformer config; it has not been + validated against a real single-file Krea-2 checkpoint. + """ + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + if not isinstance(config, Checkpoint_Config_Base): + raise ValueError("Only CheckpointConfigBase models are supported here.") + + if submodel_type is not SubModelType.Transformer: + raise ValueError( + f"Only Transformer submodels are supported. Received: {submodel_type.value if submodel_type else 'None'}" + ) + return self._load_from_singlefile(config) + + def _load_from_singlefile(self, config: AnyModelConfig) -> AnyModel: + from diffusers import Krea2Transformer2DModel + from safetensors.torch import load_file + + if not isinstance(config, Main_Checkpoint_Krea2_Config): + raise TypeError(f"Expected Main_Checkpoint_Krea2_Config, got {type(config).__name__}.") + model_path = Path(config.path) + + sd = load_file(model_path) + + # Strip ComfyUI-style key prefixes if present. + prefix_to_strip = None + for prefix in ("model.diffusion_model.", "diffusion_model."): + if any(k.startswith(prefix) for k in sd.keys() if isinstance(k, str)): + prefix_to_strip = prefix + break + if prefix_to_strip: + sd = { + (k[len(prefix_to_strip) :] if isinstance(k, str) and k.startswith(prefix_to_strip) else k): v + for k, v in sd.items() + } + + target_device = TorchDevice.choose_torch_device() + model_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + + with accelerate.init_empty_weights(): + model = Krea2Transformer2DModel(**KREA2_TRANSFORMER_CONFIG) + + new_sd_size = sum(ten.nelement() * model_dtype.itemsize for ten in sd.values()) + self._ram_cache.make_room(new_sd_size) + for k in sd.keys(): + sd[k] = sd[k].to(model_dtype) + + model.load_state_dict(sd, assign=True, strict=False) + return model + + +@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Qwen3VLEncoder, format=ModelFormat.Qwen3VLEncoder) +class Qwen3VLEncoderLoader(ModelLoader): + """Class to load standalone Qwen3-VL text encoder models for Krea-2 (directory format).""" + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + from transformers import Qwen3VLModel + + if not isinstance(config, Qwen3VLEncoder_Qwen3VLEncoder_Config): + raise ValueError("Only Qwen3VLEncoder_Qwen3VLEncoder_Config models are supported here.") + + model_path = Path(config.path) + + # Support both a full pipeline-style layout (text_encoder/ + tokenizer/) and a standalone + # download where the encoder files live directly at the root. + text_encoder_path = model_path / "text_encoder" + tokenizer_path = model_path / "tokenizer" + is_standalone = not text_encoder_path.exists() and (model_path / "config.json").exists() + if is_standalone: + text_encoder_path = model_path + tokenizer_path = model_path + + match submodel_type: + case SubModelType.Tokenizer: + # extra_special_tokens={} works around Krea-2's list-format tokenizer_config (see + # Krea2DiffusersModel); harmless for well-formed configs. + return AutoTokenizer.from_pretrained(tokenizer_path, local_files_only=True, extra_special_tokens={}) + case SubModelType.TextEncoder: + target_device = TorchDevice.choose_torch_device() + model_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + return Qwen3VLModel.from_pretrained( + text_encoder_path, + torch_dtype=model_dtype, + low_cpu_mem_usage=True, + local_files_only=True, + ) + + raise ValueError( + f"Only Tokenizer and TextEncoder submodels are supported. " + f"Received: {submodel_type.value if submodel_type else 'None'}" + ) diff --git a/invokeai/backend/model_manager/load/model_loaders/lora.py b/invokeai/backend/model_manager/load/model_loaders/lora.py index 15dfa376179..1f764929226 100644 --- a/invokeai/backend/model_manager/load/model_loaders/lora.py +++ b/invokeai/backend/model_manager/load/model_loaders/lora.py @@ -57,6 +57,9 @@ is_state_dict_likely_in_flux_xlabs_format, lora_model_from_flux_xlabs_state_dict, ) +from invokeai.backend.patches.lora_conversions.krea2_lora_conversion_utils import ( + lora_model_from_krea2_state_dict, +) from invokeai.backend.patches.lora_conversions.peft_adapter_utils import normalize_peft_adapter_names from invokeai.backend.patches.lora_conversions.qwen_image_lora_conversion_utils import ( lora_model_from_qwen_image_state_dict, @@ -172,6 +175,10 @@ def _load_model( model = lora_model_from_z_image_state_dict(state_dict=state_dict, alpha=None) elif self._model_base == BaseModelType.QwenImage: model = lora_model_from_qwen_image_state_dict(state_dict=state_dict, alpha=None) + elif self._model_base == BaseModelType.Krea2: + # Krea-2 LoRAs use diffusers PEFT format targeting the Krea2 transformer (and optionally + # the Qwen3-VL text encoder). alpha=None → alpha=rank (common diffusers default). + model = lora_model_from_krea2_state_dict(state_dict=state_dict, alpha=None) elif self._model_base == BaseModelType.Anima: # Anima LoRAs use Kohya-style or diffusers PEFT format targeting Cosmos DiT blocks. model = lora_model_from_anima_state_dict(state_dict=state_dict, alpha=None) diff --git a/invokeai/backend/model_manager/starter_models.py b/invokeai/backend/model_manager/starter_models.py index 9bc58e44269..523eb3758bb 100644 --- a/invokeai/backend/model_manager/starter_models.py +++ b/invokeai/backend/model_manager/starter_models.py @@ -1085,6 +1085,17 @@ class StarterModelBundle(BaseModel): ) # endregion +# region Krea-2 +krea2_turbo = StarterModel( + name="Krea-2 Turbo", + base=BaseModelType.Krea2, + source="krea/Krea-2-Turbo", + description="Krea-2 Turbo - distilled 12B parameter text-to-image model (8 steps, CFG disabled). " + "Full diffusers pipeline including the Qwen-Image VAE and Qwen3-VL text encoder. ~26GB", + type=ModelType.Main, +) +# endregion + # region External API GEMINI_3_IMAGE_ALLOWED_ASPECT_RATIOS = [ "1:1", @@ -1690,6 +1701,7 @@ def _gemini_3_resolution_presets( z_image_qwen3_encoder_quantized, z_image_controlnet_union, z_image_controlnet_tile, + krea2_turbo, gemini_flash_image, gemini_pro_image_preview, gemini_3_1_flash_image_preview, diff --git a/invokeai/backend/model_manager/taxonomy.py b/invokeai/backend/model_manager/taxonomy.py index a2e4e58bdc4..ae48dd4571f 100644 --- a/invokeai/backend/model_manager/taxonomy.py +++ b/invokeai/backend/model_manager/taxonomy.py @@ -58,6 +58,8 @@ class BaseModelType(str, Enum): """Indicates the model is associated with Qwen Image Edit 2511 model architecture.""" Anima = "anima" """Indicates the model is associated with Anima model architecture (Cosmos Predict2 DiT + LLM Adapter).""" + Krea2 = "krea-2" + """Indicates the model is associated with the Krea 2 model architecture, including Krea-2-Turbo.""" Unknown = "unknown" """Indicates the model's base architecture is unknown.""" @@ -79,6 +81,7 @@ class ModelType(str, Enum): T5Encoder = "t5_encoder" Qwen3Encoder = "qwen3_encoder" QwenVLEncoder = "qwen_vl_encoder" + Qwen3VLEncoder = "qwen3_vl_encoder" SpandrelImageToImage = "spandrel_image_to_image" SigLIP = "siglip" FluxRedux = "flux_redux" @@ -155,6 +158,16 @@ class ZImageVariantType(str, Enum): """Z-Image Base - undistilled foundation model with full CFG and negative prompt support.""" +class Krea2VariantType(str, Enum): + """Krea 2 model variants.""" + + Turbo = "krea2_turbo" + """Krea-2-Turbo - distilled model optimized for 8 steps with CFG disabled (guidance_scale=0). + + NOTE: the value is ``krea2_turbo`` (not ``turbo``) to avoid colliding with + ``ZImageVariantType.Turbo`` in the variant-string adapter and frontend label maps.""" + + class QwenImageVariantType(str, Enum): """Qwen Image model variants.""" @@ -193,6 +206,7 @@ class ModelFormat(str, Enum): T5Encoder = "t5_encoder" Qwen3Encoder = "qwen3_encoder" QwenVLEncoder = "qwen_vl_encoder" + Qwen3VLEncoder = "qwen3_vl_encoder" BnbQuantizedLlmInt8b = "bnb_quantized_int8b" BnbQuantizednf4b = "bnb_quantized_nf4b" GGUFQuantized = "gguf_quantized" @@ -249,6 +263,7 @@ class FluxLoRAFormat(str, Enum): ZImageVariantType, QwenImageVariantType, Qwen3VariantType, + Krea2VariantType, ] variant_type_adapter = TypeAdapter[ ModelVariantType @@ -258,6 +273,7 @@ class FluxLoRAFormat(str, Enum): | ZImageVariantType | QwenImageVariantType | Qwen3VariantType + | Krea2VariantType ]( ModelVariantType | ClipVariantType @@ -266,4 +282,5 @@ class FluxLoRAFormat(str, Enum): | ZImageVariantType | QwenImageVariantType | Qwen3VariantType + | Krea2VariantType ) diff --git a/invokeai/backend/patches/lora_conversions/krea2_lora_constants.py b/invokeai/backend/patches/lora_conversions/krea2_lora_constants.py new file mode 100644 index 00000000000..07dfa12e36a --- /dev/null +++ b/invokeai/backend/patches/lora_conversions/krea2_lora_constants.py @@ -0,0 +1,8 @@ +# Krea-2 LoRA prefix constants. +# These prefixes namespace LoRA patch keys when applying them to Krea-2 models. + +# Prefix for Krea-2 transformer (Krea2Transformer2DModel) LoRA layers. +KREA2_LORA_TRANSFORMER_PREFIX = "lora_transformer-" + +# Prefix for Krea-2 Qwen3-VL text encoder LoRA layers. +KREA2_LORA_QWEN3VL_PREFIX = "lora_qwen3vl-" diff --git a/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py new file mode 100644 index 00000000000..f77fc7ca5ea --- /dev/null +++ b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py @@ -0,0 +1,124 @@ +"""Krea-2 LoRA conversion utilities. + +Krea-2 uses a single-stream MMDiT (``Krea2Transformer2DModel``) with a Qwen3-VL text encoder. +Published LoRAs (e.g. krea/Krea-2-LoRA-*) are diffusers PEFT format: keys like +``transformer..lora_A.weight`` / ``lora_B.weight``. The distinctive Krea-2 module is the +``text_fusion`` stage, which we use to disambiguate from Qwen-Image / Z-Image LoRAs (which otherwise +share the ``transformer.transformer_blocks.`` prefix). +""" + +from typing import Dict + +import torch + +from invokeai.backend.patches.layers.base_layer_patch import BaseLayerPatch +from invokeai.backend.patches.layers.utils import any_lora_layer_from_state_dict +from invokeai.backend.patches.lora_conversions.krea2_lora_constants import ( + KREA2_LORA_QWEN3VL_PREFIX, + KREA2_LORA_TRANSFORMER_PREFIX, +) +from invokeai.backend.patches.model_patch_raw import ModelPatchRaw + +# Module-name fragments unique to the Krea-2 transformer (text-fusion stage + timestep modulation proj). +KREA2_TRANSFORMER_SIGNATURE_KEYS = ("text_fusion", "time_mod_proj") + + +def is_state_dict_likely_krea2_lora(state_dict: dict[str | int, torch.Tensor]) -> bool: + """Checks if the provided state dict is likely a Krea-2 LoRA. + + Requires the distinctive Krea-2 ``text_fusion`` / ``time_mod_proj`` modules so it does not + false-match Qwen-Image or Z-Image LoRAs that also carry ``transformer.transformer_blocks.`` keys. + """ + str_keys = [k for k in state_dict.keys() if isinstance(k, str)] + has_krea2_module = any(any(sig in k for sig in KREA2_TRANSFORMER_SIGNATURE_KEYS) for k in str_keys) + has_lora_suffix = any( + k.endswith((".lora_A.weight", ".lora_B.weight", ".lora_down.weight", ".lora_up.weight")) for k in str_keys + ) + return has_krea2_module and has_lora_suffix + + +def lora_model_from_krea2_state_dict(state_dict: Dict[str, torch.Tensor], alpha: float | None = None) -> ModelPatchRaw: + """Convert a Krea-2 LoRA state dict (diffusers PEFT) to a ModelPatchRaw. + + Handles transformer layers and (if present) Qwen3-VL text encoder layers. ``alpha=None`` is treated + as ``alpha=rank`` internally (the common diffusers default). + """ + layers: dict[str, BaseLayerPatch] = {} + grouped_state_dict = _group_by_layer(state_dict) + + transformer_prefixes = ( + "base_model.model.transformer.", + "transformer.", + "diffusion_model.", + ) + text_encoder_prefixes = ( + "base_model.model.text_encoder.", + "text_encoder.", + ) + + for layer_key, layer_dict in grouped_state_dict.items(): + values = _get_lora_layer_values(layer_dict, alpha) + + is_text_encoder = False + clean_key = layer_key + for prefix in text_encoder_prefixes: + if layer_key.startswith(prefix): + clean_key = layer_key[len(prefix) :] + is_text_encoder = True + break + if not is_text_encoder: + for prefix in transformer_prefixes: + if layer_key.startswith(prefix): + clean_key = layer_key[len(prefix) :] + break + + if is_text_encoder: + final_key = f"{KREA2_LORA_QWEN3VL_PREFIX}{clean_key}" + else: + final_key = f"{KREA2_LORA_TRANSFORMER_PREFIX}{clean_key}" + + layers[final_key] = any_lora_layer_from_state_dict(values) + + return ModelPatchRaw(layers=layers) + + +def _get_lora_layer_values(layer_dict: dict[str, torch.Tensor], alpha: float | None) -> dict[str, torch.Tensor]: + """Convert PEFT (lora_A/lora_B) layer values to internal (lora_down/lora_up) format.""" + if "lora_A.weight" in layer_dict: + values = { + "lora_down.weight": layer_dict["lora_A.weight"], + "lora_up.weight": layer_dict["lora_B.weight"], + } + if alpha is not None: + values["alpha"] = torch.tensor(alpha) + return values + return layer_dict + + +def _group_by_layer(state_dict: Dict[str, torch.Tensor]) -> dict[str, dict[str, torch.Tensor]]: + """Groups state dict keys by layer path, splitting off the LoRA weight suffix.""" + known_suffixes = [ + ".lora_A.weight", + ".lora_B.weight", + ".lora_down.weight", + ".lora_up.weight", + ".dora_scale", + ".alpha", + ] + layer_dict: dict[str, dict[str, torch.Tensor]] = {} + for key in state_dict: + if not isinstance(key, str): + continue + layer_name = None + key_name = None + for suffix in known_suffixes: + if key.endswith(suffix): + layer_name = key[: -len(suffix)] + key_name = suffix[1:] + break + if layer_name is None: + parts = key.rsplit(".", maxsplit=2) + layer_name = parts[0] + key_name = ".".join(parts[1:]) + layer_dict.setdefault(layer_name, {})[key_name] = state_dict[key] + return layer_dict diff --git a/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py b/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py index 6a9959f1e87..e84d3a313d9 100644 --- a/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py +++ b/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py @@ -105,6 +105,28 @@ def to(self, device: torch.device | None = None, dtype: torch.dtype | None = Non return self +@dataclass +class Krea2ConditioningInfo: + """Krea-2 text conditioning from the Qwen3-VL encoder. + + Krea-2 taps 12 decoder hidden-state layers and stacks them per token, so prompt_embeds keeps a + layer axis (the transformer's text-fusion stage consumes it). This is unique vs Z-Image (2D) and + Qwen-Image (3D). + """ + + prompt_embeds: torch.Tensor + """Stacked Qwen3-VL hidden states. Shape: (batch_size, seq_len, num_text_layers=12, hidden=2560).""" + + prompt_embeds_mask: torch.Tensor | None = None + """Attention mask for prompt_embeds. Shape: (batch_size, seq_len). 1/True for valid, 0/False for padding.""" + + def to(self, device: torch.device | None = None, dtype: torch.dtype | None = None): + self.prompt_embeds = self.prompt_embeds.to(device=device, dtype=dtype) + if self.prompt_embeds_mask is not None: + self.prompt_embeds_mask = self.prompt_embeds_mask.to(device=device) + return self + + @dataclass class AnimaConditioningInfo: """Anima text conditioning information from Qwen3 0.6B encoder + T5-XXL tokenizer. @@ -143,6 +165,7 @@ class ConditioningFieldData: | List[CogView4ConditioningInfo] | List[ZImageConditioningInfo] | List[QwenImageConditioningInfo] + | List[Krea2ConditioningInfo] | List[AnimaConditioningInfo] ) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 75367a502db..b1ec796c983 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1355,6 +1355,7 @@ "t5Encoder": "T5 Encoder", "qwen3Encoder": "Qwen3 Encoder", "qwenVLEncoder": "Qwen2.5-VL Encoder", + "qwen3VLEncoder": "Qwen3-VL Encoder", "animaVae": "VAE", "animaVaePlaceholder": "Select Anima-compatible VAE", "animaQwen3Encoder": "Qwen3 0.6B Encoder", @@ -1730,6 +1731,9 @@ "seedVarianceEnabled": "Seed Variance Enhancer", "seedVarianceStrength": "Variance Strength", "seedVarianceRandomizePercent": "Randomize Percent", + "krea2RebalanceEnabled": "Conditioning Rebalance", + "krea2RebalanceMultiplier": "Rebalance Multiplier", + "krea2RebalanceWeights": "Per-Layer Weights (12)", "imageActions": "Image Actions", "sendToCanvas": "Send To Canvas", "sendToUpscale": "Send To Upscale", @@ -2057,6 +2061,48 @@ "Lower values create more selective noise patterns, while 100% affects all values equally." ] }, + "krea2ConditioningRebalance": { + "heading": "Conditioning Rebalance", + "paragraphs": [ + "Krea-2 stacks 12 text-encoder layers per token. This reweights those layers and applies an overall multiplier to push the model harder toward your prompt, countering the quality dilution of the distilled Turbo model.", + "Enable this to improve prompt adherence when the model ignores parts of your prompt." + ] + }, + "krea2RebalanceMultiplier": { + "heading": "Rebalance Multiplier", + "paragraphs": [ + "Overall gain applied to the conditioning after per-layer weighting. Higher values push harder toward the prompt.", + "Default is 4.0. Very high values may over-saturate or distort the output." + ] + }, + "krea2RebalanceWeights": { + "heading": "Per-Layer Weights", + "paragraphs": [ + "Comma-separated gains for the 12 tapped encoder layers (exactly 12 values). Later layers carry more semantic detail.", + "The default emphasizes specific layers (e.g. 2.5, 5, 4) found to improve prompt adherence." + ] + }, + "krea2SeedVarianceEnhancer": { + "heading": "Seed Variance Enhancer", + "paragraphs": [ + "Distilled few-step models like Krea-2-Turbo can produce nearly identical images across different seeds. This adds seed-based noise to the text embeddings to increase variation while staying reproducible.", + "Enable this to get more diverse results when exploring seeds, at some cost to prompt adherence." + ] + }, + "krea2SeedVarianceStrength": { + "heading": "Variance Strength", + "paragraphs": [ + "Magnitude of the uniform noise added to the embeddings.", + "Higher values give more variety but can drift further from the prompt. Default is 20." + ] + }, + "krea2SeedVarianceRandomizePercent": { + "heading": "Randomize Percent", + "paragraphs": [ + "Percentage of embedding values that receive noise (1-100%).", + "Lower values create more selective perturbations, while 100% affects all values." + ] + }, "compositingMaskBlur": { "heading": "Mask Blur", "paragraphs": ["The blur radius of the mask."] diff --git a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts index e9d855648ad..2a55c964381 100644 --- a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts +++ b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts @@ -13,6 +13,12 @@ export type Feature = | 'seedVarianceEnhancer' | 'seedVarianceStrength' | 'seedVarianceRandomizePercent' + | 'krea2ConditioningRebalance' + | 'krea2RebalanceMultiplier' + | 'krea2RebalanceWeights' + | 'krea2SeedVarianceEnhancer' + | 'krea2SeedVarianceStrength' + | 'krea2SeedVarianceRandomizePercent' | 'compositingMaskBlur' | 'compositingBlurMethod' | 'compositingCoherencePass' diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts index c4c90cf98e7..7d398b0dcff 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts @@ -107,6 +107,24 @@ const slice = createSlice({ setZImageSeedVarianceRandomizePercent: (state, action: PayloadAction) => { state.zImageSeedVarianceRandomizePercent = action.payload; }, + setKrea2SeedVarianceEnabled: (state, action: PayloadAction) => { + state.krea2SeedVarianceEnabled = action.payload; + }, + setKrea2SeedVarianceStrength: (state, action: PayloadAction) => { + state.krea2SeedVarianceStrength = action.payload; + }, + setKrea2SeedVarianceRandomizePercent: (state, action: PayloadAction) => { + state.krea2SeedVarianceRandomizePercent = action.payload; + }, + setKrea2RebalanceEnabled: (state, action: PayloadAction) => { + state.krea2RebalanceEnabled = action.payload; + }, + setKrea2RebalanceMultiplier: (state, action: PayloadAction) => { + state.krea2RebalanceMultiplier = action.payload; + }, + setKrea2RebalanceWeights: (state, action: PayloadAction) => { + state.krea2RebalanceWeights = action.payload; + }, setUpscaleScheduler: (state, action: PayloadAction) => { state.upscaleScheduler = action.payload; }, @@ -648,6 +666,12 @@ export const { setZImageSeedVarianceEnabled, setZImageSeedVarianceStrength, setZImageSeedVarianceRandomizePercent, + setKrea2SeedVarianceEnabled, + setKrea2SeedVarianceStrength, + setKrea2SeedVarianceRandomizePercent, + setKrea2RebalanceEnabled, + setKrea2RebalanceMultiplier, + setKrea2RebalanceWeights, setUpscaleScheduler, setUpscaleCfgScale, setSeed, @@ -762,6 +786,7 @@ export const selectIsAnima = createParamsSelector((params) => params.model?.base export const selectIsFlux2 = createParamsSelector((params) => params.model?.base === 'flux2'); export const selectIsExternal = createParamsSelector((params) => params.model?.base === 'external'); export const selectIsQwenImage = createParamsSelector((params) => params.model?.base === 'qwen-image'); +export const selectIsKrea2 = createParamsSelector((params) => params.model?.base === 'krea-2'); export const selectIsFluxKontext = createParamsSelector((params) => { if (params.model?.base === 'flux' && params.model?.name.toLowerCase().includes('kontext')) { return true; @@ -911,6 +936,14 @@ export const selectZImageSeedVarianceStrength = createParamsSelector((params) => export const selectZImageSeedVarianceRandomizePercent = createParamsSelector( (params) => params.zImageSeedVarianceRandomizePercent ); +export const selectKrea2SeedVarianceEnabled = createParamsSelector((params) => params.krea2SeedVarianceEnabled); +export const selectKrea2SeedVarianceStrength = createParamsSelector((params) => params.krea2SeedVarianceStrength); +export const selectKrea2SeedVarianceRandomizePercent = createParamsSelector( + (params) => params.krea2SeedVarianceRandomizePercent +); +export const selectKrea2RebalanceEnabled = createParamsSelector((params) => params.krea2RebalanceEnabled); +export const selectKrea2RebalanceMultiplier = createParamsSelector((params) => params.krea2RebalanceMultiplier); +export const selectKrea2RebalanceWeights = createParamsSelector((params) => params.krea2RebalanceWeights); export const selectSeamlessXAxis = createParamsSelector((params) => params.seamlessXAxis); export const selectSeamlessYAxis = createParamsSelector((params) => params.seamlessYAxis); export const selectSeed = createParamsSelector((params) => params.seed); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 09ce177ab0f..53caca55eb2 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -854,6 +854,13 @@ export const zParamsState = z.object({ zImageSeedVarianceEnabled: z.boolean(), zImageSeedVarianceStrength: z.number().min(0).max(2), zImageSeedVarianceRandomizePercent: z.number().min(1).max(100), + // Krea-2 conditioning enhancers (optional; both default off so stock behaviour is unchanged) + krea2SeedVarianceEnabled: z.boolean(), + krea2SeedVarianceStrength: z.number().min(0).max(100), + krea2SeedVarianceRandomizePercent: z.number().min(1).max(100), + krea2RebalanceEnabled: z.boolean(), + krea2RebalanceMultiplier: z.number().min(0).max(20), + krea2RebalanceWeights: z.string(), imageSize: z.string().nullable().default(null), // OpenAI-specific external options openaiQuality: z.enum(['auto', 'high', 'medium', 'low']).default('auto'), @@ -937,6 +944,12 @@ export const getInitialParamsState = (): ParamsState => ({ zImageSeedVarianceEnabled: false, zImageSeedVarianceStrength: 0.1, zImageSeedVarianceRandomizePercent: 50, + krea2SeedVarianceEnabled: false, + krea2SeedVarianceStrength: 20, + krea2SeedVarianceRandomizePercent: 50, + krea2RebalanceEnabled: false, + krea2RebalanceMultiplier: 4, + krea2RebalanceWeights: '1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0', imageSize: null, openaiQuality: 'auto', openaiBackground: 'auto', diff --git a/invokeai/frontend/web/src/features/modelManagerV2/models.ts b/invokeai/frontend/web/src/features/modelManagerV2/models.ts index cf295c9af6a..e5bdf0412d4 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/models.ts +++ b/invokeai/frontend/web/src/features/modelManagerV2/models.ts @@ -13,6 +13,7 @@ import { isLoRAModelConfig, isNonRefinerMainModelConfig, isQwen3EncoderModelConfig, + isQwen3VLEncoderModelConfig, isQwenVLEncoderModelConfig, isRefinerMainModelModelConfig, isSigLipModelConfig, @@ -85,6 +86,11 @@ const MODEL_CATEGORIES: Record = { i18nKey: 'modelManager.qwenVLEncoder', filter: isQwenVLEncoderModelConfig, }, + qwen3_vl_encoder: { + category: 'qwen3_vl_encoder', + i18nKey: 'modelManager.qwen3VLEncoder', + filter: isQwen3VLEncoderModelConfig, + }, control_lora: { category: 'control_lora', i18nKey: 'modelManager.controlLora', @@ -163,6 +169,7 @@ export const MODEL_BASE_TO_COLOR: Record = { cogview4: 'red', 'qwen-image': 'orange', 'z-image': 'cyan', + 'krea-2': 'pink', external: 'orange', anima: 'invokePurple', unknown: 'red', @@ -187,6 +194,7 @@ export const MODEL_TYPE_TO_LONG_NAME: Record = { t5_encoder: 'T5 Encoder', qwen3_encoder: 'Qwen3 Encoder', qwen_vl_encoder: 'Qwen2.5-VL Encoder', + qwen3_vl_encoder: 'Qwen3-VL Encoder', clip_embed: 'CLIP Embed', siglip: 'SigLIP', flux_redux: 'FLUX Redux', @@ -210,6 +218,7 @@ export const MODEL_BASE_TO_LONG_NAME: Record = { cogview4: 'CogView4', 'qwen-image': 'Qwen Image', 'z-image': 'Z-Image', + 'krea-2': 'Krea-2', external: 'External', anima: 'Anima', unknown: 'Unknown', @@ -230,6 +239,7 @@ export const MODEL_BASE_TO_SHORT_NAME: Record = { cogview4: 'CogView4', 'qwen-image': 'QwenImg', 'z-image': 'Z-Image', + 'krea-2': 'Krea-2', external: 'External', anima: 'Anima', unknown: 'Unknown', @@ -248,6 +258,7 @@ export const MODEL_VARIANT_TO_LONG_NAME: Record = { klein_9b_base: 'FLUX.2 Klein 9B Base', turbo: 'Z-Image Turbo', zbase: 'Z-Image Base', + krea2_turbo: 'Krea-2 Turbo', large: 'CLIP L', gigantic: 'CLIP G', generate: 'Qwen Image', @@ -271,6 +282,7 @@ export const MODEL_FORMAT_TO_LONG_NAME: Record = { t5_encoder: 'T5 Encoder', qwen3_encoder: 'Qwen3 Encoder', qwen_vl_encoder: 'Qwen2.5-VL Encoder', + qwen3_vl_encoder: 'Qwen3-VL Encoder', bnb_quantized_int8b: 'BNB Quantized (int8b)', bnb_quantized_nf4b: 'BNB Quantized (nf4b)', gguf_quantized: 'GGUF Quantized', diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelFormatBadge.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelFormatBadge.tsx index 71d2efe0e45..56bcc4c3afb 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelFormatBadge.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelFormatBadge.tsx @@ -16,6 +16,7 @@ const FORMAT_NAME_MAP: Record = { t5_encoder: 't5_encoder', qwen3_encoder: 'qwen3_encoder', qwen_vl_encoder: 'qwen_vl_encoder', + qwen3_vl_encoder: 'qwen3_vl_encoder', bnb_quantized_int8b: 'bnb_quantized_int8b', bnb_quantized_nf4b: 'quantized', gguf_quantized: 'gguf', @@ -37,6 +38,7 @@ const FORMAT_COLOR_MAP: Record = { t5_encoder: 'base', qwen3_encoder: 'base', qwen_vl_encoder: 'base', + qwen3_vl_encoder: 'base', bnb_quantized_int8b: 'base', bnb_quantized_nf4b: 'base', gguf_quantized: 'base', diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index fb2a1ce946a..3ee19c0600d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -98,6 +98,7 @@ export const zBaseModelType = z.enum([ 'cogview4', 'qwen-image', 'z-image', + 'krea-2', 'external', 'anima', 'unknown', @@ -113,6 +114,7 @@ export const zMainModelBase = z.enum([ 'cogview4', 'qwen-image', 'z-image', + 'krea-2', 'anima', ]); type MainModelBase = z.infer; @@ -134,6 +136,7 @@ export const zModelType = z.enum([ 't5_encoder', 'qwen3_encoder', 'qwen_vl_encoder', + 'qwen3_vl_encoder', 'clip_embed', 'siglip', 'flux_redux', @@ -162,6 +165,7 @@ export const zModelVariantType = z.enum(['normal', 'inpaint', 'depth']); export const zFluxVariantType = z.enum(['dev', 'dev_fill', 'schnell']); export const zFlux2VariantType = z.enum(['klein_4b', 'klein_4b_base', 'klein_9b', 'klein_9b_base']); export const zZImageVariantType = z.enum(['turbo', 'zbase']); +export const zKrea2VariantType = z.enum(['krea2_turbo']); const zQwenImageVariantType = z.enum(['generate', 'edit']); export const zQwen3VariantType = z.enum(['qwen3_4b', 'qwen3_8b', 'qwen3_06b']); export const zAnyModelVariant = z.union([ @@ -170,6 +174,7 @@ export const zAnyModelVariant = z.union([ zFluxVariantType, zFlux2VariantType, zZImageVariantType, + zKrea2VariantType, zQwenImageVariantType, zQwen3VariantType, ]); @@ -187,6 +192,7 @@ export const zModelFormat = z.enum([ 't5_encoder', 'qwen3_encoder', 'qwen_vl_encoder', + 'qwen3_vl_encoder', 'bnb_quantized_int8b', 'bnb_quantized_nf4b', 'gguf_quantized', diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts index f17ff970f27..bf7137013ac 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts @@ -71,6 +71,7 @@ export const addImageToImage = async ({ denoise.type === 'flux2_denoise' || denoise.type === 'sd3_denoise' || denoise.type === 'z_image_denoise' || + denoise.type === 'krea2_denoise' || denoise.type === 'anima_denoise' ) { denoise.width = scaledSize.width; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts index fa01db67e60..20a88695181 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts @@ -69,6 +69,7 @@ export const addInpaint = async ({ denoise.type === 'flux2_denoise' || denoise.type === 'sd3_denoise' || denoise.type === 'z_image_denoise' || + denoise.type === 'krea2_denoise' || denoise.type === 'anima_denoise' ) { denoise.width = scaledSize.width; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.ts new file mode 100644 index 00000000000..4fe06628282 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.ts @@ -0,0 +1,68 @@ +import type { RootState } from 'app/store/store'; +import { getPrefixedId } from 'features/controlLayers/konva/util'; +import { zModelIdentifierField } from 'features/nodes/types/common'; +import type { Graph } from 'features/nodes/util/graph/generation/Graph'; +import type { Invocation, S } from 'services/api/types'; + +export const addKrea2LoRAs = ( + state: RootState, + g: Graph, + denoise: Invocation<'krea2_denoise'>, + modelLoader: Invocation<'krea2_model_loader'>, + posCond: Invocation<'krea2_text_encoder'>, + negCond: Invocation<'krea2_text_encoder'> | null +): void => { + const enabledLoRAs = state.loras.loras.filter((l) => l.isEnabled && l.model.base === 'krea-2'); + const loraCount = enabledLoRAs.length; + + if (loraCount === 0) { + return; + } + + const loraMetadata: S['LoRAMetadataField'][] = []; + + // Collect LoRAs into a collection node, then apply them all via the collection loader, which reroutes + // the transformer and Qwen3-VL encoder through itself. + const loraCollector = g.addNode({ + id: getPrefixedId('lora_collector'), + type: 'collect', + }); + const loraCollectionLoader = g.addNode({ + type: 'krea2_lora_collection_loader', + id: getPrefixedId('krea2_lora_collection_loader'), + }); + + g.addEdge(loraCollector, 'collection', loraCollectionLoader, 'loras'); + g.addEdge(modelLoader, 'transformer', loraCollectionLoader, 'transformer'); + g.addEdge(modelLoader, 'qwen3_vl_encoder', loraCollectionLoader, 'qwen3_vl_encoder'); + // Reroute model connections through the LoRA collection loader. + g.deleteEdgesTo(denoise, ['transformer']); + g.deleteEdgesTo(posCond, ['qwen3_vl_encoder']); + g.addEdge(loraCollectionLoader, 'transformer', denoise, 'transformer'); + g.addEdge(loraCollectionLoader, 'qwen3_vl_encoder', posCond, 'qwen3_vl_encoder'); + if (negCond !== null) { + g.deleteEdgesTo(negCond, ['qwen3_vl_encoder']); + g.addEdge(loraCollectionLoader, 'qwen3_vl_encoder', negCond, 'qwen3_vl_encoder'); + } + + for (const lora of enabledLoRAs) { + const { weight } = lora; + const parsedModel = zModelIdentifierField.parse(lora.model); + + const loraSelector = g.addNode({ + type: 'lora_selector', + id: getPrefixedId('lora_selector'), + lora: parsedModel, + weight, + }); + + loraMetadata.push({ + model: parsedModel, + weight, + }); + + g.addEdge(loraSelector, 'lora', loraCollector, 'item'); + } + + g.upsertMetadata({ loras: loraMetadata }); +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts index 0c57087eaad..14233f49e13 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts @@ -62,6 +62,7 @@ export const addOutpaint = async ({ denoise.type === 'flux2_denoise' || denoise.type === 'sd3_denoise' || denoise.type === 'z_image_denoise' || + denoise.type === 'krea2_denoise' || denoise.type === 'anima_denoise' ) { denoise.width = scaledSize.width; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts index 06ece522da5..654b3167296 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts @@ -44,6 +44,7 @@ export const addTextToImage = ({ denoise.type === 'flux2_denoise' || denoise.type === 'sd3_denoise' || denoise.type === 'z_image_denoise' || + denoise.type === 'krea2_denoise' || denoise.type === 'anima_denoise' ) { denoise.width = scaledSize.width; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts new file mode 100644 index 00000000000..62f476a61ea --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts @@ -0,0 +1,231 @@ +import { logger } from 'app/logging/logger'; +import { getPrefixedId } from 'features/controlLayers/konva/util'; +import { selectMainModelConfig, selectParamsSlice } from 'features/controlLayers/store/paramsSlice'; +import { selectCanvasMetadata } from 'features/controlLayers/store/selectors'; +import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers'; +import { addImageToImage } from 'features/nodes/util/graph/generation/addImageToImage'; +import { addInpaint } from 'features/nodes/util/graph/generation/addInpaint'; +import { addKrea2LoRAs } from 'features/nodes/util/graph/generation/addKrea2LoRAs'; +import { addNSFWChecker } from 'features/nodes/util/graph/generation/addNSFWChecker'; +import { addOutpaint } from 'features/nodes/util/graph/generation/addOutpaint'; +import { addTextToImage } from 'features/nodes/util/graph/generation/addTextToImage'; +import { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker'; +import { Graph } from 'features/nodes/util/graph/generation/Graph'; +import { selectCanvasOutputFields, selectPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import type { GraphBuilderArg, GraphBuilderReturn, ImageOutputNodes } from 'features/nodes/util/graph/types'; +import { selectActiveTab } from 'features/ui/store/uiSelectors'; +import type { Invocation } from 'services/api/types'; +import { isNonRefinerMainModelConfig } from 'services/api/types'; +import type { Equals } from 'tsafe'; +import { assert } from 'tsafe'; + +const log = logger('system'); + +export const buildKrea2Graph = async (arg: GraphBuilderArg): Promise => { + const { generationMode, state, manager } = arg; + + log.debug({ generationMode, manager: manager?.id }, 'Building Krea-2 graph'); + + const model = selectMainModelConfig(state); + assert(model, 'No model selected'); + assert(model.base === 'krea-2', 'Selected model is not a Krea-2 model'); + // The VAE (Qwen-Image VAE) and Qwen3-VL encoder are extracted from the diffusers pipeline. + assert(model.format === 'diffusers', 'Krea-2 currently requires a Diffusers-format model'); + + const params = selectParamsSlice(state); + // Krea-2-Turbo uses the standard CFG convention; cfg_scale defaults to 1.0 (no CFG) for the distilled model. + const { + cfgScale: cfg_scale, + steps, + krea2RebalanceEnabled, + krea2RebalanceMultiplier, + krea2RebalanceWeights, + krea2SeedVarianceEnabled, + krea2SeedVarianceStrength, + krea2SeedVarianceRandomizePercent, + } = params; + + const prompts = selectPresetModifiedPrompts(state); + + const g = new Graph(getPrefixedId('krea2_graph')); + + const modelLoader = g.addNode({ + type: 'krea2_model_loader', + id: getPrefixedId('krea2_model_loader'), + model, + }); + + const positivePrompt = g.addNode({ + id: getPrefixedId('positive_prompt'), + type: 'string', + }); + const posCond = g.addNode({ + type: 'krea2_text_encoder', + id: getPrefixedId('pos_prompt'), + }); + + // Krea-2 supports negative conditioning only when CFG is enabled (cfg_scale > 1). + let negCond: Invocation<'krea2_text_encoder'> | null = null; + if (cfg_scale > 1) { + negCond = g.addNode({ + type: 'krea2_text_encoder', + id: getPrefixedId('neg_prompt'), + prompt: prompts.negative, + }); + } + + const seed = g.addNode({ + id: getPrefixedId('seed'), + type: 'integer', + }); + const denoise = g.addNode({ + type: 'krea2_denoise', + id: getPrefixedId('denoise_latents'), + cfg_scale, + steps, + }); + // Krea-2 decodes with the Qwen-Image VAE, so reuse the Qwen-Image latents-to-image node. + const l2i = g.addNode({ + type: 'qwen_image_l2i', + id: getPrefixedId('l2i'), + }); + + g.addEdge(modelLoader, 'transformer', denoise, 'transformer'); + g.addEdge(modelLoader, 'qwen3_vl_encoder', posCond, 'qwen3_vl_encoder'); + g.addEdge(modelLoader, 'vae', l2i, 'vae'); + + g.addEdge(positivePrompt, 'value', posCond, 'prompt'); + + // Optional conditioning enhancers between the text encoder and denoise. Both default OFF (params), so + // by default the conditioning flows straight through and stock Krea-2 behaviour is unchanged. Order: + // rebalance (scale the signal toward the prompt) first, then seed variance (perturb for variety). + if (krea2RebalanceEnabled) { + const rebalance = g.addNode({ + type: 'krea2_conditioning_rebalance', + id: getPrefixedId('krea2_rebalance'), + multiplier: krea2RebalanceMultiplier, + per_layer_weights: krea2RebalanceWeights, + }); + g.addEdge(posCond, 'conditioning', rebalance, 'conditioning'); + + if (krea2SeedVarianceEnabled && krea2SeedVarianceStrength > 0) { + const seedVariance = g.addNode({ + type: 'krea2_seed_variance', + id: getPrefixedId('krea2_seed_variance'), + strength: krea2SeedVarianceStrength, + randomize_percent: krea2SeedVarianceRandomizePercent, + }); + g.addEdge(rebalance, 'conditioning', seedVariance, 'conditioning'); + g.addEdge(seed, 'value', seedVariance, 'variance_seed'); + g.addEdge(seedVariance, 'conditioning', denoise, 'positive_conditioning'); + } else { + g.addEdge(rebalance, 'conditioning', denoise, 'positive_conditioning'); + } + } else if (krea2SeedVarianceEnabled && krea2SeedVarianceStrength > 0) { + const seedVariance = g.addNode({ + type: 'krea2_seed_variance', + id: getPrefixedId('krea2_seed_variance'), + strength: krea2SeedVarianceStrength, + randomize_percent: krea2SeedVarianceRandomizePercent, + }); + g.addEdge(posCond, 'conditioning', seedVariance, 'conditioning'); + g.addEdge(seed, 'value', seedVariance, 'variance_seed'); + g.addEdge(seedVariance, 'conditioning', denoise, 'positive_conditioning'); + } else { + g.addEdge(posCond, 'conditioning', denoise, 'positive_conditioning'); + } + + if (negCond !== null) { + g.addEdge(modelLoader, 'qwen3_vl_encoder', negCond, 'qwen3_vl_encoder'); + g.addEdge(negCond, 'conditioning', denoise, 'negative_conditioning'); + } + + g.addEdge(seed, 'value', denoise, 'seed'); + g.addEdge(denoise, 'latents', l2i, 'latents'); + + // Apply any enabled Krea-2 LoRAs (reroutes transformer + Qwen3-VL encoder through the collection loader). + addKrea2LoRAs(state, g, denoise, modelLoader, posCond, negCond); + + const modelConfig = await fetchModelConfigWithTypeGuard(model.key, isNonRefinerMainModelConfig); + assert(modelConfig.base === 'krea-2'); + + g.upsertMetadata({ + cfg_scale, + model: Graph.getModelMetadataField(modelConfig), + steps, + }); + // Only record a negative prompt when CFG is enabled (cfg_scale > 1). Krea-2-Turbo runs with CFG + // disabled by default, in which case there is no negative conditioning - recording it would surface a + // spurious (often empty) negative prompt on metadata recall. + if (cfg_scale > 1) { + g.upsertMetadata({ negative_prompt: prompts.negative }); + } + g.addEdgeToMetadata(seed, 'value', 'seed'); + g.addEdgeToMetadata(positivePrompt, 'value', 'positive_prompt'); + + let canvasOutput: Invocation = l2i; + + if (generationMode === 'txt2img') { + canvasOutput = addTextToImage({ g, state, denoise, l2i }); + g.upsertMetadata({ generation_mode: 'krea2_txt2img' }); + } else if (generationMode === 'img2img') { + assert(manager !== null); + const i2l = g.addNode({ type: 'qwen_image_i2l', id: getPrefixedId('qwen_image_i2l') }); + canvasOutput = await addImageToImage({ g, state, manager, denoise, l2i, i2l, vaeSource: modelLoader }); + g.upsertMetadata({ generation_mode: 'krea2_img2img' }); + } else if (generationMode === 'inpaint') { + assert(manager !== null); + const i2l = g.addNode({ type: 'qwen_image_i2l', id: getPrefixedId('qwen_image_i2l') }); + canvasOutput = await addInpaint({ + g, + state, + manager, + l2i, + i2l, + denoise, + vaeSource: modelLoader, + modelLoader, + seed, + }); + g.upsertMetadata({ generation_mode: 'krea2_inpaint' }); + } else if (generationMode === 'outpaint') { + assert(manager !== null); + const i2l = g.addNode({ type: 'qwen_image_i2l', id: getPrefixedId('qwen_image_i2l') }); + canvasOutput = await addOutpaint({ + g, + state, + manager, + l2i, + i2l, + denoise, + vaeSource: modelLoader, + modelLoader, + seed, + }); + g.upsertMetadata({ generation_mode: 'krea2_outpaint' }); + } else { + assert>(false); + } + + if (state.system.shouldUseNSFWChecker) { + canvasOutput = addNSFWChecker(g, canvasOutput); + } + + if (state.system.shouldUseWatermarker) { + canvasOutput = addWatermarker(g, canvasOutput); + } + + g.updateNode(canvasOutput, selectCanvasOutputFields(state)); + + if (selectActiveTab(state) === 'canvas') { + g.upsertMetadata(selectCanvasMetadata(state)); + } + + g.setMetadataReceivingNode(canvasOutput); + + return { + g, + seed, + positivePrompt, + }; +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts index 28aa74db5ec..354e5bac203 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts @@ -265,7 +265,8 @@ export const getDenoisingStartAndEnd = (state: RootState): { denoising_start: nu case 'sd-2': case 'cogview4': case 'qwen-image': - case 'z-image': { + case 'z-image': + case 'krea-2': { return { denoising_start: 1 - denoisingStrength, denoising_end: 1, diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/types.ts b/invokeai/frontend/web/src/features/nodes/util/graph/types.ts index d6a18f3f9c0..c95f08a0fcb 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/types.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/types.ts @@ -47,6 +47,7 @@ export type DenoiseLatentsNodes = | 'cogview4_denoise' | 'qwen_image_denoise' | 'z_image_denoise' + | 'krea2_denoise' | 'anima_denoise'; export type MainModelLoaderNodes = @@ -58,6 +59,7 @@ export type MainModelLoaderNodes = | 'cogview4_model_loader' | 'qwen_image_model_loader' | 'z_image_model_loader' + | 'krea2_model_loader' | 'anima_model_loader'; export type VaeSourceNodes = 'seamless' | 'vae_loader'; diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2EnhancersSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2EnhancersSettings.tsx new file mode 100644 index 00000000000..8e09b34510d --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2EnhancersSettings.tsx @@ -0,0 +1,38 @@ +import { Divider, Flex } from '@invoke-ai/ui-library'; +import { useAppSelector } from 'app/store/storeHooks'; +import { selectKrea2RebalanceEnabled, selectKrea2SeedVarianceEnabled } from 'features/controlLayers/store/paramsSlice'; +import { memo } from 'react'; + +import ParamKrea2RebalanceEnabled from './ParamKrea2RebalanceEnabled'; +import ParamKrea2RebalanceMultiplier from './ParamKrea2RebalanceMultiplier'; +import ParamKrea2RebalanceWeights from './ParamKrea2RebalanceWeights'; +import ParamKrea2SeedVarianceEnabled from './ParamKrea2SeedVarianceEnabled'; +import ParamKrea2SeedVarianceRandomizePercent from './ParamKrea2SeedVarianceRandomizePercent'; +import ParamKrea2SeedVarianceStrength from './ParamKrea2SeedVarianceStrength'; + +const ParamKrea2EnhancersSettings = () => { + const rebalanceEnabled = useAppSelector(selectKrea2RebalanceEnabled); + const seedVarianceEnabled = useAppSelector(selectKrea2SeedVarianceEnabled); + + return ( + + + {rebalanceEnabled && ( + <> + + + + )} + + + {seedVarianceEnabled && ( + <> + + + + )} + + ); +}; + +export default memo(ParamKrea2EnhancersSettings); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceEnabled.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceEnabled.tsx new file mode 100644 index 00000000000..85d879a79ca --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceEnabled.tsx @@ -0,0 +1,31 @@ +import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { selectKrea2RebalanceEnabled, setKrea2RebalanceEnabled } from 'features/controlLayers/store/paramsSlice'; +import type { ChangeEvent } from 'react'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const ParamKrea2RebalanceEnabled = () => { + const { t } = useTranslation(); + const enabled = useAppSelector(selectKrea2RebalanceEnabled); + const dispatch = useAppDispatch(); + + const handleChange = useCallback( + (e: ChangeEvent) => { + dispatch(setKrea2RebalanceEnabled(e.target.checked)); + }, + [dispatch] + ); + + return ( + + + {t('parameters.krea2RebalanceEnabled')} + + + + ); +}; + +export default memo(ParamKrea2RebalanceEnabled); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceMultiplier.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceMultiplier.tsx new file mode 100644 index 00000000000..a32ab73b302 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceMultiplier.tsx @@ -0,0 +1,54 @@ +import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { selectKrea2RebalanceMultiplier, setKrea2RebalanceMultiplier } from 'features/controlLayers/store/paramsSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const CONSTRAINTS = { + initial: 4, + sliderMin: 0, + sliderMax: 10, + numberInputMin: 0, + numberInputMax: 20, + fineStep: 0.1, + coarseStep: 0.5, +}; + +const MARKS = [0, 2.5, 5, 7.5, 10]; + +const ParamKrea2RebalanceMultiplier = () => { + const multiplier = useAppSelector(selectKrea2RebalanceMultiplier); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const onChange = useCallback((v: number) => dispatch(setKrea2RebalanceMultiplier(v)), [dispatch]); + + return ( + + + {t('parameters.krea2RebalanceMultiplier')} + + + + + ); +}; + +export default memo(ParamKrea2RebalanceMultiplier); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx new file mode 100644 index 00000000000..6622feb5e51 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx @@ -0,0 +1,31 @@ +import { FormControl, FormLabel, Input } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { selectKrea2RebalanceWeights, setKrea2RebalanceWeights } from 'features/controlLayers/store/paramsSlice'; +import type { ChangeEvent } from 'react'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const ParamKrea2RebalanceWeights = () => { + const { t } = useTranslation(); + const weights = useAppSelector(selectKrea2RebalanceWeights); + const dispatch = useAppDispatch(); + + const onChange = useCallback( + (e: ChangeEvent) => { + dispatch(setKrea2RebalanceWeights(e.target.value)); + }, + [dispatch] + ); + + return ( + + + {t('parameters.krea2RebalanceWeights')} + + + + ); +}; + +export default memo(ParamKrea2RebalanceWeights); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceEnabled.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceEnabled.tsx new file mode 100644 index 00000000000..a8e5e6875db --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceEnabled.tsx @@ -0,0 +1,31 @@ +import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { selectKrea2SeedVarianceEnabled, setKrea2SeedVarianceEnabled } from 'features/controlLayers/store/paramsSlice'; +import type { ChangeEvent } from 'react'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const ParamKrea2SeedVarianceEnabled = () => { + const { t } = useTranslation(); + const enabled = useAppSelector(selectKrea2SeedVarianceEnabled); + const dispatch = useAppDispatch(); + + const handleChange = useCallback( + (e: ChangeEvent) => { + dispatch(setKrea2SeedVarianceEnabled(e.target.checked)); + }, + [dispatch] + ); + + return ( + + + {t('parameters.seedVarianceEnabled')} + + + + ); +}; + +export default memo(ParamKrea2SeedVarianceEnabled); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceRandomizePercent.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceRandomizePercent.tsx new file mode 100644 index 00000000000..a0a4440d196 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceRandomizePercent.tsx @@ -0,0 +1,57 @@ +import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { + selectKrea2SeedVarianceRandomizePercent, + setKrea2SeedVarianceRandomizePercent, +} from 'features/controlLayers/store/paramsSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const CONSTRAINTS = { + initial: 50, + sliderMin: 1, + sliderMax: 100, + numberInputMin: 1, + numberInputMax: 100, + fineStep: 1, + coarseStep: 5, +}; + +const MARKS = [1, 25, 50, 75, 100]; + +const ParamKrea2SeedVarianceRandomizePercent = () => { + const randomizePercent = useAppSelector(selectKrea2SeedVarianceRandomizePercent); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const onChange = useCallback((v: number) => dispatch(setKrea2SeedVarianceRandomizePercent(v)), [dispatch]); + + return ( + + + {t('parameters.seedVarianceRandomizePercent')} + + + + + ); +}; + +export default memo(ParamKrea2SeedVarianceRandomizePercent); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceStrength.tsx new file mode 100644 index 00000000000..4c26de394b8 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2SeedVarianceStrength.tsx @@ -0,0 +1,57 @@ +import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import { + selectKrea2SeedVarianceStrength, + setKrea2SeedVarianceStrength, +} from 'features/controlLayers/store/paramsSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const CONSTRAINTS = { + initial: 20, + sliderMin: 0, + sliderMax: 50, + numberInputMin: 0, + numberInputMax: 100, + fineStep: 1, + coarseStep: 5, +}; + +const MARKS = [0, 10, 20, 30, 40, 50]; + +const ParamKrea2SeedVarianceStrength = () => { + const strength = useAppSelector(selectKrea2SeedVarianceStrength); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const onChange = useCallback((v: number) => dispatch(setKrea2SeedVarianceStrength(v)), [dispatch]); + + return ( + + + {t('parameters.seedVarianceStrength')} + + + + + ); +}; + +export default memo(ParamKrea2SeedVarianceStrength); diff --git a/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts b/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts index 2ac59a32e2b..820ed5e49e4 100644 --- a/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts +++ b/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts @@ -20,6 +20,7 @@ export const getOptimalDimension = (base?: BaseModelType | null): number => { case 'cogview4': case 'qwen-image': case 'z-image': + case 'krea-2': case 'anima': default: return 1024; @@ -78,6 +79,7 @@ export const getGridSize = (base?: BaseModelType | null): number => { case 'sd-3': case 'qwen-image': case 'z-image': + case 'krea-2': return 16; case 'sd-1': case 'sd-2': diff --git a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueCanvas.ts b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueCanvas.ts index 1229371b6e8..0e07ea2afd0 100644 --- a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueCanvas.ts +++ b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueCanvas.ts @@ -17,6 +17,7 @@ import { buildAnimaGraph } from 'features/nodes/util/graph/generation/buildAnima import { buildCogView4Graph } from 'features/nodes/util/graph/generation/buildCogView4Graph'; import { buildExternalGraph } from 'features/nodes/util/graph/generation/buildExternalGraph'; import { buildFLUXGraph } from 'features/nodes/util/graph/generation/buildFLUXGraph'; +import { buildKrea2Graph } from 'features/nodes/util/graph/generation/buildKrea2Graph'; import { buildQwenImageGraph } from 'features/nodes/util/graph/generation/buildQwenImageGraph'; import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph'; import { buildSD3Graph } from 'features/nodes/util/graph/generation/buildSD3Graph'; @@ -69,6 +70,8 @@ const enqueueCanvas = async (store: AppStore, canvasManager: CanvasManager, prep return await buildQwenImageGraph(graphBuilderArg); case 'z-image': return await buildZImageGraph(graphBuilderArg); + case 'krea-2': + return await buildKrea2Graph(graphBuilderArg); case 'external': return await buildExternalGraph(graphBuilderArg); case 'anima': diff --git a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueGenerate.ts b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueGenerate.ts index 8b0c30d924f..f030652557e 100644 --- a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueGenerate.ts +++ b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueGenerate.ts @@ -15,6 +15,7 @@ import { buildAnimaGraph } from 'features/nodes/util/graph/generation/buildAnima import { buildCogView4Graph } from 'features/nodes/util/graph/generation/buildCogView4Graph'; import { buildExternalGraph } from 'features/nodes/util/graph/generation/buildExternalGraph'; import { buildFLUXGraph } from 'features/nodes/util/graph/generation/buildFLUXGraph'; +import { buildKrea2Graph } from 'features/nodes/util/graph/generation/buildKrea2Graph'; import { buildQwenImageGraph } from 'features/nodes/util/graph/generation/buildQwenImageGraph'; import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph'; import { buildSD3Graph } from 'features/nodes/util/graph/generation/buildSD3Graph'; @@ -62,6 +63,8 @@ const enqueueGenerate = async (store: AppStore, prepend: boolean) => { return await buildQwenImageGraph(graphBuilderArg); case 'z-image': return await buildZImageGraph(graphBuilderArg); + case 'krea-2': + return await buildKrea2Graph(graphBuilderArg); case 'external': return await buildExternalGraph(graphBuilderArg); case 'anima': diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx index bfb69b945c8..eb989f4b109 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx @@ -8,6 +8,7 @@ import { selectIsExternal, selectIsFLUX, selectIsFlux2, + selectIsKrea2, selectIsQwenImage, selectIsSD3, selectIsZImage, @@ -54,43 +55,47 @@ export const AdvancedSettingsAccordion = memo(() => { const isExternal = useAppSelector(selectIsExternal); const isQwenImage = useAppSelector(selectIsQwenImage); const isAnima = useAppSelector(selectIsAnima); + const isKrea2 = useAppSelector(selectIsKrea2); const selectBadges = useMemo( () => - createMemoizedSelector([selectParamsSlice, selectIsFLUX, selectIsFlux2], (params, isFLUX, isFlux2) => { - const badges: (string | number)[] = []; - // FLUX.2 has VAE built into main model - no badge needed - if (isFLUX && !isFlux2) { - if (vaeConfig) { - let vaeBadge = vaeConfig.name; - if (params.vaePrecision === 'fp16') { - vaeBadge += ` ${params.vaePrecision}`; + createMemoizedSelector( + [selectParamsSlice, selectIsFLUX, selectIsFlux2, selectIsKrea2], + (params, isFLUX, isFlux2, isKrea2) => { + const badges: (string | number)[] = []; + // FLUX.2 has VAE built into main model - no badge needed + if (isFLUX && !isFlux2) { + if (vaeConfig) { + let vaeBadge = vaeConfig.name; + if (params.vaePrecision === 'fp16') { + vaeBadge += ` ${params.vaePrecision}`; + } + badges.push(vaeBadge); } - badges.push(vaeBadge); - } - } else if (!isFlux2) { - if (vaeConfig) { - let vaeBadge = vaeConfig.name; - if (params.vaePrecision === 'fp16') { - vaeBadge += ` ${params.vaePrecision}`; + } else if (!isFlux2 && !isKrea2) { + if (vaeConfig) { + let vaeBadge = vaeConfig.name; + if (params.vaePrecision === 'fp16') { + vaeBadge += ` ${params.vaePrecision}`; + } + badges.push(vaeBadge); + } else if (params.vaePrecision === 'fp16') { + badges.push(`VAE ${params.vaePrecision}`); + } + if (params.clipSkip) { + badges.push(`Skip ${params.clipSkip}`); + } + if (params.cfgRescaleMultiplier) { + badges.push(`Rescale ${params.cfgRescaleMultiplier}`); + } + if (params.seamlessXAxis || params.seamlessYAxis) { + badges.push('seamless'); } - badges.push(vaeBadge); - } else if (params.vaePrecision === 'fp16') { - badges.push(`VAE ${params.vaePrecision}`); - } - if (params.clipSkip) { - badges.push(`Skip ${params.clipSkip}`); - } - if (params.cfgRescaleMultiplier) { - badges.push(`Rescale ${params.cfgRescaleMultiplier}`); - } - if (params.seamlessXAxis || params.seamlessYAxis) { - badges.push('seamless'); } - } - return badges; - }), + return badges; + } + ), [vaeConfig] ); const badges = useAppSelector(selectBadges); @@ -107,13 +112,13 @@ export const AdvancedSettingsAccordion = memo(() => { return ( - {!isZImage && !isAnima && !isFlux2 && !isQwenImage && ( + {!isZImage && !isAnima && !isFlux2 && !isQwenImage && !isKrea2 && ( {isFLUX ? : } {!isFLUX && !isSD3 && } )} - {!isFLUX && !isFlux2 && !isSD3 && !isZImage && !isQwenImage && !isAnima && ( + {!isFLUX && !isFlux2 && !isSD3 && !isZImage && !isQwenImage && !isAnima && !isKrea2 && ( <> diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx index 220008a38b0..9a25ea5f23c 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx @@ -11,6 +11,7 @@ import { selectIsExternal, selectIsFLUX, selectIsFlux2, + selectIsKrea2, selectIsQwenImage, selectIsSD3, selectIsZImage, @@ -31,6 +32,7 @@ import ParamScheduler from 'features/parameters/components/Core/ParamScheduler'; import ParamSteps from 'features/parameters/components/Core/ParamSteps'; import ParamZImageScheduler from 'features/parameters/components/Core/ParamZImageScheduler'; import ParamZImageShift from 'features/parameters/components/Core/ParamZImageShift'; +import ParamKrea2EnhancersSettings from 'features/parameters/components/Krea2Enhancers/ParamKrea2EnhancersSettings'; import ParamZImageSeedVarianceSettings from 'features/parameters/components/SeedVariance/ParamZImageSeedVarianceSettings'; import { MainModelPicker } from 'features/settingsAccordions/components/GenerationSettingsAccordion/MainModelPicker'; import { useExpanderToggle } from 'features/settingsAccordions/hooks/useExpanderToggle'; @@ -54,6 +56,7 @@ export const GenerationSettingsAccordion = memo(() => { const isZImage = useAppSelector(selectIsZImage); const isExternal = useAppSelector(selectIsExternal); const isQwenImage = useAppSelector(selectIsQwenImage); + const isKrea2 = useAppSelector(selectIsKrea2); const isAnima = useAppSelector(selectIsAnima); const fluxDypePreset = useAppSelector(selectFluxDypePreset); const modelSupportsGuidance = useAppSelector(selectModelSupportsGuidance); @@ -121,6 +124,7 @@ export const GenerationSettingsAccordion = memo(() => { {!isExternal && isFLUX && fluxDypePreset === 'manual' && } {!isExternal && isZImage && } + {!isExternal && isKrea2 && } )} diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 822b3fd8ead..a7f915490b5 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -3557,7 +3557,7 @@ export type components = { */ type: "anima_text_encoder"; }; - 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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; /** * AppVersion * @description App Version Response @@ -3709,7 +3709,7 @@ export type components = { * fallback/null value `BaseModelType.Any` for these models, instead of making the model base optional. * @enum {string} */ - BaseModelType: "any" | "sd-1" | "sd-2" | "sd-3" | "sdxl" | "sdxl-refiner" | "flux" | "flux2" | "cogview4" | "z-image" | "external" | "qwen-image" | "anima" | "unknown"; + BaseModelType: "any" | "sd-1" | "sd-2" | "sd-3" | "sdxl" | "sdxl-refiner" | "flux" | "flux2" | "cogview4" | "z-image" | "external" | "qwen-image" | "anima" | "krea-2" | "unknown"; /** Batch */ Batch: { /** @@ -4360,7 +4360,6 @@ export type components = { /** * Resize To * @description Dimensions to resize the image to, must be stringified tuple of 2 integers. Max total pixel count: 16777216 - * @example "[1024,1024]" */ resize_to?: string | null; /** @@ -7556,7 +7555,7 @@ export type components = { * @description The generation mode that output this image * @default null */ - generation_mode?: ("txt2img" | "img2img" | "inpaint" | "outpaint" | "sdxl_txt2img" | "sdxl_img2img" | "sdxl_inpaint" | "sdxl_outpaint" | "flux_txt2img" | "flux_img2img" | "flux_inpaint" | "flux_outpaint" | "flux2_txt2img" | "flux2_img2img" | "flux2_inpaint" | "flux2_outpaint" | "sd3_txt2img" | "sd3_img2img" | "sd3_inpaint" | "sd3_outpaint" | "cogview4_txt2img" | "cogview4_img2img" | "cogview4_inpaint" | "cogview4_outpaint" | "z_image_txt2img" | "z_image_img2img" | "z_image_inpaint" | "z_image_outpaint" | "qwen_image_txt2img" | "qwen_image_img2img" | "qwen_image_inpaint" | "qwen_image_outpaint" | "anima_txt2img" | "anima_img2img" | "anima_inpaint" | "anima_outpaint") | null; + generation_mode?: ("txt2img" | "img2img" | "inpaint" | "outpaint" | "sdxl_txt2img" | "sdxl_img2img" | "sdxl_inpaint" | "sdxl_outpaint" | "flux_txt2img" | "flux_img2img" | "flux_inpaint" | "flux_outpaint" | "flux2_txt2img" | "flux2_img2img" | "flux2_inpaint" | "flux2_outpaint" | "sd3_txt2img" | "sd3_img2img" | "sd3_inpaint" | "sd3_outpaint" | "cogview4_txt2img" | "cogview4_img2img" | "cogview4_inpaint" | "cogview4_outpaint" | "z_image_txt2img" | "z_image_img2img" | "z_image_inpaint" | "z_image_outpaint" | "qwen_image_txt2img" | "qwen_image_img2img" | "qwen_image_inpaint" | "qwen_image_outpaint" | "anima_txt2img" | "anima_img2img" | "anima_inpaint" | "anima_outpaint" | "krea2_txt2img" | "krea2_img2img" | "krea2_inpaint" | "krea2_outpaint") | null; /** * Positive Prompt * @description The positive prompt parameter @@ -12276,7 +12275,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"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["Krea2TextEncoderInvocation"] | 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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; }; /** * Edges @@ -12313,7 +12312,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["AnimaConditioningOutput"] | 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"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | 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"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | 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"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | 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"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PromptTemplateOutput"] | 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"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; + [key: string]: components["schemas"]["AnimaConditioningOutput"] | 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"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | 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"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | 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"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | 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"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PromptTemplateOutput"] | 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"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; }; /** * Errors @@ -15674,7 +15673,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"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["Krea2TextEncoderInvocation"] | 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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -15684,7 +15683,7 @@ export type components = { * Result * @description The result of the invocation */ - result: components["schemas"]["AnimaConditioningOutput"] | 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"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | 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"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | 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"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | 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"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PromptTemplateOutput"] | 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"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; + result: components["schemas"]["AnimaConditioningOutput"] | 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"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | 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"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | 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"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | 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"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PromptTemplateOutput"] | 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"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; }; /** * InvocationErrorEvent @@ -15738,7 +15737,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"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["Krea2TextEncoderInvocation"] | 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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -15899,6 +15898,13 @@ export type components = { invokeai_img_val_thresholds: components["schemas"]["ImageOutput"]; ip_adapter: components["schemas"]["IPAdapterOutput"]; iterate: components["schemas"]["IterateInvocationOutput"]; + krea2_conditioning_rebalance: components["schemas"]["Krea2ConditioningOutput"]; + krea2_denoise: components["schemas"]["LatentsOutput"]; + krea2_lora_collection_loader: components["schemas"]["Krea2LoRALoaderOutput"]; + krea2_lora_loader: components["schemas"]["Krea2LoRALoaderOutput"]; + krea2_model_loader: components["schemas"]["Krea2ModelLoaderOutput"]; + krea2_seed_variance: components["schemas"]["Krea2ConditioningOutput"]; + krea2_text_encoder: components["schemas"]["Krea2ConditioningOutput"]; l2i: components["schemas"]["ImageOutput"]; latents: components["schemas"]["LatentsOutput"]; latents_collection: components["schemas"]["LatentsCollectionOutput"]; @@ -16069,7 +16075,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"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["Krea2TextEncoderInvocation"] | 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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -16144,7 +16150,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"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | 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"]["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"]["ExpandMaskWithFadeInvocation"] | 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"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | 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"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | 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"]["Krea2TextEncoderInvocation"] | 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"]["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"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | 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"]["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"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | 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"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -17271,6 +17277,506 @@ export type components = { type: "iterate_output"; }; JsonValue: unknown; + /** + * Krea2ConditioningField + * @description A Krea-2 conditioning tensor primitive value + */ + Krea2ConditioningField: { + /** + * Conditioning Name + * @description The name of conditioning tensor + */ + conditioning_name: string; + }; + /** + * Krea2ConditioningOutput + * @description Base class for nodes that output a Krea-2 conditioning tensor. + */ + Krea2ConditioningOutput: { + /** @description Conditioning tensor */ + conditioning: components["schemas"]["Krea2ConditioningField"]; + /** + * type + * @default krea2_conditioning_output + * @constant + */ + type: "krea2_conditioning_output"; + }; + /** + * Conditioning Rebalance - Krea-2 + * @description Per-layer rebalancing of Krea-2 text conditioning (improves prompt adherence). + * + * Krea-2 conditioning stacks 12 Qwen3-VL hidden-state layers per token. Weighting those layers + * individually (and applying an overall multiplier) lets you push the model harder toward the prompt, + * counteracting the quality-dilution from distillation. Ported from the ComfyUI + * `ConditioningKrea2Rebalance` node. This is an optional pass between the text encoder and denoise. + */ + Krea2ConditioningRebalanceInvocation: { + /** + * 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; + /** + * Conditioning + * @description Conditioning tensor + * @default null + */ + conditioning?: components["schemas"]["Krea2ConditioningField"] | null; + /** + * Per Layer Weights + * @description Comma-separated gains for the 12 tapped encoder layers (exactly 12 values). + * @default 1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0 + */ + per_layer_weights?: string; + /** + * Multiplier + * @description Overall multiplier applied to the conditioning after per-layer weighting. + * @default 4 + */ + multiplier?: number; + /** + * type + * @default krea2_conditioning_rebalance + * @constant + */ + type: "krea2_conditioning_rebalance"; + }; + /** + * Denoise - Krea-2 + * @description Run the denoising process with a Krea-2 model. + */ + Krea2DenoiseInvocation: { + /** + * @description The board to save the image to + * @default null + */ + board?: components["schemas"]["BoardField"] | null; + /** + * @description Optional metadata to be saved with the image + * @default null + */ + metadata?: components["schemas"]["MetadataField"] | null; + /** + * 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 Latents tensor + * @default null + */ + latents?: components["schemas"]["LatentsField"] | null; + /** + * @description A mask of the region to apply the denoising process to. Values of 0.0 represent the regions to be fully denoised, and 1.0 represent the regions to be preserved. + * @default null + */ + denoise_mask?: components["schemas"]["DenoiseMaskField"] | null; + /** + * Denoising Start + * @description When to start denoising, expressed a percentage of total steps + * @default 0 + */ + denoising_start?: number; + /** + * Denoising End + * @description When to stop denoising, expressed a percentage of total steps + * @default 1 + */ + denoising_end?: number; + /** + * Transformer + * @description Krea-2 model (Transformer) to load + * @default null + */ + transformer?: components["schemas"]["TransformerField"] | null; + /** + * @description Positive conditioning tensor + * @default null + */ + positive_conditioning?: components["schemas"]["Krea2ConditioningField"] | null; + /** + * @description Negative conditioning tensor + * @default null + */ + negative_conditioning?: components["schemas"]["Krea2ConditioningField"] | null; + /** + * CFG Scale + * @description Classifier-Free Guidance scale + * @default 1 + */ + cfg_scale?: number | number[]; + /** + * Width + * @description Width of the generated image. + * @default 1024 + */ + width?: number; + /** + * Height + * @description Height of the generated image. + * @default 1024 + */ + height?: number; + /** + * Steps + * @description Number of steps to run + * @default 8 + */ + steps?: number; + /** + * Seed + * @description Randomness seed for reproducibility. + * @default 0 + */ + seed?: number; + /** + * Shift + * @description Override the resolution-aware timestep shift (mu). Leave unset to use the model default (mu=1.15 for the distilled Turbo checkpoint). + * @default null + */ + shift?: number | null; + /** + * type + * @default krea2_denoise + * @constant + */ + type: "krea2_denoise"; + }; + /** + * Apply LoRA Collection - Krea-2 + * @description Applies a collection of LoRAs to a Krea-2 transformer and/or Qwen3-VL encoder. + */ + Krea2LoRACollectionLoader: { + /** + * 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; + /** + * LoRAs + * @description LoRA models and weights. May be a single LoRA or collection. + * @default null + */ + loras?: components["schemas"]["LoRAField"] | components["schemas"]["LoRAField"][] | null; + /** + * Transformer + * @description Transformer + * @default null + */ + transformer?: components["schemas"]["TransformerField"] | null; + /** + * Qwen3-VL Encoder + * @description Qwen3-VL tokenizer and text encoder + * @default null + */ + qwen3_vl_encoder?: components["schemas"]["Qwen3VLEncoderField"] | null; + /** + * type + * @default krea2_lora_collection_loader + * @constant + */ + type: "krea2_lora_collection_loader"; + }; + /** + * Apply LoRA - Krea-2 + * @description Apply a LoRA model to a Krea-2 transformer and/or Qwen3-VL text encoder. + */ + Krea2LoRALoaderInvocation: { + /** + * 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; + /** + * LoRA + * @description LoRA model to load + * @default null + */ + lora?: components["schemas"]["ModelIdentifierField"] | null; + /** + * Weight + * @description The weight at which the LoRA is applied to each model + * @default 0.75 + */ + weight?: number; + /** + * Krea-2 Transformer + * @description Transformer + * @default null + */ + transformer?: components["schemas"]["TransformerField"] | null; + /** + * Qwen3-VL Encoder + * @description Qwen3-VL tokenizer and text encoder + * @default null + */ + qwen3_vl_encoder?: components["schemas"]["Qwen3VLEncoderField"] | null; + /** + * type + * @default krea2_lora_loader + * @constant + */ + type: "krea2_lora_loader"; + }; + /** + * Krea2LoRALoaderOutput + * @description Krea-2 LoRA Loader Output + */ + Krea2LoRALoaderOutput: { + /** + * Krea-2 Transformer + * @description Transformer + * @default null + */ + transformer: components["schemas"]["TransformerField"] | null; + /** + * Qwen3-VL Encoder + * @description Qwen3-VL tokenizer and text encoder + * @default null + */ + qwen3_vl_encoder: components["schemas"]["Qwen3VLEncoderField"] | null; + /** + * type + * @default krea2_lora_loader_output + * @constant + */ + type: "krea2_lora_loader_output"; + }; + /** + * Main Model - Krea-2 + * @description Loads a Krea-2 model, outputting its submodels. + * + * By default the VAE (Qwen-Image VAE) and Qwen3-VL text encoder are extracted from the Krea-2 + * diffusers pipeline. Standalone overrides may be supplied (e.g. when the transformer is a + * single-file checkpoint that has no bundled VAE / encoder). + */ + Krea2ModelLoaderInvocation: { + /** + * 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; + /** + * Transformer + * @description Krea-2 model (Transformer) to load + */ + model: components["schemas"]["ModelIdentifierField"]; + /** + * VAE + * @description Standalone VAE model. Krea-2 uses the Qwen-Image VAE (16-channel). If not provided, the VAE is loaded from the Krea-2 (diffusers) model. + * @default null + */ + vae_model?: components["schemas"]["ModelIdentifierField"] | null; + /** + * Qwen3-VL Encoder + * @description Standalone Qwen3-VL Encoder model. If not provided, the encoder is loaded from the Krea-2 (diffusers) model. + * @default null + */ + qwen3_vl_encoder_model?: components["schemas"]["ModelIdentifierField"] | null; + /** + * type + * @default krea2_model_loader + * @constant + */ + type: "krea2_model_loader"; + }; + /** + * Krea2ModelLoaderOutput + * @description Krea-2 base model loader output. + */ + Krea2ModelLoaderOutput: { + /** + * Transformer + * @description Transformer + */ + transformer: components["schemas"]["TransformerField"]; + /** + * Qwen3-VL Encoder + * @description Qwen3-VL tokenizer and text encoder + */ + qwen3_vl_encoder: components["schemas"]["Qwen3VLEncoderField"]; + /** + * VAE + * @description VAE + */ + vae: components["schemas"]["VAEField"]; + /** + * type + * @default krea2_model_loader_output + * @constant + */ + type: "krea2_model_loader_output"; + }; + /** + * Seed Variance - Krea-2 + * @description Inject per-seed diversity into Krea-2 text conditioning. + * + * Distilled few-step models (like Krea-2-Turbo) suffer from low seed variance — different seeds give + * near-identical images. This adds seeded uniform noise to a random subset of the text-embedding + * values, trading some prompt adherence for variety (the same idea as the Z-Image-Turbo + * `SeedVarianceEnhancer`). Optional pass between the text encoder and denoise; the defaults are + * aggressive and may need tuning for Krea-2. + */ + Krea2SeedVarianceInvocation: { + /** + * 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; + /** + * Conditioning + * @description Conditioning tensor + * @default null + */ + conditioning?: components["schemas"]["Krea2ConditioningField"] | null; + /** + * Strength + * @description Magnitude of the uniform noise added to the embeddings (noise in [-strength, +strength]). + * @default 20 + */ + strength?: number; + /** + * Randomize Percent + * @description Percentage of embedding values that get perturbed (Bernoulli mask). + * @default 50 + */ + randomize_percent?: number; + /** + * Variance Seed + * @description Seed for the variance noise (vary this to get variety). + * @default 0 + */ + variance_seed?: number; + /** + * type + * @default krea2_seed_variance + * @constant + */ + type: "krea2_seed_variance"; + }; + /** + * Prompt - Krea-2 + * @description Encodes a text prompt for Krea-2 using the Qwen3-VL text encoder. + * + * The encoder taps 12 decoder hidden-state layers and stacks them per token, producing a 4D + * conditioning tensor (B, seq, 12, hidden) that the Krea-2 transformer's text-fusion stage consumes. + */ + Krea2TextEncoderInvocation: { + /** + * 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; + /** + * Prompt + * @description Text prompt describing the desired image. + * @default null + */ + prompt?: string | null; + /** + * Qwen3-VL Encoder + * @description Qwen3-VL tokenizer and text encoder + * @default null + */ + qwen3_vl_encoder?: components["schemas"]["Qwen3VLEncoderField"] | null; + /** + * type + * @default krea2_text_encoder + * @constant + */ + type: "krea2_text_encoder"; + }; + /** + * Krea2VariantType + * @description Krea 2 model variants. + * @enum {string} + */ + Krea2VariantType: "krea2_turbo"; /** * LaMa Infill * @description Infills transparent areas of an image using the LaMa model @@ -18722,6 +19228,89 @@ export type components = { base: "flux2"; variant: components["schemas"]["Flux2VariantType"] | null; }; + /** + * LoRA_LyCORIS_Krea2_Config + * @description Model config for Krea-2 LoRA models in LyCORIS (single-file diffusers PEFT) format. + */ + LoRA_LyCORIS_Krea2_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; + /** + * Type + * @default lora + * @constant + */ + type: "lora"; + /** + * Trigger Phrases + * @description Set of trigger phrases for this model + */ + trigger_phrases: string[] | null; + /** @description Default settings for this model */ + default_settings: components["schemas"]["LoraModelDefaultSettings"] | null; + /** + * Format + * @default lycoris + * @constant + */ + format: "lycoris"; + /** + * Base + * @default krea-2 + * @constant + */ + base: "krea-2"; + }; /** * LoRA_LyCORIS_QwenImage_Config * @description Model config for Qwen Image Edit LoRA models in LyCORIS format. @@ -19919,6 +20508,95 @@ export type components = { base: "flux2"; variant: components["schemas"]["Flux2VariantType"]; }; + /** + * Main_Checkpoint_Krea2_Config + * @description Model config for Krea-2 single-file checkpoint models (safetensors, etc). + */ + Main_Checkpoint_Krea2_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; + /** + * Type + * @default main + * @constant + */ + type: "main"; + /** + * Trigger Phrases + * @description Set of trigger phrases for this model + */ + trigger_phrases: string[] | null; + /** @description Default settings for this model */ + default_settings: components["schemas"]["MainModelDefaultSettings"] | null; + /** + * Config Path + * @description Path to the config for this model, if any. + */ + config_path: string | null; + /** + * Base + * @default krea-2 + * @constant + */ + base: "krea-2"; + /** + * Format + * @default checkpoint + * @constant + */ + format: "checkpoint"; + variant: components["schemas"]["Krea2VariantType"]; + }; /** * Main_Checkpoint_QwenImage_Config * @description Model config for Qwen Image single-file checkpoint models (safetensors, etc). @@ -20095,13 +20773,187 @@ export type components = { variant: components["schemas"]["ModelVariantType"]; /** * Base - * @default sd-1 + * @default sd-1 + * @constant + */ + base: "sd-1"; + }; + /** Main_Checkpoint_SD2_Config */ + Main_Checkpoint_SD2_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; + /** + * Type + * @default main + * @constant + */ + type: "main"; + /** + * Trigger Phrases + * @description Set of trigger phrases for this model + */ + trigger_phrases: string[] | null; + /** @description Default settings for this model */ + default_settings: components["schemas"]["MainModelDefaultSettings"] | null; + /** + * Config Path + * @description Path to the config for this model, if any. + */ + config_path: string | null; + /** + * Format + * @default checkpoint + * @constant + */ + format: "checkpoint"; + prediction_type: components["schemas"]["SchedulerPredictionType"]; + variant: components["schemas"]["ModelVariantType"]; + /** + * Base + * @default sd-2 + * @constant + */ + base: "sd-2"; + }; + /** Main_Checkpoint_SDXLRefiner_Config */ + Main_Checkpoint_SDXLRefiner_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; + /** + * Type + * @default main + * @constant + */ + type: "main"; + /** + * Trigger Phrases + * @description Set of trigger phrases for this model + */ + trigger_phrases: string[] | null; + /** @description Default settings for this model */ + default_settings: components["schemas"]["MainModelDefaultSettings"] | null; + /** + * Config Path + * @description Path to the config for this model, if any. + */ + config_path: string | null; + /** + * Format + * @default checkpoint + * @constant + */ + format: "checkpoint"; + prediction_type: components["schemas"]["SchedulerPredictionType"]; + variant: components["schemas"]["ModelVariantType"]; + /** + * Base + * @default sdxl-refiner * @constant */ - base: "sd-1"; + base: "sdxl-refiner"; }; - /** Main_Checkpoint_SD2_Config */ - Main_Checkpoint_SD2_Config: { + /** Main_Checkpoint_SDXL_Config */ + Main_Checkpoint_SDXL_Config: { /** * Key * @description A unique key for this model. @@ -20182,13 +21034,16 @@ export type components = { variant: components["schemas"]["ModelVariantType"]; /** * Base - * @default sd-2 + * @default sdxl * @constant */ - base: "sd-2"; + base: "sdxl"; }; - /** Main_Checkpoint_SDXLRefiner_Config */ - Main_Checkpoint_SDXLRefiner_Config: { + /** + * Main_Checkpoint_ZImage_Config + * @description Model config for Z-Image single-file checkpoint models (safetensors, etc). + */ + Main_Checkpoint_ZImage_Config: { /** * Key * @description A unique key for this model. @@ -20259,113 +21114,22 @@ export type components = { * @description Path to the config for this model, if any. */ config_path: string | null; - /** - * Format - * @default checkpoint - * @constant - */ - format: "checkpoint"; - prediction_type: components["schemas"]["SchedulerPredictionType"]; - variant: components["schemas"]["ModelVariantType"]; /** * Base - * @default sdxl-refiner - * @constant - */ - base: "sdxl-refiner"; - }; - /** Main_Checkpoint_SDXL_Config */ - Main_Checkpoint_SDXL_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; - /** - * Type - * @default main + * @default z-image * @constant */ - type: "main"; - /** - * Trigger Phrases - * @description Set of trigger phrases for this model - */ - trigger_phrases: string[] | null; - /** @description Default settings for this model */ - default_settings: components["schemas"]["MainModelDefaultSettings"] | null; - /** - * Config Path - * @description Path to the config for this model, if any. - */ - config_path: string | null; + base: "z-image"; /** * Format * @default checkpoint * @constant */ format: "checkpoint"; - prediction_type: components["schemas"]["SchedulerPredictionType"]; - variant: components["schemas"]["ModelVariantType"]; - /** - * Base - * @default sdxl - * @constant - */ - base: "sdxl"; + variant: components["schemas"]["ZImageVariantType"]; }; - /** - * Main_Checkpoint_ZImage_Config - * @description Model config for Z-Image single-file checkpoint models (safetensors, etc). - */ - Main_Checkpoint_ZImage_Config: { + /** Main_Diffusers_CogView4_Config */ + Main_Diffusers_CogView4_Config: { /** * Key * @description A unique key for this model. @@ -20432,26 +21196,25 @@ export type components = { /** @description Default settings for this model */ default_settings: components["schemas"]["MainModelDefaultSettings"] | null; /** - * Config Path - * @description Path to the config for this model, if any. - */ - config_path: string | null; - /** - * Base - * @default z-image + * Format + * @default diffusers * @constant */ - base: "z-image"; + format: "diffusers"; + /** @default */ + repo_variant: components["schemas"]["ModelRepoVariant"]; /** - * Format - * @default checkpoint + * Base + * @default cogview4 * @constant */ - format: "checkpoint"; - variant: components["schemas"]["ZImageVariantType"]; + base: "cogview4"; }; - /** Main_Diffusers_CogView4_Config */ - Main_Diffusers_CogView4_Config: { + /** + * Main_Diffusers_FLUX_Config + * @description Model config for FLUX.1 models in diffusers format. + */ + Main_Diffusers_FLUX_Config: { /** * Key * @description A unique key for this model. @@ -20527,16 +21290,17 @@ export type components = { repo_variant: components["schemas"]["ModelRepoVariant"]; /** * Base - * @default cogview4 + * @default flux * @constant */ - base: "cogview4"; + base: "flux"; + variant: components["schemas"]["FluxVariantType"]; }; /** - * Main_Diffusers_FLUX_Config - * @description Model config for FLUX.1 models in diffusers format. + * Main_Diffusers_Flux2_Config + * @description Model config for FLUX.2 models in diffusers format (e.g. FLUX.2 Klein). */ - Main_Diffusers_FLUX_Config: { + Main_Diffusers_Flux2_Config: { /** * Key * @description A unique key for this model. @@ -20612,17 +21376,17 @@ export type components = { repo_variant: components["schemas"]["ModelRepoVariant"]; /** * Base - * @default flux + * @default flux2 * @constant */ - base: "flux"; - variant: components["schemas"]["FluxVariantType"]; + base: "flux2"; + variant: components["schemas"]["Flux2VariantType"]; }; /** - * Main_Diffusers_Flux2_Config - * @description Model config for FLUX.2 models in diffusers format (e.g. FLUX.2 Klein). + * Main_Diffusers_Krea2_Config + * @description Model config for Krea-2 diffusers models (Krea-2-Turbo). */ - Main_Diffusers_Flux2_Config: { + Main_Diffusers_Krea2_Config: { /** * Key * @description A unique key for this model. @@ -20698,11 +21462,11 @@ export type components = { repo_variant: components["schemas"]["ModelRepoVariant"]; /** * Base - * @default flux2 + * @default krea-2 * @constant */ - base: "flux2"; - variant: components["schemas"]["Flux2VariantType"]; + base: "krea-2"; + variant: components["schemas"]["Krea2VariantType"]; }; /** * Main_Diffusers_QwenImage_Config @@ -23348,7 +24112,7 @@ export type components = { * @description Storage format of model. * @enum {string} */ - ModelFormat: "omi" | "diffusers" | "checkpoint" | "lycoris" | "onnx" | "olive" | "embedding_file" | "embedding_folder" | "invokeai" | "t5_encoder" | "qwen3_encoder" | "qwen_vl_encoder" | "bnb_quantized_int8b" | "bnb_quantized_nf4b" | "gguf_quantized" | "external_api" | "unknown"; + ModelFormat: "omi" | "diffusers" | "checkpoint" | "lycoris" | "onnx" | "olive" | "embedding_file" | "embedding_folder" | "invokeai" | "t5_encoder" | "qwen3_encoder" | "qwen_vl_encoder" | "qwen3_vl_encoder" | "bnb_quantized_int8b" | "bnb_quantized_nf4b" | "gguf_quantized" | "external_api" | "unknown"; /** ModelIdentifierField */ ModelIdentifierField: { /** @@ -23485,7 +24249,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; /** * ModelInstallDownloadProgressEvent @@ -23651,7 +24415,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -23737,7 +24501,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -23758,7 +24522,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -23884,7 +24648,7 @@ export type components = { * Variant * @description The variant of the model. */ - variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | null; + variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | components["schemas"]["Krea2VariantType"] | null; /** @description The prediction type of the model. */ prediction_type?: components["schemas"]["SchedulerPredictionType"] | null; /** @@ -23909,18 +24673,6 @@ export type components = { /** * Model Keys * @description List of model keys to fetch related models for - * @example [ - * "aa3b247f-90c9-4416-bfcd-aeaa57a5339e", - * "ac32b914-10ab-496e-a24a-3068724b9c35" - * ] - * @example [ - * "b1c2d3e4-f5a6-7890-abcd-ef1234567890", - * "12345678-90ab-cdef-1234-567890abcdef", - * "fedcba98-7654-3210-fedc-ba9876543210" - * ] - * @example [ - * "3bb7c0eb-b6c8-469c-ad8c-4d69c06075e4" - * ] */ model_keys: string[]; }; @@ -23929,23 +24681,11 @@ export type components = { /** * Model Key 1 * @description The key of the first model in the relationship - * @example aa3b247f-90c9-4416-bfcd-aeaa57a5339e - * @example ac32b914-10ab-496e-a24a-3068724b9c35 - * @example d944abfd-c7c3-42e2-a4ff-da640b29b8b4 - * @example b1c2d3e4-f5a6-7890-abcd-ef1234567890 - * @example 12345678-90ab-cdef-1234-567890abcdef - * @example fedcba98-7654-3210-fedc-ba9876543210 */ model_key_1: string; /** * Model Key 2 * @description The key of the second model in the relationship - * @example 3bb7c0eb-b6c8-469c-ad8c-4d69c06075e4 - * @example f0c3da4e-d9ff-42b5-a45c-23be75c887c9 - * @example 38170dd8-f1e5-431e-866c-2c81f1277fcc - * @example c57fea2d-7646-424c-b9ad-c0ba60fc68be - * @example 10f7807b-ab54-46a9-ab03-600e88c630a1 - * @example f6c1d267-cf87-4ee0-bee0-37e791eacab7 */ model_key_2: string; }; @@ -23966,7 +24706,7 @@ export type components = { * @description Model type. * @enum {string} */ - ModelType: "onnx" | "main" | "vae" | "lora" | "control_lora" | "controlnet" | "embedding" | "ip_adapter" | "clip_vision" | "clip_embed" | "t2i_adapter" | "t5_encoder" | "qwen3_encoder" | "qwen_vl_encoder" | "spandrel_image_to_image" | "siglip" | "flux_redux" | "llava_onevision" | "text_llm" | "external_image_generator" | "unknown"; + ModelType: "onnx" | "main" | "vae" | "lora" | "control_lora" | "controlnet" | "embedding" | "ip_adapter" | "clip_vision" | "clip_embed" | "t2i_adapter" | "t5_encoder" | "qwen3_encoder" | "qwen_vl_encoder" | "qwen3_vl_encoder" | "spandrel_image_to_image" | "siglip" | "flux_redux" | "llava_onevision" | "text_llm" | "external_image_generator" | "unknown"; /** * ModelVariantType * @description Variant type. @@ -23979,7 +24719,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"])[]; }; /** * Multiply Integers @@ -25401,6 +26141,107 @@ export type components = { /** @description Qwen3 model size variant (4B or 8B) */ variant: components["schemas"]["Qwen3VariantType"]; }; + /** + * Qwen3VLEncoderField + * @description Field for the Qwen3-VL text encoder used by Krea-2 models. + */ + Qwen3VLEncoderField: { + /** @description Info to load tokenizer submodel */ + tokenizer: components["schemas"]["ModelIdentifierField"]; + /** @description Info to load text_encoder submodel */ + text_encoder: components["schemas"]["ModelIdentifierField"]; + /** + * Loras + * @description LoRAs to apply on model loading + */ + loras?: components["schemas"]["LoRAField"][]; + }; + /** + * Qwen3VLEncoder_Qwen3VLEncoder_Config + * @description Configuration for standalone Qwen3-VL text encoder models (diffusers-like directory format). + * + * Used by Krea-2, whose text conditioning comes from a Qwen3-VL model (``Qwen3VLModel``). The model + * weights are expected either in a ``text_encoder`` subfolder of the model directory or directly at the + * root (standalone download). This is distinct from the text-only ``Qwen3Encoder`` (Z-Image / FLUX.2 + * Klein) and the Qwen2.5-VL ``QwenVLEncoder`` (Qwen Image). + */ + Qwen3VLEncoder_Qwen3VLEncoder_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; + /** + * Base + * @default any + * @constant + */ + base: "any"; + /** + * Type + * @default qwen3_vl_encoder + * @constant + */ + type: "qwen3_vl_encoder"; + /** + * Format + * @default qwen3_vl_encoder + * @constant + */ + format: "qwen3_vl_encoder"; + /** + * Cpu Only + * @description Whether this model should run on CPU only + */ + cpu_only: boolean | null; + }; /** * Qwen3VariantType * @description Qwen3 text encoder variants based on model size. @@ -28737,7 +29578,7 @@ export type components = { type: components["schemas"]["ModelType"]; format?: components["schemas"]["ModelFormat"] | null; /** Variant */ - variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | null; + variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | components["schemas"]["Krea2VariantType"] | null; /** * Is Installed * @default false @@ -28782,7 +29623,7 @@ export type components = { type: components["schemas"]["ModelType"]; format?: components["schemas"]["ModelFormat"] | null; /** Variant */ - variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | null; + variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | components["schemas"]["Krea2VariantType"] | null; /** * Is Installed * @default false @@ -29313,7 +30154,7 @@ export type components = { path_or_prefix: string; model_type: components["schemas"]["ModelType"]; /** Variant */ - variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | null; + variant?: components["schemas"]["ModelVariantType"] | components["schemas"]["ClipVariantType"] | components["schemas"]["FluxVariantType"] | components["schemas"]["Flux2VariantType"] | components["schemas"]["ZImageVariantType"] | components["schemas"]["QwenImageVariantType"] | components["schemas"]["Qwen3VariantType"] | components["schemas"]["Krea2VariantType"] | null; }; /** * Subtract Integers @@ -33619,7 +34460,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -33651,7 +34492,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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -33683,8 +34524,7 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example { + /** @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -33701,9 +34541,8 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -33790,8 +34629,7 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example { + /** @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -33808,9 +34646,8 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -33863,8 +34700,7 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example { + /** @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -33881,9 +34717,8 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -34598,8 +35433,7 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example { + /** @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -34616,9 +35450,8 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_QwenImage_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -36216,13 +37049,11 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example [ + /** @example [ * "15e9eb28-8cfe-47c9-b610-37907a79fc3c", * "71272e82-0e5f-46d5-bca9-9a61f4bd8a82", * "a5d7cd49-1b98-4534-a475-aeee4ccf5fa2" - * ] - */ + * ] */ "application/json": string[]; }; }; @@ -36361,8 +37192,7 @@ export interface operations { [name: string]: unknown; }; content: { - /** - * @example [ + /** @example [ * "ca562b14-995e-4a42-90c1-9528f1a5921d", * "cc0c2b8a-c62e-41d6-878e-cc74dde5ca8f", * "18ca7649-6a9e-47d5-bc17-41ab1e8cec81", @@ -36370,8 +37200,7 @@ export interface operations { * "c382eaa3-0e28-4ab0-9446-408667699aeb", * "71272e82-0e5f-46d5-bca9-9a61f4bd8a82", * "a5d7cd49-1b98-4534-a475-aeee4ccf5fa2" - * ] - */ + * ] */ "application/json": string[]; }; }; diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 27c6fcbf3c3..b586780572d 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -117,6 +117,7 @@ export type T5EncoderBnbQuantizedLlmInt8bModelConfig = Extract< >; export type Qwen3EncoderModelConfig = Extract; export type QwenVLEncoderModelConfig = Extract; +export type Qwen3VLEncoderModelConfig = Extract; export type SpandrelImageToImageModelConfig = Extract; export type CheckpointModelConfig = Extract; export type CLIPVisionModelConfig = Extract; @@ -379,6 +380,10 @@ export const isQwenVLEncoderModelConfig = (config: AnyModelConfig): config is Qw return config.type === 'qwen_vl_encoder'; }; +export const isQwen3VLEncoderModelConfig = (config: AnyModelConfig): config is Qwen3VLEncoderModelConfig => { + return config.type === 'qwen3_vl_encoder'; +}; + export const isCLIPEmbedModelConfigOrSubmodel = ( config: AnyModelConfig, excludeSubmodels?: boolean diff --git a/pyproject.toml b/pyproject.toml index 8405927b0ac..6d8be1525ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,10 @@ dependencies = [ "accelerate", "bitsandbytes; sys_platform!='darwin'", "compel==2.1.1", - "diffusers[torch]==0.37.0", + # WIP (Krea-2 support): Krea2Pipeline/Krea2Transformer2DModel only exist in diffusers main (>=0.39 dev). + # This unpins diffusers from 0.37.0 to a git build for testing. Re-pin to the stable release that + # contains Krea-2 before merging, then un-draft the PR. + "diffusers[torch] @ git+https://github.com/huggingface/diffusers.git", "gguf", "mediapipe==0.10.14", # needed for "mediapipeface" controlnet model "numpy<2.0.0", From 89b27b56befc309c80acb17d522f68495abb0d80 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Fri, 26 Jun 2026 10:48:21 +0200 Subject: [PATCH 02/17] fix(krea2): support single-file VAE/encoder mix-and-match end-to-end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow non-diffusers Krea-2 transformers (GGUF/fp8) to run with standalone single-file VAE + Qwen3-VL encoder, fixing several blockers found in testing. - buildKrea2Graph: drop the hard "requires Diffusers-format" assert; instead require both a VAE and a Qwen3-VL encoder to be selected when the transformer is not diffusers (mirrors readiness.ts). - Qwen3-VL encoder remap: handle both single-file key conventions — implicit (model.layers.*) and explicit (model.language_model.*). The old blind model.* -> language_model.* turned the bf16 file's keys into language_model.language_model.* (398 meta tensors -> "Cannot copy out of meta tensor" crash). Both files now load 0 missing / 0 unexpected / 0 meta. - Qwen3-VL tokenizer/config: broaden the offline-cache fallback from OSError to Exception so a partial HF cache (config present, vocab missing) re-fetches instead of dying with TypeError. - Qwen3-VL encoder fp8: keep an fp8 source checkpoint fp8-resident with per-layer upcast (storage float8_e4m3fn, compute bf16) instead of dequantizing to bf16. Halves resident VRAM (~8.9GB -> ~4.4GB), avoiding partial-load thrashing alongside a large transformer. Auto-enabled for fp8 sources on CUDA; bf16 files stay bf16. - Qwen-Image VAE: a native-layout qwen_image_vae single file is classified with the Anima base and loaded as AutoencoderKLWan, but the qwen l2i/i2l nodes need AutoencoderKLQwenImage. Add backend/krea2/vae_compat.py::as_qwen_image_vae to reinterpret a Wan VAE as AutoencoderKLQwenImage (state dicts are identical, 194/194 keys); both qwen VAE nodes use it. Idempotent for real QwenImage VAEs. --- .../qwen_image_image_to_latents.py | 6 +- .../qwen_image_latents_to_image.py | 7 +- invokeai/backend/krea2/vae_compat.py | 37 ++ .../backend/model_manager/configs/factory.py | 10 +- .../backend/model_manager/configs/main.py | 52 ++- .../model_manager/configs/qwen3_vl_encoder.py | 40 +- .../model_manager/load/model_loaders/krea2.py | 358 +++++++++++++++++- invokeai/frontend/web/public/locales/en.json | 6 + .../controlLayers/store/paramsSlice.ts | 23 ++ .../src/features/controlLayers/store/types.ts | 6 + .../util/graph/generation/buildKrea2Graph.ts | 15 +- .../Advanced/ParamKrea2ModelSelects.tsx | 116 ++++++ .../web/src/features/queue/store/readiness.ts | 22 ++ .../AdvancedSettingsAccordion.tsx | 6 + .../src/services/api/hooks/modelsByType.ts | 2 + 15 files changed, 672 insertions(+), 34 deletions(-) create mode 100644 invokeai/backend/krea2/vae_compat.py create mode 100644 invokeai/frontend/web/src/features/parameters/components/Advanced/ParamKrea2ModelSelects.tsx diff --git a/invokeai/app/invocations/qwen_image_image_to_latents.py b/invokeai/app/invocations/qwen_image_image_to_latents.py index ef88e03082b..62f83d247a4 100644 --- a/invokeai/app/invocations/qwen_image_image_to_latents.py +++ b/invokeai/app/invocations/qwen_image_image_to_latents.py @@ -1,6 +1,5 @@ import einops import torch -from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage from PIL import Image as PILImage from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation @@ -15,6 +14,7 @@ from invokeai.app.invocations.model import VAEField from invokeai.app.invocations.primitives import LatentsOutput from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.krea2.vae_compat import as_qwen_image_vae from invokeai.backend.model_manager.load.load_base import LoadedModel from invokeai.backend.stable_diffusion.diffusers_pipeline import image_resized_to_grid_as_tensor from invokeai.backend.util.devices import TorchDevice @@ -45,7 +45,9 @@ class QwenImageImageToLatentsInvocation(BaseInvocation, WithMetadata, WithBoard) @staticmethod def vae_encode(vae_info: LoadedModel, image_tensor: torch.Tensor) -> torch.Tensor: with vae_info.model_on_device() as (_, vae): - assert isinstance(vae, AutoencoderKLQwenImage) + # A native-layout qwen_image_vae single file is classified with the Anima base and loaded + # as AutoencoderKLWan; reinterpret it as AutoencoderKLQwenImage (identical weights). + vae = as_qwen_image_vae(vae) vae.disable_tiling() diff --git a/invokeai/app/invocations/qwen_image_latents_to_image.py b/invokeai/app/invocations/qwen_image_latents_to_image.py index b3ea39c4bbf..876513ce872 100644 --- a/invokeai/app/invocations/qwen_image_latents_to_image.py +++ b/invokeai/app/invocations/qwen_image_latents_to_image.py @@ -1,7 +1,6 @@ from contextlib import nullcontext import torch -from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage from einops import rearrange from PIL import Image @@ -17,6 +16,7 @@ from invokeai.app.invocations.model import VAEField from invokeai.app.invocations.primitives import ImageOutput from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.krea2.vae_compat import as_qwen_image_vae from invokeai.backend.stable_diffusion.extensions.seamless import SeamlessExt from invokeai.backend.util.devices import TorchDevice @@ -40,13 +40,14 @@ def invoke(self, context: InvocationContext) -> ImageOutput: latents = context.tensors.load(self.latents.latents_name) vae_info = context.models.load(self.vae.vae) - assert isinstance(vae_info.model, AutoencoderKLQwenImage) with ( SeamlessExt.static_patch_model(vae_info.model, self.vae.seamless_axes), vae_info.model_on_device() as (_, vae), ): context.util.signal_progress("Running VAE") - assert isinstance(vae, AutoencoderKLQwenImage) + # A native-layout qwen_image_vae single file is classified with the Anima base and loaded + # as AutoencoderKLWan; reinterpret it as AutoencoderKLQwenImage (identical weights). + vae = as_qwen_image_vae(vae) latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=vae.dtype) vae.disable_tiling() diff --git a/invokeai/backend/krea2/vae_compat.py b/invokeai/backend/krea2/vae_compat.py new file mode 100644 index 00000000000..c42dd3487f3 --- /dev/null +++ b/invokeai/backend/krea2/vae_compat.py @@ -0,0 +1,37 @@ +"""Compatibility helpers for the Qwen-Image VAE used by Krea-2. + +Krea-2 (and Qwen-Image) decode/encode with ``AutoencoderKLQwenImage``. A standalone single-file +``qwen_image_vae.safetensors`` in the native (ComfyUI/Wan) layout is byte-identical to the Anima VAE +and therefore classified with the Anima base, which loads it as ``AutoencoderKLWan``. The two classes +share the exact same diffusers state-dict (identical keys and shapes), so a Wan-loaded VAE can be +reinterpreted as ``AutoencoderKLQwenImage`` losslessly — and the default ``AutoencoderKLQwenImage`` +config carries the correct Qwen-Image ``latents_mean`` / ``latents_std`` / ``z_dim`` that the qwen +encode/decode nodes read. +""" + +from typing import Any + +import accelerate +from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage + + +def as_qwen_image_vae(model: Any) -> AutoencoderKLQwenImage: + """Return ``model`` if it is already an ``AutoencoderKLQwenImage``, else reinterpret it as one. + + The only expected non-matching input is ``AutoencoderKLWan`` (the same weights loaded via the + Anima single-file path). Its state dict is loaded — with ``assign=True`` so no tensors are copied + and device/dtype are preserved — into a freshly built ``AutoencoderKLQwenImage`` whose default + config provides the correct Qwen-Image latent statistics. + """ + if isinstance(model, AutoencoderKLQwenImage): + return model + + src_state_dict = model.state_dict() + with accelerate.init_empty_weights(): + qwen_vae = AutoencoderKLQwenImage() + # assign=True shares the source tensors (no copy) and keeps their device/dtype. + qwen_vae.load_state_dict(src_state_dict, strict=True, assign=True) + # Match the eval/grad state of a normally-loaded VAE. + qwen_vae.eval() + qwen_vae.requires_grad_(False) + return qwen_vae diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index 5b761316a40..7b5f5ca86fc 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -85,6 +85,7 @@ Main_Diffusers_ZImage_Config, Main_GGUF_Flux2_Config, Main_GGUF_FLUX_Config, + Main_GGUF_Krea2_Config, Main_GGUF_QwenImage_Config, Main_GGUF_ZImage_Config, MainModelDefaultSettings, @@ -95,6 +96,7 @@ Qwen3Encoder_Qwen3Encoder_Config, ) from invokeai.backend.model_manager.configs.qwen3_vl_encoder import ( + Qwen3VLEncoder_Checkpoint_Config, Qwen3VLEncoder_Qwen3VLEncoder_Config, ) from invokeai.backend.model_manager.configs.qwen_vl_encoder import ( @@ -203,6 +205,7 @@ Annotated[Main_GGUF_FLUX_Config, Main_GGUF_FLUX_Config.get_tag()], Annotated[Main_GGUF_QwenImage_Config, Main_GGUF_QwenImage_Config.get_tag()], Annotated[Main_GGUF_ZImage_Config, Main_GGUF_ZImage_Config.get_tag()], + Annotated[Main_GGUF_Krea2_Config, Main_GGUF_Krea2_Config.get_tag()], # VAE - checkpoint format Annotated[VAE_Checkpoint_SD1_Config, VAE_Checkpoint_SD1_Config.get_tag()], Annotated[VAE_Checkpoint_SD2_Config, VAE_Checkpoint_SD2_Config.get_tag()], @@ -255,12 +258,15 @@ # T5 Encoder - all formats Annotated[T5Encoder_T5Encoder_Config, T5Encoder_T5Encoder_Config.get_tag()], Annotated[T5Encoder_BnBLLMint8_Config, T5Encoder_BnBLLMint8_Config.get_tag()], + # Qwen3-VL Encoder (Qwen3-VL multimodal encoder for Krea-2) - checked BEFORE the text-only Qwen3 + # encoder so single-file VL checkpoints (which also carry generic model.layers.* keys) are not + # misclassified as the Z-Image Qwen3 encoder. The VL probe requires the visual tower. + Annotated[Qwen3VLEncoder_Checkpoint_Config, Qwen3VLEncoder_Checkpoint_Config.get_tag()], + Annotated[Qwen3VLEncoder_Qwen3VLEncoder_Config, Qwen3VLEncoder_Qwen3VLEncoder_Config.get_tag()], # Qwen3 Encoder Annotated[Qwen3Encoder_Qwen3Encoder_Config, Qwen3Encoder_Qwen3Encoder_Config.get_tag()], Annotated[Qwen3Encoder_Checkpoint_Config, Qwen3Encoder_Checkpoint_Config.get_tag()], Annotated[Qwen3Encoder_GGUF_Config, Qwen3Encoder_GGUF_Config.get_tag()], - # Qwen3-VL Encoder (Qwen3-VL multimodal encoder for Krea-2) - Annotated[Qwen3VLEncoder_Qwen3VLEncoder_Config, Qwen3VLEncoder_Qwen3VLEncoder_Config.get_tag()], # Qwen VL Encoder (Qwen2.5-VL multimodal encoder for Qwen Image) Annotated[QwenVLEncoder_Diffusers_Config, QwenVLEncoder_Diffusers_Config.get_tag()], Annotated[QwenVLEncoder_Checkpoint_Config, QwenVLEncoder_Checkpoint_Config.get_tag()], diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index 918a9a01df5..f8423442e5a 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -207,10 +207,16 @@ def _has_krea2_keys(state_dict: dict[str | int, Any]) -> bool: prefix (with ``layerwise_blocks`` / ``refiner_blocks`` / ``projector``) is unique to it. Returns True only for Krea-2 main models, not LoRAs. """ + # The text-fusion stage is unique to Krea-2. Diffusers naming uses `text_fusion`/`time_mod_proj`; + # the native/ComfyUI GGUF conversion uses the compact `txtfusion`/`tproj` names instead. krea2_specific_keys = { - "text_fusion", # text-fusion stage (layerwise_blocks, refiner_blocks, projector) - unique to Krea-2 - "time_mod_proj", # timestep modulation projection + "text_fusion", # text-fusion stage (diffusers naming) - unique to Krea-2 + "txtfusion", # text-fusion stage (native/ComfyUI GGUF naming) + "time_mod_proj", # timestep modulation projection (diffusers) } + # Corroborating image-input signals: `img_in` (diffusers) / `first` (native), or the timestep + # modulation projection (`tproj` native). + krea2_corroborating_keys = {"img_in", "first", "tproj"} lora_suffixes = ( ".lora_down.weight", @@ -229,7 +235,7 @@ def _has_krea2_keys(state_dict: dict[str | int, Any]) -> bool: return False has_text_fusion = False - has_img_in = False + has_corroborator = False for key in state_dict.keys(): if isinstance(key, int): continue @@ -237,10 +243,10 @@ def _has_krea2_keys(state_dict: dict[str | int, Any]) -> bool: key_parts = key.split(".") if any(part in krea2_specific_keys for part in key_parts): has_text_fusion = True - if "img_in" in key_parts: - has_img_in = True - # Require the distinctive text-fusion stage; img_in is a corroborating signal. - return has_text_fusion and has_img_in + if any(part in krea2_corroborating_keys for part in key_parts): + has_corroborator = True + # Require the distinctive text-fusion stage; the image-input key is a corroborating signal. + return has_text_fusion and has_corroborator class Main_SD_Checkpoint_Config_Base(Checkpoint_Config_Base, Main_Config_Base): @@ -1408,6 +1414,38 @@ def _validate_does_not_look_like_gguf_quantized(cls, mod: ModelOnDisk) -> None: raise NotAMatchError("state dict looks like GGUF quantized") +class Main_GGUF_Krea2_Config(Checkpoint_Config_Base, Main_Config_Base, Config_Base): + """Model config for GGUF-quantized Krea-2 transformer models (single-file).""" + + base: Literal[BaseModelType.Krea2] = Field(default=BaseModelType.Krea2) + format: Literal[ModelFormat.GGUFQuantized] = Field(default=ModelFormat.GGUFQuantized) + variant: Krea2VariantType = Field() + + @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) + + cls._validate_looks_like_krea2_model(mod) + + cls._validate_looks_like_gguf_quantized(mod) + + variant = override_fields.pop("variant", None) or Krea2VariantType.Turbo + + return cls(**override_fields, variant=variant) + + @classmethod + def _validate_looks_like_krea2_model(cls, mod: ModelOnDisk) -> None: + if not _has_krea2_keys(mod.load_state_dict()): + raise NotAMatchError("state dict does not look like a Krea-2 model") + + @classmethod + def _validate_looks_like_gguf_quantized(cls, mod: ModelOnDisk) -> None: + if not _has_ggml_tensors(mod.load_state_dict()): + raise NotAMatchError("state dict does not look like GGUF quantized") + + class Main_Diffusers_QwenImage_Config(Diffusers_Config_Base, Main_Config_Base, Config_Base): """Model config for Qwen Image diffusers models (both txt2img and edit).""" diff --git a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py index 48d116632de..7677e57fb32 100644 --- a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py +++ b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py @@ -2,12 +2,13 @@ from pydantic import Field -from invokeai.backend.model_manager.configs.base import Config_Base +from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Config_Base from invokeai.backend.model_manager.configs.identification_utils import ( NotAMatchError, raise_for_class_name, raise_for_override_fields, raise_if_not_dir, + raise_if_not_file, ) from invokeai.backend.model_manager.model_on_disk import ModelOnDisk from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType @@ -63,3 +64,40 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - ) return cls(**override_fields) + + +def _is_qwen3_vl_encoder_state_dict(state_dict: dict[str | int, Any]) -> bool: + """True for a single-file Qwen3-VL encoder: a Qwen3 text decoder PLUS a visual tower. + + The visual tower (``visual.*`` / ``model.visual.*``) distinguishes Qwen3-VL from the text-only + ``Qwen3Encoder`` (Z-Image / FLUX.2 Klein), which has ``model.layers.*`` but no visual tower. + """ + str_keys = [k for k in state_dict if isinstance(k, str)] + has_text_decoder = any(".layers." in k and ("model." in k or k.startswith("layers.")) for k in str_keys) + has_visual_tower = any(k.startswith(("visual.", "model.visual.")) or ".visual." in k for k in str_keys) + return has_text_decoder and has_visual_tower + + +class Qwen3VLEncoder_Checkpoint_Config(Checkpoint_Config_Base, Config_Base): + """Configuration for a single-file Qwen3-VL text encoder checkpoint (e.g. ComfyUI ``qwen3vl_4b_*``). + + Distinguished from the text-only ``Qwen3Encoder`` checkpoint (Z-Image) by the presence of the + Qwen3-VL visual tower. The tokenizer is not bundled in single-file checkpoints and is pulled from + HuggingFace (``Qwen/Qwen3-VL-4B-Instruct``) by the loader. + """ + + base: Literal[BaseModelType.Any] = Field(default=BaseModelType.Any) + type: Literal[ModelType.Qwen3VLEncoder] = Field(default=ModelType.Qwen3VLEncoder) + format: Literal[ModelFormat.Checkpoint] = Field(default=ModelFormat.Checkpoint) + cpu_only: bool | None = Field(default=None, description="Whether this model should run on CPU only") + + @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 _is_qwen3_vl_encoder_state_dict(mod.load_state_dict()): + raise NotAMatchError("state dict does not look like a single-file Qwen3-VL encoder") + + return cls(**override_fields) diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py index 0504374b44d..825b13957fb 100644 --- a/invokeai/backend/model_manager/load/model_loaders/krea2.py +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -9,8 +9,11 @@ from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Diffusers_Config_Base from invokeai.backend.model_manager.configs.factory import AnyModelConfig -from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config -from invokeai.backend.model_manager.configs.qwen3_vl_encoder import Qwen3VLEncoder_Qwen3VLEncoder_Config +from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config, Main_GGUF_Krea2_Config +from invokeai.backend.model_manager.configs.qwen3_vl_encoder import ( + Qwen3VLEncoder_Checkpoint_Config, + Qwen3VLEncoder_Qwen3VLEncoder_Config, +) 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.load.model_loaders.generic_diffusers import GenericDiffusersLoader @@ -21,8 +24,150 @@ ModelType, SubModelType, ) +from invokeai.backend.quantization.gguf.loaders import gguf_sd_loader from invokeai.backend.util.devices import TorchDevice + +def _strip_comfyui_prefix(sd: dict[str, Any]) -> dict[str, Any]: + """Strip ComfyUI-style ``model.diffusion_model.`` / ``diffusion_model.`` key prefixes if present.""" + prefix_to_strip = None + for prefix in ("model.diffusion_model.", "diffusion_model."): + if any(isinstance(k, str) and k.startswith(prefix) for k in sd.keys()): + prefix_to_strip = prefix + break + if not prefix_to_strip: + return sd + return { + (k[len(prefix_to_strip) :] if isinstance(k, str) and k.startswith(prefix_to_strip) else k): v + for k, v in sd.items() + } + + +def _to_plain_tensor(value: Any) -> Any: + """Dequantize a GGMLTensor to a plain tensor (needed before reshape); pass others through.""" + if hasattr(value, "get_dequantized_tensor"): + return value.get_dequantized_tensor() + return value + + +def _is_native_krea2_format(sd: dict[str, Any]) -> bool: + """Detect the native/ComfyUI Krea-2 key naming (e.g. GGUF) vs. the diffusers naming.""" + return any( + isinstance(k, str) and (k.startswith(("blocks.", "txtfusion.", "first.")) or ".mod.lin" in k) for k in sd + ) + + +def _dequantize_scaled_fp8(sd: dict[str, Any]) -> dict[str, Any]: + """Dequantize ComfyUI 'scaled fp8' weights: ``dequant = weight.float() * weight_scale``. + + Each quantized layer stores an fp8 ``.weight`` plus a (usually scalar) ``.weight_scale``. + Returns a new dict with the weights dequantized to float and the ``.weight_scale`` keys removed. + No-op if there are no scale keys. + """ + import torch + + scale_keys = [k for k in sd if isinstance(k, str) and k.endswith(".weight_scale")] + if not scale_keys: + return sd + out = dict(sd) + for scale_key in scale_keys: + weight_key = scale_key.replace(".weight_scale", ".weight") + if weight_key in out: + weight = torch.as_tensor(_to_plain_tensor(out[weight_key])).float() + scale = torch.as_tensor(_to_plain_tensor(out[scale_key])).float() + out[weight_key] = weight * scale + del out[scale_key] + return out + + +def _convert_krea2_native_to_diffusers(sd: dict[str, Any]) -> dict[str, Any]: + """Convert a native/ComfyUI-format Krea-2 state dict (e.g. GGUF) to diffusers Krea2Transformer2DModel keys. + + Top-level module renames:: + + blocks.N.* -> transformer_blocks.N.* + txtfusion.* -> text_fusion.* + first.* -> img_in.* + tmlp.0/2.* -> time_embed.linear_1/2.* + tproj.1.* -> time_mod_proj.* + txtmlp.0/1/3.* -> txt_in.norm / linear_1 / linear_2.* + last.linear/norm/modulation -> final_layer.linear / norm.weight / scale_shift_table + + Within every transformer / text-fusion block:: + + attn.wq/wk/wv/wo -> attn.to_q/to_k/to_v/to_out.0 + attn.gate -> attn.to_gate + attn.qknorm.qnorm/knorm.scale -> attn.norm_q/norm_k.weight + mlp.gate/up/down -> ff.gate/up/down + prenorm/postnorm.scale -> norm1/norm2.weight + mod.lin (6*H,) -> scale_shift_table (6, H) + + The original final-block ``last.down``/``last.up`` projections have no counterpart in the diffusers + ``Krea2FinalLayer`` (a clean AdaLN + linear) and are dropped. + """ + import torch + + new_sd: dict[str, Any] = {} + for key, value in sd.items(): + if not isinstance(key, str): + new_sd[key] = value + continue + # Drop original-only final-block projections (no diffusers equivalent). + if key in ("last.down.weight", "last.up.weight"): + continue + + k = key + # Top-level module prefixes. + if k.startswith("blocks."): + k = "transformer_blocks." + k[len("blocks.") :] + elif k.startswith("txtfusion."): + k = "text_fusion." + k[len("txtfusion.") :] + elif k.startswith("first."): + k = "img_in." + k[len("first.") :] + elif k.startswith("tmlp.0."): + k = "time_embed.linear_1." + k[len("tmlp.0.") :] + elif k.startswith("tmlp.2."): + k = "time_embed.linear_2." + k[len("tmlp.2.") :] + elif k.startswith("tproj.1."): + k = "time_mod_proj." + k[len("tproj.1.") :] + elif k == "txtmlp.0.scale": + k = "txt_in.norm.weight" + elif k.startswith("txtmlp.1."): + k = "txt_in.linear_1." + k[len("txtmlp.1.") :] + elif k.startswith("txtmlp.3."): + k = "txt_in.linear_2." + k[len("txtmlp.3.") :] + elif k == "last.linear.weight": + k = "final_layer.linear.weight" + elif k == "last.linear.bias": + k = "final_layer.linear.bias" + elif k == "last.norm.scale": + k = "final_layer.norm.weight" + elif k == "last.modulation.lin": + k = "final_layer.scale_shift_table" + + # Within-block sub-module renames (apply to transformer_blocks.* and text_fusion.*). + k = k.replace(".attn.wq.weight", ".attn.to_q.weight") + k = k.replace(".attn.wk.weight", ".attn.to_k.weight") + k = k.replace(".attn.wv.weight", ".attn.to_v.weight") + k = k.replace(".attn.wo.weight", ".attn.to_out.0.weight") + k = k.replace(".attn.gate.weight", ".attn.to_gate.weight") + k = k.replace(".attn.qknorm.qnorm.scale", ".attn.norm_q.weight") + k = k.replace(".attn.qknorm.knorm.scale", ".attn.norm_k.weight") + k = k.replace(".mlp.gate.weight", ".ff.gate.weight") + k = k.replace(".mlp.up.weight", ".ff.up.weight") + k = k.replace(".mlp.down.weight", ".ff.down.weight") + k = k.replace(".prenorm.scale", ".norm1.weight") + k = k.replace(".postnorm.scale", ".norm2.weight") + + # Per-image-block modulation table: flat (6*H,) -> (6, H). + if k.endswith(".mod.lin"): + k = k[: -len(".mod.lin")] + ".scale_shift_table" + value = torch.as_tensor(_to_plain_tensor(value)).reshape(6, -1) + + new_sd[k] = value + return new_sd + + # Default Krea2Transformer2DModel config (from the Krea-2-Turbo transformer/config.json). Used when # loading a bare single-file checkpoint that has no accompanying config.json. KREA2_TRANSFORMER_CONFIG = { @@ -128,9 +273,9 @@ def _load_model( class Krea2CheckpointModel(ModelLoader): """Class to load Krea-2 transformer models from single-file checkpoints (safetensors). - NOTE: the official Krea-2-Turbo release ships only in (sharded) diffusers format. This single-file - path mirrors the Z-Image checkpoint loader and uses the known transformer config; it has not been - validated against a real single-file Krea-2 checkpoint. + Handles plain bf16/fp16 checkpoints as well as ComfyUI 'scaled fp8' checkpoints (fp8 weight + + ``.weight_scale``), and both the diffusers and native/ComfyUI key naming. Apply the fp8-storage + setting to keep the (large) transformer fp8-resident; otherwise it loads in full precision. """ def _load_model( @@ -156,18 +301,12 @@ def _load_from_singlefile(self, config: AnyModelConfig) -> AnyModel: model_path = Path(config.path) sd = load_file(model_path) - - # Strip ComfyUI-style key prefixes if present. - prefix_to_strip = None - for prefix in ("model.diffusion_model.", "diffusion_model."): - if any(k.startswith(prefix) for k in sd.keys() if isinstance(k, str)): - prefix_to_strip = prefix - break - if prefix_to_strip: - sd = { - (k[len(prefix_to_strip) :] if isinstance(k, str) and k.startswith(prefix_to_strip) else k): v - for k, v in sd.items() - } + sd = _strip_comfyui_prefix(sd) + # ComfyUI 'scaled fp8' checkpoints: fold the per-tensor weight_scale into the weights (→ float). + sd = _dequantize_scaled_fp8(sd) + # Native/ComfyUI key naming → diffusers Krea2Transformer2DModel keys. + if _is_native_krea2_format(sd): + sd = _convert_krea2_native_to_diffusers(sd) target_device = TorchDevice.choose_torch_device() model_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) @@ -181,6 +320,67 @@ def _load_from_singlefile(self, config: AnyModelConfig) -> AnyModel: sd[k] = sd[k].to(model_dtype) model.load_state_dict(sd, assign=True, strict=False) + # Honor the fp8-storage setting (re-quantizes the dequantized weights to fp8-resident on CUDA). + model = self._apply_fp8_layerwise_casting(model, config, SubModelType.Transformer) + return model + + +@ModelLoaderRegistry.register(base=BaseModelType.Krea2, type=ModelType.Main, format=ModelFormat.GGUFQuantized) +class Krea2GGUFCheckpointModel(ModelLoader): + """Class to load GGUF-quantized Krea-2 transformer models (single-file). + + GGUF ships only the transformer; the VAE (Qwen-Image), Qwen3-VL encoder, tokenizer and scheduler + are sourced separately by the Krea-2 model-loader invocation (mix-and-match, like Z-Image/FLUX). + The GGML tensors stay quantized and are dequantized on-the-fly during inference. + """ + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + if not isinstance(config, Checkpoint_Config_Base): + raise ValueError("Only CheckpointConfigBase models are supported here.") + if submodel_type is not SubModelType.Transformer: + raise ValueError( + f"Only Transformer submodels are supported. Received: {submodel_type.value if submodel_type else 'None'}" + ) + return self._load_from_gguf(config) + + def _load_from_gguf(self, config: AnyModelConfig) -> AnyModel: + from diffusers import Krea2Transformer2DModel + + from invokeai.backend.util.logging import InvokeAILogger + + if not isinstance(config, Main_GGUF_Krea2_Config): + raise TypeError(f"Expected Main_GGUF_Krea2_Config, got {type(config).__name__}.") + logger = InvokeAILogger.get_logger(self.__class__.__name__) + + model_path = Path(config.path) + target_device = TorchDevice.choose_torch_device() + compute_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + + # GGMLTensor wrappers (kept on CPU; dequantized on-the-fly by the cache during inference). + sd = gguf_sd_loader(model_path, compute_dtype=compute_dtype) + sd = _strip_comfyui_prefix(sd) + # GGUF conversions use the native/ComfyUI compact key naming; remap to diffusers keys. + if _is_native_krea2_format(sd): + sd = _convert_krea2_native_to_diffusers(sd) + + with accelerate.init_empty_weights(): + model = Krea2Transformer2DModel(**KREA2_TRANSFORMER_CONFIG) + + missing_keys, unexpected_keys = model.load_state_dict(sd, assign=True, strict=False) + # Surface key-format mismatches: GGUF conversions (city96/ComfyUI) may use original/ComfyUI key + # names that differ from the diffusers Krea2Transformer2DModel. If many params remain on meta, + # a dedicated GGUF->diffusers key conversion is needed (cf. Z-Image's _convert_z_image_gguf_to_diffusers). + still_meta = [name for name, p in model.named_parameters() if p.is_meta] + if still_meta: + logger.warning( + f"Krea-2 GGUF load left {len(still_meta)} parameters on meta (missing from state dict). " + f"First few: {still_meta[:8]}. unexpected_keys={len(unexpected_keys)}. " + "This likely means the GGUF uses a key naming that needs conversion to diffusers format." + ) return model @@ -228,3 +428,127 @@ def _load_model( f"Only Tokenizer and TextEncoder submodels are supported. " f"Received: {submodel_type.value if submodel_type else 'None'}" ) + + +def _remap_qwen3vl_singlefile_keys(sd: dict[str, Any]) -> dict[str, Any]: + """Remap ComfyUI single-file Qwen3-VL keys to the transformers ``Qwen3VLModel`` layout. + + ComfyUI/native layout uses a single ``model.`` prefix for both towers; transformers splits them: + ``model.visual.*`` -> ``visual.*`` and ``model.`` (layers/embed_tokens/norm) -> ``language_model.``. + """ + out: dict[str, Any] = {} + for k, v in sd.items(): + if not isinstance(k, str): + out[k] = v + continue + # Strip a leading "model." (some checkpoints prefix everything with it), then route by tower. + key = k[len("model.") :] if k.startswith("model.") else k + if key.startswith("visual.") or key.startswith("language_model."): + # Already the transformers layout (e.g. "model.language_model.*" / "model.visual.*"). + out[key] = v + else: + # Bare language-model keys (layers.* / embed_tokens / norm) belong under language_model. + out["language_model." + key] = v + return out + + +@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Qwen3VLEncoder, format=ModelFormat.Checkpoint) +class Qwen3VLEncoderCheckpointLoader(ModelLoader): + """Loads a single-file Qwen3-VL encoder checkpoint (e.g. ComfyUI ``qwen3vl_4b_bf16`` / ``_fp8_scaled``). + + The checkpoint bundles the language model + visual tower but no config/tokenizer; those are pulled + from HuggingFace (``Qwen/Qwen3-VL-4B-Instruct``) with offline-cache fallback. ComfyUI 'scaled fp8' + weights are dequantized to the compute dtype on load. + """ + + DEFAULT_HF_REPO = "Qwen/Qwen3-VL-4B-Instruct" + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + if not isinstance(config, Qwen3VLEncoder_Checkpoint_Config): + raise ValueError("Only Qwen3VLEncoder_Checkpoint_Config models are supported here.") + + match submodel_type: + case SubModelType.Tokenizer: + return self._load_tokenizer() + case SubModelType.TextEncoder: + return self._load_text_encoder(config) + + raise ValueError( + f"Only Tokenizer and TextEncoder submodels are supported. " + f"Received: {submodel_type.value if submodel_type else 'None'}" + ) + + def _load_tokenizer(self) -> AnyModel: + # A partial offline cache (e.g. config present but vocab/merges missing) raises something other + # than OSError (e.g. TypeError) deep in the slow-tokenizer path, so catch broadly and re-fetch. + try: + return AutoTokenizer.from_pretrained(self.DEFAULT_HF_REPO, local_files_only=True, extra_special_tokens={}) + except Exception: + return AutoTokenizer.from_pretrained(self.DEFAULT_HF_REPO, extra_special_tokens={}) + + def _load_hf_config(self) -> Any: + from transformers import AutoConfig + + try: + te_config = AutoConfig.from_pretrained(self.DEFAULT_HF_REPO, local_files_only=True) + except Exception: + te_config = AutoConfig.from_pretrained(self.DEFAULT_HF_REPO) + # transformers' Qwen3-VL rotary embedding reads `rope_scaling`; the config stores `rope_parameters`. + text_config = getattr(te_config, "text_config", None) + if text_config is not None: + rope_params = getattr(text_config, "rope_parameters", None) + if getattr(text_config, "rope_scaling", None) is None and rope_params is not None: + text_config.rope_scaling = rope_params + return te_config + + def _load_text_encoder(self, config: Qwen3VLEncoder_Checkpoint_Config) -> AnyModel: + import torch + from safetensors.torch import load_file + from transformers import Qwen3VLModel + + model_path = Path(config.path) + target_device = TorchDevice.choose_torch_device() + model_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + + sd = load_file(str(model_path)) + # Detect an fp8 source (ComfyUI 'scaled fp8' weight_scale keys, or raw float8 weights) BEFORE + # dequantizing. An fp8-on-disk encoder is kept fp8-resident with layerwise upcasting below, so + # it occupies ~half the VRAM of the dequantized bf16 model (the whole point of shipping fp8). + source_is_fp8 = any(isinstance(k, str) and k.endswith(".weight_scale") for k in sd) or any( + getattr(t, "dtype", None) in (torch.float8_e4m3fn, torch.float8_e5m2) for t in sd.values() + ) + # ComfyUI 'scaled fp8': fold weight_scale into the weights, then drop quantization metadata. + sd = _dequantize_scaled_fp8(sd) + for k in list(sd.keys()): + if isinstance(k, str) and (k.endswith(".comfy_quant") or "scale_input" in k): + del sd[k] + sd = _remap_qwen3vl_singlefile_keys(sd) + + te_config = self._load_hf_config() + with accelerate.init_empty_weights(): + model = Qwen3VLModel._from_config(te_config) + + new_sd_size = sum(ten.nelement() * model_dtype.itemsize for ten in sd.values()) + self._ram_cache.make_room(new_sd_size) + for k in sd.keys(): + sd[k] = sd[k].to(model_dtype) + + model.load_state_dict(sd, assign=True, strict=False) + + # Keep an fp8 encoder running in fp8 (storage=float8_e4m3fn, per-layer upcast to the compute + # dtype during forward) on CUDA. `_should_use_fp8` deliberately excludes text encoders (and the + # config has no fp8_storage toggle), so apply the hook-based casting directly here. This roughly + # halves the encoder's resident VRAM (~8.9GB bf16 -> ~4.4GB), which avoids partial-load thrashing + # when it shares the GPU with a large transformer. + if source_is_fp8 and self._torch_device.type == "cuda": + self._apply_fp8_to_nn_module(model, storage_dtype=torch.float8_e4m3fn, compute_dtype=model_dtype) + self._logger.info( + f"FP8 layerwise casting enabled for Qwen3-VL encoder '{config.name}' " + f"(storage=float8_e4m3fn, compute={model_dtype})." + ) + + return model diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c6333fea3ff..cea331f713f 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1362,6 +1362,10 @@ "zImageQwen3EncoderPlaceholder": "From Qwen3 source model", "zImageQwen3Source": "Qwen3 & VAE Source Model", "zImageQwen3SourcePlaceholder": "Required if VAE/Encoder empty", + "krea2Vae": "VAE (optional)", + "krea2VaePlaceholder": "From Krea-2 diffusers model", + "krea2Qwen3VlEncoder": "Qwen3-VL Encoder (optional)", + "krea2Qwen3VlEncoderPlaceholder": "From Krea-2 diffusers model", "flux2KleinVae": "VAE (optional)", "flux2KleinVaePlaceholder": "From diffusers model", "flux2KleinVaeNoModelPlaceholder": "No diffusers model available", @@ -1681,6 +1685,8 @@ "noQwenImageComponentSourceSelected": "GGUF Qwen Image models require a Diffusers Component Source for VAE/encoder", "noZImageVaeSourceSelected": "No VAE source: Select VAE (FLUX) or Qwen3 Source model", "noZImageQwen3EncoderSourceSelected": "No Qwen3 Encoder source: Select Qwen3 Encoder or Qwen3 Source model", + "noKrea2VaeModelSelected": "Non-diffusers Krea-2: select a VAE in Advanced settings", + "noKrea2Qwen3VlEncoderModelSelected": "Non-diffusers Krea-2: select a Qwen3-VL Encoder in Advanced settings", "noAnimaVaeModelSelected": "No Anima VAE model selected", "noAnimaQwen3EncoderModelSelected": "No Anima Qwen3 Encoder model selected", "fluxModelIncompatibleBboxWidth": "$t(parameters.invoke.fluxRequiresDimensionsToBeMultipleOf16), bbox width is {{width}}", diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts index 7d398b0dcff..c4d330465a3 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts @@ -241,6 +241,23 @@ const slice = createSlice({ } state.zImageQwen3SourceModel = result.data; }, + krea2VaeModelSelected: (state, action: PayloadAction) => { + const result = zParamsState.shape.krea2VaeModel.safeParse(action.payload); + if (!result.success) { + return; + } + state.krea2VaeModel = result.data; + }, + krea2Qwen3VlEncoderModelSelected: ( + state, + action: PayloadAction<{ key: string; name: string; base: string } | null> + ) => { + const result = zParamsState.shape.krea2Qwen3VlEncoderModel.safeParse(action.payload); + if (!result.success) { + return; + } + state.krea2Qwen3VlEncoderModel = result.data; + }, animaVaeModelSelected: (state, action: PayloadAction) => { const result = zParamsState.shape.animaVaeModel.safeParse(action.payload); if (!result.success) { @@ -630,6 +647,8 @@ const resetState = (state: ParamsState): ParamsState => { newState.zImageVaeModel = oldState.zImageVaeModel; newState.zImageQwen3EncoderModel = oldState.zImageQwen3EncoderModel; newState.zImageQwen3SourceModel = oldState.zImageQwen3SourceModel; + newState.krea2VaeModel = oldState.krea2VaeModel; + newState.krea2Qwen3VlEncoderModel = oldState.krea2Qwen3VlEncoderModel; newState.animaVaeModel = oldState.animaVaeModel; newState.animaQwen3EncoderModel = oldState.animaQwen3EncoderModel; newState.kleinVaeModel = oldState.kleinVaeModel; @@ -690,6 +709,8 @@ export const { zImageVaeModelSelected, zImageQwen3EncoderModelSelected, zImageQwen3SourceModelSelected, + krea2VaeModelSelected, + krea2Qwen3VlEncoderModelSelected, kleinVaeModelSelected, kleinQwen3EncoderModelSelected, qwenImageComponentSourceSelected, @@ -807,6 +828,8 @@ export const selectCLIPGEmbedModel = createParamsSelector((params) => params.cli export const selectZImageVaeModel = createParamsSelector((params) => params.zImageVaeModel); export const selectZImageQwen3EncoderModel = createParamsSelector((params) => params.zImageQwen3EncoderModel); export const selectZImageQwen3SourceModel = createParamsSelector((params) => params.zImageQwen3SourceModel); +export const selectKrea2VaeModel = createParamsSelector((params) => params.krea2VaeModel); +export const selectKrea2Qwen3VlEncoderModel = createParamsSelector((params) => params.krea2Qwen3VlEncoderModel); export const selectAnimaVaeModel = createParamsSelector((params) => params.animaVaeModel); export const selectAnimaQwen3EncoderModel = createParamsSelector((params) => params.animaQwen3EncoderModel); export const selectAnimaScheduler = createParamsSelector((params) => params.animaScheduler); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 53caca55eb2..6334b21e429 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -854,6 +854,10 @@ export const zParamsState = z.object({ zImageSeedVarianceEnabled: z.boolean(), zImageSeedVarianceStrength: z.number().min(0).max(2), zImageSeedVarianceRandomizePercent: z.number().min(1).max(100), + // Krea-2 standalone submodels (optional; used when the transformer is a single-file checkpoint/GGUF + // that has no bundled VAE / Qwen3-VL encoder. When null, they are extracted from the diffusers model.) + krea2VaeModel: zParameterVAEModel.nullable(), + krea2Qwen3VlEncoderModel: zModelIdentifierField.nullable(), // Krea-2 conditioning enhancers (optional; both default off so stock behaviour is unchanged) krea2SeedVarianceEnabled: z.boolean(), krea2SeedVarianceStrength: z.number().min(0).max(100), @@ -944,6 +948,8 @@ export const getInitialParamsState = (): ParamsState => ({ zImageSeedVarianceEnabled: false, zImageSeedVarianceStrength: 0.1, zImageSeedVarianceRandomizePercent: 50, + krea2VaeModel: null, + krea2Qwen3VlEncoderModel: null, krea2SeedVarianceEnabled: false, krea2SeedVarianceStrength: 20, krea2SeedVarianceRandomizePercent: 50, diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts index 62f476a61ea..38e2fe96b1a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts @@ -29,14 +29,14 @@ export const buildKrea2Graph = async (arg: GraphBuilderArg): Promise { + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const krea2VaeModel = useAppSelector(selectKrea2VaeModel); + // Krea-2 / Qwen-Image / Anima share the identical AutoencoderKLQwenImage VAE. A standalone + // qwen_image_vae.safetensors is classified as either base (the weights are indistinguishable), so + // accept both here. + const [qwenImageVaes, { isLoading: isLoadingQwen }] = useQwenImageVAEModels(); + const [animaVaes, { isLoading: isLoadingAnima }] = useAnimaVAEModels(); + const modelConfigs = useMemo(() => [...qwenImageVaes, ...animaVaes], [qwenImageVaes, animaVaes]); + const isLoading = isLoadingQwen || isLoadingAnima; + + const _onChange = useCallback( + (model: VAEModelConfig | null) => { + dispatch(krea2VaeModelSelected(model ? zModelIdentifierField.parse(model) : null)); + }, + [dispatch] + ); + + const { options, value, onChange, noOptionsMessage } = useModelCombobox({ + modelConfigs, + onChange: _onChange, + selectedModel: krea2VaeModel, + isLoading, + }); + + return ( + + {t('modelManager.krea2Vae')} + + + ); +}); + +ParamKrea2VaeModelSelect.displayName = 'ParamKrea2VaeModelSelect'; + +/** + * Krea-2 Qwen3-VL Encoder Model Select - optional standalone encoder used when the transformer is a + * single-file checkpoint/GGUF without a bundled encoder. + */ +const ParamKrea2Qwen3VlEncoderModelSelect = memo(() => { + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const krea2Qwen3VlEncoderModel = useAppSelector(selectKrea2Qwen3VlEncoderModel); + const [modelConfigs, { isLoading }] = useQwen3VLEncoderModels(); + + const _onChange = useCallback( + (model: Qwen3VLEncoderModelConfig | null) => { + dispatch(krea2Qwen3VlEncoderModelSelected(model ? zModelIdentifierField.parse(model) : null)); + }, + [dispatch] + ); + + const { options, value, onChange, noOptionsMessage } = useModelCombobox({ + modelConfigs, + onChange: _onChange, + selectedModel: krea2Qwen3VlEncoderModel, + isLoading, + }); + + return ( + + {t('modelManager.krea2Qwen3VlEncoder')} + + + ); +}); + +ParamKrea2Qwen3VlEncoderModelSelect.displayName = 'ParamKrea2Qwen3VlEncoderModelSelect'; + +/** + * Combined component for Krea-2 standalone submodel selection (VAE + Qwen3-VL encoder). + */ +const ParamKrea2ModelSelects = () => { + return ( + <> + + + + ); +}; + +export default memo(ParamKrea2ModelSelects); diff --git a/invokeai/frontend/web/src/features/queue/store/readiness.ts b/invokeai/frontend/web/src/features/queue/store/readiness.ts index 84bc374158f..86b3140b447 100644 --- a/invokeai/frontend/web/src/features/queue/store/readiness.ts +++ b/invokeai/frontend/web/src/features/queue/store/readiness.ts @@ -324,6 +324,17 @@ export const getReasonsWhyCannotEnqueueGenerateTab = (arg: { } } + if (model?.base === 'krea-2' && model.format !== 'diffusers') { + // Non-diffusers Krea-2 (single-file checkpoint / GGUF) ships only the transformer, so a standalone + // VAE and Qwen3-VL encoder must be selected. Diffusers models bundle them, so they're optional there. + if (!params.krea2VaeModel) { + reasons.push({ content: i18n.t('parameters.invoke.noKrea2VaeModelSelected') }); + } + if (!params.krea2Qwen3VlEncoderModel) { + reasons.push({ content: i18n.t('parameters.invoke.noKrea2Qwen3VlEncoderModelSelected') }); + } + } + if (model?.base === 'anima') { if (!params.animaVaeModel) { reasons.push({ content: i18n.t('parameters.invoke.noAnimaVaeModelSelected') }); @@ -784,6 +795,17 @@ export const getReasonsWhyCannotEnqueueCanvasTab = (arg: { } } + if (model?.base === 'krea-2' && model.format !== 'diffusers') { + // Non-diffusers Krea-2 (single-file checkpoint / GGUF) ships only the transformer, so a standalone + // VAE and Qwen3-VL encoder must be selected. Diffusers models bundle them, so they're optional there. + if (!params.krea2VaeModel) { + reasons.push({ content: i18n.t('parameters.invoke.noKrea2VaeModelSelected') }); + } + if (!params.krea2Qwen3VlEncoderModel) { + reasons.push({ content: i18n.t('parameters.invoke.noKrea2Qwen3VlEncoderModelSelected') }); + } + } + if (model?.base === 'anima') { if (!params.animaVaeModel) { reasons.push({ content: i18n.t('parameters.invoke.noAnimaVaeModelSelected') }); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx index eb989f4b109..d6f05d40b5b 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx @@ -22,6 +22,7 @@ import ParamCLIPGEmbedModelSelect from 'features/parameters/components/Advanced/ import ParamCLIPLEmbedModelSelect from 'features/parameters/components/Advanced/ParamCLIPLEmbedModelSelect'; import ParamClipSkip from 'features/parameters/components/Advanced/ParamClipSkip'; import ParamFlux2KleinModelSelect from 'features/parameters/components/Advanced/ParamFlux2KleinModelSelect'; +import ParamKrea2ModelSelects from 'features/parameters/components/Advanced/ParamKrea2ModelSelects'; import ParamQwenImageComponentSourceSelect from 'features/parameters/components/Advanced/ParamQwenImageComponentSourceSelect'; import ParamQwenImageQuantization from 'features/parameters/components/Advanced/ParamQwenImageQuantization'; import ParamT5EncoderModelSelect from 'features/parameters/components/Advanced/ParamT5EncoderModelSelect'; @@ -171,6 +172,11 @@ export const AdvancedSettingsAccordion = memo(() => { )} + {isKrea2 && ( + + + + )} ); diff --git a/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts b/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts index ca886789cea..0918e822665 100644 --- a/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts +++ b/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts @@ -28,6 +28,7 @@ import { isLoRAModelConfig, isMainOrExternalModelConfig, isQwen3EncoderModelConfig, + isQwen3VLEncoderModelConfig, isQwenImageDiffusersMainModelConfig, isQwenImageVAEModelConfig, isQwenVLEncoderModelConfig, @@ -111,6 +112,7 @@ export const useQwenImageDiffusersModels = () => buildModelsHook(isQwenImageDiff export const useQwenImageVAEModels = () => buildModelsHook(isQwenImageVAEModelConfig)(); export const useQwenVLEncoderModels = () => buildModelsHook(isQwenVLEncoderModelConfig)(); export const useQwen3EncoderModels = () => buildModelsHook(isQwen3EncoderModelConfig)(); +export const useQwen3VLEncoderModels = () => buildModelsHook(isQwen3VLEncoderModelConfig)(); export const useGlobalReferenceImageModels = buildModelsHook( (config) => isIPAdapterModelConfig(config) || isFluxReduxModelConfig(config) || isFluxKontextModelConfig(config) ); From b57e3bd374f787caf79a73037b04f4220cd8d0d0 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Thu, 2 Jul 2026 09:14:13 +0200 Subject: [PATCH 03/17] =?UTF-8?q?fix(krea2):=20re-apply=20Wan=E2=86=92Qwen?= =?UTF-8?q?Image=20VAE=20adapter=20after=20upstream=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An upstream merge reintroduced the AutoencoderKLQwenImage isinstance asserts in the qwen VAE nodes (without the import → F821) and dropped the adapter in the i2l path. A native-layout qwen_image_vae single file is classified with the Anima base and loaded as AutoencoderKLWan, so the asserts fail at runtime. - qwen_image_latents_to_image: drop the reintroduced pre-device assert (the as_qwen_image_vae adapter inside model_on_device already handles the class). - qwen_image_image_to_latents: restore the as_qwen_image_vae import + adapter call, remove both asserts. - estimate_vae_working_memory_qwen_image only reads tensor shape + element size, so it runs correctly on either VAE class before the adapter. --- invokeai/app/invocations/krea2_denoise.py | 17 +- .../qwen_image_image_to_latents.py | 8 +- .../qwen_image_latents_to_image.py | 5 +- .../backend/model_manager/configs/main.py | 39 +- invokeai/backend/model_manager/taxonomy.py | 6 + invokeai/frontend/web/openapi.json | 3492 ++++++++++++++--- .../web/src/features/modelManagerV2/models.ts | 2 + .../web/src/features/nodes/types/common.ts | 2 +- .../frontend/web/src/services/api/schema.ts | 266 +- 9 files changed, 3203 insertions(+), 634 deletions(-) diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index a5b0c5635e4..88a14419b73 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -144,16 +144,25 @@ def _prepare_cfg_scale(self, num_timesteps: int) -> list[float]: raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}") def _is_distilled(self, context: InvocationContext) -> bool: - """Read is_distilled from the model's model_index.json (pipeline-level flag).""" + """Whether the transformer is the distilled Turbo checkpoint (fixed mu) vs. Raw (dynamic mu). + + Prefer the classified variant (works for diffusers, single-file and GGUF alike); fall back to + the pipeline-level ``is_distilled`` flag in model_index.json, then default to distilled. + """ + from invokeai.backend.model_manager.taxonomy import Krea2VariantType + try: - model_path = context.models.get_absolute_path(context.models.get_config(self.transformer.transformer)) - model_index = model_path / "model_index.json" + config = context.models.get_config(self.transformer.transformer) + variant = getattr(config, "variant", None) + if variant is not None: + return variant != Krea2VariantType.Base + model_index = context.models.get_absolute_path(config) / "model_index.json" if model_index.is_file(): with open(model_index) as f: return bool(json.load(f).get("is_distilled", False)) except Exception: pass - # Only the distilled Turbo checkpoint is currently supported. + # Default to the distilled Turbo behavior. return True def _run_diffusion(self, context: InvocationContext): diff --git a/invokeai/app/invocations/qwen_image_image_to_latents.py b/invokeai/app/invocations/qwen_image_image_to_latents.py index 4c99b66479f..f56b0695dc3 100644 --- a/invokeai/app/invocations/qwen_image_image_to_latents.py +++ b/invokeai/app/invocations/qwen_image_image_to_latents.py @@ -45,14 +45,18 @@ class QwenImageImageToLatentsInvocation(BaseInvocation, WithMetadata, WithBoard) @staticmethod def vae_encode(vae_info: LoadedModel, image_tensor: torch.Tensor) -> torch.Tensor: - assert isinstance(vae_info.model, AutoencoderKLQwenImage) + # NOTE: vae_info.model may be an AutoencoderKLWan (a native-layout qwen_image_vae single file is + # classified with the Anima base); it is reinterpreted as AutoencoderKLQwenImage inside the + # model_on_device context below. The working-memory estimate only reads tensor shape + element + # size, so it is safe to run on either class here. estimated_working_memory = estimate_vae_working_memory_qwen_image( operation="encode", image_tensor=image_tensor, vae=vae_info.model, ) with vae_info.model_on_device(working_mem_bytes=estimated_working_memory) as (_, vae): - assert isinstance(vae, AutoencoderKLQwenImage) + # Reinterpret an Anima-classified Wan VAE as AutoencoderKLQwenImage (identical weights). + vae = as_qwen_image_vae(vae) vae.disable_tiling() diff --git a/invokeai/app/invocations/qwen_image_latents_to_image.py b/invokeai/app/invocations/qwen_image_latents_to_image.py index 1f4c09bb8ed..056941604c2 100644 --- a/invokeai/app/invocations/qwen_image_latents_to_image.py +++ b/invokeai/app/invocations/qwen_image_latents_to_image.py @@ -41,7 +41,10 @@ def invoke(self, context: InvocationContext) -> ImageOutput: latents = context.tensors.load(self.latents.latents_name) vae_info = context.models.load(self.vae.vae) - assert isinstance(vae_info.model, AutoencoderKLQwenImage) + # NOTE: vae_info.model may be an AutoencoderKLWan (a native-layout qwen_image_vae single file is + # classified with the Anima base); it is reinterpreted as AutoencoderKLQwenImage inside the + # model_on_device context below. The working-memory estimate only reads tensor shape + element + # size, so it is safe to run on either class here. estimated_working_memory = estimate_vae_working_memory_qwen_image( operation="decode", image_tensor=latents, diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index f8423442e5a..1ecdca83a77 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -102,8 +102,10 @@ def from_base( case BaseModelType.QwenImage: return cls(steps=40, cfg_scale=4.0, width=1024, height=1024) case BaseModelType.Krea2: - # Krea-2-Turbo is distilled: 8 steps, CFG disabled (guidance_scale=0). - # cfg_scale has a floor of 1 (ge=1); 1.0 means "no guidance" for the Krea-2 denoise loop. + # Krea-2-Raw (Base, undistilled) needs more steps and CFG; Turbo (distilled) uses 8 + # steps with CFG disabled. cfg_scale has a floor of 1 (ge=1); 1.0 means "no guidance". + if variant == Krea2VariantType.Base: + return cls(steps=28, cfg_scale=4.5, width=1024, height=1024) return cls(steps=8, cfg_scale=1.0, width=1024, height=1024) case _: # TODO(psyche): Do we want defaults for other base types? @@ -200,6 +202,20 @@ def _has_z_image_keys(state_dict: dict[str | int, Any]) -> bool: return False +def _get_krea2_variant_from_name(name: str) -> Krea2VariantType: + """Guess the Krea-2 variant from a single-file/GGUF filename. + + Turbo and Raw (Base) share the identical transformer architecture, so a single-file checkpoint + cannot be distinguished from its weights. Filenames containing "raw" or "base" (e.g. + "Krea-2-Raw", "krea2_base_q4") indicate the undistilled Base model; everything else defaults to + the distilled Turbo. The user can override the variant in the model manager. + """ + lowered = name.lower() + if "raw" in lowered or "base" in lowered: + return Krea2VariantType.Base + return Krea2VariantType.Turbo + + def _has_krea2_keys(state_dict: dict[str | int, Any]) -> bool: """Check if state dict contains Krea-2 (Krea2Transformer2DModel) transformer keys. @@ -1376,9 +1392,18 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - @classmethod def _get_variant(cls, mod: ModelOnDisk) -> Krea2VariantType: - """Determine the Krea-2 variant. Only the distilled Turbo checkpoint is currently supported.""" - # The distilled (Turbo) checkpoint sets is_distilled=true in model_index.json. Base (midtrain) - # support is not yet implemented, so everything currently maps to Turbo. + """Determine the Krea-2 variant from the pipeline-level ``is_distilled`` flag. + + Krea-2-Turbo sets ``is_distilled=true`` in model_index.json (distilled, 8 steps, CFG off); + Krea-2-Raw sets ``is_distilled=false`` (undistilled Base, more steps, CFG on). The transformer + architectures are identical, so this flag is the only reliable discriminator. + """ + try: + config = get_config_dict_or_raise(mod.path / "model_index.json") + if config.get("is_distilled", True) is False: + return Krea2VariantType.Base + except Exception: + pass return Krea2VariantType.Turbo @@ -1399,7 +1424,7 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - cls._validate_does_not_look_like_gguf_quantized(mod) - variant = override_fields.pop("variant", None) or Krea2VariantType.Turbo + variant = override_fields.pop("variant", None) or _get_krea2_variant_from_name(mod.path.name) return cls(**override_fields, variant=variant) @@ -1431,7 +1456,7 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - cls._validate_looks_like_gguf_quantized(mod) - variant = override_fields.pop("variant", None) or Krea2VariantType.Turbo + variant = override_fields.pop("variant", None) or _get_krea2_variant_from_name(mod.path.name) return cls(**override_fields, variant=variant) diff --git a/invokeai/backend/model_manager/taxonomy.py b/invokeai/backend/model_manager/taxonomy.py index ae48dd4571f..a35ab1a786c 100644 --- a/invokeai/backend/model_manager/taxonomy.py +++ b/invokeai/backend/model_manager/taxonomy.py @@ -167,6 +167,12 @@ class Krea2VariantType(str, Enum): NOTE: the value is ``krea2_turbo`` (not ``turbo``) to avoid colliding with ``ZImageVariantType.Turbo`` in the variant-string adapter and frontend label maps.""" + Base = "krea2_base" + """Krea-2-Raw - undistilled base model. Runs with more steps (~28) and CFG enabled (~4.5), + using resolution-aware timestep shifting (``is_distilled=false`` in model_index.json). + + NOTE: the value is ``krea2_base`` (not ``base``) for the same disambiguation reason as ``Turbo``.""" + class QwenImageVariantType(str, Enum): """Qwen Image model variants.""" diff --git a/invokeai/frontend/web/openapi.json b/invokeai/frontend/web/openapi.json index e822e8b260e..bef8d1199f6 100644 --- a/invokeai/frontend/web/openapi.json +++ b/invokeai/frontend/web/openapi.json @@ -804,6 +804,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -828,6 +831,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -846,6 +852,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -921,6 +930,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -960,6 +972,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -1125,6 +1143,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -1149,6 +1170,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -1167,6 +1191,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -1242,6 +1269,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -1281,6 +1311,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -1446,6 +1482,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -1470,6 +1509,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -1488,6 +1530,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -1563,6 +1608,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -1602,6 +1650,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -1817,6 +1871,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -1841,6 +1898,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -1859,6 +1919,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -1934,6 +1997,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -1973,6 +2039,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -2212,6 +2284,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -2236,6 +2311,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -2254,6 +2332,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -2329,6 +2410,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -2368,6 +2452,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -3427,6 +3517,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -3451,6 +3544,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -3469,6 +3565,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -3544,6 +3643,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -3583,6 +3685,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -11470,6 +11578,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -11494,6 +11605,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -11512,6 +11626,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -11587,6 +11704,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -11626,6 +11746,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -12006,6 +12132,7 @@ "external", "qwen-image", "anima", + "krea-2", "unknown" ], "title": "BaseModelType", @@ -18918,7 +19045,11 @@ "anima_txt2img", "anima_img2img", "anima_inpaint", - "anima_outpaint" + "anima_outpaint", + "krea2_txt2img", + "krea2_img2img", + "krea2_inpaint", + "krea2_outpaint" ], "type": "string" }, @@ -29091,6 +29222,27 @@ { "$ref": "#/components/schemas/IterateInvocation" }, + { + "$ref": "#/components/schemas/Krea2ConditioningRebalanceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2DenoiseInvocation" + }, + { + "$ref": "#/components/schemas/Krea2LoRACollectionLoader" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2SeedVarianceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2TextEncoderInvocation" + }, { "$ref": "#/components/schemas/LaMaInfillInvocation" }, @@ -29640,6 +29792,15 @@ { "$ref": "#/components/schemas/IterateInvocationOutput" }, + { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderOutput" + }, { "$ref": "#/components/schemas/LatentsCollectionOutput" }, @@ -36674,6 +36835,27 @@ { "$ref": "#/components/schemas/IterateInvocation" }, + { + "$ref": "#/components/schemas/Krea2ConditioningRebalanceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2DenoiseInvocation" + }, + { + "$ref": "#/components/schemas/Krea2LoRACollectionLoader" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2SeedVarianceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2TextEncoderInvocation" + }, { "$ref": "#/components/schemas/LaMaInfillInvocation" }, @@ -37180,6 +37362,15 @@ { "$ref": "#/components/schemas/IterateInvocationOutput" }, + { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderOutput" + }, { "$ref": "#/components/schemas/LatentsCollectionOutput" }, @@ -37803,6 +37994,27 @@ { "$ref": "#/components/schemas/IterateInvocation" }, + { + "$ref": "#/components/schemas/Krea2ConditioningRebalanceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2DenoiseInvocation" + }, + { + "$ref": "#/components/schemas/Krea2LoRACollectionLoader" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2SeedVarianceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2TextEncoderInvocation" + }, { "$ref": "#/components/schemas/LaMaInfillInvocation" }, @@ -38616,6 +38828,27 @@ "iterate": { "$ref": "#/components/schemas/IterateInvocationOutput" }, + "krea2_conditioning_rebalance": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + }, + "krea2_denoise": { + "$ref": "#/components/schemas/LatentsOutput" + }, + "krea2_lora_collection_loader": { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + }, + "krea2_lora_loader": { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + }, + "krea2_model_loader": { + "$ref": "#/components/schemas/Krea2ModelLoaderOutput" + }, + "krea2_seed_variance": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + }, + "krea2_text_encoder": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + }, "l2i": { "$ref": "#/components/schemas/ImageOutput" }, @@ -39107,6 +39340,13 @@ "invokeai_img_val_thresholds", "ip_adapter", "iterate", + "krea2_conditioning_rebalance", + "krea2_denoise", + "krea2_lora_collection_loader", + "krea2_lora_loader", + "krea2_model_loader", + "krea2_seed_variance", + "krea2_text_encoder", "l2i", "latents", "latents_collection", @@ -39700,6 +39940,27 @@ { "$ref": "#/components/schemas/IterateInvocation" }, + { + "$ref": "#/components/schemas/Krea2ConditioningRebalanceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2DenoiseInvocation" + }, + { + "$ref": "#/components/schemas/Krea2LoRACollectionLoader" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2SeedVarianceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2TextEncoderInvocation" + }, { "$ref": "#/components/schemas/LaMaInfillInvocation" }, @@ -40587,6 +40848,27 @@ { "$ref": "#/components/schemas/IterateInvocation" }, + { + "$ref": "#/components/schemas/Krea2ConditioningRebalanceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2DenoiseInvocation" + }, + { + "$ref": "#/components/schemas/Krea2LoRACollectionLoader" + }, + { + "$ref": "#/components/schemas/Krea2LoRALoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2ModelLoaderInvocation" + }, + { + "$ref": "#/components/schemas/Krea2SeedVarianceInvocation" + }, + { + "$ref": "#/components/schemas/Krea2TextEncoderInvocation" + }, { "$ref": "#/components/schemas/LaMaInfillInvocation" }, @@ -42811,11 +43093,969 @@ "type": "object" }, "JsonValue": {}, - "LaMaInfillInvocation": { - "category": "inpaint", + "Krea2ConditioningField": { + "description": "A Krea-2 conditioning tensor primitive value", + "properties": { + "conditioning_name": { + "description": "The name of conditioning tensor", + "title": "Conditioning Name", + "type": "string" + } + }, + "required": ["conditioning_name"], + "title": "Krea2ConditioningField", + "type": "object" + }, + "Krea2ConditioningOutput": { + "class": "output", + "description": "Base class for nodes that output a Krea-2 conditioning tensor.", + "properties": { + "conditioning": { + "$ref": "#/components/schemas/Krea2ConditioningField", + "description": "Conditioning tensor", + "field_kind": "output", + "ui_hidden": false + }, + "type": { + "const": "krea2_conditioning_output", + "default": "krea2_conditioning_output", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["output_meta", "conditioning", "type", "type"], + "title": "Krea2ConditioningOutput", + "type": "object" + }, + "Krea2ConditioningRebalanceInvocation": { + "category": "conditioning", "class": "invocation", - "classification": "stable", - "description": "Infills transparent areas of an image using the LaMa model", + "classification": "prototype", + "description": "Per-layer rebalancing of Krea-2 text conditioning (improves prompt adherence).\n\nKrea-2 conditioning stacks 12 Qwen3-VL hidden-state layers per token. Weighting those layers\nindividually (and applying an overall multiplier) lets you push the model harder toward the prompt,\ncounteracting the quality-dilution from distillation. Ported from the ComfyUI\n`ConditioningKrea2Rebalance` node. This is an optional pass between the text encoder and denoise.", + "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" + }, + "conditioning": { + "anyOf": [ + { + "$ref": "#/components/schemas/Krea2ConditioningField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Conditioning tensor", + "field_kind": "input", + "input": "connection", + "orig_required": true, + "title": "Conditioning" + }, + "per_layer_weights": { + "default": "1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0", + "description": "Comma-separated gains for the 12 tapped encoder layers (exactly 12 values).", + "field_kind": "input", + "input": "any", + "orig_default": "1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0", + "orig_required": false, + "title": "Per Layer Weights", + "type": "string" + }, + "multiplier": { + "default": 4.0, + "description": "Overall multiplier applied to the conditioning after per-layer weighting.", + "field_kind": "input", + "input": "any", + "orig_default": 4.0, + "orig_required": false, + "title": "Multiplier", + "type": "number" + }, + "type": { + "const": "krea2_conditioning_rebalance", + "default": "krea2_conditioning_rebalance", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["conditioning", "krea2", "krea-2"], + "title": "Conditioning Rebalance - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + } + }, + "Krea2DenoiseInvocation": { + "category": "image", + "class": "invocation", + "classification": "prototype", + "description": "Run the denoising process with a Krea-2 model.", + "node_pack": "invokeai", + "properties": { + "board": { + "anyOf": [ + { + "$ref": "#/components/schemas/BoardField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The board to save the image to", + "field_kind": "internal", + "input": "direct", + "orig_required": false, + "ui_hidden": false + }, + "metadata": { + "anyOf": [ + { + "$ref": "#/components/schemas/MetadataField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional metadata to be saved with the image", + "field_kind": "internal", + "input": "connection", + "orig_required": false, + "ui_hidden": false + }, + "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" + }, + "latents": { + "anyOf": [ + { + "$ref": "#/components/schemas/LatentsField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Latents tensor", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false + }, + "denoise_mask": { + "anyOf": [ + { + "$ref": "#/components/schemas/DenoiseMaskField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "A mask of the region to apply the denoising process to. Values of 0.0 represent the regions to be fully denoised, and 1.0 represent the regions to be preserved.", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false + }, + "denoising_start": { + "default": 0.0, + "description": "When to start denoising, expressed a percentage of total steps", + "field_kind": "input", + "input": "any", + "maximum": 1, + "minimum": 0, + "orig_default": 0.0, + "orig_required": false, + "title": "Denoising Start", + "type": "number" + }, + "denoising_end": { + "default": 1.0, + "description": "When to stop denoising, expressed a percentage of total steps", + "field_kind": "input", + "input": "any", + "maximum": 1, + "minimum": 0, + "orig_default": 1.0, + "orig_required": false, + "title": "Denoising End", + "type": "number" + }, + "transformer": { + "anyOf": [ + { + "$ref": "#/components/schemas/TransformerField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Krea-2 model (Transformer) to load", + "field_kind": "input", + "input": "connection", + "orig_required": true, + "title": "Transformer" + }, + "positive_conditioning": { + "anyOf": [ + { + "$ref": "#/components/schemas/Krea2ConditioningField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Positive conditioning tensor", + "field_kind": "input", + "input": "connection", + "orig_required": true + }, + "negative_conditioning": { + "anyOf": [ + { + "$ref": "#/components/schemas/Krea2ConditioningField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Negative conditioning tensor", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false + }, + "cfg_scale": { + "anyOf": [ + { + "type": "number" + }, + { + "items": { + "type": "number" + }, + "type": "array" + } + ], + "default": 1.0, + "description": "Classifier-Free Guidance scale", + "field_kind": "input", + "input": "any", + "orig_default": 1.0, + "orig_required": false, + "title": "CFG Scale" + }, + "width": { + "default": 1024, + "description": "Width of the generated image.", + "field_kind": "input", + "input": "any", + "multipleOf": 16, + "orig_default": 1024, + "orig_required": false, + "title": "Width", + "type": "integer" + }, + "height": { + "default": 1024, + "description": "Height of the generated image.", + "field_kind": "input", + "input": "any", + "multipleOf": 16, + "orig_default": 1024, + "orig_required": false, + "title": "Height", + "type": "integer" + }, + "steps": { + "default": 8, + "description": "Number of steps to run", + "exclusiveMinimum": 0, + "field_kind": "input", + "input": "any", + "orig_default": 8, + "orig_required": false, + "title": "Steps", + "type": "integer" + }, + "seed": { + "default": 0, + "description": "Randomness seed for reproducibility.", + "field_kind": "input", + "input": "any", + "orig_default": 0, + "orig_required": false, + "title": "Seed", + "type": "integer" + }, + "shift": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override the resolution-aware timestep shift (mu). Leave unset to use the model default (mu=1.15 for the distilled Turbo checkpoint).", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false, + "title": "Shift" + }, + "type": { + "const": "krea2_denoise", + "default": "krea2_denoise", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["image", "krea2", "krea-2"], + "title": "Denoise - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/LatentsOutput" + } + }, + "Krea2LoRACollectionLoader": { + "category": "model", + "class": "invocation", + "classification": "stable", + "description": "Applies a collection of LoRAs to a Krea-2 transformer and/or Qwen3-VL encoder.", + "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" + }, + "loras": { + "anyOf": [ + { + "$ref": "#/components/schemas/LoRAField" + }, + { + "items": { + "$ref": "#/components/schemas/LoRAField" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "LoRA models and weights. May be a single LoRA or collection.", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false, + "title": "LoRAs" + }, + "transformer": { + "anyOf": [ + { + "$ref": "#/components/schemas/TransformerField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Transformer", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false, + "title": "Transformer" + }, + "qwen3_vl_encoder": { + "anyOf": [ + { + "$ref": "#/components/schemas/Qwen3VLEncoderField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Qwen3-VL tokenizer and text encoder", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false, + "title": "Qwen3-VL Encoder" + }, + "type": { + "const": "krea2_lora_collection_loader", + "default": "krea2_lora_collection_loader", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["lora", "model", "krea2", "krea-2"], + "title": "Apply LoRA Collection - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + } + }, + "Krea2LoRALoaderInvocation": { + "category": "model", + "class": "invocation", + "classification": "stable", + "description": "Apply a LoRA model to a Krea-2 transformer and/or Qwen3-VL text encoder.", + "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" + }, + "lora": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelIdentifierField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "LoRA model to load", + "field_kind": "input", + "input": "any", + "orig_required": true, + "title": "LoRA", + "ui_model_base": ["krea-2"], + "ui_model_type": ["lora"] + }, + "weight": { + "default": 0.75, + "description": "The weight at which the LoRA is applied to each model", + "field_kind": "input", + "input": "any", + "orig_default": 0.75, + "orig_required": false, + "title": "Weight", + "type": "number" + }, + "transformer": { + "anyOf": [ + { + "$ref": "#/components/schemas/TransformerField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Transformer", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false, + "title": "Krea-2 Transformer" + }, + "qwen3_vl_encoder": { + "anyOf": [ + { + "$ref": "#/components/schemas/Qwen3VLEncoderField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Qwen3-VL tokenizer and text encoder", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false, + "title": "Qwen3-VL Encoder" + }, + "type": { + "const": "krea2_lora_loader", + "default": "krea2_lora_loader", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["lora", "model", "krea2", "krea-2"], + "title": "Apply LoRA - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2LoRALoaderOutput" + } + }, + "Krea2LoRALoaderOutput": { + "class": "output", + "description": "Krea-2 LoRA Loader Output", + "properties": { + "transformer": { + "anyOf": [ + { + "$ref": "#/components/schemas/TransformerField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Transformer", + "field_kind": "output", + "title": "Krea-2 Transformer", + "ui_hidden": false + }, + "qwen3_vl_encoder": { + "anyOf": [ + { + "$ref": "#/components/schemas/Qwen3VLEncoderField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Qwen3-VL tokenizer and text encoder", + "field_kind": "output", + "title": "Qwen3-VL Encoder", + "ui_hidden": false + }, + "type": { + "const": "krea2_lora_loader_output", + "default": "krea2_lora_loader_output", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["output_meta", "transformer", "qwen3_vl_encoder", "type", "type"], + "title": "Krea2LoRALoaderOutput", + "type": "object" + }, + "Krea2ModelLoaderInvocation": { + "category": "model", + "class": "invocation", + "classification": "prototype", + "description": "Loads a Krea-2 model, outputting its submodels.\n\nBy default the VAE (Qwen-Image VAE) and Qwen3-VL text encoder are extracted from the Krea-2\ndiffusers pipeline. Standalone overrides may be supplied (e.g. when the transformer is a\nsingle-file checkpoint that has no bundled VAE / encoder).", + "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" + }, + "model": { + "$ref": "#/components/schemas/ModelIdentifierField", + "description": "Krea-2 model (Transformer) to load", + "field_kind": "input", + "input": "direct", + "orig_required": true, + "title": "Transformer", + "ui_model_base": ["krea-2"], + "ui_model_type": ["main"] + }, + "vae_model": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelIdentifierField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Standalone VAE model. Krea-2 uses the Qwen-Image VAE (16-channel). If not provided, the VAE is loaded from the Krea-2 (diffusers) model.", + "field_kind": "input", + "input": "direct", + "orig_default": null, + "orig_required": false, + "title": "VAE", + "ui_model_base": ["qwen-image"], + "ui_model_type": ["vae"] + }, + "qwen3_vl_encoder_model": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelIdentifierField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Standalone Qwen3-VL Encoder model. If not provided, the encoder is loaded from the Krea-2 (diffusers) model.", + "field_kind": "input", + "input": "direct", + "orig_default": null, + "orig_required": false, + "title": "Qwen3-VL Encoder", + "ui_model_type": ["qwen3_vl_encoder"] + }, + "type": { + "const": "krea2_model_loader", + "default": "krea2_model_loader", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["model", "type", "id"], + "tags": ["model", "krea2", "krea-2"], + "title": "Main Model - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2ModelLoaderOutput" + } + }, + "Krea2ModelLoaderOutput": { + "class": "output", + "description": "Krea-2 base model loader output.", + "properties": { + "transformer": { + "$ref": "#/components/schemas/TransformerField", + "description": "Transformer", + "field_kind": "output", + "title": "Transformer", + "ui_hidden": false + }, + "qwen3_vl_encoder": { + "$ref": "#/components/schemas/Qwen3VLEncoderField", + "description": "Qwen3-VL tokenizer and text encoder", + "field_kind": "output", + "title": "Qwen3-VL Encoder", + "ui_hidden": false + }, + "vae": { + "$ref": "#/components/schemas/VAEField", + "description": "VAE", + "field_kind": "output", + "title": "VAE", + "ui_hidden": false + }, + "type": { + "const": "krea2_model_loader_output", + "default": "krea2_model_loader_output", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["output_meta", "transformer", "qwen3_vl_encoder", "vae", "type", "type"], + "title": "Krea2ModelLoaderOutput", + "type": "object" + }, + "Krea2SeedVarianceInvocation": { + "category": "conditioning", + "class": "invocation", + "classification": "prototype", + "description": "Inject per-seed diversity into Krea-2 text conditioning.\n\nDistilled few-step models (like Krea-2-Turbo) suffer from low seed variance \u2014 different seeds give\nnear-identical images. This adds seeded uniform noise to a random subset of the text-embedding\nvalues, trading some prompt adherence for variety (the same idea as the Z-Image-Turbo\n`SeedVarianceEnhancer`). Optional pass between the text encoder and denoise; the defaults are\naggressive and may need tuning for Krea-2.", + "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" + }, + "conditioning": { + "anyOf": [ + { + "$ref": "#/components/schemas/Krea2ConditioningField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Conditioning tensor", + "field_kind": "input", + "input": "connection", + "orig_required": true, + "title": "Conditioning" + }, + "strength": { + "default": 20.0, + "description": "Magnitude of the uniform noise added to the embeddings (noise in [-strength, +strength]).", + "field_kind": "input", + "input": "any", + "orig_default": 20.0, + "orig_required": false, + "title": "Strength", + "type": "number" + }, + "randomize_percent": { + "default": 50.0, + "description": "Percentage of embedding values that get perturbed (Bernoulli mask).", + "field_kind": "input", + "input": "any", + "maximum": 100.0, + "minimum": 1.0, + "orig_default": 50.0, + "orig_required": false, + "title": "Randomize Percent", + "type": "number" + }, + "variance_seed": { + "default": 0, + "description": "Seed for the variance noise (vary this to get variety).", + "field_kind": "input", + "input": "any", + "orig_default": 0, + "orig_required": false, + "title": "Variance Seed", + "type": "integer" + }, + "type": { + "const": "krea2_seed_variance", + "default": "krea2_seed_variance", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["conditioning", "krea2", "krea-2", "variance"], + "title": "Seed Variance - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + } + }, + "Krea2TextEncoderInvocation": { + "category": "conditioning", + "class": "invocation", + "classification": "prototype", + "description": "Encodes a text prompt for Krea-2 using the Qwen3-VL text encoder.\n\nThe encoder taps 12 decoder hidden-state layers and stacks them per token, producing a 4D\nconditioning tensor (B, seq, 12, hidden) that the Krea-2 transformer's text-fusion stage consumes.", + "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" + }, + "prompt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Text prompt describing the desired image.", + "field_kind": "input", + "input": "any", + "orig_required": true, + "title": "Prompt", + "ui_component": "textarea" + }, + "qwen3_vl_encoder": { + "anyOf": [ + { + "$ref": "#/components/schemas/Qwen3VLEncoderField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Qwen3-VL tokenizer and text encoder", + "field_kind": "input", + "input": "connection", + "orig_required": true, + "title": "Qwen3-VL Encoder" + }, + "type": { + "const": "krea2_text_encoder", + "default": "krea2_text_encoder", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["prompt", "conditioning", "krea2", "krea-2"], + "title": "Prompt - Krea-2", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/Krea2ConditioningOutput" + } + }, + "Krea2VariantType": { + "type": "string", + "enum": ["krea2_turbo", "krea2_base"], + "title": "Krea2VariantType", + "description": "Krea 2 model variants." + }, + "LaMaInfillInvocation": { + "category": "inpaint", + "class": "invocation", + "classification": "stable", + "description": "Infills transparent areas of an image using the LaMa model", "node_pack": "invokeai", "properties": { "board": { @@ -44447,19 +45687,323 @@ }, "base": { "type": "string", - "const": "flux2", + "const": "flux2", + "title": "Base", + "default": "flux2" + }, + "variant": { + "anyOf": [ + { + "$ref": "#/components/schemas/Flux2VariantType" + }, + { + "type": "null" + } + ] + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "format", + "base", + "variant" + ], + "title": "LoRA_Diffusers_Flux2_Config", + "description": "Model config for FLUX.2 (Klein) LoRA models in Diffusers format." + }, + "LoRA_Diffusers_SD1_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" + }, + "type": { + "type": "string", + "const": "lora", + "title": "Type", + "default": "lora" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/LoraModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" + }, + "format": { + "type": "string", + "const": "diffusers", + "title": "Format", + "default": "diffusers" + }, + "base": { + "type": "string", + "const": "sd-1", + "title": "Base", + "default": "sd-1" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "format", + "base" + ], + "title": "LoRA_Diffusers_SD1_Config" + }, + "LoRA_Diffusers_SD2_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" + }, + "type": { + "type": "string", + "const": "lora", + "title": "Type", + "default": "lora" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/LoraModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" + }, + "format": { + "type": "string", + "const": "diffusers", + "title": "Format", + "default": "diffusers" + }, + "base": { + "type": "string", + "const": "sd-2", "title": "Base", - "default": "flux2" - }, - "variant": { - "anyOf": [ - { - "$ref": "#/components/schemas/Flux2VariantType" - }, - { - "type": "null" - } - ] + "default": "sd-2" } }, "type": "object", @@ -44479,13 +46023,11 @@ "trigger_phrases", "default_settings", "format", - "base", - "variant" + "base" ], - "title": "LoRA_Diffusers_Flux2_Config", - "description": "Model config for FLUX.2 (Klein) LoRA models in Diffusers format." + "title": "LoRA_Diffusers_SD2_Config" }, - "LoRA_Diffusers_SD1_Config": { + "LoRA_Diffusers_SDXL_Config": { "properties": { "key": { "type": "string", @@ -44610,9 +46152,9 @@ }, "base": { "type": "string", - "const": "sd-1", + "const": "sdxl", "title": "Base", - "default": "sd-1" + "default": "sdxl" } }, "type": "object", @@ -44634,9 +46176,9 @@ "format", "base" ], - "title": "LoRA_Diffusers_SD1_Config" + "title": "LoRA_Diffusers_SDXL_Config" }, - "LoRA_Diffusers_SD2_Config": { + "LoRA_Diffusers_ZImage_Config": { "properties": { "key": { "type": "string", @@ -44761,160 +46303,19 @@ }, "base": { "type": "string", - "const": "sd-2", + "const": "z-image", "title": "Base", - "default": "sd-2" - } - }, - "type": "object", - "required": [ - "key", - "hash", - "path", - "file_size", - "name", - "description", - "source", - "source_type", - "source_api_response", - "source_url", - "cover_image", - "type", - "trigger_phrases", - "default_settings", - "format", - "base" - ], - "title": "LoRA_Diffusers_SD2_Config" - }, - "LoRA_Diffusers_SDXL_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" - }, - "type": { - "type": "string", - "const": "lora", - "title": "Type", - "default": "lora" - }, - "trigger_phrases": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array", - "uniqueItems": true - }, - { - "type": "null" - } - ], - "title": "Trigger Phrases", - "description": "Set of trigger phrases for this model" + "default": "z-image" }, - "default_settings": { + "variant": { "anyOf": [ { - "$ref": "#/components/schemas/LoraModelDefaultSettings" + "$ref": "#/components/schemas/ZImageVariantType" }, { "type": "null" } - ], - "description": "Default settings for this model" - }, - "format": { - "type": "string", - "const": "diffusers", - "title": "Format", - "default": "diffusers" - }, - "base": { - "type": "string", - "const": "sdxl", - "title": "Base", - "default": "sdxl" + ] } }, "type": "object", @@ -44934,11 +46335,13 @@ "trigger_phrases", "default_settings", "format", - "base" + "base", + "variant" ], - "title": "LoRA_Diffusers_SDXL_Config" + "title": "LoRA_Diffusers_ZImage_Config", + "description": "Model config for Z-Image LoRA models in Diffusers format." }, - "LoRA_Diffusers_ZImage_Config": { + "LoRA_LyCORIS_Anima_Config": { "properties": { "key": { "type": "string", @@ -45057,25 +46460,15 @@ }, "format": { "type": "string", - "const": "diffusers", + "const": "lycoris", "title": "Format", - "default": "diffusers" + "default": "lycoris" }, "base": { "type": "string", - "const": "z-image", + "const": "anima", "title": "Base", - "default": "z-image" - }, - "variant": { - "anyOf": [ - { - "$ref": "#/components/schemas/ZImageVariantType" - }, - { - "type": "null" - } - ] + "default": "anima" } }, "type": "object", @@ -45095,13 +46488,12 @@ "trigger_phrases", "default_settings", "format", - "base", - "variant" + "base" ], - "title": "LoRA_Diffusers_ZImage_Config", - "description": "Model config for Z-Image LoRA models in Diffusers format." + "title": "LoRA_LyCORIS_Anima_Config", + "description": "Model config for Anima LoRA models in LyCORIS format." }, - "LoRA_LyCORIS_Anima_Config": { + "LoRA_LyCORIS_FLUX_Config": { "properties": { "key": { "type": "string", @@ -45226,9 +46618,9 @@ }, "base": { "type": "string", - "const": "anima", + "const": "flux", "title": "Base", - "default": "anima" + "default": "flux" } }, "type": "object", @@ -45250,10 +46642,9 @@ "format", "base" ], - "title": "LoRA_LyCORIS_Anima_Config", - "description": "Model config for Anima LoRA models in LyCORIS format." + "title": "LoRA_LyCORIS_FLUX_Config" }, - "LoRA_LyCORIS_FLUX_Config": { + "LoRA_LyCORIS_Flux2_Config": { "properties": { "key": { "type": "string", @@ -45378,9 +46769,19 @@ }, "base": { "type": "string", - "const": "flux", + "const": "flux2", "title": "Base", - "default": "flux" + "default": "flux2" + }, + "variant": { + "anyOf": [ + { + "$ref": "#/components/schemas/Flux2VariantType" + }, + { + "type": "null" + } + ] } }, "type": "object", @@ -45400,11 +46801,13 @@ "trigger_phrases", "default_settings", "format", - "base" + "base", + "variant" ], - "title": "LoRA_LyCORIS_FLUX_Config" + "title": "LoRA_LyCORIS_Flux2_Config", + "description": "Model config for FLUX.2 (Klein) LoRA models in LyCORIS format." }, - "LoRA_LyCORIS_Flux2_Config": { + "LoRA_LyCORIS_Krea2_Config": { "properties": { "key": { "type": "string", @@ -45529,19 +46932,9 @@ }, "base": { "type": "string", - "const": "flux2", + "const": "krea-2", "title": "Base", - "default": "flux2" - }, - "variant": { - "anyOf": [ - { - "$ref": "#/components/schemas/Flux2VariantType" - }, - { - "type": "null" - } - ] + "default": "krea-2" } }, "type": "object", @@ -45561,11 +46954,10 @@ "trigger_phrases", "default_settings", "format", - "base", - "variant" + "base" ], - "title": "LoRA_LyCORIS_Flux2_Config", - "description": "Model config for FLUX.2 (Klein) LoRA models in LyCORIS format." + "title": "LoRA_LyCORIS_Krea2_Config", + "description": "Model config for Krea-2 LoRA models in LyCORIS (single-file diffusers PEFT) format." }, "LoRA_LyCORIS_QwenImage_Config": { "properties": { @@ -47380,20 +48772,523 @@ "title": "Config Path", "description": "Path to the config for this model, if any." }, - "base": { - "type": "string", - "const": "flux", - "title": "Base", - "default": "flux" - }, + "base": { + "type": "string", + "const": "flux", + "title": "Base", + "default": "flux" + }, + "format": { + "type": "string", + "const": "bnb_quantized_nf4b", + "title": "Format", + "default": "bnb_quantized_nf4b" + }, + "variant": { + "$ref": "#/components/schemas/FluxVariantType" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "config_path", + "base", + "format", + "variant" + ], + "title": "Main_BnBNF4_FLUX_Config", + "description": "Model config for main checkpoint models." + }, + "Main_Checkpoint_Anima_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" + }, + "type": { + "type": "string", + "const": "main", + "title": "Type", + "default": "main" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/MainModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" + }, + "config_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Config Path", + "description": "Path to the config for this model, if any." + }, + "base": { + "type": "string", + "const": "anima", + "title": "Base", + "default": "anima" + }, + "format": { + "type": "string", + "const": "checkpoint", + "title": "Format", + "default": "checkpoint" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "config_path", + "base", + "format" + ], + "title": "Main_Checkpoint_Anima_Config", + "description": "Model config for Anima single-file checkpoint models (safetensors).\n\nAnima is built on NVIDIA Cosmos Predict2 DiT with a custom LLM Adapter\nthat bridges Qwen3 0.6B text encoder outputs to the DiT." + }, + "Main_Checkpoint_FLUX_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" + }, + "type": { + "type": "string", + "const": "main", + "title": "Type", + "default": "main" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/MainModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" + }, + "config_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Config Path", + "description": "Path to the config for this model, if any." + }, + "format": { + "type": "string", + "const": "checkpoint", + "title": "Format", + "default": "checkpoint" + }, + "base": { + "type": "string", + "const": "flux", + "title": "Base", + "default": "flux" + }, + "variant": { + "$ref": "#/components/schemas/FluxVariantType" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "config_path", + "format", + "base", + "variant" + ], + "title": "Main_Checkpoint_FLUX_Config", + "description": "Model config for main checkpoint models." + }, + "Main_Checkpoint_Flux2_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" + }, + "type": { + "type": "string", + "const": "main", + "title": "Type", + "default": "main" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/MainModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" + }, + "config_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Config Path", + "description": "Path to the config for this model, if any." + }, "format": { "type": "string", - "const": "bnb_quantized_nf4b", + "const": "checkpoint", "title": "Format", - "default": "bnb_quantized_nf4b" + "default": "checkpoint" + }, + "base": { + "type": "string", + "const": "flux2", + "title": "Base", + "default": "flux2" }, "variant": { - "$ref": "#/components/schemas/FluxVariantType" + "$ref": "#/components/schemas/Flux2VariantType" } }, "type": "object", @@ -47413,14 +49308,14 @@ "trigger_phrases", "default_settings", "config_path", - "base", "format", + "base", "variant" ], - "title": "Main_BnBNF4_FLUX_Config", - "description": "Model config for main checkpoint models." + "title": "Main_Checkpoint_Flux2_Config", + "description": "Model config for FLUX.2 checkpoint models (e.g. Klein)." }, - "Main_Checkpoint_Anima_Config": { + "Main_Checkpoint_Krea2_Config": { "properties": { "key": { "type": "string", @@ -47551,15 +49446,18 @@ }, "base": { "type": "string", - "const": "anima", + "const": "krea-2", "title": "Base", - "default": "anima" + "default": "krea-2" }, "format": { "type": "string", "const": "checkpoint", "title": "Format", "default": "checkpoint" + }, + "variant": { + "$ref": "#/components/schemas/Krea2VariantType" } }, "type": "object", @@ -47580,12 +49478,13 @@ "default_settings", "config_path", "base", - "format" + "format", + "variant" ], - "title": "Main_Checkpoint_Anima_Config", - "description": "Model config for Anima single-file checkpoint models (safetensors).\n\nAnima is built on NVIDIA Cosmos Predict2 DiT with a custom LLM Adapter\nthat bridges Qwen3 0.6B text encoder outputs to the DiT." + "title": "Main_Checkpoint_Krea2_Config", + "description": "Model config for Krea-2 single-file checkpoint models (safetensors, etc)." }, - "Main_Checkpoint_FLUX_Config": { + "Main_Checkpoint_QwenImage_Config": { "properties": { "key": { "type": "string", @@ -47714,189 +49613,27 @@ "title": "Config Path", "description": "Path to the config for this model, if any." }, + "base": { + "type": "string", + "const": "qwen-image", + "title": "Base", + "default": "qwen-image" + }, "format": { "type": "string", "const": "checkpoint", "title": "Format", "default": "checkpoint" }, - "base": { - "type": "string", - "const": "flux", - "title": "Base", - "default": "flux" - }, "variant": { - "$ref": "#/components/schemas/FluxVariantType" - } - }, - "type": "object", - "required": [ - "key", - "hash", - "path", - "file_size", - "name", - "description", - "source", - "source_type", - "source_api_response", - "source_url", - "cover_image", - "type", - "trigger_phrases", - "default_settings", - "config_path", - "format", - "base", - "variant" - ], - "title": "Main_Checkpoint_FLUX_Config", - "description": "Model config for main checkpoint models." - }, - "Main_Checkpoint_Flux2_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" - }, - "type": { - "type": "string", - "const": "main", - "title": "Type", - "default": "main" - }, - "trigger_phrases": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array", - "uniqueItems": true - }, - { - "type": "null" - } - ], - "title": "Trigger Phrases", - "description": "Set of trigger phrases for this model" - }, - "default_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/MainModelDefaultSettings" - }, - { - "type": "null" - } - ], - "description": "Default settings for this model" - }, - "config_path": { - "anyOf": [ - { - "type": "string" + "$ref": "#/components/schemas/QwenImageVariantType" }, { "type": "null" } - ], - "title": "Config Path", - "description": "Path to the config for this model, if any." - }, - "format": { - "type": "string", - "const": "checkpoint", - "title": "Format", - "default": "checkpoint" - }, - "base": { - "type": "string", - "const": "flux2", - "title": "Base", - "default": "flux2" - }, - "variant": { - "$ref": "#/components/schemas/Flux2VariantType" + ] } }, "type": "object", @@ -47916,14 +49653,14 @@ "trigger_phrases", "default_settings", "config_path", - "format", "base", + "format", "variant" ], - "title": "Main_Checkpoint_Flux2_Config", - "description": "Model config for FLUX.2 checkpoint models (e.g. Klein)." + "title": "Main_Checkpoint_QwenImage_Config", + "description": "Model config for Qwen Image single-file checkpoint models (safetensors, etc).\n\nCovers both raw bf16/fp16 checkpoints and ComfyUI-style fp8_scaled checkpoints.\nThe loader dequantizes fp8 weights back to bf16 at load time; the\n`default_settings.fp8_storage` toggle can then optionally re-cast to fp8 for\nVRAM savings." }, - "Main_Checkpoint_QwenImage_Config": { + "Main_Checkpoint_SD1_Config": { "properties": { "key": { "type": "string", @@ -48052,27 +49789,23 @@ "title": "Config Path", "description": "Path to the config for this model, if any." }, - "base": { - "type": "string", - "const": "qwen-image", - "title": "Base", - "default": "qwen-image" - }, "format": { "type": "string", "const": "checkpoint", "title": "Format", "default": "checkpoint" }, + "prediction_type": { + "$ref": "#/components/schemas/SchedulerPredictionType" + }, "variant": { - "anyOf": [ - { - "$ref": "#/components/schemas/QwenImageVariantType" - }, - { - "type": "null" - } - ] + "$ref": "#/components/schemas/ModelVariantType" + }, + "base": { + "type": "string", + "const": "sd-1", + "title": "Base", + "default": "sd-1" } }, "type": "object", @@ -48092,14 +49825,14 @@ "trigger_phrases", "default_settings", "config_path", - "base", "format", - "variant" + "prediction_type", + "variant", + "base" ], - "title": "Main_Checkpoint_QwenImage_Config", - "description": "Model config for Qwen Image single-file checkpoint models (safetensors, etc).\n\nCovers both raw bf16/fp16 checkpoints and ComfyUI-style fp8_scaled checkpoints.\nThe loader dequantizes fp8 weights back to bf16 at load time; the\n`default_settings.fp8_storage` toggle can then optionally re-cast to fp8 for\nVRAM savings." + "title": "Main_Checkpoint_SD1_Config" }, - "Main_Checkpoint_SD1_Config": { + "Main_Checkpoint_SD2_Config": { "properties": { "key": { "type": "string", @@ -48242,9 +49975,9 @@ }, "base": { "type": "string", - "const": "sd-1", + "const": "sd-2", "title": "Base", - "default": "sd-1" + "default": "sd-2" } }, "type": "object", @@ -48269,9 +50002,9 @@ "variant", "base" ], - "title": "Main_Checkpoint_SD1_Config" + "title": "Main_Checkpoint_SD2_Config" }, - "Main_Checkpoint_SD2_Config": { + "Main_Checkpoint_SDXLRefiner_Config": { "properties": { "key": { "type": "string", @@ -48414,9 +50147,9 @@ }, "base": { "type": "string", - "const": "sd-2", + "const": "sdxl-refiner", "title": "Base", - "default": "sd-2" + "default": "sdxl-refiner" } }, "type": "object", @@ -48441,9 +50174,9 @@ "variant", "base" ], - "title": "Main_Checkpoint_SD2_Config" + "title": "Main_Checkpoint_SDXLRefiner_Config" }, - "Main_Checkpoint_SDXLRefiner_Config": { + "Main_Checkpoint_SDXL_Config": { "properties": { "key": { "type": "string", @@ -48586,9 +50319,9 @@ }, "base": { "type": "string", - "const": "sdxl-refiner", + "const": "sdxl", "title": "Base", - "default": "sdxl-refiner" + "default": "sdxl" } }, "type": "object", @@ -48613,9 +50346,9 @@ "variant", "base" ], - "title": "Main_Checkpoint_SDXLRefiner_Config" + "title": "Main_Checkpoint_SDXL_Config" }, - "Main_Checkpoint_SDXL_Config": { + "Main_Checkpoint_ZImage_Config": { "properties": { "key": { "type": "string", @@ -48744,23 +50477,20 @@ "title": "Config Path", "description": "Path to the config for this model, if any." }, + "base": { + "type": "string", + "const": "z-image", + "title": "Base", + "default": "z-image" + }, "format": { "type": "string", "const": "checkpoint", "title": "Format", "default": "checkpoint" }, - "prediction_type": { - "$ref": "#/components/schemas/SchedulerPredictionType" - }, "variant": { - "$ref": "#/components/schemas/ModelVariantType" - }, - "base": { - "type": "string", - "const": "sdxl", - "title": "Base", - "default": "sdxl" + "$ref": "#/components/schemas/ZImageVariantType" } }, "type": "object", @@ -48780,14 +50510,14 @@ "trigger_phrases", "default_settings", "config_path", + "base", "format", - "prediction_type", - "variant", - "base" + "variant" ], - "title": "Main_Checkpoint_SDXL_Config" + "title": "Main_Checkpoint_ZImage_Config", + "description": "Model config for Z-Image single-file checkpoint models (safetensors, etc)." }, - "Main_Checkpoint_ZImage_Config": { + "Main_Diffusers_CogView4_Config": { "properties": { "key": { "type": "string", @@ -48904,7 +50634,73 @@ ], "description": "Default settings for this model" }, - "config_path": { + "format": { + "type": "string", + "const": "diffusers", + "title": "Format", + "default": "diffusers" + }, + "repo_variant": { + "$ref": "#/components/schemas/ModelRepoVariant", + "default": "" + }, + "base": { + "type": "string", + "const": "cogview4", + "title": "Base", + "default": "cogview4" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "type", + "trigger_phrases", + "default_settings", + "format", + "repo_variant", + "base" + ], + "title": "Main_Diffusers_CogView4_Config" + }, + "Main_Diffusers_FLUX_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" @@ -48913,23 +50709,105 @@ "type": "null" } ], - "title": "Config Path", - "description": "Path to the config for this model, if any." + "title": "Description", + "description": "Model description" }, - "base": { + "source": { "type": "string", - "const": "z-image", - "title": "Base", - "default": "z-image" + "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" + }, + "type": { + "type": "string", + "const": "main", + "title": "Type", + "default": "main" + }, + "trigger_phrases": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": true + }, + { + "type": "null" + } + ], + "title": "Trigger Phrases", + "description": "Set of trigger phrases for this model" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/MainModelDefaultSettings" + }, + { + "type": "null" + } + ], + "description": "Default settings for this model" }, "format": { "type": "string", - "const": "checkpoint", + "const": "diffusers", "title": "Format", - "default": "checkpoint" + "default": "diffusers" + }, + "repo_variant": { + "$ref": "#/components/schemas/ModelRepoVariant", + "default": "" + }, + "base": { + "type": "string", + "const": "flux", + "title": "Base", + "default": "flux" }, "variant": { - "$ref": "#/components/schemas/ZImageVariantType" + "$ref": "#/components/schemas/FluxVariantType" } }, "type": "object", @@ -48948,15 +50826,15 @@ "type", "trigger_phrases", "default_settings", - "config_path", - "base", "format", + "repo_variant", + "base", "variant" ], - "title": "Main_Checkpoint_ZImage_Config", - "description": "Model config for Z-Image single-file checkpoint models (safetensors, etc)." + "title": "Main_Diffusers_FLUX_Config", + "description": "Model config for FLUX.1 models in diffusers format." }, - "Main_Diffusers_CogView4_Config": { + "Main_Diffusers_Flux2_Config": { "properties": { "key": { "type": "string", @@ -49085,9 +50963,12 @@ }, "base": { "type": "string", - "const": "cogview4", + "const": "flux2", "title": "Base", - "default": "cogview4" + "default": "flux2" + }, + "variant": { + "$ref": "#/components/schemas/Flux2VariantType" } }, "type": "object", @@ -49108,11 +50989,13 @@ "default_settings", "format", "repo_variant", - "base" + "base", + "variant" ], - "title": "Main_Diffusers_CogView4_Config" + "title": "Main_Diffusers_Flux2_Config", + "description": "Model config for FLUX.2 models in diffusers format (e.g. FLUX.2 Klein)." }, - "Main_Diffusers_FLUX_Config": { + "Main_Diffusers_Krea2_Config": { "properties": { "key": { "type": "string", @@ -49241,12 +51124,12 @@ }, "base": { "type": "string", - "const": "flux", + "const": "krea-2", "title": "Base", - "default": "flux" + "default": "krea-2" }, "variant": { - "$ref": "#/components/schemas/FluxVariantType" + "$ref": "#/components/schemas/Krea2VariantType" } }, "type": "object", @@ -49270,10 +51153,10 @@ "base", "variant" ], - "title": "Main_Diffusers_FLUX_Config", - "description": "Model config for FLUX.1 models in diffusers format." + "title": "Main_Diffusers_Krea2_Config", + "description": "Model config for Krea-2 diffusers models (Krea-2-Turbo)." }, - "Main_Diffusers_Flux2_Config": { + "Main_Diffusers_QwenImage_Config": { "properties": { "key": { "type": "string", @@ -49402,12 +51285,19 @@ }, "base": { "type": "string", - "const": "flux2", + "const": "qwen-image", "title": "Base", - "default": "flux2" + "default": "qwen-image" }, "variant": { - "$ref": "#/components/schemas/Flux2VariantType" + "anyOf": [ + { + "$ref": "#/components/schemas/QwenImageVariantType" + }, + { + "type": "null" + } + ] } }, "type": "object", @@ -49431,10 +51321,10 @@ "base", "variant" ], - "title": "Main_Diffusers_Flux2_Config", - "description": "Model config for FLUX.2 models in diffusers format (e.g. FLUX.2 Klein)." + "title": "Main_Diffusers_QwenImage_Config", + "description": "Model config for Qwen Image diffusers models (both txt2img and edit)." }, - "Main_Diffusers_QwenImage_Config": { + "Main_Diffusers_SD1_Config": { "properties": { "key": { "type": "string", @@ -49561,21 +51451,17 @@ "$ref": "#/components/schemas/ModelRepoVariant", "default": "" }, + "prediction_type": { + "$ref": "#/components/schemas/SchedulerPredictionType" + }, + "variant": { + "$ref": "#/components/schemas/ModelVariantType" + }, "base": { "type": "string", - "const": "qwen-image", + "const": "sd-1", "title": "Base", - "default": "qwen-image" - }, - "variant": { - "anyOf": [ - { - "$ref": "#/components/schemas/QwenImageVariantType" - }, - { - "type": "null" - } - ] + "default": "sd-1" } }, "type": "object", @@ -49596,13 +51482,13 @@ "default_settings", "format", "repo_variant", - "base", - "variant" + "prediction_type", + "variant", + "base" ], - "title": "Main_Diffusers_QwenImage_Config", - "description": "Model config for Qwen Image diffusers models (both txt2img and edit)." + "title": "Main_Diffusers_SD1_Config" }, - "Main_Diffusers_SD1_Config": { + "Main_Diffusers_SD2_Config": { "properties": { "key": { "type": "string", @@ -49737,9 +51623,9 @@ }, "base": { "type": "string", - "const": "sd-1", + "const": "sd-2", "title": "Base", - "default": "sd-1" + "default": "sd-2" } }, "type": "object", @@ -49764,9 +51650,9 @@ "variant", "base" ], - "title": "Main_Diffusers_SD1_Config" + "title": "Main_Diffusers_SD2_Config" }, - "Main_Diffusers_SD2_Config": { + "Main_Diffusers_SD3_Config": { "properties": { "key": { "type": "string", @@ -49893,17 +51779,29 @@ "$ref": "#/components/schemas/ModelRepoVariant", "default": "" }, - "prediction_type": { - "$ref": "#/components/schemas/SchedulerPredictionType" - }, - "variant": { - "$ref": "#/components/schemas/ModelVariantType" - }, "base": { "type": "string", - "const": "sd-2", + "const": "sd-3", "title": "Base", - "default": "sd-2" + "default": "sd-3" + }, + "submodels": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/SubmodelDefinition" + }, + "propertyNames": { + "$ref": "#/components/schemas/SubModelType" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Submodels", + "description": "Loadable submodels in this model" } }, "type": "object", @@ -49924,13 +51822,12 @@ "default_settings", "format", "repo_variant", - "prediction_type", - "variant", - "base" + "base", + "submodels" ], - "title": "Main_Diffusers_SD2_Config" + "title": "Main_Diffusers_SD3_Config" }, - "Main_Diffusers_SD3_Config": { + "Main_Diffusers_SDXLRefiner_Config": { "properties": { "key": { "type": "string", @@ -50057,29 +51954,17 @@ "$ref": "#/components/schemas/ModelRepoVariant", "default": "" }, + "prediction_type": { + "$ref": "#/components/schemas/SchedulerPredictionType" + }, + "variant": { + "$ref": "#/components/schemas/ModelVariantType" + }, "base": { "type": "string", - "const": "sd-3", + "const": "sdxl-refiner", "title": "Base", - "default": "sd-3" - }, - "submodels": { - "anyOf": [ - { - "additionalProperties": { - "$ref": "#/components/schemas/SubmodelDefinition" - }, - "propertyNames": { - "$ref": "#/components/schemas/SubModelType" - }, - "type": "object" - }, - { - "type": "null" - } - ], - "title": "Submodels", - "description": "Loadable submodels in this model" + "default": "sdxl-refiner" } }, "type": "object", @@ -50100,12 +51985,13 @@ "default_settings", "format", "repo_variant", - "base", - "submodels" + "prediction_type", + "variant", + "base" ], - "title": "Main_Diffusers_SD3_Config" + "title": "Main_Diffusers_SDXLRefiner_Config" }, - "Main_Diffusers_SDXLRefiner_Config": { + "Main_Diffusers_SDXL_Config": { "properties": { "key": { "type": "string", @@ -50240,9 +52126,9 @@ }, "base": { "type": "string", - "const": "sdxl-refiner", + "const": "sdxl", "title": "Base", - "default": "sdxl-refiner" + "default": "sdxl" } }, "type": "object", @@ -50267,9 +52153,9 @@ "variant", "base" ], - "title": "Main_Diffusers_SDXLRefiner_Config" + "title": "Main_Diffusers_SDXL_Config" }, - "Main_Diffusers_SDXL_Config": { + "Main_Diffusers_ZImage_Config": { "properties": { "key": { "type": "string", @@ -50396,17 +52282,14 @@ "$ref": "#/components/schemas/ModelRepoVariant", "default": "" }, - "prediction_type": { - "$ref": "#/components/schemas/SchedulerPredictionType" - }, - "variant": { - "$ref": "#/components/schemas/ModelVariantType" - }, "base": { "type": "string", - "const": "sdxl", + "const": "z-image", "title": "Base", - "default": "sdxl" + "default": "z-image" + }, + "variant": { + "$ref": "#/components/schemas/ZImageVariantType" } }, "type": "object", @@ -50427,13 +52310,13 @@ "default_settings", "format", "repo_variant", - "prediction_type", - "variant", - "base" + "base", + "variant" ], - "title": "Main_Diffusers_SDXL_Config" + "title": "Main_Diffusers_ZImage_Config", + "description": "Model config for Z-Image diffusers models (Z-Image-Turbo, Z-Image-Base)." }, - "Main_Diffusers_ZImage_Config": { + "Main_GGUF_FLUX_Config": { "properties": { "key": { "type": "string", @@ -50550,24 +52433,32 @@ ], "description": "Default settings for this model" }, - "format": { - "type": "string", - "const": "diffusers", - "title": "Format", - "default": "diffusers" - }, - "repo_variant": { - "$ref": "#/components/schemas/ModelRepoVariant", - "default": "" + "config_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Config Path", + "description": "Path to the config for this model, if any." }, "base": { "type": "string", - "const": "z-image", + "const": "flux", "title": "Base", - "default": "z-image" + "default": "flux" + }, + "format": { + "type": "string", + "const": "gguf_quantized", + "title": "Format", + "default": "gguf_quantized" }, "variant": { - "$ref": "#/components/schemas/ZImageVariantType" + "$ref": "#/components/schemas/FluxVariantType" } }, "type": "object", @@ -50586,15 +52477,15 @@ "type", "trigger_phrases", "default_settings", - "format", - "repo_variant", + "config_path", "base", + "format", "variant" ], - "title": "Main_Diffusers_ZImage_Config", - "description": "Model config for Z-Image diffusers models (Z-Image-Turbo, Z-Image-Base)." + "title": "Main_GGUF_FLUX_Config", + "description": "Model config for main checkpoint models." }, - "Main_GGUF_FLUX_Config": { + "Main_GGUF_Flux2_Config": { "properties": { "key": { "type": "string", @@ -50725,9 +52616,9 @@ }, "base": { "type": "string", - "const": "flux", + "const": "flux2", "title": "Base", - "default": "flux" + "default": "flux2" }, "format": { "type": "string", @@ -50736,7 +52627,7 @@ "default": "gguf_quantized" }, "variant": { - "$ref": "#/components/schemas/FluxVariantType" + "$ref": "#/components/schemas/Flux2VariantType" } }, "type": "object", @@ -50760,10 +52651,10 @@ "format", "variant" ], - "title": "Main_GGUF_FLUX_Config", - "description": "Model config for main checkpoint models." + "title": "Main_GGUF_Flux2_Config", + "description": "Model config for GGUF-quantized FLUX.2 checkpoint models (e.g. Klein)." }, - "Main_GGUF_Flux2_Config": { + "Main_GGUF_Krea2_Config": { "properties": { "key": { "type": "string", @@ -50894,9 +52785,9 @@ }, "base": { "type": "string", - "const": "flux2", + "const": "krea-2", "title": "Base", - "default": "flux2" + "default": "krea-2" }, "format": { "type": "string", @@ -50905,7 +52796,7 @@ "default": "gguf_quantized" }, "variant": { - "$ref": "#/components/schemas/Flux2VariantType" + "$ref": "#/components/schemas/Krea2VariantType" } }, "type": "object", @@ -50929,8 +52820,8 @@ "format", "variant" ], - "title": "Main_GGUF_Flux2_Config", - "description": "Model config for GGUF-quantized FLUX.2 checkpoint models (e.g. Klein)." + "title": "Main_GGUF_Krea2_Config", + "description": "Model config for GGUF-quantized Krea-2 transformer models (single-file)." }, "Main_GGUF_QwenImage_Config": { "properties": { @@ -54788,6 +56679,7 @@ "t5_encoder", "qwen3_encoder", "qwen_vl_encoder", + "qwen3_vl_encoder", "bnb_quantized_int8b", "bnb_quantized_nf4b", "gguf_quantized", @@ -55061,6 +56953,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -55085,6 +56980,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -55103,6 +57001,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -55178,6 +57079,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -55217,6 +57121,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -55633,6 +57543,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -55657,6 +57570,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -55675,6 +57591,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -55750,6 +57669,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -55789,6 +57711,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -56090,6 +58018,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -56114,6 +58045,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -56132,6 +58066,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -56207,6 +58144,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -56246,6 +58186,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -56397,6 +58343,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -56421,6 +58370,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -56439,6 +58391,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -56514,6 +58469,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -56553,6 +58511,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -56962,6 +58926,9 @@ { "$ref": "#/components/schemas/Qwen3VariantType" }, + { + "$ref": "#/components/schemas/Krea2VariantType" + }, { "type": "null" } @@ -57101,6 +59068,7 @@ "t5_encoder", "qwen3_encoder", "qwen_vl_encoder", + "qwen3_vl_encoder", "spandrel_image_to_image", "siglip", "flux_redux", @@ -57153,6 +59121,9 @@ { "$ref": "#/components/schemas/Main_Diffusers_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Diffusers_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_SD1_Config" }, @@ -57177,6 +59148,9 @@ { "$ref": "#/components/schemas/Main_Checkpoint_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_Checkpoint_Krea2_Config" + }, { "$ref": "#/components/schemas/Main_Checkpoint_Anima_Config" }, @@ -57195,6 +59169,9 @@ { "$ref": "#/components/schemas/Main_GGUF_ZImage_Config" }, + { + "$ref": "#/components/schemas/Main_GGUF_Krea2_Config" + }, { "$ref": "#/components/schemas/VAE_Checkpoint_SD1_Config" }, @@ -57270,6 +59247,9 @@ { "$ref": "#/components/schemas/LoRA_LyCORIS_ZImage_Config" }, + { + "$ref": "#/components/schemas/LoRA_LyCORIS_Krea2_Config" + }, { "$ref": "#/components/schemas/LoRA_LyCORIS_QwenImage_Config" }, @@ -57309,6 +59289,12 @@ { "$ref": "#/components/schemas/T5Encoder_BnBLLMint8_Config" }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Checkpoint_Config" + }, + { + "$ref": "#/components/schemas/Qwen3VLEncoder_Qwen3VLEncoder_Config" + }, { "$ref": "#/components/schemas/Qwen3Encoder_Qwen3Encoder_Config" }, @@ -59962,6 +61948,315 @@ "title": "Qwen3Encoder_Qwen3Encoder_Config", "description": "Configuration for Qwen3 Encoder models in a diffusers-like format.\n\nThe model weights are expected to be in a folder called text_encoder inside the model directory,\ncompatible with Qwen2VLForConditionalGeneration or similar architectures used by Z-Image." }, + "Qwen3VLEncoderField": { + "description": "Field for the Qwen3-VL text encoder used by Krea-2 models.", + "properties": { + "tokenizer": { + "$ref": "#/components/schemas/ModelIdentifierField", + "description": "Info to load tokenizer submodel" + }, + "text_encoder": { + "$ref": "#/components/schemas/ModelIdentifierField", + "description": "Info to load text_encoder submodel" + }, + "loras": { + "description": "LoRAs to apply on model loading", + "items": { + "$ref": "#/components/schemas/LoRAField" + }, + "title": "Loras", + "type": "array" + } + }, + "required": ["tokenizer", "text_encoder"], + "title": "Qwen3VLEncoderField", + "type": "object" + }, + "Qwen3VLEncoder_Checkpoint_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." + }, + "base": { + "type": "string", + "const": "any", + "title": "Base", + "default": "any" + }, + "type": { + "type": "string", + "const": "qwen3_vl_encoder", + "title": "Type", + "default": "qwen3_vl_encoder" + }, + "format": { + "type": "string", + "const": "checkpoint", + "title": "Format", + "default": "checkpoint" + }, + "cpu_only": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Cpu Only", + "description": "Whether this model should run on CPU only" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "config_path", + "base", + "type", + "format", + "cpu_only" + ], + "title": "Qwen3VLEncoder_Checkpoint_Config", + "description": "Configuration for a single-file Qwen3-VL text encoder checkpoint (e.g. ComfyUI ``qwen3vl_4b_*``).\n\nDistinguished from the text-only ``Qwen3Encoder`` checkpoint (Z-Image) by the presence of the\nQwen3-VL visual tower. The tokenizer is not bundled in single-file checkpoints and is pulled from\nHuggingFace (``Qwen/Qwen3-VL-4B-Instruct``) by the loader." + }, + "Qwen3VLEncoder_Qwen3VLEncoder_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" + }, + "base": { + "type": "string", + "const": "any", + "title": "Base", + "default": "any" + }, + "type": { + "type": "string", + "const": "qwen3_vl_encoder", + "title": "Type", + "default": "qwen3_vl_encoder" + }, + "format": { + "type": "string", + "const": "qwen3_vl_encoder", + "title": "Format", + "default": "qwen3_vl_encoder" + }, + "cpu_only": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Cpu Only", + "description": "Whether this model should run on CPU only" + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "base", + "type", + "format", + "cpu_only" + ], + "title": "Qwen3VLEncoder_Qwen3VLEncoder_Config", + "description": "Configuration for standalone Qwen3-VL text encoder models (diffusers-like directory format).\n\nUsed by Krea-2, whose text conditioning comes from a Qwen3-VL model (``Qwen3VLModel``). The model\nweights are expected either in a ``text_encoder`` subfolder of the model directory or directly at the\nroot (standalone download). This is distinct from the text-only ``Qwen3Encoder`` (Z-Image / FLUX.2\nKlein) and the Qwen2.5-VL ``QwenVLEncoder`` (Qwen Image)." + }, "Qwen3VariantType": { "type": "string", "enum": ["qwen3_4b", "qwen3_8b", "qwen3_06b"], @@ -66439,6 +68734,9 @@ { "$ref": "#/components/schemas/Qwen3VariantType" }, + { + "$ref": "#/components/schemas/Krea2VariantType" + }, { "type": "null" } @@ -66599,6 +68897,9 @@ { "$ref": "#/components/schemas/Qwen3VariantType" }, + { + "$ref": "#/components/schemas/Krea2VariantType" + }, { "type": "null" } @@ -67531,6 +69832,9 @@ { "$ref": "#/components/schemas/Qwen3VariantType" }, + { + "$ref": "#/components/schemas/Krea2VariantType" + }, { "type": "null" } diff --git a/invokeai/frontend/web/src/features/modelManagerV2/models.ts b/invokeai/frontend/web/src/features/modelManagerV2/models.ts index e5bdf0412d4..c2be1d0857c 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/models.ts +++ b/invokeai/frontend/web/src/features/modelManagerV2/models.ts @@ -259,6 +259,7 @@ export const MODEL_VARIANT_TO_LONG_NAME: Record = { turbo: 'Z-Image Turbo', zbase: 'Z-Image Base', krea2_turbo: 'Krea-2 Turbo', + krea2_base: 'Krea-2 Raw', large: 'CLIP L', gigantic: 'CLIP G', generate: 'Qwen Image', @@ -302,4 +303,5 @@ export const SUPPORTS_NEGATIVE_PROMPT_BASE_MODELS: BaseModelType[] = [ 'sd-3', 'z-image', 'anima', + 'krea-2', ]; diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index 3ee19c0600d..d69d3fc6071 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -165,7 +165,7 @@ export const zModelVariantType = z.enum(['normal', 'inpaint', 'depth']); export const zFluxVariantType = z.enum(['dev', 'dev_fill', 'schnell']); export const zFlux2VariantType = z.enum(['klein_4b', 'klein_4b_base', 'klein_9b', 'klein_9b_base']); export const zZImageVariantType = z.enum(['turbo', 'zbase']); -export const zKrea2VariantType = z.enum(['krea2_turbo']); +export const zKrea2VariantType = z.enum(['krea2_turbo', 'krea2_base']); const zQwenImageVariantType = z.enum(['generate', 'edit']); export const zQwen3VariantType = z.enum(['qwen3_4b', 'qwen3_8b', 'qwen3_06b']); export const zAnyModelVariant = z.union([ diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index f445988a910..95c64d204d5 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -3615,7 +3615,7 @@ export type components = { */ type: "anima_text_encoder"; }; - 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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; /** * AppVersion * @description App Version Response @@ -4418,6 +4418,7 @@ export type components = { /** * Resize To * @description Dimensions to resize the image to, must be stringified tuple of 2 integers. Max total pixel count: 16777216 + * @example "[1024,1024]" */ resize_to?: string | null; /** @@ -17883,7 +17884,7 @@ export type components = { * @description Krea 2 model variants. * @enum {string} */ - Krea2VariantType: "krea2_turbo"; + Krea2VariantType: "krea2_turbo" | "krea2_base"; /** * LaMa Infill * @description Infills transparent areas of an image using the LaMa model @@ -22360,6 +22361,95 @@ export type components = { format: "gguf_quantized"; variant: components["schemas"]["Flux2VariantType"]; }; + /** + * Main_GGUF_Krea2_Config + * @description Model config for GGUF-quantized Krea-2 transformer models (single-file). + */ + Main_GGUF_Krea2_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; + /** + * Type + * @default main + * @constant + */ + type: "main"; + /** + * Trigger Phrases + * @description Set of trigger phrases for this model + */ + trigger_phrases: string[] | null; + /** @description Default settings for this model */ + default_settings: components["schemas"]["MainModelDefaultSettings"] | null; + /** + * Config Path + * @description Path to the config for this model, if any. + */ + config_path: string | null; + /** + * Base + * @default krea-2 + * @constant + */ + base: "krea-2"; + /** + * Format + * @default gguf_quantized + * @constant + */ + format: "gguf_quantized"; + variant: components["schemas"]["Krea2VariantType"]; + }; /** * Main_GGUF_QwenImage_Config * @description Model config for GGUF-quantized Qwen Image transformer models. @@ -24366,7 +24456,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; /** * ModelInstallDownloadProgressEvent @@ -24532,7 +24622,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -24618,7 +24708,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -24639,7 +24729,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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 @@ -24790,6 +24880,18 @@ export type components = { /** * Model Keys * @description List of model keys to fetch related models for + * @example [ + * "aa3b247f-90c9-4416-bfcd-aeaa57a5339e", + * "ac32b914-10ab-496e-a24a-3068724b9c35" + * ] + * @example [ + * "b1c2d3e4-f5a6-7890-abcd-ef1234567890", + * "12345678-90ab-cdef-1234-567890abcdef", + * "fedcba98-7654-3210-fedc-ba9876543210" + * ] + * @example [ + * "3bb7c0eb-b6c8-469c-ad8c-4d69c06075e4" + * ] */ model_keys: string[]; }; @@ -24798,11 +24900,23 @@ export type components = { /** * Model Key 1 * @description The key of the first model in the relationship + * @example aa3b247f-90c9-4416-bfcd-aeaa57a5339e + * @example ac32b914-10ab-496e-a24a-3068724b9c35 + * @example d944abfd-c7c3-42e2-a4ff-da640b29b8b4 + * @example b1c2d3e4-f5a6-7890-abcd-ef1234567890 + * @example 12345678-90ab-cdef-1234-567890abcdef + * @example fedcba98-7654-3210-fedc-ba9876543210 */ model_key_1: string; /** * Model Key 2 * @description The key of the second model in the relationship + * @example 3bb7c0eb-b6c8-469c-ad8c-4d69c06075e4 + * @example f0c3da4e-d9ff-42b5-a45c-23be75c887c9 + * @example 38170dd8-f1e5-431e-866c-2c81f1277fcc + * @example c57fea2d-7646-424c-b9ad-c0ba60fc68be + * @example 10f7807b-ab54-46a9-ab03-600e88c630a1 + * @example f6c1d267-cf87-4ee0-bee0-37e791eacab7 */ model_key_2: string; }; @@ -24836,7 +24950,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"])[]; }; /** * Multiply Integers @@ -26273,6 +26387,96 @@ export type components = { */ loras?: components["schemas"]["LoRAField"][]; }; + /** + * Qwen3VLEncoder_Checkpoint_Config + * @description Configuration for a single-file Qwen3-VL text encoder checkpoint (e.g. ComfyUI ``qwen3vl_4b_*``). + * + * Distinguished from the text-only ``Qwen3Encoder`` checkpoint (Z-Image) by the presence of the + * Qwen3-VL visual tower. The tokenizer is not bundled in single-file checkpoints and is pulled from + * HuggingFace (``Qwen/Qwen3-VL-4B-Instruct``) by the loader. + */ + Qwen3VLEncoder_Checkpoint_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; + /** + * Base + * @default any + * @constant + */ + base: "any"; + /** + * Type + * @default qwen3_vl_encoder + * @constant + */ + type: "qwen3_vl_encoder"; + /** + * Format + * @default checkpoint + * @constant + */ + format: "checkpoint"; + /** + * Cpu Only + * @description Whether this model should run on CPU only + */ + cpu_only: boolean | null; + }; /** * Qwen3VLEncoder_Qwen3VLEncoder_Config * @description Configuration for standalone Qwen3-VL text encoder models (diffusers-like directory format). @@ -34577,7 +34781,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -34609,7 +34813,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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -34641,7 +34845,8 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example { + /** + * @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -34658,8 +34863,9 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -34746,7 +34952,8 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example { + /** + * @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -34763,8 +34970,9 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -34817,7 +35025,8 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example { + /** + * @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -34834,8 +35043,9 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -35550,7 +35760,8 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example { + /** + * @example { * "path": "string", * "name": "string", * "base": "sd-1", @@ -35567,8 +35778,9 @@ export interface operations { * "prediction_type": "epsilon", * "repo_variant": "fp16", * "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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_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_ZImage_Config"] | components["schemas"]["Main_Diffusers_Krea2_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_ZImage_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_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_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_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_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_Flux2_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_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_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"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_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"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -37226,11 +37438,13 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example [ + /** + * @example [ * "15e9eb28-8cfe-47c9-b610-37907a79fc3c", * "71272e82-0e5f-46d5-bca9-9a61f4bd8a82", * "a5d7cd49-1b98-4534-a475-aeee4ccf5fa2" - * ] */ + * ] + */ "application/json": string[]; }; }; @@ -37369,7 +37583,8 @@ export interface operations { [name: string]: unknown; }; content: { - /** @example [ + /** + * @example [ * "ca562b14-995e-4a42-90c1-9528f1a5921d", * "cc0c2b8a-c62e-41d6-878e-cc74dde5ca8f", * "18ca7649-6a9e-47d5-bc17-41ab1e8cec81", @@ -37377,7 +37592,8 @@ export interface operations { * "c382eaa3-0e28-4ab0-9446-408667699aeb", * "71272e82-0e5f-46d5-bca9-9a61f4bd8a82", * "a5d7cd49-1b98-4534-a475-aeee4ccf5fa2" - * ] */ + * ] + */ "application/json": string[]; }; }; From 38a0a523406c6ccb175aa38c8a50fe4a36ec2c6f Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Thu, 2 Jul 2026 09:23:21 +0200 Subject: [PATCH 04/17] fix(graph): make isMainModelWithoutUnet a type guard incl. krea2_model_loader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit krea2_model_loader was added to MainModelLoaderNodes but not to isMainModelWithoutUnet, and the guard wasn't a type predicate — so it never narrowed modelLoader. OutputFields of the loader union collapses to the common 'vae' field, making g.addEdge(modelLoader, 'unet', ...) in addInpaint/addOutpaint fail to type-check ('unet' not assignable to 'vae'). Redefine the guard as a type predicate keyed on the inverse (only main_model_loader/sdxl_model_loader expose a unet), so every transformer-based loader is treated as unet-less automatically and the negated branch narrows to the unet-bearing loaders. --- .../nodes/util/graph/graphBuilderUtils.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts index 354e5bac203..74413ef5a88 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts @@ -209,16 +209,17 @@ export const getInfill = ( export const CANVAS_OUTPUT_PREFIX = 'canvas_output'; -export const isMainModelWithoutUnet = (modelLoader: Invocation) => { - return ( - modelLoader.type === 'flux_model_loader' || - modelLoader.type === 'flux2_klein_model_loader' || - modelLoader.type === 'sd3_model_loader' || - modelLoader.type === 'cogview4_model_loader' || - modelLoader.type === 'qwen_image_model_loader' || - modelLoader.type === 'z_image_model_loader' || - modelLoader.type === 'anima_model_loader' - ); +// Only the classic SD/SDXL loaders expose a `unet` output; every other main-model loader (FLUX, +// FLUX.2, SD3, CogView4, Qwen-Image, Z-Image, Krea-2, Anima) is transformer-based and has no `unet`. +// Defining the predicate by this small allow-list means any newly added transformer loader is treated +// as unet-less automatically, and the negated branch narrows `modelLoader` to the unet-bearing loaders +// so `addEdge(modelLoader, 'unet', ...)` type-checks. +type MainModelLoaderWithUnetNodes = 'main_model_loader' | 'sdxl_model_loader'; + +export const isMainModelWithoutUnet = ( + modelLoader: Invocation +): modelLoader is Invocation> => { + return modelLoader.type !== 'main_model_loader' && modelLoader.type !== 'sdxl_model_loader'; }; export const isCanvasOutputNodeId = (nodeId: string) => nodeId.split(':')[0] === CANVAS_OUTPUT_PREFIX; From 9e0318c0e2cdc84d44102165485dab8b2dca1aed Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Thu, 2 Jul 2026 09:30:03 +0200 Subject: [PATCH 05/17] test(krea2): add Krea2VariantType type-test to satisfy knip zKrea2VariantType was only used within common.ts (in zAnyModelVariant) and never referenced externally, so knip flagged it as an unused export. Every sibling variant enum avoids this by being asserted in common.test-d.ts; add the missing Krea2VariantType assertion, which both uses the export and verifies the manual zod enum matches the generated S['Krea2VariantType']. --- invokeai/frontend/web/src/features/nodes/types/common.test-d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/invokeai/frontend/web/src/features/nodes/types/common.test-d.ts b/invokeai/frontend/web/src/features/nodes/types/common.test-d.ts index 04e0fea2cc9..373f95f6f59 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.test-d.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.test-d.ts @@ -14,6 +14,7 @@ import type { zClipVariantType, zFlux2VariantType, zFluxVariantType, + zKrea2VariantType, zModelFormat, zModelVariantType, zQwen3VariantType, @@ -52,6 +53,7 @@ describe('Common types', () => { test('FluxVariantType', () => assert, S['FluxVariantType']>>()); test('Flux2VariantType', () => assert, S['Flux2VariantType']>>()); test('ZImageVariantType', () => assert, S['ZImageVariantType']>>()); + test('Krea2VariantType', () => assert, S['Krea2VariantType']>>()); test('Qwen3VariantType', () => assert, S['Qwen3VariantType']>>()); test('ModelFormat', () => assert, S['ModelFormat']>>()); From 08987304c63329dbc888fcd92180bec86c26f250 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Mon, 6 Jul 2026 00:48:48 +0200 Subject: [PATCH 06/17] build: pin diffusers to 0.39.0 (first stable release with Krea-2) diffusers 0.39.0 is the first stable release containing Krea2Pipeline / Krea2Transformer2DModel (plus the Qwen-Image VAE and Qwen3-VL text encoder Krea-2 relies on). Replace the temporary git-main dependency with the pinned release and update the lockfile's diffusers entry (version, sdist, wheel, specifier) to the official PyPI 0.39.0 artifacts. --- pyproject.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 301951e6bbf..47e8b4e8d8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,10 +36,7 @@ dependencies = [ "accelerate", "bitsandbytes; sys_platform!='darwin'", "compel>=2.4.0,<3", - # WIP (Krea-2 support): Krea2Pipeline/Krea2Transformer2DModel only exist in diffusers main (>=0.39 dev). - # This unpins diffusers from 0.37.0 to a git build for testing. Re-pin to the stable release that - # contains Krea-2 before merging, then un-draft the PR. - "diffusers[torch] @ git+https://github.com/huggingface/diffusers.git", + "diffusers[torch]==0.39.0", "gguf", "mediapipe==0.10.14", # needed for "mediapipeface" controlnet model "numpy<2.0.0", From 96c96c83f659d3c2a987d17d473dd6322c517223 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Mon, 6 Jul 2026 01:49:59 +0200 Subject: [PATCH 07/17] feat(krea2): metadata recall, starter models, and config-probe tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close the remaining gaps against docs/new-model-integration for Krea-2. Metadata recall (§7): buildKrea2Graph now records the standalone VAE, Qwen3-VL encoder, and both conditioning enhancers (seed-variance + rebalance) to image metadata, and parsing.tsx adds the matching recall handlers (base-guarded to 'krea-2'), so a Krea-2 image's VAE/encoder/enhancer settings restore on recall — important for reproducing single-file/GGUF generations. Starter models: add Krea-2 Raw (Base variant, full pipeline), Krea-2 Turbo GGUF Q4_K_M / Q8_0 (vantagewithai/Krea-2-Turbo-GGUF) with Qwen-Image VAE + Qwen3-VL encoder dependencies, and a standalone Qwen3-VL 4B encoder (Qwen/Qwen3-VL-4B- Instruct). The VAE dependency reuses the existing diffusers qwen_image_vae starter; krea2_turbo gains its explicit Turbo variant. Tests: add config-probe unit tests for Krea-2 variant detection (name heuristic, _has_krea2_keys, GGUF/checkpoint/diffusers variant, default settings) and for the single-file Qwen3-VL encoder probe (visual-tower vs. text-only Qwen3). 31 tests. --- .../backend/model_manager/starter_models.py | 56 +++++ invokeai/frontend/web/public/locales/en.json | 4 + .../web/src/features/metadata/parsing.tsx | 174 +++++++++++++ .../util/graph/generation/buildKrea2Graph.ts | 10 + .../configs/test_krea2_main_config.py | 235 ++++++++++++++++++ .../configs/test_qwen3_vl_encoder_config.py | 96 +++++++ 6 files changed, 575 insertions(+) create mode 100644 tests/backend/model_manager/configs/test_krea2_main_config.py create mode 100644 tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py diff --git a/invokeai/backend/model_manager/starter_models.py b/invokeai/backend/model_manager/starter_models.py index 523eb3758bb..422e638e385 100644 --- a/invokeai/backend/model_manager/starter_models.py +++ b/invokeai/backend/model_manager/starter_models.py @@ -12,6 +12,7 @@ from invokeai.backend.model_manager.taxonomy import ( AnyVariant, BaseModelType, + Krea2VariantType, ModelFormat, ModelType, QwenImageVariantType, @@ -1086,6 +1087,19 @@ class StarterModelBundle(BaseModel): # endregion # region Krea-2 +# Standalone Qwen3-VL text encoder used by Krea-2 (distinct from the Qwen2.5-VL encoder above). Pair +# with single-file / GGUF Krea-2 transformers, which ship only the transformer. The Qwen-Image VAE +# dependency reuses the `qwen_image_vae` starter defined in the Qwen Image region. +qwen3_vl_encoder_4b = StarterModel( + name="Qwen3-VL 4B Encoder (Diffusers)", + base=BaseModelType.Any, + source="Qwen/Qwen3-VL-4B-Instruct", + description="Qwen3-VL 4B text encoder (Qwen3VLModel) used by Krea-2, in HuggingFace folder layout " + "(includes tokenizer). Use with single-file / GGUF Krea-2 transformers. (~8GB)", + type=ModelType.Qwen3VLEncoder, + format=ModelFormat.Qwen3VLEncoder, +) + krea2_turbo = StarterModel( name="Krea-2 Turbo", base=BaseModelType.Krea2, @@ -1093,6 +1107,44 @@ class StarterModelBundle(BaseModel): description="Krea-2 Turbo - distilled 12B parameter text-to-image model (8 steps, CFG disabled). " "Full diffusers pipeline including the Qwen-Image VAE and Qwen3-VL text encoder. ~26GB", type=ModelType.Main, + variant=Krea2VariantType.Turbo, +) + +krea2_raw = StarterModel( + name="Krea-2 Raw", + base=BaseModelType.Krea2, + source="krea/Krea-2-Raw", + description="Krea-2 Raw - undistilled 12B base model (28 steps, CFG enabled). Full diffusers pipeline " + "including the Qwen-Image VAE and Qwen3-VL text encoder. Primarily a base for finetuning / LoRA " + "training; Turbo is recommended for standard inference. ~26GB", + type=ModelType.Main, + variant=Krea2VariantType.Base, +) + +krea2_turbo_gguf_q4_k_m = StarterModel( + name="Krea-2 Turbo (Q4_K_M GGUF)", + base=BaseModelType.Krea2, + source="https://huggingface.co/vantagewithai/Krea-2-Turbo-GGUF/resolve/main/krea2_turbo-Q4_K_M.gguf", + description="Krea-2 Turbo transformer quantized to GGUF Q4_K_M for lower VRAM (~7GB transformer). " + "GGUF ships only the transformer, so the Qwen-Image VAE and Qwen3-VL encoder are installed as " + "dependencies.", + type=ModelType.Main, + format=ModelFormat.GGUFQuantized, + variant=Krea2VariantType.Turbo, + dependencies=[qwen_image_vae, qwen3_vl_encoder_4b], +) + +krea2_turbo_gguf_q8_0 = StarterModel( + name="Krea-2 Turbo (Q8_0 GGUF)", + base=BaseModelType.Krea2, + source="https://huggingface.co/vantagewithai/Krea-2-Turbo-GGUF/resolve/main/krea2_turbo-Q8_0.gguf", + description="Krea-2 Turbo transformer quantized to GGUF Q8_0 (near-full quality, ~13GB transformer). " + "GGUF ships only the transformer, so the Qwen-Image VAE and Qwen3-VL encoder are installed as " + "dependencies.", + type=ModelType.Main, + format=ModelFormat.GGUFQuantized, + variant=Krea2VariantType.Turbo, + dependencies=[qwen_image_vae, qwen3_vl_encoder_4b], ) # endregion @@ -1702,6 +1754,10 @@ def _gemini_3_resolution_presets( z_image_controlnet_union, z_image_controlnet_tile, krea2_turbo, + krea2_raw, + krea2_turbo_gguf_q4_k_m, + krea2_turbo_gguf_q8_0, + qwen3_vl_encoder_4b, gemini_flash_image, gemini_pro_image_preview, gemini_3_1_flash_image_preview, diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 44b060d1853..76979e92e99 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1035,6 +1035,10 @@ "imageDetails": "Image Details", "imageDimensions": "Image Dimensions", "imageSize": "Image Size", + "krea2Qwen3VlEncoder": "Qwen3-VL Encoder", + "krea2RebalanceEnabled": "Conditioning Rebalance Enabled", + "krea2RebalanceMultiplier": "Rebalance Multiplier", + "krea2RebalanceWeights": "Rebalance Per-Layer Weights", "metadata": "Metadata", "model": "Model", "negativePrompt": "Negative Prompt", diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index bc2623045e1..314a384a422 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -16,6 +16,8 @@ import { imageSizeChanged, kleinQwen3EncoderModelSelected, kleinVaeModelSelected, + krea2Qwen3VlEncoderModelSelected, + krea2VaeModelSelected, negativePromptChanged, openaiBackgroundChanged, openaiInputFidelityChanged, @@ -40,6 +42,12 @@ import { setFluxScheduler, setGuidance, setImg2imgStrength, + setKrea2RebalanceEnabled, + setKrea2RebalanceMultiplier, + setKrea2RebalanceWeights, + setKrea2SeedVarianceEnabled, + setKrea2SeedVarianceRandomizePercent, + setKrea2SeedVarianceStrength, setRefinerCFGScale, setRefinerNegativeAestheticScore, setRefinerPositiveAestheticScore, @@ -1151,6 +1159,164 @@ const ZImageQwen3SourceModel: SingleMetadataHandler = { }; //#endregion ZImageQwen3SourceModel +//#region Krea2VAEModel +const Krea2VAEModel: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2VAEModel', + parse: async (metadata, store) => { + const raw = getProperty(metadata, 'vae'); + const parsed = await parseModelIdentifier(raw, store, 'vae'); + assert(parsed.type === 'vae'); + // Only recall if the current main model is Krea-2 (its VAE dropdown differs from other bases). + const base = selectBase(store.getState()); + assert(base === 'krea-2', 'Krea2VAEModel handler only works with Krea-2 models'); + return Promise.resolve(parsed); + }, + recall: (value, store) => { + store.dispatch(krea2VaeModelSelected(value)); + }, + i18nKey: 'metadata.vae', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => ( + + ), +}; +//#endregion Krea2VAEModel + +//#region Krea2Qwen3VlEncoderModel +const Krea2Qwen3VlEncoderModel: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2Qwen3VlEncoderModel', + parse: async (metadata, store) => { + const raw = getProperty(metadata, 'qwen3_vl_encoder'); + const parsed = await parseModelIdentifier(raw, store, 'qwen3_vl_encoder'); + assert(parsed.type === 'qwen3_vl_encoder'); + const base = selectBase(store.getState()); + assert(base === 'krea-2', 'Krea2Qwen3VlEncoderModel handler only works with Krea-2 models'); + return Promise.resolve(parsed); + }, + recall: (value, store) => { + store.dispatch(krea2Qwen3VlEncoderModelSelected(value)); + }, + i18nKey: 'metadata.krea2Qwen3VlEncoder', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => ( + + ), +}; +//#endregion Krea2Qwen3VlEncoderModel + +//#region Krea2SeedVarianceEnabled +const Krea2SeedVarianceEnabled: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2SeedVarianceEnabled', + parse: (metadata, _store) => { + try { + const raw = getProperty(metadata, 'krea2_seed_variance_enabled'); + return Promise.resolve(z.boolean().parse(raw)); + } catch { + // Default to false when metadata doesn't contain this field (e.g. older images). + return Promise.resolve(false); + } + }, + recall: (value, store) => { + store.dispatch(setKrea2SeedVarianceEnabled(value)); + }, + i18nKey: 'metadata.seedVarianceEnabled', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2SeedVarianceEnabled + +//#region Krea2SeedVarianceStrength +const Krea2SeedVarianceStrength: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2SeedVarianceStrength', + parse: (metadata, _store) => { + const raw = getProperty(metadata, 'krea2_seed_variance_strength'); + return Promise.resolve(z.number().min(0).max(100).parse(raw)); + }, + recall: (value, store) => { + store.dispatch(setKrea2SeedVarianceStrength(value)); + }, + i18nKey: 'metadata.seedVarianceStrength', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2SeedVarianceStrength + +//#region Krea2SeedVarianceRandomizePercent +const Krea2SeedVarianceRandomizePercent: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2SeedVarianceRandomizePercent', + parse: (metadata, _store) => { + const raw = getProperty(metadata, 'krea2_seed_variance_randomize_percent'); + return Promise.resolve(z.number().min(1).max(100).parse(raw)); + }, + recall: (value, store) => { + store.dispatch(setKrea2SeedVarianceRandomizePercent(value)); + }, + i18nKey: 'metadata.seedVarianceRandomizePercent', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2SeedVarianceRandomizePercent + +//#region Krea2RebalanceEnabled +const Krea2RebalanceEnabled: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2RebalanceEnabled', + parse: (metadata, _store) => { + try { + const raw = getProperty(metadata, 'krea2_rebalance_enabled'); + return Promise.resolve(z.boolean().parse(raw)); + } catch { + return Promise.resolve(false); + } + }, + recall: (value, store) => { + store.dispatch(setKrea2RebalanceEnabled(value)); + }, + i18nKey: 'metadata.krea2RebalanceEnabled', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2RebalanceEnabled + +//#region Krea2RebalanceMultiplier +const Krea2RebalanceMultiplier: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2RebalanceMultiplier', + parse: (metadata, _store) => { + const raw = getProperty(metadata, 'krea2_rebalance_multiplier'); + return Promise.resolve(z.number().min(0).max(20).parse(raw)); + }, + recall: (value, store) => { + store.dispatch(setKrea2RebalanceMultiplier(value)); + }, + i18nKey: 'metadata.krea2RebalanceMultiplier', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2RebalanceMultiplier + +//#region Krea2RebalanceWeights +const Krea2RebalanceWeights: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'Krea2RebalanceWeights', + parse: (metadata, _store) => { + const raw = getProperty(metadata, 'krea2_rebalance_weights'); + return Promise.resolve(z.string().parse(raw)); + }, + recall: (value, store) => { + store.dispatch(setKrea2RebalanceWeights(value)); + }, + i18nKey: 'metadata.krea2RebalanceWeights', + LabelComponent: MetadataLabel, + ValueComponent: ({ value }: SingleMetadataValueProps) => , +}; +//#endregion Krea2RebalanceWeights + //#region AnimaVAEModel const AnimaVAEModel: SingleMetadataHandler = { [SingleMetadataKey]: true, @@ -1649,6 +1815,14 @@ export const ImageMetadataHandlers = { ZImageSeedVarianceEnabled, ZImageSeedVarianceStrength, ZImageSeedVarianceRandomizePercent, + Krea2VAEModel, + Krea2Qwen3VlEncoderModel, + Krea2SeedVarianceEnabled, + Krea2SeedVarianceStrength, + Krea2SeedVarianceRandomizePercent, + Krea2RebalanceEnabled, + Krea2RebalanceMultiplier, + Krea2RebalanceWeights, QwenImageComponentSource, QwenImageVaeModel, QwenImageQwenVLEncoderModel, diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts index 38e2fe96b1a..7f208ea9d93 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.ts @@ -164,6 +164,16 @@ export const buildKrea2Graph = async (arg: GraphBuilderArg): Promise 1). Krea-2-Turbo runs with CFG // disabled by default, in which case there is no negative conditioning - recording it would surface a diff --git a/tests/backend/model_manager/configs/test_krea2_main_config.py b/tests/backend/model_manager/configs/test_krea2_main_config.py new file mode 100644 index 00000000000..b1e2f44da00 --- /dev/null +++ b/tests/backend/model_manager/configs/test_krea2_main_config.py @@ -0,0 +1,235 @@ +"""Tests for Krea-2 main-model identification and variant detection. + +Krea-2-Turbo (distilled) and Krea-2-Raw (Base, undistilled) share the IDENTICAL transformer +architecture, so a single-file/GGUF checkpoint cannot be told apart from its weights. Detection: + +1. Explicit ``variant`` in override_fields always wins. +2. Diffusers pipelines read the pipeline-level ``is_distilled`` flag from model_index.json + (``false`` → Base, ``true``/absent → Turbo). +3. Single-file / GGUF fall back to a filename heuristic ("raw"/"base" → Base, else Turbo). +""" + +import json +from pathlib import Path +from tempfile import TemporaryDirectory +from unittest.mock import MagicMock, patch + +import pytest + +from invokeai.backend.model_manager.configs.main import ( + MainModelDefaultSettings, + _get_krea2_variant_from_name, + _has_krea2_keys, +) +from invokeai.backend.model_manager.taxonomy import BaseModelType, Krea2VariantType + +# Required fields for the Pydantic config models (mirrors the other config-probe tests). +_REQUIRED_FIELDS = { + "hash": "blake3:fakehash", + "path": "/fake/models/test", + "file_size": 1000, + "name": "test-model", + "description": "test", + "source": "test", + "source_type": "path", + "key": "test-key", +} + + +class TestKrea2VariantFromName: + """The filename heuristic used for single-file / GGUF Krea-2 checkpoints.""" + + @pytest.mark.parametrize( + "name, expected", + [ + ("Krea-2-Raw", Krea2VariantType.Base), + ("krea2_raw_q4.gguf", Krea2VariantType.Base), + ("Krea-2-RAW-Q8_0.gguf", Krea2VariantType.Base), # case-insensitive + ("krea2_base_fp8_scaled.safetensors", Krea2VariantType.Base), + ("Krea-2-Turbo", Krea2VariantType.Turbo), + ("krea2_turbo-Q3_K_M.gguf", Krea2VariantType.Turbo), + ("Krea-2-Turbo-Q4_K_M.gguf", Krea2VariantType.Turbo), + ("some-random-name.safetensors", Krea2VariantType.Turbo), # default + ], + ) + def test_variant_from_name(self, name: str, expected: Krea2VariantType) -> None: + assert _get_krea2_variant_from_name(name) == expected + + +class TestHasKrea2Keys: + """The Krea-2 transformer state-dict signature (diffusers + native/GGUF naming).""" + + def test_diffusers_naming_matches(self) -> None: + sd = { + "text_fusion.layerwise_blocks.0.attn.to_q.weight": object(), + "img_in.weight": object(), + "transformer_blocks.0.attn.to_q.weight": object(), + } + assert _has_krea2_keys(sd) is True + + def test_native_gguf_naming_matches(self) -> None: + # Compact ComfyUI/GGUF naming: txtfusion + first / tproj. + sd = { + "txtfusion.0.attn.wq.weight": object(), + "first.weight": object(), + "tproj.1.weight": object(), + } + assert _has_krea2_keys(sd) is True + + def test_comfyui_prefixed_keys_match(self) -> None: + sd = { + "model.diffusion_model.text_fusion.projector.weight": object(), + "model.diffusion_model.img_in.weight": object(), + } + assert _has_krea2_keys(sd) is True + + def test_text_fusion_without_corroborator_does_not_match(self) -> None: + # text-fusion alone is not enough — an image-input corroborator is required. + sd = {"text_fusion.projector.weight": object()} + assert _has_krea2_keys(sd) is False + + def test_non_krea2_state_dict_does_not_match(self) -> None: + sd = {"double_blocks.0.img_attn.qkv.weight": object(), "img_in.weight": object()} + assert _has_krea2_keys(sd) is False + + def test_lora_is_rejected(self) -> None: + # LoRA suffixes must never be classified as a Krea-2 main model. + sd = { + "text_fusion.layerwise_blocks.0.attn.to_q.lora_down.weight": object(), + "img_in.lora_up.weight": object(), + } + assert _has_krea2_keys(sd) is False + + +class TestKrea2GGUFVariantDetection: + """Main_GGUF_Krea2_Config: variant from filename, explicit override wins.""" + + def _make_mock_mod(self, filename: str) -> MagicMock: + mod = MagicMock() + mod.path = Path(f"/fake/models/{filename}") + mod.load_state_dict.return_value = {} + return mod + + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=True) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_raw_filename_sets_base_variant(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_GGUF_Krea2_Config + + mod = self._make_mock_mod("Krea-2-Raw-Q4_K_M.gguf") + config = Main_GGUF_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + assert config.variant == Krea2VariantType.Base + + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=True) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_turbo_filename_defaults_to_turbo(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_GGUF_Krea2_Config + + mod = self._make_mock_mod("krea2_turbo-Q3_K_M.gguf") + config = Main_GGUF_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + assert config.variant == Krea2VariantType.Turbo + + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=True) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_explicit_variant_override_wins(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_GGUF_Krea2_Config + + # Filename says Raw, but an explicit Turbo override must not be overwritten. + mod = self._make_mock_mod("Krea-2-Raw-Q4_K_M.gguf") + config = Main_GGUF_Krea2_Config.from_model_on_disk( + mod, {**_REQUIRED_FIELDS, "variant": Krea2VariantType.Turbo} + ) + assert config.variant == Krea2VariantType.Turbo + + +class TestKrea2CheckpointVariantDetection: + """Main_Checkpoint_Krea2_Config: variant from filename (non-GGUF single file).""" + + def _make_mock_mod(self, filename: str) -> MagicMock: + mod = MagicMock() + mod.path = Path(f"/fake/models/{filename}") + mod.load_state_dict.return_value = {} + return mod + + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=False) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_raw_filename_sets_base_variant(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config + + mod = self._make_mock_mod("krea2_raw_fp8_scaled.safetensors") + config = Main_Checkpoint_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + assert config.variant == Krea2VariantType.Base + + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=False) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_turbo_filename_defaults_to_turbo(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config + + mod = self._make_mock_mod("krea2_turbo_fp8_scaled.safetensors") + config = Main_Checkpoint_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + assert config.variant == Krea2VariantType.Turbo + + +class TestKrea2DiffusersVariantDetection: + """Main_Diffusers_Krea2_Config._get_variant reads is_distilled from model_index.json.""" + + def _make_mock_mod_with_model_index(self, tmpdir: str, model_index: dict) -> MagicMock: + path = Path(tmpdir) + (path / "model_index.json").write_text(json.dumps(model_index)) + mod = MagicMock() + mod.path = path + return mod + + def test_is_distilled_false_is_base(self) -> None: + from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config + + with TemporaryDirectory() as tmpdir: + mod = self._make_mock_mod_with_model_index( + tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": False} + ) + assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Base + + def test_is_distilled_true_is_turbo(self) -> None: + from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config + + with TemporaryDirectory() as tmpdir: + mod = self._make_mock_mod_with_model_index( + tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": True} + ) + assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Turbo + + def test_is_distilled_absent_defaults_to_turbo(self) -> None: + from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config + + with TemporaryDirectory() as tmpdir: + mod = self._make_mock_mod_with_model_index(tmpdir, {"_class_name": "Krea2Pipeline"}) + assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Turbo + + +class TestKrea2DefaultSettings: + """Per-variant default generation settings.""" + + def test_turbo_defaults(self) -> None: + ds = MainModelDefaultSettings.from_base(BaseModelType.Krea2, Krea2VariantType.Turbo) + assert ds is not None + assert ds.steps == 8 + assert ds.cfg_scale == 1.0 + assert ds.width == 1024 + assert ds.height == 1024 + + def test_base_defaults(self) -> None: + ds = MainModelDefaultSettings.from_base(BaseModelType.Krea2, Krea2VariantType.Base) + assert ds is not None + assert ds.steps == 28 + assert ds.cfg_scale == 4.5 + assert ds.width == 1024 + assert ds.height == 1024 diff --git a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py new file mode 100644 index 00000000000..7bb8de30449 --- /dev/null +++ b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py @@ -0,0 +1,96 @@ +"""Tests for single-file Qwen3-VL text-encoder identification (used by Krea-2). + +A single-file Qwen3-VL encoder is distinguished from the text-only ``Qwen3Encoder`` (Z-Image / +FLUX.2 Klein) by the presence of the Qwen3-VL **visual tower** (``visual.*`` / ``model.visual.*``). +Both have a Qwen3 text decoder (``model.layers.*``), so the visual tower is the deciding signal. +""" + +from unittest.mock import MagicMock, patch + +import pytest + +from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError +from invokeai.backend.model_manager.configs.qwen3_vl_encoder import ( + Qwen3VLEncoder_Checkpoint_Config, + _is_qwen3_vl_encoder_state_dict, +) +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType + +_REQUIRED_FIELDS = { + "hash": "blake3:fakehash", + "path": "/fake/models/qwen3vl.safetensors", + "file_size": 1000, + "name": "qwen3vl-encoder", + "description": "test", + "source": "test", + "source_type": "path", + "key": "test-key", +} + + +class TestIsQwen3VLEncoderStateDict: + def test_text_decoder_plus_visual_tower_matches(self) -> None: + # ComfyUI single-file layout (implicit LM prefix): model.layers.* + model.visual.* + sd = { + "model.layers.0.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + } + assert _is_qwen3_vl_encoder_state_dict(sd) is True + + def test_explicit_language_model_prefix_matches(self) -> None: + # Alternative single-file layout (explicit LM prefix): model.language_model.layers.* + model.visual.* + sd = { + "model.language_model.layers.0.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + } + assert _is_qwen3_vl_encoder_state_dict(sd) is True + + def test_text_only_decoder_does_not_match(self) -> None: + # Z-Image / FLUX.2 Klein Qwen3 text encoder: text decoder but NO visual tower. + sd = { + "model.layers.0.self_attn.q_proj.weight": object(), + "model.layers.0.mlp.down_proj.weight": object(), + "model.norm.weight": object(), + } + assert _is_qwen3_vl_encoder_state_dict(sd) is False + + def test_visual_tower_only_does_not_match(self) -> None: + sd = {"model.visual.blocks.0.attn.qkv.weight": object()} + assert _is_qwen3_vl_encoder_state_dict(sd) is False + + def test_ignores_non_string_keys(self) -> None: + sd: dict = {0: object(), 1: object()} + assert _is_qwen3_vl_encoder_state_dict(sd) is False + + +class TestQwen3VLEncoderCheckpointConfig: + def _make_mock_mod(self, state_dict: dict) -> MagicMock: + mod = MagicMock() + mod.load_state_dict.return_value = state_dict + return mod + + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_for_override_fields") + def test_matches_vl_single_file(self, _rfo, _rif) -> None: + mod = self._make_mock_mod( + { + "model.layers.0.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + } + ) + config = Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + assert config.type == ModelType.Qwen3VLEncoder + assert config.base == BaseModelType.Any + assert config.format == ModelFormat.Checkpoint + + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_for_override_fields") + def test_rejects_text_only_encoder(self, _rfo, _rif) -> None: + mod = self._make_mock_mod( + { + "model.layers.0.self_attn.q_proj.weight": object(), + "model.norm.weight": object(), + } + ) + with pytest.raises(NotAMatchError): + Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) From dc0620af589dfe347dde7d6d848567b834df15b3 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Mon, 6 Jul 2026 01:59:55 +0200 Subject: [PATCH 08/17] Chore Ruff --- .../model_manager/configs/test_krea2_main_config.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/backend/model_manager/configs/test_krea2_main_config.py b/tests/backend/model_manager/configs/test_krea2_main_config.py index b1e2f44da00..dec82b797fa 100644 --- a/tests/backend/model_manager/configs/test_krea2_main_config.py +++ b/tests/backend/model_manager/configs/test_krea2_main_config.py @@ -141,9 +141,7 @@ def test_explicit_variant_override_wins(self, _rfo, _rif, _hgt, _hkk) -> None: # Filename says Raw, but an explicit Turbo override must not be overwritten. mod = self._make_mock_mod("Krea-2-Raw-Q4_K_M.gguf") - config = Main_GGUF_Krea2_Config.from_model_on_disk( - mod, {**_REQUIRED_FIELDS, "variant": Krea2VariantType.Turbo} - ) + config = Main_GGUF_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS, "variant": Krea2VariantType.Turbo}) assert config.variant == Krea2VariantType.Turbo @@ -193,18 +191,14 @@ def test_is_distilled_false_is_base(self) -> None: from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config with TemporaryDirectory() as tmpdir: - mod = self._make_mock_mod_with_model_index( - tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": False} - ) + mod = self._make_mock_mod_with_model_index(tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": False}) assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Base def test_is_distilled_true_is_turbo(self) -> None: from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config with TemporaryDirectory() as tmpdir: - mod = self._make_mock_mod_with_model_index( - tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": True} - ) + mod = self._make_mock_mod_with_model_index(tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": True}) assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Turbo def test_is_distilled_absent_defaults_to_turbo(self) -> None: From 5cd2bf8bc8dfb4129150c2b6a47c3b561b1f6a03 Mon Sep 17 00:00:00 2001 From: JPPhoto Date: Mon, 13 Jul 2026 13:50:07 -0500 Subject: [PATCH 09/17] fix(krea2): validate denoise inputs and VAE compatibility --- invokeai/app/invocations/krea2_denoise.py | 8 ++++++ invokeai/backend/krea2/vae_compat.py | 3 +++ tests/app/invocations/test_krea2_denoise.py | 28 +++++++++++++++++++++ tests/backend/krea2/test_vae_compat.py | 8 ++++++ uv.lock | 8 +++--- 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 tests/app/invocations/test_krea2_denoise.py create mode 100644 tests/backend/krea2/test_vae_compat.py diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index 88a14419b73..0fef4f592b8 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -143,6 +143,12 @@ def _prepare_cfg_scale(self, num_timesteps: int) -> list[float]: return self.cfg_scale raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}") + def _validate_inputs(self) -> None: + if self.denoising_start >= self.denoising_end: + raise ValueError("denoising_start must be less than denoising_end.") + if self.denoise_mask is not None and self.latents is None: + raise ValueError("Initial latents are required when a denoise mask is provided.") + def _is_distilled(self, context: InvocationContext) -> bool: """Whether the transformer is the distilled Turbo checkpoint (fixed mu) vs. Raw (dynamic mu). @@ -168,6 +174,8 @@ def _is_distilled(self, context: InvocationContext) -> bool: def _run_diffusion(self, context: InvocationContext): from diffusers.schedulers.scheduling_flow_match_euler_discrete import FlowMatchEulerDiscreteScheduler + self._validate_inputs() + inference_dtype = torch.bfloat16 device = TorchDevice.choose_torch_device() diff --git a/invokeai/backend/krea2/vae_compat.py b/invokeai/backend/krea2/vae_compat.py index c42dd3487f3..913236c39be 100644 --- a/invokeai/backend/krea2/vae_compat.py +++ b/invokeai/backend/krea2/vae_compat.py @@ -12,6 +12,7 @@ from typing import Any import accelerate +from diffusers.models.autoencoders import AutoencoderKLWan from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage @@ -25,6 +26,8 @@ def as_qwen_image_vae(model: Any) -> AutoencoderKLQwenImage: """ if isinstance(model, AutoencoderKLQwenImage): return model + if not isinstance(model, AutoencoderKLWan): + raise TypeError(f"Expected AutoencoderKLQwenImage or AutoencoderKLWan, got {type(model).__name__}.") src_state_dict = model.state_dict() with accelerate.init_empty_weights(): diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py new file mode 100644 index 00000000000..03c854b1b20 --- /dev/null +++ b/tests/app/invocations/test_krea2_denoise.py @@ -0,0 +1,28 @@ +import pytest + +from invokeai.app.invocations.fields import DenoiseMaskField +from invokeai.app.invocations.krea2_denoise import Krea2DenoiseInvocation + + +@pytest.mark.parametrize(("denoising_start", "denoising_end"), [(0.75, 0.25), (0.5, 0.5)]) +def test_validate_inputs_rejects_empty_or_inverted_denoising_range( + denoising_start: float, denoising_end: float +) -> None: + invocation = Krea2DenoiseInvocation.model_construct( + denoising_start=denoising_start, denoising_end=denoising_end, denoise_mask=None + ) + + with pytest.raises(ValueError, match="denoising_start must be less than denoising_end"): + invocation._validate_inputs() + + +def test_validate_inputs_rejects_denoise_mask_without_latents() -> None: + invocation = Krea2DenoiseInvocation.model_construct( + denoising_start=0.0, + denoising_end=1.0, + denoise_mask=DenoiseMaskField(mask_name="mask"), + latents=None, + ) + + with pytest.raises(ValueError, match="Initial latents are required when a denoise mask is provided"): + invocation._validate_inputs() diff --git a/tests/backend/krea2/test_vae_compat.py b/tests/backend/krea2/test_vae_compat.py new file mode 100644 index 00000000000..7eb450df12a --- /dev/null +++ b/tests/backend/krea2/test_vae_compat.py @@ -0,0 +1,8 @@ +import pytest + +from invokeai.backend.krea2.vae_compat import as_qwen_image_vae + + +def test_as_qwen_image_vae_rejects_incompatible_model() -> None: + with pytest.raises(TypeError, match="Expected AutoencoderKLQwenImage or AutoencoderKLWan"): + as_qwen_image_vae(object()) diff --git a/uv.lock b/uv.lock index 6d1b0a462f8..d257a993f35 100644 --- a/uv.lock +++ b/uv.lock @@ -616,7 +616,7 @@ wheels = [ [[package]] name = "diffusers" -version = "0.37.0" +version = "0.39.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm') or sys_platform == 'darwin' or sys_platform == 'win32' or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm')" }, @@ -629,9 +629,9 @@ dependencies = [ { name = "requests", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm') or sys_platform == 'darwin' or sys_platform == 'win32' or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm')" }, { name = "safetensors", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (platform_machine != 'x86_64' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm') or sys_platform == 'darwin' or sys_platform == 'win32' or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (sys_platform != 'linux' and extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/3b/01d0ff800b811c5ad8bba682f4c6abf1d7071cd81464c01724333fefb7ba/diffusers-0.37.0.tar.gz", hash = "sha256:408789af73898585f525afd07ca72b3955affea4216a669558e9f59b5b1fe704", size = 4141136, upload-time = "2026-03-05T14:58:39.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/81/6095237b86a3116c4789f28c4435d5296c00c0fc74ffde99008fd6b3a36c/diffusers-0.39.0.tar.gz", hash = "sha256:14bb1d98c85a0e463d734c99aaa73b480a7bc9bad22af30fbf730ef8f09c1d67", size = 4651240, upload-time = "2026-07-03T08:48:47.904Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/55/586a3a2b9c95f371c9c3cb048c3cac15aedcce8d6d53ebd6bbc46860722d/diffusers-0.37.0-py3-none-any.whl", hash = "sha256:7eab74bf896974250b5e1027cae813aba1004f02d97c9b44891b83713386aa08", size = 5000449, upload-time = "2026-03-05T14:58:37.361Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/7469c46e9d22307ea686bab687d70e6bf328722952f9d10339f5e913e608/diffusers-0.39.0-py3-none-any.whl", hash = "sha256:912aca51b5787365110806e984d5555735bf8a461073bb8459029d0bca7870ef", size = 5631176, upload-time = "2026-07-03T08:48:45.337Z" }, ] [package.optional-dependencies] @@ -1125,7 +1125,7 @@ requires-dist = [ { name = "blake3" }, { name = "compel", specifier = ">=2.4.0,<3" }, { name = "deprecated" }, - { name = "diffusers", extras = ["torch"], specifier = "==0.37.0" }, + { name = "diffusers", extras = ["torch"], specifier = "==0.39.0" }, { name = "dnspython" }, { name = "dynamicprompts" }, { name = "einops" }, From cc63dff1ba4fa78b5c2e3eae45600007345dcfb2 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Mon, 13 Jul 2026 22:18:11 +0200 Subject: [PATCH 10/17] test(krea2): add loader, denoise, graph, listener, recall and starter-model coverage Backend: - test_krea2_state_dict_utils.py: cover the pure loader transforms (prefix strip, native<->diffusers conversion, scaled-fp8 dequant, Qwen3-VL key remap) and _reject_incomplete_load parametrized over the single-file/GGUF/encoder call sites (rejects meta-tensor partial loads, names the missing params) - test_krea2_denoise.py: _prepare_cfg_scale (broadcast/length/type), the per-step cfg list vs. img2img-clip regression, _validate_inputs happy path, and _get_noise determinism/shape - test_starter_models.py: Krea-2 bundle registration, diffusers+GGUF+standalone membership, and GGUF entries declaring their VAE + Qwen3-VL dependencies Frontend: - modelSelected.test.ts: Krea-2 standalone-component defaulting (auto-select on GGUF, anima-VAE fallback, no-overwrite, diffusers clears overrides, clear on switch away) - parsing.test.tsx: Krea2 VAE/encoder + enhancer recall gating (parses only for krea-2, never clobbers otherwise) - buildKrea2Graph.test.ts: CFG negative-conditioning gating, enhancer node insertion/chaining, non-diffusers standalone-model assertion, metadata - ImageMetadataActions.test.tsx: require all eight Krea2 recall handlers Fix: exclude krea-2 from the generic VAEModel metadata handler (it has a dedicated Krea2VAEModel handler), matching the existing z-image/flux2 exclusions. --- docs/src/content/docs/features/krea-2.mdx | 71 +++++ .../docs/start-here/system-requirements.mdx | 1 + invokeai/app/invocations/krea2_denoise.py | 40 ++- invokeai/app/invocations/krea2_lora_loader.py | 17 ++ .../app/invocations/krea2_text_encoder.py | 38 ++- .../backend/model_manager/configs/main.py | 12 +- .../model_manager/load/model_loaders/krea2.py | 38 ++- .../backend/model_manager/starter_models.py | 10 + invokeai/frontend/web/public/locales/en.json | 1 + .../listeners/modelSelected.test.ts | 180 ++++++++++- .../listeners/modelSelected.ts | 85 ++++++ .../ImageMetadataActions.test.tsx | 18 ++ .../ImageMetadataActions.tsx | 8 + .../src/features/metadata/parsing.test.tsx | 105 ++++++- .../web/src/features/metadata/parsing.tsx | 51 ++-- .../graph/generation/buildKrea2Graph.test.ts | 279 ++++++++++++++++++ .../ParamKrea2RebalanceWeights.tsx | 2 +- .../src/services/api/hooks/modelsByType.ts | 1 + tests/app/invocations/test_krea2_denoise.py | 66 ++++- .../load/test_krea2_state_dict_utils.py | 210 +++++++++++++ .../model_manager/test_starter_models.py | 80 +++++ 21 files changed, 1246 insertions(+), 67 deletions(-) create mode 100644 docs/src/content/docs/features/krea-2.mdx create mode 100644 invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts create mode 100644 tests/backend/model_manager/load/test_krea2_state_dict_utils.py create mode 100644 tests/backend/model_manager/test_starter_models.py diff --git a/docs/src/content/docs/features/krea-2.mdx b/docs/src/content/docs/features/krea-2.mdx new file mode 100644 index 00000000000..cdfb0aeafd6 --- /dev/null +++ b/docs/src/content/docs/features/krea-2.mdx @@ -0,0 +1,71 @@ +--- +title: Krea-2 +description: Generate images with the Krea-2 text-to-image models (Turbo and Raw), including the GGUF / single-file workflow and the conditioning enhancers. +lastUpdated: 2026-07-13 +sidebar: + order: 5 +--- + +Krea-2 is a ~12B single-stream diffusion-transformer text-to-image family. InvokeAI supports both +published checkpoints: + +- **Krea-2-Turbo** — distilled for fast, low-step generation. Runs at **8 steps** with **CFG disabled** + (CFG Scale `1.0`). This is the recommended checkpoint for everyday use. +- **Krea-2-Raw** — the undistilled base checkpoint. Runs at **more steps (~28)** with **CFG enabled** + (CFG Scale ~`4.5`) and supports negative prompts. It is primarily intended as a base for + finetuning / LoRA training, but full inference is supported. + +The variant is detected automatically on install, and selecting a Krea-2 model sets sensible defaults +(steps, CFG, 1024×1024) for that variant. + +## Hardware + +Krea-2 is a large model. See the [System Requirements](../../start-here/system-requirements) table for +details. In short, on a 24 GB card enable **FP8** in the model's Default Settings to fit 1024² (with a +LoRA). For lower VRAM, use a **GGUF** transformer (Q4_K ≈ 12 GB total). + +## Installing + +The easiest path is the **Krea-2 launchpad bundle** in the Model Manager, which installs the models and +their dependencies together. + +Krea-2 needs three components: + +| Component | Diffusers install | GGUF / single-file install | +|---|---|---| +| Transformer | bundled in the pipeline | the `.gguf` / single-file checkpoint | +| VAE (Qwen-Image) | bundled | installed separately | +| Text encoder (Qwen3-VL) | bundled | installed separately | + +- **Diffusers** (e.g. `krea/Krea-2-Turbo`, `krea/Krea-2-Raw`): a single ~26 GB install that bundles the + VAE and text encoder. Nothing else is required. +- **GGUF / single-file**: the checkpoint ships **only the transformer**. You must also install a + standalone **Qwen-Image VAE** and a **Qwen3-VL encoder** (both included in the launchpad bundle). + +When you select a GGUF/single-file Krea-2 model, InvokeAI auto-selects an installed VAE and Qwen3-VL +encoder if you have them. If none are installed, you'll be prompted to pick them (in the model dropdowns) +before you can generate. Selecting a Diffusers Krea-2 model clears those standalone selections and uses +the bundled components. + +:::note[Qwen3-VL encoder download] +Single-file Qwen3-VL encoders bundle only the weights. The tokenizer/config are fetched once from +HuggingFace (`Qwen/Qwen3-VL-4B-Instruct`) on first use, then cached for offline use. A single-file fp8 +encoder is kept resident in fp8 (roughly half the VRAM of the bf16 encoder). +::: + +## Conditioning enhancers + +Two optional, off-by-default toggles are available under **Advanced Options** (below CFG Scale). They +transform the text conditioning and are especially useful for the distilled Turbo checkpoint: + +- **Conditioning Rebalance** — per-layer weighting of the text embedding to improve prompt adherence. +- **Seed Variance Enhancer** — injects controlled noise into the conditioning to restore per-seed + diversity (the distilled model otherwise produces near-identical images across seeds), trading some + prompt adherence for variety. + +Both are recorded in image metadata and can be recalled. + +## LoRA + +Krea-2 LoRAs (diffusers PEFT format) are supported and apply to both the transformer and — where the +LoRA includes text-encoder layers — the Qwen3-VL encoder. diff --git a/docs/src/content/docs/start-here/system-requirements.mdx b/docs/src/content/docs/start-here/system-requirements.mdx index 114698ce158..4e57d106340 100644 --- a/docs/src/content/docs/start-here/system-requirements.mdx +++ b/docs/src/content/docs/start-here/system-requirements.mdx @@ -28,6 +28,7 @@ The requirements below are rough guidelines for best performance. GPUs with less | FLUX.2 Klein 4B | 1024x1024 | Nvidia 30xx+ | 12GB | 16GB | FP8 works with 8GB+; Diffusers + encoder | | FLUX.2 Klein 9B | 1024x1024 | Nvidia 40xx | 24GB | 32GB | FP8 works with 12GB+; Diffusers + encoder | | Z-Image Turbo | 1024x1024 | Nvidia 20xx+ | 8GB | 16GB | Q4_K 8GB; Q8/BF16 16GB+ | +| Krea-2 (Turbo / Raw) | 1024x1024 | Nvidia 40xx | 24GB | 32GB | FP8 works with 16GB+; GGUF Q4_K ~12GB. Diffusers ~26GB; GGUF needs a standalone VAE + Qwen3-VL encoder | :::tip[`tmpfs` on Linux] If your temporary directory is mounted as a `tmpfs`, ensure it has sufficient space. diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index 0fef4f592b8..a3bcf105cc6 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -139,7 +139,11 @@ def _prepare_cfg_scale(self, num_timesteps: int) -> list[float]: if isinstance(self.cfg_scale, float): return [self.cfg_scale] * num_timesteps if isinstance(self.cfg_scale, list): - assert len(self.cfg_scale) == num_timesteps + if len(self.cfg_scale) != num_timesteps: + raise ValueError( + f"cfg_scale list has {len(self.cfg_scale)} values but the model is configured for " + f"{num_timesteps} steps. Provide one CFG value per configured step (or a single float)." + ) return self.cfg_scale raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}") @@ -154,21 +158,25 @@ def _is_distilled(self, context: InvocationContext) -> bool: Prefer the classified variant (works for diffusers, single-file and GGUF alike); fall back to the pipeline-level ``is_distilled`` flag in model_index.json, then default to distilled. + + A failed config lookup is a real error and is allowed to propagate — silently defaulting to the + Turbo shift would apply the wrong sampling schedule to a Raw model. """ from invokeai.backend.model_manager.taxonomy import Krea2VariantType + config = context.models.get_config(self.transformer.transformer) + variant = getattr(config, "variant", None) + if variant is not None: + return variant != Krea2VariantType.Base + # No classified variant (unexpected for Krea-2) — fall back to the pipeline-level flag. Only a + # missing/malformed model_index.json is tolerated here; it defaults to the distilled behavior. try: - config = context.models.get_config(self.transformer.transformer) - variant = getattr(config, "variant", None) - if variant is not None: - return variant != Krea2VariantType.Base model_index = context.models.get_absolute_path(config) / "model_index.json" if model_index.is_file(): with open(model_index) as f: return bool(json.load(f).get("is_distilled", False)) - except Exception: + except (OSError, ValueError): pass - # Default to the distilled Turbo behavior. return True def _run_diffusion(self, context: InvocationContext): @@ -176,8 +184,8 @@ def _run_diffusion(self, context: InvocationContext): self._validate_inputs() - inference_dtype = torch.bfloat16 device = TorchDevice.choose_torch_device() + inference_dtype = TorchDevice.choose_bfloat16_safe_dtype(device) transformer_info = context.models.load(self.transformer.transformer) @@ -232,17 +240,23 @@ def _run_diffusion(self, context: InvocationContext): # Clip the schedule based on denoising_start/denoising_end for img2img strength. sigmas_sched = scheduler.sigmas # (N+1,) including terminal 0 - if self.denoising_start > 0 or self.denoising_end < 1: - total_sigmas = len(sigmas_sched) - 1 - start_idx = int(round(self.denoising_start * total_sigmas)) - end_idx = int(round(self.denoising_end * total_sigmas)) + total_sigmas = len(sigmas_sched) - 1 # == self.steps + is_clipped = self.denoising_start > 0 or self.denoising_end < 1 + start_idx = int(round(self.denoising_start * total_sigmas)) + end_idx = int(round(self.denoising_end * total_sigmas)) + if is_clipped: sigmas_sched = sigmas_sched[start_idx : end_idx + 1] timesteps_sched = sigmas_sched[:-1] * scheduler.config.num_train_timesteps else: timesteps_sched = scheduler.timesteps total_steps = len(timesteps_sched) - cfg_scale = self._prepare_cfg_scale(total_steps) + + # Build the CFG schedule against the FULL step count, then clip it to the active window. This way a + # caller-supplied per-step CFG list (one value per configured step) survives the reduction caused + # by denoising_start/denoising_end; a scalar is simply broadcast. + full_cfg_scale = self._prepare_cfg_scale(total_sigmas) + cfg_scale = full_cfg_scale[start_idx:end_idx] if is_clipped else full_cfg_scale # Load initial latents (img2img). init_latents = context.tensors.load(self.latents.latents_name) if self.latents else None diff --git a/invokeai/app/invocations/krea2_lora_loader.py b/invokeai/app/invocations/krea2_lora_loader.py index 0bacf45ffee..0f394a133bc 100644 --- a/invokeai/app/invocations/krea2_lora_loader.py +++ b/invokeai/app/invocations/krea2_lora_loader.py @@ -60,6 +60,12 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: if not context.models.exists(lora_key): raise ValueError(f"Unknown lora: {lora_key}!") + if self.lora.base is not BaseModelType.Krea2: + raise ValueError( + f"LoRA '{lora_key}' is for {self.lora.base.value if self.lora.base else 'unknown'} models, " + "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." + ) + if self.transformer and any(lora.lora.key == lora_key for lora in self.transformer.loras): raise ValueError(f'LoRA "{lora_key}" already applied to transformer.') if self.qwen3_vl_encoder and any(lora.lora.key == lora_key for lora in self.qwen3_vl_encoder.loras): @@ -113,6 +119,17 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: if self.qwen3_vl_encoder is not None: output.qwen3_vl_encoder = self.qwen3_vl_encoder.model_copy(deep=True) + # Seed the dedup set with LoRAs already present on the incoming fields so chaining collection + # loaders can't apply the same LoRA twice (the transformer and encoder are kept in sync below). + if self.transformer is not None: + added_loras.extend(existing.lora.key for existing in self.transformer.loras) + if self.qwen3_vl_encoder is not None: + added_loras.extend( + existing.lora.key + for existing in self.qwen3_vl_encoder.loras + if existing.lora.key not in added_loras + ) + for lora in loras: if lora is None: continue diff --git a/invokeai/app/invocations/krea2_text_encoder.py b/invokeai/app/invocations/krea2_text_encoder.py index 6464efc7234..852f774953c 100644 --- a/invokeai/app/invocations/krea2_text_encoder.py +++ b/invokeai/app/invocations/krea2_text_encoder.py @@ -1,3 +1,6 @@ +from contextlib import ExitStack +from typing import Iterator, Tuple + import torch from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation @@ -17,10 +20,14 @@ KREA2_START_IDX, ) from invokeai.backend.model_manager.load.model_cache.utils import get_effective_device +from invokeai.backend.patches.layer_patcher import LayerPatcher +from invokeai.backend.patches.lora_conversions.krea2_lora_constants import KREA2_LORA_QWEN3VL_PREFIX +from invokeai.backend.patches.model_patch_raw import ModelPatchRaw from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ( ConditioningFieldData, Krea2ConditioningInfo, ) +from invokeai.backend.util.devices import TorchDevice # Prompt template from diffusers Krea2Pipeline.get_text_hidden_states. The prefix (a system turn that # instructs the model to describe the image) is the same "generate" template used by Qwen-Image, which @@ -76,9 +83,23 @@ def _encode(self, context: InvocationContext) -> tuple[torch.Tensor, torch.Tenso context.util.signal_progress("Running Qwen3-VL text encoder") - with tokenizer_info as tokenizer, text_encoder_info.model_on_device() as (_, text_encoder): + with ExitStack() as exit_stack: + tokenizer = exit_stack.enter_context(tokenizer_info) + (cached_weights, text_encoder) = exit_stack.enter_context(text_encoder_info.model_on_device()) device = get_effective_device(text_encoder) + # Apply any Qwen3-VL text-encoder LoRA patches (smart/sidecar patching, fp8-aware). Without + # this, the encoder portion of a Krea-2 LoRA would be silently ignored. + exit_stack.enter_context( + LayerPatcher.apply_smart_model_patches( + model=text_encoder, + patches=self._lora_iterator(context), + prefix=KREA2_LORA_QWEN3VL_PREFIX, + dtype=TorchDevice.choose_bfloat16_safe_dtype(device), + cached_weights=cached_weights, + ) + ) + model_inputs = tokenizer( text, max_length=max_length, @@ -111,10 +132,23 @@ def _encode(self, context: InvocationContext) -> tuple[torch.Tensor, torch.Tenso prompt_embeds = stacked[:, KREA2_START_IDX:] prompt_mask = attention_mask[:, KREA2_START_IDX:].bool() - prompt_embeds = prompt_embeds.to(dtype=torch.bfloat16) + # Match the device-safe compute dtype used by the denoise loop (falls back from bf16 to + # fp16/fp32 on devices without bf16 support) rather than forcing bfloat16. + prompt_embeds = prompt_embeds.to(dtype=TorchDevice.choose_bfloat16_safe_dtype(device)) # If every token is valid (no padding), the mask is unnecessary. if prompt_mask is not None and bool(prompt_mask.all()): prompt_mask = None return prompt_embeds, prompt_mask + + def _lora_iterator(self, context: InvocationContext) -> Iterator[Tuple[ModelPatchRaw, float]]: + """Iterate over the LoRA models to apply to the Qwen3-VL text encoder.""" + for lora in self.qwen3_vl_encoder.loras: + lora_info = context.models.load(lora.lora) + if not isinstance(lora_info.model, ModelPatchRaw): + raise TypeError( + f"Expected ModelPatchRaw for LoRA '{lora.lora.key}', got {type(lora_info.model).__name__}." + ) + yield (lora_info.model, lora.weight) + del lora_info diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index 1ecdca83a77..9c0efd392bb 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -1398,12 +1398,12 @@ def _get_variant(cls, mod: ModelOnDisk) -> Krea2VariantType: Krea-2-Raw sets ``is_distilled=false`` (undistilled Base, more steps, CFG on). The transformer architectures are identical, so this flag is the only reliable discriminator. """ - try: - config = get_config_dict_or_raise(mod.path / "model_index.json") - if config.get("is_distilled", True) is False: - return Krea2VariantType.Base - except Exception: - pass + # model_index.json was already validated by the class-name check in from_model_on_disk, so a + # read/parse failure here is a genuine identification error and is allowed to propagate rather + # than being silently registered as Turbo (which would give a Raw model the wrong defaults). + config = get_config_dict_or_raise(mod.path / "model_index.json") + if config.get("is_distilled", True) is False: + return Krea2VariantType.Base return Krea2VariantType.Turbo diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py index 825b13957fb..4114254eaab 100644 --- a/invokeai/backend/model_manager/load/model_loaders/krea2.py +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -320,6 +320,7 @@ def _load_from_singlefile(self, config: AnyModelConfig) -> AnyModel: sd[k] = sd[k].to(model_dtype) model.load_state_dict(sd, assign=True, strict=False) + _reject_incomplete_load(model, what="Krea-2 single-file checkpoint") # Honor the fp8-storage setting (re-quantizes the dequantized weights to fp8-resident on CUDA). model = self._apply_fp8_layerwise_casting(model, config, SubModelType.Transformer) return model @@ -350,11 +351,8 @@ def _load_model( def _load_from_gguf(self, config: AnyModelConfig) -> AnyModel: from diffusers import Krea2Transformer2DModel - from invokeai.backend.util.logging import InvokeAILogger - if not isinstance(config, Main_GGUF_Krea2_Config): raise TypeError(f"Expected Main_GGUF_Krea2_Config, got {type(config).__name__}.") - logger = InvokeAILogger.get_logger(self.__class__.__name__) model_path = Path(config.path) target_device = TorchDevice.choose_torch_device() @@ -370,17 +368,11 @@ def _load_from_gguf(self, config: AnyModelConfig) -> AnyModel: with accelerate.init_empty_weights(): model = Krea2Transformer2DModel(**KREA2_TRANSFORMER_CONFIG) - missing_keys, unexpected_keys = model.load_state_dict(sd, assign=True, strict=False) - # Surface key-format mismatches: GGUF conversions (city96/ComfyUI) may use original/ComfyUI key - # names that differ from the diffusers Krea2Transformer2DModel. If many params remain on meta, - # a dedicated GGUF->diffusers key conversion is needed (cf. Z-Image's _convert_z_image_gguf_to_diffusers). - still_meta = [name for name, p in model.named_parameters() if p.is_meta] - if still_meta: - logger.warning( - f"Krea-2 GGUF load left {len(still_meta)} parameters on meta (missing from state dict). " - f"First few: {still_meta[:8]}. unexpected_keys={len(unexpected_keys)}. " - "This likely means the GGUF uses a key naming that needs conversion to diffusers format." - ) + model.load_state_dict(sd, assign=True, strict=False) + # Reject GGUF layouts that don't fully populate the diffusers Krea2Transformer2DModel (city96/ + # ComfyUI GGUFs may use key names needing conversion). Failing here beats a confusing meta-tensor + # crash mid-inference. + _reject_incomplete_load(model, what="Krea-2 GGUF checkpoint") return model @@ -452,6 +444,23 @@ def _remap_qwen3vl_singlefile_keys(sd: dict[str, Any]) -> dict[str, Any]: return out +def _reject_incomplete_load(model: Any, *, what: str) -> None: + """Raise if a ``load_state_dict(strict=False)`` left required parameters on the meta device. + + ``strict=False`` is used to tolerate benign extra/renamed keys, but it also silently accepts a + checkpoint that omits required weights — those tensors stay on the meta device and only fail much + later during inference. Reject such loads here, naming the offending parameters, so an incomplete, + misidentified, or differently-converted checkpoint fails at load time with an actionable message. + """ + still_meta = [name for name, p in model.named_parameters() if getattr(p, "is_meta", False)] + if still_meta: + raise RuntimeError( + f"{what} is incomplete: {len(still_meta)} parameter(s) were not provided by the checkpoint " + f"and remain uninitialized (meta device). First few: {still_meta[:8]}. The file is likely " + "incomplete, misidentified, or uses a key layout that needs conversion." + ) + + @ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Qwen3VLEncoder, format=ModelFormat.Checkpoint) class Qwen3VLEncoderCheckpointLoader(ModelLoader): """Loads a single-file Qwen3-VL encoder checkpoint (e.g. ComfyUI ``qwen3vl_4b_bf16`` / ``_fp8_scaled``). @@ -538,6 +547,7 @@ def _load_text_encoder(self, config: Qwen3VLEncoder_Checkpoint_Config) -> AnyMod sd[k] = sd[k].to(model_dtype) model.load_state_dict(sd, assign=True, strict=False) + _reject_incomplete_load(model, what="Qwen3-VL encoder checkpoint") # Keep an fp8 encoder running in fp8 (storage=float8_e4m3fn, per-layer upcast to the compute # dtype during forward) on CUDA. `_should_use_fp8` deliberately excludes text encoders (and the diff --git a/invokeai/backend/model_manager/starter_models.py b/invokeai/backend/model_manager/starter_models.py index 92d6d5decfd..213ae1733d9 100644 --- a/invokeai/backend/model_manager/starter_models.py +++ b/invokeai/backend/model_manager/starter_models.py @@ -1929,6 +1929,15 @@ def _gemini_3_resolution_presets( anima_lllite_sketch, ] +krea2_bundle: list[StarterModel] = [ + qwen_image_vae, + qwen3_vl_encoder_4b, + krea2_turbo, + krea2_raw, + krea2_turbo_gguf_q4_k_m, + krea2_turbo_gguf_q8_0, +] + STARTER_BUNDLES: dict[str, StarterModelBundle] = { BaseModelType.StableDiffusion1: StarterModelBundle(name="Stable Diffusion 1.5", models=sd1_bundle), BaseModelType.StableDiffusionXL: StarterModelBundle(name="SDXL", models=sdxl_bundle), @@ -1937,6 +1946,7 @@ def _gemini_3_resolution_presets( BaseModelType.ZImage: StarterModelBundle(name="Z-Image Turbo", models=zimage_bundle), BaseModelType.QwenImage: StarterModelBundle(name="Qwen Image", models=qwen_image_bundle), BaseModelType.Anima: StarterModelBundle(name="Anima", models=anima_bundle), + BaseModelType.Krea2: StarterModelBundle(name="Krea-2", models=krea2_bundle), } assert len(STARTER_MODELS) == len({m.source for m in STARTER_MODELS}), "Duplicate starter models" diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c171408fc89..95aa80a5d10 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1756,6 +1756,7 @@ "krea2RebalanceEnabled": "Conditioning Rebalance", "krea2RebalanceMultiplier": "Rebalance Multiplier", "krea2RebalanceWeights": "Per-Layer Weights (12)", + "krea2RebalanceWeightsPlaceholder": "1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0", "imageActions": "Image Actions", "sendToCanvas": "Send To Canvas", "sendToUpscale": "Send To Upscale", diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts index 2dab056cf69..5786c232f8a 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts @@ -37,6 +37,33 @@ const mockFluxMainModel = { type: 'main' as const, }; +const mockKrea2MainModel = { + key: 'krea2-main-key', + hash: 'krea2-main-hash', + name: 'Krea-2 Turbo', + base: 'krea-2' as const, + type: 'main' as const, +}; + +// Krea-2 borrows the Qwen-Image VAE and uses a standalone Qwen3-VL encoder for single-file / GGUF transformers. +const mockKrea2Vae = { + key: 'krea2-vae-key', + hash: 'krea2-vae-hash', + name: 'Qwen Image VAE', + base: 'qwen-image' as const, + type: 'vae' as const, + format: 'checkpoint' as const, +}; + +const mockKrea2Qwen3VlEncoder = { + key: 'krea2-q3vl-key', + hash: 'krea2-q3vl-hash', + name: 'Qwen3-VL 4B Encoder', + base: 'any' as const, + type: 'qwen3_vl_encoder' as const, + format: 'qwen3_vl_encoder' as const, +}; + // Track dispatched actions const dispatched: Array<{ type: string; payload: unknown }> = []; const mockDispatch = vi.fn((action: { type: string; payload: unknown }) => { @@ -69,9 +96,15 @@ const mockSelectAnimaQwen3EncoderModels = vi.fn((_state: unknown) => [mockAnimaQ const mockSelectAnimaVAEModels = vi.fn((_state: unknown) => [mockAnimaVAE]); +// Krea-2 standalone-component selectors (used only by the Krea-2 auto-select branch). +const mockSelectQwenImageVAEModels = vi.fn((_state: unknown) => [mockKrea2Vae]); +const mockSelectQwen3VLEncoderModels = vi.fn((_state: unknown) => [mockKrea2Qwen3VlEncoder]); + vi.mock('services/api/hooks/modelsByType', () => ({ selectAnimaQwen3EncoderModels: (state: unknown) => mockSelectAnimaQwen3EncoderModels(state), selectAnimaVAEModels: (state: unknown) => mockSelectAnimaVAEModels(state), + selectQwenImageVAEModels: (state: unknown) => mockSelectQwenImageVAEModels(state), + selectQwen3VLEncoderModels: (state: unknown) => mockSelectQwen3VLEncoderModels(state), selectQwen3EncoderModels: vi.fn(() => []), selectZImageDiffusersModels: vi.fn(() => []), selectFluxVAEModels: vi.fn(() => []), @@ -79,10 +112,14 @@ vi.mock('services/api/hooks/modelsByType', () => ({ selectRegionalRefImageModels: vi.fn(() => []), })); -// Mock model configs adapter +// Mock model configs adapter. Routed through overridable fns so the Krea-2 tests can toggle the resolved +// model's format (diffusers vs. single-file/GGUF), which drives clear-vs-auto-select. +const mockSelectModelConfigsQuery = vi.fn((_state: unknown) => ({ data: undefined }) as { data: unknown }); +const mockSelectModelById = vi.fn((_data: unknown, _key: string) => undefined as unknown); + vi.mock('services/api/endpoints/models', () => ({ - modelConfigsAdapterSelectors: { selectById: vi.fn() }, - selectModelConfigsQuery: vi.fn(() => ({ data: undefined })), + modelConfigsAdapterSelectors: { selectById: (data: unknown, key: string) => mockSelectModelById(data, key) }, + selectModelConfigsQuery: (state: unknown) => mockSelectModelConfigsQuery(state), })); vi.mock('services/api/types', () => ({ @@ -144,8 +181,15 @@ let capturedEffect: ((action: unknown, api: unknown) => void) | null = null; const paramsSliceActual = (await vi.importActual('features/controlLayers/store/paramsSlice')) as { animaQwen3EncoderModelSelected: { type: string }; animaVaeModelSelected: { type: string }; + krea2VaeModelSelected: { type: string }; + krea2Qwen3VlEncoderModelSelected: { type: string }; }; -const { animaQwen3EncoderModelSelected, animaVaeModelSelected } = paramsSliceActual; +const { + animaQwen3EncoderModelSelected, + animaVaeModelSelected, + krea2VaeModelSelected, + krea2Qwen3VlEncoderModelSelected, +} = paramsSliceActual; // Import after mocks are set up const { addModelSelectedListener } = await import('./modelSelected'); @@ -310,3 +354,131 @@ describe('zModelIdentifierField schema validation', () => { expect(zModelIdentifierField.safeParse(complete).success).toBe(true); }); }); + +describe('modelSelected listener - Krea-2 defaulting', () => { + beforeEach(() => { + dispatched.length = 0; + mockDispatch.mockClear(); + // Standalone components installed by default; resolved model defaults to a non-diffusers (single-file / + // GGUF) transformer, which is what triggers the auto-select branch. + mockSelectQwenImageVAEModels.mockReturnValue([mockKrea2Vae]); + mockSelectAnimaVAEModels.mockReturnValue([mockAnimaVAE]); + mockSelectQwen3VLEncoderModels.mockReturnValue([mockKrea2Qwen3VlEncoder]); + mockSelectModelConfigsQuery.mockReturnValue({ data: undefined }); + mockSelectModelById.mockReturnValue(undefined); + }); + + it('auto-selects a standalone VAE and Qwen3-VL encoder when switching to a single-file/GGUF Krea-2 model', () => { + const state = buildMockState({ model: mockFluxMainModel }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + const vaeDispatch = dispatched.find((a) => a.type === krea2VaeModelSelected.type); + const encoderDispatch = dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type); + + expect(vaeDispatch).toBeDefined(); + expect(encoderDispatch).toBeDefined(); + // The reducer parses payloads with zModelIdentifierField, so the dispatched values must be complete. + expect(zModelIdentifierField.safeParse(vaeDispatch!.payload).success).toBe(true); + expect(zModelIdentifierField.safeParse(encoderDispatch!.payload).success).toBe(true); + expect(vaeDispatch!.payload).toMatchObject({ key: mockKrea2Vae.key, type: 'vae' }); + expect(encoderDispatch!.payload).toMatchObject({ key: mockKrea2Qwen3VlEncoder.key, type: 'qwen3_vl_encoder' }); + }); + + it('falls back to an Anima-tagged VAE when no Qwen-Image VAE is installed', () => { + mockSelectQwenImageVAEModels.mockReturnValue([]); + mockSelectAnimaVAEModels.mockReturnValue([mockAnimaVAE]); + + const state = buildMockState({ model: mockFluxMainModel }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + const vaeDispatch = dispatched.find((a) => a.type === krea2VaeModelSelected.type); + expect(vaeDispatch).toBeDefined(); + expect(vaeDispatch!.payload).toMatchObject({ key: mockAnimaVAE.key }); + }); + + it('does not auto-select standalone components when none are installed', () => { + // No Qwen-Image VAEs, no Anima VAEs (the fallback), no Qwen3-VL encoders. + mockSelectQwenImageVAEModels.mockReturnValue([]); + mockSelectAnimaVAEModels.mockReturnValue([]); + mockSelectQwen3VLEncoderModels.mockReturnValue([]); + + const state = buildMockState({ model: mockFluxMainModel }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + expect(dispatched.find((a) => a.type === krea2VaeModelSelected.type)).toBeUndefined(); + expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)).toBeUndefined(); + }); + + it('does not overwrite standalone components the user already selected', () => { + const state = buildMockState({ + model: mockFluxMainModel, + krea2VaeModel: { key: 'existing-vae', hash: 'h', name: 'Existing VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { + key: 'existing-enc', + hash: 'h', + name: 'Existing Enc', + base: 'any', + type: 'qwen3_vl_encoder', + }, + }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + // Already set + non-diffusers -> nothing dispatched for the standalone slots. + expect(dispatched.find((a) => a.type === krea2VaeModelSelected.type)).toBeUndefined(); + expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)).toBeUndefined(); + }); + + it('clears stale standalone overrides when switching to a Diffusers Krea-2 model', () => { + // A Diffusers pipeline bundles its own VAE + encoder, so any standalone overrides must be cleared. + mockSelectModelConfigsQuery.mockReturnValue({ data: {} }); + mockSelectModelById.mockReturnValue({ format: 'diffusers' }); + + const state = buildMockState({ + model: mockFluxMainModel, + krea2VaeModel: { key: 'stale-vae', hash: 'h', name: 'Stale VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { + key: 'stale-enc', + hash: 'h', + name: 'Stale Enc', + base: 'any', + type: 'qwen3_vl_encoder', + }, + }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + const vaeDispatch = dispatched.find((a) => a.type === krea2VaeModelSelected.type); + const encoderDispatch = dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type); + expect(vaeDispatch).toBeDefined(); + expect(vaeDispatch!.payload).toBeNull(); + expect(encoderDispatch).toBeDefined(); + expect(encoderDispatch!.payload).toBeNull(); + }); + + it('clears Krea-2 standalone components when switching away from Krea-2', () => { + const state = buildMockState({ + model: mockKrea2MainModel, + krea2VaeModel: { key: 'vae', hash: 'h', name: 'VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { key: 'enc', hash: 'h', name: 'Enc', base: 'any', type: 'qwen3_vl_encoder' }, + }); + const action = modelSelected(zParameterModel.parse(mockFluxMainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + const vaeDispatch = dispatched.find((a) => a.type === krea2VaeModelSelected.type); + const encoderDispatch = dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type); + expect(vaeDispatch).toBeDefined(); + expect(vaeDispatch!.payload).toBeNull(); + expect(encoderDispatch).toBeDefined(); + expect(encoderDispatch!.payload).toBeNull(); + }); +}); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 9e67e013946..67a14c71eb6 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -9,6 +9,8 @@ import { aspectRatioIdChanged, kleinQwen3EncoderModelSelected, kleinVaeModelSelected, + krea2Qwen3VlEncoderModelSelected, + krea2VaeModelSelected, modelChanged, qwenImageComponentSourceSelected, qwenImageQwenVLEncoderModelSelected, @@ -57,6 +59,7 @@ import { selectFluxVAEModels, selectGlobalRefImageModels, selectQwen3EncoderModels, + selectQwen3VLEncoderModels, selectQwenImageDiffusersModels, selectQwenImageVAEModels, selectQwenVLEncoderModels, @@ -302,6 +305,56 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = } } + // handle incompatible Krea-2 standalone components + const { krea2VaeModel, krea2Qwen3VlEncoderModel } = state.params; + if (newBase !== 'krea-2') { + // Switching away from Krea-2 - clear the standalone VAE / Qwen3-VL encoder selections so they + // don't survive onto another model family (or get reused as stale overrides later). + if (krea2VaeModel) { + dispatch(krea2VaeModelSelected(null)); + modelsUpdatedDisabledOrCleared += 1; + } + if (krea2Qwen3VlEncoderModel) { + dispatch(krea2Qwen3VlEncoderModelSelected(null)); + modelsUpdatedDisabledOrCleared += 1; + } + } else { + // Switching to Krea-2. A Diffusers pipeline bundles its own VAE + encoder, so clear any + // standalone overrides (buildKrea2Graph would otherwise pass stale selections). A single-file / + // GGUF transformer ships only the transformer, so auto-select standalone components if the user + // hasn't already picked them - this unblocks the readiness check after installing the starter pack. + const modelConfigsResult = selectModelConfigsQuery(state); + const newModelConfig = modelConfigsResult.data + ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) + : undefined; + const isDiffusers = newModelConfig?.format === 'diffusers'; + + if (isDiffusers) { + if (krea2VaeModel) { + dispatch(krea2VaeModelSelected(null)); + modelsUpdatedDisabledOrCleared += 1; + } + if (krea2Qwen3VlEncoderModel) { + dispatch(krea2Qwen3VlEncoderModelSelected(null)); + modelsUpdatedDisabledOrCleared += 1; + } + } else { + if (!krea2VaeModel) { + // Krea-2 shares the Qwen-Image VAE; the dropdown also accepts anima-tagged copies. + const vae = selectQwenImageVAEModels(state)[0] ?? selectAnimaVAEModels(state)[0]; + if (vae) { + dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(vae))); + } + } + if (!krea2Qwen3VlEncoderModel) { + const encoder = selectQwen3VLEncoderModels(state)[0]; + if (encoder) { + dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(encoder))); + } + } + } + } + if (newModel.base !== 'external' && SUPPORTS_REF_IMAGES_BASE_MODELS.includes(newModel.base)) { // Handle incompatible reference image models - switch to first compatible model, with some smart logic // to choose the best available model based on the new main model. @@ -519,6 +572,38 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = } } + // Handle Krea-2 model changes within the same base (e.g. switching GGUF <-> Diffusers). A Diffusers + // pipeline bundles its VAE + encoder, so stale standalone overrides must be cleared; a single-file / + // GGUF transformer needs standalone components auto-selected so the readiness check passes. + if (newBase === 'krea-2' && state.params.model?.base === 'krea-2' && newModel.key !== state.params.model?.key) { + const { krea2VaeModel, krea2Qwen3VlEncoderModel } = state.params; + const modelConfigsResult = selectModelConfigsQuery(state); + const newModelConfig = modelConfigsResult.data + ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) + : undefined; + if (newModelConfig?.format === 'diffusers') { + if (krea2VaeModel) { + dispatch(krea2VaeModelSelected(null)); + } + if (krea2Qwen3VlEncoderModel) { + dispatch(krea2Qwen3VlEncoderModelSelected(null)); + } + } else { + if (!krea2VaeModel) { + const vae = selectQwenImageVAEModels(state)[0] ?? selectAnimaVAEModels(state)[0]; + if (vae) { + dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(vae))); + } + } + if (!krea2Qwen3VlEncoderModel) { + const encoder = selectQwen3VLEncoderModels(state)[0]; + if (encoder) { + dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(encoder))); + } + } + } + } + // Handle Z-Image scheduler when switching to Z-Image Base (zbase) model // LCM is not supported for undistilled models, so reset to euler if (newBase === 'z-image' && state.params.zImageScheduler === 'lcm') { diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx index a4f1427aef9..853bf2ceaad 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx @@ -9,4 +9,22 @@ describe('IMAGE_METADATA_ACTION_HANDLERS', () => { expect(IMAGE_METADATA_ACTION_HANDLERS).toContain(ImageMetadataHandlers.QwenImageQuantization); expect(IMAGE_METADATA_ACTION_HANDLERS).toContain(ImageMetadataHandlers.QwenImageShift); }); + + it('includes every Krea-2 metadata handler in the recall parameters UI', () => { + // Krea-2 records standalone components (single-file / GGUF) and the conditioning-enhancer settings. + // All must be wired into the recall UI, otherwise they are saved to metadata but cannot be recalled. + const krea2Handlers = [ + ImageMetadataHandlers.Krea2VAEModel, + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel, + ImageMetadataHandlers.Krea2SeedVarianceEnabled, + ImageMetadataHandlers.Krea2SeedVarianceStrength, + ImageMetadataHandlers.Krea2SeedVarianceRandomizePercent, + ImageMetadataHandlers.Krea2RebalanceEnabled, + ImageMetadataHandlers.Krea2RebalanceMultiplier, + ImageMetadataHandlers.Krea2RebalanceWeights, + ]; + for (const handler of krea2Handlers) { + expect(IMAGE_METADATA_ACTION_HANDLERS).toContain(handler); + } + }); }); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx index f20ef705be3..85d66d2ba2f 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx @@ -65,6 +65,14 @@ export const IMAGE_METADATA_ACTION_HANDLERS: ImageMetadataActionHandler[] = [ ImageMetadataHandlers.RefImages, ImageMetadataHandlers.KleinVAEModel, ImageMetadataHandlers.KleinQwen3EncoderModel, + ImageMetadataHandlers.Krea2VAEModel, + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel, + ImageMetadataHandlers.Krea2SeedVarianceEnabled, + ImageMetadataHandlers.Krea2SeedVarianceStrength, + ImageMetadataHandlers.Krea2SeedVarianceRandomizePercent, + ImageMetadataHandlers.Krea2RebalanceEnabled, + ImageMetadataHandlers.Krea2RebalanceMultiplier, + ImageMetadataHandlers.Krea2RebalanceWeights, ImageMetadataHandlers.LoRAs, ]; diff --git a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx index bb295303273..f008a7208f8 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx @@ -22,7 +22,7 @@ vi.mock('features/controlLayers/store/paramsSlice', async (importOriginal) => { return { ...mod, selectBase: () => currentBase }; }); -const fakeModel = (type: 'vae' | 'qwen3_encoder', base: string) => ({ +const fakeModel = (type: 'vae' | 'qwen3_encoder' | 'qwen3_vl_encoder', base: string) => ({ key: `${type}-key`, hash: 'hash', name: `Some ${type}`, @@ -105,10 +105,11 @@ describe('ImageMetadataHandlers — Klein recall gating', () => { }); describe('VAEModel (generic)', () => { - // The generic VAEModel handler must NOT also fire for FLUX.2 / Z-Image - // images, otherwise the metadata viewer renders duplicate VAE rows next - // to the dedicated KleinVAEModel / ZImageVAEModel handlers. - it.each(['flux2', 'z-image'])('rejects parsing when current base is %s', async (base) => { + // The generic VAEModel handler must NOT also fire for FLUX.2 / Z-Image / + // Krea-2 images, otherwise the metadata viewer renders duplicate VAE rows + // next to the dedicated KleinVAEModel / ZImageVAEModel / Krea2VAEModel + // handlers (and recalls into the wrong, shared VAE slot). + it.each(['flux2', 'z-image', 'krea-2'])('rejects parsing when current base is %s', async (base) => { currentBase = base; nextResolved = fakeModel('vae', base); const store = makeStore(); @@ -172,3 +173,97 @@ describe('ImageMetadataHandlers — Klein recall gating', () => { }); }); }); + +describe('ImageMetadataHandlers — Krea-2 recall gating', () => { + // Krea-2 borrows the Qwen-Image VAE and a standalone Qwen3-VL encoder for single-file / GGUF + // transformers, recalled into dedicated (krea2VaeModel / krea2Qwen3VlEncoderModel) slots — but only when + // the current main model is actually Krea-2. + describe('Krea2VAEModel', () => { + it('parses metadata.vae when the current main model is Krea-2', async () => { + currentBase = 'krea-2'; + nextResolved = fakeModel('vae', 'krea-2'); + const store = makeStore(); + + const parsed = await ImageMetadataHandlers.Krea2VAEModel.parse({ vae: nextResolved }, store); + + expect(parsed.key).toBe('vae-key'); + expect(parsed.type).toBe('vae'); + }); + + it('rejects parsing when the current main model is not Krea-2', async () => { + currentBase = 'sdxl'; + nextResolved = fakeModel('vae', 'krea-2'); + const store = makeStore(); + + await expect(ImageMetadataHandlers.Krea2VAEModel.parse({ vae: nextResolved }, store)).rejects.toThrow(); + }); + }); + + describe('Krea2Qwen3VlEncoderModel', () => { + it('parses metadata.qwen3_vl_encoder when the current main model is Krea-2', async () => { + currentBase = 'krea-2'; + nextResolved = fakeModel('qwen3_vl_encoder', 'krea-2'); + const store = makeStore(); + + const parsed = await ImageMetadataHandlers.Krea2Qwen3VlEncoderModel.parse( + { qwen3_vl_encoder: nextResolved }, + store + ); + + expect(parsed.key).toBe('qwen3_vl_encoder-key'); + expect(parsed.type).toBe('qwen3_vl_encoder'); + }); + + it('rejects parsing when the current main model is not Krea-2', async () => { + currentBase = 'flux'; + nextResolved = fakeModel('qwen3_vl_encoder', 'krea-2'); + const store = makeStore(); + + await expect( + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel.parse({ qwen3_vl_encoder: nextResolved }, store) + ).rejects.toThrow(); + }); + }); + + // The conditioning-enhancer settings are Krea-2-only scalars. Their parse is gated on the current base so + // recalling an unrelated (older / non-Krea-2) image does NOT clobber the user's hidden enhancer state. + // The base check throws synchronously, which the parse runner turns into a rejected promise. + describe('conditioning-enhancer gating', () => { + const enhancerCases = [ + { handler: 'Krea2SeedVarianceEnabled', field: 'krea2_seed_variance_enabled', value: true }, + { handler: 'Krea2SeedVarianceStrength', field: 'krea2_seed_variance_strength', value: 20 }, + { handler: 'Krea2SeedVarianceRandomizePercent', field: 'krea2_seed_variance_randomize_percent', value: 50 }, + { handler: 'Krea2RebalanceEnabled', field: 'krea2_rebalance_enabled', value: true }, + { handler: 'Krea2RebalanceMultiplier', field: 'krea2_rebalance_multiplier', value: 4 }, + { handler: 'Krea2RebalanceWeights', field: 'krea2_rebalance_weights', value: '1,1,1,1,1,1,1,2.5,5,1.1,4,1' }, + ] as const; + + // The six handlers have different value types (boolean/number/string), so index into a loosely-typed + // view to keep the union of parse signatures callable. + const getHandler = (name: (typeof enhancerCases)[number]['handler']) => + ImageMetadataHandlers[name] as unknown as { + parse: (metadata: Record, store: AppStore) => Promise; + }; + + it.each(enhancerCases)('$handler parses when the current base is Krea-2', async ({ handler, field, value }) => { + currentBase = 'krea-2'; + const store = makeStore(); + + const parsed = await getHandler(handler).parse({ [field]: value }, store); + + expect(parsed).toBe(value); + }); + + it.each(enhancerCases)( + '$handler rejects (does not clobber) when the current base is not Krea-2', + async ({ handler, field, value }) => { + currentBase = 'sdxl'; + const store = makeStore(); + + await expect( + Promise.resolve().then(() => getHandler(handler).parse({ [field]: value }, store)) + ).rejects.toThrow(); + } + ); + }); +}); diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index 314a384a422..18ff5aa80df 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -1067,9 +1067,12 @@ const VAEModel: SingleMetadataHandler = { const parsed = await parseModelIdentifier(raw, store, 'vae'); assert(parsed.type === 'vae'); assert(isCompatibleWithMainModel(parsed, store)); - // Z-Image and FLUX.2 Klein have dedicated VAE handlers; avoid rendering a duplicate row. + // Z-Image, FLUX.2 Klein and Krea-2 have dedicated VAE handlers; avoid rendering a duplicate row. const base = selectBase(store.getState()); - assert(base !== 'z-image' && base !== 'flux2', 'VAEModel handler does not apply to Z-Image or FLUX.2 Klein'); + assert( + base !== 'z-image' && base !== 'flux2' && base !== 'krea-2', + 'VAEModel handler does not apply to Z-Image, FLUX.2 Klein or Krea-2' + ); return Promise.resolve(parsed); }, recall: (value, store) => { @@ -1210,14 +1213,13 @@ const Krea2Qwen3VlEncoderModel: SingleMetadataHandler = { const Krea2SeedVarianceEnabled: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceEnabled', - parse: (metadata, _store) => { - try { - const raw = getProperty(metadata, 'krea2_seed_variance_enabled'); - return Promise.resolve(z.boolean().parse(raw)); - } catch { - // Default to false when metadata doesn't contain this field (e.g. older images). - return Promise.resolve(false); - } + parse: (metadata, store) => { + // Only applies to Krea-2 models, and only when the field is actually present — otherwise recalling + // an unrelated/older image would silently clear the user's current enhancer state. (A synchronous + // throw here is turned into a rejected promise by the parse runner, skipping the handler.) + assert(selectBase(store.getState()) === 'krea-2', 'Krea2SeedVarianceEnabled handler only applies to Krea-2 models'); + const raw = getProperty(metadata, 'krea2_seed_variance_enabled'); + return Promise.resolve(z.boolean().parse(raw)); }, recall: (value, store) => { store.dispatch(setKrea2SeedVarianceEnabled(value)); @@ -1232,7 +1234,11 @@ const Krea2SeedVarianceEnabled: SingleMetadataHandler = { const Krea2SeedVarianceStrength: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceStrength', - parse: (metadata, _store) => { + parse: (metadata, store) => { + assert( + selectBase(store.getState()) === 'krea-2', + 'Krea2SeedVarianceStrength handler only applies to Krea-2 models' + ); const raw = getProperty(metadata, 'krea2_seed_variance_strength'); return Promise.resolve(z.number().min(0).max(100).parse(raw)); }, @@ -1249,7 +1255,11 @@ const Krea2SeedVarianceStrength: SingleMetadataHandler = { const Krea2SeedVarianceRandomizePercent: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceRandomizePercent', - parse: (metadata, _store) => { + parse: (metadata, store) => { + assert( + selectBase(store.getState()) === 'krea-2', + 'Krea2SeedVarianceRandomizePercent handler only applies to Krea-2 models' + ); const raw = getProperty(metadata, 'krea2_seed_variance_randomize_percent'); return Promise.resolve(z.number().min(1).max(100).parse(raw)); }, @@ -1266,13 +1276,10 @@ const Krea2SeedVarianceRandomizePercent: SingleMetadataHandler = { const Krea2RebalanceEnabled: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceEnabled', - parse: (metadata, _store) => { - try { - const raw = getProperty(metadata, 'krea2_rebalance_enabled'); - return Promise.resolve(z.boolean().parse(raw)); - } catch { - return Promise.resolve(false); - } + parse: (metadata, store) => { + assert(selectBase(store.getState()) === 'krea-2', 'Krea2RebalanceEnabled handler only applies to Krea-2 models'); + const raw = getProperty(metadata, 'krea2_rebalance_enabled'); + return Promise.resolve(z.boolean().parse(raw)); }, recall: (value, store) => { store.dispatch(setKrea2RebalanceEnabled(value)); @@ -1287,7 +1294,8 @@ const Krea2RebalanceEnabled: SingleMetadataHandler = { const Krea2RebalanceMultiplier: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceMultiplier', - parse: (metadata, _store) => { + parse: (metadata, store) => { + assert(selectBase(store.getState()) === 'krea-2', 'Krea2RebalanceMultiplier handler only applies to Krea-2 models'); const raw = getProperty(metadata, 'krea2_rebalance_multiplier'); return Promise.resolve(z.number().min(0).max(20).parse(raw)); }, @@ -1304,7 +1312,8 @@ const Krea2RebalanceMultiplier: SingleMetadataHandler = { const Krea2RebalanceWeights: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceWeights', - parse: (metadata, _store) => { + parse: (metadata, store) => { + assert(selectBase(store.getState()) === 'krea-2', 'Krea2RebalanceWeights handler only applies to Krea-2 models'); const raw = getProperty(metadata, 'krea2_rebalance_weights'); return Promise.resolve(z.string().parse(raw)); }, diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts new file mode 100644 index 00000000000..cf5d235ba05 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts @@ -0,0 +1,279 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('app/logging/logger', () => ({ + logger: () => ({ + debug: vi.fn(), + }), +})); + +let nextId = 0; +vi.mock('features/controlLayers/konva/util', () => ({ + getPrefixedId: (prefix: string) => `${prefix}:${nextId++}`, +})); + +const baseModel = { + key: 'krea2-model', + hash: 'krea2-hash', + name: 'Krea-2 Turbo', + base: 'krea-2', + type: 'main', + format: 'diffusers', + variant: 'krea2_turbo', +}; + +let model: Record = { ...baseModel }; + +const defaultParams = { + cfgScale: 1 as number | number[], + steps: 8, + krea2VaeModel: null as unknown, + krea2Qwen3VlEncoderModel: null as unknown, + krea2RebalanceEnabled: false, + krea2RebalanceMultiplier: 4, + krea2RebalanceWeights: '1,1,1,1,1,1,1,2.5,5,1.1,4,1', + krea2SeedVarianceEnabled: false, + krea2SeedVarianceStrength: 20, + krea2SeedVarianceRandomizePercent: 50, +}; + +let params = { ...defaultParams }; + +vi.mock('features/controlLayers/store/paramsSlice', () => ({ + selectMainModelConfig: vi.fn(() => model), + selectParamsSlice: vi.fn(() => params), +})); + +vi.mock('features/controlLayers/store/selectors', () => ({ + selectCanvasMetadata: vi.fn(() => ({})), +})); + +vi.mock('features/metadata/util/modelFetchingHelpers', () => ({ + fetchModelConfigWithTypeGuard: vi.fn(() => Promise.resolve(model)), +})); + +vi.mock('features/nodes/util/graph/generation/addImageToImage', () => ({ + addImageToImage: vi.fn(), +})); + +vi.mock('features/nodes/util/graph/generation/addInpaint', () => ({ + addInpaint: vi.fn(), +})); + +vi.mock('features/nodes/util/graph/generation/addOutpaint', () => ({ + addOutpaint: vi.fn(), +})); + +vi.mock('features/nodes/util/graph/generation/addKrea2LoRAs', () => ({ + addKrea2LoRAs: vi.fn(), +})); + +vi.mock('features/nodes/util/graph/generation/addNSFWChecker', () => ({ + addNSFWChecker: vi.fn((_g, node) => node), +})); + +vi.mock('features/nodes/util/graph/generation/addWatermarker', () => ({ + addWatermarker: vi.fn((_g, node) => node), +})); + +vi.mock('features/nodes/util/graph/generation/addTextToImage', () => ({ + addTextToImage: vi.fn(({ l2i }) => l2i), +})); + +vi.mock('features/nodes/util/graph/graphBuilderUtils', () => ({ + selectCanvasOutputFields: vi.fn(() => ({})), + selectPresetModifiedPrompts: vi.fn(() => ({ + positive: 'a prompt', + negative: 'a negative prompt', + })), +})); + +vi.mock('features/ui/store/uiSelectors', () => ({ + selectActiveTab: vi.fn(() => 'generation'), +})); + +vi.mock('services/api/types', async () => { + const actual = await vi.importActual('services/api/types'); + return { + ...actual, + isNonRefinerMainModelConfig: vi.fn(() => true), + }; +}); + +import { buildKrea2Graph } from './buildKrea2Graph'; + +type BuiltGraph = Awaited>['g']; + +const buildTxt2Img = () => + buildKrea2Graph({ + generationMode: 'txt2img', + manager: null, + state: { + system: { shouldUseNSFWChecker: false, shouldUseWatermarker: false }, + } as never, + }); + +const nodeTypesOf = (g: BuiltGraph): string[] => Object.values(g.getGraph().nodes).map((n) => n.type); +const posConditioningEdge = (g: BuiltGraph) => + g.getGraph().edges.find((e) => e.destination.field === 'positive_conditioning'); + +describe('buildKrea2Graph', () => { + afterEach(() => { + nextId = 0; + params = { ...defaultParams }; + model = { ...baseModel }; + }); + + it('builds the core txt2img node chain', async () => { + const { g } = await buildTxt2Img(); + const types = nodeTypesOf(g); + expect(types).toContain('krea2_model_loader'); + expect(types).toContain('krea2_text_encoder'); + expect(types).toContain('krea2_denoise'); + // Krea-2 decodes with the Qwen-Image VAE node. + expect(types).toContain('qwen_image_l2i'); + }); + + describe('CFG gating (negative conditioning)', () => { + // Krea-2 only adds a negative prompt + negative_conditioning edge when CFG is enabled (cfg_scale > 1). + // The distilled Turbo checkpoint runs with CFG off (cfg_scale 1.0), so recording/encoding a negative + // prompt would be wasted work. + it('omits the negative prompt + edge when cfg_scale <= 1 (distilled Turbo default)', async () => { + params = { ...defaultParams, cfgScale: 1 }; + const { g } = await buildTxt2Img(); + const graph = g.getGraph(); + const hasNegPromptNode = Object.keys(graph.nodes).some((id) => id.startsWith('neg_prompt:')); + const hasNegEdge = graph.edges.some((e) => e.destination.field === 'negative_conditioning'); + expect(hasNegPromptNode).toBe(false); + expect(hasNegEdge).toBe(false); + }); + + it('includes the negative prompt + edge when cfg_scale > 1 (Raw / CFG on)', async () => { + params = { ...defaultParams, cfgScale: 4.5 }; + const { g } = await buildTxt2Img(); + const graph = g.getGraph(); + const hasNegPromptNode = Object.keys(graph.nodes).some((id) => id.startsWith('neg_prompt:')); + const hasNegEdge = graph.edges.some((e) => e.destination.field === 'negative_conditioning'); + expect(hasNegPromptNode).toBe(true); + expect(hasNegEdge).toBe(true); + }); + }); + + describe('conditioning enhancers', () => { + it('inserts no enhancer nodes by default; positive conditioning flows straight to denoise', async () => { + const { g } = await buildTxt2Img(); + const types = nodeTypesOf(g); + expect(types).not.toContain('krea2_conditioning_rebalance'); + expect(types).not.toContain('krea2_seed_variance'); + // The edge into denoise.positive_conditioning comes directly from the text encoder. + const edge = posConditioningEdge(g); + expect(edge).toBeDefined(); + expect(edge!.source.node_id.startsWith('pos_prompt:')).toBe(true); + }); + + it('inserts the rebalance node and reroutes positive conditioning through it when enabled', async () => { + params = { ...defaultParams, krea2RebalanceEnabled: true }; + const { g } = await buildTxt2Img(); + const types = nodeTypesOf(g); + expect(types).toContain('krea2_conditioning_rebalance'); + expect(types).not.toContain('krea2_seed_variance'); + const edge = posConditioningEdge(g); + expect(edge!.source.node_id.startsWith('krea2_rebalance:')).toBe(true); + }); + + it('inserts the seed-variance node when enabled with strength > 0', async () => { + params = { ...defaultParams, krea2SeedVarianceEnabled: true, krea2SeedVarianceStrength: 20 }; + const { g } = await buildTxt2Img(); + expect(nodeTypesOf(g)).toContain('krea2_seed_variance'); + const edge = posConditioningEdge(g); + expect(edge!.source.node_id.startsWith('krea2_seed_variance:')).toBe(true); + }); + + it('does not insert the seed-variance node when strength is 0 (a no-op)', async () => { + params = { ...defaultParams, krea2SeedVarianceEnabled: true, krea2SeedVarianceStrength: 0 }; + const { g } = await buildTxt2Img(); + expect(nodeTypesOf(g)).not.toContain('krea2_seed_variance'); + }); + + it('chains rebalance -> seed-variance -> denoise when both are enabled', async () => { + params = { + ...defaultParams, + krea2RebalanceEnabled: true, + krea2SeedVarianceEnabled: true, + krea2SeedVarianceStrength: 20, + }; + const { g } = await buildTxt2Img(); + const graph = g.getGraph(); + const types = nodeTypesOf(g); + expect(types).toContain('krea2_conditioning_rebalance'); + expect(types).toContain('krea2_seed_variance'); + // rebalance -> seed_variance + const rebalanceToSeed = graph.edges.find( + (e) => + e.source.node_id.startsWith('krea2_rebalance:') && e.destination.node_id.startsWith('krea2_seed_variance:') + ); + expect(rebalanceToSeed).toBeDefined(); + // seed_variance -> denoise.positive_conditioning + const edge = posConditioningEdge(g); + expect(edge!.source.node_id.startsWith('krea2_seed_variance:')).toBe(true); + }); + }); + + describe('standalone components for non-diffusers transformers', () => { + // A single-file / GGUF transformer has no bundled VAE or encoder, so both standalone submodels are + // required. A Diffusers pipeline bundles them, so it needs neither. + it('throws when a single-file/GGUF transformer has no VAE selected', async () => { + model = { ...baseModel, format: 'gguf_quantized' }; + params = { ...defaultParams, krea2VaeModel: null, krea2Qwen3VlEncoderModel: null }; + await expect(buildTxt2Img()).rejects.toThrow(/require a VAE/); + }); + + it('throws when a single-file/GGUF transformer has no Qwen3-VL encoder selected', async () => { + model = { ...baseModel, format: 'gguf_quantized' }; + params = { + ...defaultParams, + krea2VaeModel: { key: 'vae', hash: 'h', name: 'VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: null, + }; + await expect(buildTxt2Img()).rejects.toThrow(/require a Qwen3-VL encoder/); + }); + + it('passes the standalone submodels to the model loader when provided', async () => { + model = { ...baseModel, format: 'gguf_quantized' }; + params = { + ...defaultParams, + krea2VaeModel: { key: 'vae', hash: 'h', name: 'VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { key: 'enc', hash: 'h', name: 'Enc', base: 'any', type: 'qwen3_vl_encoder' }, + }; + const { g } = await buildTxt2Img(); + const loader = Object.values(g.getGraph().nodes).find((n) => n.type === 'krea2_model_loader') as + | { vae_model?: { key: string }; qwen3_vl_encoder_model?: { key: string } } + | undefined; + expect(loader?.vae_model).toMatchObject({ key: 'vae' }); + expect(loader?.qwen3_vl_encoder_model).toMatchObject({ key: 'enc' }); + }); + }); + + describe('metadata', () => { + it('records the conditioning-enhancer settings and generation mode', async () => { + params = { + ...defaultParams, + krea2RebalanceEnabled: true, + krea2RebalanceMultiplier: 4, + krea2SeedVarianceEnabled: false, + }; + const { g } = await buildTxt2Img(); + const metadata = g.getMetadataNode() as unknown as Record; + expect(metadata.krea2_rebalance_enabled).toBe(true); + expect(metadata.krea2_rebalance_multiplier).toBe(4); + expect(metadata.krea2_seed_variance_enabled).toBe(false); + expect(metadata.generation_mode).toBe('krea2_txt2img'); + }); + + it('does not record a negative prompt for the CFG-off (Turbo) default', async () => { + params = { ...defaultParams, cfgScale: 1 }; + const { g } = await buildTxt2Img(); + const metadata = g.getMetadataNode() as unknown as Record; + expect(metadata.negative_prompt).toBeUndefined(); + }); + }); +}); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx index 6622feb5e51..b527cdc4711 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx @@ -23,7 +23,7 @@ const ParamKrea2RebalanceWeights = () => { {t('parameters.krea2RebalanceWeights')} - + ); }; diff --git a/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts b/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts index 60ca6cb5424..4723a546b70 100644 --- a/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts +++ b/invokeai/frontend/web/src/services/api/hooks/modelsByType.ts @@ -157,5 +157,6 @@ export const selectZImageDiffusersModels = buildModelsSelector(isZImageDiffusers export const selectFlux2DiffusersModels = buildModelsSelector(isFlux2DiffusersMainModelConfig); export const selectFluxVAEModels = buildModelsSelector(isFluxVAEModelConfig); export const selectAnimaVAEModels = buildModelsSelector(isAnimaVAEModelConfig); +export const selectQwen3VLEncoderModels = buildModelsSelector(isQwen3VLEncoderModelConfig); export const useTextLLMModels = () => buildModelsHook(isTextLLMModelConfig)(); export const useLlavaModels = () => buildModelsHook(isLLaVAModelConfig)(); diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py index 03c854b1b20..d579dca620a 100644 --- a/tests/app/invocations/test_krea2_denoise.py +++ b/tests/app/invocations/test_krea2_denoise.py @@ -1,7 +1,8 @@ import pytest +import torch from invokeai.app.invocations.fields import DenoiseMaskField -from invokeai.app.invocations.krea2_denoise import Krea2DenoiseInvocation +from invokeai.app.invocations.krea2_denoise import KREA2_LATENT_CHANNELS, Krea2DenoiseInvocation @pytest.mark.parametrize(("denoising_start", "denoising_end"), [(0.75, 0.25), (0.5, 0.5)]) @@ -26,3 +27,66 @@ def test_validate_inputs_rejects_denoise_mask_without_latents() -> None: with pytest.raises(ValueError, match="Initial latents are required when a denoise mask is provided"): invocation._validate_inputs() + + +def test_validate_inputs_accepts_a_valid_configuration() -> None: + invocation = Krea2DenoiseInvocation.model_construct( + denoising_start=0.0, denoising_end=1.0, denoise_mask=None, latents=None + ) + # A full-range denoise with no mask is valid and must not raise. + invocation._validate_inputs() + + +class TestPrepareCfgScale: + def test_scalar_is_broadcast_to_the_step_count(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct(cfg_scale=4.5) + assert invocation._prepare_cfg_scale(8) == [4.5] * 8 + + def test_list_of_matching_length_is_returned_unchanged(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct(cfg_scale=[4.0, 3.0, 2.0]) + assert invocation._prepare_cfg_scale(3) == [4.0, 3.0, 2.0] + + def test_list_of_wrong_length_raises(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct(cfg_scale=[4.0, 3.0, 2.0]) + with pytest.raises(ValueError, match="cfg_scale list has 3 values but the model is configured for 8 steps"): + invocation._prepare_cfg_scale(8) + + def test_invalid_type_raises(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct(cfg_scale="nonsense") + with pytest.raises(ValueError, match="Invalid CFG scale type"): + invocation._prepare_cfg_scale(8) + + +def test_cfg_scale_list_is_built_against_full_step_count_then_clipped() -> None: + # Regression: a per-step CFG list carries one value per *configured* step. img2img/inpaint clips the + # sampling schedule (denoising_start/denoising_end), which shrinks the number of active steps. The list + # must be prepared against the full step count (``total_sigmas``) and *then* sliced to the active + # window — preparing it against the already-reduced count would reject the user's full-length list. + steps = 8 + invocation = Krea2DenoiseInvocation.model_construct(cfg_scale=[float(i) for i in range(steps)]) + + full_cfg_scale = invocation._prepare_cfg_scale(steps) # built against the FULL step count -> ok + assert len(full_cfg_scale) == steps + + # Slicing to the active window [start_idx:end_idx] (as _run_diffusion does) keeps the right per-step values. + start_idx, end_idx = 2, 6 + assert full_cfg_scale[start_idx:end_idx] == [2.0, 3.0, 4.0, 5.0] + + # Preparing against the reduced (clipped) count instead would have raised — the bug this guards against. + with pytest.raises(ValueError): + invocation._prepare_cfg_scale(end_idx - start_idx) + + +def test_get_noise_is_deterministic_and_correctly_shaped() -> None: + invocation = Krea2DenoiseInvocation.model_construct() + device = torch.device("cpu") + + noise_a = invocation._get_noise(height=64, width=128, dtype=torch.float32, device=device, seed=42) + noise_b = invocation._get_noise(height=64, width=128, dtype=torch.float32, device=device, seed=42) + noise_other = invocation._get_noise(height=64, width=128, dtype=torch.float32, device=device, seed=43) + + # Shape is (1, latent_channels, H // 8, W // 8). + assert noise_a.shape == (1, KREA2_LATENT_CHANNELS, 8, 16) + # Same seed -> identical noise (reproducibility); different seed -> different noise. + assert torch.equal(noise_a, noise_b) + assert not torch.equal(noise_a, noise_other) diff --git a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py new file mode 100644 index 00000000000..bad851c1fef --- /dev/null +++ b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py @@ -0,0 +1,210 @@ +"""Unit tests for the Krea-2 loader state-dict helpers. + +These cover the pure key/tensor transforms that the single-file, GGUF and Qwen3-VL encoder loaders +run before ``load_state_dict`` (prefix stripping, native<->diffusers key conversion, scaled-fp8 +dequantization, encoder key remapping) plus the shared ``_reject_incomplete_load`` guard that turns a +silent partial load into an actionable error. They exercise the conversion logic without needing the +real (diffusers ``Krea2Transformer2DModel`` / transformers ``Qwen3VLModel``) architectures or weights. +""" + +import re + +import accelerate +import pytest +import torch + +from invokeai.backend.model_manager.load.model_loaders.krea2 import ( + _convert_krea2_native_to_diffusers, + _dequantize_scaled_fp8, + _is_native_krea2_format, + _reject_incomplete_load, + _remap_qwen3vl_singlefile_keys, + _strip_comfyui_prefix, +) + + +class TestStripComfyuiPrefix: + @pytest.mark.parametrize("prefix", ["model.diffusion_model.", "diffusion_model."]) + def test_strips_known_prefixes(self, prefix: str) -> None: + sd = {f"{prefix}blocks.0.weight": torch.zeros(1), f"{prefix}first.weight": torch.zeros(1)} + out = _strip_comfyui_prefix(sd) + assert set(out.keys()) == {"blocks.0.weight", "first.weight"} + + def test_noop_when_no_prefix(self) -> None: + sd = {"blocks.0.weight": torch.zeros(1), "img_in.weight": torch.zeros(1)} + out = _strip_comfyui_prefix(sd) + assert set(out.keys()) == set(sd.keys()) + + def test_only_the_first_matching_prefix_is_used(self) -> None: + # "model.diffusion_model." is checked before "diffusion_model.", so both strip to the same tail. + sd = {"model.diffusion_model.blocks.0.weight": torch.zeros(1)} + out = _strip_comfyui_prefix(sd) + assert list(out.keys()) == ["blocks.0.weight"] + + +class TestIsNativeKrea2Format: + @pytest.mark.parametrize( + "key", + ["blocks.0.attn.wq.weight", "txtfusion.0.mlp.up.weight", "first.weight", "blocks.0.mod.lin"], + ) + def test_true_for_native_keys(self, key: str) -> None: + assert _is_native_krea2_format({key: torch.zeros(1)}) is True + + @pytest.mark.parametrize( + "key", + ["transformer_blocks.0.attn.to_q.weight", "img_in.weight", "text_fusion.0.ff.up.weight"], + ) + def test_false_for_diffusers_keys(self, key: str) -> None: + assert _is_native_krea2_format({key: torch.zeros(1)}) is False + + +class TestDequantizeScaledFp8: + def test_folds_scale_into_weight_and_drops_scale_key(self) -> None: + sd = { + "layer.weight": torch.tensor([2.0, 4.0]), + "layer.weight_scale": torch.tensor(0.5), + } + out = _dequantize_scaled_fp8(sd) + assert "layer.weight_scale" not in out + assert torch.allclose(out["layer.weight"], torch.tensor([1.0, 2.0])) + + def test_noop_without_scale_keys(self) -> None: + sd = {"layer.weight": torch.tensor([2.0, 4.0])} + out = _dequantize_scaled_fp8(sd) + assert out is sd + + def test_orphan_scale_key_is_dropped(self) -> None: + # A scale key with no matching weight is simply removed (nothing to multiply). + sd = {"other.weight": torch.tensor([1.0]), "layer.weight_scale": torch.tensor(0.5)} + out = _dequantize_scaled_fp8(sd) + assert "layer.weight_scale" not in out + assert "other.weight" in out + + +class TestConvertKrea2NativeToDiffusers: + def test_top_level_module_renames(self) -> None: + sd = { + "first.weight": torch.zeros(1), + "tmlp.0.weight": torch.zeros(1), + "tmlp.2.weight": torch.zeros(1), + "tproj.1.weight": torch.zeros(1), + "txtmlp.0.scale": torch.zeros(1), + "txtmlp.1.weight": torch.zeros(1), + "txtmlp.3.weight": torch.zeros(1), + "last.linear.weight": torch.zeros(1), + "last.norm.scale": torch.zeros(1), + } + out = _convert_krea2_native_to_diffusers(sd) + assert "img_in.weight" in out + assert "time_embed.linear_1.weight" in out + assert "time_embed.linear_2.weight" in out + assert "time_mod_proj.weight" in out + assert "txt_in.norm.weight" in out + assert "txt_in.linear_1.weight" in out + assert "txt_in.linear_2.weight" in out + assert "final_layer.linear.weight" in out + assert "final_layer.norm.weight" in out + + def test_within_block_renames(self) -> None: + sd = { + "blocks.0.attn.wq.weight": torch.zeros(1), + "blocks.0.attn.wk.weight": torch.zeros(1), + "blocks.0.attn.wv.weight": torch.zeros(1), + "blocks.0.attn.wo.weight": torch.zeros(1), + "blocks.0.attn.gate.weight": torch.zeros(1), + "blocks.0.attn.qknorm.qnorm.scale": torch.zeros(1), + "blocks.0.attn.qknorm.knorm.scale": torch.zeros(1), + "blocks.0.mlp.gate.weight": torch.zeros(1), + "blocks.0.mlp.up.weight": torch.zeros(1), + "blocks.0.mlp.down.weight": torch.zeros(1), + "blocks.0.prenorm.scale": torch.zeros(1), + "blocks.0.postnorm.scale": torch.zeros(1), + "txtfusion.1.attn.wq.weight": torch.zeros(1), + } + out = _convert_krea2_native_to_diffusers(sd) + assert "transformer_blocks.0.attn.to_q.weight" in out + assert "transformer_blocks.0.attn.to_k.weight" in out + assert "transformer_blocks.0.attn.to_v.weight" in out + assert "transformer_blocks.0.attn.to_out.0.weight" in out + assert "transformer_blocks.0.attn.to_gate.weight" in out + assert "transformer_blocks.0.attn.norm_q.weight" in out + assert "transformer_blocks.0.attn.norm_k.weight" in out + assert "transformer_blocks.0.ff.gate.weight" in out + assert "transformer_blocks.0.ff.up.weight" in out + assert "transformer_blocks.0.ff.down.weight" in out + assert "transformer_blocks.0.norm1.weight" in out + assert "transformer_blocks.0.norm2.weight" in out + # text_fusion tower renamed the same way. + assert "text_fusion.1.attn.to_q.weight" in out + # No native names survive. + assert not any(".wq." in k or ".qknorm." in k or ".mlp." in k or "prenorm" in k for k in out) + + def test_final_block_projections_are_dropped(self) -> None: + sd = {"last.down.weight": torch.zeros(2, 2), "last.up.weight": torch.zeros(2, 2)} + out = _convert_krea2_native_to_diffusers(sd) + assert out == {} + + def test_mod_lin_is_reshaped_to_scale_shift_table(self) -> None: + # A flat (6*H,) per-block modulation vector becomes a (6, H) scale_shift_table. + sd = {"blocks.0.mod.lin": torch.arange(12, dtype=torch.float32)} + out = _convert_krea2_native_to_diffusers(sd) + assert "transformer_blocks.0.scale_shift_table" in out + table = out["transformer_blocks.0.scale_shift_table"] + assert table.shape == (6, 2) + assert torch.equal(table, torch.arange(12, dtype=torch.float32).reshape(6, 2)) + + def test_non_string_keys_pass_through(self) -> None: + sentinel = object() + out = _convert_krea2_native_to_diffusers({sentinel: torch.zeros(1)}) # type: ignore[dict-item] + assert sentinel in out + + +class TestRemapQwen3vlSinglefileKeys: + def test_routes_towers_and_prefixes_bare_language_model_keys(self) -> None: + sd = { + "model.visual.blocks.0.weight": torch.zeros(1), + "model.language_model.layers.0.weight": torch.zeros(1), + "model.layers.1.weight": torch.zeros(1), # bare LM key under a model. prefix + "model.embed_tokens.weight": torch.zeros(1), + "model.norm.weight": torch.zeros(1), + "visual.blocks.1.weight": torch.zeros(1), # already un-prefixed + "layers.2.weight": torch.zeros(1), # bare, no model. prefix + } + out = _remap_qwen3vl_singlefile_keys(sd) + assert "visual.blocks.0.weight" in out + assert "language_model.layers.0.weight" in out + assert "language_model.layers.1.weight" in out + assert "language_model.embed_tokens.weight" in out + assert "language_model.norm.weight" in out + assert "visual.blocks.1.weight" in out + assert "language_model.layers.2.weight" in out + # No key retains the leading model. prefix. + assert not any(k.startswith("model.") for k in out) + + +class TestRejectIncompleteLoad: + @pytest.mark.parametrize( + "what", + ["Krea-2 single-file checkpoint", "Krea-2 GGUF checkpoint", "Qwen3-VL encoder checkpoint"], + ) + def test_raises_when_parameters_remain_on_meta_device(self, what: str) -> None: + # accelerate.init_empty_weights() leaves every parameter on the meta device — the exact state a + # strict=False load produces for a checkpoint that omits required weights. All three Krea-2 loaders + # feed their `what` label through this guard, so parametrize over the real call-site messages. + with accelerate.init_empty_weights(): + model = torch.nn.Linear(4, 4) + with pytest.raises(RuntimeError, match=re.escape(f"{what} is incomplete")): + _reject_incomplete_load(model, what=what) + + def test_does_not_raise_for_a_fully_materialized_model(self) -> None: + model = torch.nn.Linear(4, 4) # normal construction — no meta tensors + _reject_incomplete_load(model, what="Krea-2 single-file checkpoint") + + def test_names_the_missing_parameters(self) -> None: + # Materialize only the weight; the bias stays on meta and must be named in the error. + with accelerate.init_empty_weights(): + model = torch.nn.Linear(4, 4) + model.load_state_dict({"weight": torch.zeros(4, 4)}, strict=False, assign=True) + with pytest.raises(RuntimeError, match="bias") as exc_info: + _reject_incomplete_load(model, what="Krea-2 single-file checkpoint") + assert "1 parameter(s)" in str(exc_info.value) diff --git a/tests/backend/model_manager/test_starter_models.py b/tests/backend/model_manager/test_starter_models.py new file mode 100644 index 00000000000..cdcddd495ec --- /dev/null +++ b/tests/backend/model_manager/test_starter_models.py @@ -0,0 +1,80 @@ +"""Tests for the Krea-2 starter-model bundle and its GGUF dependency wiring. + +A single-file / GGUF Krea-2 transformer ships *only* the transformer, so it is unusable without a +standalone Qwen-Image VAE and Qwen3-VL text encoder. These tests assert that the Krea-2 launchpad +bundle exists, exposes both the diffusers and GGUF options, and that each GGUF entry declares the two +standalone dependencies so installing it also pulls the pieces needed to run it. +""" + +from invokeai.backend.model_manager.starter_models import ( + STARTER_BUNDLES, + STARTER_MODELS, + StarterModel, +) +from invokeai.backend.model_manager.taxonomy import ( + BaseModelType, + Krea2VariantType, + ModelFormat, + ModelType, +) + + +def _krea2_bundle_by_source() -> dict[str, StarterModel]: + bundle = STARTER_BUNDLES[BaseModelType.Krea2] + return {model.source: model for model in bundle.models} + + +def test_krea2_bundle_is_registered() -> None: + assert BaseModelType.Krea2 in STARTER_BUNDLES + assert STARTER_BUNDLES[BaseModelType.Krea2].name == "Krea-2" + + +def test_krea2_bundle_contains_diffusers_gguf_and_standalone_components() -> None: + by_source = _krea2_bundle_by_source() + # Diffusers pipelines (self-contained), GGUF transformers, and the standalone VAE + encoder that the + # GGUF transformers need. + assert "krea/Krea-2-Turbo" in by_source + assert "krea/Krea-2-Raw" in by_source + assert any(s.endswith("krea2_turbo-Q4_K_M.gguf") for s in by_source) + assert any(s.endswith("krea2_turbo-Q8_0.gguf") for s in by_source) + # Standalone components (also declared as GGUF dependencies). + assert any(m.type is ModelType.VAE for m in by_source.values()) + assert any(m.type is ModelType.Qwen3VLEncoder for m in by_source.values()) + + +def test_krea2_diffusers_variants() -> None: + by_source = _krea2_bundle_by_source() + # Turbo (distilled) vs Raw (undistilled Base) must be tagged so defaults/scheduling differ. + assert by_source["krea/Krea-2-Turbo"].variant is Krea2VariantType.Turbo + assert by_source["krea/Krea-2-Raw"].variant is Krea2VariantType.Base + + +def test_krea2_gguf_entries_declare_vae_and_encoder_dependencies() -> None: + gguf_models = [ + m + for m in _krea2_bundle_by_source().values() + if m.format is ModelFormat.GGUFQuantized and m.base is BaseModelType.Krea2 + ] + assert len(gguf_models) == 2 + + for model in gguf_models: + assert model.variant is Krea2VariantType.Turbo + assert model.dependencies is not None, f"{model.name} must declare its standalone dependencies" + dep_types = {dep.type for dep in model.dependencies} + # GGUF ships only the transformer -> it must pull a VAE and a Qwen3-VL encoder. + assert ModelType.VAE in dep_types, f"{model.name} is missing a VAE dependency" + assert ModelType.Qwen3VLEncoder in dep_types, f"{model.name} is missing a Qwen3-VL encoder dependency" + + +def test_krea2_bundle_models_are_registered_in_starter_models() -> None: + starter_sources = {m.source for m in STARTER_MODELS} + for model in STARTER_BUNDLES[BaseModelType.Krea2].models: + assert model.source in starter_sources, f"{model.name} is not registered in STARTER_MODELS" + + +def test_krea2_gguf_dependency_models_are_registered_in_starter_models() -> None: + # Every dependency source must itself be an installable starter model. + starter_sources = {m.source for m in STARTER_MODELS} + for model in STARTER_BUNDLES[BaseModelType.Krea2].models: + for dep in model.dependencies or []: + assert dep.source in starter_sources, f"dependency {dep.name} is not registered in STARTER_MODELS" From 892661a0626b3ff2afd1adee5129842c74aa3b89 Mon Sep 17 00:00:00 2001 From: JPPhoto Date: Mon, 13 Jul 2026 15:34:34 -0500 Subject: [PATCH 11/17] fix(ui): wire Krea metadata recall actions --- invokeai/frontend/web/public/locales/en.json | 1 + .../ImageMetadataActions.test.tsx | 15 +++++++++++ .../ImageMetadataActions.tsx | 8 ++++++ .../src/features/metadata/parsing.test.tsx | 27 ++++++++++++++++++- .../web/src/features/metadata/parsing.tsx | 19 +++++++++++-- .../ParamKrea2RebalanceWeights.test.ts | 17 ++++++++++++ .../ParamKrea2RebalanceWeights.tsx | 2 +- 7 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.test.ts diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c171408fc89..95aa80a5d10 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1756,6 +1756,7 @@ "krea2RebalanceEnabled": "Conditioning Rebalance", "krea2RebalanceMultiplier": "Rebalance Multiplier", "krea2RebalanceWeights": "Per-Layer Weights (12)", + "krea2RebalanceWeightsPlaceholder": "1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0", "imageActions": "Image Actions", "sendToCanvas": "Send To Canvas", "sendToUpscale": "Send To Upscale", diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx index a4f1427aef9..4645aa0c9eb 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.test.tsx @@ -9,4 +9,19 @@ describe('IMAGE_METADATA_ACTION_HANDLERS', () => { expect(IMAGE_METADATA_ACTION_HANDLERS).toContain(ImageMetadataHandlers.QwenImageQuantization); expect(IMAGE_METADATA_ACTION_HANDLERS).toContain(ImageMetadataHandlers.QwenImageShift); }); + + it('includes Krea-2 metadata handlers in the recall parameters UI', () => { + expect(IMAGE_METADATA_ACTION_HANDLERS).toEqual( + expect.arrayContaining([ + ImageMetadataHandlers.Krea2VAEModel, + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel, + ImageMetadataHandlers.Krea2SeedVarianceEnabled, + ImageMetadataHandlers.Krea2SeedVarianceStrength, + ImageMetadataHandlers.Krea2SeedVarianceRandomizePercent, + ImageMetadataHandlers.Krea2RebalanceEnabled, + ImageMetadataHandlers.Krea2RebalanceMultiplier, + ImageMetadataHandlers.Krea2RebalanceWeights, + ]) + ); + }); }); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx index f20ef705be3..85d66d2ba2f 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx @@ -65,6 +65,14 @@ export const IMAGE_METADATA_ACTION_HANDLERS: ImageMetadataActionHandler[] = [ ImageMetadataHandlers.RefImages, ImageMetadataHandlers.KleinVAEModel, ImageMetadataHandlers.KleinQwen3EncoderModel, + ImageMetadataHandlers.Krea2VAEModel, + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel, + ImageMetadataHandlers.Krea2SeedVarianceEnabled, + ImageMetadataHandlers.Krea2SeedVarianceStrength, + ImageMetadataHandlers.Krea2SeedVarianceRandomizePercent, + ImageMetadataHandlers.Krea2RebalanceEnabled, + ImageMetadataHandlers.Krea2RebalanceMultiplier, + ImageMetadataHandlers.Krea2RebalanceWeights, ImageMetadataHandlers.LoRAs, ]; diff --git a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx index bb295303273..bde794ace05 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx @@ -81,6 +81,31 @@ describe('ImageMetadataHandlers — Klein recall gating', () => { }); }); + describe('Krea-2 scalar handlers', () => { + it.each([ + [ImageMetadataHandlers.Krea2SeedVarianceEnabled, { krea2_seed_variance_enabled: true }], + [ImageMetadataHandlers.Krea2SeedVarianceStrength, { krea2_seed_variance_strength: 20 }], + [ImageMetadataHandlers.Krea2SeedVarianceRandomizePercent, { krea2_seed_variance_randomize_percent: 50 }], + [ImageMetadataHandlers.Krea2RebalanceEnabled, { krea2_rebalance_enabled: true }], + [ImageMetadataHandlers.Krea2RebalanceMultiplier, { krea2_rebalance_multiplier: 4 }], + [ImageMetadataHandlers.Krea2RebalanceWeights, { krea2_rebalance_weights: '1,1,1,1,1,1,1,1,1,1,1,1' }], + ])('rejects parsing %s for unrelated model bases', async (handler, metadata) => { + currentBase = 'krea-2'; + + await expect( + Promise.resolve().then(() => handler.parse({ ...metadata, model: { base: 'sdxl' } }, makeStore())) + ).rejects.toThrow(); + }); + + it('preserves the disabled default for older Krea-2 metadata', async () => { + currentBase = 'krea-2'; + + const metadata = { model: { base: 'krea-2' } }; + await expect(ImageMetadataHandlers.Krea2SeedVarianceEnabled.parse(metadata, makeStore())).resolves.toBe(false); + await expect(ImageMetadataHandlers.Krea2RebalanceEnabled.parse(metadata, makeStore())).resolves.toBe(false); + }); + }); + describe('KleinQwen3EncoderModel', () => { it('parses metadata.qwen3_encoder when the current main model is FLUX.2 Klein', async () => { currentBase = 'flux2'; @@ -108,7 +133,7 @@ describe('ImageMetadataHandlers — Klein recall gating', () => { // The generic VAEModel handler must NOT also fire for FLUX.2 / Z-Image // images, otherwise the metadata viewer renders duplicate VAE rows next // to the dedicated KleinVAEModel / ZImageVAEModel handlers. - it.each(['flux2', 'z-image'])('rejects parsing when current base is %s', async (base) => { + it.each(['flux2', 'z-image', 'krea-2'])('rejects parsing when current base is %s', async (base) => { currentBase = base; nextResolved = fakeModel('vae', base); const store = makeStore(); diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index 314a384a422..f7a93a20b8d 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -159,6 +159,12 @@ const getProperty = (obj: unknown, path: string): unknown => { return get(obj, path) as unknown; }; +const assertMetadataModelBase = (metadata: unknown, expectedBase: string, handlerType: string): void => { + const rawModel = getProperty(metadata, 'model'); + const modelBase = (rawModel as { base?: unknown } | undefined)?.base; + assert(modelBase === expectedBase, `${handlerType} handler only works with ${expectedBase} metadata`); +}; + type UnparsedData = { isParsed: false; isSuccess: false; @@ -1067,9 +1073,12 @@ const VAEModel: SingleMetadataHandler = { const parsed = await parseModelIdentifier(raw, store, 'vae'); assert(parsed.type === 'vae'); assert(isCompatibleWithMainModel(parsed, store)); - // Z-Image and FLUX.2 Klein have dedicated VAE handlers; avoid rendering a duplicate row. + // Z-Image, FLUX.2 Klein, and Krea-2 have dedicated VAE handlers; avoid rendering a duplicate row. const base = selectBase(store.getState()); - assert(base !== 'z-image' && base !== 'flux2', 'VAEModel handler does not apply to Z-Image or FLUX.2 Klein'); + assert( + base !== 'z-image' && base !== 'flux2' && base !== 'krea-2', + 'VAEModel handler does not apply to Z-Image, FLUX.2 Klein, or Krea-2' + ); return Promise.resolve(parsed); }, recall: (value, store) => { @@ -1211,6 +1220,7 @@ const Krea2SeedVarianceEnabled: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceEnabled', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2SeedVarianceEnabled'); try { const raw = getProperty(metadata, 'krea2_seed_variance_enabled'); return Promise.resolve(z.boolean().parse(raw)); @@ -1233,6 +1243,7 @@ const Krea2SeedVarianceStrength: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceStrength', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2SeedVarianceStrength'); const raw = getProperty(metadata, 'krea2_seed_variance_strength'); return Promise.resolve(z.number().min(0).max(100).parse(raw)); }, @@ -1250,6 +1261,7 @@ const Krea2SeedVarianceRandomizePercent: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2SeedVarianceRandomizePercent', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2SeedVarianceRandomizePercent'); const raw = getProperty(metadata, 'krea2_seed_variance_randomize_percent'); return Promise.resolve(z.number().min(1).max(100).parse(raw)); }, @@ -1267,6 +1279,7 @@ const Krea2RebalanceEnabled: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceEnabled', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2RebalanceEnabled'); try { const raw = getProperty(metadata, 'krea2_rebalance_enabled'); return Promise.resolve(z.boolean().parse(raw)); @@ -1288,6 +1301,7 @@ const Krea2RebalanceMultiplier: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceMultiplier', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2RebalanceMultiplier'); const raw = getProperty(metadata, 'krea2_rebalance_multiplier'); return Promise.resolve(z.number().min(0).max(20).parse(raw)); }, @@ -1305,6 +1319,7 @@ const Krea2RebalanceWeights: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2RebalanceWeights', parse: (metadata, _store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2RebalanceWeights'); const raw = getProperty(metadata, 'krea2_rebalance_weights'); return Promise.resolve(z.string().parse(raw)); }, diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.test.ts b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.test.ts new file mode 100644 index 00000000000..69529cbd9b0 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.test.ts @@ -0,0 +1,17 @@ +import { readFileSync } from 'node:fs'; + +import { describe, expect, it } from 'vitest'; + +const source = readFileSync(new URL('./ParamKrea2RebalanceWeights.tsx', import.meta.url), 'utf8'); +const english = JSON.parse(readFileSync(new URL('../../../../../public/locales/en.json', import.meta.url), 'utf8')) as { + parameters?: Record; +}; + +describe('ParamKrea2RebalanceWeights localisation', () => { + it('uses a translated placeholder with an English locale entry', () => { + expect(source).toContain("placeholder={t('parameters.krea2RebalanceWeightsPlaceholder')}"); + expect(english.parameters?.krea2RebalanceWeightsPlaceholder).toBe( + '1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0' + ); + }); +}); diff --git a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx index 6622feb5e51..b527cdc4711 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Krea2Enhancers/ParamKrea2RebalanceWeights.tsx @@ -23,7 +23,7 @@ const ParamKrea2RebalanceWeights = () => { {t('parameters.krea2RebalanceWeights')} - + ); }; From cf57b4dfdb6a5fc72ca45b1f953e18131bbded18 Mon Sep 17 00:00:00 2001 From: JPPhoto Date: Mon, 13 Jul 2026 16:47:22 -0500 Subject: [PATCH 12/17] fix(krea2): address adversarial review findings --- invokeai/app/invocations/krea2_denoise.py | 44 +++++---- invokeai/app/invocations/krea2_lora_loader.py | 57 ++++++----- .../backend/model_manager/configs/factory.py | 34 +++++-- .../backend/model_manager/configs/lora.py | 19 ++++ .../model_manager/configs/qwen3_vl_encoder.py | 16 +++ .../model_manager/load/model_loaders/krea2.py | 35 ++++--- .../krea2_lora_conversion_utils.py | 4 + .../listeners/modelSelected.test.ts | 47 ++++++++- .../listeners/modelSelected.ts | 27 ++--- tests/app/invocations/test_krea2_denoise.py | 26 +++++ .../app/invocations/test_krea2_lora_loader.py | 99 +++++++++++++++++++ .../configs/test_krea2_lora_config.py | 53 ++++++++++ .../configs/test_model_path_validation.py | 33 +++++++ .../configs/test_qwen3_vl_encoder_config.py | 51 +++++++++- .../load/test_krea2_state_dict_utils.py | 25 +++++ .../test_krea2_lora_conversion_utils.py | 50 ++++++++++ 16 files changed, 541 insertions(+), 79 deletions(-) create mode 100644 tests/app/invocations/test_krea2_lora_loader.py create mode 100644 tests/backend/model_manager/configs/test_krea2_lora_config.py create mode 100644 tests/backend/model_manager/configs/test_model_path_validation.py create mode 100644 tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index a3bcf105cc6..19202955746 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -147,6 +147,18 @@ def _prepare_cfg_scale(self, num_timesteps: int) -> list[float]: return self.cfg_scale raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}") + @staticmethod + def _should_apply_cfg_for_step(cfg_scale: float, *, has_negative_conditioning: bool) -> bool: + return has_negative_conditioning and cfg_scale > 1.0 + + @staticmethod + def _validate_effective_schedule(*, start_idx: int, end_idx: int) -> None: + if end_idx <= start_idx: + raise ValueError( + "The requested denoising range does not contain any effective denoising steps at the configured " + "step count. Increase denoising_end, decrease denoising_start, or increase steps." + ) + def _validate_inputs(self) -> None: if self.denoising_start >= self.denoising_end: raise ValueError("denoising_start must be less than denoising_end.") @@ -193,19 +205,6 @@ def _run_diffusion(self, context: InvocationContext): context, self.positive_conditioning.conditioning_name, inference_dtype, device ) - # CFG: standard formulation, enabled only when cfg_scale > 1 and negative conditioning is provided. - if isinstance(self.cfg_scale, list): - any_cfg_above_one = any(v > 1.0 for v in self.cfg_scale) - else: - any_cfg_above_one = self.cfg_scale > 1.0 - do_cfg = self.negative_conditioning is not None and any_cfg_above_one - neg_prompt_embeds = None - neg_prompt_mask = None - if do_cfg: - neg_prompt_embeds, neg_prompt_mask = self._load_text_conditioning( - context, self.negative_conditioning.conditioning_name, inference_dtype, device - ) - latent_height = self.height // LATENT_SCALE_FACTOR latent_width = self.width // LATENT_SCALE_FACTOR grid_height = latent_height // 2 @@ -244,6 +243,7 @@ def _run_diffusion(self, context: InvocationContext): is_clipped = self.denoising_start > 0 or self.denoising_end < 1 start_idx = int(round(self.denoising_start * total_sigmas)) end_idx = int(round(self.denoising_end * total_sigmas)) + self._validate_effective_schedule(start_idx=start_idx, end_idx=end_idx) if is_clipped: sigmas_sched = sigmas_sched[start_idx : end_idx + 1] timesteps_sched = sigmas_sched[:-1] * scheduler.config.num_train_timesteps @@ -258,6 +258,17 @@ def _run_diffusion(self, context: InvocationContext): full_cfg_scale = self._prepare_cfg_scale(total_sigmas) cfg_scale = full_cfg_scale[start_idx:end_idx] if is_clipped else full_cfg_scale + # Load negative conditioning only if at least one active step actually uses CFG. CFG is still + # decided per step below so values at or below 1.0 use the conditional prediction directly. + has_negative_conditioning = self.negative_conditioning is not None + do_cfg = has_negative_conditioning and any(value > 1.0 for value in cfg_scale) + neg_prompt_embeds = None + neg_prompt_mask = None + if do_cfg and self.negative_conditioning is not None: + neg_prompt_embeds, neg_prompt_mask = self._load_text_conditioning( + context, self.negative_conditioning.conditioning_name, inference_dtype, device + ) + # Load initial latents (img2img). init_latents = context.tensors.load(self.latents.latents_name) if self.latents else None if init_latents is not None: @@ -275,9 +286,6 @@ def _run_diffusion(self, context: InvocationContext): raise ValueError("denoising_start should be 0 when initial latents are not provided.") latents = noise - if total_steps <= 0: - return latents.unsqueeze(2) - # Pack latents into 2x2 patches: (B, C, H, W) -> (B, grid_h*grid_w, C*4). latents = pack_latents(latents, 1, KREA2_LATENT_CHANNELS, latent_height, latent_width) @@ -351,7 +359,9 @@ def _run_diffusion(self, context: InvocationContext): return_dict=False, )[0] - if do_cfg and neg_prompt_embeds is not None: + if self._should_apply_cfg_for_step( + cfg_scale[step_idx], has_negative_conditioning=neg_prompt_embeds is not None + ): noise_pred_uncond = transformer( hidden_states=latents, encoder_hidden_states=neg_prompt_embeds, diff --git a/invokeai/app/invocations/krea2_lora_loader.py b/invokeai/app/invocations/krea2_lora_loader.py index da3cb49eba0..42dc5cf2c9d 100644 --- a/invokeai/app/invocations/krea2_lora_loader.py +++ b/invokeai/app/invocations/krea2_lora_loader.py @@ -66,19 +66,29 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." ) - if self.transformer and any(lora.lora.key == lora_key for lora in self.transformer.loras): - raise ValueError(f'LoRA "{lora_key}" already applied to transformer.') - if self.qwen3_vl_encoder and any(lora.lora.key == lora_key for lora in self.qwen3_vl_encoder.loras): - raise ValueError(f'LoRA "{lora_key}" already applied to Qwen3-VL encoder.') - output = Krea2LoRALoaderOutput() if self.transformer is not None: output.transformer = self.transformer.model_copy(deep=True) - output.transformer.loras.append(LoRAField(lora=self.lora, weight=self.weight)) if self.qwen3_vl_encoder is not None: output.qwen3_vl_encoder = self.qwen3_vl_encoder.model_copy(deep=True) - output.qwen3_vl_encoder.loras.append(LoRAField(lora=self.lora, weight=self.weight)) + + transformer_lora = ( + next((item for item in output.transformer.loras if item.lora.key == lora_key), None) + if output.transformer is not None + else None + ) + encoder_lora = ( + next((item for item in output.qwen3_vl_encoder.loras if item.lora.key == lora_key), None) + if output.qwen3_vl_encoder is not None + else None + ) + effective_lora = transformer_lora or encoder_lora or LoRAField(lora=self.lora, weight=self.weight) + + if output.transformer is not None and transformer_lora is None: + output.transformer.loras.append(effective_lora.model_copy(deep=True)) + if output.qwen3_vl_encoder is not None and encoder_lora is None: + output.qwen3_vl_encoder.loras.append(effective_lora.model_copy(deep=True)) return output @@ -112,40 +122,39 @@ class Krea2LoRACollectionLoader(BaseInvocation): def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: output = Krea2LoRALoaderOutput() loras = self.loras if isinstance(self.loras, list) else [self.loras] - added_loras: list[str] = [] - if self.transformer is not None: output.transformer = self.transformer.model_copy(deep=True) if self.qwen3_vl_encoder is not None: output.qwen3_vl_encoder = self.qwen3_vl_encoder.model_copy(deep=True) - # Seed the dedup set with LoRAs already present on the incoming fields so chaining collection - # loaders can't apply the same LoRA twice (the transformer and encoder are kept in sync below). - if self.transformer is not None: - added_loras.extend(existing.lora.key for existing in self.transformer.loras) - if self.qwen3_vl_encoder is not None: - added_loras.extend( - existing.lora.key for existing in self.qwen3_vl_encoder.loras if existing.lora.key not in added_loras - ) - for lora in loras: if lora is None: continue - if lora.lora.key in added_loras: - continue if not context.models.exists(lora.lora.key): - raise Exception(f"Unknown lora: {lora.lora.key}!") + raise ValueError(f"Unknown lora: {lora.lora.key}!") if lora.lora.base is not BaseModelType.Krea2: raise ValueError( f"LoRA '{lora.lora.key}' is for {lora.lora.base.value if lora.lora.base else 'unknown'} models, " "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." ) - added_loras.append(lora.lora.key) + transformer_lora = ( + next((item for item in output.transformer.loras if item.lora.key == lora.lora.key), None) + if output.transformer is not None + else None + ) + encoder_lora = ( + next((item for item in output.qwen3_vl_encoder.loras if item.lora.key == lora.lora.key), None) + if output.qwen3_vl_encoder is not None + else None + ) + effective_lora = transformer_lora or encoder_lora or lora if self.transformer is not None and output.transformer is not None: - output.transformer.loras.append(lora) + if transformer_lora is None: + output.transformer.loras.append(effective_lora.model_copy(deep=True)) if self.qwen3_vl_encoder is not None and output.qwen3_vl_encoder is not None: - output.qwen3_vl_encoder.loras.append(lora) + if encoder_lora is None: + output.qwen3_vl_encoder.loras.append(effective_lora.model_copy(deep=True)) return output diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index c070f969e9a..92865dd4cfd 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -1,3 +1,4 @@ +import json import logging from dataclasses import dataclass from pathlib import Path @@ -421,12 +422,33 @@ def _validate_path_looks_like_model(path: Path) -> None: f"Expected one of: {', '.join(sorted(_MODEL_EXTENSIONS))}" ) else: - # A config file at the root (model_index.json / config.json) is an unambiguous - # diffusers/transformers model marker, so accept the directory regardless of file - # count. HF snapshots often bundle extra non-model assets (e.g. a model-card `images/` - # folder) that would otherwise trip the general-purpose-directory guard below. - has_root_config = any((path / config).exists() for config in _CONFIG_FILES) - if has_root_config: + # Recognized Diffusers/Transformers configs are safe model markers. A generic config.json + # is not sufficient because many large application directories contain one. + recognized_root_config = False + for config_name in _CONFIG_FILES: + config_path = path / config_name + if not config_path.exists(): + continue + try: + config = json.loads(config_path.read_text()) + except (OSError, ValueError): + continue + if config_name == "model_index.json": + recognized_root_config = isinstance(config.get("_class_name"), str) + else: + architectures = config.get("architectures") + recognized_root_config = ( + isinstance(config.get("_class_name"), str) + or isinstance(config.get("model_type"), str) + or ( + isinstance(architectures, list) + and bool(architectures) + and isinstance(architectures[0], str) + ) + ) + if recognized_root_config: + break + if recognized_root_config: return # For directories, do a quick file count check with early exit diff --git a/invokeai/backend/model_manager/configs/lora.py b/invokeai/backend/model_manager/configs/lora.py index abc0a428784..c8f3f81fd55 100644 --- a/invokeai/backend/model_manager/configs/lora.py +++ b/invokeai/backend/model_manager/configs/lora.py @@ -911,6 +911,25 @@ class LoRA_LyCORIS_Krea2_Config(LoRA_LyCORIS_Config_Base, Config_Base): base: Literal[BaseModelType.Krea2] = Field(default=BaseModelType.Krea2) + @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) + + state_dict = mod.load_state_dict() + explicit_krea2_override = override_fields.get("base") is BaseModelType.Krea2 + has_transformer_blocks = state_dict_has_any_keys_starting_with( + state_dict, {"transformer.transformer_blocks.", "transformer_blocks."} + ) + has_lora_down = state_dict_has_any_keys_ending_with(state_dict, {"lora_A.weight", "lora_down.weight"}) + has_lora_up = state_dict_has_any_keys_ending_with(state_dict, {"lora_B.weight", "lora_up.weight"}) + if explicit_krea2_override and has_transformer_blocks and has_lora_down and has_lora_up: + return cls(**override_fields) + + cls._validate_looks_like_lora(mod) + cls._validate_base(mod) + return cls(**override_fields) + @classmethod def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None: """Krea-2 LoRAs have keys like transformer.text_fusion.* / transformer.transformer_blocks.* with diff --git a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py index 7677e57fb32..fc77cec927a 100644 --- a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py +++ b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py @@ -63,6 +63,22 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - }, ) + if config_path_nested.exists(): + weights_path = mod.path / "text_encoder" + tokenizer_path = mod.path / "tokenizer" + else: + weights_path = mod.path + tokenizer_path = mod.path + + has_weights = any(weights_path.glob("*.safetensors")) or any(weights_path.glob("*.bin")) + has_tokenizer = (tokenizer_path / "tokenizer.json").exists() or ( + (tokenizer_path / "vocab.json").exists() and (tokenizer_path / "merges.txt").exists() + ) + if not has_weights: + raise NotAMatchError("standalone Qwen3-VL encoder directory does not contain model weights") + if not has_tokenizer: + raise NotAMatchError("standalone Qwen3-VL encoder directory does not contain tokenizer files") + return cls(**override_fields) diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py index 4114254eaab..557c1db133f 100644 --- a/invokeai/backend/model_manager/load/model_loaders/krea2.py +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -5,7 +5,7 @@ from typing import Any, Optional import accelerate -from transformers import AutoTokenizer +from transformers import AutoConfig, AutoTokenizer from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Diffusers_Config_Base from invokeai.backend.model_manager.configs.factory import AnyModelConfig @@ -28,6 +28,16 @@ from invokeai.backend.util.devices import TorchDevice +def _normalize_qwen3vl_rope_config(config: Any) -> Any: + """Mirror Qwen3-VL rope_parameters into rope_scaling for Transformers compatibility.""" + text_config = getattr(config, "text_config", None) + if text_config is not None: + rope_params = getattr(text_config, "rope_parameters", None) + if getattr(text_config, "rope_scaling", None) is None and rope_params is not None: + text_config.rope_scaling = rope_params + return config + + def _strip_comfyui_prefix(sd: dict[str, Any]) -> dict[str, Any]: """Strip ComfyUI-style ``model.diffusion_model.`` / ``diffusion_model.`` key prefixes if present.""" prefix_to_strip = None @@ -241,14 +251,7 @@ def _load_model( # Krea-2's Qwen3-VL text_encoder config stores rope settings under `rope_parameters`, but the # installed transformers' Qwen3VL rotary embedding reads `rope_scaling` (None here) → crash. # Patch the config so rope_scaling mirrors rope_parameters before instantiating the model. - from transformers import AutoConfig - - te_config = AutoConfig.from_pretrained(model_path, local_files_only=True) - text_config = getattr(te_config, "text_config", None) - if text_config is not None: - rope_params = getattr(text_config, "rope_parameters", None) - if getattr(text_config, "rope_scaling", None) is None and rope_params is not None: - text_config.rope_scaling = rope_params + te_config = _normalize_qwen3vl_rope_config(AutoConfig.from_pretrained(model_path, local_files_only=True)) extra_kwargs["config"] = te_config try: @@ -409,8 +412,12 @@ def _load_model( case SubModelType.TextEncoder: target_device = TorchDevice.choose_torch_device() model_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device) + te_config = _normalize_qwen3vl_rope_config( + AutoConfig.from_pretrained(text_encoder_path, local_files_only=True) + ) return Qwen3VLModel.from_pretrained( text_encoder_path, + config=te_config, torch_dtype=model_dtype, low_cpu_mem_usage=True, local_files_only=True, @@ -500,19 +507,11 @@ def _load_tokenizer(self) -> AnyModel: return AutoTokenizer.from_pretrained(self.DEFAULT_HF_REPO, extra_special_tokens={}) def _load_hf_config(self) -> Any: - from transformers import AutoConfig - try: te_config = AutoConfig.from_pretrained(self.DEFAULT_HF_REPO, local_files_only=True) except Exception: te_config = AutoConfig.from_pretrained(self.DEFAULT_HF_REPO) - # transformers' Qwen3-VL rotary embedding reads `rope_scaling`; the config stores `rope_parameters`. - text_config = getattr(te_config, "text_config", None) - if text_config is not None: - rope_params = getattr(text_config, "rope_parameters", None) - if getattr(text_config, "rope_scaling", None) is None and rope_params is not None: - text_config.rope_scaling = rope_params - return te_config + return _normalize_qwen3vl_rope_config(te_config) def _load_text_encoder(self, config: Qwen3VLEncoder_Checkpoint_Config) -> AnyModel: import torch diff --git a/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py index f77fc7ca5ea..04b8de2deb5 100644 --- a/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py +++ b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py @@ -89,6 +89,10 @@ def _get_lora_layer_values(layer_dict: dict[str, torch.Tensor], alpha: float | N "lora_down.weight": layer_dict["lora_A.weight"], "lora_up.weight": layer_dict["lora_B.weight"], } + if "dora_scale" in layer_dict: + values["dora_scale"] = layer_dict["dora_scale"] + if "alpha" in layer_dict: + values["alpha"] = layer_dict["alpha"] if alpha is not None: values["alpha"] = torch.tensor(alpha) return values diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts index 5786c232f8a..78b802edf95 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts @@ -116,9 +116,15 @@ vi.mock('services/api/hooks/modelsByType', () => ({ // model's format (diffusers vs. single-file/GGUF), which drives clear-vs-auto-select. const mockSelectModelConfigsQuery = vi.fn((_state: unknown) => ({ data: undefined }) as { data: unknown }); const mockSelectModelById = vi.fn((_data: unknown, _key: string) => undefined as unknown); +const mockSelectIndividualModelConfig = vi.fn((_state: unknown) => ({ data: undefined }) as { data: unknown }); vi.mock('services/api/endpoints/models', () => ({ modelConfigsAdapterSelectors: { selectById: (data: unknown, key: string) => mockSelectModelById(data, key) }, + modelsApi: { + endpoints: { + getModelConfig: { select: (_key: string) => (state: unknown) => mockSelectIndividualModelConfig(state) }, + }, + }, selectModelConfigsQuery: (state: unknown) => mockSelectModelConfigsQuery(state), })); @@ -364,8 +370,9 @@ describe('modelSelected listener - Krea-2 defaulting', () => { mockSelectQwenImageVAEModels.mockReturnValue([mockKrea2Vae]); mockSelectAnimaVAEModels.mockReturnValue([mockAnimaVAE]); mockSelectQwen3VLEncoderModels.mockReturnValue([mockKrea2Qwen3VlEncoder]); - mockSelectModelConfigsQuery.mockReturnValue({ data: undefined }); - mockSelectModelById.mockReturnValue(undefined); + mockSelectModelConfigsQuery.mockReturnValue({ data: {} }); + mockSelectModelById.mockReturnValue({ format: 'checkpoint' }); + mockSelectIndividualModelConfig.mockReturnValue({ data: undefined }); }); it('auto-selects a standalone VAE and Qwen3-VL encoder when switching to a single-file/GGUF Krea-2 model', () => { @@ -415,6 +422,42 @@ describe('modelSelected listener - Krea-2 defaulting', () => { expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)).toBeUndefined(); }); + it('defers standalone component changes while the selected model format is unknown', () => { + mockSelectModelConfigsQuery.mockReturnValue({ data: undefined }); + mockSelectModelById.mockReturnValue(undefined); + const state = buildMockState({ model: mockFluxMainModel }); + const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + expect(dispatched.find((a) => a.type === krea2VaeModelSelected.type)).toBeUndefined(); + expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)).toBeUndefined(); + }); + + it('uses the individual model-config cache when the list cache is unavailable', () => { + mockSelectModelConfigsQuery.mockReturnValue({ data: undefined }); + mockSelectModelById.mockReturnValue(undefined); + mockSelectIndividualModelConfig.mockReturnValue({ data: { format: 'diffusers' } }); + const state = buildMockState({ + model: mockKrea2MainModel, + krea2VaeModel: { key: 'stale-vae', hash: 'h', name: 'Stale VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { + key: 'stale-enc', + hash: 'h', + name: 'Stale Enc', + base: 'any', + type: 'qwen3_vl_encoder', + }, + }); + const nextKreaModel = { ...mockKrea2MainModel, key: 'next-krea-key' }; + const action = modelSelected(zParameterModel.parse(nextKreaModel)); + + capturedEffect!(action, { getState: () => state, dispatch: mockDispatch }); + + expect(dispatched.find((a) => a.type === krea2VaeModelSelected.type)?.payload).toBeNull(); + expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)?.payload).toBeNull(); + }); + it('does not overwrite standalone components the user already selected', () => { const state = buildMockState({ model: mockFluxMainModel, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 67a14c71eb6..38e96c5f6d7 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -52,7 +52,7 @@ import { modelSelected } from 'features/parameters/store/actions'; import { zParameterModel } from 'features/parameters/types/parameterSchemas'; import { toast } from 'features/toast/toast'; import { t } from 'i18next'; -import { modelConfigsAdapterSelectors, selectModelConfigsQuery } from 'services/api/endpoints/models'; +import { modelConfigsAdapterSelectors, modelsApi, selectModelConfigsQuery } from 'services/api/endpoints/models'; import { selectAnimaQwen3EncoderModels, selectAnimaVAEModels, @@ -324,12 +324,14 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = // GGUF transformer ships only the transformer, so auto-select standalone components if the user // hasn't already picked them - this unblocks the readiness check after installing the starter pack. const modelConfigsResult = selectModelConfigsQuery(state); - const newModelConfig = modelConfigsResult.data - ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) - : undefined; - const isDiffusers = newModelConfig?.format === 'diffusers'; - - if (isDiffusers) { + const newModelConfig = + (modelConfigsResult.data + ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) + : undefined) ?? modelsApi.endpoints.getModelConfig.select(newModel.key)(state).data; + if (!newModelConfig) { + // The model list may not be populated yet during startup or metadata recall. Defer component + // changes until the selected model's format is known instead of treating unknown as single-file. + } else if (newModelConfig.format === 'diffusers') { if (krea2VaeModel) { dispatch(krea2VaeModelSelected(null)); modelsUpdatedDisabledOrCleared += 1; @@ -578,10 +580,13 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = if (newBase === 'krea-2' && state.params.model?.base === 'krea-2' && newModel.key !== state.params.model?.key) { const { krea2VaeModel, krea2Qwen3VlEncoderModel } = state.params; const modelConfigsResult = selectModelConfigsQuery(state); - const newModelConfig = modelConfigsResult.data - ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) - : undefined; - if (newModelConfig?.format === 'diffusers') { + const newModelConfig = + (modelConfigsResult.data + ? modelConfigsAdapterSelectors.selectById(modelConfigsResult.data, newModel.key) + : undefined) ?? modelsApi.endpoints.getModelConfig.select(newModel.key)(state).data; + if (!newModelConfig) { + // Defer until the model format is known. + } else if (newModelConfig.format === 'diffusers') { if (krea2VaeModel) { dispatch(krea2VaeModelSelected(null)); } diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py index d579dca620a..d2f56577044 100644 --- a/tests/app/invocations/test_krea2_denoise.py +++ b/tests/app/invocations/test_krea2_denoise.py @@ -51,6 +51,32 @@ def test_list_of_wrong_length_raises(self) -> None: with pytest.raises(ValueError, match="cfg_scale list has 3 values but the model is configured for 8 steps"): invocation._prepare_cfg_scale(8) + +class TestCfgForStep: + def test_scale_above_one_uses_cfg_when_negative_conditioning_is_available(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct() + assert invocation._should_apply_cfg_for_step(4.0, has_negative_conditioning=True) is True + + @pytest.mark.parametrize("cfg_scale", [1.0, 0.5]) + def test_scale_at_or_below_one_does_not_use_cfg(self, cfg_scale: float) -> None: + invocation = Krea2DenoiseInvocation.model_construct() + assert invocation._should_apply_cfg_for_step(cfg_scale, has_negative_conditioning=True) is False + + def test_missing_negative_conditioning_does_not_use_cfg(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct() + assert invocation._should_apply_cfg_for_step(4.0, has_negative_conditioning=False) is False + + +class TestEffectiveScheduleValidation: + def test_rejects_a_fractional_range_that_rounds_to_zero_steps(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct() + with pytest.raises(ValueError, match="does not contain any effective denoising steps"): + invocation._validate_effective_schedule(start_idx=0, end_idx=0) + + def test_accepts_a_range_with_at_least_one_effective_step(self) -> None: + invocation = Krea2DenoiseInvocation.model_construct() + invocation._validate_effective_schedule(start_idx=0, end_idx=1) + def test_invalid_type_raises(self) -> None: invocation = Krea2DenoiseInvocation.model_construct(cfg_scale="nonsense") with pytest.raises(ValueError, match="Invalid CFG scale type"): diff --git a/tests/app/invocations/test_krea2_lora_loader.py b/tests/app/invocations/test_krea2_lora_loader.py new file mode 100644 index 00000000000..2c495f1a327 --- /dev/null +++ b/tests/app/invocations/test_krea2_lora_loader.py @@ -0,0 +1,99 @@ +from types import SimpleNamespace + +from invokeai.app.invocations.krea2_lora_loader import Krea2LoRACollectionLoader, Krea2LoRALoaderInvocation +from invokeai.app.invocations.model import LoRAField, ModelIdentifierField, Qwen3VLEncoderField, TransformerField +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType, SubModelType + + +def _model(key: str, model_type: ModelType, base: BaseModelType = BaseModelType.Krea2) -> ModelIdentifierField: + return ModelIdentifierField(key=key, hash=f"hash-{key}", name=key, base=base, type=model_type) + + +def _lora(key: str = "lora") -> LoRAField: + return LoRAField(lora=_model(key, ModelType.LoRA), weight=1.0) + + +def _transformer(loras: list[LoRAField]) -> TransformerField: + return TransformerField( + transformer=_model("main", ModelType.Main).model_copy(update={"submodel_type": SubModelType.Transformer}), + loras=loras, + ) + + +def _encoder(loras: list[LoRAField]) -> Qwen3VLEncoderField: + encoder = _model("encoder", ModelType.Qwen3VLEncoder, BaseModelType.Any) + return Qwen3VLEncoderField( + tokenizer=encoder.model_copy(update={"submodel_type": SubModelType.Tokenizer}), + text_encoder=encoder.model_copy(update={"submodel_type": SubModelType.TextEncoder}), + loras=loras, + ) + + +def _context() -> SimpleNamespace: + return SimpleNamespace(models=SimpleNamespace(exists=lambda _key: True)) + + +def test_collection_loader_repairs_transformer_only_lora_state() -> None: + lora = _lora() + existing = lora.model_copy(update={"weight": 0.25}) + invocation = Krea2LoRACollectionLoader.model_construct( + loras=[lora], transformer=_transformer([existing]), qwen3_vl_encoder=_encoder([]) + ) + + output = invocation.invoke(_context()) + + assert [item.lora.key for item in output.transformer.loras] == ["lora"] + assert [item.lora.key for item in output.qwen3_vl_encoder.loras] == ["lora"] + assert output.qwen3_vl_encoder.loras[0].weight == 0.25 + + +def test_collection_loader_repairs_encoder_only_lora_state() -> None: + lora = _lora() + invocation = Krea2LoRACollectionLoader.model_construct( + loras=[lora], transformer=_transformer([]), qwen3_vl_encoder=_encoder([lora]) + ) + + output = invocation.invoke(_context()) + + assert [item.lora.key for item in output.transformer.loras] == ["lora"] + assert [item.lora.key for item in output.qwen3_vl_encoder.loras] == ["lora"] + + +def test_collection_loader_does_not_duplicate_synchronized_lora_state() -> None: + lora = _lora() + invocation = Krea2LoRACollectionLoader.model_construct( + loras=[lora], transformer=_transformer([lora]), qwen3_vl_encoder=_encoder([lora]) + ) + + output = invocation.invoke(_context()) + + assert len(output.transformer.loras) == 1 + assert len(output.qwen3_vl_encoder.loras) == 1 + + +def test_single_loader_repairs_transformer_only_lora_state() -> None: + lora = _lora() + existing = lora.model_copy(update={"weight": 0.25}) + invocation = Krea2LoRALoaderInvocation.model_construct( + lora=lora.lora, weight=lora.weight, transformer=_transformer([existing]), qwen3_vl_encoder=_encoder([]) + ) + + output = invocation.invoke(_context()) + + assert len(output.transformer.loras) == 1 + assert [item.lora.key for item in output.qwen3_vl_encoder.loras] == ["lora"] + assert output.qwen3_vl_encoder.loras[0].weight == 0.25 + + +def test_single_loader_rejects_non_krea_lora() -> None: + lora = _model("flux-lora", ModelType.LoRA, BaseModelType.Flux) + invocation = Krea2LoRALoaderInvocation.model_construct( + lora=lora, weight=1.0, transformer=_transformer([]), qwen3_vl_encoder=_encoder([]) + ) + + try: + invocation.invoke(_context()) + except ValueError as error: + assert "not Krea-2 models" in str(error) + else: + raise AssertionError("Expected a non-Krea LoRA to be rejected") diff --git a/tests/backend/model_manager/configs/test_krea2_lora_config.py b/tests/backend/model_manager/configs/test_krea2_lora_config.py new file mode 100644 index 00000000000..488cb6a610a --- /dev/null +++ b/tests/backend/model_manager/configs/test_krea2_lora_config.py @@ -0,0 +1,53 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError +from invokeai.backend.model_manager.configs.lora import LoRA_LyCORIS_Krea2_Config +from invokeai.backend.model_manager.taxonomy import BaseModelType + +_REQUIRED_FIELDS = { + "hash": "blake3:fakehash", + "path": "/fake/models/krea2-lora.safetensors", + "file_size": 1000, + "name": "krea2-lora", + "description": "test", + "source": "test", + "source_type": "path", + "key": "test-key", +} + + +def _ambiguous_transformer_only_lora() -> MagicMock: + mod = MagicMock() + mod.load_state_dict.return_value = { + "transformer.transformer_blocks.0.attn.to_q.lora_A.weight": object(), + "transformer.transformer_blocks.0.attn.to_q.lora_B.weight": object(), + } + return mod + + +@patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") +def test_explicit_krea2_override_accepts_ambiguous_transformer_only_lora(_raise_if_not_file) -> None: + config = LoRA_LyCORIS_Krea2_Config.from_model_on_disk( + _ambiguous_transformer_only_lora(), {**_REQUIRED_FIELDS, "base": BaseModelType.Krea2} + ) + + assert config.base is BaseModelType.Krea2 + + +@patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") +def test_automatic_probe_rejects_ambiguous_transformer_only_lora(_raise_if_not_file) -> None: + with pytest.raises(NotAMatchError): + LoRA_LyCORIS_Krea2_Config.from_model_on_disk(_ambiguous_transformer_only_lora(), {**_REQUIRED_FIELDS}) + + +@patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") +def test_explicit_krea2_override_rejects_incomplete_lora_pair(_raise_if_not_file) -> None: + mod = MagicMock() + mod.load_state_dict.return_value = { + "transformer.transformer_blocks.0.attn.to_q.lora_A.weight": object(), + } + + with pytest.raises(NotAMatchError): + LoRA_LyCORIS_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS, "base": BaseModelType.Krea2}) diff --git a/tests/backend/model_manager/configs/test_model_path_validation.py b/tests/backend/model_manager/configs/test_model_path_validation.py new file mode 100644 index 00000000000..2c83cee6533 --- /dev/null +++ b/tests/backend/model_manager/configs/test_model_path_validation.py @@ -0,0 +1,33 @@ +import json +from pathlib import Path + +import pytest + +from invokeai.backend.model_manager.configs.factory import _MAX_FILES_IN_MODEL_DIR, ModelConfigFactory + + +def _fill_directory(path: Path) -> None: + for index in range(_MAX_FILES_IN_MODEL_DIR + 1): + (path / f"asset-{index}.txt").touch() + + +def test_large_directory_with_generic_config_is_rejected(tmp_path: Path) -> None: + (tmp_path / "config.json").write_text(json.dumps({"application": "not-a-model"})) + _fill_directory(tmp_path) + + with pytest.raises(ValueError, match="general-purpose directory"): + ModelConfigFactory._validate_path_looks_like_model(tmp_path) + + +def test_large_directory_with_transformers_config_is_accepted(tmp_path: Path) -> None: + (tmp_path / "config.json").write_text(json.dumps({"architectures": ["Qwen3VLModel"]})) + _fill_directory(tmp_path) + + ModelConfigFactory._validate_path_looks_like_model(tmp_path) + + +def test_large_directory_with_model_index_is_accepted(tmp_path: Path) -> None: + (tmp_path / "model_index.json").write_text(json.dumps({"_class_name": "Krea2Pipeline"})) + _fill_directory(tmp_path) + + ModelConfigFactory._validate_path_looks_like_model(tmp_path) diff --git a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py index 7bb8de30449..b908a16fb79 100644 --- a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py +++ b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py @@ -1,10 +1,12 @@ -"""Tests for single-file Qwen3-VL text-encoder identification (used by Krea-2). +"""Tests for Qwen3-VL text-encoder identification (used by Krea-2). A single-file Qwen3-VL encoder is distinguished from the text-only ``Qwen3Encoder`` (Z-Image / FLUX.2 Klein) by the presence of the Qwen3-VL **visual tower** (``visual.*`` / ``model.visual.*``). Both have a Qwen3 text decoder (``model.layers.*``), so the visual tower is the deciding signal. """ +import json +from pathlib import Path from unittest.mock import MagicMock, patch import pytest @@ -12,8 +14,10 @@ from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError from invokeai.backend.model_manager.configs.qwen3_vl_encoder import ( Qwen3VLEncoder_Checkpoint_Config, + Qwen3VLEncoder_Qwen3VLEncoder_Config, _is_qwen3_vl_encoder_state_dict, ) +from invokeai.backend.model_manager.model_on_disk import ModelOnDisk from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType _REQUIRED_FIELDS = { @@ -94,3 +98,48 @@ def test_rejects_text_only_encoder(self, _rfo, _rif) -> None: ) with pytest.raises(NotAMatchError): Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + + +class TestQwen3VLEncoderDirectoryConfig: + @staticmethod + def _write_config(path: Path) -> None: + path.write_text(json.dumps({"architectures": ["Qwen3VLModel"]})) + + @staticmethod + def _fields(path: Path) -> dict: + return {**_REQUIRED_FIELDS, "path": path.as_posix()} + + def test_accepts_direct_layout_with_weights_and_tokenizer(self, tmp_path: Path) -> None: + self._write_config(tmp_path / "config.json") + (tmp_path / "model.safetensors").touch() + (tmp_path / "tokenizer.json").touch() + + config = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + assert config.type is ModelType.Qwen3VLEncoder + + @pytest.mark.parametrize(("include_weights", "include_tokenizer"), [(False, True), (True, False), (False, False)]) + def test_rejects_incomplete_direct_layout( + self, tmp_path: Path, include_weights: bool, include_tokenizer: bool + ) -> None: + self._write_config(tmp_path / "config.json") + if include_weights: + (tmp_path / "model.safetensors").touch() + if include_tokenizer: + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="weights|tokenizer"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + def test_accepts_nested_layout_with_weights_and_tokenizer(self, tmp_path: Path) -> None: + text_encoder = tmp_path / "text_encoder" + tokenizer = tmp_path / "tokenizer" + text_encoder.mkdir() + tokenizer.mkdir() + self._write_config(text_encoder / "config.json") + (text_encoder / "model.safetensors").touch() + (tokenizer / "tokenizer.json").touch() + + config = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + assert config.format is ModelFormat.Qwen3VLEncoder diff --git a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py index bad851c1fef..2310ad58a22 100644 --- a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py +++ b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py @@ -8,6 +8,7 @@ """ import re +from types import SimpleNamespace import accelerate import pytest @@ -17,12 +18,36 @@ _convert_krea2_native_to_diffusers, _dequantize_scaled_fp8, _is_native_krea2_format, + _normalize_qwen3vl_rope_config, _reject_incomplete_load, _remap_qwen3vl_singlefile_keys, _strip_comfyui_prefix, ) +class TestNormalizeQwen3vlRopeConfig: + def test_copies_rope_parameters_when_rope_scaling_is_missing(self) -> None: + rope_parameters = {"rope_type": "default", "rope_theta": 1000000.0} + text_config = SimpleNamespace(rope_parameters=rope_parameters, rope_scaling=None) + config = SimpleNamespace(text_config=text_config) + + assert _normalize_qwen3vl_rope_config(config) is config + assert text_config.rope_scaling == rope_parameters + + def test_preserves_existing_rope_scaling(self) -> None: + existing = {"rope_type": "existing"} + text_config = SimpleNamespace(rope_parameters={"rope_type": "new"}, rope_scaling=existing) + config = SimpleNamespace(text_config=text_config) + + _normalize_qwen3vl_rope_config(config) + + assert text_config.rope_scaling is existing + + def test_accepts_config_without_a_text_config(self) -> None: + config = SimpleNamespace() + assert _normalize_qwen3vl_rope_config(config) is config + + class TestStripComfyuiPrefix: @pytest.mark.parametrize("prefix", ["model.diffusion_model.", "diffusion_model."]) def test_strips_known_prefixes(self, prefix: str) -> None: diff --git a/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py b/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py new file mode 100644 index 00000000000..0fb37617c2c --- /dev/null +++ b/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py @@ -0,0 +1,50 @@ +import torch + +from invokeai.backend.patches.layers.dora_layer import DoRALayer +from invokeai.backend.patches.layers.lora_layer import LoRALayer +from invokeai.backend.patches.lora_conversions.krea2_lora_constants import KREA2_LORA_TRANSFORMER_PREFIX +from invokeai.backend.patches.lora_conversions.krea2_lora_conversion_utils import lora_model_from_krea2_state_dict + + +def test_peft_layer_preserves_explicit_alpha() -> None: + state_dict = { + "transformer.text_fusion.0.attn.to_q.lora_A.weight": torch.ones(2, 4), + "transformer.text_fusion.0.attn.to_q.lora_B.weight": torch.ones(4, 2), + "transformer.text_fusion.0.attn.to_q.alpha": torch.tensor(1.0), + } + + model = lora_model_from_krea2_state_dict(state_dict) + + layer = model.layers[f"{KREA2_LORA_TRANSFORMER_PREFIX}text_fusion.0.attn.to_q"] + assert isinstance(layer, LoRALayer) + assert layer._alpha == 1.0 + + +def test_peft_dora_layer_preserves_magnitude_and_alpha() -> None: + dora_scale = torch.full((4, 1), 2.0) + state_dict = { + "transformer.text_fusion.0.attn.to_q.lora_A.weight": torch.ones(2, 4), + "transformer.text_fusion.0.attn.to_q.lora_B.weight": torch.ones(4, 2), + "transformer.text_fusion.0.attn.to_q.dora_scale": dora_scale, + "transformer.text_fusion.0.attn.to_q.alpha": torch.tensor(1.0), + } + + model = lora_model_from_krea2_state_dict(state_dict) + + layer = model.layers[f"{KREA2_LORA_TRANSFORMER_PREFIX}text_fusion.0.attn.to_q"] + assert isinstance(layer, DoRALayer) + assert layer._alpha == 1.0 + assert torch.equal(layer.dora_scale, dora_scale) + + +def test_peft_layer_without_explicit_alpha_uses_rank_default() -> None: + state_dict = { + "transformer.text_fusion.0.attn.to_q.lora_A.weight": torch.ones(2, 4), + "transformer.text_fusion.0.attn.to_q.lora_B.weight": torch.ones(4, 2), + } + + model = lora_model_from_krea2_state_dict(state_dict) + + layer = model.layers[f"{KREA2_LORA_TRANSFORMER_PREFIX}text_fusion.0.attn.to_q"] + assert isinstance(layer, LoRALayer) + assert layer._alpha is None From e1916789ad0b8bf8b81a4531950dd6c8b04fbd0b Mon Sep 17 00:00:00 2001 From: JPPhoto Date: Mon, 13 Jul 2026 18:43:29 -0500 Subject: [PATCH 13/17] fix Krea-2 review findings --- invokeai/app/invocations/krea2_lora_loader.py | 33 +++- .../backend/model_manager/configs/lora.py | 27 ++- .../backend/model_manager/configs/main.py | 3 + .../model_manager/configs/qwen3_vl_encoder.py | 68 ++++++- .../listeners/krea2ComponentSync.test.ts | 54 ++++++ .../listeners/krea2ComponentSync.ts | 34 ++++ .../listeners/modelSelected.ts | 74 ++++---- .../listeners/modelsLoaded.krea2.test.ts | 70 +++++++ .../listeners/modelsLoaded.ts | 34 ++++ .../controlLayers/store/paramsSlice.test.ts | 38 +++- .../controlLayers/store/paramsSlice.ts | 13 ++ .../src/features/controlLayers/store/types.ts | 4 +- .../src/features/metadata/parsing.test.tsx | 51 +++++- .../web/src/features/metadata/parsing.tsx | 2 + .../graph/generation/buildKrea2Graph.test.ts | 30 ++- .../GenerationSettingsAccordion.tsx | 17 +- .../generationSettingsVisibility.test.ts | 19 ++ .../generationSettingsVisibility.ts | 16 ++ tests/app/invocations/test_krea2_denoise.py | 137 +++++++++++++- .../app/invocations/test_krea2_lora_loader.py | 50 ++++- .../invocations/test_krea2_text_encoder.py | 108 +++++++++++ .../configs/test_krea2_lora_config.py | 24 +++ .../configs/test_krea2_main_config.py | 13 ++ .../configs/test_qwen3_vl_encoder_config.py | 112 +++++++++++- .../load/test_diffusers_039_compatibility.py | 171 ++++++++++++++++++ .../load/test_krea2_loader_boundaries.py | 148 +++++++++++++++ 26 files changed, 1273 insertions(+), 77 deletions(-) create mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts create mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts create mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts create mode 100644 invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.test.ts create mode 100644 invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.ts create mode 100644 tests/app/invocations/test_krea2_text_encoder.py create mode 100644 tests/backend/model_manager/load/test_diffusers_039_compatibility.py create mode 100644 tests/backend/model_manager/load/test_krea2_loader_boundaries.py diff --git a/invokeai/app/invocations/krea2_lora_loader.py b/invokeai/app/invocations/krea2_lora_loader.py index 42dc5cf2c9d..a63dd4b3252 100644 --- a/invokeai/app/invocations/krea2_lora_loader.py +++ b/invokeai/app/invocations/krea2_lora_loader.py @@ -60,9 +60,14 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: if not context.models.exists(lora_key): raise ValueError(f"Unknown lora: {lora_key}!") - if self.lora.base is not BaseModelType.Krea2: + stored_config = context.models.get_config(lora_key) + if ( + self.lora.base is not BaseModelType.Krea2 + or stored_config.base is not BaseModelType.Krea2 + or stored_config.type is not ModelType.LoRA + ): raise ValueError( - f"LoRA '{lora_key}' is for {self.lora.base.value if self.lora.base else 'unknown'} models, " + f"LoRA '{lora_key}' is for {stored_config.base.value if stored_config.base else 'unknown'} models, " "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." ) @@ -83,6 +88,11 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: if output.qwen3_vl_encoder is not None else None ) + if transformer_lora is not None and encoder_lora is not None and transformer_lora.weight != encoder_lora.weight: + raise ValueError( + f"LoRA '{lora_key}' has conflicting weights on the transformer ({transformer_lora.weight}) and " + f"Qwen3-VL encoder ({encoder_lora.weight})." + ) effective_lora = transformer_lora or encoder_lora or LoRAField(lora=self.lora, weight=self.weight) if output.transformer is not None and transformer_lora is None: @@ -132,9 +142,15 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: continue if not context.models.exists(lora.lora.key): raise ValueError(f"Unknown lora: {lora.lora.key}!") - if lora.lora.base is not BaseModelType.Krea2: + stored_config = context.models.get_config(lora.lora.key) + if ( + lora.lora.base is not BaseModelType.Krea2 + or stored_config.base is not BaseModelType.Krea2 + or stored_config.type is not ModelType.LoRA + ): raise ValueError( - f"LoRA '{lora.lora.key}' is for {lora.lora.base.value if lora.lora.base else 'unknown'} models, " + f"LoRA '{lora.lora.key}' is for " + f"{stored_config.base.value if stored_config.base else 'unknown'} models, " "not Krea-2 models. Ensure you are using a Krea-2 compatible LoRA." ) @@ -148,6 +164,15 @@ def invoke(self, context: InvocationContext) -> Krea2LoRALoaderOutput: if output.qwen3_vl_encoder is not None else None ) + if ( + transformer_lora is not None + and encoder_lora is not None + and transformer_lora.weight != encoder_lora.weight + ): + raise ValueError( + f"LoRA '{lora.lora.key}' has conflicting weights on the transformer " + f"({transformer_lora.weight}) and Qwen3-VL encoder ({encoder_lora.weight})." + ) effective_lora = transformer_lora or encoder_lora or lora if self.transformer is not None and output.transformer is not None: diff --git a/invokeai/backend/model_manager/configs/lora.py b/invokeai/backend/model_manager/configs/lora.py index c8f3f81fd55..2e5ba1a2606 100644 --- a/invokeai/backend/model_manager/configs/lora.py +++ b/invokeai/backend/model_manager/configs/lora.py @@ -906,6 +906,18 @@ def _has_krea2_lora_keys(state_dict: dict[str | int, Any]) -> bool: return any(isinstance(k, str) and ("text_fusion" in k or "time_mod_proj" in k) for k in state_dict.keys()) +def _has_complete_lora_pair_for_prefixes(state_dict: dict[str | int, Any], prefixes: tuple[str, ...]) -> bool: + string_keys = {key for key in state_dict if isinstance(key, str)} + pairs = (("lora_A.weight", "lora_B.weight"), ("lora_down.weight", "lora_up.weight")) + for key in string_keys: + if not key.startswith(prefixes): + continue + for down_suffix, up_suffix in pairs: + if key.endswith(down_suffix) and f"{key[: -len(down_suffix)]}{up_suffix}" in string_keys: + return True + return False + + class LoRA_LyCORIS_Krea2_Config(LoRA_LyCORIS_Config_Base, Config_Base): """Model config for Krea-2 LoRA models in LyCORIS (single-file diffusers PEFT) format.""" @@ -918,12 +930,17 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - state_dict = mod.load_state_dict() explicit_krea2_override = override_fields.get("base") is BaseModelType.Krea2 - has_transformer_blocks = state_dict_has_any_keys_starting_with( - state_dict, {"transformer.transformer_blocks.", "transformer_blocks."} + has_supported_explicit_pair = _has_complete_lora_pair_for_prefixes( + state_dict, + ( + "transformer.transformer_blocks.", + "transformer_blocks.", + "base_model.model.transformer.transformer_blocks.", + "text_encoder.", + "base_model.model.text_encoder.", + ), ) - has_lora_down = state_dict_has_any_keys_ending_with(state_dict, {"lora_A.weight", "lora_down.weight"}) - has_lora_up = state_dict_has_any_keys_ending_with(state_dict, {"lora_B.weight", "lora_up.weight"}) - if explicit_krea2_override and has_transformer_blocks and has_lora_down and has_lora_up: + if explicit_krea2_override and has_supported_explicit_pair: return cls(**override_fields) cls._validate_looks_like_lora(mod) diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index 9c0efd392bb..7bd79da9d50 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -1420,6 +1420,9 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - raise_for_override_fields(cls, override_fields) + if mod.path.suffix.lower() != ".safetensors": + raise NotAMatchError(f"expected a .safetensors file, got {mod.path.suffix or '(no suffix)'}") + cls._validate_looks_like_krea2_model(mod) cls._validate_does_not_look_like_gguf_quantized(mod) diff --git a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py index fc77cec927a..74ea1a862b9 100644 --- a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py +++ b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py @@ -1,3 +1,4 @@ +from pathlib import Path from typing import Any, Literal, Self from pydantic import Field @@ -5,6 +6,7 @@ from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Config_Base from invokeai.backend.model_manager.configs.identification_utils import ( NotAMatchError, + get_config_dict_or_raise, raise_for_class_name, raise_for_override_fields, raise_if_not_dir, @@ -13,6 +15,62 @@ from invokeai.backend.model_manager.model_on_disk import ModelOnDisk from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType +_KREA2_QWEN3_VL_HIDDEN_SIZE = 2560 +_KREA2_QWEN3_VL_NUM_HIDDEN_LAYERS = 36 + + +def _validate_krea2_qwen3_vl_config(config_path: Path) -> None: + config = get_config_dict_or_raise(config_path) + text_config = config.get("text_config", config) + if not isinstance(text_config, dict): + raise NotAMatchError("Qwen3-VL text_config must be an object") + hidden_size = text_config.get("hidden_size") + num_hidden_layers = text_config.get("num_hidden_layers") + if hidden_size != _KREA2_QWEN3_VL_HIDDEN_SIZE: + raise NotAMatchError( + f"Krea-2 requires the Qwen3-VL 4B hidden size {_KREA2_QWEN3_VL_HIDDEN_SIZE}, got {hidden_size}" + ) + if num_hidden_layers != _KREA2_QWEN3_VL_NUM_HIDDEN_LAYERS: + raise NotAMatchError( + f"Krea-2 requires {_KREA2_QWEN3_VL_NUM_HIDDEN_LAYERS} Qwen3-VL layers, got {num_hidden_layers}" + ) + + +def _has_complete_pretrained_weights(weights_path: Path) -> bool: + if (weights_path / "model.safetensors").is_file() or (weights_path / "pytorch_model.bin").is_file(): + return True + + for index_name in ("model.safetensors.index.json", "pytorch_model.bin.index.json"): + index_path = weights_path / index_name + if not index_path.is_file(): + continue + index = get_config_dict_or_raise(index_path) + weight_map = index.get("weight_map") + if not isinstance(weight_map, dict) or not weight_map: + return False + referenced_files = {filename for filename in weight_map.values() if isinstance(filename, str)} + return bool(referenced_files) and all((weights_path / filename).is_file() for filename in referenced_files) + return False + + +def _validate_krea2_qwen3_vl_checkpoint_shape(state_dict: dict[str | int, Any]) -> None: + embed_keys = ( + "model.embed_tokens.weight", + "model.language_model.embed_tokens.weight", + "language_model.embed_tokens.weight", + "embed_tokens.weight", + ) + embed = next((state_dict[key] for key in embed_keys if key in state_dict), None) + shape = getattr(embed, "shape", ()) + if len(shape) < 2 or shape[1] != _KREA2_QWEN3_VL_HIDDEN_SIZE: + hidden_size = shape[1] if len(shape) >= 2 else None + raise NotAMatchError( + f"Krea-2 requires a Qwen3-VL 4B checkpoint with hidden size " + f"{_KREA2_QWEN3_VL_HIDDEN_SIZE}, got {hidden_size}" + ) + if not any(isinstance(key, str) and ".layers.35." in key for key in state_dict): + raise NotAMatchError("Krea-2 requires a Qwen3-VL 4B checkpoint containing language-model layer 35") + class Qwen3VLEncoder_Qwen3VLEncoder_Config(Config_Base): """Configuration for standalone Qwen3-VL text encoder models (diffusers-like directory format). @@ -62,6 +120,7 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - "Qwen3VLForConditionalGeneration", }, ) + _validate_krea2_qwen3_vl_config(expected_config_path) if config_path_nested.exists(): weights_path = mod.path / "text_encoder" @@ -70,7 +129,7 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - weights_path = mod.path tokenizer_path = mod.path - has_weights = any(weights_path.glob("*.safetensors")) or any(weights_path.glob("*.bin")) + has_weights = _has_complete_pretrained_weights(weights_path) has_tokenizer = (tokenizer_path / "tokenizer.json").exists() or ( (tokenizer_path / "vocab.json").exists() and (tokenizer_path / "merges.txt").exists() ) @@ -113,7 +172,12 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - raise_for_override_fields(cls, override_fields) - if not _is_qwen3_vl_encoder_state_dict(mod.load_state_dict()): + if mod.path.suffix.lower() != ".safetensors": + raise NotAMatchError(f"expected a .safetensors file, got {mod.path.suffix or '(no suffix)'}") + + state_dict = mod.load_state_dict() + if not _is_qwen3_vl_encoder_state_dict(state_dict): raise NotAMatchError("state dict does not look like a single-file Qwen3-VL encoder") + _validate_krea2_qwen3_vl_checkpoint_shape(state_dict) return cls(**override_fields) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts new file mode 100644 index 00000000000..724b32286e1 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from 'vitest'; + +import { getKrea2ComponentUpdates } from './krea2ComponentSync'; + +const vae = { key: 'vae', hash: 'h-vae', name: 'VAE', base: 'qwen-image', type: 'vae' } as const; +const animaVae = { key: 'anima-vae', hash: 'h-anima', name: 'Anima VAE', base: 'anima', type: 'vae' } as const; +const encoder = { + key: 'encoder', + hash: 'h-encoder', + name: 'Encoder', + base: 'any', + type: 'qwen3_vl_encoder', +} as const; + +describe('getKrea2ComponentUpdates', () => { + it('clears stale standalone components for a Diffusers model', () => { + expect( + getKrea2ComponentUpdates({ + format: 'diffusers', + selectedVae: vae, + selectedEncoder: encoder, + availableQwenImageVaes: [vae], + availableAnimaVaes: [animaVae], + availableEncoders: [encoder], + }) + ).toEqual({ vae: null, encoder: null }); + }); + + it('selects installed standalone components for a non-Diffusers model', () => { + expect( + getKrea2ComponentUpdates({ + format: 'gguf_quantized', + selectedVae: null, + selectedEncoder: null, + availableQwenImageVaes: [vae], + availableAnimaVaes: [animaVae], + availableEncoders: [encoder], + }) + ).toEqual({ vae, encoder }); + }); + + it('falls back to an Anima VAE and preserves explicit standalone selections', () => { + expect( + getKrea2ComponentUpdates({ + format: 'checkpoint', + selectedVae: animaVae, + selectedEncoder: encoder, + availableQwenImageVaes: [], + availableAnimaVaes: [animaVae], + availableEncoders: [encoder], + }) + ).toEqual({}); + }); +}); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts new file mode 100644 index 00000000000..42122038855 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts @@ -0,0 +1,34 @@ +import type { ModelIdentifierField } from 'features/nodes/types/common'; + +type Krea2ComponentSyncArg = { + format: string; + selectedVae: ModelIdentifierField | null; + selectedEncoder: ModelIdentifierField | null; + availableQwenImageVaes: ModelIdentifierField[]; + availableAnimaVaes: ModelIdentifierField[]; + availableEncoders: ModelIdentifierField[]; +}; + +type Krea2ComponentUpdates = { + vae?: ModelIdentifierField | null; + encoder?: ModelIdentifierField | null; +}; + +export const getKrea2ComponentUpdates = (arg: Krea2ComponentSyncArg): Krea2ComponentUpdates => { + const { format, selectedVae, selectedEncoder, availableQwenImageVaes, availableAnimaVaes, availableEncoders } = arg; + + if (format === 'diffusers') { + return { + ...(selectedVae ? { vae: null } : {}), + ...(selectedEncoder ? { encoder: null } : {}), + }; + } + + const defaultVae = availableQwenImageVaes[0] ?? availableAnimaVaes[0]; + const defaultEncoder = availableEncoders[0]; + + return { + ...(!selectedVae && defaultVae ? { vae: defaultVae } : {}), + ...(!selectedEncoder && defaultEncoder ? { encoder: defaultEncoder } : {}), + }; +}; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 38e96c5f6d7..80c54e18816 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -69,6 +69,8 @@ import { import type { FLUXKontextModelConfig, FLUXReduxModelConfig, IPAdapterModelConfig } from 'services/api/types'; import { isExternalApiModelConfig, isFluxKontextModelConfig, isFluxReduxModelConfig } from 'services/api/types'; +import { getKrea2ComponentUpdates } from './krea2ComponentSync'; + const log = logger('models'); export const addModelSelectedListener = (startAppListening: AppStartListening) => { @@ -332,27 +334,38 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = // The model list may not be populated yet during startup or metadata recall. Defer component // changes until the selected model's format is known instead of treating unknown as single-file. } else if (newModelConfig.format === 'diffusers') { - if (krea2VaeModel) { - dispatch(krea2VaeModelSelected(null)); + const updates = getKrea2ComponentUpdates({ + format: newModelConfig.format, + selectedVae: krea2VaeModel, + selectedEncoder: krea2Qwen3VlEncoderModel, + availableQwenImageVaes: selectQwenImageVAEModels(state), + availableAnimaVaes: selectAnimaVAEModels(state), + availableEncoders: selectQwen3VLEncoderModels(state), + }); + if ('vae' in updates) { + dispatch(krea2VaeModelSelected(updates.vae ? zModelIdentifierField.parse(updates.vae) : null)); modelsUpdatedDisabledOrCleared += 1; } - if (krea2Qwen3VlEncoderModel) { - dispatch(krea2Qwen3VlEncoderModelSelected(null)); + if ('encoder' in updates) { + dispatch( + krea2Qwen3VlEncoderModelSelected(updates.encoder ? zModelIdentifierField.parse(updates.encoder) : null) + ); modelsUpdatedDisabledOrCleared += 1; } } else { - if (!krea2VaeModel) { - // Krea-2 shares the Qwen-Image VAE; the dropdown also accepts anima-tagged copies. - const vae = selectQwenImageVAEModels(state)[0] ?? selectAnimaVAEModels(state)[0]; - if (vae) { - dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(vae))); - } + const updates = getKrea2ComponentUpdates({ + format: newModelConfig.format, + selectedVae: krea2VaeModel, + selectedEncoder: krea2Qwen3VlEncoderModel, + availableQwenImageVaes: selectQwenImageVAEModels(state), + availableAnimaVaes: selectAnimaVAEModels(state), + availableEncoders: selectQwen3VLEncoderModels(state), + }); + if (updates.vae) { + dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(updates.vae))); } - if (!krea2Qwen3VlEncoderModel) { - const encoder = selectQwen3VLEncoderModels(state)[0]; - if (encoder) { - dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(encoder))); - } + if (updates.encoder) { + dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(updates.encoder))); } } } @@ -586,25 +599,22 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = : undefined) ?? modelsApi.endpoints.getModelConfig.select(newModel.key)(state).data; if (!newModelConfig) { // Defer until the model format is known. - } else if (newModelConfig.format === 'diffusers') { - if (krea2VaeModel) { - dispatch(krea2VaeModelSelected(null)); - } - if (krea2Qwen3VlEncoderModel) { - dispatch(krea2Qwen3VlEncoderModelSelected(null)); - } } else { - if (!krea2VaeModel) { - const vae = selectQwenImageVAEModels(state)[0] ?? selectAnimaVAEModels(state)[0]; - if (vae) { - dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(vae))); - } + const updates = getKrea2ComponentUpdates({ + format: newModelConfig.format, + selectedVae: krea2VaeModel, + selectedEncoder: krea2Qwen3VlEncoderModel, + availableQwenImageVaes: selectQwenImageVAEModels(state), + availableAnimaVaes: selectAnimaVAEModels(state), + availableEncoders: selectQwen3VLEncoderModels(state), + }); + if ('vae' in updates) { + dispatch(krea2VaeModelSelected(updates.vae ? zModelIdentifierField.parse(updates.vae) : null)); } - if (!krea2Qwen3VlEncoderModel) { - const encoder = selectQwen3VLEncoderModels(state)[0]; - if (encoder) { - dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(encoder))); - } + if ('encoder' in updates) { + dispatch( + krea2Qwen3VlEncoderModelSelected(updates.encoder ? zModelIdentifierField.parse(updates.encoder) : null) + ); } } } diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts new file mode 100644 index 00000000000..0d44cac0521 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts @@ -0,0 +1,70 @@ +import type { RootState } from 'app/store/store'; +import { krea2Qwen3VlEncoderModelSelected, krea2VaeModelSelected } from 'features/controlLayers/store/paramsSlice'; +import type { AnyModelConfig } from 'services/api/types'; +import { describe, expect, it, vi } from 'vitest'; + +import { handleKrea2Components } from './modelsLoaded'; + +const mainModel = { + key: 'krea-main', + hash: 'main-hash', + name: 'Krea Main', + base: 'krea-2', + type: 'main', + format: 'gguf_quantized', +} as const; +const vae = { + key: 'vae', + hash: 'vae-hash', + name: 'Qwen Image VAE', + base: 'qwen-image', + type: 'vae', + format: 'checkpoint', +} as const; +const encoder = { + key: 'encoder', + hash: 'encoder-hash', + name: 'Qwen3-VL Encoder', + base: 'any', + type: 'qwen3_vl_encoder', + format: 'qwen3_vl_encoder', +} as const; + +const makeState = (overrides: Record = {}) => + ({ + params: { + model: mainModel, + krea2VaeModel: null, + krea2Qwen3VlEncoderModel: null, + ...overrides, + }, + }) as unknown as RootState; + +describe('handleKrea2Components', () => { + it('selects standalone components when a deferred non-Diffusers model arrives in the fulfilled list', () => { + const dispatch = vi.fn(); + + handleKrea2Components( + [mainModel, vae, encoder] as unknown as AnyModelConfig[], + makeState(), + dispatch, + null as never + ); + + expect(dispatch).toHaveBeenCalledWith(krea2VaeModelSelected(expect.objectContaining({ key: vae.key }))); + expect(dispatch).toHaveBeenCalledWith( + krea2Qwen3VlEncoderModelSelected(expect.objectContaining({ key: encoder.key })) + ); + }); + + it('clears stale standalone components when a deferred Diffusers model arrives in the fulfilled list', () => { + const dispatch = vi.fn(); + const diffusersMain = { ...mainModel, format: 'diffusers' } as const; + const state = makeState({ model: diffusersMain, krea2VaeModel: vae, krea2Qwen3VlEncoderModel: encoder }); + + handleKrea2Components([diffusersMain, vae, encoder] as unknown as AnyModelConfig[], state, dispatch, null as never); + + expect(dispatch).toHaveBeenCalledWith(krea2VaeModelSelected(null)); + expect(dispatch).toHaveBeenCalledWith(krea2Qwen3VlEncoderModelSelected(null)); + }); +}); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts index 8cbbc72343b..130a0972963 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts @@ -5,6 +5,8 @@ import { loraDeleted } from 'features/controlLayers/store/lorasSlice'; import { clipEmbedModelSelected, fluxVAESelected, + krea2Qwen3VlEncoderModelSelected, + krea2VaeModelSelected, modelChanged, refinerModelChanged, t5EncoderModelSelected, @@ -19,6 +21,7 @@ import { isRegionalGuidanceFLUXReduxConfig, isRegionalGuidanceIPAdapterConfig, } from 'features/controlLayers/store/types'; +import { zModelIdentifierField } from 'features/nodes/types/common'; import { modelSelected } from 'features/parameters/store/actions'; import { postProcessingModelChanged, @@ -35,6 +38,7 @@ import type { Logger } from 'roarr'; import { modelConfigsAdapterSelectors, modelsApi } from 'services/api/endpoints/models'; import type { AnyModelConfig } from 'services/api/types'; import { + isAnimaVAEModelConfig, isCLIPEmbedModelConfigOrSubmodel, isControlLayerModelConfig, isControlNetModelConfig, @@ -44,12 +48,16 @@ import { isLoRAModelConfig, isNonFluxVAEModelConfig, isNonRefinerMainModelConfig, + isQwen3VLEncoderModelConfig, + isQwenImageVAEModelConfig, isRefinerMainModelModelConfig, isSpandrelImageToImageModelConfig, isT5EncoderModelConfigOrSubmodel, } from 'services/api/types'; import type { JsonObject } from 'type-fest'; +import { getKrea2ComponentUpdates } from './krea2ComponentSync'; + const log = logger('models'); /** @@ -75,6 +83,7 @@ export const addModelsLoadedListener = (startAppListening: AppStartListening) => const models = modelConfigsAdapterSelectors.selectAll(action.payload); handleMainModels(models, state, dispatch, log); + handleKrea2Components(models, state, dispatch, log); handleRefinerModels(models, state, dispatch, log); handleVAEModels(models, state, dispatch, log); handleLoRAModels(models, state, dispatch, log); @@ -91,6 +100,31 @@ export const addModelsLoadedListener = (startAppListening: AppStartListening) => }); }; +export const handleKrea2Components: ModelHandler = (models, state, dispatch) => { + if (state.params.model?.base !== 'krea-2') { + return; + } + const selectedModel = models.find((model) => model.key === state.params.model?.key); + if (!selectedModel || !isNonRefinerMainModelConfig(selectedModel)) { + return; + } + + const updates = getKrea2ComponentUpdates({ + format: selectedModel.format, + selectedVae: state.params.krea2VaeModel, + selectedEncoder: state.params.krea2Qwen3VlEncoderModel, + availableQwenImageVaes: models.filter((model) => isQwenImageVAEModelConfig(model)), + availableAnimaVaes: models.filter((model) => isAnimaVAEModelConfig(model)), + availableEncoders: models.filter(isQwen3VLEncoderModelConfig), + }); + if ('vae' in updates) { + dispatch(krea2VaeModelSelected(updates.vae ? zModelIdentifierField.parse(updates.vae) : null)); + } + if ('encoder' in updates) { + dispatch(krea2Qwen3VlEncoderModelSelected(updates.encoder ? zModelIdentifierField.parse(updates.encoder) : null)); + } +}; + type ModelHandler = ( models: AnyModelConfig[], state: RootState, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.test.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.test.ts index d210d2fd2ac..8abb24cad12 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.test.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.test.ts @@ -157,7 +157,7 @@ describe('paramsSliceConfig persisted state migration', () => { const result = migrate?.(v2State) as ReturnType; - expect(result._version).toBe(3); + expect(result._version).toBe(4); expect(result.qwenImageVaeModel).toBeNull(); expect(result.qwenImageQwenVLEncoderModel).toBeNull(); // Existing params should be preserved @@ -168,6 +168,42 @@ describe('paramsSliceConfig persisted state migration', () => { expect(result.dimensions.height).toBe(768); }); + it('backfills Krea-2 fields when migrating from v3 and preserves existing params', () => { + expect(migrate).toBeDefined(); + + const initial = getInitialParamsState(); + const v3State: Record = { + ...initial, + _version: 3, + positivePrompt: 'preserve this prompt', + seed: 1234, + dimensions: { ...initial.dimensions, width: 640, height: 896 }, + }; + delete v3State.krea2VaeModel; + delete v3State.krea2Qwen3VlEncoderModel; + delete v3State.krea2SeedVarianceEnabled; + delete v3State.krea2SeedVarianceStrength; + delete v3State.krea2SeedVarianceRandomizePercent; + delete v3State.krea2RebalanceEnabled; + delete v3State.krea2RebalanceMultiplier; + delete v3State.krea2RebalanceWeights; + + const result = migrate?.(v3State) as ReturnType; + + expect(result._version).toBe(4); + expect(result.krea2VaeModel).toBeNull(); + expect(result.krea2Qwen3VlEncoderModel).toBeNull(); + expect(result.krea2SeedVarianceEnabled).toBe(false); + expect(result.krea2SeedVarianceStrength).toBe(20); + expect(result.krea2SeedVarianceRandomizePercent).toBe(50); + expect(result.krea2RebalanceEnabled).toBe(false); + expect(result.krea2RebalanceMultiplier).toBe(4); + expect(result.krea2RebalanceWeights).toBe('1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0'); + expect(result.positivePrompt).toBe('preserve this prompt'); + expect(result.seed).toBe(1234); + expect(result.dimensions).toMatchObject({ width: 640, height: 896 }); + }); + it('migrates old positive prompt history entries to prompt pairs', () => { expect(migrate).toBeDefined(); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts index e91d755e47d..3c998e80199 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts @@ -806,6 +806,19 @@ export const paramsSliceConfig: SliceConfig = { state.qwenImageQwenVLEncoderModel = null; } + if (state._version === 3) { + // v3 -> v4, add Krea-2 standalone component and conditioning enhancer fields + state._version = 4; + state.krea2VaeModel = null; + state.krea2Qwen3VlEncoderModel = null; + state.krea2SeedVarianceEnabled = false; + state.krea2SeedVarianceStrength = 20; + state.krea2SeedVarianceRandomizePercent = 50; + state.krea2RebalanceEnabled = false; + state.krea2RebalanceMultiplier = 4; + state.krea2RebalanceWeights = '1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0'; + } + return zParamsState.parse(state); }, }, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 8788d1162ba..7fa1f9a3c67 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -790,7 +790,7 @@ export const zInfillMethod = z.enum(['patchmatch', 'lama', 'cv2', 'color', 'tile export type InfillMethod = z.infer; export const zParamsState = z.object({ - _version: z.literal(3), + _version: z.literal(4), maskBlur: z.number(), maskBlurMethod: zParameterMaskBlurMethod, canvasCoherenceMode: zParameterCanvasCoherenceMode, @@ -891,7 +891,7 @@ export const zParamsState = z.object({ }); export type ParamsState = z.infer; export const getInitialParamsState = (): ParamsState => ({ - _version: 3, + _version: 4, maskBlur: 16, maskBlurMethod: 'box', canvasCoherenceMode: 'Gaussian Blur', diff --git a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx index 15143b53411..ba2b17acdfe 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx @@ -179,16 +179,23 @@ describe('ImageMetadataHandlers — Krea-2 recall gating', () => { // transformers, recalled into dedicated (krea2VaeModel / krea2Qwen3VlEncoderModel) slots — but only when // the current main model is actually Krea-2. describe('Krea2VAEModel', () => { - it('parses metadata.vae when the current main model is Krea-2', async () => { - currentBase = 'krea-2'; - nextResolved = fakeModel('vae', 'krea-2'); - const store = makeStore(); + it.each(['qwen-image', 'anima'] as const)( + 'parses a supported %s VAE when the current and metadata main models are Krea-2', + async (vaeBase) => { + currentBase = 'krea-2'; + nextResolved = fakeModel('vae', vaeBase); + const store = makeStore(); - const parsed = await ImageMetadataHandlers.Krea2VAEModel.parse({ vae: nextResolved }, store); + const parsed = await ImageMetadataHandlers.Krea2VAEModel.parse( + { model: fakeModel('main', 'krea-2'), vae: nextResolved }, + store + ); - expect(parsed.key).toBe('vae-key'); - expect(parsed.type).toBe('vae'); - }); + expect(parsed.key).toBe('vae-key'); + expect(parsed.type).toBe('vae'); + expect(parsed.base).toBe(vaeBase); + } + ); it('rejects parsing when the current main model is not Krea-2', async () => { currentBase = 'sdxl'; @@ -197,6 +204,19 @@ describe('ImageMetadataHandlers — Krea-2 recall gating', () => { await expect(ImageMetadataHandlers.Krea2VAEModel.parse({ vae: nextResolved }, store)).rejects.toThrow(); }); + + it('rejects VAE metadata from a non-Krea-2 image even when Krea-2 is currently selected', async () => { + currentBase = 'krea-2'; + nextResolved = fakeModel('vae', 'sdxl'); + const store = makeStore(); + + await expect( + ImageMetadataHandlers.Krea2VAEModel.parse( + { model: fakeModel('qwen3_vl_encoder', 'sdxl'), vae: nextResolved }, + store + ) + ).rejects.toThrow(); + }); }); describe('Krea2Qwen3VlEncoderModel', () => { @@ -206,7 +226,7 @@ describe('ImageMetadataHandlers — Krea-2 recall gating', () => { const store = makeStore(); const parsed = await ImageMetadataHandlers.Krea2Qwen3VlEncoderModel.parse( - { qwen3_vl_encoder: nextResolved }, + { model: fakeModel('main', 'krea-2'), qwen3_vl_encoder: nextResolved }, store ); @@ -223,6 +243,19 @@ describe('ImageMetadataHandlers — Krea-2 recall gating', () => { ImageMetadataHandlers.Krea2Qwen3VlEncoderModel.parse({ qwen3_vl_encoder: nextResolved }, store) ).rejects.toThrow(); }); + + it('rejects encoder metadata from a non-Krea-2 image even when Krea-2 is currently selected', async () => { + currentBase = 'krea-2'; + nextResolved = fakeModel('qwen3_vl_encoder', 'any'); + const store = makeStore(); + + await expect( + ImageMetadataHandlers.Krea2Qwen3VlEncoderModel.parse( + { model: fakeModel('qwen3_vl_encoder', 'flux'), qwen3_vl_encoder: nextResolved }, + store + ) + ).rejects.toThrow(); + }); }); // The conditioning-enhancer settings are Krea-2-only scalars. Their parse is gated on the current base so diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index c72faa6b147..5cd96ebcfc1 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -1173,6 +1173,7 @@ const Krea2VAEModel: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2VAEModel', parse: async (metadata, store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2VAEModel'); const raw = getProperty(metadata, 'vae'); const parsed = await parseModelIdentifier(raw, store, 'vae'); assert(parsed.type === 'vae'); @@ -1197,6 +1198,7 @@ const Krea2Qwen3VlEncoderModel: SingleMetadataHandler = { [SingleMetadataKey]: true, type: 'Krea2Qwen3VlEncoderModel', parse: async (metadata, store) => { + assertMetadataModelBase(metadata, 'krea-2', 'Krea2Qwen3VlEncoderModel'); const raw = getProperty(metadata, 'qwen3_vl_encoder'); const parsed = await parseModelIdentifier(raw, store, 'qwen3_vl_encoder'); assert(parsed.type === 'qwen3_vl_encoder'); diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts index cf5d235ba05..6dd52be25f0 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildKrea2Graph.test.ts @@ -52,15 +52,15 @@ vi.mock('features/metadata/util/modelFetchingHelpers', () => ({ })); vi.mock('features/nodes/util/graph/generation/addImageToImage', () => ({ - addImageToImage: vi.fn(), + addImageToImage: vi.fn(({ l2i }) => Promise.resolve(l2i)), })); vi.mock('features/nodes/util/graph/generation/addInpaint', () => ({ - addInpaint: vi.fn(), + addInpaint: vi.fn(({ l2i }) => Promise.resolve(l2i)), })); vi.mock('features/nodes/util/graph/generation/addOutpaint', () => ({ - addOutpaint: vi.fn(), + addOutpaint: vi.fn(({ l2i }) => Promise.resolve(l2i)), })); vi.mock('features/nodes/util/graph/generation/addKrea2LoRAs', () => ({ @@ -99,6 +99,9 @@ vi.mock('services/api/types', async () => { }; }); +import { addImageToImage } from './addImageToImage'; +import { addInpaint } from './addInpaint'; +import { addOutpaint } from './addOutpaint'; import { buildKrea2Graph } from './buildKrea2Graph'; type BuiltGraph = Awaited>['g']; @@ -112,6 +115,15 @@ const buildTxt2Img = () => } as never, }); +const buildCanvasMode = (generationMode: 'img2img' | 'inpaint' | 'outpaint') => + buildKrea2Graph({ + generationMode, + manager: { id: 'manager' } as never, + state: { + system: { shouldUseNSFWChecker: false, shouldUseWatermarker: false }, + } as never, + }); + const nodeTypesOf = (g: BuiltGraph): string[] => Object.values(g.getGraph().nodes).map((n) => n.type); const posConditioningEdge = (g: BuiltGraph) => g.getGraph().edges.find((e) => e.destination.field === 'positive_conditioning'); @@ -133,6 +145,18 @@ describe('buildKrea2Graph', () => { expect(types).toContain('qwen_image_l2i'); }); + it.each([ + ['img2img', addImageToImage], + ['inpaint', addInpaint], + ['outpaint', addOutpaint], + ] as const)('builds the %s graph through its canvas integration', async (mode, integration) => { + const { g } = await buildCanvasMode(mode); + + expect(integration).toHaveBeenCalledOnce(); + expect(nodeTypesOf(g)).toContain('qwen_image_i2l'); + expect((g.getMetadataNode() as unknown as Record).generation_mode).toBe(`krea2_${mode}`); + }); + describe('CFG gating (negative conditioning)', () => { // Krea-2 only adds a negative prompt + negative_conditioning edge when CFG is enabled (cfg_scale > 1). // The distilled Turbo checkpoint runs with CFG off (cfg_scale 1.0), so recording/encoding a negative diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx index 9a25ea5f23c..684847e0cea 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx @@ -5,15 +5,14 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppSelector } from 'app/store/storeHooks'; import { selectLoRAsSlice } from 'features/controlLayers/store/lorasSlice'; import { + selectBase, selectFluxDypePreset, selectIsAnima, - selectIsCogView4, selectIsExternal, selectIsFLUX, selectIsFlux2, selectIsKrea2, selectIsQwenImage, - selectIsSD3, selectIsZImage, selectModelSupportsGuidance, selectModelSupportsSteps, @@ -42,6 +41,8 @@ import { useTranslation } from 'react-i18next'; import { useSelectedModelConfig } from 'services/api/hooks/useSelectedModelConfig'; import { isFluxFillMainModelModelConfig } from 'services/api/types'; +import { shouldShowStandardScheduler } from './generationSettingsVisibility'; + const formLabelProps: FormLabelProps = { minW: '4rem', }; @@ -49,10 +50,9 @@ const formLabelProps: FormLabelProps = { export const GenerationSettingsAccordion = memo(() => { const { t } = useTranslation(); const modelConfig = useSelectedModelConfig(); + const base = useAppSelector(selectBase); const isFLUX = useAppSelector(selectIsFLUX); const isFlux2 = useAppSelector(selectIsFlux2); - const isSD3 = useAppSelector(selectIsSD3); - const isCogView4 = useAppSelector(selectIsCogView4); const isZImage = useAppSelector(selectIsZImage); const isExternal = useAppSelector(selectIsExternal); const isQwenImage = useAppSelector(selectIsQwenImage); @@ -100,14 +100,7 @@ export const GenerationSettingsAccordion = memo(() => { - {!isExternal && - !isFLUX && - !isFlux2 && - !isSD3 && - !isCogView4 && - !isZImage && - !isQwenImage && - !isAnima && } + {shouldShowStandardScheduler(base) && } {!isExternal && (isFLUX || isFlux2) && } {!isExternal && isZImage && } {!isExternal && isAnima && } diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.test.ts b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.test.ts new file mode 100644 index 00000000000..9eb42dff42a --- /dev/null +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from 'vitest'; + +import { shouldShowStandardScheduler } from './generationSettingsVisibility'; + +describe('shouldShowStandardScheduler', () => { + it.each(['sd-1', 'sd-2', 'sdxl', 'sdxl-refiner', undefined] as const)( + 'shows the standard scheduler for %s', + (base) => { + expect(shouldShowStandardScheduler(base)).toBe(true); + } + ); + + it.each(['external', 'flux', 'flux2', 'sd-3', 'cogview4', 'z-image', 'qwen-image', 'anima', 'krea-2'] as const)( + 'hides the standard scheduler for %s', + (base) => { + expect(shouldShowStandardScheduler(base)).toBe(false); + } + ); +}); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.ts b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.ts new file mode 100644 index 00000000000..4e1fc34d37d --- /dev/null +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/generationSettingsVisibility.ts @@ -0,0 +1,16 @@ +import type { BaseModelType } from 'features/nodes/types/common'; + +const BASES_WITHOUT_STANDARD_SCHEDULER = new Set([ + 'external', + 'flux', + 'flux2', + 'sd-3', + 'cogview4', + 'z-image', + 'qwen-image', + 'anima', + 'krea-2', +]); + +export const shouldShowStandardScheduler = (base: BaseModelType | null | undefined): boolean => + base === undefined || base === null || !BASES_WITHOUT_STANDARD_SCHEDULER.has(base); diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py index d2f56577044..75c159b6c18 100644 --- a/tests/app/invocations/test_krea2_denoise.py +++ b/tests/app/invocations/test_krea2_denoise.py @@ -1,8 +1,14 @@ +from contextlib import contextmanager, nullcontext +from types import SimpleNamespace + import pytest import torch -from invokeai.app.invocations.fields import DenoiseMaskField +from invokeai.app.invocations.fields import DenoiseMaskField, Krea2ConditioningField, LatentsField from invokeai.app.invocations.krea2_denoise import KREA2_LATENT_CHANNELS, Krea2DenoiseInvocation +from invokeai.app.invocations.model import ModelIdentifierField, TransformerField +from invokeai.backend.model_manager.taxonomy import BaseModelType, Krea2VariantType, ModelFormat, ModelType +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ConditioningFieldData, Krea2ConditioningInfo @pytest.mark.parametrize(("denoising_start", "denoising_end"), [(0.75, 0.25), (0.5, 0.5)]) @@ -116,3 +122,132 @@ def test_get_noise_is_deterministic_and_correctly_shaped() -> None: # Same seed -> identical noise (reproducibility); different seed -> different noise. assert torch.equal(noise_a, noise_b) assert not torch.equal(noise_a, noise_other) + + +class _Scheduler: + def __init__(self, **_kwargs) -> None: + self.config = SimpleNamespace(num_train_timesteps=1000) + + def set_timesteps(self, *, sigmas, mu, device) -> None: + del mu + self.sigmas = torch.tensor([*sigmas, 0.0], device=device) + self.timesteps = self.sigmas[:-1] * self.config.num_train_timesteps + + +class _Transformer: + def __init__(self) -> None: + self.conditioning_values: list[float] = [] + + def __call__(self, *, hidden_states, encoder_hidden_states, **_kwargs): + self.conditioning_values.append(float(encoder_hidden_states.mean())) + return (torch.zeros_like(hidden_states),) + + +class _TransformerInfo: + def __init__(self, transformer: _Transformer) -> None: + self.transformer = transformer + + @contextmanager + def model_on_device(self, **_kwargs): + yield ({}, self.transformer) + + +def _model_identifier() -> ModelIdentifierField: + return ModelIdentifierField( + key="krea-model", + hash="model-hash", + name="Krea Model", + base=BaseModelType.Krea2, + type=ModelType.Main, + ) + + +def _runtime_invocation(*, cfg_scale: float | list[float], with_mask: bool = False) -> Krea2DenoiseInvocation: + return Krea2DenoiseInvocation.model_construct( + transformer=TransformerField(transformer=_model_identifier(), loras=[]), + positive_conditioning=Krea2ConditioningField(conditioning_name="positive"), + negative_conditioning=Krea2ConditioningField(conditioning_name="negative"), + cfg_scale=cfg_scale, + width=16, + height=16, + steps=2, + seed=1, + shift=1.15, + denoising_start=0.0, + denoising_end=1.0, + latents=LatentsField(latents_name="init") if with_mask else None, + denoise_mask=DenoiseMaskField(mask_name="mask") if with_mask else None, + ) + + +def _runtime_context(tmp_path, transformer: _Transformer): + conditionings = { + "positive": ConditioningFieldData(conditionings=[Krea2ConditioningInfo(prompt_embeds=torch.ones(1, 2, 12, 8))]), + "negative": ConditioningFieldData( + conditionings=[Krea2ConditioningInfo(prompt_embeds=torch.zeros(1, 2, 12, 8))] + ), + } + tensors = { + "init": torch.zeros(1, KREA2_LATENT_CHANNELS, 2, 2), + "mask": torch.zeros(1, 1, 16, 16), + } + config = SimpleNamespace(format=ModelFormat.Checkpoint, variant=Krea2VariantType.Turbo) + return SimpleNamespace( + models=SimpleNamespace( + load=lambda _identifier: _TransformerInfo(transformer), + get_config=lambda _identifier: config, + get_absolute_path=lambda _config: tmp_path, + ), + conditioning=SimpleNamespace(load=lambda name: conditionings[name]), + tensors=SimpleNamespace(load=lambda name: tensors[name]), + util=SimpleNamespace(sd_step_callback=lambda *_args: None), + ) + + +def _patch_runtime(monkeypatch) -> None: + monkeypatch.setattr( + "diffusers.schedulers.scheduling_flow_match_euler_discrete.FlowMatchEulerDiscreteScheduler", _Scheduler + ) + monkeypatch.setattr( + "invokeai.app.invocations.krea2_denoise.TorchDevice.choose_torch_device", lambda: torch.device("cpu") + ) + monkeypatch.setattr( + "invokeai.app.invocations.krea2_denoise.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + monkeypatch.setattr( + "invokeai.app.invocations.krea2_denoise.LayerPatcher.apply_smart_model_patches", + lambda **_kwargs: nullcontext(), + ) + + +def test_run_diffusion_applies_mixed_cfg_only_at_enabled_steps(monkeypatch, tmp_path) -> None: + _patch_runtime(monkeypatch) + transformer = _Transformer() + + latents = _runtime_invocation(cfg_scale=[2.0, 1.0])._run_diffusion(_runtime_context(tmp_path, transformer)) + + assert latents.shape == (1, KREA2_LATENT_CHANNELS, 1, 2, 2) + assert transformer.conditioning_values == [1.0, 0.0, 1.0] + + +def test_run_diffusion_reaches_masked_denoising_merge(monkeypatch, tmp_path) -> None: + _patch_runtime(monkeypatch) + transformer = _Transformer() + merge_sigmas: list[float] = [] + + class _InpaintExtension: + def __init__(self, **_kwargs) -> None: + pass + + def merge_intermediate_latents_with_init_latents(self, latents, sigma): + merge_sigmas.append(sigma) + return latents + + monkeypatch.setattr("invokeai.app.invocations.krea2_denoise.RectifiedFlowInpaintExtension", _InpaintExtension) + + latents = _runtime_invocation(cfg_scale=1.0, with_mask=True)._run_diffusion(_runtime_context(tmp_path, transformer)) + + assert latents.shape == (1, KREA2_LATENT_CHANNELS, 1, 2, 2) + assert len(merge_sigmas) == 2 + assert transformer.conditioning_values == [1.0, 1.0] diff --git a/tests/app/invocations/test_krea2_lora_loader.py b/tests/app/invocations/test_krea2_lora_loader.py index 2c495f1a327..63087fc2073 100644 --- a/tests/app/invocations/test_krea2_lora_loader.py +++ b/tests/app/invocations/test_krea2_lora_loader.py @@ -1,5 +1,7 @@ from types import SimpleNamespace +import pytest + from invokeai.app.invocations.krea2_lora_loader import Krea2LoRACollectionLoader, Krea2LoRALoaderInvocation from invokeai.app.invocations.model import LoRAField, ModelIdentifierField, Qwen3VLEncoderField, TransformerField from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType, SubModelType @@ -29,8 +31,13 @@ def _encoder(loras: list[LoRAField]) -> Qwen3VLEncoderField: ) -def _context() -> SimpleNamespace: - return SimpleNamespace(models=SimpleNamespace(exists=lambda _key: True)) +def _context(stored_base: BaseModelType = BaseModelType.Krea2) -> SimpleNamespace: + return SimpleNamespace( + models=SimpleNamespace( + exists=lambda _key: True, + get_config=lambda _identifier: SimpleNamespace(base=stored_base, type=ModelType.LoRA), + ) + ) def test_collection_loader_repairs_transformer_only_lora_state() -> None: @@ -97,3 +104,42 @@ def test_single_loader_rejects_non_krea_lora() -> None: assert "not Krea-2 models" in str(error) else: raise AssertionError("Expected a non-Krea LoRA to be rejected") + + +@pytest.mark.parametrize("loader_type", ["single", "collection"]) +def test_loader_rejects_forged_krea_identifier_for_non_krea_stored_model(loader_type: str) -> None: + lora = _lora("forged") + if loader_type == "single": + invocation = Krea2LoRALoaderInvocation.model_construct( + lora=lora.lora, weight=lora.weight, transformer=_transformer([]), qwen3_vl_encoder=_encoder([]) + ) + else: + invocation = Krea2LoRACollectionLoader.model_construct( + loras=[lora], transformer=_transformer([]), qwen3_vl_encoder=_encoder([]) + ) + + with pytest.raises(ValueError, match="not Krea-2"): + invocation.invoke(_context(BaseModelType.Flux)) + + +@pytest.mark.parametrize("loader_type", ["single", "collection"]) +def test_loader_rejects_conflicting_existing_weights(loader_type: str) -> None: + requested = _lora() + transformer_lora = requested.model_copy(update={"weight": 0.25}) + encoder_lora = requested.model_copy(update={"weight": 0.75}) + if loader_type == "single": + invocation = Krea2LoRALoaderInvocation.model_construct( + lora=requested.lora, + weight=requested.weight, + transformer=_transformer([transformer_lora]), + qwen3_vl_encoder=_encoder([encoder_lora]), + ) + else: + invocation = Krea2LoRACollectionLoader.model_construct( + loras=[requested], + transformer=_transformer([transformer_lora]), + qwen3_vl_encoder=_encoder([encoder_lora]), + ) + + with pytest.raises(ValueError, match="conflicting weights"): + invocation.invoke(_context()) diff --git a/tests/app/invocations/test_krea2_text_encoder.py b/tests/app/invocations/test_krea2_text_encoder.py new file mode 100644 index 00000000000..8482fb20b24 --- /dev/null +++ b/tests/app/invocations/test_krea2_text_encoder.py @@ -0,0 +1,108 @@ +from contextlib import contextmanager, nullcontext +from types import SimpleNamespace + +import pytest +import torch + +from invokeai.app.invocations.krea2_text_encoder import Krea2TextEncoderInvocation +from invokeai.app.invocations.model import LoRAField, ModelIdentifierField, Qwen3VLEncoderField +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType, SubModelType +from invokeai.backend.patches.lora_conversions.krea2_lora_constants import KREA2_LORA_QWEN3VL_PREFIX +from invokeai.backend.patches.model_patch_raw import ModelPatchRaw + + +class _Tokenizer: + def __call__(self, _text, **_kwargs): + return SimpleNamespace( + input_ids=torch.ones((1, 40), dtype=torch.long), + attention_mask=torch.ones((1, 40), dtype=torch.long), + ) + + +class _TextEncoder(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.anchor = torch.nn.Parameter(torch.zeros(1)) + + def forward(self, **_kwargs): + hidden_states = tuple(torch.full((1, 40, 4), float(index)) for index in range(36)) + return SimpleNamespace(hidden_states=hidden_states) + + +class _TokenizerInfo: + def __enter__(self): + return _Tokenizer() + + def __exit__(self, *_args): + return None + + +class _TextEncoderInfo: + @contextmanager + def model_on_device(self): + yield ({}, _TextEncoder()) + + +def _identifier(key: str, model_type: ModelType, base: BaseModelType = BaseModelType.Any) -> ModelIdentifierField: + return ModelIdentifierField(key=key, hash=f"hash-{key}", name=key, base=base, type=model_type) + + +def _invocation() -> Krea2TextEncoderInvocation: + encoder = _identifier("encoder", ModelType.Qwen3VLEncoder) + lora = _identifier("lora", ModelType.LoRA, BaseModelType.Krea2) + field = Qwen3VLEncoderField( + tokenizer=encoder.model_copy(update={"submodel_type": SubModelType.Tokenizer}), + text_encoder=encoder.model_copy(update={"submodel_type": SubModelType.TextEncoder}), + loras=[LoRAField(lora=lora, weight=0.5)], + ) + return Krea2TextEncoderInvocation.model_construct(prompt="a prompt", qwen3_vl_encoder=field) + + +def _context(lora_model) -> SimpleNamespace: + def load(identifier): + if identifier.key == "lora": + return SimpleNamespace(model=lora_model) + if identifier.submodel_type is SubModelType.Tokenizer: + return _TokenizerInfo() + return _TextEncoderInfo() + + return SimpleNamespace( + models=SimpleNamespace(load=load), util=SimpleNamespace(signal_progress=lambda _message: None) + ) + + +def test_encode_applies_qwen3_vl_lora_and_returns_selected_hidden_layers(monkeypatch) -> None: + captured = {} + + def apply_patches(**kwargs): + captured.update(kwargs) + captured["patches"] = list(kwargs["patches"]) + return nullcontext() + + monkeypatch.setattr( + "invokeai.app.invocations.krea2_text_encoder.LayerPatcher.apply_smart_model_patches", apply_patches + ) + monkeypatch.setattr( + "invokeai.app.invocations.krea2_text_encoder.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + embeds, mask = _invocation()._encode(_context(ModelPatchRaw(layers={}))) + + assert embeds.shape == (1, 6, 12, 4) + assert mask is None + assert captured["prefix"] == KREA2_LORA_QWEN3VL_PREFIX + assert captured["patches"][0][1] == 0.5 + + +def test_encode_rejects_a_loaded_non_patch_lora(monkeypatch) -> None: + def apply_patches(**kwargs): + list(kwargs["patches"]) + return nullcontext() + + monkeypatch.setattr( + "invokeai.app.invocations.krea2_text_encoder.LayerPatcher.apply_smart_model_patches", apply_patches + ) + + with pytest.raises(TypeError, match="Expected ModelPatchRaw"): + _invocation()._encode(_context(object())) diff --git a/tests/backend/model_manager/configs/test_krea2_lora_config.py b/tests/backend/model_manager/configs/test_krea2_lora_config.py index 488cb6a610a..9ac55872a44 100644 --- a/tests/backend/model_manager/configs/test_krea2_lora_config.py +++ b/tests/backend/model_manager/configs/test_krea2_lora_config.py @@ -27,6 +27,15 @@ def _ambiguous_transformer_only_lora() -> MagicMock: return mod +def _ambiguous_text_encoder_only_lora() -> MagicMock: + mod = MagicMock() + mod.load_state_dict.return_value = { + "text_encoder.language_model.layers.0.self_attn.q_proj.lora_A.weight": object(), + "text_encoder.language_model.layers.0.self_attn.q_proj.lora_B.weight": object(), + } + return mod + + @patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") def test_explicit_krea2_override_accepts_ambiguous_transformer_only_lora(_raise_if_not_file) -> None: config = LoRA_LyCORIS_Krea2_Config.from_model_on_disk( @@ -51,3 +60,18 @@ def test_explicit_krea2_override_rejects_incomplete_lora_pair(_raise_if_not_file with pytest.raises(NotAMatchError): LoRA_LyCORIS_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS, "base": BaseModelType.Krea2}) + + +@patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") +def test_explicit_krea2_override_accepts_text_encoder_only_lora(_raise_if_not_file) -> None: + config = LoRA_LyCORIS_Krea2_Config.from_model_on_disk( + _ambiguous_text_encoder_only_lora(), {**_REQUIRED_FIELDS, "base": BaseModelType.Krea2} + ) + + assert config.base is BaseModelType.Krea2 + + +@patch("invokeai.backend.model_manager.configs.lora.raise_if_not_file") +def test_automatic_probe_rejects_ambiguous_text_encoder_only_lora(_raise_if_not_file) -> None: + with pytest.raises(NotAMatchError): + LoRA_LyCORIS_Krea2_Config.from_model_on_disk(_ambiguous_text_encoder_only_lora(), {**_REQUIRED_FIELDS}) diff --git a/tests/backend/model_manager/configs/test_krea2_main_config.py b/tests/backend/model_manager/configs/test_krea2_main_config.py index dec82b797fa..b389a18fc59 100644 --- a/tests/backend/model_manager/configs/test_krea2_main_config.py +++ b/tests/backend/model_manager/configs/test_krea2_main_config.py @@ -16,6 +16,7 @@ import pytest +from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError from invokeai.backend.model_manager.configs.main import ( MainModelDefaultSettings, _get_krea2_variant_from_name, @@ -176,6 +177,18 @@ def test_turbo_filename_defaults_to_turbo(self, _rfo, _rif, _hgt, _hkk) -> None: config = Main_Checkpoint_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) assert config.variant == Krea2VariantType.Turbo + @patch("invokeai.backend.model_manager.configs.main._has_krea2_keys", return_value=True) + @patch("invokeai.backend.model_manager.configs.main._has_ggml_tensors", return_value=False) + @patch("invokeai.backend.model_manager.configs.main.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.main.raise_for_override_fields") + def test_rejects_non_safetensors_checkpoint(self, _rfo, _rif, _hgt, _hkk) -> None: + from invokeai.backend.model_manager.configs.main import Main_Checkpoint_Krea2_Config + + mod = self._make_mock_mod("krea2_turbo.bin") + + with pytest.raises(NotAMatchError, match="safetensors"): + Main_Checkpoint_Krea2_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + class TestKrea2DiffusersVariantDetection: """Main_Diffusers_Krea2_Config._get_variant reads is_distilled from model_index.json.""" diff --git a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py index b908a16fb79..0580e859ce1 100644 --- a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py +++ b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py @@ -68,8 +68,9 @@ def test_ignores_non_string_keys(self) -> None: class TestQwen3VLEncoderCheckpointConfig: - def _make_mock_mod(self, state_dict: dict) -> MagicMock: + def _make_mock_mod(self, state_dict: dict, suffix: str = ".safetensors") -> MagicMock: mod = MagicMock() + mod.path = Path(f"/fake/qwen3vl{suffix}") mod.load_state_dict.return_value = state_dict return mod @@ -78,7 +79,8 @@ def _make_mock_mod(self, state_dict: dict) -> MagicMock: def test_matches_vl_single_file(self, _rfo, _rif) -> None: mod = self._make_mock_mod( { - "model.layers.0.self_attn.q_proj.weight": object(), + "model.embed_tokens.weight": MagicMock(shape=(151936, 2560)), + "model.layers.35.self_attn.q_proj.weight": object(), "model.visual.blocks.0.attn.qkv.weight": object(), } ) @@ -99,11 +101,46 @@ def test_rejects_text_only_encoder(self, _rfo, _rif) -> None: with pytest.raises(NotAMatchError): Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_for_override_fields") + def test_rejects_non_safetensors_checkpoint(self, _rfo, _rif) -> None: + mod = self._make_mock_mod( + { + "model.layers.35.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + }, + suffix=".bin", + ) + + with pytest.raises(NotAMatchError, match="safetensors"): + Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.qwen3_vl_encoder.raise_for_override_fields") + def test_rejects_non_4b_checkpoint_shape(self, _rfo, _rif) -> None: + mod = self._make_mock_mod( + { + "model.embed_tokens.weight": MagicMock(shape=(151936, 4096)), + "model.layers.35.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + } + ) + + with pytest.raises(NotAMatchError, match="4B|hidden"): + Qwen3VLEncoder_Checkpoint_Config.from_model_on_disk(mod, {**_REQUIRED_FIELDS}) + class TestQwen3VLEncoderDirectoryConfig: @staticmethod - def _write_config(path: Path) -> None: - path.write_text(json.dumps({"architectures": ["Qwen3VLModel"]})) + def _write_config(path: Path, *, hidden_size: int = 2560, num_hidden_layers: int = 36) -> None: + path.write_text( + json.dumps( + { + "architectures": ["Qwen3VLModel"], + "text_config": {"hidden_size": hidden_size, "num_hidden_layers": num_hidden_layers}, + } + ) + ) @staticmethod def _fields(path: Path) -> dict: @@ -143,3 +180,70 @@ def test_accepts_nested_layout_with_weights_and_tokenizer(self, tmp_path: Path) config = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) assert config.format is ModelFormat.Qwen3VLEncoder + + @pytest.mark.parametrize(("hidden_size", "num_hidden_layers"), [(4096, 36), (2560, 28)]) + def test_rejects_non_4b_directory_config(self, tmp_path: Path, hidden_size: int, num_hidden_layers: int) -> None: + self._write_config(tmp_path / "config.json", hidden_size=hidden_size, num_hidden_layers=num_hidden_layers) + (tmp_path / "model.safetensors").touch() + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="4B|hidden|layers"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + def test_rejects_malformed_text_config(self, tmp_path: Path) -> None: + (tmp_path / "config.json").write_text(json.dumps({"architectures": ["Qwen3VLModel"], "text_config": []})) + (tmp_path / "model.safetensors").touch() + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="text_config"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + @pytest.mark.parametrize("artifact", ["adapter_model.safetensors", "training_args.bin"]) + def test_rejects_unrecognized_weight_artifact(self, tmp_path: Path, artifact: str) -> None: + self._write_config(tmp_path / "config.json") + (tmp_path / artifact).touch() + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="weights"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + def test_rejects_incomplete_sharded_checkpoint(self, tmp_path: Path) -> None: + self._write_config(tmp_path / "config.json") + (tmp_path / "model-00001-of-00002.safetensors").touch() + (tmp_path / "model.safetensors.index.json").write_text( + json.dumps( + { + "weight_map": { + "language_model.layers.0.weight": "model-00001-of-00002.safetensors", + "language_model.layers.35.weight": "model-00002-of-00002.safetensors", + } + } + ) + ) + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="missing|weights"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + @pytest.mark.parametrize("index_name", ["model.safetensors.index.json", "pytorch_model.bin.index.json"]) + def test_accepts_complete_sharded_checkpoint(self, tmp_path: Path, index_name: str) -> None: + self._write_config(tmp_path / "config.json") + suffix = "safetensors" if index_name.startswith("model") else "bin" + shard_names = [f"model-00001-of-00002.{suffix}", f"model-00002-of-00002.{suffix}"] + for shard_name in shard_names: + (tmp_path / shard_name).touch() + (tmp_path / index_name).write_text( + json.dumps( + { + "weight_map": { + "language_model.layers.0.weight": shard_names[0], + "language_model.layers.35.weight": shard_names[1], + } + } + ) + ) + (tmp_path / "tokenizer.json").touch() + + config = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + assert config.type is ModelType.Qwen3VLEncoder diff --git a/tests/backend/model_manager/load/test_diffusers_039_compatibility.py b/tests/backend/model_manager/load/test_diffusers_039_compatibility.py new file mode 100644 index 00000000000..1e305da9d7a --- /dev/null +++ b/tests/backend/model_manager/load/test_diffusers_039_compatibility.py @@ -0,0 +1,171 @@ +from inspect import signature + +import accelerate +import diffusers +import pytest +from packaging.version import Version + + +def test_pinned_diffusers_exposes_existing_and_krea_model_contracts() -> None: + assert Version(diffusers.__version__) == Version("0.39.0") + + expected_symbols = ( + "AutoencoderKLFlux2", + "FluxTransformer2DModel", + "Flux2Transformer2DModel", + "Krea2Transformer2DModel", + "QwenImageTransformer2DModel", + "StableDiffusionPipeline", + "StableDiffusionXLPipeline", + "ZImageTransformer2DModel", + ) + for symbol in expected_symbols: + assert getattr(diffusers, symbol, None) is not None, f"diffusers is missing {symbol}" + + +def test_flow_match_scheduler_keeps_custom_sigma_and_shift_api() -> None: + parameters = signature(diffusers.FlowMatchEulerDiscreteScheduler.set_timesteps).parameters + + assert "sigmas" in parameters + assert "mu" in parameters + assert "device" in parameters + + +@pytest.mark.parametrize( + "factory", + [ + pytest.param( + lambda: diffusers.FluxTransformer2DModel( + in_channels=4, + num_layers=1, + num_single_layers=1, + attention_head_dim=4, + num_attention_heads=1, + joint_attention_dim=8, + pooled_projection_dim=8, + axes_dims_rope=(1, 1, 2), + ), + id="flux", + ), + pytest.param( + lambda: diffusers.Flux2Transformer2DModel( + in_channels=4, + num_layers=1, + num_single_layers=1, + attention_head_dim=4, + num_attention_heads=1, + joint_attention_dim=8, + timestep_guidance_channels=4, + mlp_ratio=2, + axes_dims_rope=(1, 1, 1, 1), + ), + id="flux2", + ), + pytest.param( + lambda: diffusers.QwenImageTransformer2DModel( + patch_size=1, + in_channels=4, + out_channels=4, + num_layers=1, + attention_head_dim=8, + num_attention_heads=1, + joint_attention_dim=8, + axes_dims_rope=(2, 2, 4), + ), + id="qwen-image", + ), + pytest.param( + lambda: diffusers.ZImageTransformer2DModel( + all_patch_size=(1,), + all_f_patch_size=(1,), + in_channels=4, + dim=8, + n_layers=1, + n_refiner_layers=1, + n_heads=1, + n_kv_heads=1, + cap_feat_dim=8, + axes_dims=[2, 2, 4], + axes_lens=[8, 8, 8], + ), + id="z-image", + ), + pytest.param( + lambda: diffusers.Krea2Transformer2DModel( + in_channels=4, + num_layers=1, + attention_head_dim=8, + num_attention_heads=1, + num_key_value_heads=1, + intermediate_size=16, + timestep_embed_dim=8, + text_hidden_dim=8, + num_text_layers=2, + text_num_attention_heads=1, + text_num_key_value_heads=1, + text_intermediate_size=16, + num_layerwise_text_blocks=1, + num_refiner_text_blocks=1, + axes_dims_rope=(2, 2, 4), + ), + id="krea-2", + ), + pytest.param( + lambda: diffusers.AutoencoderKLWan( + base_dim=4, + decoder_base_dim=4, + z_dim=4, + dim_mult=[1, 1], + num_res_blocks=1, + temperal_downsample=[False], + latents_mean=[0.0] * 4, + latents_std=[1.0] * 4, + scale_factor_temporal=1, + scale_factor_spatial=2, + ), + id="anima-vae", + ), + ], +) +def test_pinned_diffusers_constructs_representative_transformer_and_vae_configs(factory) -> None: + with accelerate.init_empty_weights(): + model = factory() + + assert model is not None + + +@pytest.mark.parametrize( + "factory", + [ + pytest.param( + lambda: diffusers.StableDiffusionPipeline( + vae=None, + text_encoder=None, + tokenizer=None, + unet=None, + scheduler=None, + safety_checker=None, + feature_extractor=None, + requires_safety_checker=False, + ), + id="stable-diffusion", + ), + pytest.param( + lambda: diffusers.StableDiffusionXLPipeline( + vae=None, + text_encoder=None, + text_encoder_2=None, + tokenizer=None, + tokenizer_2=None, + unet=None, + scheduler=None, + add_watermarker=False, + ), + id="stable-diffusion-xl", + ), + ], +) +def test_pinned_diffusers_constructs_existing_stable_diffusion_pipelines(factory) -> None: + pipeline = factory() + + assert pipeline is not None diff --git a/tests/backend/model_manager/load/test_krea2_loader_boundaries.py b/tests/backend/model_manager/load/test_krea2_loader_boundaries.py new file mode 100644 index 00000000000..cb8dfe21d7a --- /dev/null +++ b/tests/backend/model_manager/load/test_krea2_loader_boundaries.py @@ -0,0 +1,148 @@ +from types import SimpleNamespace +from unittest.mock import MagicMock + +import torch + +from invokeai.backend.model_manager.configs.main import ( + Main_Checkpoint_Krea2_Config, + Main_Diffusers_Krea2_Config, + Main_GGUF_Krea2_Config, +) +from invokeai.backend.model_manager.configs.qwen3_vl_encoder import Qwen3VLEncoder_Qwen3VLEncoder_Config +from invokeai.backend.model_manager.load.model_loaders.krea2 import ( + Krea2CheckpointModel, + Krea2DiffusersModel, + Krea2GGUFCheckpointModel, + Qwen3VLEncoderLoader, +) +from invokeai.backend.model_manager.taxonomy import Krea2VariantType, SubModelType + + +class _TinyKrea2Transformer(torch.nn.Module): + def __init__(self, **_kwargs) -> None: + super().__init__() + self.weight = torch.nn.Parameter(torch.empty(2, 2)) + + +def test_single_file_loader_constructs_and_materializes_model(monkeypatch, tmp_path) -> None: + import diffusers + import safetensors.torch + + checkpoint_path = tmp_path / "krea2.safetensors" + checkpoint_path.touch() + config = Main_Checkpoint_Krea2_Config.model_construct( + path=str(checkpoint_path), variant=Krea2VariantType.Turbo, fp8_storage=None + ) + ram_cache = SimpleNamespace(make_room=MagicMock()) + loader = object.__new__(Krea2CheckpointModel) + loader._ram_cache = ram_cache + loader._apply_fp8_layerwise_casting = lambda model, _config, _submodel: model + + monkeypatch.setattr(diffusers, "Krea2Transformer2DModel", _TinyKrea2Transformer, raising=False) + monkeypatch.setattr(safetensors.torch, "load_file", lambda _path: {"weight": torch.ones(2, 2)}) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_torch_device", + lambda: torch.device("cpu"), + ) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + model = loader._load_from_singlefile(config) + + assert isinstance(model, _TinyKrea2Transformer) + assert model.weight.device.type == "cpu" + assert torch.equal(model.weight, torch.ones(2, 2)) + ram_cache.make_room.assert_called_once() + + +def test_diffusers_loader_reaches_transformer_from_pretrained(monkeypatch, tmp_path) -> None: + config = Main_Diffusers_Krea2_Config.model_construct(path=str(tmp_path), repo_variant=None) + loader = object.__new__(Krea2DiffusersModel) + loaded_model = object() + load_class = SimpleNamespace(from_pretrained=MagicMock(return_value=loaded_model)) + loader.get_hf_load_class = lambda _path, _submodel: load_class + loader._apply_fp8_layerwise_casting = lambda model, _config, _submodel: model + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_torch_device", + lambda: torch.device("cpu"), + ) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + model = loader._load_model(config, SubModelType.Transformer) + + assert model is loaded_model + load_class.from_pretrained.assert_called_once_with( + tmp_path / "transformer", torch_dtype=torch.float32, variant=None + ) + + +def test_gguf_loader_constructs_and_materializes_model(monkeypatch, tmp_path) -> None: + import diffusers + + checkpoint_path = tmp_path / "krea2.gguf" + checkpoint_path.touch() + config = Main_GGUF_Krea2_Config.model_construct(path=str(checkpoint_path), variant=Krea2VariantType.Turbo) + loader = object.__new__(Krea2GGUFCheckpointModel) + + monkeypatch.setattr(diffusers, "Krea2Transformer2DModel", _TinyKrea2Transformer, raising=False) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.gguf_sd_loader", + lambda _path, *, compute_dtype: {"weight": torch.ones(2, 2, dtype=compute_dtype)}, + ) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_torch_device", + lambda: torch.device("cpu"), + ) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + model = loader._load_from_gguf(config) + + assert isinstance(model, _TinyKrea2Transformer) + assert model.weight.device.type == "cpu" + assert torch.equal(model.weight, torch.ones(2, 2)) + + +def test_directory_encoder_loader_reaches_transformers_from_pretrained(monkeypatch, tmp_path) -> None: + import transformers + + (tmp_path / "config.json").write_text("{}") + config = Qwen3VLEncoder_Qwen3VLEncoder_Config.model_construct(path=str(tmp_path)) + loader = object.__new__(Qwen3VLEncoderLoader) + text_config = SimpleNamespace(rope_parameters={"rope_type": "default"}, rope_scaling=None) + encoder_config = SimpleNamespace(text_config=text_config) + loaded_model = object() + from_pretrained = MagicMock(return_value=loaded_model) + + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.AutoConfig.from_pretrained", + lambda *_args, **_kwargs: encoder_config, + ) + monkeypatch.setattr(transformers.Qwen3VLModel, "from_pretrained", from_pretrained) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_torch_device", + lambda: torch.device("cpu"), + ) + monkeypatch.setattr( + "invokeai.backend.model_manager.load.model_loaders.krea2.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + model = loader._load_model(config, SubModelType.TextEncoder) + + assert model is loaded_model + assert text_config.rope_scaling == text_config.rope_parameters + from_pretrained.assert_called_once_with( + tmp_path, + config=encoder_config, + torch_dtype=torch.float32, + low_cpu_mem_usage=True, + local_files_only=True, + ) From 197ce76d0245482083c4bd160836728a32bc4e8d Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Tue, 14 Jul 2026 02:18:04 +0200 Subject: [PATCH 14/17] fix(krea2): use per-prompt position ids for the CFG uncond pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rotary position ids (text tokens + image grid) were built once from the positive prompt's length and reused for the negative pass. When the negative prompt tokenizes to a different length than the positive one, the rotary embedding ends up a different length than the uncond query sequence and the transformer crashes in apply_rotary_emb ("tensor a (N) must match tensor b (M)"). Build a separate neg_position_ids from the negative prompt's length and pass it to the uncond transformer call. txt2img with CFG off (distilled Turbo) is unaffected — only the cond pass runs there. Adds a regression test that drives differing positive/negative prompt lengths and asserts len(position_ids) == text_len + image_tokens for each pass. --- invokeai/app/invocations/krea2_denoise.py | 10 ++++- tests/app/invocations/test_krea2_denoise.py | 46 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index 19202955746..9df8f20f855 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -292,6 +292,14 @@ def _run_diffusion(self, context: InvocationContext): # Position ids: text tokens at origin, image tokens carry their grid coords. text_seq_len = pos_prompt_embeds.shape[1] position_ids = prepare_position_ids(text_seq_len, grid_height, grid_width, device) + # The negative prompt can tokenize to a different length than the positive prompt, so it needs its + # own position ids. Reusing the positive ids would leave the rotary embedding (text + image tokens) + # a different length than the uncond query sequence and crash in the transformer's apply_rotary_emb. + neg_position_ids = ( + prepare_position_ids(neg_prompt_embeds.shape[1], grid_height, grid_width, device) + if neg_prompt_embeds is not None + else None + ) # Inpaint extension operates in 4D, so unpack/repack around each merge. inpaint_mask = self._prep_inpaint_mask(context, noise) @@ -367,7 +375,7 @@ def _run_diffusion(self, context: InvocationContext): encoder_hidden_states=neg_prompt_embeds, encoder_attention_mask=neg_prompt_mask, timestep=timestep, - position_ids=position_ids, + position_ids=neg_position_ids, return_dict=False, )[0] noise_pred = noise_pred_uncond + cfg_scale[step_idx] * (noise_pred_cond - noise_pred_uncond) diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py index 75c159b6c18..bbfd245ad18 100644 --- a/tests/app/invocations/test_krea2_denoise.py +++ b/tests/app/invocations/test_krea2_denoise.py @@ -251,3 +251,49 @@ def merge_intermediate_latents_with_init_latents(self, latents, sigma): assert latents.shape == (1, KREA2_LATENT_CHANNELS, 1, 2, 2) assert len(merge_sigmas) == 2 assert transformer.conditioning_values == [1.0, 1.0] + + +def test_run_diffusion_uses_per_prompt_position_ids_when_lengths_differ(monkeypatch, tmp_path) -> None: + # Regression: the positive and negative prompts can tokenize to different lengths. The rotary position + # ids (text tokens + image grid) must match *each pass's own* text length. Reusing the positive prompt's + # position ids for the uncond pass leaves the rotary embedding a different length than the negative + # query sequence, which crashes in the real transformer's apply_rotary_emb. + _patch_runtime(monkeypatch) + + image_seq_len = 1 # width=height=16 -> 2x2 latent -> a single 2x2 patch + + class _PositionIdChecker: + def __call__(self, *, hidden_states, encoder_hidden_states, position_ids, **_kwargs): + text_len = encoder_hidden_states.shape[1] + pos_len = position_ids.shape[0] + # The invariant the real Krea2Transformer2DModel enforces: rotary length == text + image tokens. + assert pos_len == text_len + image_seq_len, ( + f"position_ids length {pos_len} must equal text length {text_len} + image tokens {image_seq_len}" + ) + return (torch.zeros_like(hidden_states),) + + transformer = _PositionIdChecker() + + # Positive prompt is longer than the negative prompt (3 vs. 2 text tokens). + conditionings = { + "positive": ConditioningFieldData(conditionings=[Krea2ConditioningInfo(prompt_embeds=torch.ones(1, 3, 12, 8))]), + "negative": ConditioningFieldData( + conditionings=[Krea2ConditioningInfo(prompt_embeds=torch.zeros(1, 2, 12, 8))] + ), + } + config = SimpleNamespace(format=ModelFormat.Checkpoint, variant=Krea2VariantType.Turbo) + context = SimpleNamespace( + models=SimpleNamespace( + load=lambda _identifier: _TransformerInfo(transformer), + get_config=lambda _identifier: config, + get_absolute_path=lambda _config: tmp_path, + ), + conditioning=SimpleNamespace(load=lambda name: conditionings[name]), + tensors=SimpleNamespace(load=lambda _name: None), + util=SimpleNamespace(sd_step_callback=lambda *_args: None), + ) + + # cfg_scale > 1 so both the cond (positive) and uncond (negative) passes run each step. Without the fix, + # the uncond pass receives the positive prompt's position ids and the checker above fails. + latents = _runtime_invocation(cfg_scale=2.0)._run_diffusion(context) + assert latents.shape == (1, KREA2_LATENT_CHANNELS, 1, 2, 2) From b0219e391e654c088ee950bcd73bbb6fcb4e6050 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Tue, 14 Jul 2026 03:04:55 +0200 Subject: [PATCH 15/17] fix(krea2): resolve deep-review findings across encoder, loaders, LoRA and tokenization HIGH: - qwen3_encoder: _has_qwen_vl_visual_tower now also matches the nested model.visual.* layout (mirroring _is_qwen3_vl_encoder_state_dict), so a single-file Qwen3-VL 4B encoder no longer matches BOTH the text-only Qwen3 and the Qwen3-VL configs. The nondeterministic tie-break could register it as the wrong type and hide it from Krea-2's encoder dropdown, hard-blocking the single-file/GGUF install path. MEDIUM: - krea2_text_encoder: tokenize (prefix+prompt) and the assistant-turn suffix separately and concatenate, so prompts over the token budget keep the suffix (append-after-truncate) instead of having it silently cut off. LOW: - main: _get_krea2_variant_from_name lets "turbo" win and only matches "raw"/"base" as whole tokens, so Turbo files like "krea2_turbo_baseline_q4.gguf" are not read as Base. - krea2_lora_conversion_utils: raise a descriptive ValueError (not a bare KeyError) when a PEFT layer has lora_A without a matching lora_B. - factory: read config.json as UTF-8 so a non-ASCII config is not mis-treated as unrecognized (and the model dir wrongly rejected) under a cp1252 locale. - krea2 loader: _reject_incomplete_load also inspects named_buffers(), so a checkpoint missing a persistent buffer fails at load time rather than mid-inference. Tests: Qwen3-VL dual-match rejection, long-prompt suffix preservation, addKrea2LoRAs reroute, rebalance gains/validation, seed-variance determinism/out-of-place, variant filename heuristic, incomplete-LoRA error, UTF-8 config dir, meta-buffer rejection. --- .../app/invocations/krea2_text_encoder.py | 25 +++- .../backend/model_manager/configs/factory.py | 5 +- .../backend/model_manager/configs/main.py | 16 +- .../model_manager/configs/qwen3_encoder.py | 22 +-- .../model_manager/load/model_loaders/krea2.py | 16 +- .../krea2_lora_conversion_utils.py | 11 +- .../graph/generation/addKrea2LoRAs.test.ts | 126 ++++++++++++++++ tests/app/invocations/test_krea2_enhancers.py | 140 ++++++++++++++++++ .../invocations/test_krea2_text_encoder.py | 83 +++++++++++ .../configs/test_krea2_main_config.py | 7 + .../configs/test_model_path_validation.py | 12 ++ .../configs/test_qwen3_encoder_config.py | 46 +++++- .../load/test_krea2_state_dict_utils.py | 16 +- .../test_krea2_lora_conversion_utils.py | 16 ++ 14 files changed, 510 insertions(+), 31 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.test.ts create mode 100644 tests/app/invocations/test_krea2_enhancers.py diff --git a/invokeai/app/invocations/krea2_text_encoder.py b/invokeai/app/invocations/krea2_text_encoder.py index 852f774953c..2e0f649c1d1 100644 --- a/invokeai/app/invocations/krea2_text_encoder.py +++ b/invokeai/app/invocations/krea2_text_encoder.py @@ -77,9 +77,13 @@ def _encode(self, context: InvocationContext) -> tuple[torch.Tensor, torch.Tenso tokenizer_info = context.models.load(self.qwen3_vl_encoder.tokenizer) text_encoder_info = context.models.load(self.qwen3_vl_encoder.text_encoder) - text = _KREA2_PREFIX + self.prompt + _KREA2_SUFFIX - # diffusers caps the tokenizer length at max_sequence_length + start_idx - num_suffix_tokens. - max_length = KREA2_MAX_SEQ_LEN + KREA2_START_IDX - KREA2_NUM_SUFFIX_TOKENS + # diffusers tokenizes (prefix + prompt) and the assistant-turn suffix separately, then + # concatenates - so the suffix always survives truncation. Building one string and truncating it + # (right-truncation) drops the suffix for long (>~500-token) prompts, corrupting the trained token + # layout that the fixed prefix-drop (KREA2_START_IDX) and suffix accounting depend on. + body_text = _KREA2_PREFIX + self.prompt + # Reserve room for the suffix (diffusers: max_sequence_length + start_idx - num_suffix_tokens). + body_max_length = KREA2_MAX_SEQ_LEN + KREA2_START_IDX - KREA2_NUM_SUFFIX_TOKENS context.util.signal_progress("Running Qwen3-VL text encoder") @@ -100,14 +104,19 @@ def _encode(self, context: InvocationContext) -> tuple[torch.Tensor, torch.Tenso ) ) - model_inputs = tokenizer( - text, - max_length=max_length, + body_inputs = tokenizer( + body_text, + max_length=body_max_length, truncation=True, return_tensors="pt", ) - input_ids = model_inputs.input_ids.to(device=device) - attention_mask = model_inputs.attention_mask.to(device=device) + # Append the suffix AFTER truncation so it can never be cut. add_special_tokens=False keeps it + # to exactly the assistant-turn tokens (no extra BOS), matching the reference token layout. + suffix_inputs = tokenizer(_KREA2_SUFFIX, add_special_tokens=False, return_tensors="pt") + input_ids = torch.cat([body_inputs.input_ids, suffix_inputs.input_ids], dim=1).to(device=device) + attention_mask = torch.cat([body_inputs.attention_mask, suffix_inputs.attention_mask], dim=1).to( + device=device + ) outputs = text_encoder( input_ids=input_ids, diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index 92865dd4cfd..8a04e526259 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -430,7 +430,10 @@ def _validate_path_looks_like_model(path: Path) -> None: if not config_path.exists(): continue try: - config = json.loads(config_path.read_text()) + # Model config.json files are UTF-8; read explicitly so a non-ASCII value does not + # raise UnicodeDecodeError under a cp1252 (Windows) locale and get mis-treated as + # "unrecognized", which would wrongly reject a valid model directory. + config = json.loads(config_path.read_text(encoding="utf-8")) except (OSError, ValueError): continue if config_name == "model_index.json": diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index 7bd79da9d50..e2554189ee0 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -206,12 +206,20 @@ def _get_krea2_variant_from_name(name: str) -> Krea2VariantType: """Guess the Krea-2 variant from a single-file/GGUF filename. Turbo and Raw (Base) share the identical transformer architecture, so a single-file checkpoint - cannot be distinguished from its weights. Filenames containing "raw" or "base" (e.g. - "Krea-2-Raw", "krea2_base_q4") indicate the undistilled Base model; everything else defaults to - the distilled Turbo. The user can override the variant in the model manager. + cannot be distinguished from its weights. Filenames with a "raw"/"base" token (e.g. "Krea-2-Raw", + "krea2_base_q4") indicate the undistilled Base model; everything else defaults to the distilled + Turbo. The user can override the variant in the model manager. """ lowered = name.lower() - if "raw" in lowered or "base" in lowered: + # "turbo" is a strong positive signal for the distilled checkpoint and wins outright, so a Turbo file + # whose name merely *contains* "base"/"raw" as a substring (e.g. "baseline", "database", "raw_export") + # is not misread as Base. + if "turbo" in lowered: + return Krea2VariantType.Turbo + # Otherwise match "raw"/"base" only as a whole token delimited by non-alphanumeric separators + # ("-", "_", ".") - not as an arbitrary substring. + tokens = re.split(r"[^a-z0-9]+", lowered) + if "raw" in tokens or "base" in tokens: return Krea2VariantType.Base return Krea2VariantType.Turbo diff --git a/invokeai/backend/model_manager/configs/qwen3_encoder.py b/invokeai/backend/model_manager/configs/qwen3_encoder.py index b026c03db2f..2b072e9f3d8 100644 --- a/invokeai/backend/model_manager/configs/qwen3_encoder.py +++ b/invokeai/backend/model_manager/configs/qwen3_encoder.py @@ -47,17 +47,21 @@ def _has_ggml_tensors(state_dict: dict[str | int, Any]) -> bool: def _has_qwen_vl_visual_tower(state_dict: dict[str | int, Any]) -> bool: - """Check if state dict bundles a Qwen2.5-VL / Qwen2-VL vision tower. - - Qwen-VL encoders ship the visual tower (`visual.blocks.*`, `visual.patch_embed.*`) - alongside the language model, whereas a text-only Qwen3 encoder never does. A Qwen-VL - file otherwise satisfies the Qwen3 key heuristic (it has `model.layers.*` / - `model.embed_tokens.weight` too), so without this check it matches *both* the Qwen3 and - the QwenVLEncoder configs and the tiebreak can misroute it to Qwen3. We use it to keep - the two mutually exclusive. + """Check if state dict bundles a Qwen-VL vision tower (Qwen2-VL / Qwen2.5-VL / Qwen3-VL). + + VL encoders ship a visual tower alongside the language model, whereas a text-only Qwen3 encoder + never does. A VL file otherwise satisfies the Qwen3 key heuristic (it has ``model.layers.*`` / + ``model.embed_tokens.weight`` too), so without this check it matches *both* the text-only Qwen3 + config and the VL config and the tiebreak can misroute it. We use it to keep them mutually exclusive. + + The predicate deliberately mirrors ``_is_qwen3_vl_encoder_state_dict`` (qwen3_vl_encoder.py) so both + sides agree on what counts as a visual tower - crucially including the nested ``model.visual.*`` + layout that ComfyUI single-file Qwen3-VL checkpoints use. Matching only bare ``visual.blocks.*`` + missed that layout, letting a single-file Qwen3-VL 4B encoder match both configs and get misrouted to + the text-only Qwen3 type - silently breaking the single-file/GGUF Krea-2 encoder install path. """ for key in state_dict.keys(): - if isinstance(key, str) and (key.startswith("visual.blocks.") or key.startswith("visual.patch_embed.")): + if isinstance(key, str) and (key.startswith(("visual.", "model.visual.")) or ".visual." in key): return True return False diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py index 557c1db133f..0a219577a7f 100644 --- a/invokeai/backend/model_manager/load/model_loaders/krea2.py +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -452,17 +452,25 @@ def _remap_qwen3vl_singlefile_keys(sd: dict[str, Any]) -> dict[str, Any]: def _reject_incomplete_load(model: Any, *, what: str) -> None: - """Raise if a ``load_state_dict(strict=False)`` left required parameters on the meta device. + """Raise if a ``load_state_dict(strict=False)`` left required tensors on the meta device. ``strict=False`` is used to tolerate benign extra/renamed keys, but it also silently accepts a checkpoint that omits required weights — those tensors stay on the meta device and only fail much - later during inference. Reject such loads here, naming the offending parameters, so an incomplete, + later during inference. Reject such loads here, naming the offending tensors, so an incomplete, misidentified, or differently-converted checkpoint fails at load time with an actionable message. + + Both parameters *and persistent buffers* are checked: ``accelerate.init_empty_weights()`` places + buffers on the meta device too, so a native/GGUF checkpoint that omits a persistent buffer would + slip past a parameters-only guard and fail mid-inference instead of at load time. """ - still_meta = [name for name, p in model.named_parameters() if getattr(p, "is_meta", False)] + still_meta = [ + name + for name, tensor in (*model.named_parameters(), *model.named_buffers()) + if getattr(tensor, "is_meta", False) + ] if still_meta: raise RuntimeError( - f"{what} is incomplete: {len(still_meta)} parameter(s) were not provided by the checkpoint " + f"{what} is incomplete: {len(still_meta)} tensor(s) were not provided by the checkpoint " f"and remain uninitialized (meta device). First few: {still_meta[:8]}. The file is likely " "incomplete, misidentified, or uses a key layout that needs conversion." ) diff --git a/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py index 04b8de2deb5..75d6f921406 100644 --- a/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py +++ b/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py @@ -57,7 +57,7 @@ def lora_model_from_krea2_state_dict(state_dict: Dict[str, torch.Tensor], alpha: ) for layer_key, layer_dict in grouped_state_dict.items(): - values = _get_lora_layer_values(layer_dict, alpha) + values = _get_lora_layer_values(layer_key, layer_dict, alpha) is_text_encoder = False clean_key = layer_key @@ -82,9 +82,16 @@ def lora_model_from_krea2_state_dict(state_dict: Dict[str, torch.Tensor], alpha: return ModelPatchRaw(layers=layers) -def _get_lora_layer_values(layer_dict: dict[str, torch.Tensor], alpha: float | None) -> dict[str, torch.Tensor]: +def _get_lora_layer_values( + layer_key: str, layer_dict: dict[str, torch.Tensor], alpha: float | None +) -> dict[str, torch.Tensor]: """Convert PEFT (lora_A/lora_B) layer values to internal (lora_down/lora_up) format.""" if "lora_A.weight" in layer_dict: + if "lora_B.weight" not in layer_dict: + raise ValueError( + f"Malformed Krea-2 LoRA: layer '{layer_key}' has lora_A.weight but no matching lora_B.weight. " + "The LoRA file is incomplete or corrupt." + ) values = { "lora_down.weight": layer_dict["lora_A.weight"], "lora_up.weight": layer_dict["lora_B.weight"], diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.test.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.test.ts new file mode 100644 index 00000000000..0250fbf969d --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addKrea2LoRAs.test.ts @@ -0,0 +1,126 @@ +import type { Invocation } from 'services/api/types'; +import { describe, expect, it, vi } from 'vitest'; + +let nextId = 0; +vi.mock('features/controlLayers/konva/util', () => ({ + getPrefixedId: (prefix: string) => `${prefix}:${nextId++}`, +})); + +import { addKrea2LoRAs } from './addKrea2LoRAs'; +import { Graph } from './Graph'; + +const model = { key: 'krea2-model', hash: 'h', name: 'Krea-2', base: 'krea-2', type: 'main' }; + +const buildBaseGraph = (withNeg: boolean) => { + nextId = 0; + const g = new Graph('test'); + const modelLoader = g.addNode({ + type: 'krea2_model_loader', + id: 'model_loader', + model, + } as Invocation<'krea2_model_loader'>); + const denoise = g.addNode({ type: 'krea2_denoise', id: 'denoise' } as Invocation<'krea2_denoise'>); + const posCond = g.addNode({ type: 'krea2_text_encoder', id: 'pos_prompt' } as Invocation<'krea2_text_encoder'>); + const negCond = withNeg + ? g.addNode({ type: 'krea2_text_encoder', id: 'neg_prompt' } as Invocation<'krea2_text_encoder'>) + : null; + + // The direct model -> denoise / text-encoder edges that addKrea2LoRAs must reroute. + g.addEdge(modelLoader, 'transformer', denoise, 'transformer'); + g.addEdge(modelLoader, 'qwen3_vl_encoder', posCond, 'qwen3_vl_encoder'); + if (negCond) { + g.addEdge(modelLoader, 'qwen3_vl_encoder', negCond, 'qwen3_vl_encoder'); + } + + return { g, modelLoader, denoise, posCond, negCond }; +}; + +const stateWith = (loras: unknown[]) => ({ loras: { loras } }) as never; + +const enabledKrea2Lora = { + id: 'lora-1', + isEnabled: true, + weight: 0.8, + model: { key: 'lora-key', hash: 'lora-hash', name: 'My Krea LoRA', base: 'krea-2', type: 'lora' }, +}; + +describe('addKrea2LoRAs', () => { + it('reroutes the transformer and both text encoders through the collection loader', () => { + const { g, modelLoader, denoise, posCond, negCond } = buildBaseGraph(true); + + addKrea2LoRAs(stateWith([enabledKrea2Lora]), g, denoise, modelLoader, posCond, negCond); + + const graph = g.getGraph(); + const nodeTypes = Object.values(graph.nodes).map((n) => n.type); + expect(nodeTypes).toContain('krea2_lora_collection_loader'); + expect(nodeTypes).toContain('collect'); + expect(nodeTypes).toContain('lora_selector'); + + const collectionLoaderId = Object.values(graph.nodes).find((n) => n.type === 'krea2_lora_collection_loader')!.id; + + // The single edge into denoise.transformer now originates from the collection loader (old direct edge gone). + const transformerEdges = graph.edges.filter( + (e) => e.destination.node_id === denoise.id && e.destination.field === 'transformer' + ); + expect(transformerEdges).toHaveLength(1); + expect(transformerEdges[0]!.source.node_id).toBe(collectionLoaderId); + + // Both the positive and negative encoders are rerouted to the collection loader. + for (const cond of [posCond, negCond!]) { + const encoderEdges = graph.edges.filter( + (e) => e.destination.node_id === cond.id && e.destination.field === 'qwen3_vl_encoder' + ); + expect(encoderEdges).toHaveLength(1); + expect(encoderEdges[0]!.source.node_id).toBe(collectionLoaderId); + } + + // No stale direct edge remains from the model loader to denoise or the encoders. + const staleDirectEdges = graph.edges.filter( + (e) => + e.source.node_id === modelLoader.id && [denoise.id, posCond.id, negCond!.id].includes(e.destination.node_id) + ); + expect(staleDirectEdges).toHaveLength(0); + + // The lora selector feeds the collector, which feeds the collection loader. + const selectorId = Object.values(graph.nodes).find((n) => n.type === 'lora_selector')!.id; + const collectorId = Object.values(graph.nodes).find((n) => n.type === 'collect')!.id; + expect(graph.edges.some((e) => e.source.node_id === selectorId && e.destination.node_id === collectorId)).toBe( + true + ); + expect( + graph.edges.some((e) => e.source.node_id === collectorId && e.destination.node_id === collectionLoaderId) + ).toBe(true); + }); + + it('does nothing (keeps direct edges) when no Krea-2 LoRAs are enabled', () => { + const { g, modelLoader, denoise, posCond, negCond } = buildBaseGraph(true); + + addKrea2LoRAs(stateWith([]), g, denoise, modelLoader, posCond, negCond); + + const graph = g.getGraph(); + expect(Object.values(graph.nodes).map((n) => n.type)).not.toContain('krea2_lora_collection_loader'); + const transformerEdges = graph.edges.filter( + (e) => e.destination.node_id === denoise.id && e.destination.field === 'transformer' + ); + expect(transformerEdges).toHaveLength(1); + expect(transformerEdges[0]!.source.node_id).toBe(modelLoader.id); + }); + + it('ignores disabled and non-Krea-2 LoRAs', () => { + const { g, modelLoader, denoise, posCond, negCond } = buildBaseGraph(false); + + addKrea2LoRAs( + stateWith([ + { ...enabledKrea2Lora, isEnabled: false }, + { ...enabledKrea2Lora, id: 'flux', model: { ...enabledKrea2Lora.model, base: 'flux' } }, + ]), + g, + denoise, + modelLoader, + posCond, + negCond + ); + + expect(Object.values(g.getGraph().nodes).map((n) => n.type)).not.toContain('krea2_lora_collection_loader'); + }); +}); diff --git a/tests/app/invocations/test_krea2_enhancers.py b/tests/app/invocations/test_krea2_enhancers.py new file mode 100644 index 00000000000..99f21001e47 --- /dev/null +++ b/tests/app/invocations/test_krea2_enhancers.py @@ -0,0 +1,140 @@ +"""Tests for the optional Krea-2 conditioning enhancers (rebalance + seed variance). + +Both operate on the 4D ``prompt_embeds (B, seq, 12, hidden)`` conditioning between the text encoder and +denoise. The load-bearing logic - the per-layer gain broadcast, the exact-count weight validation, and the +seeded-noise determinism / out-of-place property - is exercised here with a stub conditioning context. +""" + +from types import SimpleNamespace + +import pytest +import torch + +from invokeai.app.invocations.fields import Krea2ConditioningField +from invokeai.app.invocations.krea2_conditioning_rebalance import Krea2ConditioningRebalanceInvocation +from invokeai.app.invocations.krea2_seed_variance import Krea2SeedVarianceInvocation +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ConditioningFieldData, Krea2ConditioningInfo + + +def _make_context(embeds: torch.Tensor, saved: dict) -> SimpleNamespace: + def load(_name: str) -> ConditioningFieldData: + return ConditioningFieldData( + conditionings=[Krea2ConditioningInfo(prompt_embeds=embeds, prompt_embeds_mask=None)] + ) + + def save(data: ConditioningFieldData) -> str: + saved["data"] = data + return "saved-name" + + return SimpleNamespace(conditioning=SimpleNamespace(load=load, save=save)) + + +def _saved_embeds(saved: dict) -> torch.Tensor: + conditioning = saved["data"].conditionings[0] + assert isinstance(conditioning, Krea2ConditioningInfo) + return conditioning.prompt_embeds + + +class TestRebalanceParseWeights: + def test_accepts_exactly_twelve_values(self) -> None: + invocation = Krea2ConditioningRebalanceInvocation.model_construct( + per_layer_weights="1,2,3,4,5,6,7,8,9,10,11,12" + ) + assert invocation._parse_weights() == [float(i) for i in range(1, 13)] + + @pytest.mark.parametrize("weights", ["1,2,3", "1,2,3,4,5,6,7,8,9,10,11,12,13"]) + def test_rejects_wrong_count(self, weights: str) -> None: + invocation = Krea2ConditioningRebalanceInvocation.model_construct(per_layer_weights=weights) + with pytest.raises(ValueError, match="exactly 12 values"): + invocation._parse_weights() + + def test_rejects_non_numeric(self) -> None: + invocation = Krea2ConditioningRebalanceInvocation.model_construct(per_layer_weights="a,b,c,d,e,f,g,h,i,j,k,l") + with pytest.raises(ValueError, match="comma-separated numbers"): + invocation._parse_weights() + + +def test_rebalance_applies_per_layer_gains_on_the_layer_axis() -> None: + # embeds is (B=1, seq=2, 12 layers, hidden=4); gains must apply along the layer axis (dim=2). + embeds = torch.ones(1, 2, 12, 4) + saved: dict = {} + invocation = Krea2ConditioningRebalanceInvocation.model_construct( + conditioning=Krea2ConditioningField(conditioning_name="c"), + per_layer_weights="1,2,3,4,5,6,7,8,9,10,11,12", + multiplier=1.0, + ) + + invocation.invoke(_make_context(embeds, saved)) + + out = _saved_embeds(saved) + assert out.shape == (1, 2, 12, 4) + for layer_index in range(12): + assert torch.allclose(out[:, :, layer_index, :], torch.full((1, 2, 4), float(layer_index + 1))) + + +def test_rebalance_applies_overall_multiplier() -> None: + embeds = torch.ones(1, 1, 12, 2) + saved: dict = {} + invocation = Krea2ConditioningRebalanceInvocation.model_construct( + conditioning=Krea2ConditioningField(conditioning_name="c"), + per_layer_weights=",".join(["1.0"] * 12), + multiplier=3.0, + ) + + invocation.invoke(_make_context(embeds, saved)) + + assert torch.allclose(_saved_embeds(saved), torch.full((1, 1, 12, 2), 3.0)) + + +def test_seed_variance_is_deterministic_for_a_fixed_seed() -> None: + embeds = torch.ones(1, 3, 12, 4) + saved_a: dict = {} + saved_b: dict = {} + invocation = Krea2SeedVarianceInvocation.model_construct( + conditioning=Krea2ConditioningField(conditioning_name="c"), + strength=20.0, + randomize_percent=50.0, + variance_seed=42, + ) + + invocation.invoke(_make_context(embeds.clone(), saved_a)) + invocation.invoke(_make_context(embeds.clone(), saved_b)) + + assert torch.equal(_saved_embeds(saved_a), _saved_embeds(saved_b)) + + +def test_seed_variance_differs_across_seeds() -> None: + embeds = torch.ones(1, 3, 12, 4) + saved_a: dict = {} + saved_b: dict = {} + + def _run(seed: int, saved: dict) -> None: + Krea2SeedVarianceInvocation.model_construct( + conditioning=Krea2ConditioningField(conditioning_name="c"), + strength=20.0, + randomize_percent=50.0, + variance_seed=seed, + ).invoke(_make_context(embeds.clone(), saved)) + + _run(42, saved_a) + _run(43, saved_b) + + assert not torch.equal(_saved_embeds(saved_a), _saved_embeds(saved_b)) + + +def test_seed_variance_does_not_mutate_the_input_conditioning() -> None: + embeds = torch.ones(1, 3, 12, 4) + original = embeds.clone() + saved: dict = {} + invocation = Krea2SeedVarianceInvocation.model_construct( + conditioning=Krea2ConditioningField(conditioning_name="c"), + strength=20.0, + randomize_percent=50.0, + variance_seed=7, + ) + + invocation.invoke(_make_context(embeds, saved)) + + # The invocation must produce a new tensor, not perturb the caller's embeds in place. + assert torch.equal(embeds, original) + assert not torch.equal(_saved_embeds(saved), original) diff --git a/tests/app/invocations/test_krea2_text_encoder.py b/tests/app/invocations/test_krea2_text_encoder.py index 8482fb20b24..f7a35878b79 100644 --- a/tests/app/invocations/test_krea2_text_encoder.py +++ b/tests/app/invocations/test_krea2_text_encoder.py @@ -106,3 +106,86 @@ def apply_patches(**kwargs): with pytest.raises(TypeError, match="Expected ModelPatchRaw"): _invocation()._encode(_context(object())) + + +def test_encode_preserves_suffix_for_a_prompt_that_overflows_truncation(monkeypatch) -> None: + # Regression: a prompt longer than the tokenizer budget must NOT lose the assistant-turn suffix. The + # encoder tokenizes (prefix + prompt) with truncation and appends the suffix AFTER, so the final tokens + # always end with the suffix template (building one string and truncating it would cut the suffix off). + from invokeai.app.invocations.krea2_text_encoder import _KREA2_SUFFIX + + suffix_ids = [901, 902, 903, 904, 905] + + class _TruncatingTokenizer: + def __call__(self, text, max_length=None, truncation=False, add_special_tokens=True, return_tensors=None): + if text == _KREA2_SUFFIX: + ids = list(suffix_ids) + else: + # Body (prefix + prompt): one filler id per whitespace token, distinct from the suffix ids. + ids = [1] * len(text.split()) + if truncation and max_length is not None and len(ids) > max_length: + ids = ids[:max_length] # right truncation, as the real tokenizer does + input_ids = torch.tensor([ids], dtype=torch.long) + return SimpleNamespace(input_ids=input_ids, attention_mask=torch.ones_like(input_ids)) + + captured: dict = {} + + class _CapturingEncoder(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.anchor = torch.nn.Parameter(torch.zeros(1)) + + def forward(self, *, input_ids, attention_mask, **_kwargs): + captured["input_ids"] = input_ids + seq = input_ids.shape[1] + hidden_states = tuple(torch.zeros((1, seq, 4)) for _ in range(36)) + return SimpleNamespace(hidden_states=hidden_states) + + encoder = _CapturingEncoder() + + class _CapturingEncoderInfo: + @contextmanager + def model_on_device(self): + yield ({}, encoder) + + class _TruncatingTokenizerInfo: + def __enter__(self): + return _TruncatingTokenizer() + + def __exit__(self, *_args): + return None + + def load(identifier): + if identifier.submodel_type is SubModelType.Tokenizer: + return _TruncatingTokenizerInfo() + return _CapturingEncoderInfo() + + context = SimpleNamespace( + models=SimpleNamespace(load=load), util=SimpleNamespace(signal_progress=lambda _message: None) + ) + + monkeypatch.setattr( + "invokeai.app.invocations.krea2_text_encoder.LayerPatcher.apply_smart_model_patches", + lambda **_kwargs: nullcontext(), + ) + monkeypatch.setattr( + "invokeai.app.invocations.krea2_text_encoder.TorchDevice.choose_bfloat16_safe_dtype", + lambda _device: torch.float32, + ) + + encoder_id = _identifier("encoder", ModelType.Qwen3VLEncoder) + field = Qwen3VLEncoderField( + tokenizer=encoder_id.model_copy(update={"submodel_type": SubModelType.Tokenizer}), + text_encoder=encoder_id.model_copy(update={"submodel_type": SubModelType.TextEncoder}), + loras=[], + ) + long_prompt = " ".join(["word"] * 2000) # far exceeds the ~541-token budget + invocation = Krea2TextEncoderInvocation.model_construct(prompt=long_prompt, qwen3_vl_encoder=field) + + invocation._encode(context) + + final_ids = captured["input_ids"][0].tolist() + # The suffix survives at the very end even though the body was truncated. + assert final_ids[-len(suffix_ids) :] == suffix_ids + # And the body really was truncated (total = reserved budget + suffix), proving append-after-truncate. + assert len(final_ids) > len(suffix_ids) diff --git a/tests/backend/model_manager/configs/test_krea2_main_config.py b/tests/backend/model_manager/configs/test_krea2_main_config.py index b389a18fc59..2d29ccc66ab 100644 --- a/tests/backend/model_manager/configs/test_krea2_main_config.py +++ b/tests/backend/model_manager/configs/test_krea2_main_config.py @@ -51,6 +51,13 @@ class TestKrea2VariantFromName: ("krea2_turbo-Q3_K_M.gguf", Krea2VariantType.Turbo), ("Krea-2-Turbo-Q4_K_M.gguf", Krea2VariantType.Turbo), ("some-random-name.safetensors", Krea2VariantType.Turbo), # default + # "turbo" wins outright, so a Turbo file whose name merely contains "base"/"raw" as a + # substring is not misread as Base. + ("krea2_turbo_baseline_q4.gguf", Krea2VariantType.Turbo), + ("krea2-turbo-raw-export.safetensors", Krea2VariantType.Turbo), + # "base"/"raw" only match as whole tokens, not arbitrary substrings. + ("krea2_database_model.safetensors", Krea2VariantType.Turbo), + ("krea2_baseline_q8.gguf", Krea2VariantType.Turbo), ], ) def test_variant_from_name(self, name: str, expected: Krea2VariantType) -> None: diff --git a/tests/backend/model_manager/configs/test_model_path_validation.py b/tests/backend/model_manager/configs/test_model_path_validation.py index 2c83cee6533..a359ed83bb2 100644 --- a/tests/backend/model_manager/configs/test_model_path_validation.py +++ b/tests/backend/model_manager/configs/test_model_path_validation.py @@ -31,3 +31,15 @@ def test_large_directory_with_model_index_is_accepted(tmp_path: Path) -> None: _fill_directory(tmp_path) ModelConfigFactory._validate_path_looks_like_model(tmp_path) + + +def test_directory_with_utf8_non_ascii_config_is_accepted(tmp_path: Path) -> None: + # config.json files are UTF-8. Reading them with the platform default encoding (cp1252 on Windows) + # raises UnicodeDecodeError on non-ASCII bytes, which gets swallowed as "unrecognized" and wrongly + # rejects a valid model directory. The config must be read explicitly as UTF-8. + (tmp_path / "config.json").write_text( + json.dumps({"architectures": ["Qwen3VLModel"], "description": "café — ünïcödé 模型"}, ensure_ascii=False), + encoding="utf-8", + ) + + ModelConfigFactory._validate_path_looks_like_model(tmp_path) diff --git a/tests/backend/model_manager/configs/test_qwen3_encoder_config.py b/tests/backend/model_manager/configs/test_qwen3_encoder_config.py index 2574b7433a8..b6d05724eb3 100644 --- a/tests/backend/model_manager/configs/test_qwen3_encoder_config.py +++ b/tests/backend/model_manager/configs/test_qwen3_encoder_config.py @@ -12,12 +12,16 @@ import json from pathlib import Path from tempfile import TemporaryDirectory -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch import pytest from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError -from invokeai.backend.model_manager.configs.qwen3_encoder import Qwen3Encoder_Qwen3Encoder_Config +from invokeai.backend.model_manager.configs.qwen3_encoder import ( + Qwen3Encoder_Checkpoint_Config, + Qwen3Encoder_Qwen3Encoder_Config, + _has_qwen_vl_visual_tower, +) _OVERRIDE_FIELDS: dict[str, object] = { "hash": "blake3:fakehash", @@ -63,6 +67,44 @@ def test_standalone_text_encoder_subfolder_still_matches() -> None: assert config.type.value == "qwen3_encoder" +class TestQwen3EncoderRejectsVisualTower: + """Regression for the single-file Qwen3-VL dual-match bug. + + A nested-layout single-file Qwen3-VL 4B encoder (``model.layers.*`` + ``model.visual.*``) previously + matched BOTH the text-only Qwen3Encoder checkpoint config and the Qwen3VLEncoder config, because the + reject helper only looked for bare ``visual.blocks.*``. The tie-break is nondeterministic, so the + encoder could register as Qwen3Encoder and vanish from Krea-2's Qwen3-VL dropdown - hard-blocking the + single-file/GGUF Krea-2 install path. The reject helper now matches the nested ``model.visual.*`` + layout too, keeping the two configs mutually exclusive. + """ + + @pytest.mark.parametrize( + "visual_key", + [ + "model.visual.blocks.0.attn.qkv.weight", # ComfyUI single-file nested layout + "visual.blocks.0.attn.qkv.weight", # already-split (transformers) layout + "model.visual.patch_embed.proj.weight", + ], + ) + def test_matches_nested_and_split_visual_layouts(self, visual_key: str) -> None: + assert _has_qwen_vl_visual_tower({visual_key: object()}) is True + + def test_ignores_text_only_decoder(self) -> None: + assert _has_qwen_vl_visual_tower({"model.layers.0.self_attn.q_proj.weight": object()}) is False + + @patch("invokeai.backend.model_manager.configs.qwen3_encoder.raise_if_not_file") + @patch("invokeai.backend.model_manager.configs.qwen3_encoder.raise_for_override_fields") + def test_checkpoint_config_rejects_nested_qwen3_vl(self, _rfo, _rif) -> None: + mod = MagicMock() + mod.path = Path("/fake/qwen3vl_4b.safetensors") + mod.load_state_dict.return_value = { + "model.layers.0.self_attn.q_proj.weight": object(), + "model.visual.blocks.0.attn.qkv.weight": object(), + } + with pytest.raises(NotAMatchError, match="visual tower"): + Qwen3Encoder_Checkpoint_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) + + def test_nested_text_encoder_with_root_tokenizer_still_matches() -> None: """A model with text_encoder/config.json should match even if tokenizer files exist at root. diff --git a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py index 2310ad58a22..e1b07955f30 100644 --- a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py +++ b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py @@ -232,4 +232,18 @@ def test_names_the_missing_parameters(self) -> None: model.load_state_dict({"weight": torch.zeros(4, 4)}, strict=False, assign=True) with pytest.raises(RuntimeError, match="bias") as exc_info: _reject_incomplete_load(model, what="Krea-2 single-file checkpoint") - assert "1 parameter(s)" in str(exc_info.value) + assert "1 tensor(s)" in str(exc_info.value) + + def test_raises_for_a_persistent_buffer_left_on_meta(self) -> None: + # Buffers land on the meta device too; a native/GGUF checkpoint that omits a persistent buffer + # must be rejected. The parameter here is fully materialized, so a parameters-only guard would + # wrongly pass - only the buffer check catches it. + class _ModuleWithMetaBuffer(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.weight = torch.nn.Parameter(torch.zeros(2, 2)) + self.register_buffer("cached_stat", torch.empty(4, device="meta")) + + model = _ModuleWithMetaBuffer() + with pytest.raises(RuntimeError, match="cached_stat"): + _reject_incomplete_load(model, what="Krea-2 GGUF checkpoint") diff --git a/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py b/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py index 0fb37617c2c..b37f3eca009 100644 --- a/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py +++ b/tests/backend/patches/lora_conversions/test_krea2_lora_conversion_utils.py @@ -1,3 +1,4 @@ +import pytest import torch from invokeai.backend.patches.layers.dora_layer import DoRALayer @@ -48,3 +49,18 @@ def test_peft_layer_without_explicit_alpha_uses_rank_default() -> None: layer = model.layers[f"{KREA2_LORA_TRANSFORMER_PREFIX}text_fusion.0.attn.to_q"] assert isinstance(layer, LoRALayer) assert layer._alpha is None + + +def test_incomplete_peft_pair_raises_descriptive_error() -> None: + # A layer with lora_A but no matching lora_B is malformed. It must raise a clear ValueError naming the + # missing key, not an uninformative bare KeyError. + state_dict = { + # Complete layer so the dict still looks like a Krea-2 LoRA. + "transformer.text_fusion.0.attn.to_k.lora_A.weight": torch.ones(2, 4), + "transformer.text_fusion.0.attn.to_k.lora_B.weight": torch.ones(4, 2), + # Incomplete layer: lora_A present, lora_B missing. + "transformer.text_fusion.0.attn.to_q.lora_A.weight": torch.ones(2, 4), + } + + with pytest.raises(ValueError, match="lora_B.weight"): + lora_model_from_krea2_state_dict(state_dict) From 21fb90d88d317ff40f0d1469a70ee72723f9b7fe Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Tue, 14 Jul 2026 03:10:52 +0200 Subject: [PATCH 16/17] fix(krea2): reshape native final-layer modulation + honor scheduler shift config - loader: last.modulation.lin (native/GGUF) is reshaped to (2, hidden) to match diffusers Krea2FinalLayer.scale_shift_table, not just renamed. assign=True would otherwise install a flat 1-D parameter (which the meta-only completeness guard cannot catch), failing at inference on the primary GGUF/native path. Verified the final table is (2, hidden) and the per-block tables are (6, hidden) against the installed Krea2Transformer2DModel. - denoise: the resolution-aware timestep shift (mu) now reads base_shift/max_shift/ base_image_seq_len/max_image_seq_len from the loaded scheduler's config, falling back to the Krea-2 defaults, so a Raw checkpoint shipping a customized scheduler_config.json is sampled with its own shift parameters. Adds a converter test asserting last.modulation.lin -> final_layer.scale_shift_table is reshaped to (2, hidden). --- invokeai/app/invocations/krea2_denoise.py | 15 ++++++++++++++- .../model_manager/load/model_loaders/krea2.py | 5 +++++ .../load/test_krea2_state_dict_utils.py | 12 ++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index 9df8f20f855..36fa5dd5fce 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -24,7 +24,11 @@ from invokeai.app.invocations.primitives import LatentsOutput from invokeai.app.services.shared.invocation_context import InvocationContext from invokeai.backend.krea2.sampling_utils import ( + KREA2_BASE_IMAGE_SEQ_LEN, + KREA2_BASE_SHIFT, KREA2_DISTILLED_MU, + KREA2_MAX_IMAGE_SEQ_LEN, + KREA2_MAX_SHIFT, build_sigmas, calculate_shift, pack_latents, @@ -232,7 +236,16 @@ def _run_diffusion(self, context: InvocationContext): elif self._is_distilled(context): mu = KREA2_DISTILLED_MU else: - mu = calculate_shift(image_seq_len) + # Resolution-aware shift. Honor the loaded scheduler's config so a Raw checkpoint that ships a + # customized scheduler_config.json is sampled with its own shift params, falling back to the + # Krea-2 defaults for the stock scheduler (and for any field the config omits). + mu = calculate_shift( + image_seq_len, + base_image_seq_len=getattr(scheduler.config, "base_image_seq_len", KREA2_BASE_IMAGE_SEQ_LEN), + max_image_seq_len=getattr(scheduler.config, "max_image_seq_len", KREA2_MAX_IMAGE_SEQ_LEN), + base_shift=getattr(scheduler.config, "base_shift", KREA2_BASE_SHIFT), + max_shift=getattr(scheduler.config, "max_shift", KREA2_MAX_SHIFT), + ) init_sigmas = build_sigmas(self.steps) scheduler.set_timesteps(sigmas=init_sigmas, mu=mu, device=device) diff --git a/invokeai/backend/model_manager/load/model_loaders/krea2.py b/invokeai/backend/model_manager/load/model_loaders/krea2.py index 0a219577a7f..7757bf89b6d 100644 --- a/invokeai/backend/model_manager/load/model_loaders/krea2.py +++ b/invokeai/backend/model_manager/load/model_loaders/krea2.py @@ -154,6 +154,11 @@ def _convert_krea2_native_to_diffusers(sd: dict[str, Any]) -> dict[str, Any]: k = "final_layer.norm.weight" elif k == "last.modulation.lin": k = "final_layer.scale_shift_table" + # Krea2FinalLayer.scale_shift_table is (2, hidden) (scale, shift). Reshape the flat native + # table just like the per-block (6, hidden) tables below - otherwise load_state_dict(assign=True) + # installs a wrong-shaped 1-D parameter (which the meta-only completeness guard cannot catch) + # and the final layer fails at inference. + value = torch.as_tensor(_to_plain_tensor(value)).reshape(2, -1) # Within-block sub-module renames (apply to transformer_blocks.* and text_fusion.*). k = k.replace(".attn.wq.weight", ".attn.to_q.weight") diff --git a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py index e1b07955f30..4b394a40b2c 100644 --- a/tests/backend/model_manager/load/test_krea2_state_dict_utils.py +++ b/tests/backend/model_manager/load/test_krea2_state_dict_utils.py @@ -178,6 +178,18 @@ def test_mod_lin_is_reshaped_to_scale_shift_table(self) -> None: assert table.shape == (6, 2) assert torch.equal(table, torch.arange(12, dtype=torch.float32).reshape(6, 2)) + def test_final_layer_modulation_is_reshaped_to_two_by_hidden(self) -> None: + # Krea2FinalLayer.scale_shift_table is (2, hidden) (scale, shift). The flat native + # last.modulation.lin must be reshaped (not merely renamed), otherwise load_state_dict(assign=True) + # installs a wrong-shaped 1-D parameter that the meta-only completeness guard cannot catch and the + # final layer fails at inference. + sd = {"last.modulation.lin": torch.arange(8, dtype=torch.float32)} # 2 * hidden, hidden=4 + out = _convert_krea2_native_to_diffusers(sd) + assert "final_layer.scale_shift_table" in out + table = out["final_layer.scale_shift_table"] + assert table.shape == (2, 4) + assert torch.equal(table, torch.arange(8, dtype=torch.float32).reshape(2, 4)) + def test_non_string_keys_pass_through(self) -> None: sentinel = object() out = _convert_krea2_native_to_diffusers({sentinel: torch.zeros(1)}) # type: ignore[dict-item] From 48a838f6e03f556b0905f930b65ca03ee8308603 Mon Sep 17 00:00:00 2001 From: JPPhoto Date: Mon, 13 Jul 2026 22:49:53 -0500 Subject: [PATCH 17/17] fix(krea2): resolve remaining review findings --- docs/src/content/docs/features/krea-2.mdx | 12 ++-- .../krea2_conditioning_rebalance.py | 5 ++ invokeai/app/invocations/krea2_denoise.py | 21 +++++- .../app/invocations/krea2_model_loader.py | 19 ++++- .../app/invocations/krea2_seed_variance.py | 1 + .../qwen_image_latents_to_image.py | 66 +++++++++-------- .../backend/model_manager/configs/factory.py | 54 ++++++++++---- .../backend/model_manager/configs/main.py | 6 +- .../model_manager/configs/qwen3_vl_encoder.py | 16 ++++- invokeai/frontend/web/openapi.json | 4 +- .../listeners/krea2ComponentSync.test.ts | 44 ++++++++++++ .../listeners/krea2ComponentSync.ts | 12 +++- .../listeners/modelSelected.test.ts | 53 +++++++++++--- .../listeners/modelSelected.ts | 10 +-- .../listeners/modelsLoaded.krea2.test.ts | 15 ++++ .../src/features/metadata/parsing.test.tsx | 10 +++ .../web/src/features/metadata/parsing.tsx | 1 + tests/app/invocations/test_krea2_denoise.py | 42 +++++++++++ tests/app/invocations/test_krea2_enhancers.py | 26 +++++++ .../invocations/test_krea2_model_loader.py | 70 +++++++++++++++++++ .../test_qwen_image_working_memory.py | 41 +++++++++++ .../configs/test_krea2_main_config.py | 6 +- .../configs/test_model_path_validation.py | 24 +++++++ .../configs/test_qwen3_vl_encoder_config.py | 34 +++++++++ 24 files changed, 514 insertions(+), 78 deletions(-) create mode 100644 tests/app/invocations/test_krea2_model_loader.py diff --git a/docs/src/content/docs/features/krea-2.mdx b/docs/src/content/docs/features/krea-2.mdx index cdfb0aeafd6..755a8581d40 100644 --- a/docs/src/content/docs/features/krea-2.mdx +++ b/docs/src/content/docs/features/krea-2.mdx @@ -12,7 +12,7 @@ published checkpoints: - **Krea-2-Turbo** — distilled for fast, low-step generation. Runs at **8 steps** with **CFG disabled** (CFG Scale `1.0`). This is the recommended checkpoint for everyday use. - **Krea-2-Raw** — the undistilled base checkpoint. Runs at **more steps (~28)** with **CFG enabled** - (CFG Scale ~`4.5`) and supports negative prompts. It is primarily intended as a base for + (CFG Scale ~`5.5`, equivalent to the reference pipeline's guidance `4.5`) and supports negative prompts. It is primarily intended as a base for finetuning / LoRA training, but full inference is supported. The variant is detected automatically on install, and selecting a Krea-2 model sets sensible defaults @@ -31,11 +31,11 @@ their dependencies together. Krea-2 needs three components: -| Component | Diffusers install | GGUF / single-file install | -|---|---|---| -| Transformer | bundled in the pipeline | the `.gguf` / single-file checkpoint | -| VAE (Qwen-Image) | bundled | installed separately | -| Text encoder (Qwen3-VL) | bundled | installed separately | +| Component | Diffusers install | GGUF / single-file install | +| ----------------------- | ----------------------- | ------------------------------------ | +| Transformer | bundled in the pipeline | the `.gguf` / single-file checkpoint | +| VAE (Qwen-Image) | bundled | installed separately | +| Text encoder (Qwen3-VL) | bundled | installed separately | - **Diffusers** (e.g. `krea/Krea-2-Turbo`, `krea/Krea-2-Raw`): a single ~26 GB install that bundles the VAE and text encoder. Nothing else is required. diff --git a/invokeai/app/invocations/krea2_conditioning_rebalance.py b/invokeai/app/invocations/krea2_conditioning_rebalance.py index c4aa7e78381..ab52a5033ae 100644 --- a/invokeai/app/invocations/krea2_conditioning_rebalance.py +++ b/invokeai/app/invocations/krea2_conditioning_rebalance.py @@ -1,3 +1,5 @@ +import math + import torch from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation @@ -40,6 +42,7 @@ class Krea2ConditioningRebalanceInvocation(BaseInvocation): ) multiplier: float = InputField( default=4.0, + allow_inf_nan=False, description="Overall multiplier applied to the conditioning after per-layer weighting.", ) @@ -50,6 +53,8 @@ def _parse_weights(self) -> list[float]: raise ValueError(f"per_layer_weights must be comma-separated numbers: {e}") from e if len(weights) != _NUM_TEXT_LAYERS: raise ValueError(f"per_layer_weights must have exactly {_NUM_TEXT_LAYERS} values, got {len(weights)}.") + if not all(math.isfinite(weight) for weight in weights): + raise ValueError("per_layer_weights must contain only finite values.") return weights @torch.no_grad() diff --git a/invokeai/app/invocations/krea2_denoise.py b/invokeai/app/invocations/krea2_denoise.py index 36fa5dd5fce..7191bd463de 100644 --- a/invokeai/app/invocations/krea2_denoise.py +++ b/invokeai/app/invocations/krea2_denoise.py @@ -1,10 +1,12 @@ import json +import math from contextlib import ExitStack from pathlib import Path from typing import Callable, Iterator, Optional, Tuple import torch import torchvision.transforms as tv_transforms +from pydantic import field_validator from torchvision.transforms.functional import resize as tv_resize from tqdm import tqdm @@ -81,8 +83,8 @@ class Krea2DenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): # CFG uses the standard formulation (uncond + cfg_scale*(cond-uncond)); cfg_scale <= 1 disables it. # Krea-2-Turbo is distilled and runs with CFG disabled (cfg_scale=1.0). cfg_scale: float | list[float] = InputField(default=1.0, description=FieldDescriptions.cfg_scale, title="CFG Scale") - width: int = InputField(default=1024, multiple_of=16, description="Width of the generated image.") - height: int = InputField(default=1024, multiple_of=16, description="Height of the generated image.") + width: int = InputField(default=1024, gt=0, multiple_of=16, description="Width of the generated image.") + height: int = InputField(default=1024, gt=0, multiple_of=16, description="Height of the generated image.") steps: int = InputField(default=8, gt=0, description=FieldDescriptions.steps) seed: int = InputField(default=0, description="Randomness seed for reproducibility.") shift: Optional[float] = InputField( @@ -91,6 +93,21 @@ class Krea2DenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): "(mu=1.15 for the distilled Turbo checkpoint).", ) + @field_validator("cfg_scale") + @classmethod + def validate_cfg_scale_is_finite(cls, value: float | list[float]) -> float | list[float]: + values = value if isinstance(value, list) else [value] + if not all(math.isfinite(item) for item in values): + raise ValueError("cfg_scale values must be finite.") + return value + + @field_validator("shift") + @classmethod + def validate_shift_is_finite(cls, value: float | None) -> float | None: + if value is not None and not math.isfinite(value): + raise ValueError("shift must be finite.") + return value + @torch.no_grad() def invoke(self, context: InvocationContext) -> LatentsOutput: latents = self._run_diffusion(context) diff --git a/invokeai/app/invocations/krea2_model_loader.py b/invokeai/app/invocations/krea2_model_loader.py index 1c3e21a00cb..5a010f726cf 100644 --- a/invokeai/app/invocations/krea2_model_loader.py +++ b/invokeai/app/invocations/krea2_model_loader.py @@ -58,7 +58,7 @@ class Krea2ModelLoaderInvocation(BaseInvocation): description="Standalone VAE model. Krea-2 uses the Qwen-Image VAE (16-channel). " "If not provided, the VAE is loaded from the Krea-2 (diffusers) model.", input=Input.Direct, - ui_model_base=BaseModelType.QwenImage, + ui_model_base=[BaseModelType.QwenImage, BaseModelType.Anima], ui_model_type=ModelType.VAE, title="VAE", ) @@ -73,11 +73,25 @@ class Krea2ModelLoaderInvocation(BaseInvocation): ) def invoke(self, context: InvocationContext) -> Krea2ModelLoaderOutput: + main_config = context.models.get_config(self.model) + if main_config.base is not BaseModelType.Krea2 or main_config.type is not ModelType.Main: + raise ValueError( + f"Model '{main_config.name}' is not a Krea-2 main model. Select a Krea-2 transformer model." + ) + # Transformer always comes from the main model. transformer = self.model.model_copy(update={"submodel_type": SubModelType.Transformer}) # Determine VAE source. if self.vae_model is not None: + vae_config = context.models.get_config(self.vae_model) + if vae_config.type is not ModelType.VAE or vae_config.base not in ( + BaseModelType.QwenImage, + BaseModelType.Anima, + ): + raise ValueError( + f"VAE '{vae_config.name}' is not compatible with Krea-2. Select a Qwen Image or Anima VAE." + ) vae = self.vae_model.model_copy(update={"submodel_type": SubModelType.VAE}) else: self._validate_diffusers_format(context, self.model, "Krea-2") @@ -85,6 +99,9 @@ def invoke(self, context: InvocationContext) -> Krea2ModelLoaderOutput: # Determine Qwen3-VL Encoder source. if self.qwen3_vl_encoder_model is not None: + encoder_config = context.models.get_config(self.qwen3_vl_encoder_model) + if encoder_config.type is not ModelType.Qwen3VLEncoder: + raise ValueError(f"Encoder '{encoder_config.name}' is not a Qwen3-VL encoder compatible with Krea-2.") tokenizer = self.qwen3_vl_encoder_model.model_copy(update={"submodel_type": SubModelType.Tokenizer}) text_encoder = self.qwen3_vl_encoder_model.model_copy(update={"submodel_type": SubModelType.TextEncoder}) else: diff --git a/invokeai/app/invocations/krea2_seed_variance.py b/invokeai/app/invocations/krea2_seed_variance.py index 39e05dfdb2a..a7ef38b1017 100644 --- a/invokeai/app/invocations/krea2_seed_variance.py +++ b/invokeai/app/invocations/krea2_seed_variance.py @@ -33,6 +33,7 @@ class Krea2SeedVarianceInvocation(BaseInvocation): ) strength: float = InputField( default=20.0, + allow_inf_nan=False, description="Magnitude of the uniform noise added to the embeddings (noise in [-strength, +strength]).", ) randomize_percent: float = InputField( diff --git a/invokeai/app/invocations/qwen_image_latents_to_image.py b/invokeai/app/invocations/qwen_image_latents_to_image.py index 056941604c2..ffa913536d3 100644 --- a/invokeai/app/invocations/qwen_image_latents_to_image.py +++ b/invokeai/app/invocations/qwen_image_latents_to_image.py @@ -50,44 +50,42 @@ def invoke(self, context: InvocationContext) -> ImageOutput: image_tensor=latents, vae=vae_info.model, ) - with ( - SeamlessExt.static_patch_model(vae_info.model, self.vae.seamless_axes), - vae_info.model_on_device(working_mem_bytes=estimated_working_memory) as (_, vae), - ): + with vae_info.model_on_device(working_mem_bytes=estimated_working_memory) as (_, vae): context.util.signal_progress("Running VAE") # A native-layout qwen_image_vae single file is classified with the Anima base and loaded # as AutoencoderKLWan; reinterpret it as AutoencoderKLQwenImage (identical weights). vae = as_qwen_image_vae(vae) - latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=vae.dtype) - - vae.disable_tiling() - - tiling_context = nullcontext() - - TorchDevice.empty_cache() - - with torch.inference_mode(), tiling_context: - # The Qwen Image VAE uses per-channel latents_mean / latents_std - # instead of a single scaling_factor. - # Latents are 5D: (B, C, num_frames, H, W) — the unpack from the - # denoise step already produces this shape. - latents_mean = ( - torch.tensor(vae.config.latents_mean) - .view(1, vae.config.z_dim, 1, 1, 1) - .to(latents.device, latents.dtype) - ) - latents_std = 1.0 / torch.tensor(vae.config.latents_std).view(1, vae.config.z_dim, 1, 1, 1).to( - latents.device, latents.dtype - ) - latents = latents / latents_std + latents_mean - - img = vae.decode(latents, return_dict=False)[0] - # Drop the temporal frame dimension: (B, C, 1, H, W) -> (B, C, H, W) - img = img[:, :, 0] - - img = img.clamp(-1, 1) - img = rearrange(img[0], "c h w -> h w c") - img_pil = Image.fromarray((127.5 * (img + 1.0)).byte().cpu().numpy()) + with SeamlessExt.static_patch_model(vae, self.vae.seamless_axes): + latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=vae.dtype) + + vae.disable_tiling() + + tiling_context = nullcontext() + + TorchDevice.empty_cache() + + with torch.inference_mode(), tiling_context: + # The Qwen Image VAE uses per-channel latents_mean / latents_std + # instead of a single scaling_factor. + # Latents are 5D: (B, C, num_frames, H, W) — the unpack from the + # denoise step already produces this shape. + latents_mean = ( + torch.tensor(vae.config.latents_mean) + .view(1, vae.config.z_dim, 1, 1, 1) + .to(latents.device, latents.dtype) + ) + latents_std = 1.0 / torch.tensor(vae.config.latents_std).view(1, vae.config.z_dim, 1, 1, 1).to( + latents.device, latents.dtype + ) + latents = latents / latents_std + latents_mean + + img = vae.decode(latents, return_dict=False)[0] + # Drop the temporal frame dimension: (B, C, 1, H, W) -> (B, C, H, W) + img = img[:, :, 0] + + img = img.clamp(-1, 1) + img = rearrange(img[0], "c h w -> h w c") + img_pil = Image.fromarray((127.5 * (img + 1.0)).byte().cpu().numpy()) TorchDevice.empty_cache() diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index 8a04e526259..a60fec1b51a 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -169,6 +169,46 @@ # Maximum depth to search for model files in directories _MAX_SEARCH_DEPTH = 2 +# Classes introduced by the versions pinned by this checkout may not exist in the interpreter used by +# lightweight config tests. Keep explicit markers only for those newly supported classes; established +# classes are resolved from the installed Diffusers/Transformers exports below. +_PINNED_MODEL_CLASS_MARKERS = {"Krea2Pipeline"} + + +def _is_known_model_marker(config_name: str, config: Any) -> bool: + """Return whether a root config names a class/model type provided by our model libraries.""" + import diffusers + import transformers + from transformers.models.auto.configuration_auto import CONFIG_MAPPING_NAMES + + if not isinstance(config, dict): + return False + + def has_export(module: Any, name: Any) -> bool: + if not isinstance(name, str) or not name: + return False + try: + return getattr(module, name, None) is not None + except Exception: + return False + + if config_name == "model_index.json": + class_name = config.get("_class_name") + return class_name in _PINNED_MODEL_CLASS_MARKERS or has_export(diffusers, class_name) + + class_name = config.get("_class_name") + if ( + class_name in _PINNED_MODEL_CLASS_MARKERS + or has_export(diffusers, class_name) + or has_export(transformers, class_name) + ): + return True + model_type = config.get("model_type") + if isinstance(model_type, str) and model_type in CONFIG_MAPPING_NAMES: + return True + architectures = config.get("architectures") + return isinstance(architectures, list) and any(has_export(transformers, name) for name in architectures) + # The types are listed explicitly because IDEs/LSPs can't identify the correct types # when AnyModelConfig is constructed dynamically using ModelConfigBase.all_config_classes @@ -436,19 +476,7 @@ def _validate_path_looks_like_model(path: Path) -> None: config = json.loads(config_path.read_text(encoding="utf-8")) except (OSError, ValueError): continue - if config_name == "model_index.json": - recognized_root_config = isinstance(config.get("_class_name"), str) - else: - architectures = config.get("architectures") - recognized_root_config = ( - isinstance(config.get("_class_name"), str) - or isinstance(config.get("model_type"), str) - or ( - isinstance(architectures, list) - and bool(architectures) - and isinstance(architectures[0], str) - ) - ) + recognized_root_config = _is_known_model_marker(config_name, config) if recognized_root_config: break if recognized_root_config: diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index e2554189ee0..56e1cd35fe7 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -105,7 +105,9 @@ def from_base( # Krea-2-Raw (Base, undistilled) needs more steps and CFG; Turbo (distilled) uses 8 # steps with CFG disabled. cfg_scale has a floor of 1 (ge=1); 1.0 means "no guidance". if variant == Krea2VariantType.Base: - return cls(steps=28, cfg_scale=4.5, width=1024, height=1024) + # Diffusers' Krea-2 guidance 4.5 uses cond + 4.5 * (cond - uncond), which is + # equivalent to InvokeAI's standard CFG convention at scale 5.5. + return cls(steps=28, cfg_scale=5.5, width=1024, height=1024) return cls(steps=8, cfg_scale=1.0, width=1024, height=1024) case _: # TODO(psyche): Do we want defaults for other base types? @@ -1410,7 +1412,7 @@ def _get_variant(cls, mod: ModelOnDisk) -> Krea2VariantType: # read/parse failure here is a genuine identification error and is allowed to propagate rather # than being silently registered as Turbo (which would give a Raw model the wrong defaults). config = get_config_dict_or_raise(mod.path / "model_index.json") - if config.get("is_distilled", True) is False: + if config.get("is_distilled", False) is False: return Krea2VariantType.Base return Krea2VariantType.Turbo diff --git a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py index 74ea1a862b9..b4af3d43859 100644 --- a/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py +++ b/invokeai/backend/model_manager/configs/qwen3_vl_encoder.py @@ -48,8 +48,20 @@ def _has_complete_pretrained_weights(weights_path: Path) -> bool: weight_map = index.get("weight_map") if not isinstance(weight_map, dict) or not weight_map: return False - referenced_files = {filename for filename in weight_map.values() if isinstance(filename, str)} - return bool(referenced_files) and all((weights_path / filename).is_file() for filename in referenced_files) + filenames = list(weight_map.values()) + if not all(isinstance(filename, str) and filename for filename in filenames): + return False + root = weights_path.resolve() + referenced_files: set[Path] = set() + for filename in filenames: + filename_path = Path(filename) + if filename_path.is_absolute(): + return False + candidate = (weights_path / filename_path).resolve() + if not candidate.is_relative_to(root): + return False + referenced_files.add(candidate) + return bool(referenced_files) and all(path.is_file() for path in referenced_files) return False diff --git a/invokeai/frontend/web/openapi.json b/invokeai/frontend/web/openapi.json index 7e97aa9b4f3..bffe9c86fe3 100644 --- a/invokeai/frontend/web/openapi.json +++ b/invokeai/frontend/web/openapi.json @@ -44152,6 +44152,7 @@ "width": { "default": 1024, "description": "Width of the generated image.", + "exclusiveMinimum": 0, "field_kind": "input", "input": "any", "multipleOf": 16, @@ -44163,6 +44164,7 @@ "height": { "default": 1024, "description": "Height of the generated image.", + "exclusiveMinimum": 0, "field_kind": "input", "input": "any", "multipleOf": 16, @@ -44544,7 +44546,7 @@ "orig_default": null, "orig_required": false, "title": "VAE", - "ui_model_base": ["qwen-image"], + "ui_model_base": ["qwen-image", "anima"], "ui_model_type": ["vae"] }, "qwen3_vl_encoder_model": { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts index 724b32286e1..a759d57ce78 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.test.ts @@ -51,4 +51,48 @@ describe('getKrea2ComponentUpdates', () => { }) ).toEqual({}); }); + + it('replaces stale standalone selections with installed compatible components', () => { + const staleVae = { ...vae, key: 'deleted-vae' }; + const staleEncoder = { ...encoder, key: 'deleted-encoder' }; + + expect( + getKrea2ComponentUpdates({ + format: 'checkpoint', + selectedVae: staleVae, + selectedEncoder: staleEncoder, + availableQwenImageVaes: [vae], + availableAnimaVaes: [], + availableEncoders: [encoder], + }) + ).toEqual({ vae, encoder }); + }); + + it('clears stale standalone selections when no compatible replacement is installed', () => { + expect( + getKrea2ComponentUpdates({ + format: 'checkpoint', + selectedVae: { ...vae, key: 'deleted-vae' }, + selectedEncoder: { ...encoder, key: 'deleted-encoder' }, + availableQwenImageVaes: [], + availableAnimaVaes: [], + availableEncoders: [], + }) + ).toEqual({ vae: null, encoder: null }); + }); + + it('replaces an installed but incompatible VAE selection', () => { + const incompatibleVae = { ...vae, key: 'sdxl-vae', base: 'sdxl' as const }; + + expect( + getKrea2ComponentUpdates({ + format: 'checkpoint', + selectedVae: incompatibleVae, + selectedEncoder: encoder, + availableQwenImageVaes: [vae], + availableAnimaVaes: [], + availableEncoders: [encoder], + }) + ).toEqual({ vae }); + }); }); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts index 42122038855..6ee342c7490 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/krea2ComponentSync.ts @@ -26,9 +26,17 @@ export const getKrea2ComponentUpdates = (arg: Krea2ComponentSyncArg): Krea2Compo const defaultVae = availableQwenImageVaes[0] ?? availableAnimaVaes[0]; const defaultEncoder = availableEncoders[0]; + const availableVaes = [...availableQwenImageVaes, ...availableAnimaVaes]; + const hasSelectedVae = selectedVae !== null && selectedVae !== undefined; + const hasSelectedEncoder = selectedEncoder !== null && selectedEncoder !== undefined; + const selectedVaeIsAvailable = hasSelectedVae && availableVaes.some((vae) => vae.key === selectedVae.key); + const selectedEncoderIsAvailable = + hasSelectedEncoder && availableEncoders.some((encoder) => encoder.key === selectedEncoder.key); return { - ...(!selectedVae && defaultVae ? { vae: defaultVae } : {}), - ...(!selectedEncoder && defaultEncoder ? { encoder: defaultEncoder } : {}), + ...(!selectedVaeIsAvailable && (hasSelectedVae || defaultVae) ? { vae: defaultVae ?? null } : {}), + ...(!selectedEncoderIsAvailable && (hasSelectedEncoder || defaultEncoder) + ? { encoder: defaultEncoder ?? null } + : {}), }; }; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts index 78b802edf95..9adf54102e1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.test.ts @@ -459,16 +459,28 @@ describe('modelSelected listener - Krea-2 defaulting', () => { }); it('does not overwrite standalone components the user already selected', () => { + const existingVae = { + key: 'existing-vae', + hash: 'h', + name: 'Existing VAE', + base: 'qwen-image', + type: 'vae', + format: 'checkpoint', + } as const; + const existingEncoder = { + key: 'existing-enc', + hash: 'h', + name: 'Existing Enc', + base: 'any', + type: 'qwen3_vl_encoder', + format: 'qwen3_vl_encoder', + } as const; + mockSelectQwenImageVAEModels.mockReturnValue([existingVae]); + mockSelectQwen3VLEncoderModels.mockReturnValue([existingEncoder]); const state = buildMockState({ model: mockFluxMainModel, - krea2VaeModel: { key: 'existing-vae', hash: 'h', name: 'Existing VAE', base: 'qwen-image', type: 'vae' }, - krea2Qwen3VlEncoderModel: { - key: 'existing-enc', - hash: 'h', - name: 'Existing Enc', - base: 'any', - type: 'qwen3_vl_encoder', - }, + krea2VaeModel: existingVae, + krea2Qwen3VlEncoderModel: existingEncoder, }); const action = modelSelected(zParameterModel.parse(mockKrea2MainModel)); @@ -479,6 +491,31 @@ describe('modelSelected listener - Krea-2 defaulting', () => { expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)).toBeUndefined(); }); + it('clears stale standalone components when no replacement is installed', () => { + mockSelectQwenImageVAEModels.mockReturnValue([]); + mockSelectAnimaVAEModels.mockReturnValue([]); + mockSelectQwen3VLEncoderModels.mockReturnValue([]); + const state = buildMockState({ + model: mockFluxMainModel, + krea2VaeModel: { key: 'deleted-vae', hash: 'h', name: 'Deleted VAE', base: 'qwen-image', type: 'vae' }, + krea2Qwen3VlEncoderModel: { + key: 'deleted-enc', + hash: 'h', + name: 'Deleted Enc', + base: 'any', + type: 'qwen3_vl_encoder', + }, + }); + + capturedEffect!(modelSelected(zParameterModel.parse(mockKrea2MainModel)), { + getState: () => state, + dispatch: mockDispatch, + }); + + expect(dispatched.find((a) => a.type === krea2VaeModelSelected.type)?.payload).toBeNull(); + expect(dispatched.find((a) => a.type === krea2Qwen3VlEncoderModelSelected.type)?.payload).toBeNull(); + }); + it('clears stale standalone overrides when switching to a Diffusers Krea-2 model', () => { // A Diffusers pipeline bundles its own VAE + encoder, so any standalone overrides must be cleared. mockSelectModelConfigsQuery.mockReturnValue({ data: {} }); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 80c54e18816..a58f5d5d3af 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -361,11 +361,13 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) = availableAnimaVaes: selectAnimaVAEModels(state), availableEncoders: selectQwen3VLEncoderModels(state), }); - if (updates.vae) { - dispatch(krea2VaeModelSelected(zModelIdentifierField.parse(updates.vae))); + if ('vae' in updates) { + dispatch(krea2VaeModelSelected(updates.vae ? zModelIdentifierField.parse(updates.vae) : null)); } - if (updates.encoder) { - dispatch(krea2Qwen3VlEncoderModelSelected(zModelIdentifierField.parse(updates.encoder))); + if ('encoder' in updates) { + dispatch( + krea2Qwen3VlEncoderModelSelected(updates.encoder ? zModelIdentifierField.parse(updates.encoder) : null) + ); } } } diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts index 0d44cac0521..e2d89af4866 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.krea2.test.ts @@ -67,4 +67,19 @@ describe('handleKrea2Components', () => { expect(dispatch).toHaveBeenCalledWith(krea2VaeModelSelected(null)); expect(dispatch).toHaveBeenCalledWith(krea2Qwen3VlEncoderModelSelected(null)); }); + + it('replaces deleted standalone components when the model list refreshes', () => { + const dispatch = vi.fn(); + const state = makeState({ + krea2VaeModel: { ...vae, key: 'deleted-vae' }, + krea2Qwen3VlEncoderModel: { ...encoder, key: 'deleted-encoder' }, + }); + + handleKrea2Components([mainModel, vae, encoder] as unknown as AnyModelConfig[], state, dispatch, null as never); + + expect(dispatch).toHaveBeenCalledWith(krea2VaeModelSelected(expect.objectContaining({ key: vae.key }))); + expect(dispatch).toHaveBeenCalledWith( + krea2Qwen3VlEncoderModelSelected(expect.objectContaining({ key: encoder.key })) + ); + }); }); diff --git a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx index ba2b17acdfe..528cb523535 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.test.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.test.tsx @@ -217,6 +217,16 @@ describe('ImageMetadataHandlers — Krea-2 recall gating', () => { ) ).rejects.toThrow(); }); + + it.each(['sdxl', 'flux'] as const)('rejects an incompatible %s VAE from Krea-2 image metadata', async (vaeBase) => { + currentBase = 'krea-2'; + nextResolved = fakeModel('vae', vaeBase); + const store = makeStore(); + + await expect( + ImageMetadataHandlers.Krea2VAEModel.parse({ model: fakeModel('main', 'krea-2'), vae: nextResolved }, store) + ).rejects.toThrow(); + }); }); describe('Krea2Qwen3VlEncoderModel', () => { diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index 5cd96ebcfc1..129e1fc995a 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -1177,6 +1177,7 @@ const Krea2VAEModel: SingleMetadataHandler = { const raw = getProperty(metadata, 'vae'); const parsed = await parseModelIdentifier(raw, store, 'vae'); assert(parsed.type === 'vae'); + assert(parsed.base === 'qwen-image' || parsed.base === 'anima', 'Krea2VAEModel requires a Qwen Image or Anima VAE'); // Only recall if the current main model is Krea-2 (its VAE dropdown differs from other bases). const base = selectBase(store.getState()); assert(base === 'krea-2', 'Krea2VAEModel handler only works with Krea-2 models'); diff --git a/tests/app/invocations/test_krea2_denoise.py b/tests/app/invocations/test_krea2_denoise.py index bbfd245ad18..cdf4830d027 100644 --- a/tests/app/invocations/test_krea2_denoise.py +++ b/tests/app/invocations/test_krea2_denoise.py @@ -1,3 +1,4 @@ +import math from contextlib import contextmanager, nullcontext from types import SimpleNamespace @@ -43,6 +44,47 @@ def test_validate_inputs_accepts_a_valid_configuration() -> None: invocation._validate_inputs() +def _validation_payload() -> dict: + model = ModelIdentifierField( + key="krea-model", + hash="model-hash", + name="Krea Model", + base=BaseModelType.Krea2, + type=ModelType.Main, + ) + return { + "transformer": TransformerField(transformer=model, loras=[]), + "positive_conditioning": Krea2ConditioningField(conditioning_name="positive"), + } + + +@pytest.mark.parametrize(("field", "value"), [("width", 0), ("width", -16), ("height", 0), ("height", -16)]) +def test_model_validation_rejects_non_positive_dimensions(field: str, value: int) -> None: + with pytest.raises(ValueError): + Krea2DenoiseInvocation(**_validation_payload(), **{field: value}) + + +@pytest.mark.parametrize( + ("field", "value"), + [ + ("cfg_scale", math.nan), + ("cfg_scale", math.inf), + ("cfg_scale", [1.0, math.nan]), + ("shift", math.nan), + ("shift", math.inf), + ], +) +def test_model_validation_rejects_non_finite_sampling_values(field: str, value: object) -> None: + with pytest.raises(ValueError): + Krea2DenoiseInvocation(**_validation_payload(), **{field: value}) + + +def test_model_validation_accepts_positive_dimensions_and_finite_sampling_values() -> None: + invocation = Krea2DenoiseInvocation(**_validation_payload(), width=16, height=32, cfg_scale=[1.0] * 8, shift=1.15) + assert invocation.width == 16 + assert invocation.height == 32 + + class TestPrepareCfgScale: def test_scalar_is_broadcast_to_the_step_count(self) -> None: invocation = Krea2DenoiseInvocation.model_construct(cfg_scale=4.5) diff --git a/tests/app/invocations/test_krea2_enhancers.py b/tests/app/invocations/test_krea2_enhancers.py index 99f21001e47..67586d37137 100644 --- a/tests/app/invocations/test_krea2_enhancers.py +++ b/tests/app/invocations/test_krea2_enhancers.py @@ -5,6 +5,7 @@ seeded-noise determinism / out-of-place property - is exercised here with a stub conditioning context. """ +import math from types import SimpleNamespace import pytest @@ -53,6 +54,31 @@ def test_rejects_non_numeric(self) -> None: with pytest.raises(ValueError, match="comma-separated numbers"): invocation._parse_weights() + @pytest.mark.parametrize("value", ["nan", "inf", "-inf"]) + def test_rejects_non_finite_weights(self, value: str) -> None: + values = ["1"] * 11 + [value] + invocation = Krea2ConditioningRebalanceInvocation.model_construct(per_layer_weights=",".join(values)) + with pytest.raises(ValueError, match="finite"): + invocation._parse_weights() + + +@pytest.mark.parametrize("value", [math.nan, math.inf, -math.inf]) +def test_rebalance_rejects_non_finite_multiplier(value: float) -> None: + with pytest.raises(ValueError): + Krea2ConditioningRebalanceInvocation( + conditioning=Krea2ConditioningField(conditioning_name="c"), + multiplier=value, + ) + + +@pytest.mark.parametrize("value", [math.nan, math.inf, -math.inf]) +def test_seed_variance_rejects_non_finite_strength(value: float) -> None: + with pytest.raises(ValueError): + Krea2SeedVarianceInvocation( + conditioning=Krea2ConditioningField(conditioning_name="c"), + strength=value, + ) + def test_rebalance_applies_per_layer_gains_on_the_layer_axis() -> None: # embeds is (B=1, seq=2, 12 layers, hidden=4); gains must apply along the layer axis (dim=2). diff --git a/tests/app/invocations/test_krea2_model_loader.py b/tests/app/invocations/test_krea2_model_loader.py new file mode 100644 index 00000000000..21432ffa9d7 --- /dev/null +++ b/tests/app/invocations/test_krea2_model_loader.py @@ -0,0 +1,70 @@ +from types import SimpleNamespace + +import pytest + +from invokeai.app.invocations.krea2_model_loader import Krea2ModelLoaderInvocation +from invokeai.app.invocations.model import ModelIdentifierField +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType + + +def _model(key: str, base: BaseModelType, model_type: ModelType) -> ModelIdentifierField: + return ModelIdentifierField(key=key, hash=f"hash-{key}", name=key, base=base, type=model_type) + + +def _context(configs: dict[str, SimpleNamespace]) -> SimpleNamespace: + return SimpleNamespace(models=SimpleNamespace(get_config=lambda identifier: configs[identifier.key])) + + +def _config(base: BaseModelType, model_type: ModelType, model_format: ModelFormat) -> SimpleNamespace: + return SimpleNamespace(base=base, type=model_type, format=model_format, name=f"{base.value}-{model_type.value}") + + +@pytest.mark.parametrize("vae_base", [BaseModelType.QwenImage, BaseModelType.Anima]) +def test_loader_accepts_supported_standalone_components(vae_base: BaseModelType) -> None: + main = _model("main", BaseModelType.Krea2, ModelType.Main) + vae = _model("vae", vae_base, ModelType.VAE) + encoder = _model("encoder", BaseModelType.Any, ModelType.Qwen3VLEncoder) + context = _context( + { + "main": _config(BaseModelType.Krea2, ModelType.Main, ModelFormat.Checkpoint), + "vae": _config(vae_base, ModelType.VAE, ModelFormat.Checkpoint), + "encoder": _config(BaseModelType.Any, ModelType.Qwen3VLEncoder, ModelFormat.Qwen3VLEncoder), + } + ) + + output = Krea2ModelLoaderInvocation(model=main, vae_model=vae, qwen3_vl_encoder_model=encoder).invoke(context) + + assert output.vae.vae.key == "vae" + assert output.qwen3_vl_encoder.text_encoder.key == "encoder" + + +@pytest.mark.parametrize( + ("target", "stored_config"), + [ + ("main", _config(BaseModelType.Flux, ModelType.Main, ModelFormat.Checkpoint)), + ("vae", _config(BaseModelType.StableDiffusionXL, ModelType.VAE, ModelFormat.Checkpoint)), + ("encoder", _config(BaseModelType.Any, ModelType.Qwen3Encoder, ModelFormat.Checkpoint)), + ], +) +def test_loader_rejects_incompatible_stored_component(target: str, stored_config: SimpleNamespace) -> None: + main = _model("main", BaseModelType.Krea2, ModelType.Main) + vae = _model("vae", BaseModelType.QwenImage, ModelType.VAE) + encoder = _model("encoder", BaseModelType.Any, ModelType.Qwen3VLEncoder) + configs = { + "main": _config(BaseModelType.Krea2, ModelType.Main, ModelFormat.Checkpoint), + "vae": _config(BaseModelType.QwenImage, ModelType.VAE, ModelFormat.Checkpoint), + "encoder": _config(BaseModelType.Any, ModelType.Qwen3VLEncoder, ModelFormat.Qwen3VLEncoder), + } + configs[target] = stored_config + + with pytest.raises(ValueError, match="Krea-2|VAE|Qwen3-VL"): + Krea2ModelLoaderInvocation(model=main, vae_model=vae, qwen3_vl_encoder_model=encoder).invoke(_context(configs)) + + +def test_loader_vae_ui_filter_includes_qwen_image_and_anima() -> None: + field = Krea2ModelLoaderInvocation.model_fields["vae_model"] + assert field.json_schema_extra is not None + assert set(field.json_schema_extra["ui_model_base"]) == { + BaseModelType.QwenImage.value, + BaseModelType.Anima.value, + } diff --git a/tests/app/invocations/test_qwen_image_working_memory.py b/tests/app/invocations/test_qwen_image_working_memory.py index f3dfbe970df..ea6cb875f09 100644 --- a/tests/app/invocations/test_qwen_image_working_memory.py +++ b/tests/app/invocations/test_qwen_image_working_memory.py @@ -112,6 +112,47 @@ def test_qwen_latents_to_image_requests_working_memory(self): assert mock_estimate.call_args.kwargs["operation"] == "decode" mock_vae_info.model_on_device.assert_called_once_with(working_mem_bytes=expected_memory) + def test_seamless_patch_is_applied_to_converted_anima_vae(self): + original_vae, mock_vae_info = self._mock_vae_info() + converted_vae = MagicMock(spec=AutoencoderKLQwenImage) + converted_vae.parameters.return_value = iter([torch.zeros(1)]) + converted_vae.dtype = torch.float32 + converted_vae.config.z_dim = 16 + converted_vae.config.latents_mean = [0.0] * 16 + converted_vae.config.latents_std = [1.0] * 16 + converted_vae.decode.side_effect = RuntimeError("stop after seamless patch") + mock_context = MagicMock() + mock_context.models.load.return_value = mock_vae_info + mock_context.tensors.load.return_value = torch.zeros(1, 16, 1, 2, 2) + + with ( + patch( + "invokeai.app.invocations.qwen_image_latents_to_image.estimate_vae_working_memory_qwen_image", + return_value=1, + ), + patch( + "invokeai.app.invocations.qwen_image_latents_to_image.as_qwen_image_vae", + return_value=converted_vae, + ), + patch( + "invokeai.app.invocations.qwen_image_latents_to_image.SeamlessExt.static_patch_model", + return_value=nullcontext(), + ) as patch_seamless, + patch( + "invokeai.app.invocations.qwen_image_latents_to_image.TorchDevice.choose_torch_device", + return_value=torch.device("cpu"), + ), + ): + invocation = QwenImageLatentsToImageInvocation.model_construct( + latents=MagicMock(latents_name="test_latents"), + vae=MagicMock(vae=MagicMock(), seamless_axes=["x"]), + ) + with pytest.raises(RuntimeError, match="stop after seamless patch"): + invocation.invoke(mock_context) + + assert original_vae is not converted_vae + patch_seamless.assert_called_once_with(converted_vae, ["x"]) + def test_qwen_image_to_latents_requests_working_memory(self): """QwenImageImageToLatentsInvocation estimates encode memory and passes it to the cache.""" mock_vae, mock_vae_info = self._mock_vae_info() diff --git a/tests/backend/model_manager/configs/test_krea2_main_config.py b/tests/backend/model_manager/configs/test_krea2_main_config.py index 2d29ccc66ab..f19ee8f0aaf 100644 --- a/tests/backend/model_manager/configs/test_krea2_main_config.py +++ b/tests/backend/model_manager/configs/test_krea2_main_config.py @@ -221,12 +221,12 @@ def test_is_distilled_true_is_turbo(self) -> None: mod = self._make_mock_mod_with_model_index(tmpdir, {"_class_name": "Krea2Pipeline", "is_distilled": True}) assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Turbo - def test_is_distilled_absent_defaults_to_turbo(self) -> None: + def test_is_distilled_absent_defaults_to_base(self) -> None: from invokeai.backend.model_manager.configs.main import Main_Diffusers_Krea2_Config with TemporaryDirectory() as tmpdir: mod = self._make_mock_mod_with_model_index(tmpdir, {"_class_name": "Krea2Pipeline"}) - assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Turbo + assert Main_Diffusers_Krea2_Config._get_variant(mod) == Krea2VariantType.Base class TestKrea2DefaultSettings: @@ -243,7 +243,7 @@ def test_turbo_defaults(self) -> None: def test_base_defaults(self) -> None: ds = MainModelDefaultSettings.from_base(BaseModelType.Krea2, Krea2VariantType.Base) assert ds is not None + assert ds.cfg_scale == 5.5 assert ds.steps == 28 - assert ds.cfg_scale == 4.5 assert ds.width == 1024 assert ds.height == 1024 diff --git a/tests/backend/model_manager/configs/test_model_path_validation.py b/tests/backend/model_manager/configs/test_model_path_validation.py index a359ed83bb2..5eb807c2b87 100644 --- a/tests/backend/model_manager/configs/test_model_path_validation.py +++ b/tests/backend/model_manager/configs/test_model_path_validation.py @@ -19,6 +19,30 @@ def test_large_directory_with_generic_config_is_rejected(tmp_path: Path) -> None ModelConfigFactory._validate_path_looks_like_model(tmp_path) +def test_large_directory_with_non_object_config_is_rejected(tmp_path: Path) -> None: + (tmp_path / "config.json").write_text("[]") + _fill_directory(tmp_path) + + with pytest.raises(ValueError, match="general-purpose directory"): + ModelConfigFactory._validate_path_looks_like_model(tmp_path) + + +@pytest.mark.parametrize( + "config", + [ + {"model_type": "application"}, + {"architectures": ["ApplicationService"]}, + {"_class_name": "ApplicationPipeline"}, + ], +) +def test_large_directory_with_unrecognized_model_markers_is_rejected(tmp_path: Path, config: dict) -> None: + (tmp_path / "config.json").write_text(json.dumps(config)) + _fill_directory(tmp_path) + + with pytest.raises(ValueError, match="general-purpose directory"): + ModelConfigFactory._validate_path_looks_like_model(tmp_path) + + def test_large_directory_with_transformers_config_is_accepted(tmp_path: Path) -> None: (tmp_path / "config.json").write_text(json.dumps({"architectures": ["Qwen3VLModel"]})) _fill_directory(tmp_path) diff --git a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py index 0580e859ce1..223daa7682b 100644 --- a/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py +++ b/tests/backend/model_manager/configs/test_qwen3_vl_encoder_config.py @@ -247,3 +247,37 @@ def test_accepts_complete_sharded_checkpoint(self, tmp_path: Path, index_name: s config = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) assert config.type is ModelType.Qwen3VLEncoder + + @pytest.mark.parametrize("bad_filename", [7, "../outside.safetensors", "/tmp/outside.safetensors"]) + def test_rejects_unsafe_or_non_string_shard_names(self, tmp_path: Path, bad_filename: object) -> None: + self._write_config(tmp_path / "config.json") + valid_shard = "model-00001-of-00002.safetensors" + (tmp_path / valid_shard).touch() + outside = tmp_path.parent / "outside.safetensors" + outside.touch() + (tmp_path / "model.safetensors.index.json").write_text( + json.dumps( + { + "weight_map": { + "language_model.layers.0.weight": valid_shard, + "language_model.layers.35.weight": bad_filename, + } + } + ) + ) + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="weights|shard|index"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path)) + + def test_rejects_existing_absolute_shard_path(self, tmp_path: Path) -> None: + self._write_config(tmp_path / "config.json") + outside = tmp_path.parent / "absolute-outside.safetensors" + outside.touch() + (tmp_path / "model.safetensors.index.json").write_text( + json.dumps({"weight_map": {"language_model.layers.0.weight": outside.as_posix()}}) + ) + (tmp_path / "tokenizer.json").touch() + + with pytest.raises(NotAMatchError, match="weights|shard|index"): + Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(ModelOnDisk(tmp_path), self._fields(tmp_path))