diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 61e76a288eb..0033b56d3c1 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -5,6 +5,8 @@ import inspect import re import sys +import types +import typing import warnings from abc import ABC, abstractmethod from enum import Enum @@ -20,8 +22,10 @@ Literal, Optional, Type, + TypedDict, TypeVar, Union, + cast, ) import semver @@ -104,6 +108,11 @@ class UIConfigBase(BaseModel): ) +class OriginalModelField(TypedDict): + annotation: Any + field_info: FieldInfo + + class BaseInvocationOutput(BaseModel): """ Base class for all invocation outputs. @@ -132,6 +141,9 @@ def get_type(cls) -> str: """Gets the invocation output's type, as provided by the `@invocation_output` decorator.""" return cls.model_fields["type"].default + _original_model_fields: ClassVar[dict[str, OriginalModelField]] = {} + """The original model fields, before any modifications were made by the @invocation_output decorator.""" + model_config = ConfigDict( protected_namespaces=(), validate_assignment=True, @@ -264,6 +276,9 @@ def invoke_internal(self, context: InvocationContext, services: "InvocationServi coerce_numbers_to_str=True, ) + _original_model_fields: ClassVar[dict[str, OriginalModelField]] = {} + """The original model fields, before any modifications were made by the @invocation decorator.""" + TBaseInvocation = TypeVar("TBaseInvocation", bound=BaseInvocation) @@ -489,6 +504,48 @@ def validate_fields(model_fields: dict[str, FieldInfo], model_type: str) -> None return None +class NoDefaultSentinel: + pass + + +def validate_field_default( + cls_name: str, field_name: str, invocation_type: str, annotation: Any, field_info: FieldInfo +) -> None: + """Validates the default value of a field against its pydantic field definition.""" + + assert isinstance(field_info.json_schema_extra, dict), "json_schema_extra is not a dict" + + # By the time we are doing this, we've already done some pydantic magic by overriding the original default value. + # We store the original default value in the json_schema_extra dict, so we can validate it here. + orig_default = field_info.json_schema_extra.get("orig_default", NoDefaultSentinel) + + if orig_default is NoDefaultSentinel: + return + + # To validate the default value, we can create a temporary pydantic model with the field we are validating as its + # only field. Then validate the default value against this temporary model. + TempDefaultValidator = cast(BaseModel, create_model(cls_name, **{field_name: (annotation, field_info)})) + + try: + TempDefaultValidator.model_validate({field_name: orig_default}) + except Exception as e: + raise InvalidFieldError( + f'Default value for field "{field_name}" on invocation "{invocation_type}" is invalid, {e}' + ) from e + + +def is_optional(annotation: Any) -> bool: + """ + Checks if the given annotation is optional (i.e. Optional[X], Union[X, None] or X | None). + """ + origin = typing.get_origin(annotation) + # PEP 604 unions (int|None) have origin types.UnionType + is_union = origin is typing.Union or origin is types.UnionType + if not is_union: + return False + return any(arg is type(None) for arg in typing.get_args(annotation)) + + def invocation( invocation_type: str, title: Optional[str] = None, @@ -523,6 +580,24 @@ def wrapper(cls: Type[TBaseInvocation]) -> Type[TBaseInvocation]: validate_fields(cls.model_fields, invocation_type) + fields: dict[str, tuple[Any, FieldInfo]] = {} + + for field_name, field_info in cls.model_fields.items(): + annotation = field_info.annotation + assert annotation is not None, f"{field_name} on invocation {invocation_type} has no type annotation." + assert isinstance(field_info.json_schema_extra, dict), ( + f"{field_name} on invocation {invocation_type} has a non-dict json_schema_extra, did you forget to use InputField?" + ) + + cls._original_model_fields[field_name] = OriginalModelField(annotation=annotation, field_info=field_info) + + validate_field_default(cls.__name__, field_name, invocation_type, annotation, field_info) + + if field_info.default is None and not is_optional(annotation): + annotation = annotation | None + + fields[field_name] = (annotation, field_info) + # Add OpenAPI schema extras uiconfig: dict[str, Any] = {} uiconfig["title"] = title @@ -557,11 +632,17 @@ def wrapper(cls: Type[TBaseInvocation]) -> Type[TBaseInvocation]: # Unfortunately, because the `GraphInvocation` uses a forward ref in its `graph` field's annotation, this does # not work. Instead, we have to create a new class with the type field and patch the original class with it. - invocation_type_annotation = Literal[invocation_type] # type: ignore - invocation_type_field = Field( - title="type", default=invocation_type, json_schema_extra={"field_kind": FieldKind.NodeAttribute} + invocation_type_annotation = Literal[invocation_type] + + # Field() returns an instance of FieldInfo, but thanks to a pydantic implementation detail, it is _typed_ as Any. + # This cast makes the type annotation match the class's true type. + invocation_type_field_info = cast( + FieldInfo, + Field(title="type", default=invocation_type, json_schema_extra={"field_kind": FieldKind.NodeAttribute}), ) + fields["type"] = (invocation_type_annotation, invocation_type_field_info) + # Validate the `invoke()` method is implemented if "invoke" in cls.__abstractmethods__: raise ValueError(f'Invocation "{invocation_type}" must implement the "invoke" method') @@ -583,17 +664,12 @@ def wrapper(cls: Type[TBaseInvocation]) -> Type[TBaseInvocation]: ) docstring = cls.__doc__ - cls = create_model( - cls.__qualname__, - __base__=cls, - __module__=cls.__module__, - type=(invocation_type_annotation, invocation_type_field), - ) - cls.__doc__ = docstring + new_class = create_model(cls.__qualname__, __base__=cls, __module__=cls.__module__, **fields) # type: ignore + new_class.__doc__ = docstring - InvocationRegistry.register_invocation(cls) + InvocationRegistry.register_invocation(new_class) - return cls + return new_class return wrapper @@ -618,23 +694,39 @@ def wrapper(cls: Type[TBaseInvocationOutput]) -> Type[TBaseInvocationOutput]: validate_fields(cls.model_fields, output_type) + fields: dict[str, tuple[Any, FieldInfo]] = {} + + for field_name, field_info in cls.model_fields.items(): + annotation = field_info.annotation + assert annotation is not None, f"{field_name} on invocation output {output_type} has no type annotation." + assert isinstance(field_info.json_schema_extra, dict), ( + f"{field_name} on invocation output {output_type} has a non-dict json_schema_extra, did you forget to use InputField?" + ) + + cls._original_model_fields[field_name] = OriginalModelField(annotation=annotation, field_info=field_info) + + if field_info.default is not PydanticUndefined and is_optional(annotation): + annotation = annotation | None + fields[field_name] = (annotation, field_info) + # Add the output type to the model. - output_type_annotation = Literal[output_type] # type: ignore - output_type_field = Field( - title="type", default=output_type, json_schema_extra={"field_kind": FieldKind.NodeAttribute} + output_type_annotation = Literal[output_type] + + # Field() returns an instance of FieldInfo, but thanks to a pydantic implementation detail, it is _typed_ as Any. + # This cast makes the type annotation match the class's true type. + output_type_field_info = cast( + FieldInfo, + Field(title="type", default=output_type, json_schema_extra={"field_kind": FieldKind.NodeAttribute}), ) + fields["type"] = (output_type_annotation, output_type_field_info) + docstring = cls.__doc__ - cls = create_model( - cls.__qualname__, - __base__=cls, - __module__=cls.__module__, - type=(output_type_annotation, output_type_field), - ) - cls.__doc__ = docstring + new_class = create_model(cls.__qualname__, __base__=cls, __module__=cls.__module__, **fields) + new_class.__doc__ = docstring - InvocationRegistry.register_output(cls) + InvocationRegistry.register_output(new_class) - return cls + return new_class return wrapper diff --git a/invokeai/app/invocations/batch.py b/invokeai/app/invocations/batch.py index 37a89104737..34ecd38f26b 100644 --- a/invokeai/app/invocations/batch.py +++ b/invokeai/app/invocations/batch.py @@ -64,7 +64,6 @@ class ImageBatchInvocation(BaseBatchInvocation): """Create a batched generation, where the workflow is executed once for each image in the batch.""" images: list[ImageField] = InputField( - default=[], min_length=1, description="The images to batch over", ) @@ -120,7 +119,6 @@ class StringBatchInvocation(BaseBatchInvocation): """Create a batched generation, where the workflow is executed once for each string in the batch.""" strings: list[str] = InputField( - default=[], min_length=1, description="The strings to batch over", ) @@ -176,7 +174,6 @@ class IntegerBatchInvocation(BaseBatchInvocation): """Create a batched generation, where the workflow is executed once for each integer in the batch.""" integers: list[int] = InputField( - default=[], min_length=1, description="The integers to batch over", ) @@ -230,7 +227,6 @@ class FloatBatchInvocation(BaseBatchInvocation): """Create a batched generation, where the workflow is executed once for each float in the batch.""" floats: list[float] = InputField( - default=[], min_length=1, description="The floats to batch over", ) diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 36dc31a0a2b..818af79b4ec 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -1710,7 +1710,7 @@ export type components = { * @description The mask image to convert. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Invert * @description Whether to invert the mask. @@ -1966,12 +1966,12 @@ export type components = { * @description The mask tensor to apply. * @default null */ - mask?: components["schemas"]["TensorField"]; + mask?: components["schemas"]["TensorField"] | null; /** * @description The image to apply the mask to. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Invert * @description Whether to invert the mask. @@ -2022,12 +2022,12 @@ export type components = { * @description The image from which to extract the masked region * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The mask defining the region (black=keep, white=discard) * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Invert Mask * @description Whether to invert the mask before applying it @@ -2304,12 +2304,12 @@ export type components = { * @description Latents tensor * @default null */ - latents_a?: components["schemas"]["LatentsField"]; + latents_a?: components["schemas"]["LatentsField"] | null; /** * @description Latents tensor * @default null */ - latents_b?: components["schemas"]["LatentsField"]; + latents_b?: components["schemas"]["LatentsField"] | null; /** * @description Mask for blending in latents B * @default null @@ -3203,7 +3203,7 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip?: components["schemas"]["CLIPField"]; + clip?: components["schemas"]["CLIPField"] | null; /** * Skipped Layers * @description Number of layers to skip in text encoder @@ -3352,7 +3352,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default infill_cv2 @@ -3657,7 +3657,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Low Threshold * @description The low threshold of the Canny pixel gradient (0-255) @@ -3713,17 +3713,17 @@ export type components = { * @description The source image * @default null */ - source_image?: components["schemas"]["ImageField"]; + source_image?: components["schemas"]["ImageField"] | null; /** * @description The target image * @default null */ - target_image?: components["schemas"]["ImageField"]; + target_image?: components["schemas"]["ImageField"] | null; /** * @description The mask to use when pasting * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Mask Blur * @description The amount to blur the mask by @@ -3778,12 +3778,12 @@ export type components = { * @description The image to apply the mask to * @default null */ - generated_image?: components["schemas"]["ImageField"]; + generated_image?: components["schemas"]["ImageField"] | null; /** * @description The mask to apply * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Mask Blur * @description The amount to blur the mask by @@ -3823,7 +3823,7 @@ export type components = { * @description The image to crop * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Left * @description Number of pixels to pad/crop from the left (negative values crop inwards, positive values pad outwards) @@ -3968,17 +3968,17 @@ export type components = { * @description CogView4 model (Transformer) to load * @default null */ - transformer?: components["schemas"]["TransformerField"]; + transformer?: components["schemas"]["TransformerField"] | null; /** * @description Positive conditioning tensor * @default null */ - positive_conditioning?: components["schemas"]["CogView4ConditioningField"]; + positive_conditioning?: components["schemas"]["CogView4ConditioningField"] | null; /** * @description Negative conditioning tensor * @default null */ - negative_conditioning?: components["schemas"]["CogView4ConditioningField"]; + negative_conditioning?: components["schemas"]["CogView4ConditioningField"] | null; /** * CFG Scale * @description Classifier-Free Guidance scale @@ -4052,12 +4052,12 @@ export type components = { * @description The image to encode. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default cogview4_i2l @@ -4101,12 +4101,12 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default cogview4_l2i @@ -4199,13 +4199,13 @@ export type components = { * @description Text prompt to encode. * @default null */ - prompt?: string; + prompt?: string | null; /** * GLM Encoder * @description GLM (THUDM) tokenizer and text encoder * @default null */ - glm_encoder?: components["schemas"]["GlmEncoderField"]; + glm_encoder?: components["schemas"]["GlmEncoderField"] | null; /** * type * @default cogview4_text_encoder @@ -4322,12 +4322,12 @@ export type components = { * @description The image to color-correct * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description Reference image for color-correction * @default null */ - reference?: components["schemas"]["ImageField"]; + reference?: components["schemas"]["ImageField"] | null; /** * @description Mask to use when applying color-correction * @default null @@ -4447,7 +4447,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Tile Size * @description Tile size @@ -4508,7 +4508,7 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip?: components["schemas"]["CLIPField"]; + clip?: components["schemas"]["CLIPField"] | null; /** * @description A mask defining the region that this conditioning prompt applies to. * @default null @@ -4615,7 +4615,7 @@ export type components = { * @description Conditioning tensor * @default null */ - conditioning?: components["schemas"]["ConditioningField"]; + conditioning?: components["schemas"]["ConditioningField"] | null; /** * type * @default conditioning @@ -4673,7 +4673,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Scale Factor * @description The scale factor used for the shuffle @@ -5116,12 +5116,12 @@ export type components = { * @description The control image * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description ControlNet model to load * @default null */ - control_model?: components["schemas"]["ModelIdentifierField"]; + control_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Control Weight * @description The weight given to the ControlNet @@ -5477,7 +5477,7 @@ export type components = { * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * @description Image which will be masked * @default null @@ -5487,7 +5487,7 @@ export type components = { * @description The mask to use when pasting * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Tiled * @description Processing using overlapping tiles (reduce memory consumption) @@ -5533,7 +5533,7 @@ export type components = { * @description Image which will be masked * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Edge Radius * @description How far to blur/expand the edges of the mask @@ -5625,7 +5625,7 @@ export type components = { * @description The image to crop * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The bounding box to crop the image to * @default null @@ -5665,31 +5665,31 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * X * @description The left x coordinate (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space. * @default null */ - x?: number; + x?: number | null; /** * Y * @description The top y coordinate (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space. * @default null */ - y?: number; + y?: number | null; /** * Width * @description The width (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space. * @default null */ - width?: number; + width?: number | null; /** * Height * @description The height (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space. * @default null */ - height?: number; + height?: number | null; /** * type * @default crop_latents @@ -5751,12 +5751,12 @@ export type components = { * @description The image to inpaint * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The mask to use when inpainting * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * type * @default cv_inpaint @@ -5800,7 +5800,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Draw Body * @default true @@ -5873,13 +5873,13 @@ export type components = { * @description Positive conditioning tensor * @default null */ - positive_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][]; + positive_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][] | null; /** * Negative Conditioning * @description Negative conditioning tensor * @default null */ - negative_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][]; + negative_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][] | null; /** * @description Noise tensor * @default null @@ -5921,7 +5921,7 @@ export type components = { * @description UNet (scheduler, LoRAs) * @default null */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * Control * @default null @@ -5991,13 +5991,13 @@ export type components = { * @description Positive conditioning tensor * @default null */ - positive_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][]; + positive_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][] | null; /** * Negative Conditioning * @description Negative conditioning tensor * @default null */ - negative_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][]; + negative_conditioning?: components["schemas"]["ConditioningField"] | components["schemas"]["ConditioningField"][] | null; /** * @description Noise tensor * @default null @@ -6039,7 +6039,7 @@ export type components = { * @description UNet (scheduler, LoRAs) * @default null */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * Control * @default null @@ -6153,7 +6153,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Model Size * @description The size of the depth model to use @@ -6444,7 +6444,7 @@ export type components = { * @description The prompt to parse with dynamicprompts * @default null */ - prompt?: string; + prompt?: string | null; /** * Max Prompts * @description The number of prompts to generate @@ -6507,7 +6507,7 @@ export type components = { * @description The input image * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Model Name * @description The Real-ESRGAN model to use @@ -6612,7 +6612,7 @@ export type components = { * @description The mask to expand * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Threshold * @description The threshold for the binary mask (0-255) @@ -6728,7 +6728,7 @@ export type components = { * @description Image to face detect * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Minimum Confidence * @description Minimum confidence for face detection (lower if detection is failing) @@ -6779,7 +6779,7 @@ export type components = { * @description Image to face detect * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Face Ids * @description Comma-separated list of face ids to mask eg '0,2,7'. Numbered from 0. Leave empty to mask all. Find face IDs with FaceIdentifier node. @@ -6880,7 +6880,7 @@ export type components = { * @description Image for face detection * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Face Id * @description The face ID to process, numbered from 0. Multiple faces not supported. Find a face's ID with FaceIdentifier node. @@ -7029,9 +7029,9 @@ export type components = { /** * Floats * @description The floats to batch over - * @default [] + * @default null */ - floats?: number[]; + floats?: number[] | null; /** * type * @default float_batch @@ -7396,12 +7396,12 @@ export type components = { * @description Control LoRA model to load * @default null */ - lora?: components["schemas"]["ModelIdentifierField"]; + lora?: components["schemas"]["ModelIdentifierField"] | null; /** * @description The image to encode. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Weight * @description The weight of the LoRA. @@ -7497,12 +7497,12 @@ export type components = { * @description The control image * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description ControlNet model to load * @default null */ - control_model?: components["schemas"]["ModelIdentifierField"]; + control_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Control Weight * @description The weight given to the ControlNet @@ -7620,7 +7620,7 @@ export type components = { * @description Flux model (Transformer) to load * @default null */ - transformer?: components["schemas"]["TransformerField"]; + transformer?: components["schemas"]["TransformerField"] | null; /** * Control LoRA * @description Control LoRA model to load @@ -7632,7 +7632,7 @@ export type components = { * @description Positive conditioning tensor * @default null */ - positive_text_conditioning?: components["schemas"]["FluxConditioningField"] | components["schemas"]["FluxConditioningField"][]; + positive_text_conditioning?: components["schemas"]["FluxConditioningField"] | components["schemas"]["FluxConditioningField"][] | null; /** * Negative Text Conditioning * @description Negative conditioning tensor. Can be None if cfg_scale is 1.0. @@ -7787,7 +7787,7 @@ export type components = { * @description Flux model (Transformer) to load * @default null */ - transformer?: components["schemas"]["TransformerField"]; + transformer?: components["schemas"]["TransformerField"] | null; /** * Control LoRA * @description Control LoRA model to load @@ -7799,7 +7799,7 @@ export type components = { * @description Positive conditioning tensor * @default null */ - positive_text_conditioning?: components["schemas"]["FluxConditioningField"] | components["schemas"]["FluxConditioningField"][]; + positive_text_conditioning?: components["schemas"]["FluxConditioningField"] | components["schemas"]["FluxConditioningField"][] | null; /** * Negative Text Conditioning * @description Negative conditioning tensor. Can be None if cfg_scale is 1.0. @@ -7925,12 +7925,12 @@ export type components = { * @description The FLUX Fill reference image. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The bool inpainting mask. Excluded regions should be set to False, included regions should be set to True. * @default null */ - mask?: components["schemas"]["TensorField"]; + mask?: components["schemas"]["TensorField"] | null; /** * type * @default flux_fill @@ -7981,13 +7981,13 @@ export type components = { * @description The IP-Adapter image prompt(s). * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * IP-Adapter Model * @description The IP-Adapter model. * @default null */ - ip_adapter_model?: components["schemas"]["ModelIdentifierField"]; + ip_adapter_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Clip Vision Model * @description CLIP Vision model to use. @@ -8047,7 +8047,7 @@ export type components = { * @description LoRA model to load * @default null */ - lora?: components["schemas"]["ModelIdentifierField"]; + lora?: components["schemas"]["ModelIdentifierField"] | null; /** * Weight * @description The weight at which the LoRA is applied to each model @@ -8148,7 +8148,7 @@ export type components = { * @description VAE model to load * @default null */ - vae_model?: components["schemas"]["ModelIdentifierField"]; + vae_model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default flux_model_loader @@ -8312,7 +8312,7 @@ export type components = { * @description The FLUX Redux image prompt. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The bool mask associated with this FLUX Redux image prompt. Excluded regions should be set to False, included regions should be set to True. * @default null @@ -8323,7 +8323,7 @@ export type components = { * @description The FLUX Redux model to use. * @default null */ - redux_model?: components["schemas"]["ModelIdentifierField"]; + redux_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Downsampling Factor * @description Redux Downsampling Factor (1-9) @@ -8394,26 +8394,25 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip?: components["schemas"]["CLIPField"]; + clip?: components["schemas"]["CLIPField"] | null; /** * T5Encoder * @description T5 tokenizer and text encoder * @default null */ - t5_encoder?: components["schemas"]["T5EncoderField"]; + t5_encoder?: components["schemas"]["T5EncoderField"] | null; /** * T5 Max Seq Len * @description Max sequence length for the T5 encoder. Expected to be 256 for FLUX schnell models and 512 for FLUX dev models. * @default null - * @enum {integer} */ - t5_max_seq_len?: 256 | 512; + t5_max_seq_len?: (256 | 512) | null; /** * Prompt * @description Text prompt to encode. * @default null */ - prompt?: string; + prompt?: string | null; /** * @description A mask defining the region that this conditioning prompt applies to. * @default null @@ -8462,12 +8461,12 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default flux_vae_decode @@ -8501,12 +8500,12 @@ export type components = { * @description The image to encode. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default flux_vae_encode @@ -8586,7 +8585,7 @@ export type components = { * @description UNet (scheduler, LoRAs) * @default null */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * B1 * @description Scaling factor for stage 1 to amplify the contributions of backbone features. @@ -8644,7 +8643,7 @@ export type components = { * @description The mask to crop. * @default null */ - mask?: components["schemas"]["ImageField"]; + mask?: components["schemas"]["ImageField"] | null; /** * Margin * @description Margin to add to the bounding box. @@ -8790,20 +8789,19 @@ export type components = { * Model * @description The Grounding DINO model to use. * @default null - * @enum {string} */ - model?: "grounding-dino-tiny" | "grounding-dino-base"; + model?: ("grounding-dino-tiny" | "grounding-dino-base") | null; /** * Prompt * @description The prompt describing the object to segment. * @default null */ - prompt?: string; + prompt?: string | null; /** * @description The image to segment. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Detection Threshold * @description The detection threshold for the Grounding DINO model. All detected bounding boxes with scores above this threshold will be returned. @@ -8853,7 +8851,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Scribble * @description Whether or not to use scribble mode @@ -8924,7 +8922,7 @@ export type components = { * @description The image to resize * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Width * @description The width to resize to (px) @@ -9146,13 +9144,13 @@ export type components = { * @description The IP-Adapter image prompt(s). * @default null */ - image?: components["schemas"]["ImageField"] | components["schemas"]["ImageField"][]; + image?: components["schemas"]["ImageField"] | components["schemas"]["ImageField"][] | null; /** * IP-Adapter Model * @description The IP-Adapter model. * @default null */ - ip_adapter_model?: components["schemas"]["ModelIdentifierField"]; + ip_adapter_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Clip Vision Model * @description CLIP Vision model to use. Overrides model settings. Mandatory for checkpoint models. @@ -9367,7 +9365,7 @@ export type components = { * @description UNet (scheduler, LoRAs) * @default null */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * Multiplier * @description Amount to multiply the model's dimensions by when calculating the ideal size (may result in initial generation artifacts if too large) @@ -9435,9 +9433,9 @@ export type components = { /** * Images * @description The images to batch over - * @default [] + * @default null */ - images?: components["schemas"]["ImageField"][]; + images?: components["schemas"]["ImageField"][] | null; /** * type * @default image_batch @@ -9481,7 +9479,7 @@ export type components = { * @description The image to blur * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Radius * @description The blur radius @@ -9550,7 +9548,7 @@ export type components = { * @description The image to get the channel from * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Channel * @description The channel to get @@ -9601,14 +9599,13 @@ export type components = { * @description The image to adjust * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Channel * @description Which channel to adjust * @default null - * @enum {string} */ - channel?: "Red (RGBA)" | "Green (RGBA)" | "Blue (RGBA)" | "Alpha (RGBA)" | "Cyan (CMYK)" | "Magenta (CMYK)" | "Yellow (CMYK)" | "Black (CMYK)" | "Hue (HSV)" | "Saturation (HSV)" | "Value (HSV)" | "Luminosity (LAB)" | "A (LAB)" | "B (LAB)" | "Y (YCbCr)" | "Cb (YCbCr)" | "Cr (YCbCr)"; + channel?: ("Red (RGBA)" | "Green (RGBA)" | "Blue (RGBA)" | "Alpha (RGBA)" | "Cyan (CMYK)" | "Magenta (CMYK)" | "Yellow (CMYK)" | "Black (CMYK)" | "Hue (HSV)" | "Saturation (HSV)" | "Value (HSV)" | "Luminosity (LAB)" | "A (LAB)" | "B (LAB)" | "Y (YCbCr)" | "Cb (YCbCr)" | "Cr (YCbCr)") | null; /** * Scale * @description The amount to scale the channel by. @@ -9664,14 +9661,13 @@ export type components = { * @description The image to adjust * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Channel * @description Which channel to adjust * @default null - * @enum {string} */ - channel?: "Red (RGBA)" | "Green (RGBA)" | "Blue (RGBA)" | "Alpha (RGBA)" | "Cyan (CMYK)" | "Magenta (CMYK)" | "Yellow (CMYK)" | "Black (CMYK)" | "Hue (HSV)" | "Saturation (HSV)" | "Value (HSV)" | "Luminosity (LAB)" | "A (LAB)" | "B (LAB)" | "Y (YCbCr)" | "Cb (YCbCr)" | "Cr (YCbCr)"; + channel?: ("Red (RGBA)" | "Green (RGBA)" | "Blue (RGBA)" | "Alpha (RGBA)" | "Cyan (CMYK)" | "Magenta (CMYK)" | "Yellow (CMYK)" | "Black (CMYK)" | "Hue (HSV)" | "Saturation (HSV)" | "Value (HSV)" | "Luminosity (LAB)" | "A (LAB)" | "B (LAB)" | "Y (YCbCr)" | "Cb (YCbCr)" | "Cr (YCbCr)") | null; /** * Offset * @description The amount to adjust the channel by @@ -9712,7 +9708,7 @@ export type components = { * @description The collection of image values * @default null */ - collection?: components["schemas"]["ImageField"][]; + collection?: components["schemas"]["ImageField"][] | null; /** * type * @default image_collection @@ -9773,7 +9769,7 @@ export type components = { * @description The image to convert * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Mode * @description The mode to convert to @@ -9824,7 +9820,7 @@ export type components = { * @description The image to crop * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * X * @description The left x coordinate of the crop rectangle @@ -10036,7 +10032,7 @@ export type components = { * @description The image to adjust * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Hue * @description The degrees by which to rotate the hue, 0-360 @@ -10086,7 +10082,7 @@ export type components = { * @description The image to lerp * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Min * @description The minimum input value @@ -10132,7 +10128,7 @@ export type components = { * @description The image to load * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default image @@ -10176,7 +10172,7 @@ export type components = { * @description The image to lerp * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Min * @description The minimum output value @@ -10227,7 +10223,7 @@ export type components = { * @description The mask image to convert. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Cutoff * @description Cutoff (<) @@ -10283,12 +10279,12 @@ export type components = { * @description The first image to multiply * @default null */ - image1?: components["schemas"]["ImageField"]; + image1?: components["schemas"]["ImageField"] | null; /** * @description The second image to multiply * @default null */ - image2?: components["schemas"]["ImageField"]; + image2?: components["schemas"]["ImageField"] | null; /** * type * @default img_mul @@ -10332,7 +10328,7 @@ export type components = { * @description The image to check * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default img_nsfw @@ -10376,7 +10372,7 @@ export type components = { * @description The image to add noise to * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Seed * @description Seed for random number generation @@ -10496,13 +10492,13 @@ export type components = { * @description The width of the entire grid. * @default null */ - width?: number; + width?: number | null; /** * Height * @description The height of the entire grid. * @default null */ - height?: number; + height?: number | null; /** * Num Cols * @description The number of columns in the grid. @@ -10570,12 +10566,12 @@ export type components = { * @description The base image * @default null */ - base_image?: components["schemas"]["ImageField"]; + base_image?: components["schemas"]["ImageField"] | null; /** * @description The image to paste * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The mask to use when pasting * @default null @@ -10673,7 +10669,7 @@ export type components = { * @description The image to resize * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Width * @description The width to resize to (px) @@ -10736,7 +10732,7 @@ export type components = { * @description The image to scale * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Scale Factor * @description The factor by which to scale the image @@ -10783,12 +10779,12 @@ export type components = { * @description The image to encode * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * Tiled * @description Processing using overlapping tiles (reduce memory consumption) @@ -10881,7 +10877,7 @@ export type components = { * @description The image to check * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Text * @description Watermark text @@ -10952,7 +10948,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The color to use to infill * @default { @@ -11006,7 +11002,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Downscale * @description Run patchmatch on downscaled image to speedup infill @@ -11063,7 +11059,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Tile Size * @description The tile size (px) @@ -11172,9 +11168,9 @@ export type components = { /** * Integers * @description The integers to batch over - * @default [] + * @default null */ - integers?: number[]; + integers?: number[] | null; /** * type * @default integer_batch @@ -11410,7 +11406,7 @@ export type components = { * @description The tensor mask to convert. * @default null */ - mask?: components["schemas"]["TensorField"]; + mask?: components["schemas"]["TensorField"] | null; /** * type * @default invert_tensor_mask @@ -12378,7 +12374,7 @@ export type components = { * @description The image to adjust * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Space * @description Color space in which to rotate hue by polar coords (*: non-invertible) @@ -12453,7 +12449,7 @@ export type components = { * @description Image from which to get channel * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default invokeai_ealightness @@ -12497,7 +12493,7 @@ export type components = { * @description The top image to blend * @default null */ - layer_upper?: components["schemas"]["ImageField"]; + layer_upper?: components["schemas"]["ImageField"] | null; /** * Blend Mode * @description Available blend modes @@ -12532,7 +12528,7 @@ export type components = { * @description The bottom image to blend * @default null */ - layer_base?: components["schemas"]["ImageField"]; + layer_base?: components["schemas"]["ImageField"] | null; /** * Color Space * @description Available color spaces for blend computations @@ -12595,12 +12591,12 @@ export type components = { * @description Image of the subject on a plain monochrome background * @default null */ - image_subject?: components["schemas"]["ImageField"]; + image_subject?: components["schemas"]["ImageField"] | null; /** * @description Image of a background scene * @default null */ - image_background?: components["schemas"]["ImageField"]; + image_background?: components["schemas"]["ImageField"] | null; /** * Chroma Key * @description Can be empty for corner flood select, or CSS-3 color or tuple @@ -12675,7 +12671,7 @@ export type components = { * @description The image from which to create a mask * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Lightness Only * @description If true, only applies to image lightness (CIELa*b*) @@ -12744,7 +12740,7 @@ export type components = { * @description The image for which to apply processing * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Invert * @description Whether to invert the image colors @@ -12818,7 +12814,7 @@ export type components = { * @description The image from which to create a mask * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Invert Output * @description Make light areas dark and vice versa @@ -12961,7 +12957,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default infill_lama @@ -12996,7 +12992,7 @@ export type components = { * @description The collection of latents tensors * @default null */ - collection?: components["schemas"]["LatentsField"][]; + collection?: components["schemas"]["LatentsField"][] | null; /** * type * @default latents_collection @@ -13064,7 +13060,7 @@ export type components = { * @description The latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * type * @default latents @@ -13158,12 +13154,12 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * Tiled * @description Processing using overlapping tiles (reduce memory consumption) @@ -13225,7 +13221,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default lineart_anime_edge_detection @@ -13269,7 +13265,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Coarse * @description Whether to use coarse mode @@ -13403,7 +13399,7 @@ export type components = { * @description The VLLM model to use * @default null */ - vllm_model?: components["schemas"]["ModelIdentifierField"]; + vllm_model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default llava_onevision_vllm @@ -13579,7 +13575,7 @@ export type components = { * @description LoRA model to load * @default null */ - lora?: components["schemas"]["ModelIdentifierField"]; + lora?: components["schemas"]["ModelIdentifierField"] | null; /** * Weight * @description The weight at which the LoRA is applied to each model @@ -13753,7 +13749,7 @@ export type components = { * @description LoRA model to load * @default null */ - lora?: components["schemas"]["ModelIdentifierField"]; + lora?: components["schemas"]["ModelIdentifierField"] | null; /** * Weight * @description The weight at which the LoRA is applied to each model @@ -13885,7 +13881,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Score Threshold * @description The threshold used to score points when determining line segments @@ -14397,7 +14393,7 @@ export type components = { * @description Main model (UNet, VAE, CLIP) to load * @default null */ - model?: components["schemas"]["ModelIdentifierField"]; + model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default main_model_loader @@ -14441,12 +14437,12 @@ export type components = { * @description The first mask to combine * @default null */ - mask1?: components["schemas"]["ImageField"]; + mask1?: components["schemas"]["ImageField"] | null; /** * @description The second image to combine * @default null */ - mask2?: components["schemas"]["ImageField"]; + mask2?: components["schemas"]["ImageField"] | null; /** * type * @default mask_combine @@ -14490,31 +14486,31 @@ export type components = { * @description The image to apply the mask to * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Edge Size * @description The size of the edge * @default null */ - edge_size?: number; + edge_size?: number | null; /** * Edge Blur * @description The amount of blur on the edge * @default null */ - edge_blur?: number; + edge_blur?: number | null; /** * Low Threshold * @description First threshold for the hysteresis procedure in Canny edge detection * @default null */ - low_threshold?: number; + low_threshold?: number | null; /** * High Threshold * @description Second threshold for the hysteresis procedure in Canny edge detection * @default null */ - high_threshold?: number; + high_threshold?: number | null; /** * type * @default mask_edge @@ -14558,7 +14554,7 @@ export type components = { * @description The image to create the mask from * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Invert * @description Whether or not to invert the mask @@ -14608,12 +14604,12 @@ export type components = { * @description The image to create the mask from * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description ID color to mask * @default null */ - color?: components["schemas"]["ColorField"]; + color?: components["schemas"]["ColorField"] | null; /** * Threshold * @description Threshold for color detection @@ -14693,7 +14689,7 @@ export type components = { * @description The mask tensor to convert. * @default null */ - mask?: components["schemas"]["TensorField"]; + mask?: components["schemas"]["TensorField"] | null; /** * type * @default tensor_mask_to_image @@ -14737,7 +14733,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Max Faces * @description Maximum number of faces to detect @@ -14784,7 +14780,7 @@ export type components = { * @description Collection of Metadata * @default null */ - collection?: components["schemas"]["MetadataField"][]; + collection?: components["schemas"]["MetadataField"][] | null; /** * type * @default merge_metadata @@ -14829,7 +14825,7 @@ export type components = { * @description A list of tile images with tile properties. * @default null */ - tiles_with_images?: components["schemas"]["TileWithImage"][]; + tiles_with_images?: components["schemas"]["TileWithImage"][] | null; /** * Blend Mode * @description blending type Linear or Seam @@ -14883,13 +14879,13 @@ export type components = { * @description The image to extract metadata from * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Key * @description The key in the image's metadata to extract the value from * @default null */ - key?: string; + key?: string | null; /** * type * @default metadata_field_extractor @@ -14923,7 +14919,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default metadata_from_image @@ -14958,7 +14954,7 @@ export type components = { * @description A single metadata item or collection of metadata items * @default null */ - items?: components["schemas"]["MetadataItemField"][] | components["schemas"]["MetadataItemField"]; + items?: components["schemas"]["MetadataItemField"][] | components["schemas"]["MetadataItemField"] | null; /** * type * @default metadata @@ -15006,13 +15002,13 @@ export type components = { * @description Label for this metadata item * @default null */ - label?: string; + label?: string | null; /** * Value * @description The value for this metadata item (may be any type) * @default null */ - value?: unknown; + value?: unknown | null; /** * type * @default metadata_item @@ -15065,7 +15061,7 @@ export type components = { * @description The value for this metadata item (may be any type) * @default null */ - value?: unknown; + value?: unknown | null; /** * type * @default metadata_item_linked @@ -15143,7 +15139,7 @@ export type components = { * @description The default bool to use if not found in the metadata * @default null */ - default_value?: boolean[]; + default_value?: boolean[] | null; /** * type * @default metadata_to_bool_collection @@ -15196,7 +15192,7 @@ export type components = { * @description The default bool to use if not found in the metadata * @default null */ - default_value?: boolean; + default_value?: boolean | null; /** * type * @default metadata_to_bool @@ -15288,7 +15284,7 @@ export type components = { * @description The default float to use if not found in the metadata * @default null */ - default_value?: number[]; + default_value?: number[] | null; /** * type * @default metadata_to_float_collection @@ -15341,7 +15337,7 @@ export type components = { * @description The default float to use if not found in the metadata * @default null */ - default_value?: number; + default_value?: number | null; /** * type * @default metadata_to_float @@ -15434,7 +15430,7 @@ export type components = { * @description The default integer to use if not found in the metadata * @default null */ - default_value?: number[]; + default_value?: number[] | null; /** * type * @default metadata_to_integer_collection @@ -15487,7 +15483,7 @@ export type components = { * @description The default integer to use if not found in the metadata * @default null */ - default_value?: number; + default_value?: number | null; /** * type * @default metadata_to_integer @@ -15648,7 +15644,7 @@ export type components = { * @description The default model to use if not found in the metadata * @default null */ - default_value?: components["schemas"]["ModelIdentifierField"]; + default_value?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default metadata_to_model @@ -15789,7 +15785,7 @@ export type components = { * @description The default SDXL Model to use if not found in the metadata * @default null */ - default_value?: components["schemas"]["ModelIdentifierField"]; + default_value?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default metadata_to_sdxl_model @@ -15938,7 +15934,7 @@ export type components = { * @description The default string collection to use if not found in the metadata * @default null */ - default_value?: string[]; + default_value?: string[] | null; /** * type * @default metadata_to_string_collection @@ -15991,7 +15987,7 @@ export type components = { * @description The default string to use if not found in the metadata * @default null */ - default_value?: string; + default_value?: string | null; /** * type * @default metadata_to_string @@ -16083,7 +16079,7 @@ export type components = { * @description The default VAE to use if not found in the metadata * @default null */ - default_value?: components["schemas"]["VAEField"]; + default_value?: components["schemas"]["VAEField"] | null; /** * type * @default metadata_to_vae @@ -16153,7 +16149,7 @@ export type components = { * @description The model to select * @default null */ - model?: components["schemas"]["ModelIdentifierField"]; + model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default model_identifier @@ -16823,7 +16819,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default normal_map @@ -16944,12 +16940,12 @@ export type components = { * @description The tile image. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description The tile properties. * @default null */ - tile?: components["schemas"]["Tile"]; + tile?: components["schemas"]["Tile"] | null; /** * type * @default pair_tile_image @@ -17006,17 +17002,17 @@ export type components = { * @description The image to paste * @default null */ - source_image?: components["schemas"]["ImageField"]; + source_image?: components["schemas"]["ImageField"] | null; /** * @description The image to paste into * @default null */ - target_image?: components["schemas"]["ImageField"]; + target_image?: components["schemas"]["ImageField"] | null; /** * @description The bounding box to paste the image into * @default null */ - bounding_box?: components["schemas"]["BoundingBoxField"]; + bounding_box?: components["schemas"]["BoundingBoxField"] | null; /** * type * @default paste_image_into_bounding_box @@ -17060,7 +17056,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Quantize Edges * @description Whether or not to use safe mode @@ -17146,7 +17142,7 @@ export type components = { * @description Path to prompt text file * @default null */ - file_path?: string; + file_path?: string | null; /** * Pre Prompt * @description String to prepend to each prompt @@ -17594,37 +17590,37 @@ export type components = { * @description The width of the entire mask. * @default null */ - width?: number; + width?: number | null; /** * Height * @description The height of the entire mask. * @default null */ - height?: number; + height?: number | null; /** * X Left * @description The left x-coordinate of the rectangular masked region (inclusive). * @default null */ - x_left?: number; + x_left?: number | null; /** * Y Top * @description The top y-coordinate of the rectangular masked region (inclusive). * @default null */ - y_top?: number; + y_top?: number | null; /** * Rectangle Width * @description The width of the rectangular masked region. * @default null */ - rectangle_width?: number; + rectangle_width?: number | null; /** * Rectangle Height * @description The height of the rectangular masked region. * @default null */ - rectangle_height?: number; + rectangle_height?: number | null; /** * type * @default rectangle_mask @@ -17695,19 +17691,19 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * Width * @description Width of output (px) * @default null */ - width?: number; + width?: number | null; /** * Height * @description Width of output (px) * @default null */ - height?: number; + height?: number | null; /** * Mode * @description Interpolation mode @@ -17904,17 +17900,17 @@ export type components = { * @description SD3 model (MMDiTX) to load * @default null */ - transformer?: components["schemas"]["TransformerField"]; + transformer?: components["schemas"]["TransformerField"] | null; /** * @description Positive conditioning tensor * @default null */ - positive_conditioning?: components["schemas"]["SD3ConditioningField"]; + positive_conditioning?: components["schemas"]["SD3ConditioningField"] | null; /** * @description Negative conditioning tensor * @default null */ - negative_conditioning?: components["schemas"]["SD3ConditioningField"]; + negative_conditioning?: components["schemas"]["SD3ConditioningField"] | null; /** * CFG Scale * @description Classifier-Free Guidance scale @@ -17988,12 +17984,12 @@ export type components = { * @description The image to encode * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default sd3_i2l @@ -18037,12 +18033,12 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * @description VAE * @default null */ - vae?: components["schemas"]["VAEField"]; + vae?: components["schemas"]["VAEField"] | null; /** * type * @default sd3_l2i @@ -18119,13 +18115,13 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip?: components["schemas"]["CLIPField"]; + clip?: components["schemas"]["CLIPField"] | null; /** * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip2?: components["schemas"]["CLIPField"]; + clip2?: components["schemas"]["CLIPField"] | null; /** * @description A mask defining the region that this conditioning prompt applies to. * @default null @@ -18218,7 +18214,7 @@ export type components = { * @description LoRA model to load * @default null */ - lora?: components["schemas"]["ModelIdentifierField"]; + lora?: components["schemas"]["ModelIdentifierField"] | null; /** * Weight * @description The weight at which the LoRA is applied to each model @@ -18306,7 +18302,7 @@ export type components = { * @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load * @default null */ - model?: components["schemas"]["ModelIdentifierField"]; + model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default sdxl_model_loader @@ -18404,7 +18400,7 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip2?: components["schemas"]["CLIPField"]; + clip2?: components["schemas"]["CLIPField"] | null; /** * type * @default sdxl_refiner_compel_prompt @@ -18438,7 +18434,7 @@ export type components = { * @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load * @default null */ - model?: components["schemas"]["ModelIdentifierField"]; + model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default sdxl_refiner_model_loader @@ -18514,7 +18510,7 @@ export type components = { * @description The image to process * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default save_image @@ -18548,13 +18544,13 @@ export type components = { * @description Latents tensor * @default null */ - latents?: components["schemas"]["LatentsField"]; + latents?: components["schemas"]["LatentsField"] | null; /** * Scale Factor * @description The factor by which to scale * @default null */ - scale_factor?: number; + scale_factor?: number | null; /** * Mode * @description Interpolation mode @@ -18751,13 +18747,13 @@ export type components = { * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip_l?: components["schemas"]["CLIPField"]; + clip_l?: components["schemas"]["CLIPField"] | null; /** * CLIP G * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count * @default null */ - clip_g?: components["schemas"]["CLIPField"]; + clip_g?: components["schemas"]["CLIPField"] | null; /** * T5Encoder * @description T5 tokenizer and text encoder @@ -18769,7 +18765,7 @@ export type components = { * @description Text prompt to encode. * @default null */ - prompt?: string; + prompt?: string | null; /** * type * @default sd3_text_encoder @@ -18880,14 +18876,13 @@ export type components = { * Model * @description The Segment Anything model to use. * @default null - * @enum {string} */ - model?: "segment-anything-base" | "segment-anything-large" | "segment-anything-huge"; + model?: ("segment-anything-base" | "segment-anything-large" | "segment-anything-huge") | null; /** * @description The image to segment. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Bounding Boxes * @description The bounding boxes to prompt the SAM model with. @@ -19301,7 +19296,7 @@ export type components = { * @description The image to show * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * type * @default show_image @@ -19426,13 +19421,13 @@ export type components = { * @description The input image * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Image-to-Image Model * @description Image-to-Image model * @default null */ - image_to_image_model?: components["schemas"]["ModelIdentifierField"]; + image_to_image_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Tile Size * @description The tile size for tiled image-to-image. Set to 0 to disable tiling. @@ -19573,13 +19568,13 @@ export type components = { * @description The input image * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Image-to-Image Model * @description Image-to-Image model * @default null */ - image_to_image_model?: components["schemas"]["ModelIdentifierField"]; + image_to_image_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Tile Size * @description The tile size for tiled image-to-image. Set to 0 to disable tiling. @@ -19702,9 +19697,9 @@ export type components = { /** * Strings * @description The strings to batch over - * @default [] + * @default null */ - strings?: string[]; + strings?: string[] | null; /** * type * @default string_batch @@ -20326,13 +20321,13 @@ export type components = { * @description The IP-Adapter image prompt. * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * T2I-Adapter Model * @description The T2I-Adapter model. * @default null */ - t2i_adapter_model?: components["schemas"]["ModelIdentifierField"]; + t2i_adapter_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Weight * @description The weight given to the T2I-Adapter @@ -20793,7 +20788,7 @@ export type components = { * @description The tile to split into properties. * @default null */ - tile?: components["schemas"]["Tile"]; + tile?: components["schemas"]["Tile"] | null; /** * type * @default tile_to_properties @@ -20898,12 +20893,12 @@ export type components = { * @description Positive conditioning tensor * @default null */ - positive_conditioning?: components["schemas"]["ConditioningField"]; + positive_conditioning?: components["schemas"]["ConditioningField"] | null; /** * @description Negative conditioning tensor * @default null */ - negative_conditioning?: components["schemas"]["ConditioningField"]; + negative_conditioning?: components["schemas"]["ConditioningField"] | null; /** * @description Noise tensor * @default null @@ -20968,7 +20963,7 @@ export type components = { * @description UNet (scheduler, LoRAs) * @default null */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * CFG Rescale Multiplier * @description Rescale multiplier for CFG guidance, used for models trained with zero-terminal SNR @@ -21178,7 +21173,7 @@ export type components = { * @description The image to use * @default null */ - image?: components["schemas"]["ImageField"]; + image?: components["schemas"]["ImageField"] | null; /** * Radius * @description Unsharp mask radius @@ -21417,7 +21412,7 @@ export type components = { * @description VAE model to load * @default null */ - vae_model?: components["schemas"]["ModelIdentifierField"]; + vae_model?: components["schemas"]["ModelIdentifierField"] | null; /** * type * @default vae_loader diff --git a/tests/app/invocations/test_is_optional.py b/tests/app/invocations/test_is_optional.py new file mode 100644 index 00000000000..58e2723ba9e --- /dev/null +++ b/tests/app/invocations/test_is_optional.py @@ -0,0 +1,46 @@ +from typing import Any, Literal, Optional, Union + +import pytest +from pydantic import BaseModel + + +class TestModel(BaseModel): + foo: Literal["bar"] = "bar" + + +@pytest.mark.parametrize( + "input_type, expected", + [ + (str, False), + (list[str], False), + (list[dict[str, Any]], False), + (list[None], False), + (list[dict[str, None]], False), + (Any, False), + (True, False), + (False, False), + (Union[str, False], False), + (Union[str, True], False), + (None, False), + (str | None, True), + (Union[str, None], True), + (Optional[str], True), + (str | int | None, True), + (None | str | int, True), + (Union[None, str], True), + (Optional[str], True), + (Optional[int], True), + (Optional[str], True), + (TestModel | None, True), + (Union[TestModel, None], True), + (Optional[TestModel], True), + ], +) +def test_is_optional(input_type: Any, expected: bool) -> None: + """ + Test the is_optional function. + """ + from invokeai.app.invocations.baseinvocation import is_optional + + result = is_optional(input_type) + assert result == expected, f"Expected {expected} but got {result} for input type {input_type}"