2023-10-17 06:23:10 +00:00
|
|
|
from typing import Any, Literal, Optional, Union
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-07-25 14:22:47 +00:00
|
|
|
from invokeai.app.invocations.baseinvocation import (
|
|
|
|
BaseInvocation,
|
|
|
|
BaseInvocationOutput,
|
|
|
|
InvocationContext,
|
feat(nodes): move all invocation metadata (type, title, tags, category) to decorator
All invocation metadata (type, title, tags and category) are now defined in decorators.
The decorators add the `type: Literal["invocation_type"]: "invocation_type"` field to the invocation.
Category is a new invocation metadata, but it is not used by the frontend just yet.
- `@invocation()` decorator for invocations
```py
@invocation(
"sdxl_compel_prompt",
title="SDXL Prompt",
tags=["sdxl", "compel", "prompt"],
category="conditioning",
)
class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase):
...
```
- `@invocation_output()` decorator for invocation outputs
```py
@invocation_output("clip_skip_output")
class ClipSkipInvocationOutput(BaseInvocationOutput):
...
```
- update invocation docs
- add category to decorator
- regen frontend types
2023-08-30 08:35:12 +00:00
|
|
|
invocation,
|
|
|
|
invocation_output,
|
2023-07-25 14:22:47 +00:00
|
|
|
)
|
2023-07-12 15:14:22 +00:00
|
|
|
from invokeai.app.invocations.controlnet_image_processors import ControlField
|
2024-01-13 04:23:06 +00:00
|
|
|
from invokeai.app.invocations.fields import FieldDescriptions, InputField, MetadataField, OutputField, UIType
|
2023-09-28 09:05:32 +00:00
|
|
|
from invokeai.app.invocations.ip_adapter import IPAdapterModelField
|
2023-07-25 14:22:47 +00:00
|
|
|
from invokeai.app.invocations.model import LoRAModelField, MainModelField, VAEModelField
|
2023-09-28 09:05:32 +00:00
|
|
|
from invokeai.app.invocations.primitives import ImageField
|
2023-10-06 09:16:00 +00:00
|
|
|
from invokeai.app.invocations.t2i_adapter import T2IAdapterField
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-08-14 03:23:09 +00:00
|
|
|
from ...version import __version__
|
|
|
|
|
2023-07-27 14:54:01 +00:00
|
|
|
|
2023-10-17 08:42:02 +00:00
|
|
|
class MetadataItemField(BaseModel):
|
|
|
|
label: str = Field(description=FieldDescriptions.metadata_item_label)
|
|
|
|
value: Any = Field(description=FieldDescriptions.metadata_item_value)
|
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
class LoRAMetadataField(BaseModel):
|
|
|
|
"""LoRA Metadata Field"""
|
2023-07-25 14:22:47 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
lora: LoRAModelField = Field(description=FieldDescriptions.lora_model)
|
|
|
|
weight: float = Field(description=FieldDescriptions.lora_weight)
|
2023-07-12 15:14:22 +00:00
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
class IPAdapterMetadataField(BaseModel):
|
|
|
|
"""IP Adapter Field, minus the CLIP Vision Encoder model"""
|
|
|
|
|
2023-09-28 09:05:32 +00:00
|
|
|
image: ImageField = Field(description="The IP-Adapter image prompt.")
|
2023-10-17 06:23:10 +00:00
|
|
|
ip_adapter_model: IPAdapterModelField = Field(
|
|
|
|
description="The IP-Adapter model.",
|
|
|
|
)
|
|
|
|
weight: Union[float, list[float]] = Field(
|
|
|
|
description="The weight given to the IP-Adapter",
|
|
|
|
)
|
2023-10-18 10:36:29 +00:00
|
|
|
begin_step_percent: float = Field(description="When the IP-Adapter is first applied (% of total steps)")
|
|
|
|
end_step_percent: float = Field(description="When the IP-Adapter is last applied (% of total steps)")
|
2023-09-28 09:05:32 +00:00
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
@invocation_output("metadata_item_output")
|
|
|
|
class MetadataItemOutput(BaseInvocationOutput):
|
|
|
|
"""Metadata Item Output"""
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
item: MetadataItemField = OutputField(description="Metadata Item")
|
2023-07-25 14:22:47 +00:00
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
@invocation("metadata_item", title="Metadata Item", tags=["metadata"], category="metadata", version="1.0.0")
|
|
|
|
class MetadataItemInvocation(BaseInvocation):
|
|
|
|
"""Used to create an arbitrary metadata item. Provide "label" and make a connection to "value" to store that data as the value."""
|
2023-07-25 14:22:47 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
label: str = InputField(description=FieldDescriptions.metadata_item_label)
|
|
|
|
value: Any = InputField(description=FieldDescriptions.metadata_item_value, ui_type=UIType.Any)
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
def invoke(self, context: InvocationContext) -> MetadataItemOutput:
|
|
|
|
return MetadataItemOutput(item=MetadataItemField(label=self.label, value=self.value))
|
2023-07-12 15:14:22 +00:00
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
@invocation_output("metadata_output")
|
|
|
|
class MetadataOutput(BaseInvocationOutput):
|
|
|
|
metadata: MetadataField = OutputField(description="Metadata Dict")
|
|
|
|
|
|
|
|
|
|
|
|
@invocation("metadata", title="Metadata", tags=["metadata"], category="metadata", version="1.0.0")
|
|
|
|
class MetadataInvocation(BaseInvocation):
|
|
|
|
"""Takes a MetadataItem or collection of MetadataItems and outputs a MetadataDict."""
|
|
|
|
|
|
|
|
items: Union[list[MetadataItemField], MetadataItemField] = InputField(
|
|
|
|
description=FieldDescriptions.metadata_item_polymorphic
|
2023-07-12 15:14:22 +00:00
|
|
|
)
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
def invoke(self, context: InvocationContext) -> MetadataOutput:
|
|
|
|
if isinstance(self.items, MetadataItemField):
|
|
|
|
# single metadata item
|
|
|
|
data = {self.items.label: self.items.value}
|
|
|
|
else:
|
|
|
|
# collection of metadata items
|
|
|
|
data = {item.label: item.value for item in self.items}
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
# add app version
|
|
|
|
data.update({"app_version": __version__})
|
|
|
|
return MetadataOutput(metadata=MetadataField.model_validate(data))
|
2023-07-12 15:14:22 +00:00
|
|
|
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
@invocation("merge_metadata", title="Metadata Merge", tags=["metadata"], category="metadata", version="1.0.0")
|
|
|
|
class MergeMetadataInvocation(BaseInvocation):
|
|
|
|
"""Merged a collection of MetadataDict into a single MetadataDict."""
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
collection: list[MetadataField] = InputField(description=FieldDescriptions.metadata_collection)
|
|
|
|
|
|
|
|
def invoke(self, context: InvocationContext) -> MetadataOutput:
|
|
|
|
data = {}
|
|
|
|
for item in self.collection:
|
|
|
|
data.update(item.model_dump())
|
2023-07-12 15:14:22 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
return MetadataOutput(metadata=MetadataField.model_validate(data))
|
|
|
|
|
|
|
|
|
2023-10-20 05:22:56 +00:00
|
|
|
GENERATION_MODES = Literal[
|
|
|
|
"txt2img", "img2img", "inpaint", "outpaint", "sdxl_txt2img", "sdxl_img2img", "sdxl_inpaint", "sdxl_outpaint"
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2023-11-16 07:47:31 +00:00
|
|
|
@invocation("core_metadata", title="Core Metadata", tags=["metadata"], category="metadata", version="1.0.1")
|
2023-10-17 06:23:10 +00:00
|
|
|
class CoreMetadataInvocation(BaseInvocation):
|
|
|
|
"""Collects core generation metadata into a MetadataField"""
|
|
|
|
|
2023-10-20 05:22:56 +00:00
|
|
|
generation_mode: Optional[GENERATION_MODES] = InputField(
|
2023-10-14 23:44:16 +00:00
|
|
|
default=None,
|
2023-07-25 14:22:47 +00:00
|
|
|
description="The generation mode that output this image",
|
|
|
|
)
|
2023-10-14 23:44:16 +00:00
|
|
|
positive_prompt: Optional[str] = InputField(default=None, description="The positive prompt parameter")
|
|
|
|
negative_prompt: Optional[str] = InputField(default=None, description="The negative prompt parameter")
|
|
|
|
width: Optional[int] = InputField(default=None, description="The width parameter")
|
|
|
|
height: Optional[int] = InputField(default=None, description="The height parameter")
|
|
|
|
seed: Optional[int] = InputField(default=None, description="The seed used for noise generation")
|
|
|
|
rand_device: Optional[str] = InputField(default=None, description="The device used for random number generation")
|
|
|
|
cfg_scale: Optional[float] = InputField(default=None, description="The classifier-free guidance scale parameter")
|
2023-11-30 09:55:20 +00:00
|
|
|
cfg_rescale_multiplier: Optional[float] = InputField(
|
|
|
|
default=None, description=FieldDescriptions.cfg_rescale_multiplier
|
|
|
|
)
|
2023-10-14 23:44:16 +00:00
|
|
|
steps: Optional[int] = InputField(default=None, description="The number of steps used for inference")
|
|
|
|
scheduler: Optional[str] = InputField(default=None, description="The scheduler used for inference")
|
2023-10-17 06:23:10 +00:00
|
|
|
seamless_x: Optional[bool] = InputField(default=None, description="Whether seamless tiling was used on the X axis")
|
|
|
|
seamless_y: Optional[bool] = InputField(default=None, description="Whether seamless tiling was used on the Y axis")
|
2023-10-14 23:44:16 +00:00
|
|
|
clip_skip: Optional[int] = InputField(
|
2023-09-21 04:54:47 +00:00
|
|
|
default=None,
|
2023-07-25 14:22:47 +00:00
|
|
|
description="The number of skipped CLIP layers",
|
|
|
|
)
|
2023-10-14 23:44:16 +00:00
|
|
|
model: Optional[MainModelField] = InputField(default=None, description="The main model used for inference")
|
|
|
|
controlnets: Optional[list[ControlField]] = InputField(
|
|
|
|
default=None, description="The ControlNets used for inference"
|
|
|
|
)
|
|
|
|
ipAdapters: Optional[list[IPAdapterMetadataField]] = InputField(
|
|
|
|
default=None, description="The IP Adapters used for inference"
|
|
|
|
)
|
|
|
|
t2iAdapters: Optional[list[T2IAdapterField]] = InputField(
|
|
|
|
default=None, description="The IP Adapters used for inference"
|
|
|
|
)
|
|
|
|
loras: Optional[list[LoRAMetadataField]] = InputField(default=None, description="The LoRAs used for inference")
|
2023-08-14 03:23:09 +00:00
|
|
|
strength: Optional[float] = InputField(
|
2023-07-12 15:14:22 +00:00
|
|
|
default=None,
|
|
|
|
description="The strength used for latents-to-latents",
|
|
|
|
)
|
2023-08-14 03:23:09 +00:00
|
|
|
init_image: Optional[str] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The name of the initial image",
|
|
|
|
)
|
|
|
|
vae: Optional[VAEModelField] = InputField(
|
2023-07-12 15:14:22 +00:00
|
|
|
default=None,
|
|
|
|
description="The VAE used for decoding, if the main model's default was not used",
|
|
|
|
)
|
|
|
|
|
2023-10-14 10:34:41 +00:00
|
|
|
# High resolution fix metadata.
|
2023-11-16 07:47:31 +00:00
|
|
|
hrf_enabled: Optional[bool] = InputField(
|
2023-10-14 23:44:16 +00:00
|
|
|
default=None,
|
2023-11-11 00:11:46 +00:00
|
|
|
description="Whether or not high resolution fix was enabled.",
|
2023-10-14 10:34:41 +00:00
|
|
|
)
|
2023-11-11 00:11:46 +00:00
|
|
|
# TODO: should this be stricter or do we just let the UI handle it?
|
|
|
|
hrf_method: Optional[str] = InputField(
|
2023-10-14 23:44:16 +00:00
|
|
|
default=None,
|
2023-11-11 00:11:46 +00:00
|
|
|
description="The high resolution fix upscale method.",
|
2023-10-14 10:34:41 +00:00
|
|
|
)
|
|
|
|
hrf_strength: Optional[float] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The high resolution fix img2img strength used in the upscale pass.",
|
|
|
|
)
|
|
|
|
|
2023-07-25 14:22:47 +00:00
|
|
|
# SDXL
|
2023-08-14 03:23:09 +00:00
|
|
|
positive_style_prompt: Optional[str] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The positive style prompt parameter",
|
|
|
|
)
|
|
|
|
negative_style_prompt: Optional[str] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The negative style prompt parameter",
|
|
|
|
)
|
2023-07-25 14:22:47 +00:00
|
|
|
|
|
|
|
# SDXL Refiner
|
2023-08-14 03:23:09 +00:00
|
|
|
refiner_model: Optional[MainModelField] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The SDXL Refiner model used",
|
|
|
|
)
|
|
|
|
refiner_cfg_scale: Optional[float] = InputField(
|
2023-07-25 14:22:47 +00:00
|
|
|
default=None,
|
|
|
|
description="The classifier-free guidance scale parameter used for the refiner",
|
|
|
|
)
|
2023-08-14 03:23:09 +00:00
|
|
|
refiner_steps: Optional[int] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The number of steps used for the refiner",
|
2023-08-13 16:02:36 +00:00
|
|
|
)
|
2023-08-14 03:23:09 +00:00
|
|
|
refiner_scheduler: Optional[str] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The scheduler used for the refiner",
|
|
|
|
)
|
2023-09-01 06:55:00 +00:00
|
|
|
refiner_positive_aesthetic_score: Optional[float] = InputField(
|
2023-08-14 03:23:09 +00:00
|
|
|
default=None,
|
|
|
|
description="The aesthetic score used for the refiner",
|
|
|
|
)
|
2023-09-01 06:55:00 +00:00
|
|
|
refiner_negative_aesthetic_score: Optional[float] = InputField(
|
2023-08-14 03:23:09 +00:00
|
|
|
default=None,
|
|
|
|
description="The aesthetic score used for the refiner",
|
|
|
|
)
|
|
|
|
refiner_start: Optional[float] = InputField(
|
|
|
|
default=None,
|
|
|
|
description="The start value used for refiner denoising",
|
2023-07-25 14:22:47 +00:00
|
|
|
)
|
2023-07-18 14:26:45 +00:00
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
def invoke(self, context: InvocationContext) -> MetadataOutput:
|
2023-07-12 15:14:22 +00:00
|
|
|
"""Collects and outputs a CoreMetadata object"""
|
|
|
|
|
2023-10-17 06:23:10 +00:00
|
|
|
return MetadataOutput(
|
|
|
|
metadata=MetadataField.model_validate(
|
|
|
|
self.model_dump(exclude_none=True, exclude={"id", "type", "is_intermediate", "use_cache"})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
model_config = ConfigDict(extra="allow")
|