From e4813f800a6b3ce58714878c8315bb913a798210 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 21:14:12 -0400 Subject: [PATCH 01/21] Update calc_model_size_by_data(...) to handle all expected model types, and to log an error if an unexpected model type is received. --- invokeai/backend/ip_adapter/ip_adapter.py | 8 ++--- .../load/model_cache/model_cache_default.py | 2 +- .../backend/model_manager/load/model_util.py | 32 ++++++++++++++++--- invokeai/backend/textual_inversion.py | 8 +++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/invokeai/backend/ip_adapter/ip_adapter.py b/invokeai/backend/ip_adapter/ip_adapter.py index c33cb3f4ab..abd6ca655a 100644 --- a/invokeai/backend/ip_adapter/ip_adapter.py +++ b/invokeai/backend/ip_adapter/ip_adapter.py @@ -136,11 +136,11 @@ class IPAdapter(RawModel): self._image_proj_model.to(device=self.device, dtype=self.dtype, non_blocking=non_blocking) self.attn_weights.to(device=self.device, dtype=self.dtype, non_blocking=non_blocking) - def calc_size(self): - # workaround for circular import - from invokeai.backend.model_manager.load.model_util import calc_model_size_by_data + def calc_size(self) -> int: + # HACK(ryand): Fix this issue with circular imports. + from invokeai.backend.model_manager.load.model_util import calc_module_size - return calc_model_size_by_data(self._image_proj_model) + calc_model_size_by_data(self.attn_weights) + return calc_module_size(self._image_proj_model) + calc_module_size(self.attn_weights) def _init_image_proj_model( self, state_dict: dict[str, torch.Tensor] diff --git a/invokeai/backend/model_manager/load/model_cache/model_cache_default.py b/invokeai/backend/model_manager/load/model_cache/model_cache_default.py index 697d3daf9b..c9e68a926a 100644 --- a/invokeai/backend/model_manager/load/model_cache/model_cache_default.py +++ b/invokeai/backend/model_manager/load/model_cache/model_cache_default.py @@ -160,7 +160,7 @@ class ModelCache(ModelCacheBase[AnyModel]): key = self._make_cache_key(key, submodel_type) if key in self._cached_models: return - size = calc_model_size_by_data(model) + size = calc_model_size_by_data(self.logger, model) self.make_room(size) state_dict = model.state_dict() if isinstance(model, torch.nn.Module) else None diff --git a/invokeai/backend/model_manager/load/model_util.py b/invokeai/backend/model_manager/load/model_util.py index c55eee48fa..c798b92d8c 100644 --- a/invokeai/backend/model_manager/load/model_util.py +++ b/invokeai/backend/model_manager/load/model_util.py @@ -2,25 +2,46 @@ """Various utility functions needed by the loader and caching system.""" import json +import logging from pathlib import Path from typing import Optional import torch -from diffusers import DiffusionPipeline +from diffusers.pipelines.pipeline_utils import DiffusionPipeline +from diffusers.schedulers.scheduling_utils import SchedulerMixin +from transformers import CLIPTokenizer +from invokeai.backend.ip_adapter.ip_adapter import IPAdapter +from invokeai.backend.lora import LoRAModelRaw from invokeai.backend.model_manager.config import AnyModel from invokeai.backend.onnx.onnx_runtime import IAIOnnxRuntimeModel +from invokeai.backend.textual_inversion import TextualInversionModelRaw -def calc_model_size_by_data(model: AnyModel) -> int: +def calc_model_size_by_data(logger: logging.Logger, model: AnyModel) -> int: """Get size of a model in memory in bytes.""" + # TODO(ryand): We should create a CacheableModel interface for all models, and move the size calculations down to + # the models themselves. if isinstance(model, DiffusionPipeline): return _calc_pipeline_by_data(model) elif isinstance(model, torch.nn.Module): - return _calc_model_by_data(model) + return calc_module_size(model) elif isinstance(model, IAIOnnxRuntimeModel): return _calc_onnx_model_by_data(model) + elif isinstance(model, SchedulerMixin): + return 0 + elif isinstance(model, CLIPTokenizer): + # TODO(ryand): Accurately calculate the tokenizer's size. It's small enough that it shouldn't matter for now. + return 0 + elif isinstance(model, (TextualInversionModelRaw, IPAdapter, LoRAModelRaw)): + return model.calc_size() else: + # TODO(ryand): Promote this from a log to an exception once we are confident that we are handling all of the + # supported model types. + logger.error( + f"Failed to calculate model size for unexpected model type: {type(model)}. The model will be treated as " + "having size 0." + ) return 0 @@ -30,11 +51,12 @@ def _calc_pipeline_by_data(pipeline: DiffusionPipeline) -> int: for submodel_key in pipeline.components.keys(): submodel = getattr(pipeline, submodel_key) if submodel is not None and isinstance(submodel, torch.nn.Module): - res += _calc_model_by_data(submodel) + res += calc_module_size(submodel) return res -def _calc_model_by_data(model: torch.nn.Module) -> int: +def calc_module_size(model: torch.nn.Module) -> int: + """Calculate the size (in bytes) of a torch.nn.Module.""" mem_params = sum([param.nelement() * param.element_size() for param in model.parameters()]) mem_bufs = sum([buf.nelement() * buf.element_size() for buf in model.buffers()]) mem: int = mem_params + mem_bufs # in bytes diff --git a/invokeai/backend/textual_inversion.py b/invokeai/backend/textual_inversion.py index 0408176edb..4c7625ea37 100644 --- a/invokeai/backend/textual_inversion.py +++ b/invokeai/backend/textual_inversion.py @@ -77,6 +77,14 @@ class TextualInversionModelRaw(RawModel): if emb is not None: emb.to(device=device, dtype=dtype, non_blocking=non_blocking) + def calc_size(self) -> int: + """Get the size of this model in bytes.""" + embedding_size = self.embedding.element_size() * self.embedding.nelement() + embedding_2_size = 0 + if self.embedding_2 is not None: + embedding_2_size = self.embedding_2.element_size() * self.embedding_2.nelement() + return embedding_size + embedding_2_size + class TextualInversionManager(BaseTextualInversionManager): """TextualInversionManager implements the BaseTextualInversionManager ABC from the compel library.""" From c1afe3570423da43077ec91c452a187bf055024a Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 27 Jun 2024 15:17:22 -0400 Subject: [PATCH 02/21] Add prototype invocation for running upscaling models with spandrel. --- invokeai/app/invocations/spandrel_upscale.py | 94 ++++++++++++++++++++ pyproject.toml | 1 + 2 files changed, 95 insertions(+) create mode 100644 invokeai/app/invocations/spandrel_upscale.py diff --git a/invokeai/app/invocations/spandrel_upscale.py b/invokeai/app/invocations/spandrel_upscale.py new file mode 100644 index 0000000000..babf399cd6 --- /dev/null +++ b/invokeai/app/invocations/spandrel_upscale.py @@ -0,0 +1,94 @@ +import numpy as np +import torch +from PIL import Image +from spandrel import ImageModelDescriptor, ModelLoader + +from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation +from invokeai.app.invocations.fields import ImageField, InputField, WithBoard, WithMetadata +from invokeai.app.invocations.primitives import ImageOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.util.devices import TorchDevice + + +def pil_to_tensor(image: Image.Image) -> torch.Tensor: + """Convert PIL Image to torch.Tensor. + + Args: + image (Image.Image): A PIL Image with shape (H, W, C) and values in the range [0, 255]. + + Returns: + torch.Tensor: A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. + """ + image_np = np.array(image) + # (H, W, C) -> (C, H, W) + image_np = np.transpose(image_np, (2, 0, 1)) + image_np = image_np / 255 + image_tensor = torch.from_numpy(image_np).float() + # (C, H, W) -> (N, C, H, W) + image_tensor = image_tensor.unsqueeze(0) + return image_tensor + + +def tensor_to_pil(tensor: torch.Tensor) -> Image.Image: + """Convert torch.Tensor to PIL Image. + + Args: + tensor (torch.Tensor): A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. + + Returns: + Image.Image: A PIL Image with shape (H, W, C) and values in the range [0, 255]. + """ + # (N, C, H, W) -> (C, H, W) + tensor = tensor.squeeze(0) + # (C, H, W) -> (H, W, C) + tensor = tensor.permute(1, 2, 0) + tensor = tensor.clamp(0, 1) + tensor = (tensor * 255).cpu().detach().numpy().astype(np.uint8) + image = Image.fromarray(tensor) + return image + + +@invocation("upscale_spandrel", title="Upscale (spandrel)", tags=["upscale"], category="upscale", version="1.0.0") +class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): + """Upscales an image using any upscaler supported by spandrel (https://github.com/chaiNNer-org/spandrel).""" + + image: ImageField = InputField(description="The input image") + # TODO(ryand): Figure out how to handle all the spandrel models so that you don't have to enter a string. + model_path: str = InputField(description="The path to the upscaling model to use.") + + def invoke(self, context: InvocationContext) -> ImageOutput: + image = context.images.get_pil(self.image.image_name) + + # Load the model. + # TODO(ryand): Integrate with the model manager. + model = ModelLoader().load_from_file(self.model_path) + if not isinstance(model, ImageModelDescriptor): + raise ValueError( + f"Loaded a spandrel model of type '{type(model)}'. Only image-to-image models are supported " + "('ImageModelDescriptor')." + ) + + # Select model device and dtype. + torch_dtype = TorchDevice.choose_torch_dtype() + torch_device = TorchDevice.choose_torch_device() + if (torch_dtype == torch.float16 and not model.supports_half) or ( + torch_dtype == torch.bfloat16 and not model.supports_bfloat16 + ): + context.logger.warning( + f"The configured dtype ('{torch_dtype}') is not supported by the {type(model.model)} model. Falling " + "back to 'float32'." + ) + torch_dtype = torch.float32 + model.to(device=torch_device, dtype=torch_dtype) + + # Prepare input image for inference. + image_tensor = pil_to_tensor(image) + image_tensor = image_tensor.to(device=torch_device, dtype=torch_dtype) + + # Run inference. + image_tensor = model(image_tensor) + + # Convert the output tensor to a PIL image. + pil_image = tensor_to_pil(image_tensor) + image_dto = context.images.save(image=pil_image) + return ImageOutput.build(image_dto) diff --git a/pyproject.toml b/pyproject.toml index fcc0aff60c..fa716254de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ dependencies = [ "opencv-python==4.9.0.80", "pytorch-lightning==2.1.3", "safetensors==0.4.3", + "spandrel==0.3.4", "timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26 "torch==2.2.2", "torchmetrics==0.11.4", From c335f92345ec9e36d6ccccb3be230e0ce4c1b920 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 14:28:36 -0400 Subject: [PATCH 03/21] (minor) simplify startswith(...) syntax. --- invokeai/backend/model_manager/probe.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 2f18f1a8a6..ce68b1e902 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -221,17 +221,17 @@ class ModelProbe(object): ckpt = ckpt.get("state_dict", ckpt) for key in [str(k) for k in ckpt.keys()]: - if any(key.startswith(v) for v in {"cond_stage_model.", "first_stage_model.", "model.diffusion_model."}): + if key.startswith(("cond_stage_model.", "first_stage_model.", "model.diffusion_model.")): return ModelType.Main - elif any(key.startswith(v) for v in {"encoder.conv_in", "decoder.conv_in"}): + elif key.startswith(("encoder.conv_in", "decoder.conv_in")): return ModelType.VAE - elif any(key.startswith(v) for v in {"lora_te_", "lora_unet_"}): + elif key.startswith(("lora_te_", "lora_unet_")): return ModelType.LoRA - elif any(key.endswith(v) for v in {"to_k_lora.up.weight", "to_q_lora.down.weight"}): + elif key.endswith(("to_k_lora.up.weight", "to_q_lora.down.weight")): return ModelType.LoRA - elif any(key.startswith(v) for v in {"controlnet", "control_model", "input_blocks"}): + elif key.startswith(("controlnet", "control_model", "input_blocks")): return ModelType.ControlNet - elif any(key.startswith(v) for v in {"image_proj.", "ip_adapter."}): + elif key.startswith(("image_proj.", "ip_adapter.")): return ModelType.IPAdapter elif key in {"emb_params", "string_to_param"}: return ModelType.TextualInversion From e6abea7bc5f58069a92e0f6f7110464381786e65 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 14:30:14 -0400 Subject: [PATCH 04/21] (minor) Remove redundant else clause on a for-loop with no break statement. --- invokeai/backend/model_manager/probe.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index ce68b1e902..28b42caa53 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -235,10 +235,10 @@ class ModelProbe(object): return ModelType.IPAdapter elif key in {"emb_params", "string_to_param"}: return ModelType.TextualInversion - else: - # diffusers-ti - if len(ckpt) < 10 and all(isinstance(v, torch.Tensor) for v in ckpt.values()): - return ModelType.TextualInversion + + # diffusers-ti + if len(ckpt) < 10 and all(isinstance(v, torch.Tensor) for v in ckpt.values()): + return ModelType.TextualInversion raise InvalidModelConfigException(f"Unable to determine model type for {model_path}") From 59ce9cf41ce02057ed45d018aae386fe4c625f07 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 15:01:42 -0400 Subject: [PATCH 05/21] WIP - Begin to integrate SpandreImageToImageModel type into the model manager. --- invokeai/backend/model_manager/config.py | 1 + .../model_loaders/spandrel_image_to_image.py | 34 ++++++++++ invokeai/backend/model_manager/probe.py | 14 +++++ invokeai/backend/raw_model.py | 24 ++++--- .../backend/spandrel_image_to_image_model.py | 63 +++++++++++++++++++ 5 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py create mode 100644 invokeai/backend/spandrel_image_to_image_model.py diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index d788012dc7..9a33cc502e 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -68,6 +68,7 @@ class ModelType(str, Enum): IPAdapter = "ip_adapter" CLIPVision = "clip_vision" T2IAdapter = "t2i_adapter" + SpandrelImageToImage = "spandrel_image_to_image" class SubModelType(str, Enum): diff --git a/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py b/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py new file mode 100644 index 0000000000..4241c21d24 --- /dev/null +++ b/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py @@ -0,0 +1,34 @@ +from pathlib import Path +from typing import Optional + +from invokeai.backend.model_manager.config import ( + AnyModel, + AnyModelConfig, + BaseModelType, + ModelFormat, + ModelType, + SubModelType, +) +from invokeai.backend.model_manager.load.load_default import ModelLoader +from invokeai.backend.model_manager.load.model_loader_registry import ModelLoaderRegistry +from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel + + +@ModelLoaderRegistry.register( + base=BaseModelType.Any, type=ModelType.SpandrelImageToImage, format=ModelFormat.Checkpoint +) +class SpandrelImageToImageModelLoader(ModelLoader): + """Class for loading Spandrel Image-to-Image models (i.e. models wrapped by spandrel.ImageModelDescriptor).""" + + def _load_model( + self, + config: AnyModelConfig, + submodel_type: Optional[SubModelType] = None, + ) -> AnyModel: + if submodel_type is not None: + raise ValueError("Unexpected submodel requested for Spandrel model.") + + model_path = Path(config.path) + model = SpandrelImageToImageModel.load_from_file(model_path) + + return model diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 28b42caa53..8ba63f0db5 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -10,6 +10,7 @@ from picklescan.scanner import scan_file_path import invokeai.backend.util.logging as logger from invokeai.app.util.misc import uuid_string from invokeai.backend.model_hash.model_hash import HASHING_ALGORITHMS, ModelHash +from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel from invokeai.backend.util.silence_warnings import SilenceWarnings from .config import ( @@ -240,6 +241,14 @@ class ModelProbe(object): if len(ckpt) < 10 and all(isinstance(v, torch.Tensor) for v in ckpt.values()): return ModelType.TextualInversion + # Check if the model can be loaded as a SpandrelImageToImageModel. + try: + _ = SpandrelImageToImageModel.load_from_state_dict(ckpt) + return ModelType.SpandrelImageToImage + except Exception: + # TODO(ryand): Catch a more specific exception type here if we can. + pass + raise InvalidModelConfigException(f"Unable to determine model type for {model_path}") @classmethod @@ -570,6 +579,11 @@ class T2IAdapterCheckpointProbe(CheckpointProbeBase): raise NotImplementedError() +class SpandrelImageToImageModelProbe(CheckpointProbeBase): + def get_base_type(self) -> BaseModelType: + raise NotImplementedError() + + ######################################################## # classes for probing folders ####################################################### diff --git a/invokeai/backend/raw_model.py b/invokeai/backend/raw_model.py index 7bca6945d9..6cce354c45 100644 --- a/invokeai/backend/raw_model.py +++ b/invokeai/backend/raw_model.py @@ -1,15 +1,3 @@ -"""Base class for 'Raw' models. - -The RawModel class is the base class of LoRAModelRaw and TextualInversionModelRaw, -and is used for type checking of calls to the model patcher. Its main purpose -is to avoid a circular import issues when lora.py tries to import BaseModelType -from invokeai.backend.model_manager.config, and the latter tries to import LoRAModelRaw -from lora.py. - -The term 'raw' was introduced to describe a wrapper around a torch.nn.Module -that adds additional methods and attributes. -""" - from abc import ABC, abstractmethod from typing import Optional @@ -17,7 +5,17 @@ import torch class RawModel(ABC): - """Abstract base class for 'Raw' model wrappers.""" + """Base class for 'Raw' models. + + The RawModel class is the base class of LoRAModelRaw, TextualInversionModelRaw, etc. + and is used for type checking of calls to the model patcher. Its main purpose + is to avoid a circular import issues when lora.py tries to import BaseModelType + from invokeai.backend.model_manager.config, and the latter tries to import LoRAModelRaw + from lora.py. + + The term 'raw' was introduced to describe a wrapper around a torch.nn.Module + that adds additional methods and attributes. + """ @abstractmethod def to( diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py new file mode 100644 index 0000000000..270f521604 --- /dev/null +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -0,0 +1,63 @@ +from pathlib import Path +from typing import Any, Optional + +import torch +from spandrel import ImageModelDescriptor, ModelLoader + +from invokeai.backend.raw_model import RawModel + + +class SpandrelImageToImageModel(RawModel): + """A wrapper for a Spandrel Image-to-Image model. + + The main reason for having a wrapper class is to integrate with the type handling of RawModel. + """ + + def __init__(self, spandrel_model: ImageModelDescriptor[Any]): + self._spandrel_model = spandrel_model + + @classmethod + def load_from_file(cls, file_path: str | Path): + model = ModelLoader().load_from_file(file_path) + if not isinstance(model, ImageModelDescriptor): + raise ValueError( + f"Loaded a spandrel model of type '{type(model)}'. Only image-to-image models are supported " + "('ImageModelDescriptor')." + ) + + return cls(spandrel_model=model) + + @classmethod + def load_from_state_dict(cls, state_dict: dict[str, torch.Tensor]): + model = ModelLoader().load_from_state_dict(state_dict) + if not isinstance(model, ImageModelDescriptor): + raise ValueError( + f"Loaded a spandrel model of type '{type(model)}'. Only image-to-image models are supported " + "('ImageModelDescriptor')." + ) + + return cls(spandrel_model=model) + + def supports_dtype(self, dtype: torch.dtype) -> bool: + """Check if the model supports the given dtype.""" + if dtype == torch.float16: + return self._spandrel_model.supports_half + elif dtype == torch.bfloat16: + return self._spandrel_model.supports_bfloat16 + elif dtype == torch.float32: + # All models support float32. + return True + else: + raise ValueError(f"Unexpected dtype '{dtype}'.") + + def to( + self, + device: Optional[torch.device] = None, + dtype: Optional[torch.dtype] = None, + non_blocking: bool = False, + ) -> None: + """Note: Some models have limited dtype support. Call supports_dtype(...) to check if the dtype is supported. + Note: The non_blocking parameter is currently ignored.""" + # TODO(ryand): spandrel.ImageModelDescriptor.to(...) does not support non_blocking. We will access the model + # directly if we want to apply this optimization. + self._spandrel_model.to(device=device, dtype=dtype) From 2a1514272f949a0feecc9f45fac564594550d0f9 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 15:22:39 -0400 Subject: [PATCH 06/21] Set the dtype correctly for SpandrelImageToImageModels when they are loaded. --- .../load/model_loaders/spandrel_image_to_image.py | 11 +++++++++++ invokeai/backend/spandrel_image_to_image_model.py | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py b/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py index 4241c21d24..7a57c5cf59 100644 --- a/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py +++ b/invokeai/backend/model_manager/load/model_loaders/spandrel_image_to_image.py @@ -1,6 +1,8 @@ from pathlib import Path from typing import Optional +import torch + from invokeai.backend.model_manager.config import ( AnyModel, AnyModelConfig, @@ -31,4 +33,13 @@ class SpandrelImageToImageModelLoader(ModelLoader): model_path = Path(config.path) model = SpandrelImageToImageModel.load_from_file(model_path) + torch_dtype = self._torch_dtype + if not model.supports_dtype(torch_dtype): + self._logger.warning( + f"The configured dtype ('{self._torch_dtype}') is not supported by the {model.get_model_type_name()} " + "model. Falling back to 'float32'." + ) + torch_dtype = torch.float32 + model.to(dtype=torch_dtype) + return model diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py index 270f521604..6413ebba6b 100644 --- a/invokeai/backend/spandrel_image_to_image_model.py +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -50,6 +50,12 @@ class SpandrelImageToImageModel(RawModel): else: raise ValueError(f"Unexpected dtype '{dtype}'.") + def get_model_type_name(self) -> str: + """The model type name. Intended for logging / debugging purposes. Do not rely on this field remaining + consistent over time. + """ + return str(type(self._spandrel_model.model)) + def to( self, device: Optional[torch.device] = None, From 95079dc7d4b499470dbcf43e9ea9f4f9a2db05c9 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 15:30:35 -0400 Subject: [PATCH 07/21] Use a ModelIdentifierField to identify the spandrel model in the UpscaleSpandrelInvocation. --- invokeai/app/invocations/spandrel_upscale.py | 51 ++++++++----------- .../backend/spandrel_image_to_image_model.py | 14 +++++ 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/invokeai/app/invocations/spandrel_upscale.py b/invokeai/app/invocations/spandrel_upscale.py index babf399cd6..3e26457104 100644 --- a/invokeai/app/invocations/spandrel_upscale.py +++ b/invokeai/app/invocations/spandrel_upscale.py @@ -1,13 +1,20 @@ import numpy as np import torch from PIL import Image -from spandrel import ImageModelDescriptor, ModelLoader from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation -from invokeai.app.invocations.fields import ImageField, InputField, WithBoard, WithMetadata +from invokeai.app.invocations.fields import ( + FieldDescriptions, + ImageField, + InputField, + UIType, + WithBoard, + WithMetadata, +) +from invokeai.app.invocations.model import ModelIdentifierField from invokeai.app.invocations.primitives import ImageOutput from invokeai.app.services.shared.invocation_context import InvocationContext -from invokeai.backend.util.devices import TorchDevice +from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel def pil_to_tensor(image: Image.Image) -> torch.Tensor: @@ -53,40 +60,26 @@ class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): """Upscales an image using any upscaler supported by spandrel (https://github.com/chaiNNer-org/spandrel).""" image: ImageField = InputField(description="The input image") - # TODO(ryand): Figure out how to handle all the spandrel models so that you don't have to enter a string. - model_path: str = InputField(description="The path to the upscaling model to use.") + spandrel_image_to_image_model: ModelIdentifierField = InputField( + description=FieldDescriptions.spandrel_image_to_image_model, ui_type=UIType.LoRAModel + ) + @torch.inference_mode() def invoke(self, context: InvocationContext) -> ImageOutput: image = context.images.get_pil(self.image.image_name) # Load the model. - # TODO(ryand): Integrate with the model manager. - model = ModelLoader().load_from_file(self.model_path) - if not isinstance(model, ImageModelDescriptor): - raise ValueError( - f"Loaded a spandrel model of type '{type(model)}'. Only image-to-image models are supported " - "('ImageModelDescriptor')." - ) + spandrel_model_info = context.models.load(self.spandrel_image_to_image_model) - # Select model device and dtype. - torch_dtype = TorchDevice.choose_torch_dtype() - torch_device = TorchDevice.choose_torch_device() - if (torch_dtype == torch.float16 and not model.supports_half) or ( - torch_dtype == torch.bfloat16 and not model.supports_bfloat16 - ): - context.logger.warning( - f"The configured dtype ('{torch_dtype}') is not supported by the {type(model.model)} model. Falling " - "back to 'float32'." - ) - torch_dtype = torch.float32 - model.to(device=torch_device, dtype=torch_dtype) + with spandrel_model_info as spandrel_model: + assert isinstance(spandrel_model, SpandrelImageToImageModel) - # Prepare input image for inference. - image_tensor = pil_to_tensor(image) - image_tensor = image_tensor.to(device=torch_device, dtype=torch_dtype) + # Prepare input image for inference. + image_tensor = pil_to_tensor(image) + image_tensor = image_tensor.to(device=spandrel_model.device, dtype=spandrel_model.dtype) - # Run inference. - image_tensor = model(image_tensor) + # Run inference. + image_tensor = spandrel_model.run(image_tensor) # Convert the output tensor to a PIL image. pil_image = tensor_to_pil(image_tensor) diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py index 6413ebba6b..e5be24e80d 100644 --- a/invokeai/backend/spandrel_image_to_image_model.py +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -16,6 +16,10 @@ class SpandrelImageToImageModel(RawModel): def __init__(self, spandrel_model: ImageModelDescriptor[Any]): self._spandrel_model = spandrel_model + def run(self, image_tensor: torch.Tensor) -> torch.Tensor: + """Run the image-to-image model.""" + return self._spandrel_model(image_tensor) + @classmethod def load_from_file(cls, file_path: str | Path): model = ModelLoader().load_from_file(file_path) @@ -67,3 +71,13 @@ class SpandrelImageToImageModel(RawModel): # TODO(ryand): spandrel.ImageModelDescriptor.to(...) does not support non_blocking. We will access the model # directly if we want to apply this optimization. self._spandrel_model.to(device=device, dtype=dtype) + + @property + def device(self) -> torch.device: + """The device of the underlying model.""" + return self._spandrel_model.device + + @property + def dtype(self) -> torch.dtype: + """The dtype of the underlying model.""" + return self._spandrel_model.dtype From 29c8ddfb884e5ab9562b27145fe926b3feaff798 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 18:03:09 -0400 Subject: [PATCH 08/21] WIP - A bunch of boilerplate to support Spandrel Image-to-Image models throughout the model manager and the frontend. --- invokeai/app/invocations/fields.py | 2 + invokeai/backend/model_manager/config.py | 12 ++ invokeai/backend/model_manager/probe.py | 19 ++- .../Invocation/fields/InputFieldRenderer.tsx | 8 + ...elImageToImageModelFieldInputComponent.tsx | 56 +++++++ .../src/features/nodes/store/nodesSlice.ts | 6 + .../web/src/features/nodes/types/common.ts | 1 + .../web/src/features/nodes/types/constants.ts | 2 + .../web/src/features/nodes/types/field.ts | 33 ++++ .../util/schema/buildFieldInputInstance.ts | 1 + .../util/schema/buildFieldInputTemplate.ts | 13 ++ .../nodes/util/workflow/validateWorkflow.ts | 1 + .../src/services/api/hooks/modelsByType.ts | 2 + .../frontend/web/src/services/api/schema.ts | 144 ++++++++++++++++-- .../frontend/web/src/services/api/types.ts | 6 + 15 files changed, 287 insertions(+), 19 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx diff --git a/invokeai/app/invocations/fields.py b/invokeai/app/invocations/fields.py index b792453b47..f341039fe0 100644 --- a/invokeai/app/invocations/fields.py +++ b/invokeai/app/invocations/fields.py @@ -48,6 +48,7 @@ class UIType(str, Enum, metaclass=MetaEnum): ControlNetModel = "ControlNetModelField" IPAdapterModel = "IPAdapterModelField" T2IAdapterModel = "T2IAdapterModelField" + SpandrelImageToImageModel = "SpandrelImageToImageModelField" # endregion # region Misc Field Types @@ -134,6 +135,7 @@ class FieldDescriptions: sdxl_main_model = "SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load" sdxl_refiner_model = "SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load" onnx_main_model = "ONNX Main model (UNet, VAE, CLIP) to load" + spandrel_image_to_image_model = "Spandrel Image-to-Image model" lora_weight = "The weight at which the LoRA is applied to each model" compel_prompt = "Prompt to be parsed by Compel to create a conditioning tensor" raw_prompt = "Raw prompt text (no parsing)" diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index 9a33cc502e..3579a0c7b2 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -373,6 +373,17 @@ class T2IAdapterConfig(DiffusersConfigBase, ControlAdapterConfigBase): return Tag(f"{ModelType.T2IAdapter.value}.{ModelFormat.Diffusers.value}") +class SpandrelImageToImageConfig(ModelConfigBase): + """Model config for Spandrel Image to Image models.""" + + type: Literal[ModelType.SpandrelImageToImage] = ModelType.SpandrelImageToImage + format: Literal[ModelFormat.Checkpoint] = ModelFormat.Checkpoint + + @staticmethod + def get_tag() -> Tag: + return Tag(f"{ModelType.SpandrelImageToImage.value}.{ModelFormat.Checkpoint.value}") + + def get_model_discriminator_value(v: Any) -> str: """ Computes the discriminator value for a model config. @@ -409,6 +420,7 @@ AnyModelConfig = Annotated[ Annotated[IPAdapterInvokeAIConfig, IPAdapterInvokeAIConfig.get_tag()], Annotated[IPAdapterCheckpointConfig, IPAdapterCheckpointConfig.get_tag()], Annotated[T2IAdapterConfig, T2IAdapterConfig.get_tag()], + Annotated[SpandrelImageToImageConfig, SpandrelImageToImageConfig.get_tag()], Annotated[CLIPVisionDiffusersConfig, CLIPVisionDiffusersConfig.get_tag()], ], Discriminator(get_model_discriminator_value), diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 8ba63f0db5..53da5fc152 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -243,10 +243,14 @@ class ModelProbe(object): # Check if the model can be loaded as a SpandrelImageToImageModel. try: - _ = SpandrelImageToImageModel.load_from_state_dict(ckpt) + # TODO(ryand): Figure out why load_from_state_dict() doesn't work as expected. + # _ = SpandrelImageToImageModel.load_from_state_dict(ckpt) + _ = SpandrelImageToImageModel.load_from_file(model_path) return ModelType.SpandrelImageToImage - except Exception: + except Exception as e: # TODO(ryand): Catch a more specific exception type here if we can. + # TODO(ryand): Delete this print statement. + print(e) pass raise InvalidModelConfigException(f"Unable to determine model type for {model_path}") @@ -579,9 +583,9 @@ class T2IAdapterCheckpointProbe(CheckpointProbeBase): raise NotImplementedError() -class SpandrelImageToImageModelProbe(CheckpointProbeBase): +class SpandrelImageToImageCheckpointProbe(CheckpointProbeBase): def get_base_type(self) -> BaseModelType: - raise NotImplementedError() + return BaseModelType.Any ######################################################## @@ -791,6 +795,11 @@ class CLIPVisionFolderProbe(FolderProbeBase): return BaseModelType.Any +class SpandrelImageToImageFolderProbe(FolderProbeBase): + def get_base_type(self) -> BaseModelType: + raise NotImplementedError() + + class T2IAdapterFolderProbe(FolderProbeBase): def get_base_type(self) -> BaseModelType: config_file = self.model_path / "config.json" @@ -820,6 +829,7 @@ ModelProbe.register_probe("diffusers", ModelType.ControlNet, ControlNetFolderPro ModelProbe.register_probe("diffusers", ModelType.IPAdapter, IPAdapterFolderProbe) ModelProbe.register_probe("diffusers", ModelType.CLIPVision, CLIPVisionFolderProbe) ModelProbe.register_probe("diffusers", ModelType.T2IAdapter, T2IAdapterFolderProbe) +ModelProbe.register_probe("diffusers", ModelType.SpandrelImageToImage, SpandrelImageToImageFolderProbe) ModelProbe.register_probe("checkpoint", ModelType.Main, PipelineCheckpointProbe) ModelProbe.register_probe("checkpoint", ModelType.VAE, VaeCheckpointProbe) @@ -829,5 +839,6 @@ ModelProbe.register_probe("checkpoint", ModelType.ControlNet, ControlNetCheckpoi ModelProbe.register_probe("checkpoint", ModelType.IPAdapter, IPAdapterCheckpointProbe) ModelProbe.register_probe("checkpoint", ModelType.CLIPVision, CLIPVisionCheckpointProbe) ModelProbe.register_probe("checkpoint", ModelType.T2IAdapter, T2IAdapterCheckpointProbe) +ModelProbe.register_probe("checkpoint", ModelType.SpandrelImageToImage, SpandrelImageToImageCheckpointProbe) ModelProbe.register_probe("onnx", ModelType.ONNX, ONNXFolderProbe) diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx index 99937ceec4..b67439eb70 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx @@ -32,6 +32,8 @@ import { isSDXLMainModelFieldInputTemplate, isSDXLRefinerModelFieldInputInstance, isSDXLRefinerModelFieldInputTemplate, + isSpandrelImageToImageModelFieldInputInstance, + isSpandrelImageToImageModelFieldInputTemplate, isStringFieldInputInstance, isStringFieldInputTemplate, isT2IAdapterModelFieldInputInstance, @@ -54,6 +56,7 @@ import NumberFieldInputComponent from './inputs/NumberFieldInputComponent'; import RefinerModelFieldInputComponent from './inputs/RefinerModelFieldInputComponent'; import SchedulerFieldInputComponent from './inputs/SchedulerFieldInputComponent'; import SDXLMainModelFieldInputComponent from './inputs/SDXLMainModelFieldInputComponent'; +import SpandrelImageToImageModelFieldInputComponent from './inputs/SpandrelImageToImageModelFieldInputComponent'; import StringFieldInputComponent from './inputs/StringFieldInputComponent'; import T2IAdapterModelFieldInputComponent from './inputs/T2IAdapterModelFieldInputComponent'; import VAEModelFieldInputComponent from './inputs/VAEModelFieldInputComponent'; @@ -125,6 +128,11 @@ const InputFieldRenderer = ({ nodeId, fieldName }: InputFieldProps) => { if (isT2IAdapterModelFieldInputInstance(fieldInstance) && isT2IAdapterModelFieldInputTemplate(fieldTemplate)) { return ; } + + if (isSpandrelImageToImageModelFieldInputInstance(fieldInstance) && isSpandrelImageToImageModelFieldInputTemplate(fieldTemplate)) { + return ; + } + if (isColorFieldInputInstance(fieldInstance) && isColorFieldInputTemplate(fieldTemplate)) { return ; } diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx new file mode 100644 index 0000000000..fbb23caa90 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx @@ -0,0 +1,56 @@ +import { Combobox, FormControl, Tooltip } from '@invoke-ai/ui-library'; +import { useAppDispatch } from 'app/store/storeHooks'; +import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox'; +import { fieldSpandrelImageToImageModelValueChanged, } from 'features/nodes/store/nodesSlice'; +import type { + SpandrelImageToImageModelFieldInputInstance, + SpandrelImageToImageModelFieldInputTemplate, +} from 'features/nodes/types/field'; +import { memo, useCallback } from 'react'; +import { useSpandrelImageToImageModels } from 'services/api/hooks/modelsByType'; +import type { SpandrelImageToImageModelConfig } from 'services/api/types'; + +import type { FieldComponentProps } from './types'; + +const SpandrelImageToImageModelFieldInputComponent = ( + props: FieldComponentProps +) => { + const { nodeId, field } = props; + const dispatch = useAppDispatch(); + + const [modelConfigs, { isLoading }] = useSpandrelImageToImageModels(); + + const _onChange = useCallback( + (value: SpandrelImageToImageModelConfig | null) => { + if (!value) { + return; + } + dispatch( + + fieldSpandrelImageToImageModelValueChanged({ + nodeId, + fieldName: field.name, + value, + }) + ); + }, + [dispatch, field.name, nodeId] + ); + + const { options, value, onChange } = useGroupedModelCombobox({ + modelConfigs, + onChange: _onChange, + selectedModel: field.value, + isLoading, + }); + + return ( + + + + + + ); +}; + +export default memo(SpandrelImageToImageModelFieldInputComponent); diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index 5ebc5de147..e1a74b947d 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -19,6 +19,7 @@ import type { ModelIdentifierFieldValue, SchedulerFieldValue, SDXLRefinerModelFieldValue, + SpandrelImageToImageModelFieldValue, StatefulFieldValue, StringFieldValue, T2IAdapterModelFieldValue, @@ -39,6 +40,7 @@ import { zModelIdentifierFieldValue, zSchedulerFieldValue, zSDXLRefinerModelFieldValue, + zSpandrelImageToImageModelFieldValue, zStatefulFieldValue, zStringFieldValue, zT2IAdapterModelFieldValue, @@ -333,6 +335,9 @@ export const nodesSlice = createSlice({ fieldT2IAdapterModelValueChanged: (state, action: FieldValueAction) => { fieldValueReducer(state, action, zT2IAdapterModelFieldValue); }, + fieldSpandrelImageToImageModelValueChanged: (state, action: FieldValueAction) => { + fieldValueReducer(state, action, zSpandrelImageToImageModelFieldValue); + }, fieldEnumModelValueChanged: (state, action: FieldValueAction) => { fieldValueReducer(state, action, zEnumFieldValue); }, @@ -384,6 +389,7 @@ export const { fieldImageValueChanged, fieldIPAdapterModelValueChanged, fieldT2IAdapterModelValueChanged, + fieldSpandrelImageToImageModelValueChanged, fieldLabelChanged, fieldLoRAModelValueChanged, fieldModelIdentifierValueChanged, diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index 54e126af3a..2ea8900281 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -66,6 +66,7 @@ const zModelType = z.enum([ 'embedding', 'onnx', 'clip_vision', + 'spandrel_image_to_image', ]); const zSubModelType = z.enum([ 'unet', diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 4ede5cd479..05697c384c 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -38,6 +38,7 @@ export const MODEL_TYPES = [ 'VAEField', 'CLIPField', 'T2IAdapterModelField', + 'SpandrelImageToImageModelField', ]; /** @@ -62,6 +63,7 @@ export const FIELD_COLORS: { [key: string]: string } = { MainModelField: 'teal.500', SDXLMainModelField: 'teal.500', SDXLRefinerModelField: 'teal.500', + SpandrelImageToImageModelField: 'teal.500', StringField: 'yellow.500', T2IAdapterField: 'teal.500', T2IAdapterModelField: 'teal.500', diff --git a/invokeai/frontend/web/src/features/nodes/types/field.ts b/invokeai/frontend/web/src/features/nodes/types/field.ts index e2a84e3390..ba9078bec2 100644 --- a/invokeai/frontend/web/src/features/nodes/types/field.ts +++ b/invokeai/frontend/web/src/features/nodes/types/field.ts @@ -139,6 +139,10 @@ const zT2IAdapterModelFieldType = zFieldTypeBase.extend({ name: z.literal('T2IAdapterModelField'), originalType: zStatelessFieldType.optional(), }); +const zSpandrelImageToImageModelFieldType = zFieldTypeBase.extend({ + name: z.literal('SpandrelImageToImageModelField'), + originalType: zStatelessFieldType.optional(), +}); const zSchedulerFieldType = zFieldTypeBase.extend({ name: z.literal('SchedulerField'), originalType: zStatelessFieldType.optional(), @@ -160,6 +164,7 @@ const zStatefulFieldType = z.union([ zControlNetModelFieldType, zIPAdapterModelFieldType, zT2IAdapterModelFieldType, + zSpandrelImageToImageModelFieldType, zColorFieldType, zSchedulerFieldType, ]); @@ -581,6 +586,30 @@ export const isT2IAdapterModelFieldInputTemplate = (val: unknown): val is T2IAda zT2IAdapterModelFieldInputTemplate.safeParse(val).success; // #endregion +// #region SpandrelModelToModelField + +export const zSpandrelImageToImageModelFieldValue = zModelIdentifierField.optional(); +const zSpandrelImageToImageModelFieldInputInstance = zFieldInputInstanceBase.extend({ + value: zSpandrelImageToImageModelFieldValue, +}); +const zSpandrelImageToImageModelFieldInputTemplate = zFieldInputTemplateBase.extend({ + type: zSpandrelImageToImageModelFieldType, + originalType: zFieldType.optional(), + default: zSpandrelImageToImageModelFieldValue, +}); +const zSpandrelImageToImageModelFieldOutputTemplate = zFieldOutputTemplateBase.extend({ + type: zSpandrelImageToImageModelFieldType, +}); +export type SpandrelImageToImageModelFieldValue = z.infer; +export type SpandrelImageToImageModelFieldInputInstance = z.infer; +export type SpandrelImageToImageModelFieldInputTemplate = z.infer; +export const isSpandrelImageToImageModelFieldInputInstance = (val: unknown): val is SpandrelImageToImageModelFieldInputInstance => + zSpandrelImageToImageModelFieldInputInstance.safeParse(val).success; +export const isSpandrelImageToImageModelFieldInputTemplate = (val: unknown): val is SpandrelImageToImageModelFieldInputTemplate => + zSpandrelImageToImageModelFieldInputTemplate.safeParse(val).success; +// #endregion + + // #region SchedulerField export const zSchedulerFieldValue = zSchedulerField.optional(); @@ -667,6 +696,7 @@ export const zStatefulFieldValue = z.union([ zControlNetModelFieldValue, zIPAdapterModelFieldValue, zT2IAdapterModelFieldValue, + zSpandrelImageToImageModelFieldValue, zColorFieldValue, zSchedulerFieldValue, ]); @@ -694,6 +724,7 @@ const zStatefulFieldInputInstance = z.union([ zControlNetModelFieldInputInstance, zIPAdapterModelFieldInputInstance, zT2IAdapterModelFieldInputInstance, + zSpandrelImageToImageModelFieldInputInstance, zColorFieldInputInstance, zSchedulerFieldInputInstance, ]); @@ -722,6 +753,7 @@ const zStatefulFieldInputTemplate = z.union([ zControlNetModelFieldInputTemplate, zIPAdapterModelFieldInputTemplate, zT2IAdapterModelFieldInputTemplate, + zSpandrelImageToImageModelFieldInputTemplate, zColorFieldInputTemplate, zSchedulerFieldInputTemplate, zStatelessFieldInputTemplate, @@ -751,6 +783,7 @@ const zStatefulFieldOutputTemplate = z.union([ zControlNetModelFieldOutputTemplate, zIPAdapterModelFieldOutputTemplate, zT2IAdapterModelFieldOutputTemplate, + zSpandrelImageToImageModelFieldOutputTemplate, zColorFieldOutputTemplate, zSchedulerFieldOutputTemplate, ]); diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputInstance.ts b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputInstance.ts index 597779fd61..a5a2d89f03 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputInstance.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputInstance.ts @@ -18,6 +18,7 @@ const FIELD_VALUE_FALLBACK_MAP: Record = SDXLRefinerModelField: undefined, StringField: '', T2IAdapterModelField: undefined, + SpandrelImageToImageModelField: undefined, VAEModelField: undefined, ControlNetModelField: undefined, }; diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts index 2b77274526..8478415cd1 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts @@ -17,6 +17,7 @@ import type { SchedulerFieldInputTemplate, SDXLMainModelFieldInputTemplate, SDXLRefinerModelFieldInputTemplate, + SpandrelImageToImageModelFieldInputTemplate, StatefulFieldType, StatelessFieldInputTemplate, StringFieldInputTemplate, @@ -263,6 +264,17 @@ const buildT2IAdapterModelFieldInputTemplate: FieldInputTemplateBuilder = ({ schemaObject, baseField, fieldType }) => { + const template: SpandrelImageToImageModelFieldInputTemplate = { + ...baseField, + type: fieldType, + default: schemaObject.default ?? undefined, + }; + + return template; +}; const buildBoardFieldInputTemplate: FieldInputTemplateBuilder = ({ schemaObject, baseField, @@ -377,6 +389,7 @@ export const TEMPLATE_BUILDER_MAP: Record { + return config.type === 'spandrel_image_to_image'; +} + export const isControlAdapterModelConfig = ( config: AnyModelConfig ): config is ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig => { From 504a42fe6133ea9c949492d4a96eff909b500a82 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 28 Jun 2024 18:18:45 -0400 Subject: [PATCH 09/21] typo: fix UIType on Spandrel Upscaling node. --- invokeai/app/invocations/spandrel_upscale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/invocations/spandrel_upscale.py b/invokeai/app/invocations/spandrel_upscale.py index 3e26457104..455a466c4f 100644 --- a/invokeai/app/invocations/spandrel_upscale.py +++ b/invokeai/app/invocations/spandrel_upscale.py @@ -61,7 +61,7 @@ class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): image: ImageField = InputField(description="The input image") spandrel_image_to_image_model: ModelIdentifierField = InputField( - description=FieldDescriptions.spandrel_image_to_image_model, ui_type=UIType.LoRAModel + description=FieldDescriptions.spandrel_image_to_image_model, ui_type=UIType.SpandrelImageToImageModel ) @torch.inference_mode() From c1c8e55e8eb5bf5ca03b6aac35187626f1ce0c52 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 09:05:02 -0400 Subject: [PATCH 10/21] Fix static check errors. --- .../subpanels/ModelManagerPanel/ModelTypeFilter.tsx | 1 + .../nodes/Invocation/fields/InputFieldRenderer.tsx | 13 +++++++++++-- ...SpandrelImageToImageModelFieldInputComponent.tsx | 3 +-- .../web/src/features/nodes/store/nodesSlice.ts | 5 ++++- .../frontend/web/src/features/nodes/types/field.ts | 9 ++++++--- invokeai/frontend/web/src/services/api/types.ts | 6 ++++-- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx index 76802b36e7..85f3fd5bf6 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx @@ -21,6 +21,7 @@ export const ModelTypeFilter = () => { t2i_adapter: t('common.t2iAdapter'), ip_adapter: t('common.ipAdapter'), clip_vision: 'Clip Vision', + spandrel_image_to_image: 'Spandrel Image to Image', }), [t] ); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx index b67439eb70..d863def973 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx @@ -129,8 +129,17 @@ const InputFieldRenderer = ({ nodeId, fieldName }: InputFieldProps) => { return ; } - if (isSpandrelImageToImageModelFieldInputInstance(fieldInstance) && isSpandrelImageToImageModelFieldInputTemplate(fieldTemplate)) { - return ; + if ( + isSpandrelImageToImageModelFieldInputInstance(fieldInstance) && + isSpandrelImageToImageModelFieldInputTemplate(fieldTemplate) + ) { + return ( + + ); } if (isColorFieldInputInstance(fieldInstance) && isColorFieldInputTemplate(fieldTemplate)) { diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx index fbb23caa90..ccd4eaa797 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SpandrelImageToImageModelFieldInputComponent.tsx @@ -1,7 +1,7 @@ import { Combobox, FormControl, Tooltip } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox'; -import { fieldSpandrelImageToImageModelValueChanged, } from 'features/nodes/store/nodesSlice'; +import { fieldSpandrelImageToImageModelValueChanged } from 'features/nodes/store/nodesSlice'; import type { SpandrelImageToImageModelFieldInputInstance, SpandrelImageToImageModelFieldInputTemplate, @@ -26,7 +26,6 @@ const SpandrelImageToImageModelFieldInputComponent = ( return; } dispatch( - fieldSpandrelImageToImageModelValueChanged({ nodeId, fieldName: field.name, diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index e1a74b947d..f9214c1572 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -335,7 +335,10 @@ export const nodesSlice = createSlice({ fieldT2IAdapterModelValueChanged: (state, action: FieldValueAction) => { fieldValueReducer(state, action, zT2IAdapterModelFieldValue); }, - fieldSpandrelImageToImageModelValueChanged: (state, action: FieldValueAction) => { + fieldSpandrelImageToImageModelValueChanged: ( + state, + action: FieldValueAction + ) => { fieldValueReducer(state, action, zSpandrelImageToImageModelFieldValue); }, fieldEnumModelValueChanged: (state, action: FieldValueAction) => { diff --git a/invokeai/frontend/web/src/features/nodes/types/field.ts b/invokeai/frontend/web/src/features/nodes/types/field.ts index ba9078bec2..925bd40b9d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/field.ts +++ b/invokeai/frontend/web/src/features/nodes/types/field.ts @@ -603,13 +603,16 @@ const zSpandrelImageToImageModelFieldOutputTemplate = zFieldOutputTemplateBase.e export type SpandrelImageToImageModelFieldValue = z.infer; export type SpandrelImageToImageModelFieldInputInstance = z.infer; export type SpandrelImageToImageModelFieldInputTemplate = z.infer; -export const isSpandrelImageToImageModelFieldInputInstance = (val: unknown): val is SpandrelImageToImageModelFieldInputInstance => +export const isSpandrelImageToImageModelFieldInputInstance = ( + val: unknown +): val is SpandrelImageToImageModelFieldInputInstance => zSpandrelImageToImageModelFieldInputInstance.safeParse(val).success; -export const isSpandrelImageToImageModelFieldInputTemplate = (val: unknown): val is SpandrelImageToImageModelFieldInputTemplate => +export const isSpandrelImageToImageModelFieldInputTemplate = ( + val: unknown +): val is SpandrelImageToImageModelFieldInputTemplate => zSpandrelImageToImageModelFieldInputTemplate.safeParse(val).success; // #endregion - // #region SchedulerField export const zSchedulerFieldValue = zSchedulerField.optional(); diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 7784d3f0e5..fdfa62342d 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -86,9 +86,11 @@ export const isT2IAdapterModelConfig = (config: AnyModelConfig): config is T2IAd return config.type === 't2i_adapter'; }; -export const isSpandrelImageToImageModelConfig = (config: AnyModelConfig): config is SpandrelImageToImageModelConfig => { +export const isSpandrelImageToImageModelConfig = ( + config: AnyModelConfig +): config is SpandrelImageToImageModelConfig => { return config.type === 'spandrel_image_to_image'; -} +}; export const isControlAdapterModelConfig = ( config: AnyModelConfig From 9328c17ded3d9f36e98a3e2cb97fba42d884e728 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 09:21:25 -0400 Subject: [PATCH 11/21] Add Spandrel models to the list of models in the Model Manager tab. --- .../subpanels/ModelManagerPanel/ModelList.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx index 67e65dbfb6..7e9ec2cad6 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx @@ -11,6 +11,7 @@ import { useLoRAModels, useMainModels, useRefinerModels, + useSpandrelImageToImageModels, useT2IAdapterModels, useVAEModels, } from 'services/api/hooks/modelsByType'; @@ -71,6 +72,12 @@ const ModelList = () => { [vaeModels, searchTerm, filteredModelType] ); + const [spandrelImageToImageModels, { isLoading: isLoadingSpandrelImageToImageModels }] = useSpandrelImageToImageModels(); + const filteredSpandrelImageToImageModels = useMemo( + () => modelsFilter(spandrelImageToImageModels, searchTerm, filteredModelType), + [spandrelImageToImageModels, searchTerm, filteredModelType] + ); + const totalFilteredModels = useMemo(() => { return ( filteredMainModels.length + @@ -80,7 +87,8 @@ const ModelList = () => { filteredControlNetModels.length + filteredT2IAdapterModels.length + filteredIPAdapterModels.length + - filteredVAEModels.length + filteredVAEModels.length + + filteredSpandrelImageToImageModels.length ); }, [ filteredControlNetModels.length, @@ -91,6 +99,7 @@ const ModelList = () => { filteredRefinerModels.length, filteredT2IAdapterModels.length, filteredVAEModels.length, + filteredSpandrelImageToImageModels.length, ]); return ( @@ -143,6 +152,11 @@ const ModelList = () => { {!isLoadingT2IAdapterModels && filteredT2IAdapterModels.length > 0 && ( )} + {/* Spandrel Image to Image List */} + {isLoadingSpandrelImageToImageModels && } + {!isLoadingSpandrelImageToImageModels && filteredSpandrelImageToImageModels.length > 0 && ( + + )} {totalFilteredModels === 0 && ( {t('modelManager.noMatchingModels')} From 1ab20f43c858c6cc788c2d0fb18c63c79e5caef9 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 09:51:51 -0400 Subject: [PATCH 12/21] Tidy spandrel model probe logic, and document the reasons behind the current implementation. --- invokeai/backend/model_manager/probe.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 53da5fc152..c7267e9f1e 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import Any, Dict, Literal, Optional, Union import safetensors.torch +import spandrel import torch from picklescan.scanner import scan_file_path @@ -242,15 +243,19 @@ class ModelProbe(object): return ModelType.TextualInversion # Check if the model can be loaded as a SpandrelImageToImageModel. + # This check is intentionally performed last, as it can be expensive (it requires loading the model from disk). try: - # TODO(ryand): Figure out why load_from_state_dict() doesn't work as expected. - # _ = SpandrelImageToImageModel.load_from_state_dict(ckpt) + # It would be nice to avoid having to load the Spandrel model from disk here. A couple of options were + # explored to avoid this: + # 1. Call `SpandrelImageToImageModel.load_from_state_dict(ckpt)`, where `ckpt` is a state_dict on the meta + # device. Unfortunately, some Spandrel models perform operations during initialization that are not + # supported on meta tensors. + # 2. Spandrel has internal logic to determine a model's type from its state_dict before loading the model. + # This logic is not exposed in spandrel's public API. We could copy the logic here, but then we have to + # maintain it, and the risk of false positive detections is higher. _ = SpandrelImageToImageModel.load_from_file(model_path) return ModelType.SpandrelImageToImage - except Exception as e: - # TODO(ryand): Catch a more specific exception type here if we can. - # TODO(ryand): Delete this print statement. - print(e) + except spandrel.UnsupportedModelError: pass raise InvalidModelConfigException(f"Unable to determine model type for {model_path}") From 6161aa73afb511729fb3a7ca6b78c02e27fe3b89 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 10:11:25 -0400 Subject: [PATCH 13/21] Move pil_to_tensor() and tensor_to_pil() utilities to the SpandrelImageToImage class. --- invokeai/app/invocations/spandrel_upscale.py | 44 +----------------- .../backend/spandrel_image_to_image_model.py | 46 ++++++++++++++++++- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/invokeai/app/invocations/spandrel_upscale.py b/invokeai/app/invocations/spandrel_upscale.py index 455a466c4f..8123691668 100644 --- a/invokeai/app/invocations/spandrel_upscale.py +++ b/invokeai/app/invocations/spandrel_upscale.py @@ -1,6 +1,4 @@ -import numpy as np import torch -from PIL import Image from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation from invokeai.app.invocations.fields import ( @@ -17,44 +15,6 @@ from invokeai.app.services.shared.invocation_context import InvocationContext from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel -def pil_to_tensor(image: Image.Image) -> torch.Tensor: - """Convert PIL Image to torch.Tensor. - - Args: - image (Image.Image): A PIL Image with shape (H, W, C) and values in the range [0, 255]. - - Returns: - torch.Tensor: A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. - """ - image_np = np.array(image) - # (H, W, C) -> (C, H, W) - image_np = np.transpose(image_np, (2, 0, 1)) - image_np = image_np / 255 - image_tensor = torch.from_numpy(image_np).float() - # (C, H, W) -> (N, C, H, W) - image_tensor = image_tensor.unsqueeze(0) - return image_tensor - - -def tensor_to_pil(tensor: torch.Tensor) -> Image.Image: - """Convert torch.Tensor to PIL Image. - - Args: - tensor (torch.Tensor): A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. - - Returns: - Image.Image: A PIL Image with shape (H, W, C) and values in the range [0, 255]. - """ - # (N, C, H, W) -> (C, H, W) - tensor = tensor.squeeze(0) - # (C, H, W) -> (H, W, C) - tensor = tensor.permute(1, 2, 0) - tensor = tensor.clamp(0, 1) - tensor = (tensor * 255).cpu().detach().numpy().astype(np.uint8) - image = Image.fromarray(tensor) - return image - - @invocation("upscale_spandrel", title="Upscale (spandrel)", tags=["upscale"], category="upscale", version="1.0.0") class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): """Upscales an image using any upscaler supported by spandrel (https://github.com/chaiNNer-org/spandrel).""" @@ -75,13 +35,13 @@ class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): assert isinstance(spandrel_model, SpandrelImageToImageModel) # Prepare input image for inference. - image_tensor = pil_to_tensor(image) + image_tensor = SpandrelImageToImageModel.pil_to_tensor(image) image_tensor = image_tensor.to(device=spandrel_model.device, dtype=spandrel_model.dtype) # Run inference. image_tensor = spandrel_model.run(image_tensor) # Convert the output tensor to a PIL image. - pil_image = tensor_to_pil(image_tensor) + pil_image = SpandrelImageToImageModel.tensor_to_pil(image_tensor) image_dto = context.images.save(image=pil_image) return ImageOutput.build(image_dto) diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py index e5be24e80d..d6afcc8a04 100644 --- a/invokeai/backend/spandrel_image_to_image_model.py +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -1,7 +1,9 @@ from pathlib import Path from typing import Any, Optional +import numpy as np import torch +from PIL import Image from spandrel import ImageModelDescriptor, ModelLoader from invokeai.backend.raw_model import RawModel @@ -16,8 +18,50 @@ class SpandrelImageToImageModel(RawModel): def __init__(self, spandrel_model: ImageModelDescriptor[Any]): self._spandrel_model = spandrel_model + @staticmethod + def pil_to_tensor(image: Image.Image) -> torch.Tensor: + """Convert PIL Image to the torch.Tensor format expected by SpandrelImageToImageModel.run(). + + Args: + image (Image.Image): A PIL Image with shape (H, W, C) and values in the range [0, 255]. + + Returns: + torch.Tensor: A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. + """ + image_np = np.array(image) + # (H, W, C) -> (C, H, W) + image_np = np.transpose(image_np, (2, 0, 1)) + image_np = image_np / 255 + image_tensor = torch.from_numpy(image_np).float() + # (C, H, W) -> (N, C, H, W) + image_tensor = image_tensor.unsqueeze(0) + return image_tensor + + @staticmethod + def tensor_to_pil(tensor: torch.Tensor) -> Image.Image: + """Convert a torch.Tensor produced by SpandrelImageToImageModel.run() to a PIL Image. + + Args: + tensor (torch.Tensor): A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. + + Returns: + Image.Image: A PIL Image with shape (H, W, C) and values in the range [0, 255]. + """ + # (N, C, H, W) -> (C, H, W) + tensor = tensor.squeeze(0) + # (C, H, W) -> (H, W, C) + tensor = tensor.permute(1, 2, 0) + tensor = tensor.clamp(0, 1) + tensor = (tensor * 255).cpu().detach().numpy().astype(np.uint8) + image = Image.fromarray(tensor) + return image + def run(self, image_tensor: torch.Tensor) -> torch.Tensor: - """Run the image-to-image model.""" + """Run the image-to-image model. + + Args: + image_tensor (torch.Tensor): A torch.Tensor with shape (N, C, H, W) and values in the range [0, 1]. + """ return self._spandrel_model(image_tensor) @classmethod From 114320ee69515ce10cb42e719faa4001c6f81c77 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 10:14:20 -0400 Subject: [PATCH 14/21] (minor) typo --- invokeai/backend/spandrel_image_to_image_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py index d6afcc8a04..1b5a032d17 100644 --- a/invokeai/backend/spandrel_image_to_image_model.py +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -112,8 +112,8 @@ class SpandrelImageToImageModel(RawModel): ) -> None: """Note: Some models have limited dtype support. Call supports_dtype(...) to check if the dtype is supported. Note: The non_blocking parameter is currently ignored.""" - # TODO(ryand): spandrel.ImageModelDescriptor.to(...) does not support non_blocking. We will access the model - # directly if we want to apply this optimization. + # TODO(ryand): spandrel.ImageModelDescriptor.to(...) does not support non_blocking. We will have to access the + # model directly if we want to apply this optimization. self._spandrel_model.to(device=device, dtype=dtype) @property From 534528b85a82225286f109a869aa52f195a9cbd0 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 2 Jul 2024 10:18:29 -0400 Subject: [PATCH 15/21] Re-generate schema.ts --- .../frontend/web/src/services/api/schema.ts | 277 +++++++++--------- 1 file changed, 145 insertions(+), 132 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 154f9ab5a5..4c1a9fdbe9 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -6561,6 +6561,12 @@ export type components = { * @default false */ tiled?: boolean; + /** + * Tile Size + * @description The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the + * @default 0 + */ + tile_size?: number; /** * Fp32 * @description Whether or not to use full float32 precision @@ -7293,145 +7299,146 @@ export type components = { project_id: string | null; }; InvocationOutputMap: { - save_image: components["schemas"]["ImageOutput"]; - integer_math: components["schemas"]["IntegerOutput"]; - segment_anything_processor: components["schemas"]["ImageOutput"]; - sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"]; - zoe_depth_image_processor: components["schemas"]["ImageOutput"]; - collect: components["schemas"]["CollectInvocationOutput"]; - range: components["schemas"]["IntegerCollectionOutput"]; - unsharp_mask: components["schemas"]["ImageOutput"]; - string_replace: components["schemas"]["StringOutput"]; - face_identifier: components["schemas"]["ImageOutput"]; - heuristic_resize: components["schemas"]["ImageOutput"]; - range_of_size: components["schemas"]["IntegerCollectionOutput"]; - latents_collection: components["schemas"]["LatentsCollectionOutput"]; - color_map_image_processor: components["schemas"]["ImageOutput"]; - img_ilerp: components["schemas"]["ImageOutput"]; - infill_patchmatch: components["schemas"]["ImageOutput"]; - face_off: components["schemas"]["FaceOffOutput"]; - string_collection: components["schemas"]["StringCollectionOutput"]; - sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"]; - sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"]; - string_join: components["schemas"]["StringOutput"]; - lblend: components["schemas"]["LatentsOutput"]; - conditioning_collection: components["schemas"]["ConditioningCollectionOutput"]; - string_split_neg: components["schemas"]["StringPosNegOutput"]; - img_watermark: components["schemas"]["ImageOutput"]; - infill_lama: components["schemas"]["ImageOutput"]; - div: components["schemas"]["IntegerOutput"]; - show_image: components["schemas"]["ImageOutput"]; - tile_to_properties: components["schemas"]["TileToPropertiesOutput"]; - sub: components["schemas"]["IntegerOutput"]; normalbae_image_processor: components["schemas"]["ImageOutput"]; - invert_tensor_mask: components["schemas"]["MaskOutput"]; - create_gradient_mask: components["schemas"]["GradientMaskOutput"]; - string_split: components["schemas"]["String2Output"]; - step_param_easing: components["schemas"]["FloatCollectionOutput"]; - metadata: components["schemas"]["MetadataOutput"]; - img_pad_crop: components["schemas"]["ImageOutput"]; - integer: components["schemas"]["IntegerOutput"]; - img_mul: components["schemas"]["ImageOutput"]; - calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"]; - color: components["schemas"]["ColorOutput"]; - infill_rgba: components["schemas"]["ImageOutput"]; - t2i_adapter: components["schemas"]["T2IAdapterOutput"]; - denoise_latents: components["schemas"]["LatentsOutput"]; - img_lerp: components["schemas"]["ImageOutput"]; - img_channel_offset: components["schemas"]["ImageOutput"]; - img_crop: components["schemas"]["ImageOutput"]; - alpha_mask_to_tensor: components["schemas"]["MaskOutput"]; - color_correct: components["schemas"]["ImageOutput"]; - calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"]; - img_hue_adjust: components["schemas"]["ImageOutput"]; - lresize: components["schemas"]["LatentsOutput"]; - img_blur: components["schemas"]["ImageOutput"]; - compel: components["schemas"]["ConditioningOutput"]; - sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"]; - float_to_int: components["schemas"]["IntegerOutput"]; - boolean: components["schemas"]["BooleanOutput"]; - string_join_three: components["schemas"]["StringOutput"]; - add: components["schemas"]["IntegerOutput"]; - merge_tiles_to_image: components["schemas"]["ImageOutput"]; - core_metadata: components["schemas"]["MetadataOutput"]; - lscale: components["schemas"]["LatentsOutput"]; - mlsd_image_processor: components["schemas"]["ImageOutput"]; - image_collection: components["schemas"]["ImageCollectionOutput"]; - crop_latents: components["schemas"]["LatentsOutput"]; - image_mask_to_tensor: components["schemas"]["MaskOutput"]; - lora_collection_loader: components["schemas"]["LoRALoaderOutput"]; - ip_adapter: components["schemas"]["IPAdapterOutput"]; - pidi_image_processor: components["schemas"]["ImageOutput"]; - rand_int: components["schemas"]["IntegerOutput"]; - img_conv: components["schemas"]["ImageOutput"]; - scheduler: components["schemas"]["SchedulerOutput"]; - img_paste: components["schemas"]["ImageOutput"]; - noise: components["schemas"]["NoiseOutput"]; - img_scale: components["schemas"]["ImageOutput"]; - i2l: components["schemas"]["LatentsOutput"]; - main_model_loader: components["schemas"]["ModelLoaderOutput"]; - blank_image: components["schemas"]["ImageOutput"]; - mask_edge: components["schemas"]["ImageOutput"]; - seamless: components["schemas"]["SeamlessModeOutput"]; - esrgan: components["schemas"]["ImageOutput"]; - canvas_paste_back: components["schemas"]["ImageOutput"]; - mul: components["schemas"]["IntegerOutput"]; - dynamic_prompt: components["schemas"]["StringCollectionOutput"]; - controlnet: components["schemas"]["ControlOutput"]; - l2i: components["schemas"]["ImageOutput"]; - ideal_size: components["schemas"]["IdealSizeOutput"]; - latents: components["schemas"]["LatentsOutput"]; - midas_depth_image_processor: components["schemas"]["ImageOutput"]; - tomask: components["schemas"]["ImageOutput"]; - float_math: components["schemas"]["FloatOutput"]; - round_float: components["schemas"]["FloatOutput"]; - cv_inpaint: components["schemas"]["ImageOutput"]; - create_denoise_mask: components["schemas"]["DenoiseMaskOutput"]; - model_identifier: components["schemas"]["ModelIdentifierOutput"]; - pair_tile_image: components["schemas"]["PairTileImageOutput"]; - lineart_image_processor: components["schemas"]["ImageOutput"]; - img_nsfw: components["schemas"]["ImageOutput"]; - infill_cv2: components["schemas"]["ImageOutput"]; - clip_skip: components["schemas"]["CLIPSkipInvocationOutput"]; - dw_openpose_image_processor: components["schemas"]["ImageOutput"]; - img_resize: components["schemas"]["ImageOutput"]; - iterate: components["schemas"]["IterateInvocationOutput"]; - rectangle_mask: components["schemas"]["MaskOutput"]; - canny_image_processor: components["schemas"]["ImageOutput"]; - calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"]; - mask_from_id: components["schemas"]["ImageOutput"]; - metadata_item: components["schemas"]["MetadataItemOutput"]; - infill_tile: components["schemas"]["ImageOutput"]; - tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"]; - img_channel_multiply: components["schemas"]["ImageOutput"]; - boolean_collection: components["schemas"]["BooleanCollectionOutput"]; - lora_loader: components["schemas"]["LoRALoaderOutput"]; - float_collection: components["schemas"]["FloatCollectionOutput"]; - string: components["schemas"]["StringOutput"]; - freeu: components["schemas"]["UNetOutput"]; - lineart_anime_image_processor: components["schemas"]["ImageOutput"]; - depth_anything_image_processor: components["schemas"]["ImageOutput"]; - image: components["schemas"]["ImageOutput"]; - face_mask_detection: components["schemas"]["FaceMaskOutput"]; - rand_float: components["schemas"]["FloatOutput"]; - float: components["schemas"]["FloatOutput"]; - random_range: components["schemas"]["IntegerCollectionOutput"]; - integer_collection: components["schemas"]["IntegerCollectionOutput"]; - sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"]; mask_combine: components["schemas"]["ImageOutput"]; - tile_image_processor: components["schemas"]["ImageOutput"]; - img_chan: components["schemas"]["ImageOutput"]; - vae_loader: components["schemas"]["VAEOutput"]; + save_image: components["schemas"]["ImageOutput"]; + lineart_anime_image_processor: components["schemas"]["ImageOutput"]; + latents: components["schemas"]["LatentsOutput"]; + add: components["schemas"]["IntegerOutput"]; + sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"]; + t2i_adapter: components["schemas"]["T2IAdapterOutput"]; + lblend: components["schemas"]["LatentsOutput"]; + sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"]; + lora_collection_loader: components["schemas"]["LoRALoaderOutput"]; + esrgan: components["schemas"]["ImageOutput"]; + noise: components["schemas"]["NoiseOutput"]; + conditioning_collection: components["schemas"]["ConditioningCollectionOutput"]; + mlsd_image_processor: components["schemas"]["ImageOutput"]; + canvas_paste_back: components["schemas"]["ImageOutput"]; + cv_inpaint: components["schemas"]["ImageOutput"]; prompt_from_file: components["schemas"]["StringCollectionOutput"]; - float_range: components["schemas"]["FloatCollectionOutput"]; - merge_metadata: components["schemas"]["MetadataOutput"]; - sdxl_compel_prompt: components["schemas"]["ConditioningOutput"]; - hed_image_processor: components["schemas"]["ImageOutput"]; + unsharp_mask: components["schemas"]["ImageOutput"]; lora_selector: components["schemas"]["LoRASelectorOutput"]; + img_scale: components["schemas"]["ImageOutput"]; + img_resize: components["schemas"]["ImageOutput"]; + integer_collection: components["schemas"]["IntegerCollectionOutput"]; + latents_collection: components["schemas"]["LatentsCollectionOutput"]; conditioning: components["schemas"]["ConditioningOutput"]; - leres_image_processor: components["schemas"]["ImageOutput"]; + segment_anything_processor: components["schemas"]["ImageOutput"]; + calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"]; + sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"]; + lscale: components["schemas"]["LatentsOutput"]; + crop_latents: components["schemas"]["LatentsOutput"]; + sub: components["schemas"]["IntegerOutput"]; + infill_patchmatch: components["schemas"]["ImageOutput"]; + create_denoise_mask: components["schemas"]["DenoiseMaskOutput"]; + freeu: components["schemas"]["UNetOutput"]; + heuristic_resize: components["schemas"]["ImageOutput"]; + calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"]; + image: components["schemas"]["ImageOutput"]; + controlnet: components["schemas"]["ControlOutput"]; + img_pad_crop: components["schemas"]["ImageOutput"]; + img_paste: components["schemas"]["ImageOutput"]; + string_split_neg: components["schemas"]["StringPosNegOutput"]; + face_identifier: components["schemas"]["ImageOutput"]; + model_identifier: components["schemas"]["ModelIdentifierOutput"]; + integer: components["schemas"]["IntegerOutput"]; + merge_tiles_to_image: components["schemas"]["ImageOutput"]; + scheduler: components["schemas"]["SchedulerOutput"]; + mul: components["schemas"]["IntegerOutput"]; + metadata: components["schemas"]["MetadataOutput"]; + boolean: components["schemas"]["BooleanOutput"]; + lineart_image_processor: components["schemas"]["ImageOutput"]; + clip_skip: components["schemas"]["CLIPSkipInvocationOutput"]; + img_ilerp: components["schemas"]["ImageOutput"]; + dw_openpose_image_processor: components["schemas"]["ImageOutput"]; + float_range: components["schemas"]["FloatCollectionOutput"]; + rectangle_mask: components["schemas"]["MaskOutput"]; + metadata_item: components["schemas"]["MetadataItemOutput"]; + seamless: components["schemas"]["SeamlessModeOutput"]; + float_to_int: components["schemas"]["IntegerOutput"]; + calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"]; + string_replace: components["schemas"]["StringOutput"]; + infill_rgba: components["schemas"]["ImageOutput"]; + depth_anything_image_processor: components["schemas"]["ImageOutput"]; mediapipe_face_processor: components["schemas"]["ImageOutput"]; + img_blur: components["schemas"]["ImageOutput"]; + face_mask_detection: components["schemas"]["FaceMaskOutput"]; + color: components["schemas"]["ColorOutput"]; + string_join: components["schemas"]["StringOutput"]; content_shuffle_image_processor: components["schemas"]["ImageOutput"]; + invert_tensor_mask: components["schemas"]["MaskOutput"]; + float_collection: components["schemas"]["FloatCollectionOutput"]; + create_gradient_mask: components["schemas"]["GradientMaskOutput"]; + integer_math: components["schemas"]["IntegerOutput"]; + ip_adapter: components["schemas"]["IPAdapterOutput"]; + img_conv: components["schemas"]["ImageOutput"]; + img_crop: components["schemas"]["ImageOutput"]; + pair_tile_image: components["schemas"]["PairTileImageOutput"]; + string_join_three: components["schemas"]["StringOutput"]; + merge_metadata: components["schemas"]["MetadataOutput"]; + upscale_spandrel: components["schemas"]["ImageOutput"]; + denoise_latents: components["schemas"]["LatentsOutput"]; + float: components["schemas"]["FloatOutput"]; + collect: components["schemas"]["CollectInvocationOutput"]; + boolean_collection: components["schemas"]["BooleanCollectionOutput"]; + infill_tile: components["schemas"]["ImageOutput"]; + zoe_depth_image_processor: components["schemas"]["ImageOutput"]; + core_metadata: components["schemas"]["MetadataOutput"]; + string_split: components["schemas"]["String2Output"]; + random_range: components["schemas"]["IntegerCollectionOutput"]; + range: components["schemas"]["IntegerCollectionOutput"]; + div: components["schemas"]["IntegerOutput"]; + float_math: components["schemas"]["FloatOutput"]; + l2i: components["schemas"]["ImageOutput"]; + vae_loader: components["schemas"]["VAEOutput"]; + img_channel_offset: components["schemas"]["ImageOutput"]; + img_chan: components["schemas"]["ImageOutput"]; + img_nsfw: components["schemas"]["ImageOutput"]; + canny_image_processor: components["schemas"]["ImageOutput"]; + show_image: components["schemas"]["ImageOutput"]; + lresize: components["schemas"]["LatentsOutput"]; + blank_image: components["schemas"]["ImageOutput"]; + color_correct: components["schemas"]["ImageOutput"]; + tile_image_processor: components["schemas"]["ImageOutput"]; + string: components["schemas"]["StringOutput"]; + pidi_image_processor: components["schemas"]["ImageOutput"]; + dynamic_prompt: components["schemas"]["StringCollectionOutput"]; + mask_edge: components["schemas"]["ImageOutput"]; + compel: components["schemas"]["ConditioningOutput"]; + hed_image_processor: components["schemas"]["ImageOutput"]; + img_watermark: components["schemas"]["ImageOutput"]; + alpha_mask_to_tensor: components["schemas"]["MaskOutput"]; + mask_from_id: components["schemas"]["ImageOutput"]; + tile_to_properties: components["schemas"]["TileToPropertiesOutput"]; + tomask: components["schemas"]["ImageOutput"]; + sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"]; + tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"]; + sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"]; + img_hue_adjust: components["schemas"]["ImageOutput"]; + face_off: components["schemas"]["FaceOffOutput"]; + img_mul: components["schemas"]["ImageOutput"]; + rand_int: components["schemas"]["IntegerOutput"]; + image_mask_to_tensor: components["schemas"]["MaskOutput"]; + rand_float: components["schemas"]["FloatOutput"]; + img_lerp: components["schemas"]["ImageOutput"]; + i2l: components["schemas"]["LatentsOutput"]; + image_collection: components["schemas"]["ImageCollectionOutput"]; + round_float: components["schemas"]["FloatOutput"]; + leres_image_processor: components["schemas"]["ImageOutput"]; + lora_loader: components["schemas"]["LoRALoaderOutput"]; + infill_cv2: components["schemas"]["ImageOutput"]; + infill_lama: components["schemas"]["ImageOutput"]; + ideal_size: components["schemas"]["IdealSizeOutput"]; + sdxl_compel_prompt: components["schemas"]["ConditioningOutput"]; + midas_depth_image_processor: components["schemas"]["ImageOutput"]; + color_map_image_processor: components["schemas"]["ImageOutput"]; + img_channel_multiply: components["schemas"]["ImageOutput"]; + iterate: components["schemas"]["IterateInvocationOutput"]; + string_collection: components["schemas"]["StringCollectionOutput"]; + step_param_easing: components["schemas"]["FloatCollectionOutput"]; + main_model_loader: components["schemas"]["ModelLoaderOutput"]; + range_of_size: components["schemas"]["IntegerCollectionOutput"]; }; /** * InvocationStartedEvent @@ -7769,6 +7776,12 @@ export type components = { * @default false */ tiled?: boolean; + /** + * Tile Size + * @description The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the + * @default 0 + */ + tile_size?: number; /** * Fp32 * @description Whether or not to use full float32 precision From 9d3739244f037302da7c302a59242fc06c798ff7 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 3 Jul 2024 15:57:02 -0400 Subject: [PATCH 16/21] Prettier formatting. --- .../subpanels/ModelManagerPanel/ModelList.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx index 7e9ec2cad6..f531fc2f9a 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx @@ -72,7 +72,8 @@ const ModelList = () => { [vaeModels, searchTerm, filteredModelType] ); - const [spandrelImageToImageModels, { isLoading: isLoadingSpandrelImageToImageModels }] = useSpandrelImageToImageModels(); + const [spandrelImageToImageModels, { isLoading: isLoadingSpandrelImageToImageModels }] = + useSpandrelImageToImageModels(); const filteredSpandrelImageToImageModels = useMemo( () => modelsFilter(spandrelImageToImageModels, searchTerm, filteredModelType), [spandrelImageToImageModels, searchTerm, filteredModelType] @@ -153,9 +154,15 @@ const ModelList = () => { )} {/* Spandrel Image to Image List */} - {isLoadingSpandrelImageToImageModels && } + {isLoadingSpandrelImageToImageModels && ( + + )} {!isLoadingSpandrelImageToImageModels && filteredSpandrelImageToImageModels.length > 0 && ( - + )} {totalFilteredModels === 0 && ( From a405f14ea2853a3a5cf10076511f2d918fceaef6 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 3 Jul 2024 16:38:16 -0400 Subject: [PATCH 17/21] Fix SpandrelImageToImageModel size calculation for the model cache. --- invokeai/backend/model_manager/load/model_util.py | 3 ++- invokeai/backend/spandrel_image_to_image_model.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/model_manager/load/model_util.py b/invokeai/backend/model_manager/load/model_util.py index c798b92d8c..57ff81c2ef 100644 --- a/invokeai/backend/model_manager/load/model_util.py +++ b/invokeai/backend/model_manager/load/model_util.py @@ -15,6 +15,7 @@ from invokeai.backend.ip_adapter.ip_adapter import IPAdapter from invokeai.backend.lora import LoRAModelRaw from invokeai.backend.model_manager.config import AnyModel from invokeai.backend.onnx.onnx_runtime import IAIOnnxRuntimeModel +from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel from invokeai.backend.textual_inversion import TextualInversionModelRaw @@ -33,7 +34,7 @@ def calc_model_size_by_data(logger: logging.Logger, model: AnyModel) -> int: elif isinstance(model, CLIPTokenizer): # TODO(ryand): Accurately calculate the tokenizer's size. It's small enough that it shouldn't matter for now. return 0 - elif isinstance(model, (TextualInversionModelRaw, IPAdapter, LoRAModelRaw)): + elif isinstance(model, (TextualInversionModelRaw, IPAdapter, LoRAModelRaw, SpandrelImageToImageModel)): return model.calc_size() else: # TODO(ryand): Promote this from a log to an exception once we are confident that we are handling all of the diff --git a/invokeai/backend/spandrel_image_to_image_model.py b/invokeai/backend/spandrel_image_to_image_model.py index 1b5a032d17..adb78d0d71 100644 --- a/invokeai/backend/spandrel_image_to_image_model.py +++ b/invokeai/backend/spandrel_image_to_image_model.py @@ -125,3 +125,10 @@ class SpandrelImageToImageModel(RawModel): def dtype(self) -> torch.dtype: """The dtype of the underlying model.""" return self._spandrel_model.dtype + + def calc_size(self) -> int: + """Get size of the model in memory in bytes.""" + # HACK(ryand): Fix this issue with circular imports. + from invokeai.backend.model_manager.load.model_util import calc_module_size + + return calc_module_size(self._spandrel_model.model) From d09999736ca416e46d1d7e4c252f7afe81f9e368 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 5 Jul 2024 14:04:08 -0400 Subject: [PATCH 18/21] Rename spandrel models to 'Image-to-Image Model' throughout the UI. --- invokeai/app/invocations/fields.py | 2 +- invokeai/app/invocations/spandrel_upscale.py | 47 --- .../subpanels/ModelManagerPanel/ModelList.tsx | 4 +- .../ModelManagerPanel/ModelTypeFilter.tsx | 2 +- .../frontend/web/src/services/api/schema.ts | 389 +++++++++--------- 5 files changed, 199 insertions(+), 245 deletions(-) delete mode 100644 invokeai/app/invocations/spandrel_upscale.py diff --git a/invokeai/app/invocations/fields.py b/invokeai/app/invocations/fields.py index f341039fe0..dff2084de7 100644 --- a/invokeai/app/invocations/fields.py +++ b/invokeai/app/invocations/fields.py @@ -135,7 +135,7 @@ class FieldDescriptions: sdxl_main_model = "SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load" sdxl_refiner_model = "SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load" onnx_main_model = "ONNX Main model (UNet, VAE, CLIP) to load" - spandrel_image_to_image_model = "Spandrel Image-to-Image model" + spandrel_image_to_image_model = "Image-to-Image model" lora_weight = "The weight at which the LoRA is applied to each model" compel_prompt = "Prompt to be parsed by Compel to create a conditioning tensor" raw_prompt = "Raw prompt text (no parsing)" diff --git a/invokeai/app/invocations/spandrel_upscale.py b/invokeai/app/invocations/spandrel_upscale.py deleted file mode 100644 index 8123691668..0000000000 --- a/invokeai/app/invocations/spandrel_upscale.py +++ /dev/null @@ -1,47 +0,0 @@ -import torch - -from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation -from invokeai.app.invocations.fields import ( - FieldDescriptions, - ImageField, - InputField, - UIType, - WithBoard, - WithMetadata, -) -from invokeai.app.invocations.model import ModelIdentifierField -from invokeai.app.invocations.primitives import ImageOutput -from invokeai.app.services.shared.invocation_context import InvocationContext -from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel - - -@invocation("upscale_spandrel", title="Upscale (spandrel)", tags=["upscale"], category="upscale", version="1.0.0") -class UpscaleSpandrelInvocation(BaseInvocation, WithMetadata, WithBoard): - """Upscales an image using any upscaler supported by spandrel (https://github.com/chaiNNer-org/spandrel).""" - - image: ImageField = InputField(description="The input image") - spandrel_image_to_image_model: ModelIdentifierField = InputField( - description=FieldDescriptions.spandrel_image_to_image_model, ui_type=UIType.SpandrelImageToImageModel - ) - - @torch.inference_mode() - def invoke(self, context: InvocationContext) -> ImageOutput: - image = context.images.get_pil(self.image.image_name) - - # Load the model. - spandrel_model_info = context.models.load(self.spandrel_image_to_image_model) - - with spandrel_model_info as spandrel_model: - assert isinstance(spandrel_model, SpandrelImageToImageModel) - - # Prepare input image for inference. - image_tensor = SpandrelImageToImageModel.pil_to_tensor(image) - image_tensor = image_tensor.to(device=spandrel_model.device, dtype=spandrel_model.dtype) - - # Run inference. - image_tensor = spandrel_model.run(image_tensor) - - # Convert the output tensor to a PIL image. - pil_image = SpandrelImageToImageModel.tensor_to_pil(image_tensor) - image_dto = context.images.save(image=pil_image) - return ImageOutput.build(image_dto) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx index f531fc2f9a..b82917221e 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx @@ -155,11 +155,11 @@ const ModelList = () => { )} {/* Spandrel Image to Image List */} {isLoadingSpandrelImageToImageModels && ( - + )} {!isLoadingSpandrelImageToImageModels && filteredSpandrelImageToImageModels.length > 0 && ( diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx index 85f3fd5bf6..1a2444870b 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx @@ -21,7 +21,7 @@ export const ModelTypeFilter = () => { t2i_adapter: t('common.t2iAdapter'), ip_adapter: t('common.ipAdapter'), clip_vision: 'Clip Vision', - spandrel_image_to_image: 'Spandrel Image to Image', + spandrel_image_to_image: 'Image-to-Image', }), [t] ); diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 4c1a9fdbe9..3bd322278b 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -4784,7 +4784,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["UpscaleSpandrelInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; + [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; }; /** * Edges @@ -7155,7 +7155,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["UpscaleSpandrelInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -7201,7 +7201,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["UpscaleSpandrelInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -7264,7 +7264,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["UpscaleSpandrelInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -7299,146 +7299,146 @@ export type components = { project_id: string | null; }; InvocationOutputMap: { - normalbae_image_processor: components["schemas"]["ImageOutput"]; - mask_combine: components["schemas"]["ImageOutput"]; - save_image: components["schemas"]["ImageOutput"]; - lineart_anime_image_processor: components["schemas"]["ImageOutput"]; - latents: components["schemas"]["LatentsOutput"]; - add: components["schemas"]["IntegerOutput"]; - sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"]; - t2i_adapter: components["schemas"]["T2IAdapterOutput"]; - lblend: components["schemas"]["LatentsOutput"]; - sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"]; - lora_collection_loader: components["schemas"]["LoRALoaderOutput"]; - esrgan: components["schemas"]["ImageOutput"]; - noise: components["schemas"]["NoiseOutput"]; - conditioning_collection: components["schemas"]["ConditioningCollectionOutput"]; - mlsd_image_processor: components["schemas"]["ImageOutput"]; - canvas_paste_back: components["schemas"]["ImageOutput"]; - cv_inpaint: components["schemas"]["ImageOutput"]; - prompt_from_file: components["schemas"]["StringCollectionOutput"]; - unsharp_mask: components["schemas"]["ImageOutput"]; - lora_selector: components["schemas"]["LoRASelectorOutput"]; - img_scale: components["schemas"]["ImageOutput"]; - img_resize: components["schemas"]["ImageOutput"]; - integer_collection: components["schemas"]["IntegerCollectionOutput"]; - latents_collection: components["schemas"]["LatentsCollectionOutput"]; - conditioning: components["schemas"]["ConditioningOutput"]; - segment_anything_processor: components["schemas"]["ImageOutput"]; - calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"]; - sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"]; - lscale: components["schemas"]["LatentsOutput"]; - crop_latents: components["schemas"]["LatentsOutput"]; - sub: components["schemas"]["IntegerOutput"]; - infill_patchmatch: components["schemas"]["ImageOutput"]; - create_denoise_mask: components["schemas"]["DenoiseMaskOutput"]; - freeu: components["schemas"]["UNetOutput"]; - heuristic_resize: components["schemas"]["ImageOutput"]; - calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"]; - image: components["schemas"]["ImageOutput"]; - controlnet: components["schemas"]["ControlOutput"]; - img_pad_crop: components["schemas"]["ImageOutput"]; - img_paste: components["schemas"]["ImageOutput"]; - string_split_neg: components["schemas"]["StringPosNegOutput"]; - face_identifier: components["schemas"]["ImageOutput"]; - model_identifier: components["schemas"]["ModelIdentifierOutput"]; - integer: components["schemas"]["IntegerOutput"]; - merge_tiles_to_image: components["schemas"]["ImageOutput"]; - scheduler: components["schemas"]["SchedulerOutput"]; - mul: components["schemas"]["IntegerOutput"]; - metadata: components["schemas"]["MetadataOutput"]; - boolean: components["schemas"]["BooleanOutput"]; - lineart_image_processor: components["schemas"]["ImageOutput"]; - clip_skip: components["schemas"]["CLIPSkipInvocationOutput"]; - img_ilerp: components["schemas"]["ImageOutput"]; - dw_openpose_image_processor: components["schemas"]["ImageOutput"]; - float_range: components["schemas"]["FloatCollectionOutput"]; - rectangle_mask: components["schemas"]["MaskOutput"]; - metadata_item: components["schemas"]["MetadataItemOutput"]; - seamless: components["schemas"]["SeamlessModeOutput"]; - float_to_int: components["schemas"]["IntegerOutput"]; - calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"]; - string_replace: components["schemas"]["StringOutput"]; - infill_rgba: components["schemas"]["ImageOutput"]; - depth_anything_image_processor: components["schemas"]["ImageOutput"]; - mediapipe_face_processor: components["schemas"]["ImageOutput"]; - img_blur: components["schemas"]["ImageOutput"]; - face_mask_detection: components["schemas"]["FaceMaskOutput"]; - color: components["schemas"]["ColorOutput"]; - string_join: components["schemas"]["StringOutput"]; - content_shuffle_image_processor: components["schemas"]["ImageOutput"]; - invert_tensor_mask: components["schemas"]["MaskOutput"]; - float_collection: components["schemas"]["FloatCollectionOutput"]; - create_gradient_mask: components["schemas"]["GradientMaskOutput"]; - integer_math: components["schemas"]["IntegerOutput"]; - ip_adapter: components["schemas"]["IPAdapterOutput"]; - img_conv: components["schemas"]["ImageOutput"]; - img_crop: components["schemas"]["ImageOutput"]; - pair_tile_image: components["schemas"]["PairTileImageOutput"]; - string_join_three: components["schemas"]["StringOutput"]; - merge_metadata: components["schemas"]["MetadataOutput"]; - upscale_spandrel: components["schemas"]["ImageOutput"]; - denoise_latents: components["schemas"]["LatentsOutput"]; - float: components["schemas"]["FloatOutput"]; - collect: components["schemas"]["CollectInvocationOutput"]; - boolean_collection: components["schemas"]["BooleanCollectionOutput"]; - infill_tile: components["schemas"]["ImageOutput"]; - zoe_depth_image_processor: components["schemas"]["ImageOutput"]; - core_metadata: components["schemas"]["MetadataOutput"]; - string_split: components["schemas"]["String2Output"]; - random_range: components["schemas"]["IntegerCollectionOutput"]; - range: components["schemas"]["IntegerCollectionOutput"]; - div: components["schemas"]["IntegerOutput"]; - float_math: components["schemas"]["FloatOutput"]; - l2i: components["schemas"]["ImageOutput"]; - vae_loader: components["schemas"]["VAEOutput"]; - img_channel_offset: components["schemas"]["ImageOutput"]; - img_chan: components["schemas"]["ImageOutput"]; - img_nsfw: components["schemas"]["ImageOutput"]; - canny_image_processor: components["schemas"]["ImageOutput"]; - show_image: components["schemas"]["ImageOutput"]; - lresize: components["schemas"]["LatentsOutput"]; - blank_image: components["schemas"]["ImageOutput"]; - color_correct: components["schemas"]["ImageOutput"]; - tile_image_processor: components["schemas"]["ImageOutput"]; - string: components["schemas"]["StringOutput"]; - pidi_image_processor: components["schemas"]["ImageOutput"]; - dynamic_prompt: components["schemas"]["StringCollectionOutput"]; - mask_edge: components["schemas"]["ImageOutput"]; - compel: components["schemas"]["ConditioningOutput"]; - hed_image_processor: components["schemas"]["ImageOutput"]; - img_watermark: components["schemas"]["ImageOutput"]; - alpha_mask_to_tensor: components["schemas"]["MaskOutput"]; - mask_from_id: components["schemas"]["ImageOutput"]; - tile_to_properties: components["schemas"]["TileToPropertiesOutput"]; - tomask: components["schemas"]["ImageOutput"]; - sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"]; - tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"]; - sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"]; - img_hue_adjust: components["schemas"]["ImageOutput"]; - face_off: components["schemas"]["FaceOffOutput"]; - img_mul: components["schemas"]["ImageOutput"]; - rand_int: components["schemas"]["IntegerOutput"]; - image_mask_to_tensor: components["schemas"]["MaskOutput"]; - rand_float: components["schemas"]["FloatOutput"]; - img_lerp: components["schemas"]["ImageOutput"]; - i2l: components["schemas"]["LatentsOutput"]; - image_collection: components["schemas"]["ImageCollectionOutput"]; - round_float: components["schemas"]["FloatOutput"]; - leres_image_processor: components["schemas"]["ImageOutput"]; - lora_loader: components["schemas"]["LoRALoaderOutput"]; - infill_cv2: components["schemas"]["ImageOutput"]; - infill_lama: components["schemas"]["ImageOutput"]; - ideal_size: components["schemas"]["IdealSizeOutput"]; - sdxl_compel_prompt: components["schemas"]["ConditioningOutput"]; - midas_depth_image_processor: components["schemas"]["ImageOutput"]; - color_map_image_processor: components["schemas"]["ImageOutput"]; - img_channel_multiply: components["schemas"]["ImageOutput"]; - iterate: components["schemas"]["IterateInvocationOutput"]; - string_collection: components["schemas"]["StringCollectionOutput"]; - step_param_easing: components["schemas"]["FloatCollectionOutput"]; - main_model_loader: components["schemas"]["ModelLoaderOutput"]; range_of_size: components["schemas"]["IntegerCollectionOutput"]; + color_correct: components["schemas"]["ImageOutput"]; + image: components["schemas"]["ImageOutput"]; + latents_collection: components["schemas"]["LatentsCollectionOutput"]; + img_blur: components["schemas"]["ImageOutput"]; + lineart_anime_image_processor: components["schemas"]["ImageOutput"]; + sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"]; + boolean: components["schemas"]["BooleanOutput"]; + infill_cv2: components["schemas"]["ImageOutput"]; + i2l: components["schemas"]["LatentsOutput"]; + tile_image_processor: components["schemas"]["ImageOutput"]; + dw_openpose_image_processor: components["schemas"]["ImageOutput"]; + canvas_paste_back: components["schemas"]["ImageOutput"]; + heuristic_resize: components["schemas"]["ImageOutput"]; + mediapipe_face_processor: components["schemas"]["ImageOutput"]; + conditioning: components["schemas"]["ConditioningOutput"]; + mask_from_id: components["schemas"]["ImageOutput"]; + img_nsfw: components["schemas"]["ImageOutput"]; + conditioning_collection: components["schemas"]["ConditioningCollectionOutput"]; + invert_tensor_mask: components["schemas"]["MaskOutput"]; + sub: components["schemas"]["IntegerOutput"]; + infill_lama: components["schemas"]["ImageOutput"]; + calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"]; + leres_image_processor: components["schemas"]["ImageOutput"]; + img_scale: components["schemas"]["ImageOutput"]; + mask_edge: components["schemas"]["ImageOutput"]; + esrgan: components["schemas"]["ImageOutput"]; + sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"]; + pair_tile_image: components["schemas"]["PairTileImageOutput"]; + string: components["schemas"]["StringOutput"]; + calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"]; + t2i_adapter: components["schemas"]["T2IAdapterOutput"]; + img_paste: components["schemas"]["ImageOutput"]; + midas_depth_image_processor: components["schemas"]["ImageOutput"]; + pidi_image_processor: components["schemas"]["ImageOutput"]; + sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"]; + tile_to_properties: components["schemas"]["TileToPropertiesOutput"]; + clip_skip: components["schemas"]["CLIPSkipInvocationOutput"]; + blank_image: components["schemas"]["ImageOutput"]; + img_channel_multiply: components["schemas"]["ImageOutput"]; + canny_image_processor: components["schemas"]["ImageOutput"]; + l2i: components["schemas"]["ImageOutput"]; + img_mul: components["schemas"]["ImageOutput"]; + vae_loader: components["schemas"]["VAEOutput"]; + string_collection: components["schemas"]["StringCollectionOutput"]; + tomask: components["schemas"]["ImageOutput"]; + infill_patchmatch: components["schemas"]["ImageOutput"]; + compel: components["schemas"]["ConditioningOutput"]; + calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"]; + tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"]; + string_join_three: components["schemas"]["StringOutput"]; + rectangle_mask: components["schemas"]["MaskOutput"]; + crop_latents: components["schemas"]["LatentsOutput"]; + mul: components["schemas"]["IntegerOutput"]; + merge_tiles_to_image: components["schemas"]["ImageOutput"]; + integer_math: components["schemas"]["IntegerOutput"]; + iterate: components["schemas"]["IterateInvocationOutput"]; + range: components["schemas"]["IntegerCollectionOutput"]; + collect: components["schemas"]["CollectInvocationOutput"]; + img_ilerp: components["schemas"]["ImageOutput"]; + rand_float: components["schemas"]["FloatOutput"]; + latents: components["schemas"]["LatentsOutput"]; + face_identifier: components["schemas"]["ImageOutput"]; + depth_anything_image_processor: components["schemas"]["ImageOutput"]; + round_float: components["schemas"]["FloatOutput"]; + create_denoise_mask: components["schemas"]["DenoiseMaskOutput"]; + core_metadata: components["schemas"]["MetadataOutput"]; + float_range: components["schemas"]["FloatCollectionOutput"]; + face_mask_detection: components["schemas"]["FaceMaskOutput"]; + ip_adapter: components["schemas"]["IPAdapterOutput"]; + lscale: components["schemas"]["LatentsOutput"]; + lineart_image_processor: components["schemas"]["ImageOutput"]; + integer_collection: components["schemas"]["IntegerCollectionOutput"]; + cv_inpaint: components["schemas"]["ImageOutput"]; + mlsd_image_processor: components["schemas"]["ImageOutput"]; + ideal_size: components["schemas"]["IdealSizeOutput"]; + segment_anything_processor: components["schemas"]["ImageOutput"]; + img_watermark: components["schemas"]["ImageOutput"]; + hed_image_processor: components["schemas"]["ImageOutput"]; + normalbae_image_processor: components["schemas"]["ImageOutput"]; + infill_tile: components["schemas"]["ImageOutput"]; + sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"]; + denoise_latents: components["schemas"]["LatentsOutput"]; + unsharp_mask: components["schemas"]["ImageOutput"]; + float_collection: components["schemas"]["FloatCollectionOutput"]; + show_image: components["schemas"]["ImageOutput"]; + img_conv: components["schemas"]["ImageOutput"]; + model_identifier: components["schemas"]["ModelIdentifierOutput"]; + step_param_easing: components["schemas"]["FloatCollectionOutput"]; + float_math: components["schemas"]["FloatOutput"]; + color_map_image_processor: components["schemas"]["ImageOutput"]; + spandrel_image_to_image: components["schemas"]["ImageOutput"]; + img_crop: components["schemas"]["ImageOutput"]; + lblend: components["schemas"]["LatentsOutput"]; + random_range: components["schemas"]["IntegerCollectionOutput"]; + float: components["schemas"]["FloatOutput"]; + merge_metadata: components["schemas"]["MetadataOutput"]; + alpha_mask_to_tensor: components["schemas"]["MaskOutput"]; + image_collection: components["schemas"]["ImageCollectionOutput"]; + image_mask_to_tensor: components["schemas"]["MaskOutput"]; + color: components["schemas"]["ColorOutput"]; + img_hue_adjust: components["schemas"]["ImageOutput"]; + string_split: components["schemas"]["String2Output"]; + prompt_from_file: components["schemas"]["StringCollectionOutput"]; + metadata: components["schemas"]["MetadataOutput"]; + freeu: components["schemas"]["UNetOutput"]; + create_gradient_mask: components["schemas"]["GradientMaskOutput"]; + img_chan: components["schemas"]["ImageOutput"]; + div: components["schemas"]["IntegerOutput"]; + save_image: components["schemas"]["ImageOutput"]; + img_pad_crop: components["schemas"]["ImageOutput"]; + lora_collection_loader: components["schemas"]["LoRALoaderOutput"]; + scheduler: components["schemas"]["SchedulerOutput"]; + face_off: components["schemas"]["FaceOffOutput"]; + img_lerp: components["schemas"]["ImageOutput"]; + zoe_depth_image_processor: components["schemas"]["ImageOutput"]; + add: components["schemas"]["IntegerOutput"]; + string_split_neg: components["schemas"]["StringPosNegOutput"]; + img_channel_offset: components["schemas"]["ImageOutput"]; + main_model_loader: components["schemas"]["ModelLoaderOutput"]; + rand_int: components["schemas"]["IntegerOutput"]; + float_to_int: components["schemas"]["IntegerOutput"]; + controlnet: components["schemas"]["ControlOutput"]; + metadata_item: components["schemas"]["MetadataItemOutput"]; + integer: components["schemas"]["IntegerOutput"]; + dynamic_prompt: components["schemas"]["StringCollectionOutput"]; + sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"]; + lora_selector: components["schemas"]["LoRASelectorOutput"]; + lresize: components["schemas"]["LatentsOutput"]; + noise: components["schemas"]["NoiseOutput"]; + lora_loader: components["schemas"]["LoRALoaderOutput"]; + seamless: components["schemas"]["SeamlessModeOutput"]; + mask_combine: components["schemas"]["ImageOutput"]; + string_join: components["schemas"]["StringOutput"]; + string_replace: components["schemas"]["StringOutput"]; + sdxl_compel_prompt: components["schemas"]["ConditioningOutput"]; + img_resize: components["schemas"]["ImageOutput"]; + boolean_collection: components["schemas"]["BooleanCollectionOutput"]; + infill_rgba: components["schemas"]["ImageOutput"]; + content_shuffle_image_processor: components["schemas"]["ImageOutput"]; }; /** * InvocationStartedEvent @@ -7474,7 +7474,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["UpscaleSpandrelInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | 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"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | 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"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringCollectionInvocation"] | 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"]["TileResamplerProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -11934,6 +11934,57 @@ export type components = { */ format: "checkpoint"; }; + /** + * Image-to-Image + * @description Run any spandrel image-to-image model (https://github.com/chaiNNer-org/spandrel). + */ + SpandrelImageToImageInvocation: { + /** + * @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 The input image + * @default null + */ + image?: components["schemas"]["ImageField"]; + /** + * Image-to-Image Model + * @description Image-to-Image model + * @default null + */ + image_to_image_model?: components["schemas"]["ModelIdentifierField"]; + /** + * type + * @default spandrel_image_to_image + * @constant + * @enum {string} + */ + type: "spandrel_image_to_image"; + }; /** StarterModel */ StarterModel: { /** Description */ @@ -13323,56 +13374,6 @@ export type components = { */ type: "unsharp_mask"; }; - /** - * Upscale (spandrel) - * @description Upscales an image using any upscaler supported by spandrel (https://github.com/chaiNNer-org/spandrel). - */ - UpscaleSpandrelInvocation: { - /** - * @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 The input image - * @default null - */ - image?: components["schemas"]["ImageField"]; - /** - * @description Spandrel Image-to-Image model - * @default null - */ - spandrel_image_to_image_model?: components["schemas"]["ModelIdentifierField"]; - /** - * type - * @default upscale_spandrel - * @constant - * @enum {string} - */ - type: "upscale_spandrel"; - }; /** Upscaler */ Upscaler: { /** From 0ce6ec634d26a63e0df022391616e61c53a55d03 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 5 Jul 2024 14:05:12 -0400 Subject: [PATCH 19/21] Do not assign the result of SpandrelImageToImageModel.load_from_file(...) during probe to ensure that the model is immediately gc'd. --- invokeai/backend/model_manager/probe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index c7267e9f1e..3b36e2f5af 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -253,7 +253,7 @@ class ModelProbe(object): # 2. Spandrel has internal logic to determine a model's type from its state_dict before loading the model. # This logic is not exposed in spandrel's public API. We could copy the logic here, but then we have to # maintain it, and the risk of false positive detections is higher. - _ = SpandrelImageToImageModel.load_from_file(model_path) + SpandrelImageToImageModel.load_from_file(model_path) return ModelType.SpandrelImageToImage except spandrel.UnsupportedModelError: pass From ecbff2aa44e346bc70baef7c1dab9431c4185130 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 5 Jul 2024 14:57:05 -0400 Subject: [PATCH 20/21] Whoops... forgot to commit this file. --- .../invocations/spandrel_image_to_image.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 invokeai/app/invocations/spandrel_image_to_image.py diff --git a/invokeai/app/invocations/spandrel_image_to_image.py b/invokeai/app/invocations/spandrel_image_to_image.py new file mode 100644 index 0000000000..76cf31480c --- /dev/null +++ b/invokeai/app/invocations/spandrel_image_to_image.py @@ -0,0 +1,49 @@ +import torch + +from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation +from invokeai.app.invocations.fields import ( + FieldDescriptions, + ImageField, + InputField, + UIType, + WithBoard, + WithMetadata, +) +from invokeai.app.invocations.model import ModelIdentifierField +from invokeai.app.invocations.primitives import ImageOutput +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.spandrel_image_to_image_model import SpandrelImageToImageModel + + +@invocation("spandrel_image_to_image", title="Image-to-Image", tags=["upscale"], category="upscale", version="1.0.0") +class SpandrelImageToImageInvocation(BaseInvocation, WithMetadata, WithBoard): + """Run any spandrel image-to-image model (https://github.com/chaiNNer-org/spandrel).""" + + image: ImageField = InputField(description="The input image") + image_to_image_model: ModelIdentifierField = InputField( + title="Image-to-Image Model", + description=FieldDescriptions.spandrel_image_to_image_model, + ui_type=UIType.SpandrelImageToImageModel, + ) + + @torch.inference_mode() + def invoke(self, context: InvocationContext) -> ImageOutput: + image = context.images.get_pil(self.image.image_name) + + # Load the model. + spandrel_model_info = context.models.load(self.image_to_image_model) + + with spandrel_model_info as spandrel_model: + assert isinstance(spandrel_model, SpandrelImageToImageModel) + + # Prepare input image for inference. + image_tensor = SpandrelImageToImageModel.pil_to_tensor(image) + image_tensor = image_tensor.to(device=spandrel_model.device, dtype=spandrel_model.dtype) + + # Run inference. + image_tensor = spandrel_model.run(image_tensor) + + # Convert the output tensor to a PIL image. + pil_image = SpandrelImageToImageModel.tensor_to_pil(image_tensor) + image_dto = context.images.save(image=pil_image) + return ImageOutput.build(image_dto) From 650902dc2924f7aced87fb74906e8a444b5ae3c1 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 10 Jul 2024 13:59:17 -0400 Subject: [PATCH 21/21] Fix broken unit test caused by non-existent model path. --- invokeai/backend/model_manager/probe.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 42727a31d7..1929b3f4fd 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -256,6 +256,12 @@ class ModelProbe(object): return ModelType.SpandrelImageToImage except spandrel.UnsupportedModelError: pass + except RuntimeError as e: + if "No such file or directory" in str(e): + # This error is expected if the model_path does not exist (which is the case in some unit tests). + pass + else: + raise e raise InvalidModelConfigException(f"Unable to determine model type for {model_path}")