From 08fee6a4db220e8279ec8e042639470ee1b667e4 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:32:02 +1100 Subject: [PATCH 01/16] tidy(mm): only main models get the main default settings --- invokeai/app/services/model_records/model_records_base.py | 4 ++-- invokeai/backend/model_manager/config.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py index 0b56b7f6c0..1df64709b9 100644 --- a/invokeai/app/services/model_records/model_records_base.py +++ b/invokeai/app/services/model_records/model_records_base.py @@ -18,7 +18,7 @@ ModelFormat, ModelType, ) -from invokeai.backend.model_manager.config import ModelDefaultSettings, ModelVariantType, SchedulerPredictionType +from invokeai.backend.model_manager.config import MainModelDefaultSettings, ModelVariantType, SchedulerPredictionType class DuplicateModelException(Exception): @@ -68,7 +68,7 @@ class ModelRecordChanges(BaseModelExcludeNull): description: Optional[str] = Field(description="Model description", default=None) base: Optional[BaseModelType] = Field(description="The base model.", default=None) trigger_phrases: Optional[set[str]] = Field(description="Set of trigger phrases for this model", default=None) - default_settings: Optional[ModelDefaultSettings] = Field( + default_settings: Optional[MainModelDefaultSettings] = Field( description="Default settings for this model", default=None ) diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index de86b20fb2..78cf5ca19c 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -131,7 +131,7 @@ class ModelSourceType(str, Enum): HFRepoID = "hf_repo_id" -class ModelDefaultSettings(BaseModel): +class MainModelDefaultSettings(BaseModel): vae: str | None vae_precision: str | None scheduler: SCHEDULER_NAME_VALUES | None @@ -156,9 +156,6 @@ class ModelConfigBase(BaseModel): source_api_response: Optional[str] = Field( description="The original API response from the source, as stringified JSON.", default=None ) - default_settings: Optional[ModelDefaultSettings] = Field( - description="Default settings for this model", default=None - ) cover_image: Optional[str] = Field(description="Url for image to preview model", default=None) @staticmethod @@ -279,6 +276,9 @@ def get_tag() -> Tag: class MainConfigBase(ModelConfigBase): type: Literal[ModelType.Main] = ModelType.Main trigger_phrases: Optional[set[str]] = Field(description="Set of trigger phrases for this model", default=None) + default_settings: Optional[MainModelDefaultSettings] = Field( + description="Default settings for this model", default=None + ) class MainCheckpointConfig(CheckpointConfigBase, MainConfigBase): From 0a24a343190c2a8e3d9ccc2a6cf25aa2fd769831 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:33:23 +1100 Subject: [PATCH 02/16] feat(mm): add default settings for control adapters Only includes `preprocessor` at this time. --- invokeai/backend/model_manager/config.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index 78cf5ca19c..466327fae0 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -140,6 +140,11 @@ class MainModelDefaultSettings(BaseModel): cfg_rescale_multiplier: float | None +class ControlAdapterDefaultSettings(BaseModel): + # This could be narrowed to controlnet processor nodes, but they change. Leaving this a string is safer. + preprocessor: str | None + + class ModelConfigBase(BaseModel): """Base class for model configuration information.""" @@ -229,7 +234,13 @@ def get_tag() -> Tag: return Tag(f"{ModelType.VAE.value}.{ModelFormat.Diffusers.value}") -class ControlNetDiffusersConfig(DiffusersConfigBase): +class ControlAdapterConfigBase(BaseModel): + default_settings: Optional[ControlAdapterDefaultSettings] = Field( + description="Default settings for this model", default=None + ) + + +class ControlNetDiffusersConfig(DiffusersConfigBase, ControlAdapterConfigBase): """Model config for ControlNet models (diffusers version).""" type: Literal[ModelType.ControlNet] = ModelType.ControlNet @@ -240,7 +251,7 @@ def get_tag() -> Tag: return Tag(f"{ModelType.ControlNet.value}.{ModelFormat.Diffusers.value}") -class ControlNetCheckpointConfig(CheckpointConfigBase): +class ControlNetCheckpointConfig(CheckpointConfigBase, ControlAdapterConfigBase): """Model config for ControlNet models (diffusers version).""" type: Literal[ModelType.ControlNet] = ModelType.ControlNet @@ -301,7 +312,7 @@ def get_tag() -> Tag: return Tag(f"{ModelType.Main.value}.{ModelFormat.Diffusers.value}") -class IPAdapterConfig(ModelConfigBase): +class IPAdapterConfig(ModelConfigBase, ControlAdapterConfigBase): """Model config for IP Adaptor format models.""" type: Literal[ModelType.IPAdapter] = ModelType.IPAdapter @@ -324,7 +335,7 @@ def get_tag() -> Tag: return Tag(f"{ModelType.CLIPVision.value}.{ModelFormat.Diffusers.value}") -class T2IAdapterConfig(ModelConfigBase): +class T2IAdapterConfig(ModelConfigBase, ControlAdapterConfigBase): """Model config for T2I.""" type: Literal[ModelType.T2IAdapter] = ModelType.T2IAdapter From a9437382000624266a1ab4324f79a32acb2d0672 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:37:31 +1100 Subject: [PATCH 03/16] feat(mm): add AnyDefaultSettings union --- invokeai/backend/model_manager/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index 466327fae0..3e63ad7ac8 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -22,7 +22,7 @@ import time from enum import Enum -from typing import Literal, Optional, Type, Union +from typing import Literal, Optional, Type, TypeAlias, Union import torch from diffusers.models.modeling_utils import ModelMixin @@ -387,6 +387,7 @@ def get_model_discriminator_value(v: Any) -> str: ] AnyModelConfigValidator = TypeAdapter(AnyModelConfig) +AnyDefaultSettings: TypeAlias = Union[MainModelDefaultSettings, ControlAdapterDefaultSettings] class ModelConfigFactory(object): From ba0839d16edc72a862187f354ee5ecabe14057d2 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:01:43 +1100 Subject: [PATCH 04/16] feat(mm): add control adapter default settings while probing --- invokeai/backend/model_manager/probe.py | 45 ++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 75925dcf0b..49c25fa843 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -14,6 +14,7 @@ from .config import ( AnyModelConfig, BaseModelType, + ControlAdapterDefaultSettings, InvalidModelConfigException, ModelConfigFactory, ModelFormat, @@ -159,6 +160,12 @@ def probe( fields["format"] = fields.get("format") or probe.get_format() fields["hash"] = fields.get("hash") or ModelHash().hash(model_path) + fields["default_settings"] = ( + fields.get("default_settings") or probe.get_default_settings(fields["name"]) + if isinstance(probe, ControlAdapterProbe) + else None + ) + if format_type == ModelFormat.Diffusers and isinstance(probe, FolderProbeBase): fields["repo_variant"] = fields.get("repo_variant") or probe.get_repo_variant() @@ -329,6 +336,36 @@ def _scan_model(cls, model_name: str, checkpoint: Path) -> None: raise Exception("The model {model_name} is potentially infected by malware. Aborting import.") +class ControlAdapterProbe(ProbeBase): + """Adds `get_default_settings` for ControlNet and T2IAdapter probes""" + + # TODO(psyche): It would be nice to get these from the invocations, but that creates circular dependencies. + # "canny": CannyImageProcessorInvocation.get_type() + MODEL_NAME_TO_PREPROCESSOR = { + "canny": "canny_image_processor", + "mlsd": "mlsd_image_processor", + "depth": "depth_anything_image_processor", + "bae": "normalbae_image_processor", + "normal_bae": "normalbae_image_processor", + "sketch": "pidi_image_processor", + "scribble": "lineart_image_processor", + "lineart": "lineart_image_processor", + "lineart_anime": "lineart_anime_image_processor", + "softedge": "hed_image_processor", + "shuffle": "content_shuffle_image_processor", + "openpose": "dw_openpose_image_processor", + "mediapipe": "mediapipe_face_processor", + "pidi": "pidi_image_processor", + "zoe": "zoe_depth_image_processor", + "color": "color_map_image_processor", + } + + def get_default_settings(self, model_name: str) -> Optional[ControlAdapterDefaultSettings]: + if model_name in self.MODEL_NAME_TO_PREPROCESSOR: + return ControlAdapterDefaultSettings(preprocessor=self.MODEL_NAME_TO_PREPROCESSOR[model_name]) + return None + + # ##################################################3 # Checkpoint probing # ##################################################3 @@ -452,7 +489,7 @@ def get_base_type(self) -> BaseModelType: raise InvalidModelConfigException(f"{self.model_path}: Could not determine base type") -class ControlNetCheckpointProbe(CheckpointProbeBase): +class ControlNetCheckpointProbe(CheckpointProbeBase, ControlAdapterProbe): """Class for probing controlnets.""" def get_base_type(self) -> BaseModelType: @@ -480,7 +517,7 @@ def get_base_type(self) -> BaseModelType: raise NotImplementedError() -class T2IAdapterCheckpointProbe(CheckpointProbeBase): +class T2IAdapterCheckpointProbe(CheckpointProbeBase, ControlAdapterProbe): def get_base_type(self) -> BaseModelType: raise NotImplementedError() @@ -618,7 +655,7 @@ def get_variant_type(self) -> ModelVariantType: return ModelVariantType.Normal -class ControlNetFolderProbe(FolderProbeBase): +class ControlNetFolderProbe(FolderProbeBase, ControlAdapterProbe): def get_base_type(self) -> BaseModelType: config_file = self.model_path / "config.json" if not config_file.exists(): @@ -692,7 +729,7 @@ def get_base_type(self) -> BaseModelType: return BaseModelType.Any -class T2IAdapterFolderProbe(FolderProbeBase): +class T2IAdapterFolderProbe(FolderProbeBase, ControlAdapterProbe): def get_base_type(self) -> BaseModelType: config_file = self.model_path / "config.json" if not config_file.exists(): From e52ae0a6521047adc42fb1d082dbf94051c958a8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:13:27 +1100 Subject: [PATCH 05/16] fix(mm): remove default settings from IP adapter config --- invokeai/backend/model_manager/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py index 3e63ad7ac8..9261f0e50f 100644 --- a/invokeai/backend/model_manager/config.py +++ b/invokeai/backend/model_manager/config.py @@ -312,7 +312,7 @@ def get_tag() -> Tag: return Tag(f"{ModelType.Main.value}.{ModelFormat.Diffusers.value}") -class IPAdapterConfig(ModelConfigBase, ControlAdapterConfigBase): +class IPAdapterConfig(ModelConfigBase): """Model config for IP Adaptor format models.""" type: Literal[ModelType.IPAdapter] = ModelType.IPAdapter From f945255fde8d19ec3c98222ee0364c0b4dd61ddc Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:36:39 +1100 Subject: [PATCH 06/16] chore(ui): typegen --- .../frontend/web/src/services/api/schema.ts | 77 ++++++++----------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 12f7a88ba1..94b62269f2 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -1376,8 +1376,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -2240,6 +2238,11 @@ export type components = { */ type: "content_shuffle_image_processor"; }; + /** ControlAdapterDefaultSettings */ + ControlAdapterDefaultSettings: { + /** Preprocessor */ + preprocessor: string | null; + }; /** ControlField */ ControlField: { /** @description The control image */ @@ -2284,6 +2287,8 @@ export type components = { * @description Model config for ControlNet models (diffusers version). */ ControlNetCheckpointConfig: { + /** @description Default settings for this model */ + default_settings?: components["schemas"]["ControlAdapterDefaultSettings"] | null; /** * Key * @description A unique key for this model. @@ -2323,8 +2328,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -2358,6 +2361,8 @@ export type components = { * @description Model config for ControlNet models (diffusers version). */ ControlNetDiffusersConfig: { + /** @description Default settings for this model */ + default_settings?: components["schemas"]["ControlAdapterDefaultSettings"] | null; /** * Key * @description A unique key for this model. @@ -2397,8 +2402,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -4100,7 +4103,7 @@ export type components = { * @description The nodes in this graph */ nodes: { - [key: string]: components["schemas"]["FaceOffInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["InfillColorInvocation"]; + [key: string]: components["schemas"]["ImageBlurInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["IntegerInvocation"]; }; /** * Edges @@ -4137,7 +4140,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["T2IAdapterOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["String2Output"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["CalculateImageTilesOutput"]; + [key: string]: components["schemas"]["T2IAdapterOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["SDXLModelLoaderOutput"]; }; /** * Errors @@ -4317,8 +4320,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -6370,8 +6371,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -6523,8 +6522,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -6629,8 +6626,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -6647,6 +6642,8 @@ export type components = { * @description Set of trigger phrases for this model */ trigger_phrases?: string[] | null; + /** @description Default settings for this model */ + default_settings?: components["schemas"]["MainModelDefaultSettings"] | null; /** * Format * @default checkpoint @@ -6717,8 +6714,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -6735,6 +6730,8 @@ export type components = { * @description Set of trigger phrases for this model */ trigger_phrases?: string[] | null; + /** @description Default settings for this model */ + default_settings?: components["schemas"]["MainModelDefaultSettings"] | null; /** * Format * @default diffusers @@ -6744,6 +6741,21 @@ export type components = { /** @default */ repo_variant?: components["schemas"]["ModelRepoVariant"] | null; }; + /** MainModelDefaultSettings */ + MainModelDefaultSettings: { + /** Vae */ + vae: string | null; + /** Vae Precision */ + vae_precision: string | null; + /** Scheduler */ + scheduler: ("ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc" | "lcm") | null; + /** Steps */ + steps: number | null; + /** Cfg Scale */ + cfg_scale: number | null; + /** Cfg Rescale Multiplier */ + cfg_rescale_multiplier: number | null; + }; /** * Main Model * @description Loads a main model, outputting its submodels. @@ -7263,21 +7275,6 @@ export type components = { */ type: "mlsd_image_processor"; }; - /** ModelDefaultSettings */ - ModelDefaultSettings: { - /** Vae */ - vae: string | null; - /** Vae Precision */ - vae_precision: string | null; - /** Scheduler */ - scheduler: ("ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc" | "lcm") | null; - /** Steps */ - steps: number | null; - /** Cfg Scale */ - cfg_scale: number | null; - /** Cfg Rescale Multiplier */ - cfg_rescale_multiplier: number | null; - }; /** ModelField */ ModelField: { /** @@ -7446,7 +7443,7 @@ export type components = { */ trigger_phrases?: string[] | null; /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; + default_settings?: components["schemas"]["MainModelDefaultSettings"] | null; /** @description The variant of the model. */ variant?: components["schemas"]["ModelVariantType"] | null; /** @description The prediction type of the model. */ @@ -9649,6 +9646,8 @@ export type components = { * @description Model config for T2I. */ T2IAdapterConfig: { + /** @description Default settings for this model */ + default_settings?: components["schemas"]["ControlAdapterDefaultSettings"] | null; /** * Key * @description A unique key for this model. @@ -9688,8 +9687,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -9901,8 +9898,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -9965,8 +9960,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -10290,8 +10283,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model @@ -10364,8 +10355,6 @@ export type components = { * @description The original API response from the source, as stringified JSON. */ source_api_response?: string | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["ModelDefaultSettings"] | null; /** * Cover Image * @description Url for image to preview model From 3e5556a41d00c6e4218847d2eaa88240f7d4dc07 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:45:46 +1100 Subject: [PATCH 07/16] feat(ui): use default settings for control adapters for processor --- .../ControlAdapterShouldAutoConfig.tsx | 6 +- .../parameters/ParamControlAdapterModel.tsx | 13 ++-- .../hooks/useAddControlAdapter.ts | 26 ++++++- .../hooks/useControlAdapterModel.ts | 11 ++- .../store/controlAdaptersSlice.ts | 70 ++++++------------- .../controlAdapters/store/types.test.ts | 13 ++++ .../features/controlAdapters/store/types.ts | 19 +++++ .../util/buildControlAdapterProcessor.ts | 11 +++ .../web/src/features/metadata/util/parsers.ts | 11 +-- .../hooks/useGetModelConfigWithTypeGuard.ts | 20 ++++++ .../frontend/web/src/services/api/types.ts | 6 ++ 11 files changed, 138 insertions(+), 68 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts create mode 100644 invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapterProcessor.ts create mode 100644 invokeai/frontend/web/src/services/api/hooks/useGetModelConfigWithTypeGuard.ts diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx index 7399febb2d..cb3d36c58d 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx @@ -1,6 +1,7 @@ import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled'; +import { useControlAdapterModel } from 'features/controlAdapters/hooks/useControlAdapterModel'; import { useControlAdapterShouldAutoConfig } from 'features/controlAdapters/hooks/useControlAdapterShouldAutoConfig'; import { controlAdapterAutoConfigToggled } from 'features/controlAdapters/store/controlAdaptersSlice'; import { isNil } from 'lodash-es'; @@ -14,12 +15,13 @@ type Props = { const ControlAdapterShouldAutoConfig = ({ id }: Props) => { const isEnabled = useControlAdapterIsEnabled(id); const shouldAutoConfig = useControlAdapterShouldAutoConfig(id); + const { modelConfig } = useControlAdapterModel(id); const dispatch = useAppDispatch(); const { t } = useTranslation(); const handleShouldAutoConfigChanged = useCallback(() => { - dispatch(controlAdapterAutoConfigToggled({ id })); - }, [id, dispatch]); + dispatch(controlAdapterAutoConfigToggled({ id, modelConfig })); + }, [id, dispatch, modelConfig]); if (isNil(shouldAutoConfig)) { return null; diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx index d7cf2e8452..8bd80a8d2e 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx @@ -6,7 +6,6 @@ import { useControlAdapterModel } from 'features/controlAdapters/hooks/useContro import { useControlAdapterModelQuery } from 'features/controlAdapters/hooks/useControlAdapterModelQuery'; import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType'; import { controlAdapterModelChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; -import { getModelKeyAndBase } from 'features/metadata/util/modelFetchingHelpers'; import { memo, useCallback, useMemo } from 'react'; import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types'; @@ -17,21 +16,21 @@ type ParamControlAdapterModelProps = { const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => { const isEnabled = useControlAdapterIsEnabled(id); const controlAdapterType = useControlAdapterType(id); - const model = useControlAdapterModel(id); + const { modelConfig } = useControlAdapterModel(id); const dispatch = useAppDispatch(); const currentBaseModel = useAppSelector((s) => s.generation.model?.base); const { data, isLoading } = useControlAdapterModelQuery(controlAdapterType); const _onChange = useCallback( - (model: ControlNetModelConfig | IPAdapterModelConfig | T2IAdapterModelConfig | null) => { - if (!model) { + (modelConfig: ControlNetModelConfig | IPAdapterModelConfig | T2IAdapterModelConfig | null) => { + if (!modelConfig) { return; } dispatch( controlAdapterModelChanged({ id, - model: getModelKeyAndBase(model), + modelConfig, }) ); }, @@ -39,8 +38,8 @@ const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => { ); const selectedModel = useMemo( - () => (model && controlAdapterType ? { ...model, model_type: controlAdapterType } : null), - [controlAdapterType, model] + () => (modelConfig && controlAdapterType ? { ...modelConfig, model_type: controlAdapterType } : null), + [controlAdapterType, modelConfig] ); const { items, selectedItem, onChange, placeholder } = useModelCustomSelect({ diff --git a/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts b/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts index 7fd1088767..82d6e8c5d6 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts @@ -1,7 +1,9 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice'; -import type { ControlAdapterType } from 'features/controlAdapters/store/types'; +import { type ControlAdapterType, isControlAdapterProcessorType } from 'features/controlAdapters/store/types'; import { useCallback, useMemo } from 'react'; +import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types'; import { useControlAdapterModels } from './useControlAdapterModels'; @@ -11,7 +13,7 @@ export const useAddControlAdapter = (type: ControlAdapterType) => { const models = useControlAdapterModels(type); - const firstModel = useMemo(() => { + const firstModel: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig | undefined = useMemo(() => { // prefer to use a model that matches the base model const firstCompatibleModel = models.filter((m) => (baseModel ? m.base === baseModel : true))[0]; @@ -28,6 +30,26 @@ export const useAddControlAdapter = (type: ControlAdapterType) => { if (isDisabled) { return; } + + if ( + (type === 'controlnet' || type === 't2i_adapter') && + (firstModel?.type === 'controlnet' || firstModel?.type === 't2i_adapter') + ) { + const defaultPreprocessor = firstModel.default_settings?.preprocessor; + const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; + const processorNode = CONTROLNET_PROCESSORS[processorType].default; + dispatch( + controlAdapterAdded({ + type, + overrides: { + model: firstModel, + processorType, + processorNode, + }, + }) + ); + return; + } dispatch( controlAdapterAdded({ type, diff --git a/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModel.ts b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModel.ts index 1416c8c9f1..4de2aeac7f 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModel.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModel.ts @@ -1,3 +1,4 @@ +import { skipToken } from '@reduxjs/toolkit/query'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppSelector } from 'app/store/storeHooks'; import { @@ -5,18 +6,22 @@ import { selectControlAdaptersSlice, } from 'features/controlAdapters/store/controlAdaptersSlice'; import { useMemo } from 'react'; +import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard'; +import { isControlAdapterModelConfig } from 'services/api/types'; export const useControlAdapterModel = (id: string) => { const selector = useMemo( () => createMemoizedSelector( selectControlAdaptersSlice, - (controlAdapters) => selectControlAdapterById(controlAdapters, id)?.model + (controlAdapters) => selectControlAdapterById(controlAdapters, id)?.model?.key ), [id] ); - const model = useAppSelector(selector); + const key = useAppSelector(selector); - return model; + const result = useGetModelConfigWithTypeGuard(key ?? skipToken, isControlAdapterModelConfig); + + return result; }; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts index a20e287011..ee36d10e28 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts @@ -3,20 +3,14 @@ import { createEntityAdapter, createSlice, isAnyOf } from '@reduxjs/toolkit'; import { getSelectorsOptions } from 'app/store/createMemoizedSelector'; import type { PersistConfig, RootState } from 'app/store/store'; import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter'; -import type { - ParameterControlNetModel, - ParameterIPAdapterModel, - ParameterT2IAdapterModel, -} from 'features/parameters/types/parameterSchemas'; +import { buildControlAdapterProcessor } from 'features/controlAdapters/util/buildControlAdapterProcessor'; import { cloneDeep, merge, uniq } from 'lodash-es'; +import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types'; import { socketInvocationError } from 'services/events/actions'; import { v4 as uuidv4 } from 'uuid'; import { controlAdapterImageProcessed } from './actions'; -import { - CONTROLNET_MODEL_DEFAULT_PROCESSORS as CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS, - CONTROLNET_PROCESSORS, -} from './constants'; +import { CONTROLNET_PROCESSORS } from './constants'; import type { ControlAdapterConfig, ControlAdapterProcessorType, @@ -194,15 +188,17 @@ export const controlAdaptersSlice = createSlice({ state, action: PayloadAction<{ id: string; - model: ParameterControlNetModel | ParameterT2IAdapterModel | ParameterIPAdapterModel; + modelConfig: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig; }> ) => { - const { id, model } = action.payload; + const { id, modelConfig } = action.payload; const cn = selectControlAdapterById(state, id); if (!cn) { return; } + const model = { key: modelConfig.key, base: modelConfig.base }; + if (!isControlNetOrT2IAdapter(cn)) { caAdapter.updateOne(state, { id, changes: { model } }); return; @@ -215,24 +211,14 @@ export const controlAdaptersSlice = createSlice({ update.changes.processedControlImage = null; - let processorType: ControlAdapterProcessorType | undefined = undefined; - - for (const modelSubstring in CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS) { - // TODO(MM2): matching modelSubstring to the model key is no longer a valid way to figure out the default processorType - if (model.key.includes(modelSubstring)) { - processorType = CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS[modelSubstring]; - break; - } + if (modelConfig.type === 'ip_adapter') { + // should never happen... + return; } - if (processorType) { - update.changes.processorType = processorType; - update.changes.processorNode = CONTROLNET_PROCESSORS[processorType] - .default as RequiredControlAdapterProcessorNode; - } else { - update.changes.processorType = 'none'; - update.changes.processorNode = CONTROLNET_PROCESSORS.none.default as RequiredControlAdapterProcessorNode; - } + const processor = buildControlAdapterProcessor(modelConfig); + update.changes.processorType = processor.processorType; + update.changes.processorNode = processor.processorNode; caAdapter.updateOne(state, update); }, @@ -324,39 +310,23 @@ export const controlAdaptersSlice = createSlice({ state, action: PayloadAction<{ id: string; + modelConfig?: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig; }> ) => { - const { id } = action.payload; + const { id, modelConfig } = action.payload; const cn = selectControlAdapterById(state, id); - if (!cn || !isControlNetOrT2IAdapter(cn)) { + if (!cn || !isControlNetOrT2IAdapter(cn) || modelConfig?.type === 'ip_adapter') { return; } - const update: Update = { id, changes: { shouldAutoConfig: !cn.shouldAutoConfig }, }; - if (update.changes.shouldAutoConfig) { - // manage the processor for the user - let processorType: ControlAdapterProcessorType | undefined = undefined; - - for (const modelSubstring in CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS) { - // TODO(MM2): matching modelSubstring to the model key is no longer a valid way to figure out the default processorType - if (cn.model?.key.includes(modelSubstring)) { - processorType = CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS[modelSubstring]; - break; - } - } - - if (processorType) { - update.changes.processorType = processorType; - update.changes.processorNode = CONTROLNET_PROCESSORS[processorType] - .default as RequiredControlAdapterProcessorNode; - } else { - update.changes.processorType = 'none'; - update.changes.processorNode = CONTROLNET_PROCESSORS.none.default as RequiredControlAdapterProcessorNode; - } + if (update.changes.shouldAutoConfig && modelConfig) { + const processor = buildControlAdapterProcessor(modelConfig); + update.changes.processorType = processor.processorType; + update.changes.processorNode = processor.processorNode; } caAdapter.updateOne(state, update); diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts new file mode 100644 index 0000000000..143f5ff3d4 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts @@ -0,0 +1,13 @@ +import type { + ControlAdapterProcessorType, + zControlAdapterProcessorType, +} from 'features/controlAdapters/store/types'; +import type { Equals } from 'tsafe'; +import { assert } from 'tsafe'; +import { describe, test } from 'vitest'; +import type { z } from 'zod'; + +describe('Control Adapter Types', () => { + test('ControlAdapterProcessorType', () => + assert>>()); +}); diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts index 3665355ecf..28e375fe49 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts @@ -47,6 +47,25 @@ export type ControlAdapterProcessorNode = * Any ControlNet processor type */ export type ControlAdapterProcessorType = NonNullable; +export const zControlAdapterProcessorType = z.enum([ + 'canny_image_processor', + 'color_map_image_processor', + 'content_shuffle_image_processor', + 'depth_anything_image_processor', + 'hed_image_processor', + 'lineart_anime_image_processor', + 'lineart_image_processor', + 'mediapipe_face_processor', + 'midas_depth_image_processor', + 'mlsd_image_processor', + 'normalbae_image_processor', + 'dw_openpose_image_processor', + 'pidi_image_processor', + 'zoe_depth_image_processor', + 'none', +]); +export const isControlAdapterProcessorType = (v: unknown): v is ControlAdapterProcessorType => + zControlAdapterProcessorType.safeParse(v).success; /** * The Canny processor node, with parameters flagged as required diff --git a/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapterProcessor.ts b/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapterProcessor.ts new file mode 100644 index 0000000000..911bacc787 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapterProcessor.ts @@ -0,0 +1,11 @@ +import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; +import { isControlAdapterProcessorType } from 'features/controlAdapters/store/types'; +import type { ControlNetModelConfig, T2IAdapterModelConfig } from 'services/api/types'; + +export const buildControlAdapterProcessor = (modelConfig: ControlNetModelConfig | T2IAdapterModelConfig) => { + const defaultPreprocessor = modelConfig.default_settings?.preprocessor; + const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; + const processorNode = CONTROLNET_PROCESSORS[processorType].default; + + return { processorType, processorNode }; +}; diff --git a/invokeai/frontend/web/src/features/metadata/util/parsers.ts b/invokeai/frontend/web/src/features/metadata/util/parsers.ts index 30ec37991c..9cb2841ae4 100644 --- a/invokeai/frontend/web/src/features/metadata/util/parsers.ts +++ b/invokeai/frontend/web/src/features/metadata/util/parsers.ts @@ -1,4 +1,5 @@ import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; +import { isControlAdapterProcessorType } from 'features/controlAdapters/store/types'; import { initialControlNet, initialIPAdapter, @@ -253,8 +254,9 @@ const parseControlNet: MetadataParseFunc = async (meta .catch(null) .parse(getProperty(metadataItem, 'resize_mode')); - const processorType = 'none'; - const processorNode = CONTROLNET_PROCESSORS.none.default; + const defaultPreprocessor = controlNetModel.default_settings?.preprocessor; + const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; + const processorNode = CONTROLNET_PROCESSORS[processorType].default; const controlNet: ControlNetConfigMetadata = { type: 'controlnet', @@ -305,8 +307,9 @@ const parseT2IAdapter: MetadataParseFunc = async (meta .catch(null) .parse(getProperty(metadataItem, 'resize_mode')); - const processorType = 'none'; - const processorNode = CONTROLNET_PROCESSORS.none.default; + const defaultPreprocessor = t2iAdapterModel.default_settings?.preprocessor; + const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; + const processorNode = CONTROLNET_PROCESSORS[processorType].default; const t2iAdapter: T2IAdapterConfigMetadata = { type: 't2i_adapter', diff --git a/invokeai/frontend/web/src/services/api/hooks/useGetModelConfigWithTypeGuard.ts b/invokeai/frontend/web/src/services/api/hooks/useGetModelConfigWithTypeGuard.ts new file mode 100644 index 0000000000..6de2941403 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/hooks/useGetModelConfigWithTypeGuard.ts @@ -0,0 +1,20 @@ +import { skipToken } from '@reduxjs/toolkit/query'; +import { useGetModelConfigQuery } from 'services/api/endpoints/models'; +import type { AnyModelConfig } from 'services/api/types'; + +export const useGetModelConfigWithTypeGuard = ( + key: string | typeof skipToken, + typeGuard: (config: AnyModelConfig) => config is T +) => { + const result = useGetModelConfigQuery(key ?? skipToken, { + selectFromResult: (result) => { + const modelConfig = result.data; + return { + ...result, + modelConfig: modelConfig && typeGuard(modelConfig) ? modelConfig : undefined, + }; + }, + }); + + return result; +}; diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 7a870a321f..46faa35d8e 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -83,6 +83,12 @@ export const isT2IAdapterModelConfig = (config: AnyModelConfig): config is T2IAd return config.type === 't2i_adapter'; }; +export const isControlAdapterModelConfig = ( + config: AnyModelConfig +): config is ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig => { + return isControlNetModelConfig(config) || isT2IAdapterModelConfig(config) || isIPAdapterModelConfig(config); +}; + export const isNonRefinerMainModelConfig = (config: AnyModelConfig): config is MainModelConfig => { return config.type === 'main' && config.base !== 'sdxl-refiner'; }; From c90bedbfae2c73b39e75204bb81942f9917f1227 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:50:00 +1100 Subject: [PATCH 08/16] feat(ui): update default settings for main models Needed some massaging now that only main models get main model default settings. --- .../hooks/useMainModelDefaultSettings.ts | 65 ++++++++ .../subpanels/ModelPanel/DefaultSettings.tsx | 68 --------- .../DefaultCfgRescaleMultiplier.tsx | 2 +- .../DefaultCfgScale.tsx | 2 +- .../DefaultScheduler.tsx | 2 +- .../DefaultSettingsForm.tsx | 0 .../DefaultSteps.tsx | 2 +- .../DefaultVae.tsx | 2 +- .../DefaultVaePrecision.tsx | 2 +- .../MainModelDefaultSettings.tsx | 144 ++++++++++++++++++ .../SettingToggle.tsx | 0 .../subpanels/ModelPanel/ModelView.tsx | 4 +- .../frontend/web/src/services/api/types.ts | 6 + 13 files changed, 223 insertions(+), 76 deletions(-) create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts delete mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings.tsx rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultCfgRescaleMultiplier.tsx (98%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultCfgScale.tsx (98%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultScheduler.tsx (97%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultSettingsForm.tsx (100%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultSteps.tsx (98%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultVae.tsx (98%) rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/DefaultVaePrecision.tsx (97%) create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{DefaultSettings => MainModelDefaultSettings}/SettingToggle.tsx (100%) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts new file mode 100644 index 0000000000..207199ec93 --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts @@ -0,0 +1,65 @@ +import { skipToken } from '@reduxjs/toolkit/query'; +import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; +import { useAppSelector } from 'app/store/storeHooks'; +import { selectConfigSlice } from 'features/system/store/configSlice'; +import { isNil } from 'lodash-es'; +import { useMemo } from 'react'; +import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard'; +import { isNonRefinerMainModelConfig } from 'services/api/types'; + +const initialStatesSelector = createMemoizedSelector(selectConfigSlice, (config) => { + const { steps, guidance, scheduler, cfgRescaleMultiplier, vaePrecision } = config.sd; + + return { + initialSteps: steps.initial, + initialCfg: guidance.initial, + initialScheduler: scheduler, + initialCfgRescaleMultiplier: cfgRescaleMultiplier.initial, + initialVaePrecision: vaePrecision, + }; +}); + +export const useMainModelDefaultSettings = (modelKey?: string | null) => { + const { modelConfig, isLoading } = useGetModelConfigWithTypeGuard(modelKey ?? skipToken, isNonRefinerMainModelConfig); + + const { initialSteps, initialCfg, initialScheduler, initialCfgRescaleMultiplier, initialVaePrecision } = + useAppSelector(initialStatesSelector); + + const defaultSettingsDefaults = useMemo(() => { + return { + vae: { + isEnabled: !isNil(modelConfig?.default_settings?.vae), + value: modelConfig?.default_settings?.vae || 'default', + }, + vaePrecision: { + isEnabled: !isNil(modelConfig?.default_settings?.vae_precision), + value: modelConfig?.default_settings?.vae_precision || initialVaePrecision || 'fp32', + }, + scheduler: { + isEnabled: !isNil(modelConfig?.default_settings?.scheduler), + value: modelConfig?.default_settings?.scheduler || initialScheduler || 'euler', + }, + steps: { + isEnabled: !isNil(modelConfig?.default_settings?.steps), + value: modelConfig?.default_settings?.steps || initialSteps, + }, + cfgScale: { + isEnabled: !isNil(modelConfig?.default_settings?.cfg_scale), + value: modelConfig?.default_settings?.cfg_scale || initialCfg, + }, + cfgRescaleMultiplier: { + isEnabled: !isNil(modelConfig?.default_settings?.cfg_rescale_multiplier), + value: modelConfig?.default_settings?.cfg_rescale_multiplier || initialCfgRescaleMultiplier, + }, + }; + }, [ + modelConfig?.default_settings, + initialSteps, + initialCfg, + initialScheduler, + initialCfgRescaleMultiplier, + initialVaePrecision, + ]); + + return { defaultSettingsDefaults, isLoading }; +}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings.tsx deleted file mode 100644 index 0e31d3b53e..0000000000 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Text } from '@invoke-ai/ui-library'; -import { skipToken } from '@reduxjs/toolkit/query'; -import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; -import { useAppSelector } from 'app/store/storeHooks'; -import { selectConfigSlice } from 'features/system/store/configSlice'; -import { isNil } from 'lodash-es'; -import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useGetModelConfigQuery } from 'services/api/endpoints/models'; - -import { DefaultSettingsForm } from './DefaultSettings/DefaultSettingsForm'; - -const initialStatesSelector = createMemoizedSelector(selectConfigSlice, (config) => { - const { steps, guidance, scheduler, cfgRescaleMultiplier, vaePrecision } = config.sd; - - return { - initialSteps: steps.initial, - initialCfg: guidance.initial, - initialScheduler: scheduler, - initialCfgRescaleMultiplier: cfgRescaleMultiplier.initial, - initialVaePrecision: vaePrecision, - }; -}); - -export const DefaultSettings = () => { - const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); - const { t } = useTranslation(); - - const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken); - const { initialSteps, initialCfg, initialScheduler, initialCfgRescaleMultiplier, initialVaePrecision } = - useAppSelector(initialStatesSelector); - - const defaultSettingsDefaults = useMemo(() => { - return { - vae: { isEnabled: !isNil(data?.default_settings?.vae), value: data?.default_settings?.vae || 'default' }, - vaePrecision: { - isEnabled: !isNil(data?.default_settings?.vae_precision), - value: data?.default_settings?.vae_precision || initialVaePrecision || 'fp32', - }, - scheduler: { - isEnabled: !isNil(data?.default_settings?.scheduler), - value: data?.default_settings?.scheduler || initialScheduler || 'euler', - }, - steps: { isEnabled: !isNil(data?.default_settings?.steps), value: data?.default_settings?.steps || initialSteps }, - cfgScale: { - isEnabled: !isNil(data?.default_settings?.cfg_scale), - value: data?.default_settings?.cfg_scale || initialCfg, - }, - cfgRescaleMultiplier: { - isEnabled: !isNil(data?.default_settings?.cfg_rescale_multiplier), - value: data?.default_settings?.cfg_rescale_multiplier || initialCfgRescaleMultiplier, - }, - }; - }, [ - data?.default_settings, - initialSteps, - initialCfg, - initialScheduler, - initialCfgRescaleMultiplier, - initialVaePrecision, - ]); - - if (isLoading) { - return {t('common.loading')}; - } - - return ; -}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgRescaleMultiplier.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx similarity index 98% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgRescaleMultiplier.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx index 5e1cfe990a..f27885aa81 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgRescaleMultiplier.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx @@ -1,7 +1,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgScale.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx similarity index 98% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgScale.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx index a1bb34868b..131d85ac27 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultCfgScale.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx @@ -1,7 +1,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultScheduler.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx similarity index 97% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultScheduler.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx index d195b2cc38..145f670e54 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultScheduler.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx @@ -1,7 +1,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library'; import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants'; import { isParameterScheduler } from 'features/parameters/types/parameterSchemas'; import { useCallback, useMemo } from 'react'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultSettingsForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx similarity index 100% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultSettingsForm.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultSteps.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx similarity index 98% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultSteps.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx index 37282564b5..c366fe1237 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultSteps.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx @@ -1,7 +1,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVae.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx similarity index 98% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVae.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx index d00f6b212f..612ea32690 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVae.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx @@ -3,7 +3,7 @@ import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { skipToken } from '@reduxjs/toolkit/query'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { map } from 'lodash-es'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVaePrecision.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx similarity index 97% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVaePrecision.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx index b5cfe6f81e..9c7286540b 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/DefaultVaePrecision.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx @@ -1,7 +1,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library'; import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; import { isParameterPrecision } from 'features/parameters/types/parameterSchemas'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx new file mode 100644 index 0000000000..54563bf63f --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx @@ -0,0 +1,144 @@ +import { Button, Flex, Heading, Text } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useMainModelDefaultSettings } from 'features/modelManagerV2/hooks/useMainModelDefaultSettings'; +import type { ParameterScheduler } from 'features/parameters/types/parameterSchemas'; +import { addToast } from 'features/system/store/systemSlice'; +import { makeToast } from 'features/system/util/makeToast'; +import { useCallback } from 'react'; +import type { SubmitHandler } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { PiCheckBold } from 'react-icons/pi'; +import { useUpdateModelMutation } from 'services/api/endpoints/models'; + +import { DefaultCfgRescaleMultiplier } from './DefaultCfgRescaleMultiplier'; +import { DefaultCfgScale } from './DefaultCfgScale'; +import { DefaultScheduler } from './DefaultScheduler'; +import { DefaultSteps } from './DefaultSteps'; +import { DefaultVae } from './DefaultVae'; +import { DefaultVaePrecision } from './DefaultVaePrecision'; +interface FormField { + value: T; + isEnabled: boolean; +} + +type DefaultSettingsFormData = { + vae: FormField; + vaePrecision: FormField; + scheduler: FormField; + steps: FormField; + cfgScale: FormField; + cfgRescaleMultiplier: FormField; +}; + +export const MainModelDefaultSettings = () => { + const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + + const { defaultSettingsDefaults, isLoading: isLoadingDefaultSettings } = + useMainModelDefaultSettings(selectedModelKey); + + const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation(); + + const { handleSubmit, control, formState, reset } = useForm({ + defaultValues: defaultSettingsDefaults, + }); + + const onSubmit = useCallback>( + (data) => { + if (!selectedModelKey) { + return; + } + + const body = { + vae: data.vae.isEnabled ? data.vae.value : null, + vae_precision: data.vaePrecision.isEnabled ? data.vaePrecision.value : null, + cfg_scale: data.cfgScale.isEnabled ? data.cfgScale.value : null, + cfg_rescale_multiplier: data.cfgRescaleMultiplier.isEnabled ? data.cfgRescaleMultiplier.value : null, + steps: data.steps.isEnabled ? data.steps.value : null, + scheduler: data.scheduler.isEnabled ? data.scheduler.value : null, + }; + + updateModel({ + key: selectedModelKey, + body: { default_settings: body }, + }) + .unwrap() + .then((_) => { + dispatch( + addToast( + makeToast({ + title: t('modelManager.defaultSettingsSaved'), + status: 'success', + }) + ) + ); + reset(data); + }) + .catch((error) => { + if (error) { + dispatch( + addToast( + makeToast({ + title: `${error.data.detail} `, + status: 'error', + }) + ) + ); + } + }); + }, + [selectedModelKey, dispatch, reset, updateModel, t] + ); + + if (isLoadingDefaultSettings) { + return {t('common.loading')}; + } + + return ( + <> + + {t('modelManager.defaultSettings')} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle.tsx similarity index 100% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/DefaultSettings/SettingToggle.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle.tsx diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx index a167823596..a8143f1c19 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx @@ -5,7 +5,7 @@ import { TriggerPhrases } from 'features/modelManagerV2/subpanels/ModelPanel/Tri import { useTranslation } from 'react-i18next'; import { useGetModelConfigQuery } from 'services/api/endpoints/models'; -import { DefaultSettings } from './DefaultSettings'; +import { MainModelDefaultSettings } from './MainModelDefaultSettings/MainModelDefaultSettings'; import { ModelAttrView } from './ModelAttrView'; export const ModelView = () => { @@ -61,7 +61,7 @@ export const ModelView = () => { {data.type === 'main' && ( - + )} {(data.type === 'main' || data.type === 'lora') && ( diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 46faa35d8e..2d304a8333 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -89,6 +89,12 @@ export const isControlAdapterModelConfig = ( return isControlNetModelConfig(config) || isT2IAdapterModelConfig(config) || isIPAdapterModelConfig(config); }; +export const isControlNetOrT2IAdapterModelConfig = ( + config: AnyModelConfig +): config is ControlNetModelConfig | T2IAdapterModelConfig => { + return isControlNetModelConfig(config) || isT2IAdapterModelConfig(config); +}; + export const isNonRefinerMainModelConfig = (config: AnyModelConfig): config is MainModelConfig => { return config.type === 'main' && config.base !== 'sdxl-refiner'; }; From 97953f5eb3fc354fe2746413c0d940d2b5d1fa7b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:19:10 +1100 Subject: [PATCH 09/16] fix(mm): add control adapter default settings to ModelRecordChanges schema This is needed to update Control Adapter defaults. --- .../app/services/model_records/model_records_base.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py index 1df64709b9..094ade6383 100644 --- a/invokeai/app/services/model_records/model_records_base.py +++ b/invokeai/app/services/model_records/model_records_base.py @@ -18,7 +18,12 @@ ModelFormat, ModelType, ) -from invokeai.backend.model_manager.config import MainModelDefaultSettings, ModelVariantType, SchedulerPredictionType +from invokeai.backend.model_manager.config import ( + ControlAdapterDefaultSettings, + MainModelDefaultSettings, + ModelVariantType, + SchedulerPredictionType, +) class DuplicateModelException(Exception): @@ -68,7 +73,7 @@ class ModelRecordChanges(BaseModelExcludeNull): description: Optional[str] = Field(description="Model description", default=None) base: Optional[BaseModelType] = Field(description="The base model.", default=None) trigger_phrases: Optional[set[str]] = Field(description="Set of trigger phrases for this model", default=None) - default_settings: Optional[MainModelDefaultSettings] = Field( + default_settings: Optional[MainModelDefaultSettings | ControlAdapterDefaultSettings] = Field( description="Default settings for this model", default=None ) From 5a96b2b371921c3cf8343ee84e46a44a8f724800 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:22:34 +1100 Subject: [PATCH 10/16] chore(ui): typegen --- invokeai/frontend/web/src/services/api/schema.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 94b62269f2..db244d53d1 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -4103,7 +4103,7 @@ export type components = { * @description The nodes in this graph */ nodes: { - [key: string]: components["schemas"]["ImageBlurInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["IntegerInvocation"]; + [key: string]: components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["IntegerMathInvocation"]; }; /** * Edges @@ -4140,7 +4140,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["T2IAdapterOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["SDXLModelLoaderOutput"]; + [key: string]: components["schemas"]["LatentsOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["FloatOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["UNetOutput"]; }; /** * Errors @@ -7442,8 +7442,11 @@ export type components = { * @description Set of trigger phrases for this model */ trigger_phrases?: string[] | null; - /** @description Default settings for this model */ - default_settings?: components["schemas"]["MainModelDefaultSettings"] | null; + /** + * Default Settings + * @description Default settings for this model + */ + default_settings?: components["schemas"]["MainModelDefaultSettings"] | components["schemas"]["ControlAdapterDefaultSettings"] | null; /** @description The variant of the model. */ variant?: components["schemas"]["ModelVariantType"] | null; /** @description The prediction type of the model. */ From 4ab572ddd80cf0b8058924ba1b6884982d29acfc Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:22:37 +1100 Subject: [PATCH 11/16] feat(ui): update default settings for control adapters - Split out main model defaults - Add controlnet/t2i defaults (which includes only the preprocessor) --- .../listeners/setDefaultSettings.ts | 78 +++++----- .../controlAdapters/store/constants.ts | 20 --- .../controlAdapters/store/types.test.ts | 5 +- ...seControlNetOrT2IAdapterDefaultSettings.ts | 23 +++ .../ControlNetOrT2IAdapterDefaultSettings.tsx | 105 +++++++++++++ .../DefaultPreprocessor.tsx | 66 ++++++++ .../DefaultCfgRescaleMultiplier.tsx | 8 +- .../DefaultCfgScale.tsx | 8 +- .../DefaultScheduler.tsx | 8 +- .../DefaultSettingsForm.tsx | 141 ------------------ .../MainModelDefaultSettings/DefaultSteps.tsx | 8 +- .../MainModelDefaultSettings/DefaultVae.tsx | 8 +- .../DefaultVaePrecision.tsx | 8 +- .../MainModelDefaultSettings.tsx | 9 +- .../subpanels/ModelPanel/ModelView.tsx | 6 + .../SettingToggle.tsx | 4 +- 16 files changed, 273 insertions(+), 232 deletions(-) create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx delete mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx rename invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/{MainModelDefaultSettings => }/SettingToggle.tsx (79%) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts index da7cf6b6fe..e76f9de8f0 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts @@ -21,6 +21,7 @@ import { makeToast } from 'features/system/util/makeToast'; import { t } from 'i18next'; import { map } from 'lodash-es'; import { modelsApi } from 'services/api/endpoints/models'; +import { isNonRefinerMainModelConfig } from 'services/api/types'; export const addSetDefaultSettingsListener = (startAppListening: AppStartListening) => { startAppListening({ @@ -36,61 +37,64 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni const modelConfig = await dispatch(modelsApi.endpoints.getModelConfig.initiate(currentModel.key)).unwrap(); - if (!modelConfig || !modelConfig.default_settings) { + if (!modelConfig) { return; } - const { vae, vae_precision, cfg_scale, cfg_rescale_multiplier, steps, scheduler } = modelConfig.default_settings; + if (isNonRefinerMainModelConfig(modelConfig) && modelConfig.default_settings) { + const { vae, vae_precision, cfg_scale, cfg_rescale_multiplier, steps, scheduler } = + modelConfig.default_settings; - if (vae) { - // we store this as "default" within default settings - // to distinguish it from no default set - if (vae === 'default') { - dispatch(vaeSelected(null)); - } else { - const { data } = modelsApi.endpoints.getVaeModels.select()(state); - const vaeArray = map(data?.entities); - const validVae = vaeArray.find((model) => model.key === vae); + if (vae) { + // we store this as "default" within default settings + // to distinguish it from no default set + if (vae === 'default') { + dispatch(vaeSelected(null)); + } else { + const { data } = modelsApi.endpoints.getVaeModels.select()(state); + const vaeArray = map(data?.entities); + const validVae = vaeArray.find((model) => model.key === vae); - const result = zParameterVAEModel.safeParse(validVae); - if (!result.success) { - return; + const result = zParameterVAEModel.safeParse(validVae); + if (!result.success) { + return; + } + dispatch(vaeSelected(result.data)); } - dispatch(vaeSelected(result.data)); } - } - if (vae_precision) { - if (isParameterPrecision(vae_precision)) { - dispatch(vaePrecisionChanged(vae_precision)); + if (vae_precision) { + if (isParameterPrecision(vae_precision)) { + dispatch(vaePrecisionChanged(vae_precision)); + } } - } - if (cfg_scale) { - if (isParameterCFGScale(cfg_scale)) { - dispatch(setCfgScale(cfg_scale)); + if (cfg_scale) { + if (isParameterCFGScale(cfg_scale)) { + dispatch(setCfgScale(cfg_scale)); + } } - } - if (cfg_rescale_multiplier) { - if (isParameterCFGRescaleMultiplier(cfg_rescale_multiplier)) { - dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier)); + if (cfg_rescale_multiplier) { + if (isParameterCFGRescaleMultiplier(cfg_rescale_multiplier)) { + dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier)); + } } - } - if (steps) { - if (isParameterSteps(steps)) { - dispatch(setSteps(steps)); + if (steps) { + if (isParameterSteps(steps)) { + dispatch(setSteps(steps)); + } } - } - if (scheduler) { - if (isParameterScheduler(scheduler)) { - dispatch(setScheduler(scheduler)); + if (scheduler) { + if (isParameterScheduler(scheduler)) { + dispatch(setScheduler(scheduler)); + } } - } - dispatch(addToast(makeToast({ title: t('toast.parameterSet', { parameter: 'Default settings' }) }))); + dispatch(addToast(makeToast({ title: t('toast.parameterSet', { parameter: 'Default settings' }) }))); + } }, }); }; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index 01c7d4217f..91f792bf97 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -253,23 +253,3 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = { }, }, }; - -export const CONTROLNET_MODEL_DEFAULT_PROCESSORS: { - [key: string]: ControlAdapterProcessorType; -} = { - canny: 'canny_image_processor', - mlsd: 'mlsd_image_processor', - depth: 'depth_anything_image_processor', - bae: 'normalbae_image_processor', - sketch: 'pidi_image_processor', - scribble: 'lineart_image_processor', - lineart: 'lineart_image_processor', - lineart_anime: 'lineart_anime_image_processor', - softedge: 'hed_image_processor', - shuffle: 'content_shuffle_image_processor', - openpose: 'dw_openpose_image_processor', - mediapipe: 'mediapipe_face_processor', - pidi: 'pidi_image_processor', - zoe: 'zoe_depth_image_processor', - color: 'color_map_image_processor', -}; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts index 143f5ff3d4..3bde8bc6c6 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.test.ts @@ -1,7 +1,4 @@ -import type { - ControlAdapterProcessorType, - zControlAdapterProcessorType, -} from 'features/controlAdapters/store/types'; +import type { ControlAdapterProcessorType, zControlAdapterProcessorType } from 'features/controlAdapters/store/types'; import type { Equals } from 'tsafe'; import { assert } from 'tsafe'; import { describe, test } from 'vitest'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts new file mode 100644 index 0000000000..826bec17b1 --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts @@ -0,0 +1,23 @@ +import { skipToken } from '@reduxjs/toolkit/query'; +import { isNil } from 'lodash-es'; +import { useMemo } from 'react'; +import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard'; +import { isControlNetOrT2IAdapterModelConfig } from 'services/api/types'; + +export const useControlNetOrT2IAdapterDefaultSettings = (modelKey?: string | null) => { + const { modelConfig, isLoading } = useGetModelConfigWithTypeGuard( + modelKey ?? skipToken, + isControlNetOrT2IAdapterModelConfig + ); + + const defaultSettingsDefaults = useMemo(() => { + return { + preprocessor: { + isEnabled: !isNil(modelConfig?.default_settings?.preprocessor), + value: modelConfig?.default_settings?.preprocessor || 'none', + }, + }; + }, [modelConfig?.default_settings]); + + return { defaultSettingsDefaults, isLoading }; +}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx new file mode 100644 index 0000000000..d54320b9dd --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx @@ -0,0 +1,105 @@ +import { Button, Flex, Heading, Text } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings'; +import { DefaultPreprocessor } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor'; +import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings'; +import { addToast } from 'features/system/store/systemSlice'; +import { makeToast } from 'features/system/util/makeToast'; +import { useCallback } from 'react'; +import type { SubmitHandler } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { PiCheckBold } from 'react-icons/pi'; +import { useUpdateModelMutation } from 'services/api/endpoints/models'; + +export type ControlNetOrT2IAdapterDefaultSettingsFormData = { + preprocessor: FormField; +}; + +export const ControlNetOrT2IAdapterDefaultSettings = () => { + const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + + const { defaultSettingsDefaults, isLoading: isLoadingDefaultSettings } = + useControlNetOrT2IAdapterDefaultSettings(selectedModelKey); + + const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation(); + + const { handleSubmit, control, formState, reset } = useForm({ + defaultValues: defaultSettingsDefaults, + }); + + const onSubmit = useCallback>( + (data) => { + if (!selectedModelKey) { + return; + } + + const body = { + preprocessor: data.preprocessor.isEnabled ? data.preprocessor.value : null, + }; + + updateModel({ + key: selectedModelKey, + body: { default_settings: body }, + }) + .unwrap() + .then((_) => { + dispatch( + addToast( + makeToast({ + title: t('modelManager.defaultSettingsSaved'), + status: 'success', + }) + ) + ); + reset(data); + }) + .catch((error) => { + if (error) { + dispatch( + addToast( + makeToast({ + title: `${error.data.detail} `, + status: 'error', + }) + ) + ); + } + }); + }, + [selectedModelKey, dispatch, reset, updateModel, t] + ); + + if (isLoadingDefaultSettings) { + return {t('common.loading')}; + } + + return ( + <> + + {t('modelManager.defaultSettings')} + + + + + + + + + + + + ); +}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx new file mode 100644 index 0000000000..b2284336bf --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx @@ -0,0 +1,66 @@ +import type { ComboboxOnChange } from '@invoke-ai/ui-library'; +import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; +import type { ControlNetOrT2IAdapterDefaultSettingsFormData } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings'; +import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; +import { useCallback, useMemo } from 'react'; +import type { UseControllerProps } from 'react-hook-form'; +import { useController } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +const OPTIONS = [ + { label: 'Canny', value: 'canny_image_processor' }, + { label: 'MLSD', value: 'mlsd_image_processor' }, + { label: 'Depth Anything', value: 'depth_anything_image_processor' }, + { label: 'Normal BAE', value: 'normalbae_image_processor' }, + { label: 'Pidi', value: 'pidi_image_processor' }, + { label: 'Lineart', value: 'lineart_image_processor' }, + { label: 'Lineart Anime', value: 'lineart_anime_image_processor' }, + { label: 'HED', value: 'hed_image_processor' }, + { label: 'Content Shuffle', value: 'content_shuffle_image_processor' }, + { label: 'DW OpenPose', value: 'dw_openpose_image_processor' }, + { label: 'MediaPipe Face', value: 'mediapipe_face_processor' }, + { label: 'ZoeDepth', value: 'zoe_depth_image_processor' }, + { label: 'Color Map', value: 'color_map_image_processor' }, + { label: 'None', value: 'none' }, +] as const; + +type DefaultSchedulerType = ControlNetOrT2IAdapterDefaultSettingsFormData['preprocessor']; + +export function DefaultPreprocessor(props: UseControllerProps) { + const { t } = useTranslation(); + const { field } = useController(props); + + const onChange = useCallback( + (v) => { + if (!v) { + return; + } + const updatedValue = { + ...(field.value as FormField), + value: v.value, + }; + field.onChange(updatedValue); + }, + [field] + ); + + const value = useMemo(() => OPTIONS.find((o) => o.value === (field.value as FormField).value), [field]); + + const isDisabled = useMemo(() => { + return !(field.value as DefaultSchedulerType).isEnabled; + }, [field.value]); + + return ( + + + + {t('controlnet.processor')} + + + + + + ); +} diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx index f27885aa81..d16ce1460c 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx @@ -1,17 +1,17 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; -type DefaultCfgRescaleMultiplierType = DefaultSettingsFormData['cfgRescaleMultiplier']; +type DefaultCfgRescaleMultiplierType = MainModelDefaultSettingsFormData['cfgRescaleMultiplier']; -export function DefaultCfgRescaleMultiplier(props: UseControllerProps) { +export function DefaultCfgRescaleMultiplier(props: UseControllerProps) { const { field } = useController(props); const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx index 131d85ac27..293261bc35 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx @@ -1,17 +1,17 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; -type DefaultCfgType = DefaultSettingsFormData['cfgScale']; +type DefaultCfgType = MainModelDefaultSettingsFormData['cfgScale']; -export function DefaultCfgScale(props: UseControllerProps) { +export function DefaultCfgScale(props: UseControllerProps) { const { field } = useController(props); const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx index 145f670e54..4397e35a51 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx @@ -1,7 +1,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library'; import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants'; import { isParameterScheduler } from 'features/parameters/types/parameterSchemas'; import { useCallback, useMemo } from 'react'; @@ -9,11 +9,11 @@ import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; -type DefaultSchedulerType = DefaultSettingsFormData['scheduler']; +type DefaultSchedulerType = MainModelDefaultSettingsFormData['scheduler']; -export function DefaultScheduler(props: UseControllerProps) { +export function DefaultScheduler(props: UseControllerProps) { const { t } = useTranslation(); const { field } = useController(props); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx deleted file mode 100644 index 3c8551a52f..0000000000 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSettingsForm.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { Button, Flex, Heading } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import type { ParameterScheduler } from 'features/parameters/types/parameterSchemas'; -import { addToast } from 'features/system/store/systemSlice'; -import { makeToast } from 'features/system/util/makeToast'; -import { useCallback } from 'react'; -import type { SubmitHandler } from 'react-hook-form'; -import { useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { PiCheckBold } from 'react-icons/pi'; -import { useUpdateModelMutation } from 'services/api/endpoints/models'; - -import { DefaultCfgRescaleMultiplier } from './DefaultCfgRescaleMultiplier'; -import { DefaultCfgScale } from './DefaultCfgScale'; -import { DefaultScheduler } from './DefaultScheduler'; -import { DefaultSteps } from './DefaultSteps'; -import { DefaultVae } from './DefaultVae'; -import { DefaultVaePrecision } from './DefaultVaePrecision'; - -export interface FormField { - value: T; - isEnabled: boolean; -} - -export type DefaultSettingsFormData = { - vae: FormField; - vaePrecision: FormField; - scheduler: FormField; - steps: FormField; - cfgScale: FormField; - cfgRescaleMultiplier: FormField; -}; - -export const DefaultSettingsForm = ({ - defaultSettingsDefaults, -}: { - defaultSettingsDefaults: DefaultSettingsFormData; -}) => { - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); - - const [updateModel, { isLoading }] = useUpdateModelMutation(); - - const { handleSubmit, control, formState, reset } = useForm({ - defaultValues: defaultSettingsDefaults, - }); - - const onSubmit = useCallback>( - (data) => { - if (!selectedModelKey) { - return; - } - - const body = { - vae: data.vae.isEnabled ? data.vae.value : null, - vae_precision: data.vaePrecision.isEnabled ? data.vaePrecision.value : null, - cfg_scale: data.cfgScale.isEnabled ? data.cfgScale.value : null, - cfg_rescale_multiplier: data.cfgRescaleMultiplier.isEnabled ? data.cfgRescaleMultiplier.value : null, - steps: data.steps.isEnabled ? data.steps.value : null, - scheduler: data.scheduler.isEnabled ? data.scheduler.value : null, - }; - - updateModel({ - key: selectedModelKey, - body: { default_settings: body }, - }) - .unwrap() - .then((_) => { - dispatch( - addToast( - makeToast({ - title: t('modelManager.defaultSettingsSaved'), - status: 'success', - }) - ) - ); - reset(data); - }) - .catch((error) => { - if (error) { - dispatch( - addToast( - makeToast({ - title: `${error.data.detail} `, - status: 'error', - }) - ) - ); - } - }); - }, - [selectedModelKey, dispatch, reset, updateModel, t] - ); - - return ( - <> - - {t('modelManager.defaultSettings')} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx index c366fe1237..9c1912a0f7 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx @@ -1,17 +1,17 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; -type DefaultSteps = DefaultSettingsFormData['steps']; +type DefaultSteps = MainModelDefaultSettingsFormData['steps']; -export function DefaultSteps(props: UseControllerProps) { +export function DefaultSteps(props: UseControllerProps) { const { field } = useController(props); const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx index 612ea32690..dcaab94377 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx @@ -3,7 +3,7 @@ import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { skipToken } from '@reduxjs/toolkit/query'; import { useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { map } from 'lodash-es'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; @@ -11,11 +11,11 @@ import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useGetModelConfigQuery, useGetVaeModelsQuery } from 'services/api/endpoints/models'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; -type DefaultVaeType = DefaultSettingsFormData['vae']; +type DefaultVaeType = MainModelDefaultSettingsFormData['vae']; -export function DefaultVae(props: UseControllerProps) { +export function DefaultVae(props: UseControllerProps) { const { t } = useTranslation(); const { field } = useController(props); const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx index 9c7286540b..d33cf4e08d 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx @@ -1,23 +1,23 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library'; import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle'; +import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle'; import { isParameterPrecision } from 'features/parameters/types/parameterSchemas'; import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import type { DefaultSettingsFormData } from './DefaultSettingsForm'; +import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings'; const options = [ { label: 'FP16', value: 'fp16' }, { label: 'FP32', value: 'fp32' }, ]; -type DefaultVaePrecisionType = DefaultSettingsFormData['vaePrecision']; +type DefaultVaePrecisionType = MainModelDefaultSettingsFormData['vaePrecision']; -export function DefaultVaePrecision(props: UseControllerProps) { +export function DefaultVaePrecision(props: UseControllerProps) { const { t } = useTranslation(); const { field } = useController(props); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx index 54563bf63f..9766fc1a14 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx @@ -17,12 +17,13 @@ import { DefaultScheduler } from './DefaultScheduler'; import { DefaultSteps } from './DefaultSteps'; import { DefaultVae } from './DefaultVae'; import { DefaultVaePrecision } from './DefaultVaePrecision'; -interface FormField { + +export interface FormField { value: T; isEnabled: boolean; } -type DefaultSettingsFormData = { +export type MainModelDefaultSettingsFormData = { vae: FormField; vaePrecision: FormField; scheduler: FormField; @@ -41,11 +42,11 @@ export const MainModelDefaultSettings = () => { const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation(); - const { handleSubmit, control, formState, reset } = useForm({ + const { handleSubmit, control, formState, reset } = useForm({ defaultValues: defaultSettingsDefaults, }); - const onSubmit = useCallback>( + const onSubmit = useCallback>( (data) => { if (!selectedModelKey) { return; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx index a8143f1c19..f7e2780fe1 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx @@ -1,6 +1,7 @@ import { Box, Flex, Text } from '@invoke-ai/ui-library'; import { skipToken } from '@reduxjs/toolkit/query'; import { useAppSelector } from 'app/store/storeHooks'; +import { ControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings'; import { TriggerPhrases } from 'features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases'; import { useTranslation } from 'react-i18next'; import { useGetModelConfigQuery } from 'services/api/endpoints/models'; @@ -64,6 +65,11 @@ export const ModelView = () => { )} + {(data.type === 'controlnet' || data.type === 't2i_adapter') && ( + + + + )} {(data.type === 'main' || data.type === 'lora') && ( diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx similarity index 79% rename from invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle.tsx rename to invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx index 7f5cd8efb9..15e4693c4f 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx @@ -4,9 +4,9 @@ import { useCallback, useMemo } from 'react'; import type { UseControllerProps } from 'react-hook-form'; import { useController } from 'react-hook-form'; -import type { DefaultSettingsFormData, FormField } from './DefaultSettingsForm'; +import type { FormField } from './MainModelDefaultSettings/MainModelDefaultSettings'; -export function SettingToggle(props: UseControllerProps) { +export function SettingToggle>>(props: UseControllerProps) { const { field } = useController(props); const value = useMemo(() => { From bf303ec743f5c9b3e8a6680fa72a7af960a43c4b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:25:45 +1100 Subject: [PATCH 12/16] fix(ui): do not show default settings for refiner models --- .../features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx index f7e2780fe1..adb123f24d 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx @@ -60,7 +60,7 @@ export const ModelView = () => { )} - {data.type === 'main' && ( + {data.type === 'main' && data.base !== 'sdxl-refiner' && ( From a097f18c14f24add6c326d8028a63ec78f48bd6c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:39:13 +1100 Subject: [PATCH 13/16] fix(mm): fix bug in control adapter probe default settings Wasn't checking for matches correctly. --- invokeai/backend/model_manager/probe.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 49c25fa843..cfcb1f154e 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -346,23 +346,25 @@ class ControlAdapterProbe(ProbeBase): "mlsd": "mlsd_image_processor", "depth": "depth_anything_image_processor", "bae": "normalbae_image_processor", - "normal_bae": "normalbae_image_processor", + "normal": "normalbae_image_processor", "sketch": "pidi_image_processor", "scribble": "lineart_image_processor", "lineart": "lineart_image_processor", "lineart_anime": "lineart_anime_image_processor", "softedge": "hed_image_processor", "shuffle": "content_shuffle_image_processor", - "openpose": "dw_openpose_image_processor", + "pose": "dw_openpose_image_processor", "mediapipe": "mediapipe_face_processor", "pidi": "pidi_image_processor", "zoe": "zoe_depth_image_processor", "color": "color_map_image_processor", } - def get_default_settings(self, model_name: str) -> Optional[ControlAdapterDefaultSettings]: - if model_name in self.MODEL_NAME_TO_PREPROCESSOR: - return ControlAdapterDefaultSettings(preprocessor=self.MODEL_NAME_TO_PREPROCESSOR[model_name]) + @classmethod + def get_default_settings(cls, model_name: str) -> Optional[ControlAdapterDefaultSettings]: + for k, v in cls.MODEL_NAME_TO_PREPROCESSOR.items(): + if k in model_name: + return ControlAdapterDefaultSettings(preprocessor=v) return None From 7343971ce23fffdbc5be6ff4c6e5480c8dee6418 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:39:26 +1100 Subject: [PATCH 14/16] tests(mm): add tests for control adapter probe default settings --- tests/test_model_probe.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/test_model_probe.py b/tests/test_model_probe.py index 78a9ec50b4..1aba632380 100644 --- a/tests/test_model_probe.py +++ b/tests/test_model_probe.py @@ -3,7 +3,7 @@ import pytest from invokeai.backend.model_manager import BaseModelType, ModelRepoVariant -from invokeai.backend.model_manager.probe import VaeFolderProbe +from invokeai.backend.model_manager.probe import ControlAdapterProbe, VaeFolderProbe @pytest.mark.parametrize( @@ -28,3 +28,17 @@ def test_repo_variant(datadir: Path): probe = VaeFolderProbe(datadir / "vae" / "taesdxl-fp16") repo_variant = probe.get_repo_variant() assert repo_variant == ModelRepoVariant.FP16 + + +def test_controlnet_t2i_default_settings(): + should_be_canny = ControlAdapterProbe.get_default_settings("some_canny_model") + assert should_be_canny and should_be_canny.preprocessor == "canny_image_processor" + + should_be_depth_anything = ControlAdapterProbe.get_default_settings("some_depth_model") + assert should_be_depth_anything and should_be_depth_anything.preprocessor == "depth_anything_image_processor" + + should_be_dw_openpose = ControlAdapterProbe.get_default_settings("some_pose_model") + assert should_be_dw_openpose and should_be_dw_openpose.preprocessor == "dw_openpose_image_processor" + + should_be_none = ControlAdapterProbe.get_default_settings("i like turtles") + assert should_be_none is None From 24600d33a4261fdd6e79365d5ccaaa8797fe6516 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:47:58 +1100 Subject: [PATCH 15/16] feat(ui): use control adapter processor helper in metadata parser --- .../web/src/features/metadata/util/parsers.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/invokeai/frontend/web/src/features/metadata/util/parsers.ts b/invokeai/frontend/web/src/features/metadata/util/parsers.ts index 9cb2841ae4..24274b8e6a 100644 --- a/invokeai/frontend/web/src/features/metadata/util/parsers.ts +++ b/invokeai/frontend/web/src/features/metadata/util/parsers.ts @@ -1,10 +1,9 @@ -import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; -import { isControlAdapterProcessorType } from 'features/controlAdapters/store/types'; import { initialControlNet, initialIPAdapter, initialT2IAdapter, } from 'features/controlAdapters/util/buildControlAdapter'; +import { buildControlAdapterProcessor } from 'features/controlAdapters/util/buildControlAdapterProcessor'; import type { LoRA } from 'features/lora/store/loraSlice'; import { defaultLoRAConfig } from 'features/lora/store/loraSlice'; import type { @@ -254,9 +253,7 @@ const parseControlNet: MetadataParseFunc = async (meta .catch(null) .parse(getProperty(metadataItem, 'resize_mode')); - const defaultPreprocessor = controlNetModel.default_settings?.preprocessor; - const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; - const processorNode = CONTROLNET_PROCESSORS[processorType].default; + const { processorType, processorNode } = buildControlAdapterProcessor(controlNetModel); const controlNet: ControlNetConfigMetadata = { type: 'controlnet', @@ -307,9 +304,7 @@ const parseT2IAdapter: MetadataParseFunc = async (meta .catch(null) .parse(getProperty(metadataItem, 'resize_mode')); - const defaultPreprocessor = t2iAdapterModel.default_settings?.preprocessor; - const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none'; - const processorNode = CONTROLNET_PROCESSORS[processorType].default; + const { processorType, processorNode } = buildControlAdapterProcessor(t2iAdapterModel); const t2iAdapter: T2IAdapterConfigMetadata = { type: 't2i_adapter', From ec9fe97e4b51fb2923ec70af237031ff0705263e Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Fri, 8 Mar 2024 12:20:08 -0500 Subject: [PATCH 16/16] Rerun typegen --- invokeai/frontend/web/src/services/api/schema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index db244d53d1..58b1ca309e 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -4103,7 +4103,7 @@ export type components = { * @description The nodes in this graph */ nodes: { - [key: string]: components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["IntegerMathInvocation"]; + [key: string]: components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["DWOpenposeImageProcessorInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"]; }; /** * Edges @@ -4140,7 +4140,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["LatentsOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["FloatOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["UNetOutput"]; + [key: string]: components["schemas"]["ColorCollectionOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["String2Output"] | components["schemas"]["NoiseOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["IPAdapterOutput"]; }; /** * Errors