From 8464450a53227eccb29fa83c03ac35e15b2715bd Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 13 Oct 2023 14:44:42 -0400 Subject: [PATCH 001/119] Add support for multi-image IP-Adapter. --- invokeai/app/invocations/ip_adapter.py | 4 ++-- invokeai/app/invocations/latent.py | 9 ++++++-- .../backend/ip_adapter/attention_processor.py | 21 ++++++++++++++++--- .../diffusion/conditioning_data.py | 4 ++-- .../diffusion/shared_invokeai_diffusion.py | 11 +++++++--- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/invokeai/app/invocations/ip_adapter.py b/invokeai/app/invocations/ip_adapter.py index 3e3a3d9b1f..ca35a17060 100644 --- a/invokeai/app/invocations/ip_adapter.py +++ b/invokeai/app/invocations/ip_adapter.py @@ -32,7 +32,7 @@ class CLIPVisionModelField(BaseModel): class IPAdapterField(BaseModel): - image: ImageField = Field(description="The IP-Adapter image prompt.") + image: Union[ImageField, List[ImageField]] = Field(description="The IP-Adapter image prompt(s).") ip_adapter_model: IPAdapterModelField = Field(description="The IP-Adapter model to use.") image_encoder_model: CLIPVisionModelField = Field(description="The name of the CLIP image encoder model.") weight: Union[float, List[float]] = Field(default=1, description="The weight given to the ControlNet") @@ -56,7 +56,7 @@ class IPAdapterInvocation(BaseInvocation): """Collects IP-Adapter info to pass to other nodes.""" # Inputs - image: ImageField = InputField(description="The IP-Adapter image prompt.") + image: Union[ImageField, List[ImageField]] = InputField(description="The IP-Adapter image prompt(s).") ip_adapter_model: IPAdapterModelField = InputField( description="The IP-Adapter model.", title="IP-Adapter Model", input=Input.Direct, ui_order=-1 ) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 7ca8cbbe6c..2e69e4dac5 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -445,14 +445,19 @@ class DenoiseLatentsInvocation(BaseInvocation): context=context, ) - input_image = context.services.images.get_pil_image(single_ip_adapter.image.image_name) + # `single_ip_adapter.image` could be a list or a single ImageField. Normalize to a list here. + single_ipa_images = single_ip_adapter.image + if not isinstance(single_ipa_images, list): + single_ipa_images = [single_ipa_images] + + single_ipa_images = [context.services.images.get_pil_image(image.image_name) for image in single_ipa_images] # TODO(ryand): With some effort, the step of running the CLIP Vision encoder could be done before any other # models are needed in memory. This would help to reduce peak memory utilization in low-memory environments. with image_encoder_model_info as image_encoder_model: # Get image embeddings from CLIP and ImageProjModel. image_prompt_embeds, uncond_image_prompt_embeds = ip_adapter_model.get_image_embeds( - input_image, image_encoder_model + single_ipa_images, image_encoder_model ) conditioning_data.ip_adapter_conditioning.append( IPAdapterConditioningInfo(image_prompt_embeds, uncond_image_prompt_embeds) diff --git a/invokeai/backend/ip_adapter/attention_processor.py b/invokeai/backend/ip_adapter/attention_processor.py index 2873c52322..96ab5f876a 100644 --- a/invokeai/backend/ip_adapter/attention_processor.py +++ b/invokeai/backend/ip_adapter/attention_processor.py @@ -67,6 +67,12 @@ class IPAttnProcessor2_0(torch.nn.Module): temb=None, ip_adapter_image_prompt_embeds=None, ): + """Apply IP-Adapter attention. + + Args: + ip_adapter_image_prompt_embeds (torch.Tensor): The image prompt embeddings. + Shape: (batch_size, num_ip_images, seq_len, ip_embedding_len). + """ residual = hidden_states if attn.spatial_norm is not None: @@ -127,26 +133,35 @@ class IPAttnProcessor2_0(torch.nn.Module): for ipa_embed, ipa_weights, scale in zip(ip_adapter_image_prompt_embeds, self._weights, self._scales): # The batch dimensions should match. assert ipa_embed.shape[0] == encoder_hidden_states.shape[0] - # The channel dimensions should match. - assert ipa_embed.shape[2] == encoder_hidden_states.shape[2] + # The token_len dimensions should match. + assert ipa_embed.shape[-1] == encoder_hidden_states.shape[-1] ip_hidden_states = ipa_embed + # ip_hidden_state.shape = (batch_size, num_ip_images, ip_seq_len, ip_image_embedding) + ip_key = ipa_weights.to_k_ip(ip_hidden_states) ip_value = ipa_weights.to_v_ip(ip_hidden_states) + # ip_key.shape, ip_value.shape: (batch_size, num_ip_images, ip_seq_len, head_dim * num_heads) + ip_key = ip_key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) ip_value = ip_value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) - # The output of sdpa has shape: (batch, num_heads, seq_len, head_dim) + # ip_key.shape, ip_value.shape: (batch_size, num_heads, num_ip_images * ip_seq_len, head_dim) + # TODO: add support for attn.scale when we move to Torch 2.1 ip_hidden_states = F.scaled_dot_product_attention( query, ip_key, ip_value, attn_mask=None, dropout_p=0.0, is_causal=False ) + # ip_hidden_states.shape: (batch_size, num_heads, query_seq_len, head_dim) + ip_hidden_states = ip_hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim) ip_hidden_states = ip_hidden_states.to(query.dtype) + # ip_hidden_states.shape: (batch_size, query_seq_len, num_heads * head_dim) + hidden_states = hidden_states + scale * ip_hidden_states # linear proj diff --git a/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py b/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py index 7c3f835a44..6a63c225fc 100644 --- a/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py +++ b/invokeai/backend/stable_diffusion/diffusion/conditioning_data.py @@ -55,11 +55,11 @@ class PostprocessingSettings: class IPAdapterConditioningInfo: cond_image_prompt_embeds: torch.Tensor """IP-Adapter image encoder conditioning embeddings. - Shape: (batch_size, num_tokens, encoding_dim). + Shape: (num_images, num_tokens, encoding_dim). """ uncond_image_prompt_embeds: torch.Tensor """IP-Adapter image encoding embeddings to use for unconditional generation. - Shape: (batch_size, num_tokens, encoding_dim). + Shape: (num_images, num_tokens, encoding_dim). """ diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index c12c86ed92..943fe7b307 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -345,9 +345,12 @@ class InvokeAIDiffuserComponent: cross_attention_kwargs = None if conditioning_data.ip_adapter_conditioning is not None: + # Note that we 'stack' to produce tensors of shape (batch_size, num_ip_images, seq_len, token_len). cross_attention_kwargs = { "ip_adapter_image_prompt_embeds": [ - torch.cat([ipa_conditioning.uncond_image_prompt_embeds, ipa_conditioning.cond_image_prompt_embeds]) + torch.stack( + [ipa_conditioning.uncond_image_prompt_embeds, ipa_conditioning.cond_image_prompt_embeds] + ) for ipa_conditioning in conditioning_data.ip_adapter_conditioning ] } @@ -415,9 +418,10 @@ class InvokeAIDiffuserComponent: # Run unconditional UNet denoising. cross_attention_kwargs = None if conditioning_data.ip_adapter_conditioning is not None: + # Note that we 'unsqueeze' to produce tensors of shape (batch_size=1, num_ip_images, seq_len, token_len). cross_attention_kwargs = { "ip_adapter_image_prompt_embeds": [ - ipa_conditioning.uncond_image_prompt_embeds + torch.unsqueeze(ipa_conditioning.uncond_image_prompt_embeds, dim=0) for ipa_conditioning in conditioning_data.ip_adapter_conditioning ] } @@ -444,9 +448,10 @@ class InvokeAIDiffuserComponent: # Run conditional UNet denoising. cross_attention_kwargs = None if conditioning_data.ip_adapter_conditioning is not None: + # Note that we 'unsqueeze' to produce tensors of shape (batch_size=1, num_ip_images, seq_len, token_len). cross_attention_kwargs = { "ip_adapter_image_prompt_embeds": [ - ipa_conditioning.cond_image_prompt_embeds + torch.unsqueeze(ipa_conditioning.cond_image_prompt_embeds, dim=0) for ipa_conditioning in conditioning_data.ip_adapter_conditioning ] } From 49279bbe7416415308dcee7e0b58132f6dc9589e Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Sat, 14 Oct 2023 13:00:52 -0400 Subject: [PATCH 002/119] Update IP-Adapter unit test for multi-image. --- tests/backend/ip_adapter/test_ip_adapter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/backend/ip_adapter/test_ip_adapter.py b/tests/backend/ip_adapter/test_ip_adapter.py index 7f634ee1fe..6712196778 100644 --- a/tests/backend/ip_adapter/test_ip_adapter.py +++ b/tests/backend/ip_adapter/test_ip_adapter.py @@ -65,7 +65,10 @@ def test_ip_adapter_unet_patch(model_params, model_installer, torch_device): ip_adapter.to(torch_device, dtype=torch.float32) unet.to(torch_device, dtype=torch.float32) - cross_attention_kwargs = {"ip_adapter_image_prompt_embeds": [torch.randn((1, 4, 768)).to(torch_device)]} + # ip_embeds shape: (batch_size, num_ip_images, seq_len, ip_image_embedding_len) + ip_embeds = torch.randn((1, 3, 4, 768)).to(torch_device) + + cross_attention_kwargs = {"ip_adapter_image_prompt_embeds": [ip_embeds]} ip_adapter_unet_patcher = UNetPatcher([ip_adapter]) with ip_adapter_unet_patcher.apply_ip_adapter_attention(unet): output = unet(**dummy_unet_input, cross_attention_kwargs=cross_attention_kwargs).sample From 35ebc9e18d7735986998219b3377de5558b8bfe5 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Sat, 14 Oct 2023 13:28:50 -0400 Subject: [PATCH 003/119] Bump invocation versions for the multi-image IP feature. --- invokeai/app/invocations/ip_adapter.py | 2 +- invokeai/app/invocations/latent.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/ip_adapter.py b/invokeai/app/invocations/ip_adapter.py index ca35a17060..15502ad52b 100644 --- a/invokeai/app/invocations/ip_adapter.py +++ b/invokeai/app/invocations/ip_adapter.py @@ -51,7 +51,7 @@ class IPAdapterOutput(BaseInvocationOutput): ip_adapter: IPAdapterField = OutputField(description=FieldDescriptions.ip_adapter, title="IP-Adapter") -@invocation("ip_adapter", title="IP-Adapter", tags=["ip_adapter", "control"], category="ip_adapter", version="1.0.0") +@invocation("ip_adapter", title="IP-Adapter", tags=["ip_adapter", "control"], category="ip_adapter", version="1.1.0") class IPAdapterInvocation(BaseInvocation): """Collects IP-Adapter info to pass to other nodes.""" diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 2e69e4dac5..3b6fd2498f 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -198,7 +198,7 @@ def get_scheduler( title="Denoise Latents", tags=["latents", "denoise", "txt2img", "t2i", "t2l", "img2img", "i2i", "l2l"], category="latents", - version="1.3.0", + version="1.4.0", ) class DenoiseLatentsInvocation(BaseInvocation): """Denoises noisy latents to decodable images""" From 3079c75a60c01f5478f3230a8f74159d347fb1a0 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Mon, 16 Oct 2023 08:35:32 -0400 Subject: [PATCH 004/119] (minor) Make it more clear that shape annotations are just comments and not commented lines of code. --- invokeai/backend/ip_adapter/attention_processor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/invokeai/backend/ip_adapter/attention_processor.py b/invokeai/backend/ip_adapter/attention_processor.py index 96ab5f876a..c06d7d113c 100644 --- a/invokeai/backend/ip_adapter/attention_processor.py +++ b/invokeai/backend/ip_adapter/attention_processor.py @@ -138,29 +138,29 @@ class IPAttnProcessor2_0(torch.nn.Module): ip_hidden_states = ipa_embed - # ip_hidden_state.shape = (batch_size, num_ip_images, ip_seq_len, ip_image_embedding) + # Expected ip_hidden_state shape: (batch_size, num_ip_images, ip_seq_len, ip_image_embedding) ip_key = ipa_weights.to_k_ip(ip_hidden_states) ip_value = ipa_weights.to_v_ip(ip_hidden_states) - # ip_key.shape, ip_value.shape: (batch_size, num_ip_images, ip_seq_len, head_dim * num_heads) + # Expected ip_key and ip_value shape: (batch_size, num_ip_images, ip_seq_len, head_dim * num_heads) ip_key = ip_key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) ip_value = ip_value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) - # ip_key.shape, ip_value.shape: (batch_size, num_heads, num_ip_images * ip_seq_len, head_dim) + # Expected ip_key and ip_value shape: (batch_size, num_heads, num_ip_images * ip_seq_len, head_dim) # TODO: add support for attn.scale when we move to Torch 2.1 ip_hidden_states = F.scaled_dot_product_attention( query, ip_key, ip_value, attn_mask=None, dropout_p=0.0, is_causal=False ) - # ip_hidden_states.shape: (batch_size, num_heads, query_seq_len, head_dim) + # Expected ip_hidden_states shape: (batch_size, num_heads, query_seq_len, head_dim) ip_hidden_states = ip_hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim) ip_hidden_states = ip_hidden_states.to(query.dtype) - # ip_hidden_states.shape: (batch_size, query_seq_len, num_heads * head_dim) + # Expected ip_hidden_states shape: (batch_size, query_seq_len, num_heads * head_dim) hidden_states = hidden_states + scale * ip_hidden_states From 9542883bb5b88e97a66dfe4da60d366238dcfb41 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 28 Sep 2023 09:28:41 -0400 Subject: [PATCH 005/119] update requirements to python 3.10-11 --- docs/installation/010_INSTALL_AUTOMATED.md | 4 ++-- docs/installation/020_INSTALL_MANUAL.md | 4 ++-- docs/installation/060_INSTALL_PATCHMATCH.md | 3 +-- installer/install.bat.in | 13 ++++++------- installer/install.sh.in | 4 ++-- installer/lib/installer.py | 10 +--------- installer/readme.txt | 8 ++++---- pyproject.toml | 2 +- 8 files changed, 19 insertions(+), 29 deletions(-) diff --git a/docs/installation/010_INSTALL_AUTOMATED.md b/docs/installation/010_INSTALL_AUTOMATED.md index 0937c07bca..52192f33c0 100644 --- a/docs/installation/010_INSTALL_AUTOMATED.md +++ b/docs/installation/010_INSTALL_AUTOMATED.md @@ -40,7 +40,7 @@ experimental versions later. this, open up a command-line window ("Terminal" on Linux and Macintosh, "Command" or "Powershell" on Windows) and type `python --version`. If Python is installed, it will print out the version - number. If it is version `3.9.*`, `3.10.*` or `3.11.*` you meet + number. If it is version `3.10.*` or `3.11.*` you meet requirements. !!! warning "What to do if you have an unsupported version" @@ -48,7 +48,7 @@ experimental versions later. Go to [Python Downloads](https://www.python.org/downloads/) and download the appropriate installer package for your platform. We recommend [Version - 3.10.9](https://www.python.org/downloads/release/python-3109/), + 3.10.12](https://www.python.org/downloads/release/python-3109/), which has been extensively tested with InvokeAI. _Please select your platform in the section below for platform-specific diff --git a/docs/installation/020_INSTALL_MANUAL.md b/docs/installation/020_INSTALL_MANUAL.md index a19992d266..27484c0ffd 100644 --- a/docs/installation/020_INSTALL_MANUAL.md +++ b/docs/installation/020_INSTALL_MANUAL.md @@ -32,7 +32,7 @@ gaming): * **Python** - version 3.9 through 3.11 + version 3.10 through 3.11 * **CUDA Tools** @@ -65,7 +65,7 @@ gaming): To install InvokeAI with virtual environments and the PIP package manager, please follow these steps: -1. Please make sure you are using Python 3.9 through 3.11. The rest of the install +1. Please make sure you are using Python 3.10 through 3.11. The rest of the install procedure depends on this and will not work with other versions: ```bash diff --git a/docs/installation/060_INSTALL_PATCHMATCH.md b/docs/installation/060_INSTALL_PATCHMATCH.md index ccfd19d207..a9646f8b60 100644 --- a/docs/installation/060_INSTALL_PATCHMATCH.md +++ b/docs/installation/060_INSTALL_PATCHMATCH.md @@ -59,8 +59,7 @@ Prior to installing PyPatchMatch, you need to take the following steps: `from patchmatch import patch_match`: It should look like the following: ```py - Python 3.9.5 (default, Nov 23 2021, 15:27:38) - [GCC 9.3.0] on linux + Python 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from patchmatch import patch_match Compiling and loading c extensions from "/home/lstein/Projects/InvokeAI/.invokeai-env/src/pypatchmatch/patchmatch". diff --git a/installer/install.bat.in b/installer/install.bat.in index ffe96d4355..5fa76471de 100644 --- a/installer/install.bat.in +++ b/installer/install.bat.in @@ -1,7 +1,7 @@ @echo off setlocal EnableExtensions EnableDelayedExpansion -@rem This script requires the user to install Python 3.9 or higher. All other +@rem This script requires the user to install Python 3.10 or higher. All other @rem requirements are downloaded as needed. @rem change to the script's directory @@ -19,7 +19,7 @@ set INVOKEAI_VERSION=latest set INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ set TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting set PYTHON_URL=https://www.python.org/downloads/windows/ -set MINIMUM_PYTHON_VERSION=3.9.0 +set MINIMUM_PYTHON_VERSION=3.10.0 set PYTHON_URL=https://www.python.org/downloads/release/python-3109/ set err_msg=An error has occurred and the script could not continue. @@ -28,8 +28,7 @@ set err_msg=An error has occurred and the script could not continue. echo This script will install InvokeAI and its dependencies. echo. echo BEFORE YOU START PLEASE MAKE SURE TO DO THE FOLLOWING -echo 1. Install python 3.9 or 3.10. Python version 3.11 and above are -echo not supported at the moment. +echo 1. Install python 3.10 or 3.11. Python version 3.9 is no longer supported. echo 2. Double-click on the file WinLongPathsEnabled.reg in order to echo enable long path support on your system. echo 3. Install the Visual C++ core libraries. @@ -46,19 +45,19 @@ echo ***** Checking and Updating Python ***** call python --version >.tmp1 2>.tmp2 if %errorlevel% == 1 ( - set err_msg=Please install Python 3.10. See %INSTRUCTIONS% for details. + set err_msg=Please install Python 3.10-11. See %INSTRUCTIONS% for details. goto err_exit ) for /f "tokens=2" %%i in (.tmp1) do set python_version=%%i if "%python_version%" == "" ( - set err_msg=No python was detected on your system. Please install Python version %MINIMUM_PYTHON_VERSION% or higher. We recommend Python 3.10.9 from %PYTHON_URL% + set err_msg=No python was detected on your system. Please install Python version %MINIMUM_PYTHON_VERSION% or higher. We recommend Python 3.10.12 from %PYTHON_URL% goto err_exit ) call :compareVersions %MINIMUM_PYTHON_VERSION% %python_version% if %errorlevel% == 1 ( - set err_msg=Your version of Python is too low. You need at least %MINIMUM_PYTHON_VERSION% but you have %python_version%. We recommend Python 3.10.9 from %PYTHON_URL% + set err_msg=Your version of Python is too low. You need at least %MINIMUM_PYTHON_VERSION% but you have %python_version%. We recommend Python 3.10.12 from %PYTHON_URL% goto err_exit ) diff --git a/installer/install.sh.in b/installer/install.sh.in index 1b8ba92ea6..9cf41192bf 100755 --- a/installer/install.sh.in +++ b/installer/install.sh.in @@ -8,10 +8,10 @@ cd $scriptdir function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } -MINIMUM_PYTHON_VERSION=3.9.0 +MINIMUM_PYTHON_VERSION=3.10.0 MAXIMUM_PYTHON_VERSION=3.11.100 PYTHON="" -for candidate in python3.11 python3.10 python3.9 python3 python ; do +for candidate in python3.11 python3.10 python3 python ; do if ppath=`which $candidate`; then # when using `pyenv`, the executable for an inactive Python version will exist but will not be operational # we check that this found executable can actually run diff --git a/installer/lib/installer.py b/installer/lib/installer.py index 70ed4d4331..bf48e3b06d 100644 --- a/installer/lib/installer.py +++ b/installer/lib/installer.py @@ -13,7 +13,7 @@ from pathlib import Path from tempfile import TemporaryDirectory from typing import Union -SUPPORTED_PYTHON = ">=3.9.0,<=3.11.100" +SUPPORTED_PYTHON = ">=3.10.0,<=3.11.100" INSTALLER_REQS = ["rich", "semver", "requests", "plumbum", "prompt-toolkit"] BOOTSTRAP_VENV_PREFIX = "invokeai-installer-tmp" @@ -67,7 +67,6 @@ class Installer: # Cleaning up temporary directories on Windows results in a race condition # and a stack trace. # `ignore_cleanup_errors` was only added in Python 3.10 - # users of Python 3.9 will see a gnarly stack trace on installer exit if OS == "Windows" and int(platform.python_version_tuple()[1]) >= 10: venv_dir = TemporaryDirectory(prefix=BOOTSTRAP_VENV_PREFIX, ignore_cleanup_errors=True) else: @@ -139,13 +138,6 @@ class Installer: except shutil.SameFileError: venv.create(venv_dir, with_pip=True, symlinks=True) - # upgrade pip in Python 3.9 environments - if int(platform.python_version_tuple()[1]) == 9: - from plumbum import FG, local - - pip = local[get_pip_from_venv(venv_dir)] - pip["install", "--upgrade", "pip"] & FG - return venv_dir def install( diff --git a/installer/readme.txt b/installer/readme.txt index b9a97e2093..ef040c3913 100644 --- a/installer/readme.txt +++ b/installer/readme.txt @@ -4,7 +4,7 @@ Project homepage: https://github.com/invoke-ai/InvokeAI Preparations: - You will need to install Python 3.9 or higher for this installer + You will need to install Python 3.10 or higher for this installer to work. Instructions are given here: https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ @@ -14,15 +14,15 @@ Preparations: python --version If all is well, it will print "Python 3.X.X", where the version number - is at least 3.9.*, and not higher than 3.11.*. + is at least 3.10.*, and not higher than 3.11.*. If this works, check the version of the Python package manager, pip: pip --version You should get a message that indicates that the pip package - installer was derived from Python 3.9 or 3.10. For example: - "pip 22.3.1 from /usr/bin/pip (python 3.9)" + installer was derived from Python 3.10 or 3.11. For example: + "pip 22.0.1 from /usr/bin/pip (python 3.10)" Long Paths on Windows: diff --git a/pyproject.toml b/pyproject.toml index 03fc45c5dc..67486e1120 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "InvokeAI" description = "An implementation of Stable Diffusion which provides various new features and options to aid the image generation process" -requires-python = ">=3.9, <3.12" +requires-python = ">=3.10, <3.12" readme = { content-type = "text/markdown", file = "README.md" } keywords = ["stable-diffusion", "AI"] dynamic = ["version"] From f11ba81a8d5e200c2985658ad05d1b6f0ad4f593 Mon Sep 17 00:00:00 2001 From: user1 Date: Tue, 10 Oct 2023 11:29:19 -0700 Subject: [PATCH 006/119] Fixing some var and arg names. --- .../stable_diffusion/diffusers_pipeline.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 0943b78bf8..5681a04695 100644 --- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py +++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py @@ -546,11 +546,13 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): # Handle ControlNet(s) and T2I-Adapter(s) down_block_additional_residuals = None mid_block_additional_residual = None - if control_data is not None and t2i_adapter_data is not None: + down_intrablock_additional_residuals = None + # if control_data is not None and t2i_adapter_data is not None: # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. - raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") - elif control_data is not None: + # raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") + # elif control_data is not None: + if control_data is not None: down_block_additional_residuals, mid_block_additional_residual = self.invokeai_diffuser.do_controlnet_step( control_data=control_data, sample=latent_model_input, @@ -559,7 +561,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): total_step_count=total_step_count, conditioning_data=conditioning_data, ) - elif t2i_adapter_data is not None: + # elif t2i_adapter_data is not None: + if t2i_adapter_data is not None: accum_adapter_state = None for single_t2i_adapter_data in t2i_adapter_data: # Determine the T2I-Adapter weights for the current denoising step. @@ -584,7 +587,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): for idx, value in enumerate(single_t2i_adapter_data.adapter_state): accum_adapter_state[idx] += value * t2i_adapter_weight - down_block_additional_residuals = accum_adapter_state + # down_block_additional_residuals = accum_adapter_state + down_intrablock_additional_residuals = accum_adapter_state uc_noise_pred, c_noise_pred = self.invokeai_diffuser.do_unet_step( sample=latent_model_input, @@ -593,8 +597,9 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): total_step_count=total_step_count, conditioning_data=conditioning_data, # extra: - down_block_additional_residuals=down_block_additional_residuals, - mid_block_additional_residual=mid_block_additional_residual, + down_block_additional_residuals=down_block_additional_residuals, # for ControlNet + mid_block_additional_residual=mid_block_additional_residual, # for ControlNet + down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter ) guidance_scale = conditioning_data.guidance_scale From 378689a519eaebb0181c38d0ad8faf6e747ceb16 Mon Sep 17 00:00:00 2001 From: user1 Date: Tue, 10 Oct 2023 12:25:54 -0700 Subject: [PATCH 007/119] Changes to _apply_standard_conditioning_sequentially() and _apply_cross_attention_controlled_conditioning() to reflect changes to T2I-Adapter implementation to allow usage of T2I-Adapter and ControlNet at the same time. Also, the PREVIOUS commit (@8d3885d, which was already pushed to github repo) was wrongly commented, but too late to fix without a force push or other mucking that I'm reluctant to do. That commit is actually the one that has all the changes to diffusers_pipeline.py to use additional arg down_intrablock_additional_residuals (introduced in diffusers PR https://github.com/huggingface/diffusers/pull/5362) to detangle T2I-Adapter from ControlNet inputs to main UNet. --- .../diffusion/shared_invokeai_diffusion.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index c12c86ed92..ef0f3ee261 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -260,7 +260,6 @@ class InvokeAIDiffuserComponent: conditioning_data, **kwargs, ) - else: ( unconditioned_next_x, @@ -407,6 +406,16 @@ class InvokeAIDiffuserComponent: uncond_down_block.append(_uncond_down) cond_down_block.append(_cond_down) + uncond_down_intrablock, cond_down_intrablock = None, None + down_intrablock_additional_residuals = kwargs.pop("down_intrablock_additional_residuals", None) + if down_intrablock_additional_residuals is not None: + uncond_down_intrablock, cond_down_intrablock = [], [] + for down_intrablock in down_intrablock_additional_residuals: + print("down_intrablock shape: ", down_intrablock.shape) + _uncond_down, _cond_down = down_intrablock.chunk(2) + uncond_down_intrablock.append(_uncond_down) + cond_down_intrablock.append(_cond_down) + uncond_mid_block, cond_mid_block = None, None mid_block_additional_residual = kwargs.pop("mid_block_additional_residual", None) if mid_block_additional_residual is not None: @@ -437,6 +446,7 @@ class InvokeAIDiffuserComponent: cross_attention_kwargs=cross_attention_kwargs, down_block_additional_residuals=uncond_down_block, mid_block_additional_residual=uncond_mid_block, + down_intrablock_additional_residuals=uncond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -465,6 +475,7 @@ class InvokeAIDiffuserComponent: cross_attention_kwargs=cross_attention_kwargs, down_block_additional_residuals=cond_down_block, mid_block_additional_residual=cond_mid_block, + down_intrablock_additional_residuals=cond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -489,6 +500,15 @@ class InvokeAIDiffuserComponent: uncond_down_block.append(_uncond_down) cond_down_block.append(_cond_down) + uncond_down_intrablock, cond_down_intrablock = None, None + down_intrablock_additional_residuals = kwargs.pop("down_intrablock_additional_residuals", None) + if down_intrablock_additional_residuals is not None: + uncond_down_intrablock, cond_down_intrablock = [], [] + for down_intrablock in down_intrablock_additional_residuals: + _uncond_down, _cond_down = down_intrablock.chunk(2) + uncond_down_intrablock.append(_uncond_down) + cond_down_intrablock.append(_cond_down) + uncond_mid_block, cond_mid_block = None, None mid_block_additional_residual = kwargs.pop("mid_block_additional_residual", None) if mid_block_additional_residual is not None: @@ -517,6 +537,7 @@ class InvokeAIDiffuserComponent: {"swap_cross_attn_context": cross_attn_processor_context}, down_block_additional_residuals=uncond_down_block, mid_block_additional_residual=uncond_mid_block, + down_intrablock_additional_residuals=uncond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -536,6 +557,7 @@ class InvokeAIDiffuserComponent: {"swap_cross_attn_context": cross_attn_processor_context}, down_block_additional_residuals=cond_down_block, mid_block_additional_residual=cond_mid_block, + down_intrablock_additional_residuals=cond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) From 06f8a3276d96c4d4f4f316d5714fcc885a77c5d2 Mon Sep 17 00:00:00 2001 From: user1 Date: Mon, 16 Oct 2023 10:15:12 -0700 Subject: [PATCH 008/119] Cleaning up (removing diagnostic prints) --- .../stable_diffusion/diffusion/shared_invokeai_diffusion.py | 1 - 1 file changed, 1 deletion(-) diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index ef0f3ee261..d2af522496 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -411,7 +411,6 @@ class InvokeAIDiffuserComponent: if down_intrablock_additional_residuals is not None: uncond_down_intrablock, cond_down_intrablock = [], [] for down_intrablock in down_intrablock_additional_residuals: - print("down_intrablock shape: ", down_intrablock.shape) _uncond_down, _cond_down = down_intrablock.chunk(2) uncond_down_intrablock.append(_uncond_down) cond_down_intrablock.append(_cond_down) From fff29d663db391307db82a84c1a7af644d5b6d45 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 18:54:15 +1100 Subject: [PATCH 009/119] chore: lint --- invokeai/backend/stable_diffusion/diffusers_pipeline.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 5681a04695..1b65326f6e 100644 --- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py +++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py @@ -548,8 +548,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): mid_block_additional_residual = None down_intrablock_additional_residuals = None # if control_data is not None and t2i_adapter_data is not None: - # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility - # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. + # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility + # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. # raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") # elif control_data is not None: if control_data is not None: @@ -598,8 +598,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): conditioning_data=conditioning_data, # extra: down_block_additional_residuals=down_block_additional_residuals, # for ControlNet - mid_block_additional_residual=mid_block_additional_residual, # for ControlNet - down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter + mid_block_additional_residual=mid_block_additional_residual, # for ControlNet + down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter ) guidance_scale = conditioning_data.guidance_scale From b14699355317fdaf1eaff03b36a5ce85fedb2943 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 18:58:02 +1100 Subject: [PATCH 010/119] feat(ui): remove special handling for t2i vs controlnet --- .../middleware/listenerMiddleware/index.ts | 7 +- .../listeners/controlAdapterAddedOrEnabled.ts | 87 ------------------- .../store/controlAdaptersSlice.ts | 67 -------------- .../frontend/web/src/services/api/schema.d.ts | 71 +++++++++++---- 4 files changed, 55 insertions(+), 177 deletions(-) delete mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index cbc88966a7..772ea216c0 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -12,6 +12,7 @@ import { addFirstListImagesListener } from './listeners/addFirstListImagesListen import { addAnyEnqueuedListener } from './listeners/anyEnqueued'; import { addAppConfigReceivedListener } from './listeners/appConfigReceived'; import { addAppStartedListener } from './listeners/appStarted'; +import { addBatchEnqueuedListener } from './listeners/batchEnqueued'; import { addDeleteBoardAndImagesFulfilledListener } from './listeners/boardAndImagesDeleted'; import { addBoardIdSelectedListener } from './listeners/boardIdSelected'; import { addCanvasCopiedToClipboardListener } from './listeners/canvasCopiedToClipboard'; @@ -71,8 +72,6 @@ import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSa import { addTabChangedListener } from './listeners/tabChanged'; import { addUpscaleRequestedListener } from './listeners/upscaleRequested'; import { addWorkflowLoadedListener } from './listeners/workflowLoaded'; -import { addBatchEnqueuedListener } from './listeners/batchEnqueued'; -import { addControlAdapterAddedOrEnabledListener } from './listeners/controlAdapterAddedOrEnabled'; export const listenerMiddleware = createListenerMiddleware(); @@ -200,7 +199,3 @@ addTabChangedListener(); // Dynamic prompts addDynamicPromptsListener(); - -// Display toast when controlnet or t2i adapter enabled -// TODO: Remove when they can both be enabled at same time -addControlAdapterAddedOrEnabledListener(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts deleted file mode 100644 index bc5387c1fb..0000000000 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { isAnyOf } from '@reduxjs/toolkit'; -import { - controlAdapterAdded, - controlAdapterAddedFromImage, - controlAdapterIsEnabledChanged, - controlAdapterRecalled, - selectControlAdapterAll, - selectControlAdapterById, -} from 'features/controlAdapters/store/controlAdaptersSlice'; -import { ControlAdapterType } from 'features/controlAdapters/store/types'; -import { addToast } from 'features/system/store/systemSlice'; -import i18n from 'i18n'; -import { startAppListening } from '..'; - -const isAnyControlAdapterAddedOrEnabled = isAnyOf( - controlAdapterAdded, - controlAdapterAddedFromImage, - controlAdapterRecalled, - controlAdapterIsEnabledChanged -); - -/** - * Until we can have both controlnet and t2i adapter enabled at once, they are mutually exclusive - * This displays a toast when one is enabled and the other is already enabled, or one is added - * with the other enabled - */ -export const addControlAdapterAddedOrEnabledListener = () => { - startAppListening({ - matcher: isAnyControlAdapterAddedOrEnabled, - effect: async (action, { dispatch, getOriginalState }) => { - const controlAdapters = getOriginalState().controlAdapters; - - const hasEnabledControlNets = selectControlAdapterAll( - controlAdapters - ).some((ca) => ca.isEnabled && ca.type === 'controlnet'); - - const hasEnabledT2IAdapters = selectControlAdapterAll( - controlAdapters - ).some((ca) => ca.isEnabled && ca.type === 't2i_adapter'); - - let caType: ControlAdapterType | null = null; - - if (controlAdapterAdded.match(action)) { - caType = action.payload.type; - } - - if (controlAdapterAddedFromImage.match(action)) { - caType = action.payload.type; - } - - if (controlAdapterRecalled.match(action)) { - caType = action.payload.type; - } - - if (controlAdapterIsEnabledChanged.match(action)) { - const _caType = selectControlAdapterById( - controlAdapters, - action.payload.id - )?.type; - if (!_caType) { - return; - } - caType = _caType; - } - - if ( - (caType === 'controlnet' && hasEnabledT2IAdapters) || - (caType === 't2i_adapter' && hasEnabledControlNets) - ) { - const title = - caType === 'controlnet' - ? i18n.t('controlnet.controlNetEnabledT2IDisabled') - : i18n.t('controlnet.t2iEnabledControlNetDisabled'); - - const description = i18n.t('controlnet.controlNetT2IMutexDesc'); - - dispatch( - addToast({ - title, - description, - status: 'warning', - }) - ); - } - }, - }); -}; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts index a3645fad9d..9e293f1104 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts @@ -88,61 +88,6 @@ export const selectValidT2IAdapters = (controlAdapters: ControlAdaptersState) => (ca.processorType === 'none' && Boolean(ca.controlImage))) ); -// TODO: I think we can safely remove this? -// const disableAllIPAdapters = ( -// state: ControlAdaptersState, -// exclude?: string -// ) => { -// const updates: Update[] = selectAllIPAdapters(state) -// .filter((ca) => ca.id !== exclude) -// .map((ca) => ({ -// id: ca.id, -// changes: { isEnabled: false }, -// })); -// caAdapter.updateMany(state, updates); -// }; - -const disableAllControlNets = ( - state: ControlAdaptersState, - exclude?: string -) => { - const updates: Update[] = selectAllControlNets(state) - .filter((ca) => ca.id !== exclude) - .map((ca) => ({ - id: ca.id, - changes: { isEnabled: false }, - })); - caAdapter.updateMany(state, updates); -}; - -const disableAllT2IAdapters = ( - state: ControlAdaptersState, - exclude?: string -) => { - const updates: Update[] = selectAllT2IAdapters(state) - .filter((ca) => ca.id !== exclude) - .map((ca) => ({ - id: ca.id, - changes: { isEnabled: false }, - })); - caAdapter.updateMany(state, updates); -}; - -const disableIncompatibleControlAdapters = ( - state: ControlAdaptersState, - type: ControlAdapterType, - exclude?: string -) => { - if (type === 'controlnet') { - // we cannot do controlnet + t2i adapter, if we are enabled a controlnet, disable all t2is - disableAllT2IAdapters(state, exclude); - } - if (type === 't2i_adapter') { - // we cannot do controlnet + t2i adapter, if we are enabled a t2i, disable controlnets - disableAllControlNets(state, exclude); - } -}; - export const controlAdaptersSlice = createSlice({ name: 'controlAdapters', initialState: initialControlAdapterState, @@ -158,7 +103,6 @@ export const controlAdaptersSlice = createSlice({ ) => { const { id, type, overrides } = action.payload; caAdapter.addOne(state, buildControlAdapter(id, type, overrides)); - disableIncompatibleControlAdapters(state, type, id); }, prepare: ({ type, @@ -175,8 +119,6 @@ export const controlAdaptersSlice = createSlice({ action: PayloadAction ) => { caAdapter.addOne(state, action.payload); - const { type, id } = action.payload; - disableIncompatibleControlAdapters(state, type, id); }, controlAdapterDuplicated: { reducer: ( @@ -196,8 +138,6 @@ export const controlAdaptersSlice = createSlice({ isEnabled: true, }); caAdapter.addOne(state, newControlAdapter); - const { type } = newControlAdapter; - disableIncompatibleControlAdapters(state, type, newId); }, prepare: (id: string) => { return { payload: { id, newId: uuidv4() } }; @@ -217,7 +157,6 @@ export const controlAdaptersSlice = createSlice({ state, buildControlAdapter(id, type, { controlImage }) ); - disableIncompatibleControlAdapters(state, type, id); }, prepare: (payload: { type: ControlAdapterType; @@ -235,12 +174,6 @@ export const controlAdaptersSlice = createSlice({ ) => { const { id, isEnabled } = action.payload; caAdapter.updateOne(state, { id, changes: { isEnabled } }); - if (isEnabled) { - // we are enabling a control adapter. due to limitations in the current system, we may need to disable other adapters - // TODO: disable when multiple IP adapters are supported - const ca = selectControlAdapterById(state, id); - ca && disableIncompatibleControlAdapters(state, ca.type, id); - } }, controlAdapterImageChanged: ( state, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index d4678dc03b..e0da45c4c9 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -5,6 +5,13 @@ export type paths = { + "/api/v1/sessions/{session_id}": { + /** + * Get Session + * @description Gets a session + */ + get: operations["get_session"]; + }; "/api/v1/utilities/dynamicprompts": { /** * Parse Dynamicprompts @@ -1897,7 +1904,7 @@ export type components = { * Created By * @description The name of the creator of the image */ - created_by: string | null; + created_by?: string | null; /** * Positive Prompt * @description The positive prompt parameter @@ -3035,7 +3042,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["MainModelLoaderInvocation"]; + [key: string]: components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"]; }; /** * Edges @@ -3072,7 +3079,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SchedulerOutput"]; + [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ImageCollectionOutput"]; }; /** * Errors @@ -9139,11 +9146,11 @@ export type components = { ui_order: number | null; }; /** - * StableDiffusionOnnxModelFormat + * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; + IPAdapterModelFormat: "invokeai"; /** * StableDiffusion2ModelFormat * @description An enumeration. @@ -9156,36 +9163,36 @@ export type components = { * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; /** * CLIPVisionModelFormat * @description An enumeration. * @enum {string} */ CLIPVisionModelFormat: "diffusers"; + /** + * StableDiffusionOnnxModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; - /** - * IPAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - IPAdapterModelFormat: "invokeai"; /** * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ T2IAdapterModelFormat: "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -9200,6 +9207,36 @@ export type external = Record; export type operations = { + /** + * Get Session + * @description Gets a session + */ + get_session: { + parameters: { + path: { + /** @description The id of the session to get */ + session_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GraphExecutionState"]; + }; + }; + /** @description Session not found */ + 404: { + content: never; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; /** * Parse Dynamicprompts * @description Creates a batch process From bdf4c4944cf0e9e827ee026fddfd1bd74f3c40e0 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:56:52 +1100 Subject: [PATCH 011/119] Revert "feat(ui): remove special handling for t2i vs controlnet" This reverts commit b14699355317fdaf1eaff03b36a5ce85fedb2943. --- .../middleware/listenerMiddleware/index.ts | 7 +- .../listeners/controlAdapterAddedOrEnabled.ts | 87 +++++++++++++++++++ .../store/controlAdaptersSlice.ts | 67 ++++++++++++++ .../frontend/web/src/services/api/schema.d.ts | 71 ++++----------- 4 files changed, 177 insertions(+), 55 deletions(-) create mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index 772ea216c0..cbc88966a7 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -12,7 +12,6 @@ import { addFirstListImagesListener } from './listeners/addFirstListImagesListen import { addAnyEnqueuedListener } from './listeners/anyEnqueued'; import { addAppConfigReceivedListener } from './listeners/appConfigReceived'; import { addAppStartedListener } from './listeners/appStarted'; -import { addBatchEnqueuedListener } from './listeners/batchEnqueued'; import { addDeleteBoardAndImagesFulfilledListener } from './listeners/boardAndImagesDeleted'; import { addBoardIdSelectedListener } from './listeners/boardIdSelected'; import { addCanvasCopiedToClipboardListener } from './listeners/canvasCopiedToClipboard'; @@ -72,6 +71,8 @@ import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSa import { addTabChangedListener } from './listeners/tabChanged'; import { addUpscaleRequestedListener } from './listeners/upscaleRequested'; import { addWorkflowLoadedListener } from './listeners/workflowLoaded'; +import { addBatchEnqueuedListener } from './listeners/batchEnqueued'; +import { addControlAdapterAddedOrEnabledListener } from './listeners/controlAdapterAddedOrEnabled'; export const listenerMiddleware = createListenerMiddleware(); @@ -199,3 +200,7 @@ addTabChangedListener(); // Dynamic prompts addDynamicPromptsListener(); + +// Display toast when controlnet or t2i adapter enabled +// TODO: Remove when they can both be enabled at same time +addControlAdapterAddedOrEnabledListener(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts new file mode 100644 index 0000000000..bc5387c1fb --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlAdapterAddedOrEnabled.ts @@ -0,0 +1,87 @@ +import { isAnyOf } from '@reduxjs/toolkit'; +import { + controlAdapterAdded, + controlAdapterAddedFromImage, + controlAdapterIsEnabledChanged, + controlAdapterRecalled, + selectControlAdapterAll, + selectControlAdapterById, +} from 'features/controlAdapters/store/controlAdaptersSlice'; +import { ControlAdapterType } from 'features/controlAdapters/store/types'; +import { addToast } from 'features/system/store/systemSlice'; +import i18n from 'i18n'; +import { startAppListening } from '..'; + +const isAnyControlAdapterAddedOrEnabled = isAnyOf( + controlAdapterAdded, + controlAdapterAddedFromImage, + controlAdapterRecalled, + controlAdapterIsEnabledChanged +); + +/** + * Until we can have both controlnet and t2i adapter enabled at once, they are mutually exclusive + * This displays a toast when one is enabled and the other is already enabled, or one is added + * with the other enabled + */ +export const addControlAdapterAddedOrEnabledListener = () => { + startAppListening({ + matcher: isAnyControlAdapterAddedOrEnabled, + effect: async (action, { dispatch, getOriginalState }) => { + const controlAdapters = getOriginalState().controlAdapters; + + const hasEnabledControlNets = selectControlAdapterAll( + controlAdapters + ).some((ca) => ca.isEnabled && ca.type === 'controlnet'); + + const hasEnabledT2IAdapters = selectControlAdapterAll( + controlAdapters + ).some((ca) => ca.isEnabled && ca.type === 't2i_adapter'); + + let caType: ControlAdapterType | null = null; + + if (controlAdapterAdded.match(action)) { + caType = action.payload.type; + } + + if (controlAdapterAddedFromImage.match(action)) { + caType = action.payload.type; + } + + if (controlAdapterRecalled.match(action)) { + caType = action.payload.type; + } + + if (controlAdapterIsEnabledChanged.match(action)) { + const _caType = selectControlAdapterById( + controlAdapters, + action.payload.id + )?.type; + if (!_caType) { + return; + } + caType = _caType; + } + + if ( + (caType === 'controlnet' && hasEnabledT2IAdapters) || + (caType === 't2i_adapter' && hasEnabledControlNets) + ) { + const title = + caType === 'controlnet' + ? i18n.t('controlnet.controlNetEnabledT2IDisabled') + : i18n.t('controlnet.t2iEnabledControlNetDisabled'); + + const description = i18n.t('controlnet.controlNetT2IMutexDesc'); + + dispatch( + addToast({ + title, + description, + status: 'warning', + }) + ); + } + }, + }); +}; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts index 9e293f1104..a3645fad9d 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts @@ -88,6 +88,61 @@ export const selectValidT2IAdapters = (controlAdapters: ControlAdaptersState) => (ca.processorType === 'none' && Boolean(ca.controlImage))) ); +// TODO: I think we can safely remove this? +// const disableAllIPAdapters = ( +// state: ControlAdaptersState, +// exclude?: string +// ) => { +// const updates: Update[] = selectAllIPAdapters(state) +// .filter((ca) => ca.id !== exclude) +// .map((ca) => ({ +// id: ca.id, +// changes: { isEnabled: false }, +// })); +// caAdapter.updateMany(state, updates); +// }; + +const disableAllControlNets = ( + state: ControlAdaptersState, + exclude?: string +) => { + const updates: Update[] = selectAllControlNets(state) + .filter((ca) => ca.id !== exclude) + .map((ca) => ({ + id: ca.id, + changes: { isEnabled: false }, + })); + caAdapter.updateMany(state, updates); +}; + +const disableAllT2IAdapters = ( + state: ControlAdaptersState, + exclude?: string +) => { + const updates: Update[] = selectAllT2IAdapters(state) + .filter((ca) => ca.id !== exclude) + .map((ca) => ({ + id: ca.id, + changes: { isEnabled: false }, + })); + caAdapter.updateMany(state, updates); +}; + +const disableIncompatibleControlAdapters = ( + state: ControlAdaptersState, + type: ControlAdapterType, + exclude?: string +) => { + if (type === 'controlnet') { + // we cannot do controlnet + t2i adapter, if we are enabled a controlnet, disable all t2is + disableAllT2IAdapters(state, exclude); + } + if (type === 't2i_adapter') { + // we cannot do controlnet + t2i adapter, if we are enabled a t2i, disable controlnets + disableAllControlNets(state, exclude); + } +}; + export const controlAdaptersSlice = createSlice({ name: 'controlAdapters', initialState: initialControlAdapterState, @@ -103,6 +158,7 @@ export const controlAdaptersSlice = createSlice({ ) => { const { id, type, overrides } = action.payload; caAdapter.addOne(state, buildControlAdapter(id, type, overrides)); + disableIncompatibleControlAdapters(state, type, id); }, prepare: ({ type, @@ -119,6 +175,8 @@ export const controlAdaptersSlice = createSlice({ action: PayloadAction ) => { caAdapter.addOne(state, action.payload); + const { type, id } = action.payload; + disableIncompatibleControlAdapters(state, type, id); }, controlAdapterDuplicated: { reducer: ( @@ -138,6 +196,8 @@ export const controlAdaptersSlice = createSlice({ isEnabled: true, }); caAdapter.addOne(state, newControlAdapter); + const { type } = newControlAdapter; + disableIncompatibleControlAdapters(state, type, newId); }, prepare: (id: string) => { return { payload: { id, newId: uuidv4() } }; @@ -157,6 +217,7 @@ export const controlAdaptersSlice = createSlice({ state, buildControlAdapter(id, type, { controlImage }) ); + disableIncompatibleControlAdapters(state, type, id); }, prepare: (payload: { type: ControlAdapterType; @@ -174,6 +235,12 @@ export const controlAdaptersSlice = createSlice({ ) => { const { id, isEnabled } = action.payload; caAdapter.updateOne(state, { id, changes: { isEnabled } }); + if (isEnabled) { + // we are enabling a control adapter. due to limitations in the current system, we may need to disable other adapters + // TODO: disable when multiple IP adapters are supported + const ca = selectControlAdapterById(state, id); + ca && disableIncompatibleControlAdapters(state, ca.type, id); + } }, controlAdapterImageChanged: ( state, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index e0da45c4c9..d4678dc03b 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -5,13 +5,6 @@ export type paths = { - "/api/v1/sessions/{session_id}": { - /** - * Get Session - * @description Gets a session - */ - get: operations["get_session"]; - }; "/api/v1/utilities/dynamicprompts": { /** * Parse Dynamicprompts @@ -1904,7 +1897,7 @@ export type components = { * Created By * @description The name of the creator of the image */ - created_by?: string | null; + created_by: string | null; /** * Positive Prompt * @description The positive prompt parameter @@ -3042,7 +3035,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"]; + [key: string]: components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["MainModelLoaderInvocation"]; }; /** * Edges @@ -3079,7 +3072,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ImageCollectionOutput"]; + [key: string]: components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SchedulerOutput"]; }; /** * Errors @@ -9146,11 +9139,11 @@ export type components = { ui_order: number | null; }; /** - * IPAdapterModelFormat + * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ - IPAdapterModelFormat: "invokeai"; + StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** * StableDiffusion2ModelFormat * @description An enumeration. @@ -9163,36 +9156,36 @@ export type components = { * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; /** * CLIPVisionModelFormat * @description An enumeration. * @enum {string} */ CLIPVisionModelFormat: "diffusers"; - /** - * StableDiffusionOnnxModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * IPAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + IPAdapterModelFormat: "invokeai"; /** * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ T2IAdapterModelFormat: "diffusers"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -9207,36 +9200,6 @@ export type external = Record; export type operations = { - /** - * Get Session - * @description Gets a session - */ - get_session: { - parameters: { - path: { - /** @description The id of the session to get */ - session_id: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; /** * Parse Dynamicprompts * @description Creates a batch process From 38e7eb8878aa213426764b5aaa27532ef2b9db8a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:56:52 +1100 Subject: [PATCH 012/119] Revert "chore: lint" This reverts commit fff29d663db391307db82a84c1a7af644d5b6d45. --- invokeai/backend/stable_diffusion/diffusers_pipeline.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 1b65326f6e..5681a04695 100644 --- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py +++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py @@ -548,8 +548,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): mid_block_additional_residual = None down_intrablock_additional_residuals = None # if control_data is not None and t2i_adapter_data is not None: - # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility - # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. + # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility + # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. # raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") # elif control_data is not None: if control_data is not None: @@ -598,8 +598,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): conditioning_data=conditioning_data, # extra: down_block_additional_residuals=down_block_additional_residuals, # for ControlNet - mid_block_additional_residual=mid_block_additional_residual, # for ControlNet - down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter + mid_block_additional_residual=mid_block_additional_residual, # for ControlNet + down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter ) guidance_scale = conditioning_data.guidance_scale From 6e697b7b6f0a7d7ae24455e15c15baa1bc0adaf6 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:56:52 +1100 Subject: [PATCH 013/119] Revert "Cleaning up (removing diagnostic prints)" This reverts commit 06f8a3276d96c4d4f4f316d5714fcc885a77c5d2. --- .../stable_diffusion/diffusion/shared_invokeai_diffusion.py | 1 + 1 file changed, 1 insertion(+) diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index d2af522496..ef0f3ee261 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -411,6 +411,7 @@ class InvokeAIDiffuserComponent: if down_intrablock_additional_residuals is not None: uncond_down_intrablock, cond_down_intrablock = [], [] for down_intrablock in down_intrablock_additional_residuals: + print("down_intrablock shape: ", down_intrablock.shape) _uncond_down, _cond_down = down_intrablock.chunk(2) uncond_down_intrablock.append(_uncond_down) cond_down_intrablock.append(_cond_down) From c04fb451ee4603cad7751f890a0b3047c15df5b3 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:56:52 +1100 Subject: [PATCH 014/119] Revert "Changes to _apply_standard_conditioning_sequentially() and _apply_cross_attention_controlled_conditioning() to reflect changes to T2I-Adapter implementation to allow usage of T2I-Adapter and ControlNet at the same time." This reverts commit 378689a519eaebb0181c38d0ad8faf6e747ceb16. --- .../diffusion/shared_invokeai_diffusion.py | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index ef0f3ee261..c12c86ed92 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -260,6 +260,7 @@ class InvokeAIDiffuserComponent: conditioning_data, **kwargs, ) + else: ( unconditioned_next_x, @@ -406,16 +407,6 @@ class InvokeAIDiffuserComponent: uncond_down_block.append(_uncond_down) cond_down_block.append(_cond_down) - uncond_down_intrablock, cond_down_intrablock = None, None - down_intrablock_additional_residuals = kwargs.pop("down_intrablock_additional_residuals", None) - if down_intrablock_additional_residuals is not None: - uncond_down_intrablock, cond_down_intrablock = [], [] - for down_intrablock in down_intrablock_additional_residuals: - print("down_intrablock shape: ", down_intrablock.shape) - _uncond_down, _cond_down = down_intrablock.chunk(2) - uncond_down_intrablock.append(_uncond_down) - cond_down_intrablock.append(_cond_down) - uncond_mid_block, cond_mid_block = None, None mid_block_additional_residual = kwargs.pop("mid_block_additional_residual", None) if mid_block_additional_residual is not None: @@ -446,7 +437,6 @@ class InvokeAIDiffuserComponent: cross_attention_kwargs=cross_attention_kwargs, down_block_additional_residuals=uncond_down_block, mid_block_additional_residual=uncond_mid_block, - down_intrablock_additional_residuals=uncond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -475,7 +465,6 @@ class InvokeAIDiffuserComponent: cross_attention_kwargs=cross_attention_kwargs, down_block_additional_residuals=cond_down_block, mid_block_additional_residual=cond_mid_block, - down_intrablock_additional_residuals=cond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -500,15 +489,6 @@ class InvokeAIDiffuserComponent: uncond_down_block.append(_uncond_down) cond_down_block.append(_cond_down) - uncond_down_intrablock, cond_down_intrablock = None, None - down_intrablock_additional_residuals = kwargs.pop("down_intrablock_additional_residuals", None) - if down_intrablock_additional_residuals is not None: - uncond_down_intrablock, cond_down_intrablock = [], [] - for down_intrablock in down_intrablock_additional_residuals: - _uncond_down, _cond_down = down_intrablock.chunk(2) - uncond_down_intrablock.append(_uncond_down) - cond_down_intrablock.append(_cond_down) - uncond_mid_block, cond_mid_block = None, None mid_block_additional_residual = kwargs.pop("mid_block_additional_residual", None) if mid_block_additional_residual is not None: @@ -537,7 +517,6 @@ class InvokeAIDiffuserComponent: {"swap_cross_attn_context": cross_attn_processor_context}, down_block_additional_residuals=uncond_down_block, mid_block_additional_residual=uncond_mid_block, - down_intrablock_additional_residuals=uncond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) @@ -557,7 +536,6 @@ class InvokeAIDiffuserComponent: {"swap_cross_attn_context": cross_attn_processor_context}, down_block_additional_residuals=cond_down_block, mid_block_additional_residual=cond_mid_block, - down_intrablock_additional_residuals=cond_down_intrablock, added_cond_kwargs=added_cond_kwargs, **kwargs, ) From 58a0709c1ea19293e49f6c88d8836f0378a982cd Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:56:52 +1100 Subject: [PATCH 015/119] Revert "Fixing some var and arg names." This reverts commit f11ba81a8d5e200c2985658ad05d1b6f0ad4f593. --- .../stable_diffusion/diffusers_pipeline.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 5681a04695..0943b78bf8 100644 --- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py +++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py @@ -546,13 +546,11 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): # Handle ControlNet(s) and T2I-Adapter(s) down_block_additional_residuals = None mid_block_additional_residual = None - down_intrablock_additional_residuals = None - # if control_data is not None and t2i_adapter_data is not None: + if control_data is not None and t2i_adapter_data is not None: # TODO(ryand): This is a limitation of the UNet2DConditionModel API, not a fundamental incompatibility # between ControlNets and T2I-Adapters. We will try to fix this upstream in diffusers. - # raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") - # elif control_data is not None: - if control_data is not None: + raise Exception("ControlNet(s) and T2I-Adapter(s) cannot be used simultaneously (yet).") + elif control_data is not None: down_block_additional_residuals, mid_block_additional_residual = self.invokeai_diffuser.do_controlnet_step( control_data=control_data, sample=latent_model_input, @@ -561,8 +559,7 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): total_step_count=total_step_count, conditioning_data=conditioning_data, ) - # elif t2i_adapter_data is not None: - if t2i_adapter_data is not None: + elif t2i_adapter_data is not None: accum_adapter_state = None for single_t2i_adapter_data in t2i_adapter_data: # Determine the T2I-Adapter weights for the current denoising step. @@ -587,8 +584,7 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): for idx, value in enumerate(single_t2i_adapter_data.adapter_state): accum_adapter_state[idx] += value * t2i_adapter_weight - # down_block_additional_residuals = accum_adapter_state - down_intrablock_additional_residuals = accum_adapter_state + down_block_additional_residuals = accum_adapter_state uc_noise_pred, c_noise_pred = self.invokeai_diffuser.do_unet_step( sample=latent_model_input, @@ -597,9 +593,8 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): total_step_count=total_step_count, conditioning_data=conditioning_data, # extra: - down_block_additional_residuals=down_block_additional_residuals, # for ControlNet - mid_block_additional_residual=mid_block_additional_residual, # for ControlNet - down_intrablock_additional_residuals=down_intrablock_additional_residuals, # for T2I-Adapter + down_block_additional_residuals=down_block_additional_residuals, + mid_block_additional_residual=mid_block_additional_residual, ) guidance_scale = conditioning_data.guidance_scale From 284a257c2531195b3b25138eb959325a9c434ef2 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 05:00:40 +1100 Subject: [PATCH 016/119] feat: remove `enqueue_graph` routes/methods (#4922) This is totally extraneous - it's almost identical to `enqueue_batch`. --- invokeai/app/api/routers/session_queue.py | 19 --- .../session_queue/session_queue_base.py | 7 - .../session_queue/session_queue_common.py | 8 - .../session_queue/session_queue_sqlite.py | 28 --- .../listeners/anyEnqueued.ts | 8 +- .../listeners/controlNetImageProcessed.ts | 84 ++++----- .../listeners/upscaleRequested.ts | 32 ++-- .../hooks/useIsQueueMutationInProgress.ts | 6 - .../web/src/services/api/endpoints/queue.ts | 25 --- .../frontend/web/src/services/api/schema.d.ts | 160 +++++++----------- .../frontend/web/src/services/api/types.ts | 1 - 11 files changed, 126 insertions(+), 252 deletions(-) diff --git a/invokeai/app/api/routers/session_queue.py b/invokeai/app/api/routers/session_queue.py index 7ecb0504a3..40f1f2213b 100644 --- a/invokeai/app/api/routers/session_queue.py +++ b/invokeai/app/api/routers/session_queue.py @@ -12,13 +12,11 @@ from invokeai.app.services.session_queue.session_queue_common import ( CancelByBatchIDsResult, ClearResult, EnqueueBatchResult, - EnqueueGraphResult, PruneResult, SessionQueueItem, SessionQueueItemDTO, SessionQueueStatus, ) -from invokeai.app.services.shared.graph import Graph from invokeai.app.services.shared.pagination import CursorPaginatedResults from ..dependencies import ApiDependencies @@ -33,23 +31,6 @@ class SessionQueueAndProcessorStatus(BaseModel): processor: SessionProcessorStatus -@session_queue_router.post( - "/{queue_id}/enqueue_graph", - operation_id="enqueue_graph", - responses={ - 201: {"model": EnqueueGraphResult}, - }, -) -async def enqueue_graph( - queue_id: str = Path(description="The queue id to perform this operation on"), - graph: Graph = Body(description="The graph to enqueue"), - prepend: bool = Body(default=False, description="Whether or not to prepend this batch in the queue"), -) -> EnqueueGraphResult: - """Enqueues a graph for single execution.""" - - return ApiDependencies.invoker.services.session_queue.enqueue_graph(queue_id=queue_id, graph=graph, prepend=prepend) - - @session_queue_router.post( "/{queue_id}/enqueue_batch", operation_id="enqueue_batch", diff --git a/invokeai/app/services/session_queue/session_queue_base.py b/invokeai/app/services/session_queue/session_queue_base.py index b5272f1868..e0b6e4f528 100644 --- a/invokeai/app/services/session_queue/session_queue_base.py +++ b/invokeai/app/services/session_queue/session_queue_base.py @@ -9,7 +9,6 @@ from invokeai.app.services.session_queue.session_queue_common import ( CancelByQueueIDResult, ClearResult, EnqueueBatchResult, - EnqueueGraphResult, IsEmptyResult, IsFullResult, PruneResult, @@ -17,7 +16,6 @@ from invokeai.app.services.session_queue.session_queue_common import ( SessionQueueItemDTO, SessionQueueStatus, ) -from invokeai.app.services.shared.graph import Graph from invokeai.app.services.shared.pagination import CursorPaginatedResults @@ -29,11 +27,6 @@ class SessionQueueBase(ABC): """Dequeues the next session queue item.""" pass - @abstractmethod - def enqueue_graph(self, queue_id: str, graph: Graph, prepend: bool) -> EnqueueGraphResult: - """Enqueues a single graph for execution.""" - pass - @abstractmethod def enqueue_batch(self, queue_id: str, batch: Batch, prepend: bool) -> EnqueueBatchResult: """Enqueues all permutations of a batch for execution.""" diff --git a/invokeai/app/services/session_queue/session_queue_common.py b/invokeai/app/services/session_queue/session_queue_common.py index 48e1da83b5..cbf2154b66 100644 --- a/invokeai/app/services/session_queue/session_queue_common.py +++ b/invokeai/app/services/session_queue/session_queue_common.py @@ -276,14 +276,6 @@ class EnqueueBatchResult(BaseModel): priority: int = Field(description="The priority of the enqueued batch") -class EnqueueGraphResult(BaseModel): - enqueued: int = Field(description="The total number of queue items enqueued") - requested: int = Field(description="The total number of queue items requested to be enqueued") - batch: Batch = Field(description="The batch that was enqueued") - priority: int = Field(description="The priority of the enqueued batch") - queue_item: SessionQueueItemDTO = Field(description="The queue item that was enqueued") - - class ClearResult(BaseModel): """Result of clearing the session queue""" diff --git a/invokeai/app/services/session_queue/session_queue_sqlite.py b/invokeai/app/services/session_queue/session_queue_sqlite.py index 4daab9cdbc..7259a7bd0c 100644 --- a/invokeai/app/services/session_queue/session_queue_sqlite.py +++ b/invokeai/app/services/session_queue/session_queue_sqlite.py @@ -17,7 +17,6 @@ from invokeai.app.services.session_queue.session_queue_common import ( CancelByQueueIDResult, ClearResult, EnqueueBatchResult, - EnqueueGraphResult, IsEmptyResult, IsFullResult, PruneResult, @@ -28,7 +27,6 @@ from invokeai.app.services.session_queue.session_queue_common import ( calc_session_count, prepare_values_to_insert, ) -from invokeai.app.services.shared.graph import Graph from invokeai.app.services.shared.pagination import CursorPaginatedResults from invokeai.app.services.shared.sqlite import SqliteDatabase @@ -255,32 +253,6 @@ class SqliteSessionQueue(SessionQueueBase): ) return cast(Union[int, None], self.__cursor.fetchone()[0]) or 0 - def enqueue_graph(self, queue_id: str, graph: Graph, prepend: bool) -> EnqueueGraphResult: - enqueue_result = self.enqueue_batch(queue_id=queue_id, batch=Batch(graph=graph), prepend=prepend) - try: - self.__lock.acquire() - self.__cursor.execute( - """--sql - SELECT * - FROM session_queue - WHERE queue_id = ? - AND batch_id = ? - """, - (queue_id, enqueue_result.batch.batch_id), - ) - result = cast(Union[sqlite3.Row, None], self.__cursor.fetchone()) - except Exception: - self.__conn.rollback() - raise - finally: - self.__lock.release() - if result is None: - raise SessionQueueItemNotFoundError(f"No queue item with batch id {enqueue_result.batch.batch_id}") - return EnqueueGraphResult( - **enqueue_result.model_dump(), - queue_item=SessionQueueItemDTO.queue_item_dto_from_dict(dict(result)), - ) - def enqueue_batch(self, queue_id: str, batch: Batch, prepend: bool) -> EnqueueBatchResult: try: self.__lock.acquire() diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts index ff11491b53..3f0e3342f9 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts @@ -1,15 +1,9 @@ -import { isAnyOf } from '@reduxjs/toolkit'; import { queueApi } from 'services/api/endpoints/queue'; import { startAppListening } from '..'; -const matcher = isAnyOf( - queueApi.endpoints.enqueueBatch.matchFulfilled, - queueApi.endpoints.enqueueGraph.matchFulfilled -); - export const addAnyEnqueuedListener = () => { startAppListening({ - matcher, + matcher: queueApi.endpoints.enqueueBatch.matchFulfilled, effect: async (_, { dispatch, getState }) => { const { data } = queueApi.endpoints.getQueueStatus.select()(getState()); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts index f3db0ea65f..a454e5ca48 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts @@ -1,22 +1,22 @@ import { logger } from 'app/logging/logger'; import { parseify } from 'common/util/serialize'; +import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions'; import { - pendingControlImagesCleared, controlAdapterImageChanged, - selectControlAdapterById, controlAdapterProcessedImageChanged, + pendingControlImagesCleared, + selectControlAdapterById, } from 'features/controlAdapters/store/controlAdaptersSlice'; +import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { SAVE_IMAGE } from 'features/nodes/util/graphBuilders/constants'; import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { imagesApi } from 'services/api/endpoints/images'; import { queueApi } from 'services/api/endpoints/queue'; import { isImageOutput } from 'services/api/guards'; -import { Graph, ImageDTO } from 'services/api/types'; +import { BatchConfig, ImageDTO } from 'services/api/types'; import { socketInvocationComplete } from 'services/events/actions'; import { startAppListening } from '..'; -import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions'; -import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; export const addControlNetImageProcessedListener = () => { startAppListening({ @@ -37,41 +37,46 @@ export const addControlNetImageProcessedListener = () => { // ControlNet one-off procressing graph is just the processor node, no edges. // Also we need to grab the image. - const graph: Graph = { - nodes: { - [ca.processorNode.id]: { - ...ca.processorNode, - is_intermediate: true, - image: { image_name: ca.controlImage }, - }, - [SAVE_IMAGE]: { - id: SAVE_IMAGE, - type: 'save_image', - is_intermediate: true, - use_cache: false, + + const enqueueBatchArg: BatchConfig = { + prepend: true, + batch: { + graph: { + nodes: { + [ca.processorNode.id]: { + ...ca.processorNode, + is_intermediate: true, + image: { image_name: ca.controlImage }, + }, + [SAVE_IMAGE]: { + id: SAVE_IMAGE, + type: 'save_image', + is_intermediate: true, + use_cache: false, + }, + }, + edges: [ + { + source: { + node_id: ca.processorNode.id, + field: 'image', + }, + destination: { + node_id: SAVE_IMAGE, + field: 'image', + }, + }, + ], }, + runs: 1, }, - edges: [ - { - source: { - node_id: ca.processorNode.id, - field: 'image', - }, - destination: { - node_id: SAVE_IMAGE, - field: 'image', - }, - }, - ], }; + try { const req = dispatch( - queueApi.endpoints.enqueueGraph.initiate( - { graph, prepend: true }, - { - fixedCacheKey: 'enqueueGraph', - } - ) + queueApi.endpoints.enqueueBatch.initiate(enqueueBatchArg, { + fixedCacheKey: 'enqueueBatch', + }) ); const enqueueResult = await req.unwrap(); req.reset(); @@ -83,8 +88,8 @@ export const addControlNetImageProcessedListener = () => { const [invocationCompleteAction] = await take( (action): action is ReturnType => socketInvocationComplete.match(action) && - action.payload.data.graph_execution_state_id === - enqueueResult.queue_item.session_id && + action.payload.data.queue_batch_id === + enqueueResult.batch.batch_id && action.payload.data.source_node_id === SAVE_IMAGE ); @@ -116,7 +121,10 @@ export const addControlNetImageProcessedListener = () => { ); } } catch (error) { - log.error({ graph: parseify(graph) }, t('queue.graphFailedToQueue')); + log.error( + { enqueueBatchArg: parseify(enqueueBatchArg) }, + t('queue.graphFailedToQueue') + ); // handle usage-related errors if (error instanceof Object) { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts index c252f412a6..9ddcdc9701 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts @@ -6,7 +6,7 @@ import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { queueApi } from 'services/api/endpoints/queue'; import { startAppListening } from '..'; -import { ImageDTO } from 'services/api/types'; +import { BatchConfig, ImageDTO } from 'services/api/types'; import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale'; export const upscaleRequested = createAction<{ imageDTO: ImageDTO }>( @@ -44,20 +44,23 @@ export const addUpscaleRequestedListener = () => { const { esrganModelName } = state.postprocessing; const { autoAddBoardId } = state.gallery; - const graph = buildAdHocUpscaleGraph({ - image_name, - esrganModelName, - autoAddBoardId, - }); + const enqueueBatchArg: BatchConfig = { + prepend: true, + batch: { + graph: buildAdHocUpscaleGraph({ + image_name, + esrganModelName, + autoAddBoardId, + }), + runs: 1, + }, + }; try { const req = dispatch( - queueApi.endpoints.enqueueGraph.initiate( - { graph, prepend: true }, - { - fixedCacheKey: 'enqueueGraph', - } - ) + queueApi.endpoints.enqueueBatch.initiate(enqueueBatchArg, { + fixedCacheKey: 'enqueueBatch', + }) ); const enqueueResult = await req.unwrap(); @@ -67,7 +70,10 @@ export const addUpscaleRequestedListener = () => { t('queue.graphQueued') ); } catch (error) { - log.error({ graph: parseify(graph) }, t('queue.graphFailedToQueue')); + log.error( + { enqueueBatchArg: parseify(enqueueBatchArg) }, + t('queue.graphFailedToQueue') + ); // handle usage-related errors if (error instanceof Object) { diff --git a/invokeai/frontend/web/src/features/queue/hooks/useIsQueueMutationInProgress.ts b/invokeai/frontend/web/src/features/queue/hooks/useIsQueueMutationInProgress.ts index abb3967b92..9947c17086 100644 --- a/invokeai/frontend/web/src/features/queue/hooks/useIsQueueMutationInProgress.ts +++ b/invokeai/frontend/web/src/features/queue/hooks/useIsQueueMutationInProgress.ts @@ -3,7 +3,6 @@ import { // useCancelByBatchIdsMutation, useClearQueueMutation, useEnqueueBatchMutation, - useEnqueueGraphMutation, usePruneQueueMutation, useResumeProcessorMutation, usePauseProcessorMutation, @@ -14,10 +13,6 @@ export const useIsQueueMutationInProgress = () => { useEnqueueBatchMutation({ fixedCacheKey: 'enqueueBatch', }); - const [_triggerEnqueueGraph, { isLoading: isLoadingEnqueueGraph }] = - useEnqueueGraphMutation({ - fixedCacheKey: 'enqueueGraph', - }); const [_triggerResumeProcessor, { isLoading: isLoadingResumeProcessor }] = useResumeProcessorMutation({ fixedCacheKey: 'resumeProcessor', @@ -44,7 +39,6 @@ export const useIsQueueMutationInProgress = () => { // }); return ( isLoadingEnqueueBatch || - isLoadingEnqueueGraph || isLoadingResumeProcessor || isLoadingPauseProcessor || isLoadingCancelQueue || diff --git a/invokeai/frontend/web/src/services/api/endpoints/queue.ts b/invokeai/frontend/web/src/services/api/endpoints/queue.ts index ab75964e89..d44e333850 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/queue.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/queue.ts @@ -83,30 +83,6 @@ export const queueApi = api.injectEndpoints({ } }, }), - enqueueGraph: build.mutation< - paths['/api/v1/queue/{queue_id}/enqueue_graph']['post']['responses']['201']['content']['application/json'], - paths['/api/v1/queue/{queue_id}/enqueue_graph']['post']['requestBody']['content']['application/json'] - >({ - query: (arg) => ({ - url: `queue/${$queueId.get()}/enqueue_graph`, - body: arg, - method: 'POST', - }), - invalidatesTags: [ - 'SessionQueueStatus', - 'CurrentSessionQueueItem', - 'NextSessionQueueItem', - ], - onQueryStarted: async (arg, api) => { - const { dispatch, queryFulfilled } = api; - try { - await queryFulfilled; - resetListQueryData(dispatch); - } catch { - // no-op - } - }, - }), resumeProcessor: build.mutation< paths['/api/v1/queue/{queue_id}/processor/resume']['put']['responses']['200']['content']['application/json'], void @@ -341,7 +317,6 @@ export const queueApi = api.injectEndpoints({ export const { useCancelByBatchIdsMutation, - useEnqueueGraphMutation, useEnqueueBatchMutation, usePauseProcessorMutation, useResumeProcessorMutation, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index d4678dc03b..6bc54f0e35 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -5,6 +5,13 @@ export type paths = { + "/api/v1/sessions/{session_id}": { + /** + * Get Session + * @description Gets a session + */ + get: operations["get_session"]; + }; "/api/v1/utilities/dynamicprompts": { /** * Parse Dynamicprompts @@ -275,13 +282,6 @@ export type paths = { */ get: operations["get_invocation_cache_status"]; }; - "/api/v1/queue/{queue_id}/enqueue_graph": { - /** - * Enqueue Graph - * @description Enqueues a graph for single execution. - */ - post: operations["enqueue_graph"]; - }; "/api/v1/queue/{queue_id}/enqueue_batch": { /** * Enqueue Batch @@ -800,17 +800,6 @@ export type components = { */ prepend?: boolean; }; - /** Body_enqueue_graph */ - Body_enqueue_graph: { - /** @description The graph to enqueue */ - graph: components["schemas"]["Graph"]; - /** - * Prepend - * @description Whether or not to prepend this batch in the queue - * @default false - */ - prepend?: boolean; - }; /** Body_import_model */ Body_import_model: { /** @@ -1897,7 +1886,7 @@ export type components = { * Created By * @description The name of the creator of the image */ - created_by: string | null; + created_by?: string | null; /** * Positive Prompt * @description The positive prompt parameter @@ -2476,28 +2465,6 @@ export type components = { */ priority: number; }; - /** EnqueueGraphResult */ - EnqueueGraphResult: { - /** - * Enqueued - * @description The total number of queue items enqueued - */ - enqueued: number; - /** - * Requested - * @description The total number of queue items requested to be enqueued - */ - requested: number; - /** @description The batch that was enqueued */ - batch: components["schemas"]["Batch"]; - /** - * Priority - * @description The priority of the enqueued batch - */ - priority: number; - /** @description The queue item that was enqueued */ - queue_item: components["schemas"]["SessionQueueItemDTO"]; - }; /** * FaceIdentifier * @description Outputs an image with detected face IDs printed on each face. For use with other FaceTools. @@ -3035,7 +3002,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["MainModelLoaderInvocation"]; + [key: string]: components["schemas"]["IntegerInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["InfillColorInvocation"]; }; /** * Edges @@ -3072,7 +3039,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SchedulerOutput"]; + [key: string]: components["schemas"]["String2Output"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["StringPosNegOutput"]; }; /** * Errors @@ -9138,6 +9105,18 @@ export type components = { /** Ui Order */ ui_order: number | null; }; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. @@ -9151,41 +9130,29 @@ export type components = { */ StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusion1ModelFormat + * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; + IPAdapterModelFormat: "invokeai"; /** * CLIPVisionModelFormat * @description An enumeration. * @enum {string} */ CLIPVisionModelFormat: "diffusers"; - /** - * StableDiffusionXLModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; - /** - * IPAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - IPAdapterModelFormat: "invokeai"; /** * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ T2IAdapterModelFormat: "diffusers"; + /** + * StableDiffusionXLModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -9200,6 +9167,36 @@ export type external = Record; export type operations = { + /** + * Get Session + * @description Gets a session + */ + get_session: { + parameters: { + path: { + /** @description The id of the session to get */ + session_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GraphExecutionState"]; + }; + }; + /** @description Session not found */ + 404: { + content: never; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; /** * Parse Dynamicprompts * @description Creates a batch process @@ -10309,43 +10306,6 @@ export type operations = { }; }; }; - /** - * Enqueue Graph - * @description Enqueues a graph for single execution. - */ - enqueue_graph: { - parameters: { - path: { - /** @description The queue id to perform this operation on */ - queue_id: string; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["Body_enqueue_graph"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["EnqueueGraphResult"]; - }; - }; - /** @description Created */ - 201: { - content: { - "application/json": components["schemas"]["EnqueueGraphResult"]; - }; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; /** * Enqueue Batch * @description Processes a batch and enqueues the output graphs for execution. diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 6fda849b89..63617a4eb5 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -26,7 +26,6 @@ export type BatchConfig = paths['/api/v1/queue/{queue_id}/enqueue_batch']['post']['requestBody']['content']['application/json']; export type EnqueueBatchResult = components['schemas']['EnqueueBatchResult']; -export type EnqueueGraphResult = components['schemas']['EnqueueGraphResult']; /** * This is an unsafe type; the object inside is not guaranteed to be valid. From 975ba6b74f51394f78327431062c960e676cf9a9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 08:43:56 +1100 Subject: [PATCH 017/119] fix(ui): use pidi processor for sketch --- .../web/src/features/controlAdapters/store/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index c35847d323..db2311f3f5 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -246,7 +246,7 @@ export const CONTROLNET_MODEL_DEFAULT_PROCESSORS: { mlsd: 'mlsd_image_processor', depth: 'midas_depth_image_processor', bae: 'normalbae_image_processor', - sketch: 'lineart_image_processor', + sketch: 'pidi_image_processor', scribble: 'lineart_image_processor', lineart: 'lineart_image_processor', lineart_anime: 'lineart_anime_image_processor', From 252c9a5f5ab3d3301f8ae912137135a9b66b2c1a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:50:52 +1100 Subject: [PATCH 018/119] fix(backend): fix nsfw/watermarker util types --- .../backend/image_util/invisible_watermark.py | 6 ++--- invokeai/backend/image_util/safety_checker.py | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/invokeai/backend/image_util/invisible_watermark.py b/invokeai/backend/image_util/invisible_watermark.py index 3e8604f9c3..37b3ca918c 100644 --- a/invokeai/backend/image_util/invisible_watermark.py +++ b/invokeai/backend/image_util/invisible_watermark.py @@ -20,12 +20,12 @@ class InvisibleWatermark: """ @classmethod - def invisible_watermark_available(self) -> bool: + def invisible_watermark_available(cls) -> bool: return config.invisible_watermark @classmethod - def add_watermark(self, image: Image, watermark_text: str) -> Image: - if not self.invisible_watermark_available(): + def add_watermark(cls, image: Image.Image, watermark_text: str) -> Image.Image: + if not cls.invisible_watermark_available(): return image logger.debug(f'Applying invisible watermark "{watermark_text}"') bgr = cv2.cvtColor(np.array(image.convert("RGB")), cv2.COLOR_RGB2BGR) diff --git a/invokeai/backend/image_util/safety_checker.py b/invokeai/backend/image_util/safety_checker.py index fd1f05f10e..b9649925e1 100644 --- a/invokeai/backend/image_util/safety_checker.py +++ b/invokeai/backend/image_util/safety_checker.py @@ -26,8 +26,8 @@ class SafetyChecker: tried_load: bool = False @classmethod - def _load_safety_checker(self): - if self.tried_load: + def _load_safety_checker(cls): + if cls.tried_load: return if config.nsfw_checker: @@ -35,31 +35,31 @@ class SafetyChecker: from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker from transformers import AutoFeatureExtractor - self.safety_checker = StableDiffusionSafetyChecker.from_pretrained(config.models_path / CHECKER_PATH) - self.feature_extractor = AutoFeatureExtractor.from_pretrained(config.models_path / CHECKER_PATH) + cls.safety_checker = StableDiffusionSafetyChecker.from_pretrained(config.models_path / CHECKER_PATH) + cls.feature_extractor = AutoFeatureExtractor.from_pretrained(config.models_path / CHECKER_PATH) logger.info("NSFW checker initialized") except Exception as e: logger.warning(f"Could not load NSFW checker: {str(e)}") else: logger.info("NSFW checker loading disabled") - self.tried_load = True + cls.tried_load = True @classmethod - def safety_checker_available(self) -> bool: - self._load_safety_checker() - return self.safety_checker is not None + def safety_checker_available(cls) -> bool: + cls._load_safety_checker() + return cls.safety_checker is not None @classmethod - def has_nsfw_concept(self, image: Image) -> bool: - if not self.safety_checker_available(): + def has_nsfw_concept(cls, image: Image.Image) -> bool: + if not cls.safety_checker_available(): return False device = choose_torch_device() - features = self.feature_extractor([image], return_tensors="pt") + features = cls.feature_extractor([image], return_tensors="pt") features.to(device) - self.safety_checker.to(device) + cls.safety_checker.to(device) x_image = np.array(image).astype(np.float32) / 255.0 x_image = x_image[None].transpose(0, 3, 1, 2) with SilenceWarnings(): - checked_image, has_nsfw_concept = self.safety_checker(images=x_image, clip_input=features.pixel_values) + checked_image, has_nsfw_concept = cls.safety_checker(images=x_image, clip_input=features.pixel_values) return has_nsfw_concept[0] From d27392cc2d9c4ac2ab2b9dd1703cc969daf85884 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Tue, 17 Oct 2023 12:59:48 -0400 Subject: [PATCH 019/119] remove all references to CLI --- docs/CHANGELOG.md | 4 +- CODE_OF_CONDUCT.md => docs/CODE_OF_CONDUCT.md | 0 .../contribution_guides/development.md | 2 +- docs/deprecated/CLI.md | 4 +- docs/{other => deprecated}/TRANSLATION.md | 0 docs/{features => deprecated}/VARIATIONS.md | 2 +- docs/features/CONCEPTS.md | 5 +- docs/features/CONFIGURATION.md | 2 +- docs/features/CONTROLNET.md | 6 +- docs/features/MODEL_MERGING.md | 7 +- docs/features/UTILITIES.md | 10 +- docs/features/index.md | 2 +- docs/index.md | 7 +- docs/installation/050_INSTALLING_MODELS.md | 2 +- .../deprecated_documentation/INSTALL_LINUX.md | 4 +- .../deprecated_documentation/INSTALL_MAC.md | 2 +- .../INSTALL_SOURCE.md | 2 +- .../INSTALL_WINDOWS.md | 4 +- installer/templates/invoke.bat.in | 40 +- installer/templates/invoke.sh.in | 61 +-- invokeai/app/cli/__init__.py | 0 invokeai/app/cli/commands.py | 312 ----------- invokeai/app/cli/completer.py | 171 ------- invokeai/app/cli_app.py | 484 ------------------ mkdocs.yml | 9 +- pyproject.toml | 3 +- 26 files changed, 86 insertions(+), 1059 deletions(-) rename CODE_OF_CONDUCT.md => docs/CODE_OF_CONDUCT.md (100%) rename docs/{other => deprecated}/TRANSLATION.md (100%) rename docs/{features => deprecated}/VARIATIONS.md (97%) delete mode 100644 invokeai/app/cli/__init__.py delete mode 100644 invokeai/app/cli/commands.py delete mode 100644 invokeai/app/cli/completer.py delete mode 100644 invokeai/app/cli_app.py diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ca765b3ca6..24bd5ad7dd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -488,7 +488,7 @@ sections describe what's new for InvokeAI. - A choice of installer scripts that automate installation and configuration. See - [Installation](installation/index.md). + [Installation](installation/INSTALLATION.md). - A streamlined manual installation process that works for both Conda and PIP-only installs. See [Manual Installation](installation/020_INSTALL_MANUAL.md). @@ -657,7 +657,7 @@ sections describe what's new for InvokeAI. ## v1.13 (3 September 2022) -- Support image variations (see [VARIATIONS](features/VARIATIONS.md) +- Support image variations (see [VARIATIONS](deprecated/VARIATIONS.md) ([Kevin Gibbons](https://github.com/bakkot) and many contributors and reviewers) - Supports a Google Colab notebook for a standalone server running on Google diff --git a/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to docs/CODE_OF_CONDUCT.md diff --git a/docs/contributing/contribution_guides/development.md b/docs/contributing/contribution_guides/development.md index 086fd6e90d..2f50d7f579 100644 --- a/docs/contributing/contribution_guides/development.md +++ b/docs/contributing/contribution_guides/development.md @@ -45,5 +45,5 @@ For backend related work, please reach out to **@blessedcoolant**, **@lstein**, ## **What does the Code of Conduct mean for me?** -Our [Code of Conduct](CODE_OF_CONDUCT.md) means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. If you are the victim of any inappropriate behavior or comments as described in our Code of Conduct, we are here for you and will do the best to ensure that the abuser is reprimanded appropriately, per our code. +Our [Code of Conduct](../../CODE_OF_CONDUCT.md) means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. If you are the victim of any inappropriate behavior or comments as described in our Code of Conduct, we are here for you and will do the best to ensure that the abuser is reprimanded appropriately, per our code. diff --git a/docs/deprecated/CLI.md b/docs/deprecated/CLI.md index eaa215c8dd..b40aeffc37 100644 --- a/docs/deprecated/CLI.md +++ b/docs/deprecated/CLI.md @@ -211,8 +211,8 @@ Here are the invoke> command that apply to txt2img: | `--facetool ` | `-ft ` | `-ft gfpgan` | Select face restoration algorithm to use: gfpgan, codeformer | | `--codeformer_fidelity` | `-cf ` | `0.75` | Used along with CodeFormer. Takes values between 0 and 1. 0 produces high quality but low accuracy. 1 produces high accuracy but low quality | | `--save_original` | `-save_orig` | `False` | When upscaling or fixing faces, this will cause the original image to be saved rather than replaced. | -| `--variation ` | `-v` | `0.0` | Add a bit of noise (0.0=none, 1.0=high) to the image in order to generate a series of variations. Usually used in combination with `-S` and `-n` to generate a series a riffs on a starting image. See [Variations](../features/VARIATIONS.md). | -| `--with_variations ` | | `None` | Combine two or more variations. See [Variations](../features/VARIATIONS.md) for now to use this. | +| `--variation ` | `-v` | `0.0` | Add a bit of noise (0.0=none, 1.0=high) to the image in order to generate a series of variations. Usually used in combination with `-S` and `-n` to generate a series a riffs on a starting image. See [Variations](VARIATIONS.md). | +| `--with_variations ` | | `None` | Combine two or more variations. See [Variations](VARIATIONS.md) for now to use this. | | `--save_intermediates ` | | `None` | Save the image from every nth step into an "intermediates" folder inside the output directory | | `--h_symmetry_time_pct ` | | `None` | Create symmetry along the X axis at the desired percent complete of the generation process. (Must be between 0.0 and 1.0; set to a very small number like 0.0001 for just after the first step of generation.) | | `--v_symmetry_time_pct ` | | `None` | Create symmetry along the Y axis at the desired percent complete of the generation process. (Must be between 0.0 and 1.0; set to a very small number like 0.0001 for just after the first step of generation.) | diff --git a/docs/other/TRANSLATION.md b/docs/deprecated/TRANSLATION.md similarity index 100% rename from docs/other/TRANSLATION.md rename to docs/deprecated/TRANSLATION.md diff --git a/docs/features/VARIATIONS.md b/docs/deprecated/VARIATIONS.md similarity index 97% rename from docs/features/VARIATIONS.md rename to docs/deprecated/VARIATIONS.md index e6e21490c8..0c09b71836 100644 --- a/docs/features/VARIATIONS.md +++ b/docs/deprecated/VARIATIONS.md @@ -126,6 +126,6 @@ amounts of image-to-image variation even when the seed is fixed and the `-v` argument is very low. Others are more deterministic. Feel free to experiment until you find the combination that you like. -Also be aware of the [Perlin Noise](OTHER.md#thresholding-and-perlin-noise-initialization-options) +Also be aware of the [Perlin Noise](../features/OTHER.md#thresholding-and-perlin-noise-initialization-options) feature, which provides another way of introducing variability into your image generation requests. diff --git a/docs/features/CONCEPTS.md b/docs/features/CONCEPTS.md index df9ee5bd26..5f3d2d961f 100644 --- a/docs/features/CONCEPTS.md +++ b/docs/features/CONCEPTS.md @@ -28,8 +28,9 @@ by placing them in the designated directory for the compatible model type ### An Example -Here are a few examples to illustrate how it works. All these images were -generated using the command-line client and the Stable Diffusion 1.5 model: +Here are a few examples to illustrate how it works. All these images +were generated using the legacy command-line client and the Stable +Diffusion 1.5 model: | Japanese gardener | Japanese gardener <ghibli-face> | Japanese gardener <hoi4-leaders> | Japanese gardener <cartoona-animals> | | :--------------------------------: | :-----------------------------------: | :------------------------------------: | :----------------------------------------: | diff --git a/docs/features/CONFIGURATION.md b/docs/features/CONFIGURATION.md index cfd65f8a61..f83caf522d 100644 --- a/docs/features/CONFIGURATION.md +++ b/docs/features/CONFIGURATION.md @@ -82,7 +82,7 @@ format of YAML files can be found [here](https://circleci.com/blog/what-is-yaml-a-beginner-s-guide/). You can fix a broken `invokeai.yaml` by deleting it and running the -configuration script again -- option [7] in the launcher, "Re-run the +configuration script again -- option [6] in the launcher, "Re-run the configure script". #### Reading Environment Variables diff --git a/docs/features/CONTROLNET.md b/docs/features/CONTROLNET.md index 8284ddf75d..d287e6cb19 100644 --- a/docs/features/CONTROLNET.md +++ b/docs/features/CONTROLNET.md @@ -46,7 +46,7 @@ Diffuser-style ControlNet models are available at HuggingFace (http://huggingface.co) and accessed via their repo IDs (identifiers in the format "author/modelname"). The easiest way to install them is to use the InvokeAI model installer application. Use the -`invoke.sh`/`invoke.bat` launcher to select item [5] and then navigate +`invoke.sh`/`invoke.bat` launcher to select item [4] and then navigate to the CONTROLNETS section. Select the models you wish to install and press "APPLY CHANGES". You may also enter additional HuggingFace repo_ids in the "Additional models" textbox: @@ -145,8 +145,8 @@ Additionally, each ControlNet section can be expanded in order to manipulate set #### Installation There are several ways to install IP-Adapter models with an existing InvokeAI installation: -1. Through the command line interface launched from the invoke.sh / invoke.bat scripts, option [5] to download models. -2. Through the Model Manager UI with models from the *Tools* section of [www.models.invoke.ai](www.models.invoke.ai). To do this, copy the repo ID from the desired model page, and paste it in the Add Model field of the model manager. **Note** Both the IP-Adapter and the Image Encoder must be installed for IP-Adapter to work. For example, the [SD 1.5 IP-Adapter](https://models.invoke.ai/InvokeAI/ip_adapter_plus_sd15) and [SD1.5 Image Encoder](https://models.invoke.ai/InvokeAI/ip_adapter_sd_image_encoder) must be installed to use IP-Adapter with SD1.5 based models. +1. Through the command line interface launched from the invoke.sh / invoke.bat scripts, option [4] to download models. +2. Through the Model Manager UI with models from the *Tools* section of [www.models.invoke.ai](https://www.models.invoke.ai). To do this, copy the repo ID from the desired model page, and paste it in the Add Model field of the model manager. **Note** Both the IP-Adapter and the Image Encoder must be installed for IP-Adapter to work. For example, the [SD 1.5 IP-Adapter](https://models.invoke.ai/InvokeAI/ip_adapter_plus_sd15) and [SD1.5 Image Encoder](https://models.invoke.ai/InvokeAI/ip_adapter_sd_image_encoder) must be installed to use IP-Adapter with SD1.5 based models. 3. **Advanced -- Not recommended ** Manually downloading the IP-Adapter and Image Encoder files - Image Encoder folders shouid be placed in the `models\any\clip_vision` folders. IP Adapter Model folders should be placed in the relevant `ip-adapter` folder of relevant base model folder of Invoke root directory. For example, for the SDXL IP-Adapter, files should be added to the `model/sdxl/ip_adapter/` folder. #### Using IP-Adapter diff --git a/docs/features/MODEL_MERGING.md b/docs/features/MODEL_MERGING.md index 6adf4db16a..e384662ef5 100644 --- a/docs/features/MODEL_MERGING.md +++ b/docs/features/MODEL_MERGING.md @@ -16,9 +16,10 @@ Model Merging can be be done by navigating to the Model Manager and clicking the display all the diffusers-style models that InvokeAI knows about. If you do not see the model you are looking for, then it is probably a legacy checkpoint model and needs to be converted using the - `invoke` command-line client and its `!optimize` command. You - must select at least two models to merge. The third can be left at - "None" if you desire. + "Convert" option in the Web-based Model Manager tab. + + You must select at least two models to merge. The third can be left + at "None" if you desire. * Alpha: This is the ratio to use when combining models. It ranges from 0 to 1. The higher the value, the more weight is given to the diff --git a/docs/features/UTILITIES.md b/docs/features/UTILITIES.md index a73118d55a..2d62fe3a79 100644 --- a/docs/features/UTILITIES.md +++ b/docs/features/UTILITIES.md @@ -8,7 +8,7 @@ title: Command-line Utilities InvokeAI comes with several scripts that are accessible via the command line. To access these commands, start the "developer's -console" from the launcher (`invoke.bat` menu item [8]). Users who are +console" from the launcher (`invoke.bat` menu item [7]). Users who are familiar with Python can alternatively activate InvokeAI's virtual environment (typically, but not necessarily `invokeai/.venv`). @@ -34,7 +34,7 @@ invokeai-web --ram 7 ## **invokeai-merge** -This is the model merge script, the same as launcher option [4]. Call +This is the model merge script, the same as launcher option [3]. Call it with the `--gui` command-line argument to start the interactive console-based GUI. Alternatively, you can run it non-interactively using command-line arguments as illustrated in the example below which @@ -48,7 +48,7 @@ invokeai-merge --force --base-model sd-1 --models stable-diffusion-1.5 inkdiffus ## **invokeai-ti** This is the textual inversion training script that is run by launcher -option [3]. Call it with `--gui` to run the interactive console-based +option [2]. Call it with `--gui` to run the interactive console-based front end. It can also be run non-interactively. It has about a zillion arguments, but a typical training session can be launched with: @@ -68,7 +68,7 @@ in Windows). ## **invokeai-install** This is the console-based model install script that is run by launcher -option [5]. If called without arguments, it will launch the +option [4]. If called without arguments, it will launch the interactive console-based interface. It can also be used non-interactively to list, add and remove models as shown by these examples: @@ -148,7 +148,7 @@ launch the web server against it with `invokeai-web --root InvokeAI-New`. ## **invokeai-update** This is the interactive console-based script that is run by launcher -menu item [9] to update to a new version of InvokeAI. It takes no +menu item [8] to update to a new version of InvokeAI. It takes no command-line arguments. ## **invokeai-metadata** diff --git a/docs/features/index.md b/docs/features/index.md index bd37366314..6315b20ca5 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -28,7 +28,7 @@ Learn how to install and use ControlNet models for fine control over image output. ### * [Image-to-Image Guide](IMG2IMG.md) -Use a seed image to build new creations in the CLI. +Use a seed image to build new creations. ## Model Management diff --git a/docs/index.md b/docs/index.md index 9a426e5684..8c9ed5b7f8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -143,7 +143,6 @@ Mac and Linux machines, and runs on GPU cards with as little as 4 GB of RAM. ### Prompt Engineering - [Prompt Syntax](features/PROMPTS.md) -- [Generating Variations](features/VARIATIONS.md) ### InvokeAI Configuration - [Guide to InvokeAI Runtime Settings](features/CONFIGURATION.md) @@ -166,10 +165,8 @@ still a work in progress, but coming soon. ### Command-Line Interface Retired -The original "invokeai" command-line interface has been retired. The -`invokeai` command will now launch a new command-line client that can -be used by developers to create and test nodes. It is not intended to -be used for routine image generation or manipulation. +All "invokeai" command-line interfaces have been retired as of version +3.4. To launch the Web GUI from the command-line, use the command `invokeai-web` rather than the traditional `invokeai --web`. diff --git a/docs/installation/050_INSTALLING_MODELS.md b/docs/installation/050_INSTALLING_MODELS.md index d455d2146f..5333e2aa88 100644 --- a/docs/installation/050_INSTALLING_MODELS.md +++ b/docs/installation/050_INSTALLING_MODELS.md @@ -84,7 +84,7 @@ InvokeAI root directory's `autoimport` folder. ### Installation via `invokeai-model-install` -From the `invoke` launcher, choose option [5] "Download and install +From the `invoke` launcher, choose option [4] "Download and install models." This will launch the same script that prompted you to select models at install time. You can use this to add models that you skipped the first time around. It is all right to specify a model that diff --git a/docs/installation/deprecated_documentation/INSTALL_LINUX.md b/docs/installation/deprecated_documentation/INSTALL_LINUX.md index 1e66698ec2..97060f85ad 100644 --- a/docs/installation/deprecated_documentation/INSTALL_LINUX.md +++ b/docs/installation/deprecated_documentation/INSTALL_LINUX.md @@ -79,7 +79,7 @@ title: Manual Installation, Linux and obtaining an access token for downloading. It will then download and install the weights files for you. - Please look [here](../INSTALL_MANUAL.md) for a manual process for doing + Please look [here](../020_INSTALL_MANUAL.md) for a manual process for doing the same thing. 7. Start generating images! @@ -112,7 +112,7 @@ title: Manual Installation, Linux To use an alternative model you may invoke the `!switch` command in the CLI, or pass `--model ` during `invoke.py` launch for either the CLI or the Web UI. See [Command Line - Client](../../features/CLI.md#model-selection-and-importation). The + Client](../../deprecated/CLI.md#model-selection-and-importation). The model names are defined in `configs/models.yaml`. 8. Subsequently, to relaunch the script, be sure to run "conda activate diff --git a/docs/installation/deprecated_documentation/INSTALL_MAC.md b/docs/installation/deprecated_documentation/INSTALL_MAC.md index 7a3c5b564f..dea3c329a7 100644 --- a/docs/installation/deprecated_documentation/INSTALL_MAC.md +++ b/docs/installation/deprecated_documentation/INSTALL_MAC.md @@ -150,7 +150,7 @@ will do our best to help. To use an alternative model you may invoke the `!switch` command in the CLI, or pass `--model ` during `invoke.py` launch for either the CLI or the Web UI. See [Command Line - Client](../../features/CLI.md#model-selection-and-importation). The + Client](../../deprecated/CLI.md#model-selection-and-importation). The model names are defined in `configs/models.yaml`. --- diff --git a/docs/installation/deprecated_documentation/INSTALL_SOURCE.md b/docs/installation/deprecated_documentation/INSTALL_SOURCE.md index 2b1b750fbf..b71cd68ab7 100644 --- a/docs/installation/deprecated_documentation/INSTALL_SOURCE.md +++ b/docs/installation/deprecated_documentation/INSTALL_SOURCE.md @@ -128,7 +128,7 @@ python scripts/invoke.py --web --max_load_models=3 \ ``` These options are described in detail in the -[Command-Line Interface](../../features/CLI.md) documentation. +[Command-Line Interface](../../deprecated/CLI.md) documentation. ## Troubleshooting diff --git a/docs/installation/deprecated_documentation/INSTALL_WINDOWS.md b/docs/installation/deprecated_documentation/INSTALL_WINDOWS.md index 19acb832e4..9536f09db2 100644 --- a/docs/installation/deprecated_documentation/INSTALL_WINDOWS.md +++ b/docs/installation/deprecated_documentation/INSTALL_WINDOWS.md @@ -75,7 +75,7 @@ Note that you will need NVIDIA drivers, Python 3.10, and Git installed beforehan obtaining an access token for downloading. It will then download and install the weights files for you. - Please look [here](../INSTALL_MANUAL.md) for a manual process for doing the + Please look [here](../020_INSTALL_MANUAL.md) for a manual process for doing the same thing. 8. Start generating images! @@ -108,7 +108,7 @@ Note that you will need NVIDIA drivers, Python 3.10, and Git installed beforehan To use an alternative model you may invoke the `!switch` command in the CLI, or pass `--model ` during `invoke.py` launch for either the CLI or the Web UI. See [Command Line - Client](../../features/CLI.md#model-selection-and-importation). The + Client](../../deprecated/CLI.md#model-selection-and-importation). The model names are defined in `configs/models.yaml`. 9. Subsequently, to relaunch the script, first activate the Anaconda diff --git a/installer/templates/invoke.bat.in b/installer/templates/invoke.bat.in index 227091b33a..ee6d56fc56 100644 --- a/installer/templates/invoke.bat.in +++ b/installer/templates/invoke.bat.in @@ -9,41 +9,37 @@ set INVOKEAI_ROOT=. :start echo Desired action: echo 1. Generate images with the browser-based interface -echo 2. Explore InvokeAI nodes using a command-line interface -echo 3. Run textual inversion training -echo 4. Merge models (diffusers type only) -echo 5. Download and install models -echo 6. Change InvokeAI startup options -echo 7. Re-run the configure script to fix a broken install or to complete a major upgrade -echo 8. Open the developer console -echo 9. Update InvokeAI -echo 10. Run the InvokeAI image database maintenance script -echo 11. Command-line help +echo 2. Run textual inversion training +echo 3. Merge models (diffusers type only) +echo 4. Download and install models +echo 5. Change InvokeAI startup options +echo 6. Re-run the configure script to fix a broken install or to complete a major upgrade +echo 7. Open the developer console +echo 8. Update InvokeAI +echo 9. Run the InvokeAI image database maintenance script +echo 10. Command-line help echo Q - Quit -set /P choice="Please enter 1-11, Q: [1] " +set /P choice="Please enter 1-10, Q: [1] " if not defined choice set choice=1 IF /I "%choice%" == "1" ( echo Starting the InvokeAI browser-based UI.. python .venv\Scripts\invokeai-web.exe %* ) ELSE IF /I "%choice%" == "2" ( - echo Starting the InvokeAI command-line.. - python .venv\Scripts\invokeai.exe %* -) ELSE IF /I "%choice%" == "3" ( echo Starting textual inversion training.. python .venv\Scripts\invokeai-ti.exe --gui -) ELSE IF /I "%choice%" == "4" ( +) ELSE IF /I "%choice%" == "3" ( echo Starting model merging script.. python .venv\Scripts\invokeai-merge.exe --gui -) ELSE IF /I "%choice%" == "5" ( +) ELSE IF /I "%choice%" == "4" ( echo Running invokeai-model-install... python .venv\Scripts\invokeai-model-install.exe -) ELSE IF /I "%choice%" == "6" ( +) ELSE IF /I "%choice%" == "5" ( echo Running invokeai-configure... python .venv\Scripts\invokeai-configure.exe --skip-sd-weight --skip-support-models -) ELSE IF /I "%choice%" == "7" ( +) ELSE IF /I "%choice%" == "6" ( echo Running invokeai-configure... python .venv\Scripts\invokeai-configure.exe --yes --skip-sd-weight -) ELSE IF /I "%choice%" == "8" ( +) ELSE IF /I "%choice%" == "7" ( echo Developer Console echo Python command is: where python @@ -55,13 +51,13 @@ IF /I "%choice%" == "1" ( echo ************************* echo *** Type `exit` to quit this shell and deactivate the Python virtual environment *** call cmd /k -) ELSE IF /I "%choice%" == "9" ( +) ELSE IF /I "%choice%" == "8" ( echo Running invokeai-update... python -m invokeai.frontend.install.invokeai_update -) ELSE IF /I "%choice%" == "10" ( +) ELSE IF /I "%choice%" == "9" ( echo Running the db maintenance script... python .venv\Scripts\invokeai-db-maintenance.exe -) ELSE IF /I "%choice%" == "11" ( +) ELSE IF /I "%choice%" == "10" ( echo Displaying command line help... python .venv\Scripts\invokeai-web.exe --help %* pause diff --git a/installer/templates/invoke.sh.in b/installer/templates/invoke.sh.in index 6cf6967608..3230c9f442 100644 --- a/installer/templates/invoke.sh.in +++ b/installer/templates/invoke.sh.in @@ -58,52 +58,47 @@ do_choice() { invokeai-web $PARAMS ;; 2) - clear - printf "Explore InvokeAI nodes using a command-line interface\n" - invokeai $PARAMS - ;; - 3) clear printf "Textual inversion training\n" invokeai-ti --gui $PARAMS ;; - 4) + 3) clear printf "Merge models (diffusers type only)\n" invokeai-merge --gui $PARAMS ;; - 5) + 4) clear printf "Download and install models\n" invokeai-model-install --root ${INVOKEAI_ROOT} ;; - 6) + 5) clear printf "Change InvokeAI startup options\n" invokeai-configure --root ${INVOKEAI_ROOT} --skip-sd-weights --skip-support-models ;; - 7) + 6) clear printf "Re-run the configure script to fix a broken install or to complete a major upgrade\n" invokeai-configure --root ${INVOKEAI_ROOT} --yes --default_only --skip-sd-weights ;; - 8) + 7) clear printf "Open the developer console\n" file_name=$(basename "${BASH_SOURCE[0]}") bash --init-file "$file_name" ;; - 9) + 8) clear printf "Update InvokeAI\n" python -m invokeai.frontend.install.invokeai_update ;; - 10) + 9) clear printf "Running the db maintenance script\n" invokeai-db-maintenance --root ${INVOKEAI_ROOT} ;; - 11) + 10) clear printf "Command-line help\n" invokeai-web --help @@ -121,16 +116,15 @@ do_choice() { do_dialog() { options=( 1 "Generate images with a browser-based interface" - 2 "Explore InvokeAI nodes using a command-line interface" - 3 "Textual inversion training" - 4 "Merge models (diffusers type only)" - 5 "Download and install models" - 6 "Change InvokeAI startup options" - 7 "Re-run the configure script to fix a broken install or to complete a major upgrade" - 8 "Open the developer console" - 9 "Update InvokeAI" - 10 "Run the InvokeAI image database maintenance script" - 11 "Command-line help" + 2 "Textual inversion training" + 3 "Merge models (diffusers type only)" + 4 "Download and install models" + 5 "Change InvokeAI startup options" + 6 "Re-run the configure script to fix a broken install or to complete a major upgrade" + 7 "Open the developer console" + 8 "Update InvokeAI" + 9 "Run the InvokeAI image database maintenance script" + 10 "Command-line help" ) choice=$(dialog --clear \ @@ -155,18 +149,17 @@ do_line_input() { printf " ** For a more attractive experience, please install the 'dialog' utility using your package manager. **\n\n" printf "What would you like to do?\n" printf "1: Generate images using the browser-based interface\n" - printf "2: Explore InvokeAI nodes using the command-line interface\n" - printf "3: Run textual inversion training\n" - printf "4: Merge models (diffusers type only)\n" - printf "5: Download and install models\n" - printf "6: Change InvokeAI startup options\n" - printf "7: Re-run the configure script to fix a broken install\n" - printf "8: Open the developer console\n" - printf "9: Update InvokeAI\n" - printf "10: Run the InvokeAI image database maintenance script\n" - printf "11: Command-line help\n" + printf "2: Run textual inversion training\n" + printf "3: Merge models (diffusers type only)\n" + printf "4: Download and install models\n" + printf "5: Change InvokeAI startup options\n" + printf "6: Re-run the configure script to fix a broken install\n" + printf "7: Open the developer console\n" + printf "8: Update InvokeAI\n" + printf "9: Run the InvokeAI image database maintenance script\n" + printf "10: Command-line help\n" printf "Q: Quit\n\n" - read -p "Please enter 1-11, Q: [1] " yn + read -p "Please enter 1-10, Q: [1] " yn choice=${yn:='1'} do_choice $choice clear diff --git a/invokeai/app/cli/__init__.py b/invokeai/app/cli/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/invokeai/app/cli/commands.py b/invokeai/app/cli/commands.py deleted file mode 100644 index c21c6315ed..0000000000 --- a/invokeai/app/cli/commands.py +++ /dev/null @@ -1,312 +0,0 @@ -# Copyright (c) 2023 Kyle Schouviller (https://github.com/kyle0654) - -import argparse -from abc import ABC, abstractmethod -from typing import Any, Callable, Iterable, Literal, Union, get_args, get_origin, get_type_hints - -import matplotlib.pyplot as plt -import networkx as nx -from pydantic import BaseModel, Field - -import invokeai.backend.util.logging as logger - -from ..invocations.baseinvocation import BaseInvocation -from ..invocations.image import ImageField -from ..services.graph import Edge, GraphExecutionState, LibraryGraph -from ..services.invoker import Invoker - - -def add_field_argument(command_parser, name: str, field, default_override=None): - default = ( - default_override - if default_override is not None - else field.default - if field.default_factory is None - else field.default_factory() - ) - if get_origin(field.annotation) == Literal: - allowed_values = get_args(field.annotation) - allowed_types = set() - for val in allowed_values: - allowed_types.add(type(val)) - allowed_types_list = list(allowed_types) - field_type = allowed_types_list[0] if len(allowed_types) == 1 else Union[allowed_types_list] # type: ignore - - command_parser.add_argument( - f"--{name}", - dest=name, - type=field_type, - default=default, - choices=allowed_values, - help=field.description, - ) - else: - command_parser.add_argument( - f"--{name}", - dest=name, - type=field.annotation, - default=default, - help=field.description, - ) - - -def add_parsers( - subparsers, - commands: list[type], - command_field: str = "type", - exclude_fields: list[str] = ["id", "type"], - add_arguments: Union[Callable[[argparse.ArgumentParser], None], None] = None, -): - """Adds parsers for each command to the subparsers""" - - # Create subparsers for each command - for command in commands: - hints = get_type_hints(command) - cmd_name = get_args(hints[command_field])[0] - command_parser = subparsers.add_parser(cmd_name, help=command.__doc__) - - if add_arguments is not None: - add_arguments(command_parser) - - # Convert all fields to arguments - fields = command.__fields__ # type: ignore - for name, field in fields.items(): - if name in exclude_fields: - continue - - add_field_argument(command_parser, name, field) - - -def add_graph_parsers( - subparsers, graphs: list[LibraryGraph], add_arguments: Union[Callable[[argparse.ArgumentParser], None], None] = None -): - for graph in graphs: - command_parser = subparsers.add_parser(graph.name, help=graph.description) - - if add_arguments is not None: - add_arguments(command_parser) - - # Add arguments for inputs - for exposed_input in graph.exposed_inputs: - node = graph.graph.get_node(exposed_input.node_path) - field = node.__fields__[exposed_input.field] - default_override = getattr(node, exposed_input.field) - add_field_argument(command_parser, exposed_input.alias, field, default_override) - - -class CliContext: - invoker: Invoker - session: GraphExecutionState - parser: argparse.ArgumentParser - defaults: dict[str, Any] - graph_nodes: dict[str, str] - nodes_added: list[str] - - def __init__(self, invoker: Invoker, session: GraphExecutionState, parser: argparse.ArgumentParser): - self.invoker = invoker - self.session = session - self.parser = parser - self.defaults = dict() - self.graph_nodes = dict() - self.nodes_added = list() - - def get_session(self): - self.session = self.invoker.services.graph_execution_manager.get(self.session.id) - return self.session - - def reset(self): - self.session = self.invoker.create_execution_state() - self.graph_nodes = dict() - self.nodes_added = list() - # Leave defaults unchanged - - def add_node(self, node: BaseInvocation): - self.get_session() - self.session.graph.add_node(node) - self.nodes_added.append(node.id) - self.invoker.services.graph_execution_manager.set(self.session) - - def add_edge(self, edge: Edge): - self.get_session() - self.session.add_edge(edge) - self.invoker.services.graph_execution_manager.set(self.session) - - -class ExitCli(Exception): - """Exception to exit the CLI""" - - pass - - -class BaseCommand(ABC, BaseModel): - """A CLI command""" - - # All commands must include a type name like this: - - @classmethod - def get_all_subclasses(cls): - subclasses = [] - toprocess = [cls] - while len(toprocess) > 0: - next = toprocess.pop(0) - next_subclasses = next.__subclasses__() - subclasses.extend(next_subclasses) - toprocess.extend(next_subclasses) - return subclasses - - @classmethod - def get_commands(cls): - return tuple(BaseCommand.get_all_subclasses()) - - @classmethod - def get_commands_map(cls): - # Get the type strings out of the literals and into a dictionary - return dict(map(lambda t: (get_args(get_type_hints(t)["type"])[0], t), BaseCommand.get_all_subclasses())) - - @abstractmethod - def run(self, context: CliContext) -> None: - """Run the command. Raise ExitCli to exit.""" - pass - - -class ExitCommand(BaseCommand): - """Exits the CLI""" - - type: Literal["exit"] = "exit" - - def run(self, context: CliContext) -> None: - raise ExitCli() - - -class HelpCommand(BaseCommand): - """Shows help""" - - type: Literal["help"] = "help" - - def run(self, context: CliContext) -> None: - context.parser.print_help() - - -def get_graph_execution_history( - graph_execution_state: GraphExecutionState, -) -> Iterable[str]: - """Gets the history of fully-executed invocations for a graph execution""" - return (n for n in reversed(graph_execution_state.executed_history) if n in graph_execution_state.graph.nodes) - - -def get_invocation_command(invocation) -> str: - fields = invocation.__fields__.items() - type_hints = get_type_hints(type(invocation)) - command = [invocation.type] - for name, field in fields: - if name in ["id", "type"]: - continue - - # TODO: add links - - # Skip image fields when serializing command - type_hint = type_hints.get(name) or None - if type_hint is ImageField or ImageField in get_args(type_hint): - continue - - field_value = getattr(invocation, name) - field_default = field.default - if field_value != field_default: - if type_hint is str or str in get_args(type_hint): - command.append(f'--{name} "{field_value}"') - else: - command.append(f"--{name} {field_value}") - - return " ".join(command) - - -class HistoryCommand(BaseCommand): - """Shows the invocation history""" - - type: Literal["history"] = "history" - - # Inputs - # fmt: off - count: int = Field(default=5, gt=0, description="The number of history entries to show") - # fmt: on - - def run(self, context: CliContext) -> None: - history = list(get_graph_execution_history(context.get_session())) - for i in range(min(self.count, len(history))): - entry_id = history[-1 - i] - entry = context.get_session().graph.get_node(entry_id) - logger.info(f"{entry_id}: {get_invocation_command(entry)}") - - -class SetDefaultCommand(BaseCommand): - """Sets a default value for a field""" - - type: Literal["default"] = "default" - - # Inputs - # fmt: off - field: str = Field(description="The field to set the default for") - value: str = Field(description="The value to set the default to, or None to clear the default") - # fmt: on - - def run(self, context: CliContext) -> None: - if self.value is None: - if self.field in context.defaults: - del context.defaults[self.field] - else: - context.defaults[self.field] = self.value - - -class DrawGraphCommand(BaseCommand): - """Debugs a graph""" - - type: Literal["draw_graph"] = "draw_graph" - - def run(self, context: CliContext) -> None: - session: GraphExecutionState = context.invoker.services.graph_execution_manager.get(context.session.id) - nxgraph = session.graph.nx_graph_flat() - - # Draw the networkx graph - plt.figure(figsize=(20, 20)) - pos = nx.spectral_layout(nxgraph) - nx.draw_networkx_nodes(nxgraph, pos, node_size=1000) - nx.draw_networkx_edges(nxgraph, pos, width=2) - nx.draw_networkx_labels(nxgraph, pos, font_size=20, font_family="sans-serif") - plt.axis("off") - plt.show() - - -class DrawExecutionGraphCommand(BaseCommand): - """Debugs an execution graph""" - - type: Literal["draw_xgraph"] = "draw_xgraph" - - def run(self, context: CliContext) -> None: - session: GraphExecutionState = context.invoker.services.graph_execution_manager.get(context.session.id) - nxgraph = session.execution_graph.nx_graph_flat() - - # Draw the networkx graph - plt.figure(figsize=(20, 20)) - pos = nx.spectral_layout(nxgraph) - nx.draw_networkx_nodes(nxgraph, pos, node_size=1000) - nx.draw_networkx_edges(nxgraph, pos, width=2) - nx.draw_networkx_labels(nxgraph, pos, font_size=20, font_family="sans-serif") - plt.axis("off") - plt.show() - - -class SortedHelpFormatter(argparse.HelpFormatter): - def _iter_indented_subactions(self, action): - try: - get_subactions = action._get_subactions - except AttributeError: - pass - else: - self._indent() - if isinstance(action, argparse._SubParsersAction): - for subaction in sorted(get_subactions(), key=lambda x: x.dest): - yield subaction - else: - for subaction in get_subactions(): - yield subaction - self._dedent() diff --git a/invokeai/app/cli/completer.py b/invokeai/app/cli/completer.py deleted file mode 100644 index 5aece8a058..0000000000 --- a/invokeai/app/cli/completer.py +++ /dev/null @@ -1,171 +0,0 @@ -""" -Readline helper functions for cli_app.py -You may import the global singleton `completer` to get access to the -completer object. -""" -import atexit -import readline -import shlex -from pathlib import Path -from typing import Dict, List, Literal, get_args, get_origin, get_type_hints - -import invokeai.backend.util.logging as logger - -from ...backend import ModelManager -from ..invocations.baseinvocation import BaseInvocation -from ..services.invocation_services import InvocationServices -from .commands import BaseCommand - -# singleton object, class variable -completer = None - - -class Completer(object): - def __init__(self, model_manager: ModelManager): - self.commands = self.get_commands() - self.matches = None - self.linebuffer = None - self.manager = model_manager - return - - def complete(self, text, state): - """ - Complete commands and switches fromm the node CLI command line. - Switches are determined in a context-specific manner. - """ - - buffer = readline.get_line_buffer() - if state == 0: - options = None - try: - current_command, current_switch = self.get_current_command(buffer) - options = self.get_command_options(current_command, current_switch) - except IndexError: - pass - options = options or list(self.parse_commands().keys()) - - if not text: # first time - self.matches = options - else: - self.matches = [s for s in options if s and s.startswith(text)] - - try: - match = self.matches[state] - except IndexError: - match = None - return match - - @classmethod - def get_commands(self) -> List[object]: - """ - Return a list of all the client commands and invocations. - """ - return BaseCommand.get_commands() + BaseInvocation.get_invocations() - - def get_current_command(self, buffer: str) -> tuple[str, str]: - """ - Parse the readline buffer to find the most recent command and its switch. - """ - if len(buffer) == 0: - return None, None - tokens = shlex.split(buffer) - command = None - switch = None - for t in tokens: - if t[0].isalpha(): - if switch is None: - command = t - else: - switch = t - # don't try to autocomplete switches that are already complete - if switch and buffer.endswith(" "): - switch = None - return command or "", switch or "" - - def parse_commands(self) -> Dict[str, List[str]]: - """ - Return a dict in which the keys are the command name - and the values are the parameters the command takes. - """ - result = dict() - for command in self.commands: - hints = get_type_hints(command) - name = get_args(hints["type"])[0] - result.update({name: hints}) - return result - - def get_command_options(self, command: str, switch: str) -> List[str]: - """ - Return all the parameters that can be passed to the command as - command-line switches. Returns None if the command is unrecognized. - """ - parsed_commands = self.parse_commands() - if command not in parsed_commands: - return None - - # handle switches in the format "-foo=bar" - argument = None - if switch and "=" in switch: - switch, argument = switch.split("=") - - parameter = switch.strip("-") - if parameter in parsed_commands[command]: - if argument is None: - return self.get_parameter_options(parameter, parsed_commands[command][parameter]) - else: - return [ - f"--{parameter}={x}" - for x in self.get_parameter_options(parameter, parsed_commands[command][parameter]) - ] - else: - return [f"--{x}" for x in parsed_commands[command].keys()] - - def get_parameter_options(self, parameter: str, typehint) -> List[str]: - """ - Given a parameter type (such as Literal), offers autocompletions. - """ - if get_origin(typehint) == Literal: - return get_args(typehint) - if parameter == "model": - return self.manager.model_names() - - def _pre_input_hook(self): - if self.linebuffer: - readline.insert_text(self.linebuffer) - readline.redisplay() - self.linebuffer = None - - -def set_autocompleter(services: InvocationServices) -> Completer: - global completer - - if completer: - return completer - - completer = Completer(services.model_manager) - - readline.set_completer(completer.complete) - try: - readline.set_auto_history(True) - except AttributeError: - # pyreadline3 does not have a set_auto_history() method - pass - readline.set_pre_input_hook(completer._pre_input_hook) - readline.set_completer_delims(" ") - readline.parse_and_bind("tab: complete") - readline.parse_and_bind("set print-completions-horizontally off") - readline.parse_and_bind("set page-completions on") - readline.parse_and_bind("set skip-completed-text on") - readline.parse_and_bind("set show-all-if-ambiguous on") - - histfile = Path(services.configuration.root_dir / ".invoke_history") - try: - readline.read_history_file(histfile) - readline.set_history_length(1000) - except FileNotFoundError: - pass - except OSError: # file likely corrupted - newname = f"{histfile}.old" - logger.error(f"Your history file {histfile} couldn't be loaded and may be corrupted. Renaming it to {newname}") - histfile.replace(Path(newname)) - atexit.register(readline.write_history_file, histfile) diff --git a/invokeai/app/cli_app.py b/invokeai/app/cli_app.py deleted file mode 100644 index 2f8a4d2cbd..0000000000 --- a/invokeai/app/cli_app.py +++ /dev/null @@ -1,484 +0,0 @@ -# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team - -from invokeai.app.services.invocation_cache.invocation_cache_memory import MemoryInvocationCache - -from .services.config import InvokeAIAppConfig - -# parse_args() must be called before any other imports. if it is not called first, consumers of the config -# which are imported/used before parse_args() is called will get the default config values instead of the -# values from the command line or config file. - -if True: # hack to make flake8 happy with imports coming after setting up the config - import argparse - import re - import shlex - import sqlite3 - import sys - import time - from typing import Optional, Union, get_type_hints - - import torch - from pydantic import BaseModel, ValidationError - from pydantic.fields import Field - - import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) - from invokeai.app.services.board_image_record_storage import SqliteBoardImageRecordStorage - from invokeai.app.services.board_images import BoardImagesService, BoardImagesServiceDependencies - from invokeai.app.services.board_record_storage import SqliteBoardRecordStorage - from invokeai.app.services.boards import BoardService, BoardServiceDependencies - from invokeai.app.services.image_record_storage import SqliteImageRecordStorage - from invokeai.app.services.images import ImageService, ImageServiceDependencies - from invokeai.app.services.invocation_stats import InvocationStatsService - from invokeai.app.services.resource_name import SimpleNameService - from invokeai.app.services.urls import LocalUrlService - from invokeai.backend.util.logging import InvokeAILogger - from invokeai.version.invokeai_version import __version__ - - from .cli.commands import BaseCommand, CliContext, ExitCli, SortedHelpFormatter, add_graph_parsers, add_parsers - from .cli.completer import set_autocompleter - from .invocations.baseinvocation import BaseInvocation - from .services.default_graphs import create_system_graphs, default_text_to_image_graph_id - from .services.events import EventServiceBase - from .services.graph import ( - Edge, - EdgeConnection, - GraphExecutionState, - GraphInvocation, - LibraryGraph, - are_connection_types_compatible, - ) - from .services.image_file_storage import DiskImageFileStorage - from .services.invocation_queue import MemoryInvocationQueue - from .services.invocation_services import InvocationServices - from .services.invoker import Invoker - from .services.latent_storage import DiskLatentsStorage, ForwardCacheLatentsStorage - from .services.model_manager_service import ModelManagerService - from .services.processor import DefaultInvocationProcessor - from .services.sqlite import SqliteItemStorage - - if torch.backends.mps.is_available(): - import invokeai.backend.util.mps_fixes # noqa: F401 (monkeypatching on import) - -config = InvokeAIAppConfig.get_config() -config.parse_args() -logger = InvokeAILogger().get_logger(config=config) - - -class CliCommand(BaseModel): - command: Union[BaseCommand.get_commands() + BaseInvocation.get_invocations()] = Field(discriminator="type") # type: ignore - - -class InvalidArgs(Exception): - pass - - -def add_invocation_args(command_parser): - # Add linking capability - command_parser.add_argument( - "--link", - "-l", - action="append", - nargs=3, - help="A link in the format 'source_node source_field dest_field'. source_node can be relative to history (e.g. -1)", - ) - - command_parser.add_argument( - "--link_node", - "-ln", - action="append", - help="A link from all fields in the specified node. Node can be relative to history (e.g. -1)", - ) - - -def get_command_parser(services: InvocationServices) -> argparse.ArgumentParser: - # Create invocation parser - parser = argparse.ArgumentParser(formatter_class=SortedHelpFormatter) - - def exit(*args, **kwargs): - raise InvalidArgs - - parser.exit = exit - subparsers = parser.add_subparsers(dest="type") - - # Create subparsers for each invocation - invocations = BaseInvocation.get_all_subclasses() - add_parsers(subparsers, invocations, add_arguments=add_invocation_args) - - # Create subparsers for each command - commands = BaseCommand.get_all_subclasses() - add_parsers(subparsers, commands, exclude_fields=["type"]) - - # Create subparsers for exposed CLI graphs - # TODO: add a way to identify these graphs - text_to_image = services.graph_library.get(default_text_to_image_graph_id) - add_graph_parsers(subparsers, [text_to_image], add_arguments=add_invocation_args) - - return parser - - -class NodeField: - alias: str - node_path: str - field: str - field_type: type - - def __init__(self, alias: str, node_path: str, field: str, field_type: type): - self.alias = alias - self.node_path = node_path - self.field = field - self.field_type = field_type - - -def fields_from_type_hints(hints: dict[str, type], node_path: str) -> dict[str, NodeField]: - return {k: NodeField(alias=k, node_path=node_path, field=k, field_type=v) for k, v in hints.items()} - - -def get_node_input_field(graph: LibraryGraph, field_alias: str, node_id: str) -> NodeField: - """Gets the node field for the specified field alias""" - exposed_input = next(e for e in graph.exposed_inputs if e.alias == field_alias) - node_type = type(graph.graph.get_node(exposed_input.node_path)) - return NodeField( - alias=exposed_input.alias, - node_path=f"{node_id}.{exposed_input.node_path}", - field=exposed_input.field, - field_type=get_type_hints(node_type)[exposed_input.field], - ) - - -def get_node_output_field(graph: LibraryGraph, field_alias: str, node_id: str) -> NodeField: - """Gets the node field for the specified field alias""" - exposed_output = next(e for e in graph.exposed_outputs if e.alias == field_alias) - node_type = type(graph.graph.get_node(exposed_output.node_path)) - node_output_type = node_type.get_output_type() - return NodeField( - alias=exposed_output.alias, - node_path=f"{node_id}.{exposed_output.node_path}", - field=exposed_output.field, - field_type=get_type_hints(node_output_type)[exposed_output.field], - ) - - -def get_node_inputs(invocation: BaseInvocation, context: CliContext) -> dict[str, NodeField]: - """Gets the inputs for the specified invocation from the context""" - node_type = type(invocation) - if node_type is not GraphInvocation: - return fields_from_type_hints(get_type_hints(node_type), invocation.id) - else: - graph: LibraryGraph = context.invoker.services.graph_library.get(context.graph_nodes[invocation.id]) - return {e.alias: get_node_input_field(graph, e.alias, invocation.id) for e in graph.exposed_inputs} - - -def get_node_outputs(invocation: BaseInvocation, context: CliContext) -> dict[str, NodeField]: - """Gets the outputs for the specified invocation from the context""" - node_type = type(invocation) - if node_type is not GraphInvocation: - return fields_from_type_hints(get_type_hints(node_type.get_output_type()), invocation.id) - else: - graph: LibraryGraph = context.invoker.services.graph_library.get(context.graph_nodes[invocation.id]) - return {e.alias: get_node_output_field(graph, e.alias, invocation.id) for e in graph.exposed_outputs} - - -def generate_matching_edges(a: BaseInvocation, b: BaseInvocation, context: CliContext) -> list[Edge]: - """Generates all possible edges between two invocations""" - afields = get_node_outputs(a, context) - bfields = get_node_inputs(b, context) - - matching_fields = set(afields.keys()).intersection(bfields.keys()) - - # Remove invalid fields - invalid_fields = set(["type", "id"]) - matching_fields = matching_fields.difference(invalid_fields) - - # Validate types - matching_fields = [ - f for f in matching_fields if are_connection_types_compatible(afields[f].field_type, bfields[f].field_type) - ] - - edges = [ - Edge( - source=EdgeConnection(node_id=afields[alias].node_path, field=afields[alias].field), - destination=EdgeConnection(node_id=bfields[alias].node_path, field=bfields[alias].field), - ) - for alias in matching_fields - ] - return edges - - -class SessionError(Exception): - """Raised when a session error has occurred""" - - pass - - -def invoke_all(context: CliContext): - """Runs all invocations in the specified session""" - context.invoker.invoke(context.session, invoke_all=True) - while not context.get_session().is_complete(): - # Wait some time - time.sleep(0.1) - - # Print any errors - if context.session.has_error(): - for n in context.session.errors: - context.invoker.services.logger.error( - f"Error in node {n} (source node {context.session.prepared_source_mapping[n]}): {context.session.errors[n]}" - ) - - raise SessionError() - - -def invoke_cli(): - logger.info(f"InvokeAI version {__version__}") - # get the optional list of invocations to execute on the command line - parser = config.get_parser() - parser.add_argument("commands", nargs="*") - invocation_commands = parser.parse_args().commands - - # get the optional file to read commands from. - # Simplest is to use it for STDIN - if infile := config.from_file: - sys.stdin = open(infile, "r") - - model_manager = ModelManagerService(config, logger) - - events = EventServiceBase() - output_folder = config.output_path - - # TODO: build a file/path manager? - if config.use_memory_db: - db_location = ":memory:" - else: - db_location = config.db_path - db_location.parent.mkdir(parents=True, exist_ok=True) - - db_conn = sqlite3.connect(db_location, check_same_thread=False) # TODO: figure out a better threading solution - logger.info(f'InvokeAI database location is "{db_location}"') - - graph_execution_manager = SqliteItemStorage[GraphExecutionState](conn=db_conn, table_name="graph_executions") - - urls = LocalUrlService() - image_record_storage = SqliteImageRecordStorage(conn=db_conn) - image_file_storage = DiskImageFileStorage(f"{output_folder}/images") - names = SimpleNameService() - - board_record_storage = SqliteBoardRecordStorage(conn=db_conn) - board_image_record_storage = SqliteBoardImageRecordStorage(conn=db_conn) - - boards = BoardService( - services=BoardServiceDependencies( - board_image_record_storage=board_image_record_storage, - board_record_storage=board_record_storage, - image_record_storage=image_record_storage, - url=urls, - logger=logger, - ) - ) - - board_images = BoardImagesService( - services=BoardImagesServiceDependencies( - board_image_record_storage=board_image_record_storage, - board_record_storage=board_record_storage, - image_record_storage=image_record_storage, - url=urls, - logger=logger, - ) - ) - - images = ImageService( - services=ImageServiceDependencies( - board_image_record_storage=board_image_record_storage, - image_record_storage=image_record_storage, - image_file_storage=image_file_storage, - url=urls, - logger=logger, - names=names, - graph_execution_manager=graph_execution_manager, - ) - ) - - services = InvocationServices( - model_manager=model_manager, - events=events, - latents=ForwardCacheLatentsStorage(DiskLatentsStorage(f"{output_folder}/latents")), - images=images, - boards=boards, - board_images=board_images, - queue=MemoryInvocationQueue(), - graph_library=SqliteItemStorage[LibraryGraph](conn=db_conn, table_name="graphs"), - graph_execution_manager=graph_execution_manager, - processor=DefaultInvocationProcessor(), - performance_statistics=InvocationStatsService(graph_execution_manager), - logger=logger, - configuration=config, - invocation_cache=MemoryInvocationCache(max_cache_size=config.node_cache_size), - ) - - system_graphs = create_system_graphs(services.graph_library) - system_graph_names = set([g.name for g in system_graphs]) - set_autocompleter(services) - - invoker = Invoker(services) - session: GraphExecutionState = invoker.create_execution_state() - parser = get_command_parser(services) - - re_negid = re.compile("^-[0-9]+$") - - # Uncomment to print out previous sessions at startup - # print(services.session_manager.list()) - - context = CliContext(invoker, session, parser) - set_autocompleter(services) - - command_line_args_exist = len(invocation_commands) > 0 - done = False - - while not done: - try: - if command_line_args_exist: - cmd_input = invocation_commands.pop(0) - done = len(invocation_commands) == 0 - else: - cmd_input = input("invoke> ") - except (KeyboardInterrupt, EOFError): - # Ctrl-c exits - break - - try: - # Refresh the state of the session - # history = list(get_graph_execution_history(context.session)) - history = list(reversed(context.nodes_added)) - - # Split the command for piping - cmds = cmd_input.split("|") - start_id = len(context.nodes_added) - current_id = start_id - new_invocations = list() - for cmd in cmds: - if cmd is None or cmd.strip() == "": - raise InvalidArgs("Empty command") - - # Parse args to create invocation - args = vars(context.parser.parse_args(shlex.split(cmd.strip()))) - - # Override defaults - for field_name, field_default in context.defaults.items(): - if field_name in args: - args[field_name] = field_default - - # Parse invocation - command: CliCommand = None # type:ignore - system_graph: Optional[LibraryGraph] = None - if args["type"] in system_graph_names: - system_graph = next(filter(lambda g: g.name == args["type"], system_graphs)) - invocation = GraphInvocation(graph=system_graph.graph, id=str(current_id)) - for exposed_input in system_graph.exposed_inputs: - if exposed_input.alias in args: - node = invocation.graph.get_node(exposed_input.node_path) - field = exposed_input.field - setattr(node, field, args[exposed_input.alias]) - command = CliCommand(command=invocation) - context.graph_nodes[invocation.id] = system_graph.id - else: - args["id"] = current_id - command = CliCommand(command=args) - - if command is None: - continue - - # Run any CLI commands immediately - if isinstance(command.command, BaseCommand): - # Invoke all current nodes to preserve operation order - invoke_all(context) - - # Run the command - command.command.run(context) - continue - - # TODO: handle linking with library graphs - # Pipe previous command output (if there was a previous command) - edges: list[Edge] = list() - if len(history) > 0 or current_id != start_id: - from_id = history[0] if current_id == start_id else str(current_id - 1) - from_node = ( - next(filter(lambda n: n[0].id == from_id, new_invocations))[0] - if current_id != start_id - else context.session.graph.get_node(from_id) - ) - matching_edges = generate_matching_edges(from_node, command.command, context) - edges.extend(matching_edges) - - # Parse provided links - if "link_node" in args and args["link_node"]: - for link in args["link_node"]: - node_id = link - if re_negid.match(node_id): - node_id = str(current_id + int(node_id)) - - link_node = context.session.graph.get_node(node_id) - matching_edges = generate_matching_edges(link_node, command.command, context) - matching_destinations = [e.destination for e in matching_edges] - edges = [e for e in edges if e.destination not in matching_destinations] - edges.extend(matching_edges) - - if "link" in args and args["link"]: - for link in args["link"]: - edges = [ - e - for e in edges - if e.destination.node_id != command.command.id or e.destination.field != link[2] - ] - - node_id = link[0] - if re_negid.match(node_id): - node_id = str(current_id + int(node_id)) - - # TODO: handle missing input/output - node_output = get_node_outputs(context.session.graph.get_node(node_id), context)[link[1]] - node_input = get_node_inputs(command.command, context)[link[2]] - - edges.append( - Edge( - source=EdgeConnection(node_id=node_output.node_path, field=node_output.field), - destination=EdgeConnection(node_id=node_input.node_path, field=node_input.field), - ) - ) - - new_invocations.append((command.command, edges)) - - current_id = current_id + 1 - - # Add the node to the session - context.add_node(command.command) - for edge in edges: - print(edge) - context.add_edge(edge) - - # Execute all remaining nodes - invoke_all(context) - - except InvalidArgs: - invoker.services.logger.warning('Invalid command, use "help" to list commands') - continue - - except ValidationError: - invoker.services.logger.warning('Invalid command arguments, run " --help" for summary') - - except SessionError: - # Start a new session - invoker.services.logger.warning("Session error: creating a new session") - context.reset() - - except ExitCli: - break - - except SystemExit: - continue - - invoker.stop() - - -if __name__ == "__main__": - if config.version: - print(f"InvokeAI version {__version__}") - else: - invoke_cli() diff --git a/mkdocs.yml b/mkdocs.yml index f95d83ac8f..97b2a16f19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -134,6 +134,7 @@ nav: - List of Default Nodes: 'nodes/defaultNodes.md' - Workflow Editor Usage: 'nodes/NODES.md' - ComfyUI to InvokeAI: 'nodes/comfyToInvoke.md' + - Facetool Node: 'nodes/detailedNodes/faceTools.md' - Contributing Nodes: 'nodes/contributingNodes.md' - Features: - Overview: 'features/index.md' @@ -144,7 +145,7 @@ nav: - Image-to-Image: 'features/IMG2IMG.md' - Controlling Logging: 'features/LOGGING.md' - Model Merging: 'features/MODEL_MERGING.md' - - Using Nodes : './nodes/overview' + - Using Nodes : 'nodes/overview.md' - NSFW Checker: 'features/WATERMARK+NSFW.md' - Postprocessing: 'features/POSTPROCESS.md' - Prompting Features: 'features/PROMPTS.md' @@ -152,15 +153,18 @@ nav: - Unified Canvas: 'features/UNIFIED_CANVAS.md' - InvokeAI Web Server: 'features/WEB.md' - WebUI Hotkeys: "features/WEBUIHOTKEYS.md" + - Maintenance Utilities: "features/UTILITIES.md" - Other: 'features/OTHER.md' - Contributing: - How to Contribute: 'contributing/CONTRIBUTING.md' + - InvokeAI Code of Conduct: 'CODE_OF_CONDUCT.md' - Development: - Overview: 'contributing/contribution_guides/development.md' - New Contributors: 'contributing/contribution_guides/newContributorChecklist.md' - InvokeAI Architecture: 'contributing/ARCHITECTURE.md' - Frontend Documentation: 'contributing/contribution_guides/contributingToFrontend.md' - Local Development: 'contributing/LOCAL_DEVELOPMENT.md' + - Adding Tests: 'contributing/TESTS.md' - Documentation: 'contributing/contribution_guides/documentation.md' - Nodes: 'contributing/INVOCATIONS.md' - Translation: 'contributing/contribution_guides/translation.md' @@ -168,9 +172,12 @@ nav: - Changelog: 'CHANGELOG.md' - Deprecated: - Command Line Interface: 'deprecated/CLI.md' + - Variations: 'deprecated/VARIATIONS.md' + - Translations: 'deprecated/TRANSLATION.md' - Embiggen: 'deprecated/EMBIGGEN.md' - Inpainting: 'deprecated/INPAINTING.md' - Outpainting: 'deprecated/OUTPAINTING.md' + - Troubleshooting: 'help/deprecated/TROUBLESHOOT.md' - Help: - Getting Started: 'help/gettingStartedWithAI.md' - Diffusion Overview: 'help/diffusion.md' diff --git a/pyproject.toml b/pyproject.toml index 67486e1120..96c6c3dd73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,7 +125,7 @@ dependencies = [ # shortcut commands to start cli and web # "invokeai --web" will launch the web interface # "invokeai" will launch the CLI -"invokeai" = "invokeai.frontend.legacy_launch_invokeai:main" +# "invokeai" = "invokeai.frontend.legacy_launch_invokeai:main" # new shortcut to launch web interface "invokeai-web" = "invokeai.app.api_app:invoke_api" @@ -138,7 +138,6 @@ dependencies = [ "invokeai-migrate3" = "invokeai.backend.install.migrate_to_3:main" "invokeai-update" = "invokeai.frontend.install.invokeai_update:main" "invokeai-metadata" = "invokeai.backend.image_util.invoke_metadata:main" -"invokeai-node-cli" = "invokeai.app.cli_app:invoke_cli" "invokeai-node-web" = "invokeai.app.api_app:invoke_api" "invokeai-import-images" = "invokeai.frontend.install.import_images:main" "invokeai-db-maintenance" = "invokeai.backend.util.db_maintenance:main" From 67a343b3e45bfafec0b5deb62f0117610f3acab6 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:20:06 +1100 Subject: [PATCH 020/119] Update pyproject.toml --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 96c6c3dd73..2bcaea2efa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,9 +122,8 @@ dependencies = [ "configure_invokeai.py" = "invokeai.frontend.install.invokeai_configure:invokeai_configure" "textual_inversion.py" = "invokeai.frontend.training:invokeai_textual_inversion" -# shortcut commands to start cli and web +# shortcut commands to start web ui # "invokeai --web" will launch the web interface -# "invokeai" will launch the CLI # "invokeai" = "invokeai.frontend.legacy_launch_invokeai:main" # new shortcut to launch web interface From 024aa5eb90a72eb99125895bba2397a4f23886bd Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:19:06 +1100 Subject: [PATCH 021/119] fix(ui): fix field sorting closes #4934 --- .../hooks/useAnyOrDirectInputFieldNames.ts | 19 +++++++--------- .../hooks/useConnectionInputFieldNames.ts | 22 +++++++++---------- .../nodes/hooks/useOutputFieldNames.ts | 8 +++---- .../nodes/util/getSortedFilteredFieldNames.ts | 20 +++++++++++++++++ 4 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts index 36f2e8a62c..dda2efc156 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts @@ -9,6 +9,7 @@ import { POLYMORPHIC_TYPES, TYPES_WITH_INPUT_COMPONENTS, } from '../types/constants'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useAnyOrDirectInputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -24,17 +25,13 @@ export const useAnyOrDirectInputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.inputs) - .filter( - (field) => - (['any', 'direct'].includes(field.input) || - POLYMORPHIC_TYPES.includes(field.type)) && - TYPES_WITH_INPUT_COMPONENTS.includes(field.type) - ) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + const fields = map(nodeTemplate.inputs).filter( + (field) => + (['any', 'direct'].includes(field.input) || + POLYMORPHIC_TYPES.includes(field.type)) && + TYPES_WITH_INPUT_COMPONENTS.includes(field.type) + ); + return getSortedFilteredFieldNames(fields); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts index eea874cc87..9fb31df801 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts @@ -9,6 +9,7 @@ import { TYPES_WITH_INPUT_COMPONENTS, } from '../types/constants'; import { isInvocationNode } from '../types/types'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useConnectionInputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -24,17 +25,16 @@ export const useConnectionInputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.inputs) - .filter( - (field) => - (field.input === 'connection' && - !POLYMORPHIC_TYPES.includes(field.type)) || - !TYPES_WITH_INPUT_COMPONENTS.includes(field.type) - ) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + + // get the visible fields + const fields = map(nodeTemplate.inputs).filter( + (field) => + (field.input === 'connection' && + !POLYMORPHIC_TYPES.includes(field.type)) || + !TYPES_WITH_INPUT_COMPONENTS.includes(field.type) + ); + + return getSortedFilteredFieldNames(fields); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts index 97956a4889..e0a1e5433e 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts @@ -5,6 +5,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { map } from 'lodash-es'; import { useMemo } from 'react'; import { isInvocationNode } from '../types/types'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useOutputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -20,11 +21,8 @@ export const useOutputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.outputs) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + + return getSortedFilteredFieldNames(map(nodeTemplate.outputs)); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts b/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts new file mode 100644 index 0000000000..b235fe8a07 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts @@ -0,0 +1,20 @@ +import { isNil } from 'lodash-es'; +import { InputFieldTemplate, OutputFieldTemplate } from '../types/types'; + +export const getSortedFilteredFieldNames = ( + fields: InputFieldTemplate[] | OutputFieldTemplate[] +): string[] => { + const visibleFields = fields.filter((field) => !field.ui_hidden); + + // we want explicitly ordered fields to be before unordered fields; split the list + const orderedFields = visibleFields + .filter((f) => !isNil(f.ui_order)) + .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)); + const unorderedFields = visibleFields.filter((f) => isNil(f.ui_order)); + + // concat the lists, and return the field names, skipping `is_intermediate` + return orderedFields + .concat(unorderedFields) + .map((f) => f.name) + .filter((fieldName) => fieldName !== 'is_intermediate'); +}; From 5e6df975fd0245f1a0ccbc9f96e05f7c362311a3 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:31:29 +1100 Subject: [PATCH 022/119] fix(nodes): fix math node validation Update field_validator api for pydantic v2 --- invokeai/app/invocations/math.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/invokeai/app/invocations/math.py b/invokeai/app/invocations/math.py index 2aefa1def4..3ed325802e 100644 --- a/invokeai/app/invocations/math.py +++ b/invokeai/app/invocations/math.py @@ -3,7 +3,7 @@ from typing import Literal import numpy as np -from pydantic import field_validator +from pydantic import ValidationInfo, field_validator from invokeai.app.invocations.primitives import FloatOutput, IntegerOutput @@ -186,12 +186,12 @@ class IntegerMathInvocation(BaseInvocation): b: int = InputField(default=0, description=FieldDescriptions.num_2) @field_validator("b") - def no_unrepresentable_results(cls, v, values): - if values["operation"] == "DIV" and v == 0: + def no_unrepresentable_results(cls, v: int, info: ValidationInfo): + if info.data["operation"] == "DIV" and v == 0: raise ValueError("Cannot divide by zero") - elif values["operation"] == "MOD" and v == 0: + elif info.data["operation"] == "MOD" and v == 0: raise ValueError("Cannot divide by zero") - elif values["operation"] == "EXP" and v < 0: + elif info.data["operation"] == "EXP" and v < 0: raise ValueError("Result of exponentiation is not an integer") return v @@ -260,12 +260,12 @@ class FloatMathInvocation(BaseInvocation): b: float = InputField(default=0, description=FieldDescriptions.num_2) @field_validator("b") - def no_unrepresentable_results(cls, v, values): - if values["operation"] == "DIV" and v == 0: + def no_unrepresentable_results(cls, v: float, info: ValidationInfo): + if info.data["operation"] == "DIV" and v == 0: raise ValueError("Cannot divide by zero") - elif values["operation"] == "EXP" and values["a"] == 0 and v < 0: + elif info.data["operation"] == "EXP" and info.data["a"] == 0 and v < 0: raise ValueError("Cannot raise zero to a negative power") - elif values["operation"] == "EXP" and type(values["a"] ** v) is complex: + elif info.data["operation"] == "EXP" and type(info.data["a"] ** v) is complex: raise ValueError("Root operation resulted in a complex number") return v From 0a01d86ab13293a0f2ac4d83d40fb93ebd85c6f8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:36:25 +1100 Subject: [PATCH 023/119] fix(ui): fix multiple control adapters on canvas We were making an edges for each adapter where we should isntead have one from the adapter's collect node into the denoising node --- .../addControlNetToLinearGraph.ts | 20 ++++++++-------- .../addIPAdapterToLinearGraph.ts | 24 +++++++++---------- .../addT2IAdapterToLinearGraph.ts | 20 ++++++++-------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts index 552a9c6c9b..37bd82d4f8 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts @@ -43,6 +43,16 @@ export const addControlNetToLinearGraph = ( }, }); + if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { + graph.edges.push({ + source: { node_id: CONTROL_NET_COLLECT, field: 'collection' }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'control', + }, + }); + } + validControlNets.forEach((controlNet) => { if (!controlNet.model) { return; @@ -106,16 +116,6 @@ export const addControlNetToLinearGraph = ( field: 'item', }, }); - - if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { - graph.edges.push({ - source: { node_id: controlNetNode.id, field: 'control' }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'control', - }, - }); - } }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts index f96b2e52ed..19bf7d8338 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts @@ -32,15 +32,25 @@ export const addIPAdapterToLinearGraph = ( type: 'collect', is_intermediate: true, }; - graph.nodes[ipAdapterCollectNode.id] = ipAdapterCollectNode; + graph.nodes[IP_ADAPTER_COLLECT] = ipAdapterCollectNode; graph.edges.push({ - source: { node_id: ipAdapterCollectNode.id, field: 'collection' }, + source: { node_id: IP_ADAPTER_COLLECT, field: 'collection' }, destination: { node_id: baseNodeId, field: 'ip_adapter', }, }); + if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { + graph.edges.push({ + source: { node_id: IP_ADAPTER_COLLECT, field: 'collection' }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'ip_adapter', + }, + }); + } + validIPAdapters.forEach((ipAdapter) => { if (!ipAdapter.model) { return; @@ -87,16 +97,6 @@ export const addIPAdapterToLinearGraph = ( field: 'item', }, }); - - if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { - graph.edges.push({ - source: { node_id: ipAdapterNode.id, field: 'ip_adapter' }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'ip_adapter', - }, - }); - } }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts index 16dc5bbc71..9511475bb3 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts @@ -42,6 +42,16 @@ export const addT2IAdaptersToLinearGraph = ( }, }); + if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { + graph.edges.push({ + source: { node_id: T2I_ADAPTER_COLLECT, field: 'collection' }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 't2i_adapter', + }, + }); + } + validT2IAdapters.forEach((t2iAdapter) => { if (!t2iAdapter.model) { return; @@ -103,16 +113,6 @@ export const addT2IAdaptersToLinearGraph = ( field: 'item', }, }); - - if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { - graph.edges.push({ - source: { node_id: t2iAdapterNode.id, field: 't2i_adapter' }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 't2i_adapter', - }, - }); - } }); } }; From fdf02c33d06ea6f2d297a6064981b94df7148c4d Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Tue, 17 Oct 2023 21:59:04 -0500 Subject: [PATCH 024/119] Catch generic model errors Prevent the app from dying on invalid models. --- invokeai/backend/model_management/model_manager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index 38a7361c85..9390c8ce54 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -1011,6 +1011,8 @@ class ModelManager(object): self.logger.warning(f"Not a valid model: {model_path}. {e}") except NotImplementedError as e: self.logger.warning(e) + except Exception as e: + self.logger.warning(f"Error loading model {model_path}. {e}") imported_models = self.scan_autoimport_directory() if (new_models_found or imported_models) and self.config_path: From a459786d735cc2b14e7631e9d955c544bd7ce6e3 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:40:34 +1100 Subject: [PATCH 025/119] fix(nodes): enable number to string coercion --- invokeai/app/invocations/baseinvocation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 8bd4a89f45..ba94e7c440 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -693,6 +693,7 @@ class BaseInvocation(ABC, BaseModel): validate_assignment=True, json_schema_extra=json_schema_extra, json_schema_serialization_defaults_required=True, + coerce_numbers_to_str=True, ) From 9e063711789336ab16a07e1873b753eee1b094c9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:39:21 +1100 Subject: [PATCH 026/119] feat(api): serve app via route & add cache-control: no-store This should prevent `index.html` from *ever* being cached, so UIs will never be out of date. Minor organisation to accomodate this. Deleting old unused files from the early days --- invokeai/app/api_app.py | 24 +- .../static/{dream_web => docs}/favicon.ico | Bin .../frontend/web/static/dream_web/index.css | 179 -------- .../frontend/web/static/dream_web/index.html | 187 -------- .../frontend/web/static/dream_web/index.js | 409 ------------------ .../frontend/web/static/dream_web/test.html | 246 ----------- .../web/static/legacy_web/favicon.ico | Bin 1150 -> 0 bytes .../frontend/web/static/legacy_web/index.css | 152 ------- .../frontend/web/static/legacy_web/index.html | 137 ------ .../frontend/web/static/legacy_web/index.js | 234 ---------- 10 files changed, 17 insertions(+), 1551 deletions(-) rename invokeai/frontend/web/static/{dream_web => docs}/favicon.ico (100%) delete mode 100644 invokeai/frontend/web/static/dream_web/index.css delete mode 100644 invokeai/frontend/web/static/dream_web/index.html delete mode 100644 invokeai/frontend/web/static/dream_web/index.js delete mode 100644 invokeai/frontend/web/static/dream_web/test.html delete mode 100644 invokeai/frontend/web/static/legacy_web/favicon.ico delete mode 100644 invokeai/frontend/web/static/legacy_web/index.css delete mode 100644 invokeai/frontend/web/static/legacy_web/index.html delete mode 100644 invokeai/frontend/web/static/legacy_web/index.js diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index e07b037dd1..f45541e63b 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -23,6 +23,7 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware from pydantic.json_schema import models_json_schema + from fastapi.responses import FileResponse # noinspection PyUnresolvedReferences import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) @@ -173,16 +174,13 @@ def custom_openapi(): app.openapi = custom_openapi # type: ignore [method-assign] # this is a valid assignment -# Override API doc favicons -app.mount("/static", StaticFiles(directory=Path(web_dir.__path__[0], "static/dream_web")), name="static") - @app.get("/docs", include_in_schema=False) def overridden_swagger(): return get_swagger_ui_html( openapi_url=app.openapi_url, title=app.title, - swagger_favicon_url="/static/favicon.ico", + swagger_favicon_url="/static/docs/favicon.ico", ) @@ -191,12 +189,24 @@ def overridden_redoc(): return get_redoc_html( openapi_url=app.openapi_url, title=app.title, - redoc_favicon_url="/static/favicon.ico", + redoc_favicon_url="/static/docs/favicon.ico", ) -# Must mount *after* the other routes else it borks em -app.mount("/", StaticFiles(directory=Path(web_dir.__path__[0], "dist"), html=True), name="ui") +web_root_path = Path(list(web_dir.__path__)[0]) + + +# Cannot add headers to StaticFiles, so we must serve index.html with a custom route +# Add cache-control: no-store header to prevent caching of index.html, which leads to broken UIs at release +@app.get("/", include_in_schema=False, name="ui_root") +def get_index() -> FileResponse: + return FileResponse(Path(web_root_path, "dist/index.html"), headers={"Cache-Control": "no-store"}) + + +# # Must mount *after* the other routes else it borks em +app.mount("/static", StaticFiles(directory=Path(web_root_path, "static/")), name="static") # docs favicon is in here +app.mount("/assets", StaticFiles(directory=Path(web_root_path, "dist/assets/")), name="assets") +app.mount("/locales", StaticFiles(directory=Path(web_root_path, "dist/locales/")), name="locales") def invoke_api(): diff --git a/invokeai/frontend/web/static/dream_web/favicon.ico b/invokeai/frontend/web/static/docs/favicon.ico similarity index 100% rename from invokeai/frontend/web/static/dream_web/favicon.ico rename to invokeai/frontend/web/static/docs/favicon.ico diff --git a/invokeai/frontend/web/static/dream_web/index.css b/invokeai/frontend/web/static/dream_web/index.css deleted file mode 100644 index 25a0994a3d..0000000000 --- a/invokeai/frontend/web/static/dream_web/index.css +++ /dev/null @@ -1,179 +0,0 @@ -:root { - --fields-dark:#DCDCDC; - --fields-light:#F5F5F5; -} - -* { - font-family: 'Arial'; - font-size: 100%; -} -body { - font-size: 1em; -} -textarea { - font-size: 0.95em; -} -header, form, #progress-section { - margin-left: auto; - margin-right: auto; - max-width: 1024px; - text-align: center; -} -fieldset { - border: none; - line-height: 2.2em; -} -fieldset > legend { - width: auto; - margin-left: 0; - margin-right: auto; - font-weight:bold; -} -select, input { - margin-right: 10px; - padding: 2px; -} -input:disabled { - cursor:auto; -} -input[type=submit] { - cursor: pointer; - background-color: #666; - color: white; -} -input[type=checkbox] { - cursor: pointer; - margin-right: 0px; - width: 20px; - height: 20px; - vertical-align: middle; -} -input#seed { - margin-right: 0px; -} -div { - padding: 10px 10px 10px 10px; -} -header { - margin-bottom: 16px; -} -header h1 { - margin-bottom: 0; - font-size: 2em; -} -#search-box { - display: flex; -} -#scaling-inprocess-message { - font-weight: bold; - font-style: italic; - display: none; -} -#prompt { - flex-grow: 1; - padding: 5px 10px 5px 10px; - border: 1px solid #999; - outline: none; -} -#submit { - padding: 5px 10px 5px 10px; - border: 1px solid #999; -} -#reset-all, #remove-image { - margin-top: 12px; - font-size: 0.8em; - background-color: pink; - border: 1px solid #999; - border-radius: 4px; -} -#results { - text-align: center; - margin: auto; - padding-top: 10px; -} -#results figure { - display: inline-block; - margin: 10px; -} -#results figcaption { - font-size: 0.8em; - padding: 3px; - color: #888; - cursor: pointer; -} -#results img { - border-radius: 5px; - object-fit: contain; - background-color: var(--fields-dark); -} -#fieldset-config { - line-height:2em; -} -input[type="number"] { - width: 60px; -} -#seed { - width: 150px; -} -button#reset-seed { - font-size: 1.7em; - background: #efefef; - border: 1px solid #999; - border-radius: 4px; - line-height: 0.8; - margin: 0 10px 0 0; - padding: 0 5px 3px; - vertical-align: middle; -} -label { - white-space: nowrap; -} -#progress-section { - display: none; -} -#progress-image { - width: 30vh; - height: 30vh; - object-fit: contain; - background-color: var(--fields-dark); -} -#cancel-button { - cursor: pointer; - color: red; -} -#txt2img { - background-color: var(--fields-dark); -} -#variations { - background-color: var(--fields-light); -} -#initimg { - background-color: var(--fields-dark); -} -#img2img { - background-color: var(--fields-light); -} -#initimg > :not(legend) { - background-color: var(--fields-light); - margin: .5em; -} - -#postprocess, #initimg { - display:flex; - flex-wrap:wrap; - padding: 0; - margin-top: 1em; - background-color: var(--fields-dark); -} -#postprocess > fieldset, #initimg > * { - flex-grow: 1; -} -#postprocess > fieldset { - background-color: var(--fields-dark); -} -#progress-section { - background-color: var(--fields-light); -} -#no-results-message:not(:only-child) { - display: none; -} diff --git a/invokeai/frontend/web/static/dream_web/index.html b/invokeai/frontend/web/static/dream_web/index.html deleted file mode 100644 index feb542adb2..0000000000 --- a/invokeai/frontend/web/static/dream_web/index.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - Stable Diffusion Dream Server - - - - - - - - - - - -
-

Stable Diffusion Dream Server

-
- For news and support for this web service, visit our GitHub - site -
-
- -
- -
-
- - - - - - - - - - - - - - - -
- - - - - - - - - -
- - - - - -
-
- - - - -
-
-
- - - - -
- - - -
-
- - - - - - - - -
-
-
-
- - - - - - -
-
- - - - - - - - -
-
- -
-
-
-
- - -
- -
- Postprocessing...1/3 -
-
-
- -
-
-
- - - diff --git a/invokeai/frontend/web/static/dream_web/index.js b/invokeai/frontend/web/static/dream_web/index.js deleted file mode 100644 index 438232f0c7..0000000000 --- a/invokeai/frontend/web/static/dream_web/index.js +++ /dev/null @@ -1,409 +0,0 @@ -const socket = io(); - -var priorResultsLoadState = { - page: 0, - pages: 1, - per_page: 10, - total: 20, - offset: 0, // number of items generated since last load - loading: false, - initialized: false, -}; - -function loadPriorResults() { - // Fix next page by offset - let offsetPages = - priorResultsLoadState.offset / priorResultsLoadState.per_page; - priorResultsLoadState.page += offsetPages; - priorResultsLoadState.pages += offsetPages; - priorResultsLoadState.total += priorResultsLoadState.offset; - priorResultsLoadState.offset = 0; - - if (priorResultsLoadState.loading) { - return; - } - - if (priorResultsLoadState.page >= priorResultsLoadState.pages) { - return; // Nothing more to load - } - - // Load - priorResultsLoadState.loading = true; - let url = new URL('/api/images', document.baseURI); - url.searchParams.append( - 'page', - priorResultsLoadState.initialized - ? priorResultsLoadState.page + 1 - : priorResultsLoadState.page - ); - url.searchParams.append('per_page', priorResultsLoadState.per_page); - fetch(url.href, { - method: 'GET', - headers: new Headers({ 'content-type': 'application/json' }), - }) - .then((response) => response.json()) - .then((data) => { - priorResultsLoadState.page = data.page; - priorResultsLoadState.pages = data.pages; - priorResultsLoadState.per_page = data.per_page; - priorResultsLoadState.total = data.total; - - data.items.forEach(function (dreamId, index) { - let src = 'api/images/' + dreamId; - fetch('/api/images/' + dreamId + '/metadata', { - method: 'GET', - headers: new Headers({ 'content-type': 'application/json' }), - }) - .then((response) => response.json()) - .then((metadata) => { - let seed = metadata.seed || 0; // TODO: Parse old metadata - appendOutput(src, seed, metadata, true); - }); - }); - - // Load until page is full - if (!priorResultsLoadState.initialized) { - if (document.body.scrollHeight <= window.innerHeight) { - loadPriorResults(); - } - } - }) - .finally(() => { - priorResultsLoadState.loading = false; - priorResultsLoadState.initialized = true; - }); -} - -function resetForm() { - var form = document.getElementById('generate-form'); - form.querySelector('fieldset').removeAttribute('disabled'); -} - -function initProgress(totalSteps, showProgressImages) { - // TODO: Progress could theoretically come from multiple jobs at the same time (in the future) - let progressSectionEle = document.querySelector('#progress-section'); - progressSectionEle.style.display = 'initial'; - let progressEle = document.querySelector('#progress-bar'); - progressEle.setAttribute('max', totalSteps); - - let progressImageEle = document.querySelector('#progress-image'); - progressImageEle.src = BLANK_IMAGE_URL; - progressImageEle.style.display = showProgressImages ? 'initial' : 'none'; -} - -function setProgress(step, totalSteps, src) { - let progressEle = document.querySelector('#progress-bar'); - progressEle.setAttribute('value', step); - - if (src) { - let progressImageEle = document.querySelector('#progress-image'); - progressImageEle.src = src; - } -} - -function resetProgress(hide = true) { - if (hide) { - let progressSectionEle = document.querySelector('#progress-section'); - progressSectionEle.style.display = 'none'; - } - let progressEle = document.querySelector('#progress-bar'); - progressEle.setAttribute('value', 0); -} - -function toBase64(file) { - return new Promise((resolve, reject) => { - const r = new FileReader(); - r.readAsDataURL(file); - r.onload = () => resolve(r.result); - r.onerror = (error) => reject(error); - }); -} - -function ondragdream(event) { - let dream = event.target.dataset.dream; - event.dataTransfer.setData('dream', dream); -} - -function seedClick(event) { - // Get element - var image = event.target.closest('figure').querySelector('img'); - var dream = JSON.parse(decodeURIComponent(image.dataset.dream)); - - let form = document.querySelector('#generate-form'); - for (const [k, v] of new FormData(form)) { - if (k == 'initimg') { - continue; - } - let formElem = form.querySelector(`*[name=${k}]`); - formElem.value = dream[k] !== undefined ? dream[k] : formElem.defaultValue; - } - - document.querySelector('#seed').value = dream.seed; - document.querySelector('#iterations').value = 1; // Reset to 1 iteration since we clicked a single image (not a full job) - - // NOTE: leaving this manual for the user for now - it was very confusing with this behavior - // document.querySelector("#with_variations").value = variations || ''; - // if (document.querySelector("#variation_amount").value <= 0) { - // document.querySelector("#variation_amount").value = 0.2; - // } - - saveFields(document.querySelector('#generate-form')); -} - -function appendOutput(src, seed, config, toEnd = false) { - let outputNode = document.createElement('figure'); - let altText = seed.toString() + ' | ' + config.prompt; - - // img needs width and height for lazy loading to work - // TODO: store the full config in a data attribute on the image? - const figureContents = ` - - ${altText} - -
${seed}
- `; - - outputNode.innerHTML = figureContents; - - if (toEnd) { - document.querySelector('#results').append(outputNode); - } else { - document.querySelector('#results').prepend(outputNode); - } - document.querySelector('#no-results-message')?.remove(); -} - -function saveFields(form) { - for (const [k, v] of new FormData(form)) { - if (typeof v !== 'object') { - // Don't save 'file' type - localStorage.setItem(k, v); - } - } -} - -function loadFields(form) { - for (const [k, v] of new FormData(form)) { - const item = localStorage.getItem(k); - if (item != null) { - form.querySelector(`*[name=${k}]`).value = item; - } - } -} - -function clearFields(form) { - localStorage.clear(); - let prompt = form.prompt.value; - form.reset(); - form.prompt.value = prompt; -} - -const BLANK_IMAGE_URL = - 'data:image/svg+xml,'; -async function generateSubmit(form) { - // Convert file data to base64 - // TODO: Should probably uplaod files with formdata or something, and store them in the backend? - let formData = Object.fromEntries(new FormData(form)); - if (!formData.enable_generate && !formData.enable_init_image) { - gen_label = document.querySelector('label[for=enable_generate]').innerHTML; - initimg_label = document.querySelector( - 'label[for=enable_init_image]' - ).innerHTML; - alert(`Error: one of "${gen_label}" or "${initimg_label}" must be set`); - } - - formData.initimg_name = formData.initimg.name; - formData.initimg = - formData.initimg.name !== '' ? await toBase64(formData.initimg) : null; - - // Evaluate all checkboxes - let checkboxes = form.querySelectorAll('input[type=checkbox]'); - checkboxes.forEach(function (checkbox) { - if (checkbox.checked) { - formData[checkbox.name] = 'true'; - } - }); - - let strength = formData.strength; - let totalSteps = formData.initimg - ? Math.floor(strength * formData.steps) - : formData.steps; - let showProgressImages = formData.progress_images; - - // Set enabling flags - - // Initialize the progress bar - initProgress(totalSteps, showProgressImages); - - // POST, use response to listen for events - fetch(form.action, { - method: form.method, - headers: new Headers({ 'content-type': 'application/json' }), - body: JSON.stringify(formData), - }) - .then((response) => response.json()) - .then((data) => { - var jobId = data.jobId; - socket.emit('join_room', { room: jobId }); - }); - - form.querySelector('fieldset').setAttribute('disabled', ''); -} - -function fieldSetEnableChecked(event) { - cb = event.target; - fields = cb.closest('fieldset'); - fields.disabled = !cb.checked; -} - -// Socket listeners -socket.on('job_started', (data) => {}); - -socket.on('dream_result', (data) => { - var jobId = data.jobId; - var dreamId = data.dreamId; - var dreamRequest = data.dreamRequest; - var src = 'api/images/' + dreamId; - - priorResultsLoadState.offset += 1; - appendOutput(src, dreamRequest.seed, dreamRequest); - - resetProgress(false); -}); - -socket.on('dream_progress', (data) => { - // TODO: it'd be nice if we could get a seed reported here, but the generator would need to be updated - var step = data.step; - var totalSteps = data.totalSteps; - var jobId = data.jobId; - var dreamId = data.dreamId; - - var progressType = data.progressType; - if (progressType === 'GENERATION') { - var src = data.hasProgressImage - ? 'api/intermediates/' + dreamId + '/' + step - : null; - setProgress(step, totalSteps, src); - } else if (progressType === 'UPSCALING_STARTED') { - // step and totalSteps are used for upscale count on this message - document.getElementById('processing_cnt').textContent = step; - document.getElementById('processing_total').textContent = totalSteps; - document.getElementById('scaling-inprocess-message').style.display = - 'block'; - } else if (progressType == 'UPSCALING_DONE') { - document.getElementById('scaling-inprocess-message').style.display = 'none'; - } -}); - -socket.on('job_canceled', (data) => { - resetForm(); - resetProgress(); -}); - -socket.on('job_done', (data) => { - jobId = data.jobId; - socket.emit('leave_room', { room: jobId }); - - resetForm(); - resetProgress(); -}); - -window.onload = async () => { - document.querySelector('#prompt').addEventListener('keydown', (e) => { - if (e.key === 'Enter' && !e.shiftKey) { - const form = e.target.form; - generateSubmit(form); - } - }); - document.querySelector('#generate-form').addEventListener('submit', (e) => { - e.preventDefault(); - const form = e.target; - - generateSubmit(form); - }); - document.querySelector('#generate-form').addEventListener('change', (e) => { - saveFields(e.target.form); - }); - document.querySelector('#reset-seed').addEventListener('click', (e) => { - document.querySelector('#seed').value = 0; - saveFields(e.target.form); - }); - document.querySelector('#reset-all').addEventListener('click', (e) => { - clearFields(e.target.form); - }); - document.querySelector('#remove-image').addEventListener('click', (e) => { - initimg.value = null; - }); - loadFields(document.querySelector('#generate-form')); - - document.querySelector('#cancel-button').addEventListener('click', () => { - fetch('/api/cancel').catch((e) => { - console.error(e); - }); - }); - document.documentElement.addEventListener('keydown', (e) => { - if (e.key === 'Escape') - fetch('/api/cancel').catch((err) => { - console.error(err); - }); - }); - - if (!config.gfpgan_model_exists) { - document.querySelector('#gfpgan').style.display = 'none'; - } - - window.addEventListener('scroll', () => { - if (window.innerHeight + window.pageYOffset >= document.body.offsetHeight) { - loadPriorResults(); - } - }); - - // Enable/disable forms by checkboxes - document - .querySelectorAll('legend > input[type=checkbox]') - .forEach(function (cb) { - cb.addEventListener('change', fieldSetEnableChecked); - fieldSetEnableChecked({ target: cb }); - }); - - // Load some of the previous results - loadPriorResults(); - - // Image drop/upload WIP - /* - let drop = document.getElementById('dropper'); - function ondrop(event) { - let dreamData = event.dataTransfer.getData('dream'); - if (dreamData) { - var dream = JSON.parse(decodeURIComponent(dreamData)); - alert(dream.dreamId); - } - }; - - function ondragenter(event) { - event.preventDefault(); - }; - - function ondragover(event) { - event.preventDefault(); - }; - - function ondragleave(event) { - - } - - drop.addEventListener('drop', ondrop); - drop.addEventListener('dragenter', ondragenter); - drop.addEventListener('dragover', ondragover); - drop.addEventListener('dragleave', ondragleave); - */ -}; diff --git a/invokeai/frontend/web/static/dream_web/test.html b/invokeai/frontend/web/static/dream_web/test.html deleted file mode 100644 index cbb746a5a1..0000000000 --- a/invokeai/frontend/web/static/dream_web/test.html +++ /dev/null @@ -1,246 +0,0 @@ - - - InvokeAI Test - - - - - - - - - - - - - - - -
- -
- - - - diff --git a/invokeai/frontend/web/static/legacy_web/favicon.ico b/invokeai/frontend/web/static/legacy_web/favicon.ico deleted file mode 100644 index 51eb844a6a4a9d4b13e17e38b0fc915e7e97d4b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmaiy%TE(g6vi*n1a-yAr5H_2eSt+l!2}h8?$p@n=nPJTglL%pit>^TL`+1D5hx&N z)!<{Tc1e&lvO-)*Ow^TsgK$#zJKYFEA;2&@TN?6A5C9Q()1;lGF^Sd zF~GSouqjvv->jVh^vZ3gw#sUXZQHSqR>WSmwCOtUf;BK6W$k#wMKX$aiq1TKiY)i0 zVAh_I80S)!qiamC2k7>K9QPINuKnap%uv%}j+#E^Jur4AXDJpbkvT6Ctz07yN&)Z7 znrGHFe)vUp?-<1^k5RnhDB0a3h^>+{H77oj<%hM0acGw^T{k?>wWp=8-IJ2<;2zkW z55$XEACugh&R(wZ1^nba=DC(TD08@HP|IVZ?1<#7_S=$s)|_Dd@;ZI;mZvYT`CA{Y z_Vq(y{pYvZf8ANnKfH$f+a32rZ=N(I_xgGd_x}n~fRYte5_cZWQRBiY+1KuqaiB`D zuiiy$g`D(znbUIcklw#ZXiGqz&xFs - - Stable Diffusion Dream Server - - - - - - - - -
-

Stable Diffusion Dream Server

-
- For news and support for this web service, visit our GitHub site -
-
- -
-
-
- -
-
-
Basic options
- - - - - - - - - - -
- - - - - - - - - -
- - - - - -
- - - - - - -
-
-
Image-to-image options
- - - -
- - - - -
-
-
Post-processing options
- - - - - - -
-
-
-
-
- - -
- -
- Postprocessing...1/3 -
- -
- -
-
-

No results...

-
-
-
- - diff --git a/invokeai/frontend/web/static/legacy_web/index.js b/invokeai/frontend/web/static/legacy_web/index.js deleted file mode 100644 index a150f3f2e9..0000000000 --- a/invokeai/frontend/web/static/legacy_web/index.js +++ /dev/null @@ -1,234 +0,0 @@ -function toBase64(file) { - return new Promise((resolve, reject) => { - const r = new FileReader(); - r.readAsDataURL(file); - r.onload = () => resolve(r.result); - r.onerror = (error) => reject(error); - }); -} - -function appendOutput(src, seed, config) { - let outputNode = document.createElement('figure'); - - let variations = config.with_variations; - if (config.variation_amount > 0) { - variations = - (variations ? variations + ',' : '') + - seed + - ':' + - config.variation_amount; - } - let baseseed = - config.with_variations || config.variation_amount > 0 ? config.seed : seed; - let altText = - baseseed + ' | ' + (variations ? variations + ' | ' : '') + config.prompt; - - // img needs width and height for lazy loading to work - const figureContents = ` - - ${altText} - -
${seed}
- `; - - outputNode.innerHTML = figureContents; - let figcaption = outputNode.querySelector('figcaption'); - - // Reload image config - figcaption.addEventListener('click', () => { - let form = document.querySelector('#generate-form'); - for (const [k, v] of new FormData(form)) { - if (k == 'initimg') { - continue; - } - form.querySelector(`*[name=${k}]`).value = config[k]; - } - - document.querySelector('#seed').value = baseseed; - document.querySelector('#with_variations').value = variations || ''; - if (document.querySelector('#variation_amount').value <= 0) { - document.querySelector('#variation_amount').value = 0.2; - } - - saveFields(document.querySelector('#generate-form')); - }); - - document.querySelector('#results').prepend(outputNode); -} - -function saveFields(form) { - for (const [k, v] of new FormData(form)) { - if (typeof v !== 'object') { - // Don't save 'file' type - localStorage.setItem(k, v); - } - } -} - -function loadFields(form) { - for (const [k, v] of new FormData(form)) { - const item = localStorage.getItem(k); - if (item != null) { - form.querySelector(`*[name=${k}]`).value = item; - } - } -} - -function clearFields(form) { - localStorage.clear(); - let prompt = form.prompt.value; - form.reset(); - form.prompt.value = prompt; -} - -const BLANK_IMAGE_URL = - 'data:image/svg+xml,'; -async function generateSubmit(form) { - const prompt = document.querySelector('#prompt').value; - - // Convert file data to base64 - let formData = Object.fromEntries(new FormData(form)); - formData.initimg_name = formData.initimg.name; - formData.initimg = - formData.initimg.name !== '' ? await toBase64(formData.initimg) : null; - - let strength = formData.strength; - let totalSteps = formData.initimg - ? Math.floor(strength * formData.steps) - : formData.steps; - - let progressSectionEle = document.querySelector('#progress-section'); - progressSectionEle.style.display = 'initial'; - let progressEle = document.querySelector('#progress-bar'); - progressEle.setAttribute('max', totalSteps); - let progressImageEle = document.querySelector('#progress-image'); - progressImageEle.src = BLANK_IMAGE_URL; - - progressImageEle.style.display = {}.hasOwnProperty.call( - formData, - 'progress_images' - ) - ? 'initial' - : 'none'; - - // Post as JSON, using Fetch streaming to get results - fetch(form.action, { - method: form.method, - body: JSON.stringify(formData), - }).then(async (response) => { - const reader = response.body.getReader(); - - let noOutputs = true; - while (true) { - let { value, done } = await reader.read(); - value = new TextDecoder().decode(value); - if (done) { - progressSectionEle.style.display = 'none'; - break; - } - - for (let event of value.split('\n').filter((e) => e !== '')) { - const data = JSON.parse(event); - - if (data.event === 'result') { - noOutputs = false; - appendOutput(data.url, data.seed, data.config); - progressEle.setAttribute('value', 0); - progressEle.setAttribute('max', totalSteps); - } else if (data.event === 'upscaling-started') { - document.getElementById('processing_cnt').textContent = - data.processed_file_cnt; - document.getElementById('scaling-inprocess-message').style.display = - 'block'; - } else if (data.event === 'upscaling-done') { - document.getElementById('scaling-inprocess-message').style.display = - 'none'; - } else if (data.event === 'step') { - progressEle.setAttribute('value', data.step); - if (data.url) { - progressImageEle.src = data.url; - } - } else if (data.event === 'canceled') { - // avoid alerting as if this were an error case - noOutputs = false; - } - } - } - - // Re-enable form, remove no-results-message - form.querySelector('fieldset').removeAttribute('disabled'); - document.querySelector('#prompt').value = prompt; - document.querySelector('progress').setAttribute('value', '0'); - - if (noOutputs) { - alert('Error occurred while generating.'); - } - }); - - // Disable form while generating - form.querySelector('fieldset').setAttribute('disabled', ''); - document.querySelector('#prompt').value = `Generating: "${prompt}"`; -} - -async function fetchRunLog() { - try { - let response = await fetch('/run_log.json'); - const data = await response.json(); - for (let item of data.run_log) { - appendOutput(item.url, item.seed, item); - } - } catch (e) { - console.error(e); - } -} - -window.onload = async () => { - document.querySelector('#prompt').addEventListener('keydown', (e) => { - if (e.key === 'Enter' && !e.shiftKey) { - const form = e.target.form; - generateSubmit(form); - } - }); - document.querySelector('#generate-form').addEventListener('submit', (e) => { - e.preventDefault(); - const form = e.target; - - generateSubmit(form); - }); - document.querySelector('#generate-form').addEventListener('change', (e) => { - saveFields(e.target.form); - }); - document.querySelector('#reset-seed').addEventListener('click', (e) => { - document.querySelector('#seed').value = -1; - saveFields(e.target.form); - }); - document.querySelector('#reset-all').addEventListener('click', (e) => { - clearFields(e.target.form); - }); - document.querySelector('#remove-image').addEventListener('click', (e) => { - initimg.value = null; - }); - loadFields(document.querySelector('#generate-form')); - - document.querySelector('#cancel-button').addEventListener('click', () => { - fetch('/cancel').catch((e) => { - console.error(e); - }); - }); - document.documentElement.addEventListener('keydown', (e) => { - if (e.key === 'Escape') - fetch('/cancel').catch((err) => { - console.error(err); - }); - }); - - if (!config.gfpgan_model_exists) { - document.querySelector('#gfpgan').style.display = 'none'; - } - await fetchRunLog(); -}; From ef14ba17131674319c56bc565bf5069ef9e78647 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:40:26 +1100 Subject: [PATCH 027/119] fix(api): fix uvicorn config loop arg We were providing the loop itself, not the kind of loop. This didn't appear to cause any issues whatsoever, but now it's correct. --- invokeai/app/api_app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index f45541e63b..cc55329389 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -245,7 +245,7 @@ def invoke_api(): app=app, host=app_config.host, port=port, - loop=loop, + loop="asyncio", log_level=app_config.log_level, ) server = uvicorn.Server(config) From e4c45012f4fb528cc14eacccee6424d60a9085b8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:42:34 +1100 Subject: [PATCH 028/119] feat(api): add gzip middleware On our local installs this will be a very minor change. For those running on remote servers, load times should be slightly improved. It's a small change but I think correct. --- invokeai/app/api_app.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index cc55329389..5889c7e228 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -17,6 +17,7 @@ if True: # hack to make flake8 happy with imports coming after setting up the c import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware + from fastapi.middleware.gzip import GZipMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html from fastapi.openapi.utils import get_openapi from fastapi.staticfiles import StaticFiles @@ -72,6 +73,8 @@ app.add_middleware( allow_headers=app_config.allow_headers, ) +app.add_middleware(GZipMiddleware, minimum_size=1000) + # Add startup event to load dependencies @app.on_event("startup") From da403ba04c41f85e007da6b19a088a2627406536 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:43:01 +1100 Subject: [PATCH 029/119] fix(api): flesh out types for `api_app.py` --- invokeai/app/api_app.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 5889c7e228..6bdf358147 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -1,3 +1,5 @@ +from typing import Any +from fastapi.responses import HTMLResponse from .services.config import InvokeAIAppConfig # parse_args() must be called before any other imports. if it is not called first, consumers of the config @@ -13,7 +15,6 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from inspect import signature from pathlib import Path - import torch import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware @@ -26,6 +27,7 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from pydantic.json_schema import models_json_schema from fastapi.responses import FileResponse + # for PyCharm: # noinspection PyUnresolvedReferences import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) import invokeai.frontend.web as web_dir @@ -36,16 +38,15 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from .api.routers import app_info, board_images, boards, images, models, session_queue, sessions, utilities from .api.sockets import SocketIO from .invocations.baseinvocation import BaseInvocation, UIConfigBase, _InputField, _OutputField + from torch.backends.mps import is_available as is_mps_available - if torch.backends.mps.is_available(): - # noinspection PyUnresolvedReferences + if is_mps_available(): import invokeai.backend.util.mps_fixes # noqa: F401 (monkeypatching on import) app_config = InvokeAIAppConfig.get_config() app_config.parse_args() logger = InvokeAILogger.get_logger(config=app_config) - # fix for windows mimetypes registry entries being borked # see https://github.com/invoke-ai/InvokeAI/discussions/3684#discussioncomment-6391352 mimetypes.add_type("application/javascript", ".js") @@ -78,13 +79,13 @@ app.add_middleware(GZipMiddleware, minimum_size=1000) # Add startup event to load dependencies @app.on_event("startup") -async def startup_event(): +async def startup_event() -> None: ApiDependencies.initialize(config=app_config, event_handler_id=event_handler_id, logger=logger) # Shut down threads @app.on_event("shutdown") -async def shutdown_event(): +async def shutdown_event() -> None: ApiDependencies.shutdown() @@ -108,7 +109,7 @@ app.include_router(session_queue.session_queue_router, prefix="/api") # Build a custom OpenAPI to include all outputs # TODO: can outputs be included on metadata of invocation schemas somehow? -def custom_openapi(): +def custom_openapi() -> dict[str, Any]: if app.openapi_schema: return app.openapi_schema openapi_schema = get_openapi( @@ -179,18 +180,18 @@ app.openapi = custom_openapi # type: ignore [method-assign] # this is a valid a @app.get("/docs", include_in_schema=False) -def overridden_swagger(): +def overridden_swagger() -> HTMLResponse: return get_swagger_ui_html( - openapi_url=app.openapi_url, + openapi_url=app.openapi_url, # type: ignore [arg-type] # this is always a string title=app.title, swagger_favicon_url="/static/docs/favicon.ico", ) @app.get("/redoc", include_in_schema=False) -def overridden_redoc(): +def overridden_redoc() -> HTMLResponse: return get_redoc_html( - openapi_url=app.openapi_url, + openapi_url=app.openapi_url, # type: ignore [arg-type] # this is always a string title=app.title, redoc_favicon_url="/static/docs/favicon.ico", ) @@ -212,8 +213,8 @@ app.mount("/assets", StaticFiles(directory=Path(web_root_path, "dist/assets/")), app.mount("/locales", StaticFiles(directory=Path(web_root_path, "dist/locales/")), name="locales") -def invoke_api(): - def find_port(port: int): +def invoke_api() -> None: + def find_port(port: int) -> int: """Find a port not in use starting at given port""" # Taken from https://waylonwalker.com/python-find-available-port/, thanks Waylon! # https://github.com/WaylonWalker From 96e80c71fb80fb5039a4f1563ee251af9c7e0354 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:27:03 +1100 Subject: [PATCH 030/119] chore: lint --- invokeai/app/api_app.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 6bdf358147..866a6665c8 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -1,5 +1,7 @@ from typing import Any + from fastapi.responses import HTMLResponse + from .services.config import InvokeAIAppConfig # parse_args() must be called before any other imports. if it is not called first, consumers of the config @@ -21,11 +23,12 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from fastapi.middleware.gzip import GZipMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html from fastapi.openapi.utils import get_openapi + from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware from pydantic.json_schema import models_json_schema - from fastapi.responses import FileResponse + from torch.backends.mps import is_available as is_mps_available # for PyCharm: # noinspection PyUnresolvedReferences @@ -38,7 +41,6 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from .api.routers import app_info, board_images, boards, images, models, session_queue, sessions, utilities from .api.sockets import SocketIO from .invocations.baseinvocation import BaseInvocation, UIConfigBase, _InputField, _OutputField - from torch.backends.mps import is_available as is_mps_available if is_mps_available(): import invokeai.backend.util.mps_fixes # noqa: F401 (monkeypatching on import) From 677918df61d9d6221547f11bcf8318af91b9d95c Mon Sep 17 00:00:00 2001 From: Millun Atluri Date: Thu, 19 Oct 2023 14:38:31 +1100 Subject: [PATCH 031/119] Docs Update (python version & T2I (#4867) * Updated Control Adapter Docs * fixed typo * Update docs for 3.10 * Update diffusers language Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com> * Diffusers format Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com> * Current T2I Adapter usage Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com> * Update test-invoke-pip.yml --------- Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com> --- README.md | 2 +- docs/features/CONTROLNET.md | 66 ++++++++++++++++++++----------- docs/help/gettingStartedWithAI.md | 4 +- docs/nodes/communityNodes.md | 2 +- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 15c5747ea8..932bd79ae9 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ and go to http://localhost:9090. ### Command-Line Installation (for developers and users familiar with Terminals) -You must have Python 3.9 through 3.11 installed on your machine. Earlier or +You must have Python 3.10 through 3.11 installed on your machine. Earlier or later versions are not supported. Node.js also needs to be installed along with yarn (can be installed with the command `npm install -g yarn` if needed) diff --git a/docs/features/CONTROLNET.md b/docs/features/CONTROLNET.md index d287e6cb19..f55194207c 100644 --- a/docs/features/CONTROLNET.md +++ b/docs/features/CONTROLNET.md @@ -17,9 +17,6 @@ image generation, providing you with a way to direct the network towards generating images that better fit your desired style or outcome. - -#### How it works - ControlNet works by analyzing an input image, pre-processing that image to identify relevant information that can be interpreted by each specific ControlNet model, and then inserting that control information @@ -27,35 +24,21 @@ into the generation process. This can be used to adjust the style, composition, or other aspects of the image to better achieve a specific result. - -#### Models +#### Installation InvokeAI provides access to a series of ControlNet models that provide -different effects or styles in your generated images. Currently -InvokeAI only supports "diffuser" style ControlNet models. These are -folders that contain the files `config.json` and/or -`diffusion_pytorch_model.safetensors` and -`diffusion_pytorch_model.fp16.safetensors`. The name of the folder is -the name of the model. +different effects or styles in your generated images. -***InvokeAI does not currently support checkpoint-format -ControlNets. These come in the form of a single file with the -extension `.safetensors`.*** +To install ControlNet Models: -Diffuser-style ControlNet models are available at HuggingFace -(http://huggingface.co) and accessed via their repo IDs (identifiers -in the format "author/modelname"). The easiest way to install them is +1. The easiest way to install them is to use the InvokeAI model installer application. Use the `invoke.sh`/`invoke.bat` launcher to select item [4] and then navigate to the CONTROLNETS section. Select the models you wish to install and press "APPLY CHANGES". You may also enter additional HuggingFace -repo_ids in the "Additional models" textbox: +repo_ids in the "Additional models" textbox. +2. Using the "Add Model" function of the model manager, enter the HuggingFace Repo ID of the ControlNet. The ID is in the format "author/repoName" -![Model Installer - -Controlnetl](../assets/installing-models/model-installer-controlnet.png){:width="640px"} - -Command-line users can launch the model installer using the command -`invokeai-model-install`. _Be aware that some ControlNet models require additional code functionality in order to work properly, so just installing a @@ -63,6 +46,17 @@ third-party ControlNet model may not have the desired effect._ Please read and follow the documentation for installing a third party model not currently included among InvokeAI's default list. +Currently InvokeAI **only** supports 🤗 Diffusers-format ControlNet models. These are +folders that contain the files `config.json` and/or +`diffusion_pytorch_model.safetensors` and +`diffusion_pytorch_model.fp16.safetensors`. The name of the folder is +the name of the model. + +🤗 Diffusers-format ControlNet models are available at HuggingFace +(http://huggingface.co) and accessed via their repo IDs (identifiers +in the format "author/modelname"). + +#### ControlNet Models The models currently supported include: **Canny**: @@ -133,6 +127,30 @@ Start/End - 0 represents the start of the generation, 1 represents the end. The Additionally, each ControlNet section can be expanded in order to manipulate settings for the image pre-processor that adjusts your uploaded image before using it in when you Invoke. +## T2I-Adapter +[T2I-Adapter](https://github.com/TencentARC/T2I-Adapter) is a tool similar to ControlNet that allows for control over the generation process by providing control information during the generation process. T2I-Adapter models tend to be smaller and more efficient than ControlNets. + +##### Installation +To install T2I-Adapter Models: + +1. The easiest way to install models is +to use the InvokeAI model installer application. Use the +`invoke.sh`/`invoke.bat` launcher to select item [5] and then navigate +to the T2I-Adapters section. Select the models you wish to install and +press "APPLY CHANGES". You may also enter additional HuggingFace +repo_ids in the "Additional models" textbox. +2. Using the "Add Model" function of the model manager, enter the HuggingFace Repo ID of the T2I-Adapter. The ID is in the format "author/repoName" + +#### Usage +Each T2I Adapter has two settings that are applied. + +Weight - Strength of the model applied to the generation for the section, defined by start/end. + +Start/End - 0 represents the start of the generation, 1 represents the end. The Start/end setting controls what steps during the generation process have the ControlNet applied. + +Additionally, each section can be expanded with the "Show Advanced" button in order to manipulate settings for the image pre-processor that adjusts your uploaded image before using it in during the generation process. + +**Note:** T2I-Adapter models and ControlNet models cannot currently be used together. ## IP-Adapter @@ -140,7 +158,7 @@ Additionally, each ControlNet section can be expanded in order to manipulate set ![IP-Adapter + T2I](https://github.com/tencent-ailab/IP-Adapter/raw/main/assets/demo/ip_adpter_plus_multi.jpg) -![IP-Adapter + IMG2IMG](https://github.com/tencent-ailab/IP-Adapter/blob/main/assets/demo/image-to-image.jpg) +![IP-Adapter + IMG2IMG](https://raw.githubusercontent.com/tencent-ailab/IP-Adapter/main/assets/demo/image-to-image.jpg) #### Installation There are several ways to install IP-Adapter models with an existing InvokeAI installation: diff --git a/docs/help/gettingStartedWithAI.md b/docs/help/gettingStartedWithAI.md index 1f22e1edba..617bd60401 100644 --- a/docs/help/gettingStartedWithAI.md +++ b/docs/help/gettingStartedWithAI.md @@ -57,7 +57,9 @@ Prompts provide the models directions on what to generate. As a general rule of Models are the magic that power InvokeAI. These files represent the output of training a machine on understanding massive amounts of images - providing them with the capability to generate new images using just a text description of what you’d like to see. (Like Stable Diffusion!) -Invoke offers a simple way to download several different models upon installation, but many more can be discovered online, including at ****. Each model can produce a unique style of output, based on the images it was trained on - Try out different models to see which best fits your creative vision! +Invoke offers a simple way to download several different models upon installation, but many more can be discovered online, including at https://models.invoke.ai + +Each model can produce a unique style of output, based on the images it was trained on - Try out different models to see which best fits your creative vision! - *Models that contain “inpainting” in the name are designed for use with the inpainting feature of the Unified Canvas* diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index d5a5d5654f..cec5d18df6 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -181,7 +181,7 @@ This includes 15 Nodes: **Output Example:** - + [Full mp4 of Example Output test.mp4](https://github.com/helix4u/load_video_frame/blob/main/test.mp4) -------------------------------- From 9195c8c95732eabc3b285bc9b3d2a021ad037223 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 18:28:36 +1100 Subject: [PATCH 032/119] feat: dedicated route to get intermediates count This fixes a weird issue where the list images method needed to handle `None` for its `limit` and `offset` arguments, in order to get a count of all intermediates. --- invokeai/app/api/routers/images.py | 13 +++- .../image_records/image_records_base.py | 5 ++ .../image_records/image_records_sqlite.py | 25 +++++-- invokeai/app/services/images/images_base.py | 5 ++ .../app/services/images/images_default.py | 7 ++ .../SettingsClearIntermediates.tsx | 15 ++--- .../web/src/services/api/endpoints/images.ts | 16 ++--- .../frontend/web/src/services/api/schema.d.ts | 65 +++++++++++++------ 8 files changed, 106 insertions(+), 45 deletions(-) diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 43a72943ee..84d8e8eea4 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -87,7 +87,7 @@ async def delete_image( pass -@images_router.post("/clear-intermediates", operation_id="clear_intermediates") +@images_router.delete("/intermediates", operation_id="clear_intermediates") async def clear_intermediates() -> int: """Clears all intermediates""" @@ -99,6 +99,17 @@ async def clear_intermediates() -> int: pass +@images_router.get("/intermediates", operation_id="get_intermediates_count") +async def get_intermediates_count() -> int: + """Gets the count of intermediate images""" + + try: + return ApiDependencies.invoker.services.images.get_intermediates_count() + except Exception: + raise HTTPException(status_code=500, detail="Failed to get intermediates") + pass + + @images_router.patch( "/i/{image_name}", operation_id="update_image", diff --git a/invokeai/app/services/image_records/image_records_base.py b/invokeai/app/services/image_records/image_records_base.py index 107ff85f9b..7e74b06e9e 100644 --- a/invokeai/app/services/image_records/image_records_base.py +++ b/invokeai/app/services/image_records/image_records_base.py @@ -61,6 +61,11 @@ class ImageRecordStorageBase(ABC): """Deletes all intermediate image records, returning a list of deleted image names.""" pass + @abstractmethod + def get_intermediates_count(self) -> int: + """Gets a count of all intermediate images.""" + pass + @abstractmethod def save( self, diff --git a/invokeai/app/services/image_records/image_records_sqlite.py b/invokeai/app/services/image_records/image_records_sqlite.py index 9793236d9c..33bf373a7d 100644 --- a/invokeai/app/services/image_records/image_records_sqlite.py +++ b/invokeai/app/services/image_records/image_records_sqlite.py @@ -297,11 +297,8 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): images_query += query_conditions + query_pagination + ";" # Add all the parameters images_params = query_params.copy() - - if limit is not None: - images_params.append(limit) - if offset is not None: - images_params.append(offset) + # Add the pagination parameters + images_params.extend([limit, offset]) # Build the list of images, deserializing each row self._cursor.execute(images_query, images_params) @@ -357,6 +354,24 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): finally: self._lock.release() + def get_intermediates_count(self) -> int: + try: + self._lock.acquire() + self._cursor.execute( + """--sql + SELECT COUNT(*) FROM images + WHERE is_intermediate = TRUE; + """ + ) + count = cast(int, self._cursor.fetchone()[0]) + self._conn.commit() + return count + except sqlite3.Error as e: + self._conn.rollback() + raise ImageRecordDeleteException from e + finally: + self._lock.release() + def delete_intermediates(self) -> list[str]: try: self._lock.acquire() diff --git a/invokeai/app/services/images/images_base.py b/invokeai/app/services/images/images_base.py index a611e9485d..ac7a4a2152 100644 --- a/invokeai/app/services/images/images_base.py +++ b/invokeai/app/services/images/images_base.py @@ -123,6 +123,11 @@ class ImageServiceABC(ABC): """Deletes all intermediate images.""" pass + @abstractmethod + def get_intermediates_count(self) -> int: + """Gets the number of intermediate images.""" + pass + @abstractmethod def delete_images_on_board(self, board_id: str): """Deletes all images on a board.""" diff --git a/invokeai/app/services/images/images_default.py b/invokeai/app/services/images/images_default.py index d4e473b8e4..3c78c4f29a 100644 --- a/invokeai/app/services/images/images_default.py +++ b/invokeai/app/services/images/images_default.py @@ -284,3 +284,10 @@ class ImageService(ImageServiceABC): except Exception as e: self.__invoker.services.logger.error("Problem deleting image records and files") raise e + + def get_intermediates_count(self) -> int: + try: + return self.__invoker.services.image_records.get_intermediates_count() + except Exception as e: + self.__invoker.services.logger.error("Problem getting intermediates count") + raise e diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx index fbe5692431..c419fa716f 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx @@ -1,7 +1,7 @@ import { Heading, Text } from '@chakra-ui/react'; import { useAppDispatch } from 'app/store/storeHooks'; import { controlAdaptersReset } from 'features/controlAdapters/store/controlAdaptersSlice'; -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useGetQueueStatusQuery } from 'services/api/endpoints/queue'; import IAIButton from '../../../../common/components/IAIButton'; @@ -17,8 +17,12 @@ export default function SettingsClearIntermediates() { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const { data: intermediatesCount, refetch: updateIntermediatesCount } = - useGetIntermediatesCountQuery(); + const { data: intermediatesCount } = useGetIntermediatesCountQuery( + undefined, + { + refetchOnMountOrArgChange: true, + } + ); const [clearIntermediates, { isLoading: isLoadingClearIntermediates }] = useClearIntermediatesMutation(); @@ -55,11 +59,6 @@ export default function SettingsClearIntermediates() { }); }, [t, clearIntermediates, dispatch, hasPendingItems]); - useEffect(() => { - // update the count on mount - updateIntermediatesCount(); - }, [updateIntermediatesCount]); - return ( {t('settings.clearIntermediates')} diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index 99a5fc5f50..c8d42d17f6 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -100,14 +100,12 @@ export const imagesApi = api.injectEndpoints({ keepUnusedDataFor: 86400, }), getIntermediatesCount: build.query({ - query: () => ({ url: getListImagesUrl({ is_intermediate: true }) }), + query: () => ({ url: 'images/intermediates' }), providesTags: ['IntermediatesCount'], - transformResponse: (response: OffsetPaginatedResults_ImageDTO_) => { - // TODO: This is storing a primitive value in the cache. `immer` cannot track state changes, so - // attempts to use manual cache updates on this value will fail. This should be changed into an - // object. - return response.total; - }, + }), + clearIntermediates: build.mutation({ + query: () => ({ url: `images/intermediates`, method: 'DELETE' }), + invalidatesTags: ['IntermediatesCount'], }), getImageDTO: build.query({ query: (image_name) => ({ url: `images/i/${image_name}` }), @@ -185,10 +183,6 @@ export const imagesApi = api.injectEndpoints({ ], keepUnusedDataFor: 86400, // 24 hours }), - clearIntermediates: build.mutation({ - query: () => ({ url: `images/clear-intermediates`, method: 'POST' }), - invalidatesTags: ['IntermediatesCount'], - }), deleteImage: build.mutation({ query: ({ image_name }) => ({ url: `images/i/${image_name}`, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 6bc54f0e35..62f60c1dbc 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -109,12 +109,17 @@ export type paths = { */ patch: operations["update_image"]; }; - "/api/v1/images/clear-intermediates": { + "/api/v1/images/intermediates": { + /** + * Get Intermediates Count + * @description Gets the count of intermediate images + */ + get: operations["get_intermediates_count"]; /** * Clear Intermediates * @description Clears all intermediates */ - post: operations["clear_intermediates"]; + delete: operations["clear_intermediates"]; }; "/api/v1/images/i/{image_name}/metadata": { /** @@ -3002,7 +3007,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["IntegerInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["InfillColorInvocation"]; + [key: string]: components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlendLatentsInvocation"]; }; /** * Edges @@ -3039,7 +3044,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["String2Output"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["StringPosNegOutput"]; + [key: string]: components["schemas"]["IntegerOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["String2Output"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ClipSkipInvocationOutput"]; }; /** * Errors @@ -3169,8 +3174,11 @@ export type components = { }; /** IPAdapterField */ IPAdapterField: { - /** @description The IP-Adapter image prompt. */ - image: components["schemas"]["ImageField"]; + /** + * Image + * @description The IP-Adapter image prompt(s). + */ + image: components["schemas"]["ImageField"] | components["schemas"]["ImageField"][]; /** @description The IP-Adapter model to use. */ ip_adapter_model: components["schemas"]["IPAdapterModelField"]; /** @description The name of the CLIP image encoder model. */ @@ -3221,8 +3229,11 @@ export type components = { * @default true */ use_cache?: boolean | null; - /** @description The IP-Adapter image prompt. */ - image?: components["schemas"]["ImageField"]; + /** + * Image + * @description The IP-Adapter image prompt(s). + */ + image?: components["schemas"]["ImageField"] | components["schemas"]["ImageField"][]; /** * IP-Adapter Model * @description The IP-Adapter model. @@ -9105,12 +9116,6 @@ export type components = { /** Ui Order */ ui_order: number | null; }; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusion1ModelFormat * @description An enumeration. @@ -9118,17 +9123,17 @@ export type components = { */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusionOnnxModelFormat + * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; + T2IAdapterModelFormat: "diffusers"; /** - * StableDiffusion2ModelFormat + * ControlNetModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + ControlNetModelFormat: "checkpoint" | "diffusers"; /** * IPAdapterModelFormat * @description An enumeration. @@ -9142,11 +9147,17 @@ export type components = { */ CLIPVisionModelFormat: "diffusers"; /** - * T2IAdapterModelFormat + * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ - T2IAdapterModelFormat: "diffusers"; + StableDiffusionOnnxModelFormat: "olive" | "onnx"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. @@ -9670,6 +9681,20 @@ export type operations = { }; }; }; + /** + * Get Intermediates Count + * @description Gets the count of intermediate images + */ + get_intermediates_count: { + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": number; + }; + }; + }; + }; /** * Clear Intermediates * @description Clears all intermediates From f102e380768031d288c51ec635813cefc8c143db Mon Sep 17 00:00:00 2001 From: Eugene Brodsky Date: Tue, 10 Oct 2023 23:03:25 -0400 Subject: [PATCH 033/119] feat(docker): update docker image, etc. to python3.11+ubuntu23.04 --- .gitignore | 12 +----------- docker/Dockerfile | 17 ++++++----------- docker/docker-entrypoint.sh | 2 +- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 44a0864b5b..2b99d137b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,5 @@ .idea/ -# ignore the Anaconda/Miniconda installer used while building Docker image -anaconda.sh - # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -136,12 +133,10 @@ celerybeat.pid # Environments .env -.venv +.venv* env/ venv/ ENV/ -env.bak/ -venv.bak/ # Spyder project settings .spyderproject @@ -186,11 +181,6 @@ cython_debug/ .scratch/ .vscode/ -# ignore environment.yml and requirements.txt -# these are links to the real files in environments-and-requirements -environment.yml -requirements.txt - # source installer files installer/*zip installer/install.bat diff --git a/docker/Dockerfile b/docker/Dockerfile index e158c681a4..73852ec66e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,7 +2,7 @@ ## Builder stage -FROM library/ubuntu:22.04 AS builder +FROM library/ubuntu:23.04 AS builder ARG DEBIAN_FRONTEND=noninteractive RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache @@ -10,7 +10,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt update && apt-get install -y \ git \ - python3.10-venv \ + python3-venv \ python3-pip \ build-essential @@ -37,7 +37,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ elif [ "$GPU_DRIVER" = "rocm" ]; then \ extra_index_url_arg="--extra-index-url https://download.pytorch.org/whl/rocm5.4.2"; \ else \ - extra_index_url_arg="--extra-index-url https://download.pytorch.org/whl/cu118"; \ + extra_index_url_arg="--extra-index-url https://download.pytorch.org/whl/cu121"; \ fi &&\ pip install $extra_index_url_arg \ torch==$TORCH_VERSION \ @@ -70,7 +70,7 @@ RUN --mount=type=cache,target=/usr/lib/node_modules \ #### Runtime stage --------------------------------------- -FROM library/ubuntu:22.04 AS runtime +FROM library/ubuntu:23.04 AS runtime ARG DEBIAN_FRONTEND=noninteractive ENV PYTHONUNBUFFERED=1 @@ -85,6 +85,7 @@ RUN apt update && apt install -y --no-install-recommends \ iotop \ bzip2 \ gosu \ + magic-wormhole \ libglib2.0-0 \ libgl1-mesa-glx \ python3-venv \ @@ -94,10 +95,6 @@ RUN apt update && apt install -y --no-install-recommends \ libstdc++-10-dev &&\ apt-get clean && apt-get autoclean -# globally add magic-wormhole -# for ease of transferring data to and from the container -# when running in sandboxed cloud environments; e.g. Runpod etc. -RUN pip install magic-wormhole ENV INVOKEAI_SRC=/opt/invokeai ENV VIRTUAL_ENV=/opt/venv/invokeai @@ -120,9 +117,7 @@ WORKDIR ${INVOKEAI_SRC} RUN cd /usr/lib/$(uname -p)-linux-gnu/pkgconfig/ && ln -sf opencv4.pc opencv.pc RUN python3 -c "from patchmatch import patch_match" -# Create unprivileged user and make the local dir -RUN useradd --create-home --shell /bin/bash -u 1000 --comment "container local user" invoke -RUN mkdir -p ${INVOKEAI_ROOT} && chown -R invoke:invoke ${INVOKEAI_ROOT} +RUN mkdir -p ${INVOKEAI_ROOT} && chown -R 1000:1000 ${INVOKEAI_ROOT} COPY docker/docker-entrypoint.sh ./ ENTRYPOINT ["/opt/invokeai/docker-entrypoint.sh"] diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 6d776feb0e..7a9e6921ce 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -19,7 +19,7 @@ set -e -o pipefail # Default UID: 1000 chosen due to popularity on Linux systems. Possibly 501 on MacOS. USER_ID=${CONTAINER_UID:-1000} -USER=invoke +USER=ubuntu usermod -u ${USER_ID} ${USER} 1>/dev/null configure() { From 575c7bbfd8d3a36ca8043b033b13ceb810082e06 Mon Sep 17 00:00:00 2001 From: Eugene Brodsky Date: Thu, 19 Oct 2023 11:25:47 -0400 Subject: [PATCH 034/119] feat(docker): update docker documentation --- docker/.env.sample | 8 +- docker/README.md | 19 +- docker/build.sh | 4 +- docker/run.sh | 7 +- docs/installation/040_INSTALL_DOCKER.md | 258 ++++-------------------- 5 files changed, 62 insertions(+), 234 deletions(-) diff --git a/docker/.env.sample b/docker/.env.sample index 7e414ecd65..c0a56402fc 100644 --- a/docker/.env.sample +++ b/docker/.env.sample @@ -1,13 +1,15 @@ ## Make a copy of this file named `.env` and fill in the values below. -## Any environment variables supported by InvokeAI can be specified here. +## Any environment variables supported by InvokeAI can be specified here, +## in addition to the examples below. # INVOKEAI_ROOT is the path to a path on the local filesystem where InvokeAI will store data. # Outputs will also be stored here by default. # This **must** be an absolute path. INVOKEAI_ROOT= -HUGGINGFACE_TOKEN= +# Get this value from your HuggingFace account settings page. +# HUGGING_FACE_HUB_TOKEN= -## optional variables specific to the docker setup +## optional variables specific to the docker setup. # GPU_DRIVER=cuda # CONTAINER_UID=1000 \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index 91f7fb8c51..4291ece25f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,7 +5,7 @@ All commands are to be run from the `docker` directory: `cd docker` #### Linux 1. Ensure builkit is enabled in the Docker daemon settings (`/etc/docker/daemon.json`) -2. Install the `docker compose` plugin using your package manager, or follow a [tutorial](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-22-04). +2. Install the `docker compose` plugin using your package manager, or follow a [tutorial](https://docs.docker.com/compose/install/linux/#install-using-the-repository). - The deprecated `docker-compose` (hyphenated) CLI continues to work for now. 3. Ensure docker daemon is able to access the GPU. - You may need to install [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) @@ -20,7 +20,6 @@ This is done via Docker Desktop preferences ## Quickstart - 1. Make a copy of `env.sample` and name it `.env` (`cp env.sample .env` (Mac/Linux) or `copy example.env .env` (Windows)). Make changes as necessary. Set `INVOKEAI_ROOT` to an absolute path to: a. the desired location of the InvokeAI runtime directory, or b. an existing, v3.0.0 compatible runtime directory. @@ -42,20 +41,22 @@ The Docker daemon on the system must be already set up to use the GPU. In case o Check the `.env.sample` file. It contains some environment variables for running in Docker. Copy it, name it `.env`, and fill it in with your own values. Next time you run `docker compose up`, your custom values will be used. -You can also set these values in `docker compose.yml` directly, but `.env` will help avoid conflicts when code is updated. +You can also set these values in `docker-compose.yml` directly, but `.env` will help avoid conflicts when code is updated. -Example (most values are optional): +Example (values are optional, but setting `INVOKEAI_ROOT` is highly recommended): -``` +```bash INVOKEAI_ROOT=/Volumes/WorkDrive/invokeai HUGGINGFACE_TOKEN=the_actual_token CONTAINER_UID=1000 GPU_DRIVER=cuda ``` +Any environment variables supported by InvokeAI can be set here - please see the [Configuration docs](https://invoke-ai.github.io/InvokeAI/features/CONFIGURATION/) for further detail. + ## Even Moar Customizing! -See the `docker compose.yaml` file. The `command` instruction can be uncommented and used to run arbitrary startup commands. Some examples below. +See the `docker-compose.yml` file. The `command` instruction can be uncommented and used to run arbitrary startup commands. Some examples below. ### Reconfigure the runtime directory @@ -63,7 +64,7 @@ Can be used to download additional models from the supported model list In conjunction with `INVOKEAI_ROOT` can be also used to initialize a runtime directory -``` +```yaml command: - invokeai-configure - --yes @@ -71,7 +72,7 @@ command: Or install models: -``` +```yaml command: - invokeai-model-install -``` \ No newline at end of file +``` diff --git a/docker/build.sh b/docker/build.sh index db25439840..3b3875c15c 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -5,7 +5,7 @@ build_args="" [[ -f ".env" ]] && build_args=$(awk '$1 ~ /\=[^$]/ {print "--build-arg " $0 " "}' .env) -echo "docker-compose build args:" +echo "docker compose build args:" echo $build_args -docker-compose build $build_args +docker compose build $build_args diff --git a/docker/run.sh b/docker/run.sh index bb764ec022..0306c4ddab 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -1,8 +1,11 @@ #!/usr/bin/env bash set -e +# This script is provided for backwards compatibility with the old docker setup. +# it doesn't do much aside from wrapping the usual docker compose CLI. + SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") cd "$SCRIPTDIR" || exit 1 -docker-compose up --build -d -docker-compose logs -f +docker compose up --build -d +docker compose logs -f diff --git a/docs/installation/040_INSTALL_DOCKER.md b/docs/installation/040_INSTALL_DOCKER.md index fd75067cf1..a672f71ba8 100644 --- a/docs/installation/040_INSTALL_DOCKER.md +++ b/docs/installation/040_INSTALL_DOCKER.md @@ -4,30 +4,31 @@ title: Installing with Docker # :fontawesome-brands-docker: Docker -!!! warning "For most users" +!!! warning "macOS and AMD GPU Users" - We highly recommend to Install InvokeAI locally using [these instructions](INSTALLATION.md) + We highly recommend to Install InvokeAI locally using [these instructions](INSTALLATION.md), + because Docker containers can not access the GPU on macOS. -!!! tip "For developers" +!!! warning "AMD GPU Users" - For container-related development tasks or for enabling easy - deployment to other environments (on-premises or cloud), follow these - instructions. + Container support for AMD GPUs has been reported to work by the community, but has not received + extensive testing. Please make sure to set the `GPU_DRIVER=rocm` environment variable (see below), and + use the `build.sh` script to build the image for this to take effect at build time. - For general use, install locally to leverage your machine's GPU. +!!! tip "Linux and Windows Users" + + For optimal performance, configure your Docker daemon to access your machine's GPU. + Docker Desktop on Windows [includes GPU support](https://www.docker.com/blog/wsl-2-gpu-support-for-docker-desktop-on-nvidia-gpus/). + Linux users should install and configure the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) ## Why containers? -They provide a flexible, reliable way to build and deploy InvokeAI. You'll also -use a Docker volume to store the largest model files and image outputs as a -first step in decoupling storage and compute. Future enhancements can do this -for other assets. See [Processes](https://12factor.net/processes) under the -Twelve-Factor App methodology for details on why running applications in such a -stateless fashion is important. +They provide a flexible, reliable way to build and deploy InvokeAI. +See [Processes](https://12factor.net/processes) under the Twelve-Factor App +methodology for details on why running applications in such a stateless fashion is important. -You can specify the target platform when building the image and running the -container. You'll also need to specify the InvokeAI requirements file that -matches the container's OS and the architecture it will run on. +The container is configured for CUDA by default, but can be built to support AMD GPUs +by setting the `GPU_DRIVER=rocm` environment variable at Docker image build time. Developers on Apple silicon (M1/M2): You [can't access your GPU cores from Docker containers](https://github.com/pytorch/pytorch/issues/81224) @@ -36,6 +37,16 @@ development purposes it's fine. Once you're done with development tasks on your laptop you can build for the target platform and architecture and deploy to another environment with NVIDIA GPUs on-premises or in the cloud. +## TL;DR + +This assumes properly configured Docker on Linux or Windows/WSL2. Read on for detailed customization options. + + ```bash + # docker compose commands should be run from the `docker` directory + cd docker + docker compose up + ``` + ## Installation in a Linux container (desktop) ### Prerequisites @@ -58,222 +69,33 @@ a token and copy it, since you will need in for the next step. ### Setup -Set the fork you want to use and other variables. +Set up your environmnent variables. In the `docker` directory, make a copy of `env.sample` and name it `.env`. Make changes as necessary. -!!! tip +Any environment variables supported by InvokeAI can be set here - please see the [CONFIGURATION](../features/CONFIGURATION.md) for further detail. - I preffer to save my env vars - in the repository root in a `.env` (or `.envrc`) file to automatically re-apply - them when I come back. - -The build- and run- scripts contain default values for almost everything, -besides the [Hugging Face Token](https://huggingface.co/settings/tokens) you -created in the last step. - -Some Suggestions of variables you may want to change besides the Token: +At a minimum, you might want to set the `INVOKEAI_ROOT` environment variable +to point to the location where you wish to store your InvokeAI models, configuration, and outputs.
| Environment-Variable | Default value | Description | | ----------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `HUGGING_FACE_HUB_TOKEN` | No default, but **required**! | This is the only **required** variable, without it you can't download the huggingface models | -| `REPOSITORY_NAME` | The Basename of the Repo folder | This name will used as the container repository/image name | -| `VOLUMENAME` | `${REPOSITORY_NAME,,}_data` | Name of the Docker Volume where model files will be stored | -| `ARCH` | arch of the build machine | Can be changed if you want to build the image for another arch | -| `CONTAINER_REGISTRY` | ghcr.io | Name of the Container Registry to use for the full tag | -| `CONTAINER_REPOSITORY` | `$(whoami)/${REPOSITORY_NAME}` | Name of the Container Repository | -| `CONTAINER_FLAVOR` | `cuda` | The flavor of the image to built, available options are `cuda`, `rocm` and `cpu`. If you choose `rocm` or `cpu`, the extra-index-url will be selected automatically, unless you set one yourself. | -| `CONTAINER_TAG` | `${INVOKEAI_BRANCH##*/}-${CONTAINER_FLAVOR}` | The Container Repository / Tag which will be used | -| `INVOKE_DOCKERFILE` | `Dockerfile` | The Dockerfile which should be built, handy for development | -| `PIP_EXTRA_INDEX_URL` | | If you want to use a custom pip-extra-index-url | +| `INVOKEAI_ROOT` | `~/invokeai` | **Required** - the location of your InvokeAI root directory. It will be created if it does not exist. +| `HUGGING_FACE_HUB_TOKEN` | | InvokeAI will work without it, but some of the integrations with HuggingFace (like downloading from models from private repositories) may not work| +| `GPU_DRIVER` | `cuda` | Optionally change this to `rocm` to build the image for AMD GPUs. NOTE: Use the `build.sh` script to build the image for this to take effect.
#### Build the Image -I provided a build script, which is located next to the Dockerfile in -`docker/build.sh`. It can be executed from repository root like this: +Use the standard `docker compose build` command from within the `docker` directory. -```bash -./docker/build.sh -``` - -The build Script not only builds the container, but also creates the docker -volume if not existing yet. +If using an AMD GPU: + a: set the `GPU_DRIVER=rocm` environment variable in `docker-compose.yml` and continue using `docker compose build` as usual, or + b: set `GPU_DRIVER=rocm` in the `.env` file and use the `build.sh` script, provided for convenience #### Run the Container -After the build process is done, you can run the container via the provided -`docker/run.sh` script +Use the standard `docker compose up` command, and generally the `docker compose` [CLI](https://docs.docker.com/compose/reference/) as usual. -```bash -./docker/run.sh -``` - -When used without arguments, the container will start the webserver and provide -you the link to open it. But if you want to use some other parameters you can -also do so. - -!!! example "run script example" - - ```bash - ./docker/run.sh "banana sushi" -Ak_lms -S42 -s10 - ``` - - This would generate the legendary "banana sushi" with Seed 42, k_lms Sampler and 10 steps. - - Find out more about available CLI-Parameters at [features/CLI.md](../../features/CLI/#arguments) - ---- - -## Running the container on your GPU - -If you have an Nvidia GPU, you can enable InvokeAI to run on the GPU by running -the container with an extra environment variable to enable GPU usage and have -the process run much faster: - -```bash -GPU_FLAGS=all ./docker/run.sh -``` - -This passes the `--gpus all` to docker and uses the GPU. - -If you don't have a GPU (or your host is not yet setup to use it) you will see a -message like this: - -`docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].` - -You can use the full set of GPU combinations documented here: - -https://docs.docker.com/config/containers/resource_constraints/#gpu - -For example, use `GPU_FLAGS=device=GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a` to -choose a specific device identified by a UUID. - ---- - -!!! warning "Deprecated" - - From here on you will find the the previous Docker-Docs, which will still - provide some usefull informations. - -## Usage (time to have fun) - -### Startup - -If you're on a **Linux container** the `invoke` script is **automatically -started** and the output dir set to the Docker volume you created earlier. - -If you're **directly on macOS follow these startup instructions**. With the -Conda environment activated (`conda activate ldm`), run the interactive -interface that combines the functionality of the original scripts `txt2img` and -`img2img`: Use the more accurate but VRAM-intensive full precision math because -half-precision requires autocast and won't work. By default the images are saved -in `outputs/img-samples/`. - -```Shell -python3 scripts/invoke.py --full_precision -``` - -You'll get the script's prompt. You can see available options or quit. - -```Shell -invoke> -h -invoke> q -``` - -### Text to Image - -For quick (but bad) image results test with 5 steps (default 50) and 1 sample -image. This will let you know that everything is set up correctly. Then increase -steps to 100 or more for good (but slower) results. The prompt can be in quotes -or not. - -```Shell -invoke> The hulk fighting with sheldon cooper -s5 -n1 -invoke> "woman closeup highly detailed" -s 150 -# Reuse previous seed and apply face restoration -invoke> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75 -``` - -You'll need to experiment to see if face restoration is making it better or -worse for your specific prompt. - -If you're on a container the output is set to the Docker volume. You can copy it -wherever you want. You can download it from the Docker Desktop app, Volumes, -my-vol, data. Or you can copy it from your Mac terminal. Keep in mind -`docker cp` can't expand `*.png` so you'll need to specify the image file name. - -On your host Mac (you can use the name of any container that mounted the -volume): - -```Shell -docker cp dummy:/data/000001.928403745.png /Users//Pictures -``` - -### Image to Image - -You can also do text-guided image-to-image translation. For example, turning a -sketch into a detailed drawing. - -`strength` is a value between 0.0 and 1.0 that controls the amount of noise that -is added to the input image. Values that approach 1.0 allow for lots of -variations but will also produce images that are not semantically consistent -with the input. 0.0 preserves image exactly, 1.0 replaces it completely. - -Make sure your input image size dimensions are multiples of 64 e.g. 512x512. -Otherwise you'll get `Error: product of dimension sizes > 2**31'`. If you still -get the error -[try a different size](https://support.apple.com/guide/preview/resize-rotate-or-flip-an-image-prvw2015/mac#:~:text=image's%20file%20size-,In%20the%20Preview%20app%20on%20your%20Mac%2C%20open%20the%20file,is%20shown%20at%20the%20bottom.) -like 512x256. - -If you're on a Docker container, copy your input image into the Docker volume - -```Shell -docker cp /Users//Pictures/sketch-mountains-input.jpg dummy:/data/ -``` - -Try it out generating an image (or more). The `invoke` script needs absolute -paths to find the image so don't use `~`. - -If you're on your Mac - -```Shell -invoke> "A fantasy landscape, trending on artstation" -I /Users//Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4 -``` - -If you're on a Linux container on your Mac - -```Shell -invoke> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1 -``` - -### Web Interface - -You can use the `invoke` script with a graphical web interface. Start the web -server with: - -```Shell -python3 scripts/invoke.py --full_precision --web -``` - -If it's running on your Mac point your Mac web browser to - - -Press Control-C at the command line to stop the web server. - -### Notes - -Some text you can add at the end of the prompt to make it very pretty: - -```Shell -cinematic photo, highly detailed, cinematic lighting, ultra-detailed, ultrarealistic, photorealism, Octane Rendering, cyberpunk lights, Hyper Detail, 8K, HD, Unreal Engine, V-Ray, full hd, cyberpunk, abstract, 3d octane render + 4k UHD + immense detail + dramatic lighting + well lit + black, purple, blue, pink, cerulean, teal, metallic colours, + fine details, ultra photoreal, photographic, concept art, cinematic composition, rule of thirds, mysterious, eerie, photorealism, breathtaking detailed, painting art deco pattern, by hsiao, ron cheng, john james audubon, bizarre compositions, exquisite detail, extremely moody lighting, painted by greg rutkowski makoto shinkai takashi takeuchi studio ghibli, akihiko yoshida -``` - -The original scripts should work as well. - -```Shell -python3 scripts/orig_scripts/txt2img.py --help -python3 scripts/orig_scripts/txt2img.py --ddim_steps 100 --n_iter 1 --n_samples 1 --plms --prompt "new born baby kitten. Hyper Detail, Octane Rendering, Unreal Engine, V-Ray" -python3 scripts/orig_scripts/txt2img.py --ddim_steps 5 --n_iter 1 --n_samples 1 --plms --prompt "ocean" # or --klms -``` +Once the container starts up (and configures the InvokeAI root directory if this is a new installation), you can access InvokeAI at [http://localhost:9090](http://localhost:9090) From c2da74c5871e5992eed0fedc088d4b46e5731464 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 17:02:15 +1100 Subject: [PATCH 035/119] feat: add workflows table & service --- invokeai/app/api/dependencies.py | 3 + invokeai/app/api/routers/workflows.py | 20 +++ invokeai/app/api_app.py | 20 ++- invokeai/app/invocations/baseinvocation.py | 32 +--- invokeai/app/services/invocation_services.py | 4 + .../app/services/workflow_records/__init__.py | 0 .../workflow_records/workflow_records_base.py | 17 ++ .../workflow_records_common.py | 22 +++ .../workflow_records_sqlite.py | 148 ++++++++++++++++++ tests/nodes/test_graph_execution_state.py | 1 + tests/nodes/test_invoker.py | 1 + 11 files changed, 235 insertions(+), 33 deletions(-) create mode 100644 invokeai/app/api/routers/workflows.py create mode 100644 invokeai/app/services/workflow_records/__init__.py create mode 100644 invokeai/app/services/workflow_records/workflow_records_base.py create mode 100644 invokeai/app/services/workflow_records/workflow_records_common.py create mode 100644 invokeai/app/services/workflow_records/workflow_records_sqlite.py diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index c9a2f0a843..ae4882c0d0 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -30,6 +30,7 @@ from ..services.shared.default_graphs import create_system_graphs from ..services.shared.graph import GraphExecutionState, LibraryGraph from ..services.shared.sqlite import SqliteDatabase from ..services.urls.urls_default import LocalUrlService +from ..services.workflow_records.workflow_records_sqlite import SqliteWorkflowRecordsStorage from .events import FastAPIEventService @@ -90,6 +91,7 @@ class ApiDependencies: session_processor = DefaultSessionProcessor() session_queue = SqliteSessionQueue(db=db) urls = LocalUrlService() + workflow_records = SqliteWorkflowRecordsStorage(db=db) services = InvocationServices( board_image_records=board_image_records, @@ -114,6 +116,7 @@ class ApiDependencies: session_processor=session_processor, session_queue=session_queue, urls=urls, + workflow_records=workflow_records, ) create_system_graphs(services.graph_library) diff --git a/invokeai/app/api/routers/workflows.py b/invokeai/app/api/routers/workflows.py new file mode 100644 index 0000000000..814123fc81 --- /dev/null +++ b/invokeai/app/api/routers/workflows.py @@ -0,0 +1,20 @@ +from fastapi import APIRouter, Body, Path + +from invokeai.app.api.dependencies import ApiDependencies +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField + +workflows_router = APIRouter(prefix="/v1/workflows", tags=["workflows"]) + + +@workflows_router.get( + "/i/{workflow_id}", + operation_id="get_workflow", + responses={ + 200: {"model": WorkflowField}, + }, +) +async def get_workflow( + workflow_id: str = Path(description="The workflow to get"), +) -> WorkflowField: + """Gets a workflow""" + return ApiDependencies.invoker.services.workflow_records.get(workflow_id) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 866a6665c8..e04cf564ab 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -38,7 +38,17 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from ..backend.util.logging import InvokeAILogger from .api.dependencies import ApiDependencies - from .api.routers import app_info, board_images, boards, images, models, session_queue, sessions, utilities + from .api.routers import ( + app_info, + board_images, + boards, + images, + models, + sessions, + session_queue, + utilities, + workflows, + ) from .api.sockets import SocketIO from .invocations.baseinvocation import BaseInvocation, UIConfigBase, _InputField, _OutputField @@ -95,18 +105,13 @@ async def shutdown_event() -> None: app.include_router(sessions.session_router, prefix="/api") app.include_router(utilities.utilities_router, prefix="/api") - app.include_router(models.models_router, prefix="/api") - app.include_router(images.images_router, prefix="/api") - app.include_router(boards.boards_router, prefix="/api") - app.include_router(board_images.board_images_router, prefix="/api") - app.include_router(app_info.app_router, prefix="/api") - app.include_router(session_queue.session_queue_router, prefix="/api") +app.include_router(workflows.workflows_router, prefix="/api") # Build a custom OpenAPI to include all outputs @@ -166,7 +171,6 @@ def custom_openapi() -> dict[str, Any]: # print(f"Config with name {name} already defined") continue - # "BaseModelType":{"title":"BaseModelType","description":"An enumeration.","enum":["sd-1","sd-2"],"type":"string"} openapi_schema["components"]["schemas"][name] = dict( title=name, description="An enumeration.", diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index ba94e7c440..f2e5f33e6e 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -2,7 +2,6 @@ from __future__ import annotations -import json import re from abc import ABC, abstractmethod from enum import Enum @@ -11,12 +10,13 @@ from types import UnionType from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Literal, Optional, Type, TypeVar, Union import semver -from pydantic import BaseModel, ConfigDict, Field, create_model, field_validator +from pydantic import BaseModel, ConfigDict, Field, RootModel, TypeAdapter, create_model from pydantic.fields import _Unset from pydantic_core import PydanticUndefined from invokeai.app.services.config.config_default import InvokeAIAppConfig from invokeai.app.util.misc import uuid_string +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField if TYPE_CHECKING: from ..services.invocation_services import InvocationServices @@ -60,7 +60,7 @@ class FieldDescriptions: denoised_latents = "Denoised latents tensor" latents = "Latents tensor" strength = "Strength of denoising (proportional to steps)" - core_metadata = "Optional core metadata to be written to image" + workflow = "Optional workflow to be saved with the image" interp_mode = "Interpolation mode" torch_antialias = "Whether or not to apply antialiasing (bilinear or bicubic only)" fp32 = "Whether or not to use full float32 precision" @@ -665,27 +665,7 @@ class BaseInvocation(ABC, BaseModel): description="Whether or not this is an intermediate invocation.", json_schema_extra=dict(ui_type=UIType.IsIntermediate), ) - workflow: Optional[str] = Field( - default=None, - description="The workflow to save with the image", - json_schema_extra=dict(ui_type=UIType.WorkflowField), - ) - use_cache: Optional[bool] = Field( - default=True, - description="Whether or not to use the cache", - ) - - @field_validator("workflow", mode="before") - @classmethod - def validate_workflow_is_json(cls, v): - """We don't have a workflow schema in the backend, so we just check that it's valid JSON""" - if v is None: - return None - try: - json.loads(v) - except json.decoder.JSONDecodeError: - raise ValueError("Workflow must be valid JSON") - return v + use_cache: bool = InputField(default=True, description="Whether or not to use the cache") UIConfig: ClassVar[Type[UIConfigBase]] @@ -824,4 +804,6 @@ def invocation_output( return wrapper -GenericBaseModel = TypeVar("GenericBaseModel", bound=BaseModel) +class WithWorkflow(BaseModel): + workflow: Optional[WorkflowField] = InputField(default=None, description=FieldDescriptions.workflow) + diff --git a/invokeai/app/services/invocation_services.py b/invokeai/app/services/invocation_services.py index ba53ea50cf..94db75d810 100644 --- a/invokeai/app/services/invocation_services.py +++ b/invokeai/app/services/invocation_services.py @@ -27,6 +27,7 @@ if TYPE_CHECKING: from .session_queue.session_queue_base import SessionQueueBase from .shared.graph import GraphExecutionState, LibraryGraph from .urls.urls_base import UrlServiceBase + from .workflow_records.workflow_records_base import WorkflowRecordsStorageBase class InvocationServices: @@ -55,6 +56,7 @@ class InvocationServices: invocation_cache: "InvocationCacheBase" names: "NameServiceBase" urls: "UrlServiceBase" + workflow_records: "WorkflowRecordsStorageBase" def __init__( self, @@ -80,6 +82,7 @@ class InvocationServices: invocation_cache: "InvocationCacheBase", names: "NameServiceBase", urls: "UrlServiceBase", + workflow_records: "WorkflowRecordsStorageBase", ): self.board_images = board_images self.board_image_records = board_image_records @@ -103,3 +106,4 @@ class InvocationServices: self.invocation_cache = invocation_cache self.names = names self.urls = urls + self.workflow_records = workflow_records diff --git a/invokeai/app/services/workflow_records/__init__.py b/invokeai/app/services/workflow_records/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/invokeai/app/services/workflow_records/workflow_records_base.py b/invokeai/app/services/workflow_records/workflow_records_base.py new file mode 100644 index 0000000000..97f7cfe3c0 --- /dev/null +++ b/invokeai/app/services/workflow_records/workflow_records_base.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod + +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField + + +class WorkflowRecordsStorageBase(ABC): + """Base class for workflow storage services.""" + + @abstractmethod + def get(self, workflow_id: str) -> WorkflowField: + """Get workflow by id.""" + pass + + @abstractmethod + def create(self, workflow: WorkflowField) -> WorkflowField: + """Creates a workflow.""" + pass diff --git a/invokeai/app/services/workflow_records/workflow_records_common.py b/invokeai/app/services/workflow_records/workflow_records_common.py new file mode 100644 index 0000000000..d548656dab --- /dev/null +++ b/invokeai/app/services/workflow_records/workflow_records_common.py @@ -0,0 +1,22 @@ +from typing import Any + +from pydantic import Field, RootModel, TypeAdapter + + +class WorkflowNotFoundError(Exception): + """Raised when a workflow is not found""" + + +class WorkflowField(RootModel): + """ + Pydantic model for workflows with custom root of type dict[str, Any]. + Workflows are stored without a strict schema. + """ + + root: dict[str, Any] = Field(description="Workflow dict") + + def model_dump(self, *args, **kwargs) -> dict[str, Any]: + return super().model_dump(*args, **kwargs)["root"] + + +type_adapter_WorkflowField = TypeAdapter(WorkflowField) diff --git a/invokeai/app/services/workflow_records/workflow_records_sqlite.py b/invokeai/app/services/workflow_records/workflow_records_sqlite.py new file mode 100644 index 0000000000..2b284ac03f --- /dev/null +++ b/invokeai/app/services/workflow_records/workflow_records_sqlite.py @@ -0,0 +1,148 @@ +import sqlite3 +import threading + +from invokeai.app.services.invoker import Invoker +from invokeai.app.services.shared.sqlite import SqliteDatabase +from invokeai.app.services.workflow_records.workflow_records_base import WorkflowRecordsStorageBase +from invokeai.app.services.workflow_records.workflow_records_common import ( + WorkflowField, + WorkflowNotFoundError, + type_adapter_WorkflowField, +) +from invokeai.app.util.misc import uuid_string + + +class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase): + _invoker: Invoker + _conn: sqlite3.Connection + _cursor: sqlite3.Cursor + _lock: threading.RLock + + def __init__(self, db: SqliteDatabase) -> None: + super().__init__() + self._lock = db.lock + self._conn = db.conn + self._cursor = self._conn.cursor() + self._create_tables() + + def start(self, invoker: Invoker) -> None: + self._invoker = invoker + + def get(self, workflow_id: str) -> WorkflowField: + try: + self._lock.acquire() + self._cursor.execute( + """--sql + SELECT workflow + FROM workflows + WHERE workflow_id = ?; + """, + (workflow_id,), + ) + row = self._cursor.fetchone() + if row is None: + raise WorkflowNotFoundError(f"Workflow with id {workflow_id} not found") + return type_adapter_WorkflowField.validate_json(row[0]) + except Exception: + self._conn.rollback() + raise + finally: + self._lock.release() + + def create(self, workflow: WorkflowField) -> WorkflowField: + try: + # workflows do not have ids until they are saved + workflow_id = uuid_string() + workflow.root["id"] = workflow_id + self._lock.acquire() + self._cursor.execute( + """--sql + INSERT INTO workflows(workflow) + VALUES (?); + """, + (workflow.json(),), + ) + self._conn.commit() + except Exception: + self._conn.rollback() + raise + finally: + self._lock.release() + return self.get(workflow_id) + + def _create_tables(self) -> None: + try: + self._lock.acquire() + self._cursor.execute( + """--sql + CREATE TABLE IF NOT EXISTS workflows ( + workflow TEXT NOT NULL, + workflow_id TEXT GENERATED ALWAYS AS (json_extract(workflow, '$.id')) VIRTUAL NOT NULL UNIQUE, -- gets implicit index + created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), + updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) -- updated via trigger + ); + """ + ) + + self._cursor.execute( + """--sql + CREATE TRIGGER IF NOT EXISTS tg_workflows_updated_at + AFTER UPDATE + ON workflows FOR EACH ROW + BEGIN + UPDATE workflows + SET updated_at = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') + WHERE workflow_id = old.workflow_id; + END; + """ + ) + + self._conn.commit() + except Exception: + self._conn.rollback() + raise + finally: + self._lock.release() + + # def update(self, workflow_id: str, workflow: Workflow) -> Workflow: + # """Updates a workflow record.""" + # try: + # workflow_id = workflow.get("id", None) + # if type(workflow_id) is not str: + # raise WorkflowNotFoundError(f"Workflow does not have a valid id, got {workflow_id}") + # self._lock.acquire() + # self._cursor.execute( + # """--sql + # UPDATE workflows + # SET workflow = ? + # WHERE workflow_id = ? + # """, + # (workflow, workflow_id), + # ) + # self._conn.commit() + # except Exception: + # self._conn.rollback() + # raise + # finally: + # self._lock.release() + # return self.get(workflow_id) + + # def delete(self, workflow_id: str) -> Workflow: + # """Updates a workflow record.""" + # workflow = self.get(workflow_id) + # try: + # self._lock.acquire() + # self._cursor.execute( + # """--sql + # DELETE FROM workflows + # WHERE workflow_id = ? + # """, + # (workflow_id,), + # ) + # self._conn.commit() + # except Exception: + # self._conn.rollback() + # raise + # finally: + # self._lock.release() + # return workflow diff --git a/tests/nodes/test_graph_execution_state.py b/tests/nodes/test_graph_execution_state.py index 27b8a58bea..e2d435e621 100644 --- a/tests/nodes/test_graph_execution_state.py +++ b/tests/nodes/test_graph_execution_state.py @@ -75,6 +75,7 @@ def mock_services() -> InvocationServices: session_processor=None, # type: ignore session_queue=None, # type: ignore urls=None, # type: ignore + workflow_records=None, # type: ignore ) diff --git a/tests/nodes/test_invoker.py b/tests/nodes/test_invoker.py index 105f7417cd..9774f07fdd 100644 --- a/tests/nodes/test_invoker.py +++ b/tests/nodes/test_invoker.py @@ -80,6 +80,7 @@ def mock_services() -> InvocationServices: session_processor=None, # type: ignore session_queue=None, # type: ignore urls=None, # type: ignore + workflow_records=None, # type: ignore ) From f0db4d36e459a802abe9843ce619cc9e9bd3e3e0 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 17:23:10 +1100 Subject: [PATCH 036/119] feat: metadata refactor - Refactor how metadata is handled to support a user-defined metadata in graphs - Update workflow embed handling - Update UI to work with these changes - Update tests to support metadata/workflow changes --- invokeai/app/api/routers/images.py | 33 +- invokeai/app/api/routers/workflows.py | 2 +- invokeai/app/api_app.py | 2 +- invokeai/app/invocations/baseinvocation.py | 36 +- .../controlnet_image_processors.py | 7 +- invokeai/app/invocations/cv.py | 4 +- invokeai/app/invocations/facetools.py | 8 +- invokeai/app/invocations/image.py | 223 +-- invokeai/app/invocations/infill.py | 21 +- invokeai/app/invocations/latent.py | 12 +- invokeai/app/invocations/metadata.py | 174 +- invokeai/app/invocations/onnx.py | 14 +- invokeai/app/invocations/primitives.py | 4 +- invokeai/app/invocations/upscale.py | 5 +- .../services/image_files/image_files_base.py | 7 +- .../services/image_files/image_files_disk.py | 11 +- .../image_records/image_records_base.py | 6 +- .../image_records/image_records_common.py | 8 + .../image_records/image_records_sqlite.py | 35 +- invokeai/app/services/images/images_base.py | 9 +- invokeai/app/services/images/images_common.py | 2 - .../app/services/images/images_default.py | 35 +- invokeai/app/services/shared/graph.py | 32 +- .../CurrentImage/CurrentImageButtons.tsx | 41 +- .../SingleSelectionMenuItems.tsx | 42 +- .../ImageMetadataViewer.tsx | 28 +- .../Invocation/EmbedWorkflowCheckbox.tsx | 6 +- .../nodes/Invocation/InvocationNodeFooter.tsx | 4 +- .../features/nodes/hooks/useWithWorkflow.ts | 31 + .../util/validateSourceAndTargetTypes.ts | 5 +- .../web/src/features/nodes/types/constants.ts | 38 + .../web/src/features/nodes/types/types.ts | 120 +- .../nodes/util/fieldTemplateBuilders.ts | 144 +- .../features/nodes/util/fieldValueBuilders.ts | 6 + .../addControlNetToLinearGraph.ts | 25 +- .../nodes/util/graphBuilders/addHrfToGraph.ts | 42 +- .../addIPAdapterToLinearGraph.ts | 33 +- .../util/graphBuilders/addLoRAsToGraph.ts | 53 +- .../util/graphBuilders/addSDXLLoRAstoGraph.ts | 63 +- .../graphBuilders/addSDXLRefinerToGraph.ts | 27 +- .../util/graphBuilders/addSaveImageNode.ts | 27 +- .../graphBuilders/addSeamlessToLinearGraph.ts | 12 + .../addT2IAdapterToLinearGraph.ts | 23 +- .../nodes/util/graphBuilders/addVAEToGraph.ts | 10 +- .../graphBuilders/addWatermarkerToGraph.ts | 25 +- .../graphBuilders/buildAdHocUpscaleGraph.ts | 9 +- .../buildCanvasImageToImageGraph.ts | 14 +- .../buildCanvasSDXLImageToImageGraph.ts | 23 +- .../buildCanvasSDXLTextToImageGraph.ts | 23 +- .../buildCanvasTextToImageGraph.ts | 23 +- .../graphBuilders/buildLinearBatchConfig.ts | 75 +- .../buildLinearImageToImageGraph.ts | 23 +- .../buildLinearSDXLImageToImageGraph.ts | 25 +- .../buildLinearSDXLTextToImageGraph.ts | 23 +- .../buildLinearTextToImageGraph.ts | 30 +- .../util/graphBuilders/buildNodesGraph.ts | 5 +- .../nodes/util/graphBuilders/constants.ts | 8 + .../nodes/util/graphBuilders/metadata.ts | 58 + .../src/features/nodes/util/parseSchema.ts | 44 +- .../web/src/services/api/endpoints/images.ts | 18 +- .../src/services/api/endpoints/workflows.ts | 31 + .../frontend/web/src/services/api/index.ts | 1 + .../frontend/web/src/services/api/schema.d.ts | 1489 +++++++---------- .../frontend/web/src/services/api/types.ts | 17 +- tests/nodes/test_node_graph.py | 148 +- tests/nodes/test_nodes.py | 23 + 66 files changed, 1807 insertions(+), 1798 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/hooks/useWithWorkflow.ts create mode 100644 invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts create mode 100644 invokeai/frontend/web/src/services/api/endpoints/workflows.ts diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 84d8e8eea4..f462437700 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -5,12 +5,13 @@ from fastapi import Body, HTTPException, Path, Query, Request, Response, UploadF from fastapi.responses import FileResponse from fastapi.routing import APIRouter from PIL import Image -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, ValidationError -from invokeai.app.invocations.metadata import ImageMetadata +from invokeai.app.invocations.baseinvocation import MetadataField, type_adapter_MetadataField from invokeai.app.services.image_records.image_records_common import ImageCategory, ImageRecordChanges, ResourceOrigin from invokeai.app.services.images.images_common import ImageDTO, ImageUrlsDTO from invokeai.app.services.shared.pagination import OffsetPaginatedResults +from invokeai.app.services.workflow_records.workflow_records_common import type_adapter_WorkflowField from ..dependencies import ApiDependencies @@ -45,8 +46,10 @@ async def upload_image( if not file.content_type or not file.content_type.startswith("image"): raise HTTPException(status_code=415, detail="Not an image") - contents = await file.read() + metadata = None + workflow = None + contents = await file.read() try: pil_image = Image.open(io.BytesIO(contents)) if crop_visible: @@ -56,6 +59,24 @@ async def upload_image( # Error opening the image raise HTTPException(status_code=415, detail="Failed to read image") + # attempt to parse metadata from image + metadata_raw = pil_image.info.get("invokeai_metadata", None) + if metadata_raw: + try: + metadata = type_adapter_MetadataField.validate_json(metadata_raw) + except ValidationError: + ApiDependencies.invoker.services.logger.warn("Failed to parse metadata for uploaded image") + pass + + # attempt to parse workflow from image + workflow_raw = pil_image.info.get("invokeai_workflow", None) + if workflow_raw is not None: + try: + workflow = type_adapter_WorkflowField.validate_json(workflow_raw) + except ValidationError: + ApiDependencies.invoker.services.logger.warn("Failed to parse metadata for uploaded image") + pass + try: image_dto = ApiDependencies.invoker.services.images.create( image=pil_image, @@ -63,6 +84,8 @@ async def upload_image( image_category=image_category, session_id=session_id, board_id=board_id, + metadata=metadata, + workflow=workflow, is_intermediate=is_intermediate, ) @@ -146,11 +169,11 @@ async def get_image_dto( @images_router.get( "/i/{image_name}/metadata", operation_id="get_image_metadata", - response_model=ImageMetadata, + response_model=Optional[MetadataField], ) async def get_image_metadata( image_name: str = Path(description="The name of image to get"), -) -> ImageMetadata: +) -> Optional[MetadataField]: """Gets an image's metadata""" try: diff --git a/invokeai/app/api/routers/workflows.py b/invokeai/app/api/routers/workflows.py index 814123fc81..57a33fe73f 100644 --- a/invokeai/app/api/routers/workflows.py +++ b/invokeai/app/api/routers/workflows.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Body, Path +from fastapi import APIRouter, Path from invokeai.app.api.dependencies import ApiDependencies from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index e04cf564ab..51aa14c75b 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -44,8 +44,8 @@ if True: # hack to make flake8 happy with imports coming after setting up the c boards, images, models, - sessions, session_queue, + sessions, utilities, workflows, ) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index f2e5f33e6e..39df4971a6 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -15,8 +15,8 @@ from pydantic.fields import _Unset from pydantic_core import PydanticUndefined from invokeai.app.services.config.config_default import InvokeAIAppConfig -from invokeai.app.util.misc import uuid_string from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField +from invokeai.app.util.misc import uuid_string if TYPE_CHECKING: from ..services.invocation_services import InvocationServices @@ -60,6 +60,11 @@ class FieldDescriptions: denoised_latents = "Denoised latents tensor" latents = "Latents tensor" strength = "Strength of denoising (proportional to steps)" + metadata = "Optional metadata to be saved with the image" + metadata_collection = "Collection of Metadata" + metadata_item_polymorphic = "A single metadata item or collection of metadata items" + metadata_item_label = "Label for this metadata item" + metadata_item_value = "The value for this metadata item (may be any type)" workflow = "Optional workflow to be saved with the image" interp_mode = "Interpolation mode" torch_antialias = "Whether or not to apply antialiasing (bilinear or bicubic only)" @@ -167,8 +172,12 @@ class UIType(str, Enum): Scheduler = "Scheduler" WorkflowField = "WorkflowField" IsIntermediate = "IsIntermediate" - MetadataField = "MetadataField" BoardField = "BoardField" + Any = "Any" + MetadataItem = "MetadataItem" + MetadataItemCollection = "MetadataItemCollection" + MetadataItemPolymorphic = "MetadataItemPolymorphic" + MetadataDict = "MetadataDict" # endregion @@ -807,3 +816,26 @@ def invocation_output( class WithWorkflow(BaseModel): workflow: Optional[WorkflowField] = InputField(default=None, description=FieldDescriptions.workflow) + +class MetadataItemField(BaseModel): + label: str = Field(description=FieldDescriptions.metadata_item_label) + value: Any = Field(description=FieldDescriptions.metadata_item_value) + + +class MetadataField(RootModel): + """ + Pydantic model for metadata with custom root of type dict[str, Any]. + Metadata is stored without a strict schema. + """ + + root: dict[str, Any] = Field(description="A dictionary of metadata, shape of which is arbitrary") + + def model_dump(self, *args, **kwargs) -> dict[str, Any]: + return super().model_dump(*args, **kwargs)["root"] + + +type_adapter_MetadataField = TypeAdapter(MetadataField) + + +class WithMetadata(BaseModel): + metadata: Optional[MetadataField] = InputField(default=None, description=FieldDescriptions.metadata) diff --git a/invokeai/app/invocations/controlnet_image_processors.py b/invokeai/app/invocations/controlnet_image_processors.py index 200c37d851..7c76b70e7f 100644 --- a/invokeai/app/invocations/controlnet_image_processors.py +++ b/invokeai/app/invocations/controlnet_image_processors.py @@ -38,6 +38,8 @@ from .baseinvocation import ( InputField, InvocationContext, OutputField, + WithMetadata, + WithWorkflow, invocation, invocation_output, ) @@ -127,12 +129,12 @@ class ControlNetInvocation(BaseInvocation): # This invocation exists for other invocations to subclass it - do not register with @invocation! -class ImageProcessorInvocation(BaseInvocation): +class ImageProcessorInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Base class for invocations that preprocess images for ControlNet""" image: ImageField = InputField(description="The image to process") - def run_processor(self, image): + def run_processor(self, image: Image.Image) -> Image.Image: # superclass just passes through image without processing return image @@ -150,6 +152,7 @@ class ImageProcessorInvocation(BaseInvocation): session_id=context.graph_execution_state_id, node_id=self.id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) diff --git a/invokeai/app/invocations/cv.py b/invokeai/app/invocations/cv.py index 3b85955d74..e5cfd327c1 100644 --- a/invokeai/app/invocations/cv.py +++ b/invokeai/app/invocations/cv.py @@ -8,11 +8,11 @@ from PIL import Image, ImageOps from invokeai.app.invocations.primitives import ImageField, ImageOutput from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin -from .baseinvocation import BaseInvocation, InputField, InvocationContext, invocation +from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation @invocation("cv_inpaint", title="OpenCV Inpaint", tags=["opencv", "inpaint"], category="inpaint", version="1.0.0") -class CvInpaintInvocation(BaseInvocation): +class CvInpaintInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Simple inpaint using opencv.""" image: ImageField = InputField(description="The image to inpaint") diff --git a/invokeai/app/invocations/facetools.py b/invokeai/app/invocations/facetools.py index 40e15e9476..0bb24ef69d 100644 --- a/invokeai/app/invocations/facetools.py +++ b/invokeai/app/invocations/facetools.py @@ -16,6 +16,8 @@ from invokeai.app.invocations.baseinvocation import ( InputField, InvocationContext, OutputField, + WithMetadata, + WithWorkflow, invocation, invocation_output, ) @@ -437,7 +439,7 @@ def get_faces_list( @invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.0.2") -class FaceOffInvocation(BaseInvocation): +class FaceOffInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Bound, extract, and mask a face from an image using MediaPipe detection""" image: ImageField = InputField(description="Image for face detection") @@ -531,7 +533,7 @@ class FaceOffInvocation(BaseInvocation): @invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.0.2") -class FaceMaskInvocation(BaseInvocation): +class FaceMaskInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Face mask creation using mediapipe face detection""" image: ImageField = InputField(description="Image to face detect") @@ -650,7 +652,7 @@ class FaceMaskInvocation(BaseInvocation): @invocation( "face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.0.2" ) -class FaceIdentifierInvocation(BaseInvocation): +class FaceIdentifierInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Outputs an image with detected face IDs printed on each face. For use with other FaceTools.""" image: ImageField = InputField(description="Image to face detect") diff --git a/invokeai/app/invocations/image.py b/invokeai/app/invocations/image.py index 3a4f4eadac..9a4e9da954 100644 --- a/invokeai/app/invocations/image.py +++ b/invokeai/app/invocations/image.py @@ -7,13 +7,21 @@ import cv2 import numpy from PIL import Image, ImageChops, ImageFilter, ImageOps -from invokeai.app.invocations.metadata import CoreMetadata from invokeai.app.invocations.primitives import BoardField, ColorField, ImageField, ImageOutput from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin from invokeai.backend.image_util.invisible_watermark import InvisibleWatermark from invokeai.backend.image_util.safety_checker import SafetyChecker -from .baseinvocation import BaseInvocation, FieldDescriptions, Input, InputField, InvocationContext, invocation +from .baseinvocation import ( + BaseInvocation, + FieldDescriptions, + Input, + InputField, + InvocationContext, + WithMetadata, + WithWorkflow, + invocation, +) @invocation("show_image", title="Show Image", tags=["image"], category="image", version="1.0.0") @@ -36,14 +44,8 @@ class ShowImageInvocation(BaseInvocation): ) -@invocation( - "blank_image", - title="Blank Image", - tags=["image"], - category="image", - version="1.0.0", -) -class BlankImageInvocation(BaseInvocation): +@invocation("blank_image", title="Blank Image", tags=["image"], category="image", version="1.0.0") +class BlankImageInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Creates a blank image and forwards it to the pipeline""" width: int = InputField(default=512, description="The width of the image") @@ -61,6 +63,7 @@ class BlankImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -71,14 +74,8 @@ class BlankImageInvocation(BaseInvocation): ) -@invocation( - "img_crop", - title="Crop Image", - tags=["image", "crop"], - category="image", - version="1.0.0", -) -class ImageCropInvocation(BaseInvocation): +@invocation("img_crop", title="Crop Image", tags=["image", "crop"], category="image", version="1.0.0") +class ImageCropInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Crops an image to a specified box. The box can be outside of the image.""" image: ImageField = InputField(description="The image to crop") @@ -100,6 +97,7 @@ class ImageCropInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -110,14 +108,8 @@ class ImageCropInvocation(BaseInvocation): ) -@invocation( - "img_paste", - title="Paste Image", - tags=["image", "paste"], - category="image", - version="1.0.1", -) -class ImagePasteInvocation(BaseInvocation): +@invocation("img_paste", title="Paste Image", tags=["image", "paste"], category="image", version="1.0.1") +class ImagePasteInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Pastes an image into another image.""" base_image: ImageField = InputField(description="The base image") @@ -159,6 +151,7 @@ class ImagePasteInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -169,14 +162,8 @@ class ImagePasteInvocation(BaseInvocation): ) -@invocation( - "tomask", - title="Mask from Alpha", - tags=["image", "mask"], - category="image", - version="1.0.0", -) -class MaskFromAlphaInvocation(BaseInvocation): +@invocation("tomask", title="Mask from Alpha", tags=["image", "mask"], category="image", version="1.0.0") +class MaskFromAlphaInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Extracts the alpha channel of an image as a mask.""" image: ImageField = InputField(description="The image to create the mask from") @@ -196,6 +183,7 @@ class MaskFromAlphaInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -206,14 +194,8 @@ class MaskFromAlphaInvocation(BaseInvocation): ) -@invocation( - "img_mul", - title="Multiply Images", - tags=["image", "multiply"], - category="image", - version="1.0.0", -) -class ImageMultiplyInvocation(BaseInvocation): +@invocation("img_mul", title="Multiply Images", tags=["image", "multiply"], category="image", version="1.0.0") +class ImageMultiplyInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Multiplies two images together using `PIL.ImageChops.multiply()`.""" image1: ImageField = InputField(description="The first image to multiply") @@ -232,6 +214,7 @@ class ImageMultiplyInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -245,14 +228,8 @@ class ImageMultiplyInvocation(BaseInvocation): IMAGE_CHANNELS = Literal["A", "R", "G", "B"] -@invocation( - "img_chan", - title="Extract Image Channel", - tags=["image", "channel"], - category="image", - version="1.0.0", -) -class ImageChannelInvocation(BaseInvocation): +@invocation("img_chan", title="Extract Image Channel", tags=["image", "channel"], category="image", version="1.0.0") +class ImageChannelInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Gets a channel from an image.""" image: ImageField = InputField(description="The image to get the channel from") @@ -270,6 +247,7 @@ class ImageChannelInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -283,14 +261,8 @@ class ImageChannelInvocation(BaseInvocation): IMAGE_MODES = Literal["L", "RGB", "RGBA", "CMYK", "YCbCr", "LAB", "HSV", "I", "F"] -@invocation( - "img_conv", - title="Convert Image Mode", - tags=["image", "convert"], - category="image", - version="1.0.0", -) -class ImageConvertInvocation(BaseInvocation): +@invocation("img_conv", title="Convert Image Mode", tags=["image", "convert"], category="image", version="1.0.0") +class ImageConvertInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Converts an image to a different mode.""" image: ImageField = InputField(description="The image to convert") @@ -308,6 +280,7 @@ class ImageConvertInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -318,14 +291,8 @@ class ImageConvertInvocation(BaseInvocation): ) -@invocation( - "img_blur", - title="Blur Image", - tags=["image", "blur"], - category="image", - version="1.0.0", -) -class ImageBlurInvocation(BaseInvocation): +@invocation("img_blur", title="Blur Image", tags=["image", "blur"], category="image", version="1.0.0") +class ImageBlurInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Blurs an image""" image: ImageField = InputField(description="The image to blur") @@ -348,6 +315,7 @@ class ImageBlurInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -378,23 +346,14 @@ PIL_RESAMPLING_MAP = { } -@invocation( - "img_resize", - title="Resize Image", - tags=["image", "resize"], - category="image", - version="1.0.0", -) -class ImageResizeInvocation(BaseInvocation): +@invocation("img_resize", title="Resize Image", tags=["image", "resize"], category="image", version="1.0.0") +class ImageResizeInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Resizes an image to specific dimensions""" image: ImageField = InputField(description="The image to resize") width: int = InputField(default=512, gt=0, description="The width to resize to (px)") height: int = InputField(default=512, gt=0, description="The height to resize to (px)") resample_mode: PIL_RESAMPLING_MODES = InputField(default="bicubic", description="The resampling mode") - metadata: Optional[CoreMetadata] = InputField( - default=None, description=FieldDescriptions.core_metadata, ui_hidden=True - ) def invoke(self, context: InvocationContext) -> ImageOutput: image = context.services.images.get_pil_image(self.image.image_name) @@ -413,7 +372,7 @@ class ImageResizeInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) @@ -424,14 +383,8 @@ class ImageResizeInvocation(BaseInvocation): ) -@invocation( - "img_scale", - title="Scale Image", - tags=["image", "scale"], - category="image", - version="1.0.0", -) -class ImageScaleInvocation(BaseInvocation): +@invocation("img_scale", title="Scale Image", tags=["image", "scale"], category="image", version="1.0.0") +class ImageScaleInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Scales an image by a factor""" image: ImageField = InputField(description="The image to scale") @@ -461,6 +414,7 @@ class ImageScaleInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -471,14 +425,8 @@ class ImageScaleInvocation(BaseInvocation): ) -@invocation( - "img_lerp", - title="Lerp Image", - tags=["image", "lerp"], - category="image", - version="1.0.0", -) -class ImageLerpInvocation(BaseInvocation): +@invocation("img_lerp", title="Lerp Image", tags=["image", "lerp"], category="image", version="1.0.0") +class ImageLerpInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Linear interpolation of all pixels of an image""" image: ImageField = InputField(description="The image to lerp") @@ -500,6 +448,7 @@ class ImageLerpInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -510,14 +459,8 @@ class ImageLerpInvocation(BaseInvocation): ) -@invocation( - "img_ilerp", - title="Inverse Lerp Image", - tags=["image", "ilerp"], - category="image", - version="1.0.0", -) -class ImageInverseLerpInvocation(BaseInvocation): +@invocation("img_ilerp", title="Inverse Lerp Image", tags=["image", "ilerp"], category="image", version="1.0.0") +class ImageInverseLerpInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Inverse linear interpolation of all pixels of an image""" image: ImageField = InputField(description="The image to lerp") @@ -539,6 +482,7 @@ class ImageInverseLerpInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -549,20 +493,11 @@ class ImageInverseLerpInvocation(BaseInvocation): ) -@invocation( - "img_nsfw", - title="Blur NSFW Image", - tags=["image", "nsfw"], - category="image", - version="1.0.0", -) -class ImageNSFWBlurInvocation(BaseInvocation): +@invocation("img_nsfw", title="Blur NSFW Image", tags=["image", "nsfw"], category="image", version="1.0.0") +class ImageNSFWBlurInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Add blur to NSFW-flagged images""" image: ImageField = InputField(description="The image to check") - metadata: Optional[CoreMetadata] = InputField( - default=None, description=FieldDescriptions.core_metadata, ui_hidden=True - ) def invoke(self, context: InvocationContext) -> ImageOutput: image = context.services.images.get_pil_image(self.image.image_name) @@ -583,7 +518,7 @@ class ImageNSFWBlurInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) @@ -607,14 +542,11 @@ class ImageNSFWBlurInvocation(BaseInvocation): category="image", version="1.0.0", ) -class ImageWatermarkInvocation(BaseInvocation): +class ImageWatermarkInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Add an invisible watermark to an image""" image: ImageField = InputField(description="The image to check") text: str = InputField(default="InvokeAI", description="Watermark text") - metadata: Optional[CoreMetadata] = InputField( - default=None, description=FieldDescriptions.core_metadata, ui_hidden=True - ) def invoke(self, context: InvocationContext) -> ImageOutput: image = context.services.images.get_pil_image(self.image.image_name) @@ -626,7 +558,7 @@ class ImageWatermarkInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) @@ -637,14 +569,8 @@ class ImageWatermarkInvocation(BaseInvocation): ) -@invocation( - "mask_edge", - title="Mask Edge", - tags=["image", "mask", "inpaint"], - category="image", - version="1.0.0", -) -class MaskEdgeInvocation(BaseInvocation): +@invocation("mask_edge", title="Mask Edge", tags=["image", "mask", "inpaint"], category="image", version="1.0.0") +class MaskEdgeInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Applies an edge mask to an image""" image: ImageField = InputField(description="The image to apply the mask to") @@ -678,6 +604,7 @@ class MaskEdgeInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -695,7 +622,7 @@ class MaskEdgeInvocation(BaseInvocation): category="image", version="1.0.0", ) -class MaskCombineInvocation(BaseInvocation): +class MaskCombineInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`.""" mask1: ImageField = InputField(description="The first mask to combine") @@ -714,6 +641,7 @@ class MaskCombineInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -724,14 +652,8 @@ class MaskCombineInvocation(BaseInvocation): ) -@invocation( - "color_correct", - title="Color Correct", - tags=["image", "color"], - category="image", - version="1.0.0", -) -class ColorCorrectInvocation(BaseInvocation): +@invocation("color_correct", title="Color Correct", tags=["image", "color"], category="image", version="1.0.0") +class ColorCorrectInvocation(BaseInvocation, WithWorkflow, WithMetadata): """ Shifts the colors of a target image to match the reference image, optionally using a mask to only color-correct certain regions of the target image. @@ -830,6 +752,7 @@ class ColorCorrectInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -840,14 +763,8 @@ class ColorCorrectInvocation(BaseInvocation): ) -@invocation( - "img_hue_adjust", - title="Adjust Image Hue", - tags=["image", "hue"], - category="image", - version="1.0.0", -) -class ImageHueAdjustmentInvocation(BaseInvocation): +@invocation("img_hue_adjust", title="Adjust Image Hue", tags=["image", "hue"], category="image", version="1.0.0") +class ImageHueAdjustmentInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Adjusts the Hue of an image.""" image: ImageField = InputField(description="The image to adjust") @@ -875,6 +792,7 @@ class ImageHueAdjustmentInvocation(BaseInvocation): node_id=self.id, is_intermediate=self.is_intermediate, session_id=context.graph_execution_state_id, + metadata=self.metadata, workflow=self.workflow, ) @@ -950,7 +868,7 @@ CHANNEL_FORMATS = { category="image", version="1.0.0", ) -class ImageChannelOffsetInvocation(BaseInvocation): +class ImageChannelOffsetInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Add or subtract a value from a specific color channel of an image.""" image: ImageField = InputField(description="The image to adjust") @@ -984,6 +902,7 @@ class ImageChannelOffsetInvocation(BaseInvocation): node_id=self.id, is_intermediate=self.is_intermediate, session_id=context.graph_execution_state_id, + metadata=self.metadata, workflow=self.workflow, ) @@ -1020,7 +939,7 @@ class ImageChannelOffsetInvocation(BaseInvocation): category="image", version="1.0.0", ) -class ImageChannelMultiplyInvocation(BaseInvocation): +class ImageChannelMultiplyInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Scale a specific color channel of an image.""" image: ImageField = InputField(description="The image to adjust") @@ -1060,6 +979,7 @@ class ImageChannelMultiplyInvocation(BaseInvocation): is_intermediate=self.is_intermediate, session_id=context.graph_execution_state_id, workflow=self.workflow, + metadata=self.metadata, ) return ImageOutput( @@ -1079,16 +999,11 @@ class ImageChannelMultiplyInvocation(BaseInvocation): version="1.0.1", use_cache=False, ) -class SaveImageInvocation(BaseInvocation): +class SaveImageInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Saves an image. Unlike an image primitive, this invocation stores a copy of the image.""" image: ImageField = InputField(description=FieldDescriptions.image) - board: Optional[BoardField] = InputField(default=None, description=FieldDescriptions.board, input=Input.Direct) - metadata: Optional[CoreMetadata] = InputField( - default=None, - description=FieldDescriptions.core_metadata, - ui_hidden=True, - ) + board: BoardField = InputField(default=None, description=FieldDescriptions.board, input=Input.Direct) def invoke(self, context: InvocationContext) -> ImageOutput: image = context.services.images.get_pil_image(self.image.image_name) @@ -1101,7 +1016,7 @@ class SaveImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) diff --git a/invokeai/app/invocations/infill.py b/invokeai/app/invocations/infill.py index d8384290f3..b100fe7c4e 100644 --- a/invokeai/app/invocations/infill.py +++ b/invokeai/app/invocations/infill.py @@ -13,7 +13,7 @@ from invokeai.backend.image_util.cv2_inpaint import cv2_inpaint from invokeai.backend.image_util.lama import LaMA from invokeai.backend.image_util.patchmatch import PatchMatch -from .baseinvocation import BaseInvocation, InputField, InvocationContext, invocation +from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation from .image import PIL_RESAMPLING_MAP, PIL_RESAMPLING_MODES @@ -119,7 +119,7 @@ def tile_fill_missing(im: Image.Image, tile_size: int = 16, seed: Optional[int] @invocation("infill_rgba", title="Solid Color Infill", tags=["image", "inpaint"], category="inpaint", version="1.0.0") -class InfillColorInvocation(BaseInvocation): +class InfillColorInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Infills transparent areas of an image with a solid color""" image: ImageField = InputField(description="The image to infill") @@ -143,6 +143,7 @@ class InfillColorInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -154,7 +155,7 @@ class InfillColorInvocation(BaseInvocation): @invocation("infill_tile", title="Tile Infill", tags=["image", "inpaint"], category="inpaint", version="1.0.0") -class InfillTileInvocation(BaseInvocation): +class InfillTileInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Infills transparent areas of an image with tiles of the image""" image: ImageField = InputField(description="The image to infill") @@ -179,6 +180,7 @@ class InfillTileInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -192,7 +194,7 @@ class InfillTileInvocation(BaseInvocation): @invocation( "infill_patchmatch", title="PatchMatch Infill", tags=["image", "inpaint"], category="inpaint", version="1.0.0" ) -class InfillPatchMatchInvocation(BaseInvocation): +class InfillPatchMatchInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Infills transparent areas of an image using the PatchMatch algorithm""" image: ImageField = InputField(description="The image to infill") @@ -232,6 +234,7 @@ class InfillPatchMatchInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) @@ -243,7 +246,7 @@ class InfillPatchMatchInvocation(BaseInvocation): @invocation("infill_lama", title="LaMa Infill", tags=["image", "inpaint"], category="inpaint", version="1.0.0") -class LaMaInfillInvocation(BaseInvocation): +class LaMaInfillInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Infills transparent areas of an image using the LaMa model""" image: ImageField = InputField(description="The image to infill") @@ -260,6 +263,8 @@ class LaMaInfillInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, + workflow=self.workflow, ) return ImageOutput( @@ -269,8 +274,8 @@ class LaMaInfillInvocation(BaseInvocation): ) -@invocation("infill_cv2", title="CV2 Infill", tags=["image", "inpaint"], category="inpaint", version="1.0.0") -class CV2InfillInvocation(BaseInvocation): +@invocation("infill_cv2", title="CV2 Infill", tags=["image", "inpaint"], category="inpaint") +class CV2InfillInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Infills transparent areas of an image using OpenCV Inpainting""" image: ImageField = InputField(description="The image to infill") @@ -287,6 +292,8 @@ class CV2InfillInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, + workflow=self.workflow, ) return ImageOutput( diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index c28c87395d..a537972c0b 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -23,7 +23,6 @@ from pydantic import field_validator from torchvision.transforms.functional import resize as tv_resize from invokeai.app.invocations.ip_adapter import IPAdapterField -from invokeai.app.invocations.metadata import CoreMetadata from invokeai.app.invocations.primitives import ( DenoiseMaskField, DenoiseMaskOutput, @@ -64,6 +63,8 @@ from .baseinvocation import ( InvocationContext, OutputField, UIType, + WithMetadata, + WithWorkflow, invocation, invocation_output, ) @@ -792,7 +793,7 @@ class DenoiseLatentsInvocation(BaseInvocation): category="latents", version="1.0.0", ) -class LatentsToImageInvocation(BaseInvocation): +class LatentsToImageInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Generates an image from latents.""" latents: LatentsField = InputField( @@ -805,11 +806,6 @@ class LatentsToImageInvocation(BaseInvocation): ) tiled: bool = InputField(default=False, description=FieldDescriptions.tiled) fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32) - metadata: Optional[CoreMetadata] = InputField( - default=None, - description=FieldDescriptions.core_metadata, - ui_hidden=True, - ) @torch.no_grad() def invoke(self, context: InvocationContext) -> ImageOutput: @@ -878,7 +874,7 @@ class LatentsToImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 4d76926aaa..205dbef814 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -1,13 +1,17 @@ -from typing import Optional +from typing import Any, Literal, Optional, Union -from pydantic import Field +from pydantic import BaseModel, ConfigDict, Field from invokeai.app.invocations.baseinvocation import ( BaseInvocation, BaseInvocationOutput, + FieldDescriptions, InputField, InvocationContext, + MetadataField, + MetadataItemField, OutputField, + UIType, invocation, invocation_output, ) @@ -16,116 +20,100 @@ from invokeai.app.invocations.ip_adapter import IPAdapterModelField from invokeai.app.invocations.model import LoRAModelField, MainModelField, VAEModelField from invokeai.app.invocations.primitives import ImageField from invokeai.app.invocations.t2i_adapter import T2IAdapterField -from invokeai.app.util.model_exclude_null import BaseModelExcludeNull from ...version import __version__ -class LoRAMetadataField(BaseModelExcludeNull): - """LoRA metadata for an image generated in InvokeAI.""" +class LoRAMetadataField(BaseModel): + """LoRA Metadata Field""" - lora: LoRAModelField = Field(description="The LoRA model") - weight: float = Field(description="The weight of the LoRA model") + lora: LoRAModelField = Field(description=FieldDescriptions.lora_model) + weight: float = Field(description=FieldDescriptions.lora_weight) -class IPAdapterMetadataField(BaseModelExcludeNull): +class IPAdapterMetadataField(BaseModel): + """IP Adapter Field, minus the CLIP Vision Encoder model""" + image: ImageField = Field(description="The IP-Adapter image prompt.") - ip_adapter_model: IPAdapterModelField = Field(description="The IP-Adapter model to use.") - weight: float = Field(description="The weight of the IP-Adapter model") + ip_adapter_model: IPAdapterModelField = Field( + description="The IP-Adapter model.", + ) + weight: Union[float, list[float]] = Field( + default=1, + ge=0, + description="The weight given to the IP-Adapter", + ) begin_step_percent: float = Field( - default=0, ge=0, le=1, description="When the IP-Adapter is first applied (% of total steps)" + default=0, ge=-1, le=2, description="When the IP-Adapter is first applied (% of total steps)" ) end_step_percent: float = Field( default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)" ) -class CoreMetadata(BaseModelExcludeNull): - """Core generation metadata for an image generated in InvokeAI.""" +@invocation_output("metadata_item_output") +class MetadataItemOutput(BaseInvocationOutput): + """Metadata Item Output""" - app_version: str = Field(default=__version__, description="The version of InvokeAI used to generate this image") - generation_mode: Optional[str] = Field( - default=None, - description="The generation mode that output this image", - ) - created_by: Optional[str] = Field(default=None, description="The name of the creator of the image") - positive_prompt: Optional[str] = Field(default=None, description="The positive prompt parameter") - negative_prompt: Optional[str] = Field(default=None, description="The negative prompt parameter") - width: Optional[int] = Field(default=None, description="The width parameter") - height: Optional[int] = Field(default=None, description="The height parameter") - seed: Optional[int] = Field(default=None, description="The seed used for noise generation") - rand_device: Optional[str] = Field(default=None, description="The device used for random number generation") - cfg_scale: Optional[float] = Field(default=None, description="The classifier-free guidance scale parameter") - steps: Optional[int] = Field(default=None, description="The number of steps used for inference") - scheduler: Optional[str] = Field(default=None, description="The scheduler used for inference") - clip_skip: Optional[int] = Field( - default=None, - description="The number of skipped CLIP layers", - ) - model: Optional[MainModelField] = Field(default=None, description="The main model used for inference") - controlnets: Optional[list[ControlField]] = Field(default=None, description="The ControlNets used for inference") - ipAdapters: Optional[list[IPAdapterMetadataField]] = Field( - default=None, description="The IP Adapters used for inference" - ) - t2iAdapters: Optional[list[T2IAdapterField]] = Field(default=None, description="The IP Adapters used for inference") - loras: Optional[list[LoRAMetadataField]] = Field(default=None, description="The LoRAs used for inference") - vae: Optional[VAEModelField] = Field( - default=None, - description="The VAE used for decoding, if the main model's default was not used", + item: MetadataItemField = OutputField(description="Metadata Item") + + +@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.""" + + label: str = InputField(description=FieldDescriptions.metadata_item_label) + value: Any = InputField(description=FieldDescriptions.metadata_item_value, ui_type=UIType.Any) + + def invoke(self, context: InvocationContext) -> MetadataItemOutput: + return MetadataItemOutput(item=MetadataItemField(label=self.label, value=self.value)) + + +@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 ) - # Latents-to-Latents - strength: Optional[float] = Field( - default=None, - description="The strength used for latents-to-latents", - ) - init_image: Optional[str] = Field(default=None, description="The name of the initial image") + 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} - # SDXL - positive_style_prompt: Optional[str] = Field(default=None, description="The positive style prompt parameter") - negative_style_prompt: Optional[str] = Field(default=None, description="The negative style prompt parameter") - - # SDXL Refiner - refiner_model: Optional[MainModelField] = Field(default=None, description="The SDXL Refiner model used") - refiner_cfg_scale: Optional[float] = Field( - default=None, - description="The classifier-free guidance scale parameter used for the refiner", - ) - refiner_steps: Optional[int] = Field(default=None, description="The number of steps used for the refiner") - refiner_scheduler: Optional[str] = Field(default=None, description="The scheduler used for the refiner") - refiner_positive_aesthetic_score: Optional[float] = Field( - default=None, description="The aesthetic score used for the refiner" - ) - refiner_negative_aesthetic_score: Optional[float] = Field( - default=None, description="The aesthetic score used for the refiner" - ) - refiner_start: Optional[float] = Field(default=None, description="The start value used for refiner denoising") + # add app version + data.update({"app_version": __version__}) + return MetadataOutput(metadata=MetadataField.model_validate(data)) -class ImageMetadata(BaseModelExcludeNull): - """An image's generation metadata""" +@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.""" - metadata: Optional[dict] = Field( - default=None, - description="The image's core metadata, if it was created in the Linear or Canvas UI", - ) - graph: Optional[dict] = Field(default=None, description="The graph that created the image") + 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()) + + return MetadataOutput(metadata=MetadataField.model_validate(data)) -@invocation_output("metadata_accumulator_output") -class MetadataAccumulatorOutput(BaseInvocationOutput): - """The output of the MetadataAccumulator node""" +@invocation("core_metadata", title="Core Metadata", tags=["metadata"], category="metadata", version="1.0.0") +class CoreMetadataInvocation(BaseInvocation): + """Collects core generation metadata into a MetadataField""" - metadata: CoreMetadata = OutputField(description="The core metadata for the image") - - -@invocation( - "metadata_accumulator", title="Metadata Accumulator", tags=["metadata"], category="metadata", version="1.0.0" -) -class MetadataAccumulatorInvocation(BaseInvocation): - """Outputs a Core Metadata Object""" - - generation_mode: Optional[str] = InputField( + generation_mode: Literal["txt2img", "img2img", "inpaint", "outpaint"] = InputField( default=None, description="The generation mode that output this image", ) @@ -138,6 +126,8 @@ class MetadataAccumulatorInvocation(BaseInvocation): cfg_scale: Optional[float] = InputField(default=None, description="The classifier-free guidance scale parameter") 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") + 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") clip_skip: Optional[int] = InputField( default=None, description="The number of skipped CLIP layers", @@ -220,7 +210,13 @@ class MetadataAccumulatorInvocation(BaseInvocation): description="The start value used for refiner denoising", ) - def invoke(self, context: InvocationContext) -> MetadataAccumulatorOutput: + def invoke(self, context: InvocationContext) -> MetadataOutput: """Collects and outputs a CoreMetadata object""" - return MetadataAccumulatorOutput(metadata=CoreMetadata(**self.model_dump())) + return MetadataOutput( + metadata=MetadataField.model_validate( + self.model_dump(exclude_none=True, exclude={"id", "type", "is_intermediate", "use_cache"}) + ) + ) + + model_config = ConfigDict(extra="allow") diff --git a/invokeai/app/invocations/onnx.py b/invokeai/app/invocations/onnx.py index 3f4f688cf4..140505f736 100644 --- a/invokeai/app/invocations/onnx.py +++ b/invokeai/app/invocations/onnx.py @@ -4,7 +4,7 @@ import inspect import re # from contextlib import ExitStack -from typing import List, Literal, Optional, Union +from typing import List, Literal, Union import numpy as np import torch @@ -12,7 +12,6 @@ from diffusers.image_processor import VaeImageProcessor from pydantic import BaseModel, ConfigDict, Field, field_validator from tqdm import tqdm -from invokeai.app.invocations.metadata import CoreMetadata from invokeai.app.invocations.primitives import ConditioningField, ConditioningOutput, ImageField, ImageOutput from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin from invokeai.app.util.step_callback import stable_diffusion_step_callback @@ -31,6 +30,8 @@ from .baseinvocation import ( OutputField, UIComponent, UIType, + WithMetadata, + WithWorkflow, invocation, invocation_output, ) @@ -327,7 +328,7 @@ class ONNXTextToLatentsInvocation(BaseInvocation): category="image", version="1.0.0", ) -class ONNXLatentsToImageInvocation(BaseInvocation): +class ONNXLatentsToImageInvocation(BaseInvocation, WithMetadata, WithWorkflow): """Generates an image from latents.""" latents: LatentsField = InputField( @@ -338,11 +339,6 @@ class ONNXLatentsToImageInvocation(BaseInvocation): description=FieldDescriptions.vae, input=Input.Connection, ) - metadata: Optional[CoreMetadata] = InputField( - default=None, - description=FieldDescriptions.core_metadata, - ui_hidden=True, - ) # tiled: bool = InputField(default=False, description="Decode latents by overlaping tiles(less memory consumption)") def invoke(self, context: InvocationContext) -> ImageOutput: @@ -381,7 +377,7 @@ class ONNXLatentsToImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.model_dump() if self.metadata else None, + metadata=self.metadata, workflow=self.workflow, ) diff --git a/invokeai/app/invocations/primitives.py b/invokeai/app/invocations/primitives.py index c314edfd15..88ede88cde 100644 --- a/invokeai/app/invocations/primitives.py +++ b/invokeai/app/invocations/primitives.py @@ -251,7 +251,9 @@ class ImageCollectionOutput(BaseInvocationOutput): @invocation("image", title="Image Primitive", tags=["primitives", "image"], category="primitives", version="1.0.0") -class ImageInvocation(BaseInvocation): +class ImageInvocation( + BaseInvocation, +): """An image primitive value""" image: ImageField = InputField(description="The image to load") diff --git a/invokeai/app/invocations/upscale.py b/invokeai/app/invocations/upscale.py index d30bb71d95..1167914aca 100644 --- a/invokeai/app/invocations/upscale.py +++ b/invokeai/app/invocations/upscale.py @@ -14,7 +14,7 @@ from invokeai.app.invocations.primitives import ImageField, ImageOutput from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin from invokeai.backend.util.devices import choose_torch_device -from .baseinvocation import BaseInvocation, InputField, InvocationContext, invocation +from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation # TODO: Populate this from disk? # TODO: Use model manager to load? @@ -30,7 +30,7 @@ if choose_torch_device() == torch.device("mps"): @invocation("esrgan", title="Upscale (RealESRGAN)", tags=["esrgan", "upscale"], category="esrgan", version="1.1.0") -class ESRGANInvocation(BaseInvocation): +class ESRGANInvocation(BaseInvocation, WithWorkflow, WithMetadata): """Upscales an image using RealESRGAN.""" image: ImageField = InputField(description="The input image") @@ -123,6 +123,7 @@ class ESRGANInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, + metadata=self.metadata, workflow=self.workflow, ) diff --git a/invokeai/app/services/image_files/image_files_base.py b/invokeai/app/services/image_files/image_files_base.py index 5dde7b05d6..3f6e797225 100644 --- a/invokeai/app/services/image_files/image_files_base.py +++ b/invokeai/app/services/image_files/image_files_base.py @@ -4,6 +4,9 @@ from typing import Optional from PIL.Image import Image as PILImageType +from invokeai.app.invocations.metadata import MetadataField +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField + class ImageFileStorageBase(ABC): """Low-level service responsible for storing and retrieving image files.""" @@ -30,8 +33,8 @@ class ImageFileStorageBase(ABC): self, image: PILImageType, image_name: str, - metadata: Optional[dict] = None, - workflow: Optional[str] = None, + metadata: Optional[MetadataField] = None, + workflow: Optional[WorkflowField] = None, thumbnail_size: int = 256, ) -> None: """Saves an image and a 256x256 WEBP thumbnail. Returns a tuple of the image name, thumbnail name, and created timestamp.""" diff --git a/invokeai/app/services/image_files/image_files_disk.py b/invokeai/app/services/image_files/image_files_disk.py index 9111a71605..57c05562d5 100644 --- a/invokeai/app/services/image_files/image_files_disk.py +++ b/invokeai/app/services/image_files/image_files_disk.py @@ -1,5 +1,4 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team -import json from pathlib import Path from queue import Queue from typing import Dict, Optional, Union @@ -8,7 +7,9 @@ from PIL import Image, PngImagePlugin from PIL.Image import Image as PILImageType from send2trash import send2trash +from invokeai.app.invocations.metadata import MetadataField from invokeai.app.services.invoker import Invoker +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField from invokeai.app.util.thumbnails import get_thumbnail_name, make_thumbnail from .image_files_base import ImageFileStorageBase @@ -55,8 +56,8 @@ class DiskImageFileStorage(ImageFileStorageBase): self, image: PILImageType, image_name: str, - metadata: Optional[dict] = None, - workflow: Optional[str] = None, + metadata: Optional[MetadataField] = None, + workflow: Optional[WorkflowField] = None, thumbnail_size: int = 256, ) -> None: try: @@ -67,9 +68,9 @@ class DiskImageFileStorage(ImageFileStorageBase): if metadata is not None or workflow is not None: if metadata is not None: - pnginfo.add_text("invokeai_metadata", json.dumps(metadata)) + pnginfo.add_text("invokeai_metadata", metadata.model_dump_json()) if workflow is not None: - pnginfo.add_text("invokeai_workflow", workflow) + pnginfo.add_text("invokeai_workflow", workflow.model_dump_json()) else: # For uploaded images, we want to retain metadata. PIL strips it on save; manually add it back # TODO: retain non-invokeai metadata on save... diff --git a/invokeai/app/services/image_records/image_records_base.py b/invokeai/app/services/image_records/image_records_base.py index 7e74b06e9e..cd1db81857 100644 --- a/invokeai/app/services/image_records/image_records_base.py +++ b/invokeai/app/services/image_records/image_records_base.py @@ -2,6 +2,7 @@ from abc import ABC, abstractmethod from datetime import datetime from typing import Optional +from invokeai.app.invocations.metadata import MetadataField from invokeai.app.services.shared.pagination import OffsetPaginatedResults from .image_records_common import ImageCategory, ImageRecord, ImageRecordChanges, ResourceOrigin @@ -18,7 +19,7 @@ class ImageRecordStorageBase(ABC): pass @abstractmethod - def get_metadata(self, image_name: str) -> Optional[dict]: + def get_metadata(self, image_name: str) -> Optional[MetadataField]: """Gets an image's metadata'.""" pass @@ -78,7 +79,8 @@ class ImageRecordStorageBase(ABC): starred: Optional[bool] = False, session_id: Optional[str] = None, node_id: Optional[str] = None, - metadata: Optional[dict] = None, + metadata: Optional[MetadataField] = None, + workflow_id: Optional[str] = None, ) -> datetime: """Saves an image record.""" pass diff --git a/invokeai/app/services/image_records/image_records_common.py b/invokeai/app/services/image_records/image_records_common.py index 5a6e5652c9..6576fb9647 100644 --- a/invokeai/app/services/image_records/image_records_common.py +++ b/invokeai/app/services/image_records/image_records_common.py @@ -100,6 +100,7 @@ IMAGE_DTO_COLS = ", ".join( "width", "height", "session_id", + "workflow_id", "node_id", "is_intermediate", "created_at", @@ -140,6 +141,11 @@ class ImageRecord(BaseModelExcludeNull): description="The session ID that generated this image, if it is a generated image.", ) """The session ID that generated this image, if it is a generated image.""" + workflow_id: Optional[str] = Field( + default=None, + description="The workflow that generated this image.", + ) + """The workflow that generated this image.""" node_id: Optional[str] = Field( default=None, description="The node ID that generated this image, if it is a generated image.", @@ -184,6 +190,7 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord: width = image_dict.get("width", 0) height = image_dict.get("height", 0) session_id = image_dict.get("session_id", None) + workflow_id = image_dict.get("workflow_id", None) node_id = image_dict.get("node_id", None) created_at = image_dict.get("created_at", get_iso_timestamp()) updated_at = image_dict.get("updated_at", get_iso_timestamp()) @@ -198,6 +205,7 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord: width=width, height=height, session_id=session_id, + workflow_id=workflow_id, node_id=node_id, created_at=created_at, updated_at=updated_at, diff --git a/invokeai/app/services/image_records/image_records_sqlite.py b/invokeai/app/services/image_records/image_records_sqlite.py index 33bf373a7d..7b60ec3d5b 100644 --- a/invokeai/app/services/image_records/image_records_sqlite.py +++ b/invokeai/app/services/image_records/image_records_sqlite.py @@ -1,9 +1,9 @@ -import json import sqlite3 import threading from datetime import datetime from typing import Optional, Union, cast +from invokeai.app.invocations.baseinvocation import MetadataField, type_adapter_MetadataField from invokeai.app.services.shared.pagination import OffsetPaginatedResults from invokeai.app.services.shared.sqlite import SqliteDatabase @@ -76,6 +76,16 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): """ ) + if "workflow_id" not in columns: + self._cursor.execute( + """--sql + ALTER TABLE images + ADD COLUMN workflow_id TEXT; + -- TODO: This requires a migration: + -- FOREIGN KEY (workflow_id) REFERENCES workflows (workflow_id) ON DELETE SET NULL; + """ + ) + # Create the `images` table indices. self._cursor.execute( """--sql @@ -141,22 +151,26 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): return deserialize_image_record(dict(result)) - def get_metadata(self, image_name: str) -> Optional[dict]: + def get_metadata(self, image_name: str) -> Optional[MetadataField]: try: self._lock.acquire() self._cursor.execute( """--sql - SELECT images.metadata FROM images + SELECT metadata FROM images WHERE image_name = ?; """, (image_name,), ) result = cast(Optional[sqlite3.Row], self._cursor.fetchone()) - if not result or not result[0]: - return None - return json.loads(result[0]) + + if not result: + raise ImageRecordNotFoundException + + as_dict = dict(result) + metadata_raw = cast(Optional[str], as_dict.get("metadata", None)) + return type_adapter_MetadataField.validate_json(metadata_raw) if metadata_raw is not None else None except sqlite3.Error as e: self._conn.rollback() raise ImageRecordNotFoundException from e @@ -408,10 +422,11 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): starred: Optional[bool] = False, session_id: Optional[str] = None, node_id: Optional[str] = None, - metadata: Optional[dict] = None, + metadata: Optional[MetadataField] = None, + workflow_id: Optional[str] = None, ) -> datetime: try: - metadata_json = None if metadata is None else json.dumps(metadata) + metadata_json = metadata.model_dump_json() if metadata is not None else None self._lock.acquire() self._cursor.execute( """--sql @@ -424,10 +439,11 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): node_id, session_id, metadata, + workflow_id, is_intermediate, starred ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, ( image_name, @@ -438,6 +454,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): node_id, session_id, metadata_json, + workflow_id, is_intermediate, starred, ), diff --git a/invokeai/app/services/images/images_base.py b/invokeai/app/services/images/images_base.py index ac7a4a2152..ebb40424bc 100644 --- a/invokeai/app/services/images/images_base.py +++ b/invokeai/app/services/images/images_base.py @@ -3,7 +3,7 @@ from typing import Callable, Optional from PIL.Image import Image as PILImageType -from invokeai.app.invocations.metadata import ImageMetadata +from invokeai.app.invocations.metadata import MetadataField from invokeai.app.services.image_records.image_records_common import ( ImageCategory, ImageRecord, @@ -12,6 +12,7 @@ from invokeai.app.services.image_records.image_records_common import ( ) from invokeai.app.services.images.images_common import ImageDTO from invokeai.app.services.shared.pagination import OffsetPaginatedResults +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField class ImageServiceABC(ABC): @@ -50,8 +51,8 @@ class ImageServiceABC(ABC): session_id: Optional[str] = None, board_id: Optional[str] = None, is_intermediate: Optional[bool] = False, - metadata: Optional[dict] = None, - workflow: Optional[str] = None, + metadata: Optional[MetadataField] = None, + workflow: Optional[WorkflowField] = None, ) -> ImageDTO: """Creates an image, storing the file and its metadata.""" pass @@ -81,7 +82,7 @@ class ImageServiceABC(ABC): pass @abstractmethod - def get_metadata(self, image_name: str) -> ImageMetadata: + def get_metadata(self, image_name: str) -> Optional[MetadataField]: """Gets an image's metadata.""" pass diff --git a/invokeai/app/services/images/images_common.py b/invokeai/app/services/images/images_common.py index 325cecdd26..0464244b94 100644 --- a/invokeai/app/services/images/images_common.py +++ b/invokeai/app/services/images/images_common.py @@ -25,8 +25,6 @@ class ImageDTO(ImageRecord, ImageUrlsDTO): ) """The id of the board the image belongs to, if one exists.""" - pass - def image_record_to_dto( image_record: ImageRecord, diff --git a/invokeai/app/services/images/images_default.py b/invokeai/app/services/images/images_default.py index 3c78c4f29a..e466e809b1 100644 --- a/invokeai/app/services/images/images_default.py +++ b/invokeai/app/services/images/images_default.py @@ -2,10 +2,10 @@ from typing import Optional from PIL.Image import Image as PILImageType -from invokeai.app.invocations.metadata import ImageMetadata +from invokeai.app.invocations.metadata import MetadataField from invokeai.app.services.invoker import Invoker from invokeai.app.services.shared.pagination import OffsetPaginatedResults -from invokeai.app.util.metadata import get_metadata_graph_from_raw_session +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField from ..image_files.image_files_common import ( ImageFileDeleteException, @@ -42,8 +42,8 @@ class ImageService(ImageServiceABC): session_id: Optional[str] = None, board_id: Optional[str] = None, is_intermediate: Optional[bool] = False, - metadata: Optional[dict] = None, - workflow: Optional[str] = None, + metadata: Optional[MetadataField] = None, + workflow: Optional[WorkflowField] = None, ) -> ImageDTO: if image_origin not in ResourceOrigin: raise InvalidOriginException @@ -56,6 +56,12 @@ class ImageService(ImageServiceABC): (width, height) = image.size try: + if workflow is not None: + created_workflow = self.__invoker.services.workflow_records.create(workflow) + workflow_id = created_workflow.model_dump()["id"] + else: + workflow_id = None + # TODO: Consider using a transaction here to ensure consistency between storage and database self.__invoker.services.image_records.save( # Non-nullable fields @@ -69,6 +75,7 @@ class ImageService(ImageServiceABC): # Nullable fields node_id=node_id, metadata=metadata, + workflow_id=workflow_id, session_id=session_id, ) if board_id is not None: @@ -146,25 +153,9 @@ class ImageService(ImageServiceABC): self.__invoker.services.logger.error("Problem getting image DTO") raise e - def get_metadata(self, image_name: str) -> ImageMetadata: + def get_metadata(self, image_name: str) -> Optional[MetadataField]: try: - image_record = self.__invoker.services.image_records.get(image_name) - metadata = self.__invoker.services.image_records.get_metadata(image_name) - - if not image_record.session_id: - return ImageMetadata(metadata=metadata) - - session_raw = self.__invoker.services.graph_execution_manager.get_raw(image_record.session_id) - graph = None - - if session_raw: - try: - graph = get_metadata_graph_from_raw_session(session_raw) - except Exception as e: - self.__invoker.services.logger.warn(f"Failed to parse session graph: {e}") - graph = None - - return ImageMetadata(graph=graph, metadata=metadata) + return self.__invoker.services.image_records.get_metadata(image_name) except ImageRecordNotFoundException: self.__invoker.services.logger.error("Image record not found") raise diff --git a/invokeai/app/services/shared/graph.py b/invokeai/app/services/shared/graph.py index 8f974f7c6b..0f703db749 100644 --- a/invokeai/app/services/shared/graph.py +++ b/invokeai/app/services/shared/graph.py @@ -439,6 +439,14 @@ class Graph(BaseModel): except Exception as e: raise UnknownGraphValidationError(f"Problem validating graph {e}") from e + def _is_destination_field_Any(self, edge: Edge) -> bool: + """Checks if the destination field for an edge is of type typing.Any""" + return get_input_field(self.get_node(edge.destination.node_id), edge.destination.field) == Any + + def _is_destination_field_list_of_Any(self, edge: Edge) -> bool: + """Checks if the destination field for an edge is of type typing.Any""" + return get_input_field(self.get_node(edge.destination.node_id), edge.destination.field) == list[Any] + def _validate_edge(self, edge: Edge): """Validates that a new edge doesn't create a cycle in the graph""" @@ -491,8 +499,19 @@ class Graph(BaseModel): f"Collector output type does not match collector input type: {edge.source.node_id}.{edge.source.field} to {edge.destination.node_id}.{edge.destination.field}" ) - # Validate if collector output type matches input type (if this edge results in both being set) - if isinstance(from_node, CollectInvocation) and edge.source.field == "collection": + # Validate that we are not connecting collector to iterator (currently unsupported) + if isinstance(from_node, CollectInvocation) and isinstance(to_node, IterateInvocation): + raise InvalidEdgeError( + f"Cannot connect collector to iterator: {edge.source.node_id}.{edge.source.field} to {edge.destination.node_id}.{edge.destination.field}" + ) + + # Validate if collector output type matches input type (if this edge results in both being set) - skip if the destination field is not Any or list[Any] + if ( + isinstance(from_node, CollectInvocation) + and edge.source.field == "collection" + and not self._is_destination_field_list_of_Any(edge) + and not self._is_destination_field_Any(edge) + ): if not self._is_collector_connection_valid(edge.source.node_id, new_output=edge.destination): raise InvalidEdgeError( f"Collector input type does not match collector output type: {edge.source.node_id}.{edge.source.field} to {edge.destination.node_id}.{edge.destination.field}" @@ -725,16 +744,15 @@ class Graph(BaseModel): # Get the input root type input_root_type = next(t[0] for t in type_degrees if t[1] == 0) # type: ignore - # Verify that all outputs are lists - # if not all((get_origin(f) == list for f in output_fields)): - # return False - # Verify that all outputs are lists if not all(is_list_or_contains_list(f) for f in output_fields): return False # Verify that all outputs match the input type (are a base class or the same class) - if not all((issubclass(input_root_type, get_args(f)[0]) for f in output_fields)): + if not all( + is_union_subtype(input_root_type, get_args(f)[0]) or issubclass(input_root_type, get_args(f)[0]) + for f in output_fields + ): return False return True diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx index 57f06a0cea..4c0aa5e0e8 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx @@ -27,7 +27,7 @@ import { setShouldShowImageDetails, setShouldShowProgressInViewer, } from 'features/ui/store/uiSlice'; -import { memo, useCallback, useMemo } from 'react'; +import { memo, useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { @@ -40,11 +40,13 @@ import { import { FaCircleNodes, FaEllipsis } from 'react-icons/fa6'; import { useGetImageDTOQuery, - useGetImageMetadataFromFileQuery, + useGetImageMetadataQuery, } from 'services/api/endpoints/images'; import { menuListMotionProps } from 'theme/components/menu'; +import { useDebounce } from 'use-debounce'; import { sentImageToImg2Img } from '../../store/actions'; import SingleSelectionMenuItems from '../ImageContextMenu/SingleSelectionMenuItems'; +import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; const currentImageButtonsSelector = createSelector( [stateSelector, activeTabNameSelector], @@ -89,7 +91,6 @@ const CurrentImageButtons = () => { shouldShowImageDetails, lastSelectedImage, shouldShowProgressInViewer, - shouldFetchMetadataFromApi, } = useAppSelector(currentImageButtonsSelector); const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled; @@ -104,23 +105,17 @@ const CurrentImageButtons = () => { lastSelectedImage?.image_name ?? skipToken ); - const getMetadataArg = useMemo(() => { - if (lastSelectedImage) { - return { image: lastSelectedImage, shouldFetchMetadataFromApi }; - } else { - return skipToken; - } - }, [lastSelectedImage, shouldFetchMetadataFromApi]); + const [debouncedImageName] = useDebounce(lastSelectedImage?.image_name, 300); + const [debouncedWorkflowId] = useDebounce( + lastSelectedImage?.workflow_id, + 300 + ); - const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( - getMetadataArg, - { - selectFromResult: (res) => ({ - isLoading: res.isFetching, - metadata: res?.currentData?.metadata, - workflow: res?.currentData?.workflow, - }), - } + const { data: metadata, isLoading: isLoadingMetadata } = + useGetImageMetadataQuery(debouncedImageName ?? skipToken); + + const { data: workflow, isLoading: isLoadingWorkflow } = useGetWorkflowQuery( + debouncedWorkflowId ?? skipToken ); const handleLoadWorkflow = useCallback(() => { @@ -257,7 +252,7 @@ const CurrentImageButtons = () => { } tooltip={`${t('nodes.loadWorkflow')} (W)`} aria-label={`${t('nodes.loadWorkflow')} (W)`} @@ -265,7 +260,7 @@ const CurrentImageButtons = () => { onClick={handleLoadWorkflow} /> } tooltip={`${t('parameters.usePrompt')} (P)`} aria-label={`${t('parameters.usePrompt')} (P)`} @@ -273,7 +268,7 @@ const CurrentImageButtons = () => { onClick={handleUsePrompt} /> } tooltip={`${t('parameters.useSeed')} (S)`} aria-label={`${t('parameters.useSeed')} (S)`} @@ -281,7 +276,7 @@ const CurrentImageButtons = () => { onClick={handleUseSeed} /> } tooltip={`${t('parameters.useAll')} (A)`} aria-label={`${t('parameters.useAll')} (A)`} diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 35a4e9f18c..38de235e38 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -1,8 +1,9 @@ import { Flex, MenuItem, Spinner } from '@chakra-ui/react'; import { useStore } from '@nanostores/react'; +import { skipToken } from '@reduxjs/toolkit/dist/query'; import { useAppToaster } from 'app/components/Toaster'; import { $customStarUI } from 'app/store/nanostores/customStarUI'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { imagesToChangeSelected, @@ -32,12 +33,13 @@ import { import { FaCircleNodes } from 'react-icons/fa6'; import { MdStar, MdStarBorder } from 'react-icons/md'; import { - useGetImageMetadataFromFileQuery, + useGetImageMetadataQuery, useStarImagesMutation, useUnstarImagesMutation, } from 'services/api/endpoints/images'; +import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; import { ImageDTO } from 'services/api/types'; -import { configSelector } from '../../../system/store/configSelectors'; +import { useDebounce } from 'use-debounce'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; type SingleSelectionMenuItemsProps = { @@ -53,18 +55,16 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const toaster = useAppToaster(); const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; - const { shouldFetchMetadataFromApi } = useAppSelector(configSelector); const customStarUi = useStore($customStarUI); - const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( - { image: imageDTO, shouldFetchMetadataFromApi }, - { - selectFromResult: (res) => ({ - isLoading: res.isFetching, - metadata: res?.currentData?.metadata, - workflow: res?.currentData?.workflow, - }), - } + const [debouncedImageName] = useDebounce(imageDTO?.image_name, 300); + const [debouncedWorkflowId] = useDebounce(imageDTO?.workflow_id, 300); + + const { data: metadata, isLoading: isLoadingMetadata } = + useGetImageMetadataQuery(debouncedImageName ?? skipToken); + + const { data: workflow, isLoading: isLoadingWorkflow } = useGetWorkflowQuery( + debouncedWorkflowId ?? skipToken ); const [starImages] = useStarImagesMutation(); @@ -181,17 +181,17 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { {t('parameters.downloadImage')} : } + icon={isLoadingWorkflow ? : } onClickCapture={handleLoadWorkflow} - isDisabled={isLoading || !workflow} + isDisabled={isLoadingWorkflow || !workflow} > {t('nodes.loadWorkflow')} : } + icon={isLoadingMetadata ? : } onClickCapture={handleRecallPrompt} isDisabled={ - isLoading || + isLoadingMetadata || (metadata?.positive_prompt === undefined && metadata?.negative_prompt === undefined) } @@ -199,16 +199,16 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { {t('parameters.usePrompt')} : } + icon={isLoadingMetadata ? : } onClickCapture={handleRecallSeed} - isDisabled={isLoading || metadata?.seed === undefined} + isDisabled={isLoadingMetadata || metadata?.seed === undefined} > {t('parameters.useSeed')} : } + icon={isLoadingMetadata ? : } onClickCapture={handleUseAllParameters} - isDisabled={isLoading || !metadata} + isDisabled={isLoadingMetadata || !metadata} > {t('parameters.useAll')} diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx index e9cb3ffcaf..f6820b9d20 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx @@ -9,16 +9,17 @@ import { Tabs, Text, } from '@chakra-ui/react'; +import { skipToken } from '@reduxjs/toolkit/dist/query'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; +import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent'; import { memo } from 'react'; -import { useGetImageMetadataFromFileQuery } from 'services/api/endpoints/images'; +import { useTranslation } from 'react-i18next'; +import { useGetImageMetadataQuery } from 'services/api/endpoints/images'; +import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; import { ImageDTO } from 'services/api/types'; +import { useDebounce } from 'use-debounce'; import DataViewer from './DataViewer'; import ImageMetadataActions from './ImageMetadataActions'; -import { useAppSelector } from '../../../../app/store/storeHooks'; -import { configSelector } from '../../../system/store/configSelectors'; -import { useTranslation } from 'react-i18next'; -import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent'; type ImageMetadataViewerProps = { image: ImageDTO; @@ -32,16 +33,15 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => { // }); const { t } = useTranslation(); - const { shouldFetchMetadataFromApi } = useAppSelector(configSelector); + const [debouncedImageName] = useDebounce(image.image_name, 300); + const [debouncedWorkflowId] = useDebounce(image.workflow_id, 300); - const { metadata, workflow } = useGetImageMetadataFromFileQuery( - { image, shouldFetchMetadataFromApi }, - { - selectFromResult: (res) => ({ - metadata: res?.currentData?.metadata, - workflow: res?.currentData?.workflow, - }), - } + const { data: metadata } = useGetImageMetadataQuery( + debouncedImageName ?? skipToken + ); + + const { data: workflow } = useGetWorkflowQuery( + debouncedWorkflowId ?? skipToken ); return ( diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/EmbedWorkflowCheckbox.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/EmbedWorkflowCheckbox.tsx index 447dfcbd97..3c06b9f9da 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/EmbedWorkflowCheckbox.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/EmbedWorkflowCheckbox.tsx @@ -1,13 +1,13 @@ import { Checkbox, Flex, FormControl, FormLabel } from '@chakra-ui/react'; import { useAppDispatch } from 'app/store/storeHooks'; import { useEmbedWorkflow } from 'features/nodes/hooks/useEmbedWorkflow'; -import { useHasImageOutput } from 'features/nodes/hooks/useHasImageOutput'; +import { useWithWorkflow } from 'features/nodes/hooks/useWithWorkflow'; import { nodeEmbedWorkflowChanged } from 'features/nodes/store/nodesSlice'; import { ChangeEvent, memo, useCallback } from 'react'; const EmbedWorkflowCheckbox = ({ nodeId }: { nodeId: string }) => { const dispatch = useAppDispatch(); - const hasImageOutput = useHasImageOutput(nodeId); + const withWorkflow = useWithWorkflow(nodeId); const embedWorkflow = useEmbedWorkflow(nodeId); const handleChange = useCallback( (e: ChangeEvent) => { @@ -21,7 +21,7 @@ const EmbedWorkflowCheckbox = ({ nodeId }: { nodeId: string }) => { [dispatch, nodeId] ); - if (!hasImageOutput) { + if (!withWorkflow) { return null; } diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx index ec5085221e..1424c6b837 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx @@ -1,11 +1,11 @@ import { Flex } from '@chakra-ui/react'; +import { useHasImageOutput } from 'features/nodes/hooks/useHasImageOutput'; import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants'; import { memo } from 'react'; +import { useFeatureStatus } from '../../../../../system/hooks/useFeatureStatus'; import EmbedWorkflowCheckbox from './EmbedWorkflowCheckbox'; import SaveToGalleryCheckbox from './SaveToGalleryCheckbox'; import UseCacheCheckbox from './UseCacheCheckbox'; -import { useHasImageOutput } from 'features/nodes/hooks/useHasImageOutput'; -import { useFeatureStatus } from '../../../../../system/hooks/useFeatureStatus'; type Props = { nodeId: string; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useWithWorkflow.ts b/invokeai/frontend/web/src/features/nodes/hooks/useWithWorkflow.ts new file mode 100644 index 0000000000..3c83e01731 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/hooks/useWithWorkflow.ts @@ -0,0 +1,31 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { useMemo } from 'react'; +import { isInvocationNode } from '../types/types'; + +export const useWithWorkflow = (nodeId: string) => { + const selector = useMemo( + () => + createSelector( + stateSelector, + ({ nodes }) => { + const node = nodes.nodes.find((node) => node.id === nodeId); + if (!isInvocationNode(node)) { + return false; + } + const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? '']; + if (!nodeTemplate) { + return false; + } + return nodeTemplate.withWorkflow; + }, + defaultSelectorOptions + ), + [nodeId] + ); + + const withWorkflow = useAppSelector(selector); + return withWorkflow; +}; diff --git a/invokeai/frontend/web/src/features/nodes/store/util/validateSourceAndTargetTypes.ts b/invokeai/frontend/web/src/features/nodes/store/util/validateSourceAndTargetTypes.ts index 8c2bef34fe..2f47e47a78 100644 --- a/invokeai/frontend/web/src/features/nodes/store/util/validateSourceAndTargetTypes.ts +++ b/invokeai/frontend/web/src/features/nodes/store/util/validateSourceAndTargetTypes.ts @@ -69,6 +69,8 @@ export const validateSourceAndTargetTypes = ( (sourceType === 'integer' || sourceType === 'float') && targetType === 'string'; + const isTargetAnyType = targetType === 'Any'; + return ( isCollectionItemToNonCollection || isNonCollectionToCollectionItem || @@ -76,6 +78,7 @@ export const validateSourceAndTargetTypes = ( isGenericCollectionToAnyCollectionOrPolymorphic || isCollectionToGenericCollection || isIntToFloat || - isIntOrFloatToString + isIntOrFloatToString || + isTargetAnyType ); }; diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 076f71cc02..c6eec736da 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -33,6 +33,8 @@ export const COLLECTION_TYPES: FieldType[] = [ 'ColorCollection', 'T2IAdapterCollection', 'IPAdapterCollection', + 'MetadataItemCollection', + 'MetadataCollection', ]; export const POLYMORPHIC_TYPES: FieldType[] = [ @@ -47,6 +49,7 @@ export const POLYMORPHIC_TYPES: FieldType[] = [ 'ColorPolymorphic', 'T2IAdapterPolymorphic', 'IPAdapterPolymorphic', + 'MetadataItemPolymorphic', ]; export const MODEL_TYPES: FieldType[] = [ @@ -78,6 +81,8 @@ export const COLLECTION_MAP: FieldTypeMapWithNumber = { ColorField: 'ColorCollection', T2IAdapterField: 'T2IAdapterCollection', IPAdapterField: 'IPAdapterCollection', + MetadataItemField: 'MetadataItemCollection', + MetadataField: 'MetadataCollection', }; export const isCollectionItemType = ( itemType: string | undefined @@ -97,6 +102,7 @@ export const SINGLE_TO_POLYMORPHIC_MAP: FieldTypeMapWithNumber = { ColorField: 'ColorPolymorphic', T2IAdapterField: 'T2IAdapterPolymorphic', IPAdapterField: 'IPAdapterPolymorphic', + MetadataItemField: 'MetadataItemPolymorphic', }; export const POLYMORPHIC_TO_SINGLE_MAP: FieldTypeMap = { @@ -111,6 +117,7 @@ export const POLYMORPHIC_TO_SINGLE_MAP: FieldTypeMap = { ColorPolymorphic: 'ColorField', T2IAdapterPolymorphic: 'T2IAdapterField', IPAdapterPolymorphic: 'IPAdapterField', + MetadataItemPolymorphic: 'MetadataItemField', }; export const TYPES_WITH_INPUT_COMPONENTS: FieldType[] = [ @@ -144,6 +151,37 @@ export const isPolymorphicItemType = ( Boolean(itemType && itemType in SINGLE_TO_POLYMORPHIC_MAP); export const FIELDS: Record = { + Any: { + color: 'gray.500', + description: 'Any field type is accepted.', + title: 'Any', + }, + MetadataField: { + color: 'gray.500', + description: 'A metadata dict.', + title: 'Metadata Dict', + }, + MetadataCollection: { + color: 'gray.500', + description: 'A collection of metadata dicts.', + title: 'Metadata Dict Collection', + }, + MetadataItemField: { + color: 'gray.500', + description: 'A metadata item.', + title: 'Metadata Item', + }, + MetadataItemCollection: { + color: 'gray.500', + description: 'Any field type is accepted.', + title: 'Metadata Item Collection', + }, + MetadataItemPolymorphic: { + color: 'gray.500', + description: + 'MetadataItem or MetadataItemCollection field types are accepted.', + title: 'Metadata Item Polymorphic', + }, boolean: { color: 'green.500', description: t('nodes.booleanDescription'), diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index 87c716bb81..ba1ca05c4d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -54,6 +54,10 @@ export type InvocationTemplate = { * The type of this node's output */ outputType: string; // TODO: generate a union of output types + /** + * Whether or not this invocation supports workflows + */ + withWorkflow: boolean; /** * The invocation's version. */ @@ -72,6 +76,7 @@ export type FieldUIConfig = { // TODO: Get this from the OpenAPI schema? may be tricky... export const zFieldType = z.enum([ + 'Any', 'BoardField', 'boolean', 'BooleanCollection', @@ -109,6 +114,11 @@ export const zFieldType = z.enum([ 'LatentsPolymorphic', 'LoRAModelField', 'MainModelField', + 'MetadataField', + 'MetadataCollection', + 'MetadataItemField', + 'MetadataItemCollection', + 'MetadataItemPolymorphic', 'ONNXModelField', 'Scheduler', 'SDXLMainModelField', @@ -685,6 +695,57 @@ export type CollectionItemInputFieldValue = z.infer< typeof zCollectionItemInputFieldValue >; +export const zMetadataItemField = z.object({ + label: z.string(), + value: z.any(), +}); +export type MetadataItemField = z.infer; + +export const zMetadataItemInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('MetadataItemField'), + value: zMetadataItemField.optional(), +}); +export type MetadataItemInputFieldValue = z.infer< + typeof zMetadataItemInputFieldValue +>; + +export const zMetadataItemCollectionInputFieldValue = + zInputFieldValueBase.extend({ + type: z.literal('MetadataItemCollection'), + value: z.array(zMetadataItemField).optional(), + }); +export type MetadataItemCollectionInputFieldValue = z.infer< + typeof zMetadataItemCollectionInputFieldValue +>; + +export const zMetadataItemPolymorphicInputFieldValue = + zInputFieldValueBase.extend({ + type: z.literal('MetadataItemPolymorphic'), + value: z + .union([zMetadataItemField, z.array(zMetadataItemField)]) + .optional(), + }); +export type MetadataItemPolymorphicInputFieldValue = z.infer< + typeof zMetadataItemPolymorphicInputFieldValue +>; + +export const zMetadataField = z.record(z.any()); +export type MetadataField = z.infer; + +export const zMetadataInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('MetadataField'), + value: zMetadataField.optional(), +}); +export type MetadataInputFieldValue = z.infer; + +export const zMetadataCollectionInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('MetadataCollection'), + value: z.array(zMetadataField).optional(), +}); +export type MetadataCollectionInputFieldValue = z.infer< + typeof zMetadataCollectionInputFieldValue +>; + export const zColorField = z.object({ r: z.number().int().min(0).max(255), g: z.number().int().min(0).max(255), @@ -723,7 +784,13 @@ export type SchedulerInputFieldValue = z.infer< typeof zSchedulerInputFieldValue >; +export const zAnyInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('Any'), + value: z.any().optional(), +}); + export const zInputFieldValue = z.discriminatedUnion('type', [ + zAnyInputFieldValue, zBoardInputFieldValue, zBooleanCollectionInputFieldValue, zBooleanInputFieldValue, @@ -774,6 +841,11 @@ export const zInputFieldValue = z.discriminatedUnion('type', [ zUNetInputFieldValue, zVaeInputFieldValue, zVaeModelInputFieldValue, + zMetadataItemInputFieldValue, + zMetadataItemCollectionInputFieldValue, + zMetadataItemPolymorphicInputFieldValue, + zMetadataInputFieldValue, + zMetadataCollectionInputFieldValue, ]); export type InputFieldValue = z.infer; @@ -786,6 +858,11 @@ export type InputFieldTemplateBase = { fieldKind: 'input'; } & _InputField; +export type AnyInputFieldTemplate = InputFieldTemplateBase & { + type: 'Any'; + default: undefined; +}; + export type IntegerInputFieldTemplate = InputFieldTemplateBase & { type: 'integer'; default: number; @@ -939,6 +1016,11 @@ export type UNetInputFieldTemplate = InputFieldTemplateBase & { type: 'UNetField'; }; +export type MetadataItemFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'MetadataItemField'; +}; + export type ClipInputFieldTemplate = InputFieldTemplateBase & { default: undefined; type: 'ClipField'; @@ -1087,6 +1169,34 @@ export type WorkflowInputFieldTemplate = InputFieldTemplateBase & { type: 'WorkflowField'; }; +export type MetadataItemInputFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'MetadataItemField'; +}; + +export type MetadataItemCollectionInputFieldTemplate = + InputFieldTemplateBase & { + default: undefined; + type: 'MetadataItemCollection'; + }; + +export type MetadataItemPolymorphicInputFieldTemplate = Omit< + MetadataItemInputFieldTemplate, + 'type' +> & { + type: 'MetadataItemPolymorphic'; +}; + +export type MetadataInputFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'MetadataField'; +}; + +export type MetadataCollectionInputFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'MetadataCollection'; +}; + /** * An input field template is generated on each page load from the OpenAPI schema. * @@ -1094,6 +1204,7 @@ export type WorkflowInputFieldTemplate = InputFieldTemplateBase & { * maximum length, pattern to match, etc). */ export type InputFieldTemplate = + | AnyInputFieldTemplate | BoardInputFieldTemplate | BooleanCollectionInputFieldTemplate | BooleanPolymorphicInputFieldTemplate @@ -1143,7 +1254,12 @@ export type InputFieldTemplate = | T2IAdapterPolymorphicInputFieldTemplate | UNetInputFieldTemplate | VaeInputFieldTemplate - | VaeModelInputFieldTemplate; + | VaeModelInputFieldTemplate + | MetadataItemInputFieldTemplate + | MetadataItemCollectionInputFieldTemplate + | MetadataInputFieldTemplate + | MetadataItemPolymorphicInputFieldTemplate + | MetadataCollectionInputFieldTemplate; export const isInputFieldValue = ( field?: InputFieldValue | OutputFieldValue @@ -1264,7 +1380,7 @@ export const isInvocationFieldSchema = ( export type InvocationEdgeExtra = { type: 'default' | 'collapsed' }; -const zLoRAMetadataItem = z.object({ +export const zLoRAMetadataItem = z.object({ lora: zLoRAModelField.deepPartial(), weight: z.number(), }); diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index 3fd44207c0..92e44e9ab2 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -7,6 +7,7 @@ import { startCase, } from 'lodash-es'; import { OpenAPIV3_1 } from 'openapi-types'; +import { ControlField } from 'services/api/types'; import { COLLECTION_MAP, POLYMORPHIC_TYPES, @@ -15,36 +16,70 @@ import { isPolymorphicItemType, } from '../types/constants'; import { + AnyInputFieldTemplate, + BoardInputFieldTemplate, BooleanCollectionInputFieldTemplate, BooleanInputFieldTemplate, + BooleanPolymorphicInputFieldTemplate, ClipInputFieldTemplate, CollectionInputFieldTemplate, CollectionItemInputFieldTemplate, + ColorCollectionInputFieldTemplate, ColorInputFieldTemplate, + ColorPolymorphicInputFieldTemplate, + ConditioningCollectionInputFieldTemplate, + ConditioningField, ConditioningInputFieldTemplate, + ConditioningPolymorphicInputFieldTemplate, + ControlCollectionInputFieldTemplate, ControlInputFieldTemplate, ControlNetModelInputFieldTemplate, + ControlPolymorphicInputFieldTemplate, DenoiseMaskInputFieldTemplate, EnumInputFieldTemplate, FieldType, FloatCollectionInputFieldTemplate, - FloatPolymorphicInputFieldTemplate, FloatInputFieldTemplate, + FloatPolymorphicInputFieldTemplate, + IPAdapterCollectionInputFieldTemplate, + IPAdapterField, + IPAdapterInputFieldTemplate, + IPAdapterModelInputFieldTemplate, + IPAdapterPolymorphicInputFieldTemplate, ImageCollectionInputFieldTemplate, + ImageField, ImageInputFieldTemplate, + ImagePolymorphicInputFieldTemplate, + InputFieldTemplate, InputFieldTemplateBase, IntegerCollectionInputFieldTemplate, IntegerInputFieldTemplate, + IntegerPolymorphicInputFieldTemplate, InvocationFieldSchema, InvocationSchemaObject, + LatentsCollectionInputFieldTemplate, + LatentsField, LatentsInputFieldTemplate, + LatentsPolymorphicInputFieldTemplate, LoRAModelInputFieldTemplate, MainModelInputFieldTemplate, + MetadataCollectionInputFieldTemplate, + MetadataInputFieldTemplate, + MetadataItemCollectionInputFieldTemplate, + MetadataItemInputFieldTemplate, + MetadataItemPolymorphicInputFieldTemplate, + OpenAPIV3_1SchemaOrRef, SDXLMainModelInputFieldTemplate, SDXLRefinerModelInputFieldTemplate, SchedulerInputFieldTemplate, StringCollectionInputFieldTemplate, StringInputFieldTemplate, + StringPolymorphicInputFieldTemplate, + T2IAdapterCollectionInputFieldTemplate, + T2IAdapterField, + T2IAdapterInputFieldTemplate, + T2IAdapterModelInputFieldTemplate, + T2IAdapterPolymorphicInputFieldTemplate, UNetInputFieldTemplate, VaeInputFieldTemplate, VaeModelInputFieldTemplate, @@ -52,36 +87,7 @@ import { isNonArraySchemaObject, isRefObject, isSchemaObject, - ControlPolymorphicInputFieldTemplate, - ColorPolymorphicInputFieldTemplate, - ColorCollectionInputFieldTemplate, - IntegerPolymorphicInputFieldTemplate, - StringPolymorphicInputFieldTemplate, - BooleanPolymorphicInputFieldTemplate, - ImagePolymorphicInputFieldTemplate, - LatentsPolymorphicInputFieldTemplate, - LatentsCollectionInputFieldTemplate, - ConditioningPolymorphicInputFieldTemplate, - ConditioningCollectionInputFieldTemplate, - ControlCollectionInputFieldTemplate, - ImageField, - LatentsField, - ConditioningField, - IPAdapterField, - IPAdapterInputFieldTemplate, - IPAdapterModelInputFieldTemplate, - IPAdapterPolymorphicInputFieldTemplate, - IPAdapterCollectionInputFieldTemplate, - T2IAdapterField, - T2IAdapterInputFieldTemplate, - T2IAdapterModelInputFieldTemplate, - T2IAdapterPolymorphicInputFieldTemplate, - T2IAdapterCollectionInputFieldTemplate, - BoardInputFieldTemplate, - InputFieldTemplate, - OpenAPIV3_1SchemaOrRef, } from '../types/types'; -import { ControlField } from 'services/api/types'; export type BaseFieldProperties = 'name' | 'title' | 'description'; @@ -851,6 +857,78 @@ const buildCollectionItemInputFieldTemplate = ({ return template; }; +const buildAnyInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): AnyInputFieldTemplate => { + const template: AnyInputFieldTemplate = { + ...baseField, + type: 'Any', + default: undefined, + }; + + return template; +}; + +const buildMetadataItemInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): MetadataItemInputFieldTemplate => { + const template: MetadataItemInputFieldTemplate = { + ...baseField, + type: 'MetadataItemField', + default: undefined, + }; + + return template; +}; + +const buildMetadataItemCollectionInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): MetadataItemCollectionInputFieldTemplate => { + const template: MetadataItemCollectionInputFieldTemplate = { + ...baseField, + type: 'MetadataItemCollection', + default: undefined, + }; + + return template; +}; + +const buildMetadataItemPolymorphicInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): MetadataItemPolymorphicInputFieldTemplate => { + const template: MetadataItemPolymorphicInputFieldTemplate = { + ...baseField, + type: 'MetadataItemPolymorphic', + default: undefined, + }; + + return template; +}; + +const buildMetadataDictInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): MetadataInputFieldTemplate => { + const template: MetadataInputFieldTemplate = { + ...baseField, + type: 'MetadataField', + default: undefined, + }; + + return template; +}; + +const buildMetadataCollectionInputFieldTemplate = ({ + baseField, +}: BuildInputFieldArg): MetadataCollectionInputFieldTemplate => { + const template: MetadataCollectionInputFieldTemplate = { + ...baseField, + type: 'MetadataCollection', + default: undefined, + }; + + return template; +}; + const buildColorInputFieldTemplate = ({ schemaObject, baseField, @@ -1012,6 +1090,7 @@ const TEMPLATE_BUILDER_MAP: { [key in FieldType]?: (arg: BuildInputFieldArg) => InputFieldTemplate; } = { BoardField: buildBoardInputFieldTemplate, + Any: buildAnyInputFieldTemplate, boolean: buildBooleanInputFieldTemplate, BooleanCollection: buildBooleanCollectionInputFieldTemplate, BooleanPolymorphic: buildBooleanPolymorphicInputFieldTemplate, @@ -1047,6 +1126,11 @@ const TEMPLATE_BUILDER_MAP: { LatentsField: buildLatentsInputFieldTemplate, LatentsPolymorphic: buildLatentsPolymorphicInputFieldTemplate, LoRAModelField: buildLoRAModelInputFieldTemplate, + MetadataItemField: buildMetadataItemInputFieldTemplate, + MetadataItemCollection: buildMetadataItemCollectionInputFieldTemplate, + MetadataItemPolymorphic: buildMetadataItemPolymorphicInputFieldTemplate, + MetadataField: buildMetadataDictInputFieldTemplate, + MetadataCollection: buildMetadataCollectionInputFieldTemplate, MainModelField: buildMainModelInputFieldTemplate, Scheduler: buildSchedulerInputFieldTemplate, SDXLMainModelField: buildSDXLMainModelInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts index 97f520379a..ca2513649d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts @@ -3,6 +3,7 @@ import { FieldType, InputFieldTemplate, InputFieldValue } from '../types/types'; const FIELD_VALUE_FALLBACK_MAP: { [key in FieldType]: InputFieldValue['value']; } = { + Any: undefined, enum: '', BoardField: undefined, boolean: false, @@ -38,6 +39,11 @@ const FIELD_VALUE_FALLBACK_MAP: { LatentsCollection: [], LatentsField: undefined, LatentsPolymorphic: undefined, + MetadataItemField: undefined, + MetadataItemCollection: [], + MetadataItemPolymorphic: undefined, + MetadataField: undefined, + MetadataCollection: [], LoRAModelField: undefined, MainModelField: undefined, ONNXModelField: undefined, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts index 37bd82d4f8..60d4e36dca 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts @@ -5,14 +5,14 @@ import { CollectInvocation, ControlField, ControlNetInvocation, - MetadataAccumulatorInvocation, + CoreMetadataInvocation, } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; import { CANVAS_COHERENCE_DENOISE_LATENTS, CONTROL_NET_COLLECT, - METADATA_ACCUMULATOR, } from './constants'; +import { upsertMetadata } from './metadata'; export const addControlNetToLinearGraph = ( state: RootState, @@ -23,9 +23,11 @@ export const addControlNetToLinearGraph = ( (ca) => ca.model?.base_model === state.generation.model?.base_model ); - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; + // const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as + // | MetadataAccumulatorInvocation + // | undefined; + + const controlNetMetadata: CoreMetadataInvocation['controlnets'] = []; if (validControlNets.length) { // Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect @@ -99,15 +101,9 @@ export const addControlNetToLinearGraph = ( graph.nodes[controlNetNode.id] = controlNetNode as ControlNetInvocation; - if (metadataAccumulator?.controlnets) { - // metadata accumulator only needs a control field - not the whole node - // extract what we need and add to the accumulator - const controlField = omit(controlNetNode, [ - 'id', - 'type', - ]) as ControlField; - metadataAccumulator.controlnets.push(controlField); - } + controlNetMetadata.push( + omit(controlNetNode, ['id', 'type', 'is_intermediate']) as ControlField + ); graph.edges.push({ source: { node_id: controlNetNode.id, field: 'control' }, @@ -117,5 +113,6 @@ export const addControlNetToLinearGraph = ( }, }); }); + upsertMetadata(graph, { controlnets: controlNetMetadata }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts index 4b4a8a8a03..8c23ae667e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts @@ -1,25 +1,25 @@ +import { logger } from 'app/logging/logger'; import { RootState } from 'app/store/store'; import { NonNullableGraph } from 'features/nodes/types/types'; import { DenoiseLatentsInvocation, - ResizeLatentsInvocation, - NoiseInvocation, - LatentsToImageInvocation, Edge, + LatentsToImageInvocation, + NoiseInvocation, + ResizeLatentsInvocation, } from 'services/api/types'; import { - LATENTS_TO_IMAGE, DENOISE_LATENTS, - NOISE, - MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, - LATENTS_TO_IMAGE_HRF, DENOISE_LATENTS_HRF, - RESCALE_LATENTS, + LATENTS_TO_IMAGE, + LATENTS_TO_IMAGE_HRF, + MAIN_MODEL_LOADER, + NOISE, NOISE_HRF, + RESCALE_LATENTS, VAE_LOADER, } from './constants'; -import { logger } from 'app/logging/logger'; +import { upsertMetadata } from './metadata'; // Copy certain connections from previous DENOISE_LATENTS to new DENOISE_LATENTS_HRF. function copyConnectionsToDenoiseLatentsHrf(graph: NonNullableGraph): void { @@ -71,10 +71,8 @@ export const addHrfToGraph = ( } const log = logger('txt2img'); - const { vae } = state.generation; + const { vae, hrfWidth, hrfHeight, hrfStrength } = state.generation; const isAutoVae = !vae; - const hrfWidth = state.generation.hrfWidth; - const hrfHeight = state.generation.hrfHeight; // Pre-existing (original) graph nodes. const originalDenoiseLatentsNode = graph.nodes[DENOISE_LATENTS] as @@ -116,7 +114,7 @@ export const addHrfToGraph = ( cfg_scale: originalDenoiseLatentsNode?.cfg_scale, scheduler: originalDenoiseLatentsNode?.scheduler, steps: originalDenoiseLatentsNode?.steps, - denoising_start: 1 - state.generation.hrfStrength, + denoising_start: 1 - hrfStrength, denoising_end: 1, }; @@ -221,16 +219,6 @@ export const addHrfToGraph = ( field: 'latents', }, }, - { - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: LATENTS_TO_IMAGE_HRF, - field: 'metadata', - }, - }, { source: { node_id: isAutoVae ? MAIN_MODEL_LOADER : VAE_LOADER, @@ -243,5 +231,11 @@ export const addHrfToGraph = ( } ); + upsertMetadata(graph, { + hrf_height: hrfHeight, + hrf_width: hrfWidth, + hrf_strength: hrfStrength, + }); + copyConnectionsToDenoiseLatentsHrf(graph); }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts index 19bf7d8338..93c6cdb284 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts @@ -1,16 +1,18 @@ import { RootState } from 'app/store/store'; import { selectValidIPAdapters } from 'features/controlAdapters/store/controlAdaptersSlice'; +import { omit } from 'lodash-es'; import { CollectInvocation, + CoreMetadataInvocation, IPAdapterInvocation, - MetadataAccumulatorInvocation, + IPAdapterMetadataField, } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; import { CANVAS_COHERENCE_DENOISE_LATENTS, IP_ADAPTER_COLLECT, - METADATA_ACCUMULATOR, } from './constants'; +import { upsertMetadata } from './metadata'; export const addIPAdapterToLinearGraph = ( state: RootState, @@ -21,10 +23,6 @@ export const addIPAdapterToLinearGraph = ( (ca) => ca.model?.base_model === state.generation.model?.base_model ); - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - if (validIPAdapters.length) { // Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect const ipAdapterCollectNode: CollectInvocation = { @@ -50,6 +48,7 @@ export const addIPAdapterToLinearGraph = ( }, }); } + const ipAdapterMetdata: CoreMetadataInvocation['ipAdapters'] = []; validIPAdapters.forEach((ipAdapter) => { if (!ipAdapter.model) { @@ -76,19 +75,13 @@ export const addIPAdapterToLinearGraph = ( graph.nodes[ipAdapterNode.id] = ipAdapterNode as IPAdapterInvocation; - if (metadataAccumulator?.ipAdapters) { - const ipAdapterField = { - image: { - image_name: ipAdapter.controlImage, - }, - weight, - ip_adapter_model: model, - begin_step_percent: beginStepPct, - end_step_percent: endStepPct, - }; - - metadataAccumulator.ipAdapters.push(ipAdapterField); - } + ipAdapterMetdata.push( + omit(ipAdapterNode, [ + 'id', + 'type', + 'is_intermediate', + ]) as IPAdapterMetadataField + ); graph.edges.push({ source: { node_id: ipAdapterNode.id, field: 'ip_adapter' }, @@ -98,5 +91,7 @@ export const addIPAdapterToLinearGraph = ( }, }); }); + + upsertMetadata(graph, { ipAdapters: ipAdapterMetdata }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts index e199a78a20..66c2bd0444 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts @@ -2,20 +2,20 @@ import { RootState } from 'app/store/store'; import { NonNullableGraph } from 'features/nodes/types/types'; import { forEach, size } from 'lodash-es'; import { + CoreMetadataInvocation, LoraLoaderInvocation, - MetadataAccumulatorInvocation, } from 'services/api/types'; import { + CANVAS_COHERENCE_DENOISE_LATENTS, CANVAS_INPAINT_GRAPH, CANVAS_OUTPAINT_GRAPH, - CANVAS_COHERENCE_DENOISE_LATENTS, CLIP_SKIP, LORA_LOADER, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, POSITIVE_CONDITIONING, } from './constants'; +import { upsertMetadata } from './metadata'; export const addLoRAsToGraph = ( state: RootState, @@ -33,29 +33,29 @@ export const addLoRAsToGraph = ( const { loras } = state.lora; const loraCount = size(loras); - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - if (loraCount > 0) { - // Remove modelLoaderNodeId unet connection to feed it to LoRAs - graph.edges = graph.edges.filter( - (e) => - !( - e.source.node_id === modelLoaderNodeId && - ['unet'].includes(e.source.field) - ) - ); - // Remove CLIP_SKIP connections to conditionings to feed it through LoRAs - graph.edges = graph.edges.filter( - (e) => - !(e.source.node_id === CLIP_SKIP && ['clip'].includes(e.source.field)) - ); + if (loraCount === 0) { + return; } + // Remove modelLoaderNodeId unet connection to feed it to LoRAs + graph.edges = graph.edges.filter( + (e) => + !( + e.source.node_id === modelLoaderNodeId && + ['unet'].includes(e.source.field) + ) + ); + // Remove CLIP_SKIP connections to conditionings to feed it through LoRAs + graph.edges = graph.edges.filter( + (e) => + !(e.source.node_id === CLIP_SKIP && ['clip'].includes(e.source.field)) + ); + // we need to remember the last lora so we can chain from it let lastLoraNodeId = ''; let currentLoraIndex = 0; + const loraMetadata: CoreMetadataInvocation['loras'] = []; forEach(loras, (lora) => { const { model_name, base_model, weight } = lora; @@ -69,13 +69,10 @@ export const addLoRAsToGraph = ( weight, }; - // add the lora to the metadata accumulator - if (metadataAccumulator?.loras) { - metadataAccumulator.loras.push({ - lora: { model_name, base_model }, - weight, - }); - } + loraMetadata.push({ + lora: { model_name, base_model }, + weight, + }); // add to graph graph.nodes[currentLoraNodeId] = loraLoaderNode; @@ -182,4 +179,6 @@ export const addLoRAsToGraph = ( lastLoraNodeId = currentLoraNodeId; currentLoraIndex += 1; }); + + upsertMetadata(graph, { loras: loraMetadata }); }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts index cb052984d4..04841f0def 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts @@ -1,14 +1,14 @@ import { RootState } from 'app/store/store'; -import { NonNullableGraph } from 'features/nodes/types/types'; -import { forEach, size } from 'lodash-es'; import { - MetadataAccumulatorInvocation, - SDXLLoraLoaderInvocation, -} from 'services/api/types'; + LoRAMetadataItem, + NonNullableGraph, + zLoRAMetadataItem, +} from 'features/nodes/types/types'; +import { forEach, size } from 'lodash-es'; +import { SDXLLoraLoaderInvocation } from 'services/api/types'; import { CANVAS_COHERENCE_DENOISE_LATENTS, LORA_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, POSITIVE_CONDITIONING, SDXL_CANVAS_INPAINT_GRAPH, @@ -17,6 +17,7 @@ import { SDXL_REFINER_INPAINT_CREATE_MASK, SEAMLESS, } from './constants'; +import { upsertMetadata } from './metadata'; export const addSDXLLoRAsToGraph = ( state: RootState, @@ -34,9 +35,12 @@ export const addSDXLLoRAsToGraph = ( const { loras } = state.lora; const loraCount = size(loras); - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; + + if (loraCount === 0) { + return; + } + + const loraMetadata: LoRAMetadataItem[] = []; // Handle Seamless Plugs const unetLoaderId = modelLoaderNodeId; @@ -47,22 +51,17 @@ export const addSDXLLoRAsToGraph = ( clipLoaderId = SDXL_MODEL_LOADER; } - if (loraCount > 0) { - // Remove modelLoaderNodeId unet/clip/clip2 connections to feed it to LoRAs - graph.edges = graph.edges.filter( - (e) => - !( - e.source.node_id === unetLoaderId && ['unet'].includes(e.source.field) - ) && - !( - e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field) - ) && - !( - e.source.node_id === clipLoaderId && - ['clip2'].includes(e.source.field) - ) - ); - } + // Remove modelLoaderNodeId unet/clip/clip2 connections to feed it to LoRAs + graph.edges = graph.edges.filter( + (e) => + !( + e.source.node_id === unetLoaderId && ['unet'].includes(e.source.field) + ) && + !( + e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field) + ) && + !(e.source.node_id === clipLoaderId && ['clip2'].includes(e.source.field)) + ); // we need to remember the last lora so we can chain from it let lastLoraNodeId = ''; @@ -80,16 +79,12 @@ export const addSDXLLoRAsToGraph = ( weight, }; - // add the lora to the metadata accumulator - if (metadataAccumulator) { - if (!metadataAccumulator.loras) { - metadataAccumulator.loras = []; - } - metadataAccumulator.loras.push({ + loraMetadata.push( + zLoRAMetadataItem.parse({ lora: { model_name, base_model }, weight, - }); - } + }) + ); // add to graph graph.nodes[currentLoraNodeId] = loraLoaderNode; @@ -242,4 +237,6 @@ export const addSDXLLoRAsToGraph = ( lastLoraNodeId = currentLoraNodeId; currentLoraIndex += 1; }); + + upsertMetadata(graph, { loras: loraMetadata }); }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts index a6ee6a091d..136263f63e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts @@ -2,7 +2,6 @@ import { RootState } from 'app/store/store'; import { CreateDenoiseMaskInvocation, ImageDTO, - MetadataAccumulatorInvocation, SeamlessModeInvocation, } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; @@ -12,7 +11,6 @@ import { LATENTS_TO_IMAGE, MASK_COMBINE, MASK_RESIZE_UP, - METADATA_ACCUMULATOR, SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, SDXL_CANVAS_INPAINT_GRAPH, SDXL_CANVAS_OUTPAINT_GRAPH, @@ -26,6 +24,7 @@ import { SDXL_REFINER_SEAMLESS, } from './constants'; import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt'; +import { upsertMetadata } from './metadata'; export const addSDXLRefinerToGraph = ( state: RootState, @@ -58,21 +57,15 @@ export const addSDXLRefinerToGraph = ( return; } - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - - if (metadataAccumulator) { - metadataAccumulator.refiner_model = refinerModel; - metadataAccumulator.refiner_positive_aesthetic_score = - refinerPositiveAestheticScore; - metadataAccumulator.refiner_negative_aesthetic_score = - refinerNegativeAestheticScore; - metadataAccumulator.refiner_cfg_scale = refinerCFGScale; - metadataAccumulator.refiner_scheduler = refinerScheduler; - metadataAccumulator.refiner_start = refinerStart; - metadataAccumulator.refiner_steps = refinerSteps; - } + upsertMetadata(graph, { + refiner_model: refinerModel, + refiner_positive_aesthetic_score: refinerPositiveAestheticScore, + refiner_negative_aesthetic_score: refinerNegativeAestheticScore, + refiner_cfg_scale: refinerCFGScale, + refiner_scheduler: refinerScheduler, + refiner_start: refinerStart, + refiner_steps: refinerSteps, + }); const modelLoaderId = modelLoaderNodeId ? modelLoaderNodeId diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts index d5a6addf8a..79aace8f62 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts @@ -1,19 +1,15 @@ +import { RootState } from 'app/store/store'; import { NonNullableGraph } from 'features/nodes/types/types'; +import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; +import { SaveImageInvocation } from 'services/api/types'; import { CANVAS_OUTPUT, LATENTS_TO_IMAGE, LATENTS_TO_IMAGE_HRF, - METADATA_ACCUMULATOR, NSFW_CHECKER, SAVE_IMAGE, WATERMARKER, } from './constants'; -import { - MetadataAccumulatorInvocation, - SaveImageInvocation, -} from 'services/api/types'; -import { RootState } from 'app/store/store'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; /** * Set the `use_cache` field on the linear/canvas graph's final image output node to False. @@ -37,23 +33,6 @@ export const addSaveImageNode = ( graph.nodes[SAVE_IMAGE] = saveImageNode; - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - - if (metadataAccumulator) { - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: SAVE_IMAGE, - field: 'metadata', - }, - }); - } - const destination = { node_id: SAVE_IMAGE, field: 'image', diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts index bdbaacd384..ba341a8a3d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -1,6 +1,7 @@ import { RootState } from 'app/store/store'; import { SeamlessModeInvocation } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; +import { upsertMetadata } from './metadata'; import { CANVAS_COHERENCE_DENOISE_LATENTS, CANVAS_INPAINT_GRAPH, @@ -31,6 +32,17 @@ export const addSeamlessToLinearGraph = ( seamless_y: seamlessYAxis, } as SeamlessModeInvocation; + if (seamlessXAxis) { + upsertMetadata(graph, { + seamless_x: seamlessXAxis, + }); + } + if (seamlessYAxis) { + upsertMetadata(graph, { + seamless_y: seamlessYAxis, + }); + } + let denoisingNodeId = DENOISE_LATENTS; if ( diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts index 9511475bb3..71c2aaeede 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts @@ -3,15 +3,15 @@ import { selectValidT2IAdapters } from 'features/controlAdapters/store/controlAd import { omit } from 'lodash-es'; import { CollectInvocation, - MetadataAccumulatorInvocation, + CoreMetadataInvocation, T2IAdapterInvocation, } from 'services/api/types'; import { NonNullableGraph, T2IAdapterField } from '../../types/types'; import { CANVAS_COHERENCE_DENOISE_LATENTS, - METADATA_ACCUMULATOR, T2I_ADAPTER_COLLECT, } from './constants'; +import { upsertMetadata } from './metadata'; export const addT2IAdaptersToLinearGraph = ( state: RootState, @@ -22,10 +22,6 @@ export const addT2IAdaptersToLinearGraph = ( (ca) => ca.model?.base_model === state.generation.model?.base_model ); - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - if (validT2IAdapters.length) { // Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect const t2iAdapterCollectNode: CollectInvocation = { @@ -51,6 +47,7 @@ export const addT2IAdaptersToLinearGraph = ( }, }); } + const t2iAdapterMetdata: CoreMetadataInvocation['t2iAdapters'] = []; validT2IAdapters.forEach((t2iAdapter) => { if (!t2iAdapter.model) { @@ -96,15 +93,13 @@ export const addT2IAdaptersToLinearGraph = ( graph.nodes[t2iAdapterNode.id] = t2iAdapterNode as T2IAdapterInvocation; - if (metadataAccumulator?.t2iAdapters) { - // metadata accumulator only needs a control field - not the whole node - // extract what we need and add to the accumulator - const t2iAdapterField = omit(t2iAdapterNode, [ + t2iAdapterMetdata.push( + omit(t2iAdapterNode, [ 'id', 'type', - ]) as T2IAdapterField; - metadataAccumulator.t2iAdapters.push(t2iAdapterField); - } + 'is_intermediate', + ]) as T2IAdapterField + ); graph.edges.push({ source: { node_id: t2iAdapterNode.id, field: 't2i_adapter' }, @@ -114,5 +109,7 @@ export const addT2IAdaptersToLinearGraph = ( }, }); }); + + upsertMetadata(graph, { t2iAdapters: t2iAdapterMetdata }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts index 696c8afff2..f049a89e36 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts @@ -1,6 +1,5 @@ import { RootState } from 'app/store/store'; import { NonNullableGraph } from 'features/nodes/types/types'; -import { MetadataAccumulatorInvocation } from 'services/api/types'; import { CANVAS_COHERENCE_INPAINT_CREATE_MASK, CANVAS_IMAGE_TO_IMAGE_GRAPH, @@ -14,7 +13,6 @@ import { INPAINT_IMAGE, LATENTS_TO_IMAGE, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, ONNX_MODEL_LOADER, SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, SDXL_CANVAS_INPAINT_GRAPH, @@ -26,6 +24,7 @@ import { TEXT_TO_IMAGE_GRAPH, VAE_LOADER, } from './constants'; +import { upsertMetadata } from './metadata'; export const addVAEToGraph = ( state: RootState, @@ -41,9 +40,6 @@ export const addVAEToGraph = ( ); const isAutoVae = !vae; - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; if (!isAutoVae) { graph.nodes[VAE_LOADER] = { @@ -181,7 +177,7 @@ export const addVAEToGraph = ( } } - if (vae && metadataAccumulator) { - metadataAccumulator.vae = vae; + if (vae) { + upsertMetadata(graph, { vae }); } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addWatermarkerToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addWatermarkerToGraph.ts index 4e515906b6..c43437e4fc 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addWatermarkerToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addWatermarkerToGraph.ts @@ -5,14 +5,8 @@ import { ImageNSFWBlurInvocation, ImageWatermarkInvocation, LatentsToImageInvocation, - MetadataAccumulatorInvocation, } from 'services/api/types'; -import { - LATENTS_TO_IMAGE, - METADATA_ACCUMULATOR, - NSFW_CHECKER, - WATERMARKER, -} from './constants'; +import { LATENTS_TO_IMAGE, NSFW_CHECKER, WATERMARKER } from './constants'; export const addWatermarkerToGraph = ( state: RootState, @@ -32,10 +26,6 @@ export const addWatermarkerToGraph = ( | ImageNSFWBlurInvocation | undefined; - const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as - | MetadataAccumulatorInvocation - | undefined; - if (!nodeToAddTo) { // something has gone terribly awry return; @@ -80,17 +70,4 @@ export const addWatermarkerToGraph = ( }, }); } - - if (metadataAccumulator) { - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: WATERMARKER, - field: 'metadata', - }, - }); - } }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts index c612e88598..46e415a886 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts @@ -1,12 +1,13 @@ +import { BoardId } from 'features/gallery/store/types'; import { NonNullableGraph } from 'features/nodes/types/types'; import { ESRGANModelName } from 'features/parameters/store/postprocessingSlice'; import { - Graph, ESRGANInvocation, + Graph, SaveImageInvocation, } from 'services/api/types'; import { REALESRGAN as ESRGAN, SAVE_IMAGE } from './constants'; -import { BoardId } from 'features/gallery/store/types'; +import { addCoreMetadataNode } from './metadata'; type Arg = { image_name: string; @@ -55,5 +56,9 @@ export const buildAdHocUpscaleGraph = ({ ], }; + addCoreMetadataNode(graph, { + esrgan_model: esrganModelName, + }); + return graph; }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index 59bdf669e6..9d957c3a4a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -20,12 +20,12 @@ import { IMG2IMG_RESIZE, LATENTS_TO_IMAGE, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Canvas tab's Image to Image graph. @@ -308,10 +308,7 @@ export const buildCanvasImageToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'img2img', cfg_scale, width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width, @@ -325,15 +322,10 @@ export const buildCanvasImageToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], clip_skip: clipSkip, strength, init_image: initialImage.image_name, - }; + }); // Add Seamless To Graph if (seamlessXAxis || seamlessYAxis) { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index b9c0c9eff3..c1ecde5395 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -16,7 +16,6 @@ import { IMAGE_TO_LATENTS, IMG2IMG_RESIZE, LATENTS_TO_IMAGE, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, @@ -28,6 +27,7 @@ import { } from './constants'; import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt'; import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Canvas tab's Image to Image graph. @@ -319,10 +319,7 @@ export const buildCanvasSDXLImageToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'img2img', cfg_scale, width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width, @@ -336,24 +333,8 @@ export const buildCanvasSDXLImageToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], strength, init_image: initialImage.image_name, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index df636669dc..e43891eba4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -18,7 +18,6 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { CANVAS_OUTPUT, LATENTS_TO_IMAGE, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, ONNX_MODEL_LOADER, @@ -30,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Canvas tab's Text to Image graph. @@ -301,10 +301,7 @@ export const buildCanvasSDXLTextToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'txt2img', cfg_scale, width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width, @@ -318,22 +315,6 @@ export const buildCanvasSDXLTextToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts index 38f11f14ac..6e48c14086 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts @@ -21,13 +21,13 @@ import { DENOISE_LATENTS, LATENTS_TO_IMAGE, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, ONNX_MODEL_LOADER, POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Canvas tab's Text to Image graph. @@ -289,10 +289,7 @@ export const buildCanvasTextToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'txt2img', cfg_scale, width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width, @@ -306,23 +303,7 @@ export const buildCanvasTextToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], clip_skip: clipSkip, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts index 9c25ee3b8f..313826452c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts @@ -7,10 +7,12 @@ import { components } from 'services/api/schema'; import { Batch, BatchConfig } from 'services/api/types'; import { CANVAS_COHERENCE_NOISE, + METADATA, METADATA_ACCUMULATOR, NOISE, POSITIVE_CONDITIONING, } from './constants'; +import { removeMetadata } from './metadata'; export const prepareLinearUIBatch = ( state: RootState, @@ -24,7 +26,6 @@ export const prepareLinearUIBatch = ( const data: Batch['data'] = []; if (prompts.length === 1) { - unset(graph.nodes[METADATA_ACCUMULATOR], 'seed'); const seeds = generateSeeds({ count: iterations, start: shouldRandomizeSeed ? undefined : seed, @@ -40,13 +41,13 @@ export const prepareLinearUIBatch = ( }); } - if (graph.nodes[METADATA_ACCUMULATOR]) { - zipped.push({ - node_path: METADATA_ACCUMULATOR, - field_name: 'seed', - items: seeds, - }); - } + // add to metadata + removeMetadata(graph, 'seed'); + zipped.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); if (graph.nodes[CANVAS_COHERENCE_NOISE]) { zipped.push({ @@ -77,13 +78,13 @@ export const prepareLinearUIBatch = ( }); } - if (graph.nodes[METADATA_ACCUMULATOR]) { - firstBatchDatumList.push({ - node_path: METADATA_ACCUMULATOR, - field_name: 'seed', - items: seeds, - }); - } + // add to metadata + removeMetadata(graph, 'seed'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); if (graph.nodes[CANVAS_COHERENCE_NOISE]) { firstBatchDatumList.push({ @@ -106,13 +107,15 @@ export const prepareLinearUIBatch = ( items: seeds, }); } - if (graph.nodes[METADATA_ACCUMULATOR]) { - secondBatchDatumList.push({ - node_path: METADATA_ACCUMULATOR, - field_name: 'seed', - items: seeds, - }); - } + + // add to metadata + removeMetadata(graph, 'seed'); + secondBatchDatumList.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); + if (graph.nodes[CANVAS_COHERENCE_NOISE]) { secondBatchDatumList.push({ node_path: CANVAS_COHERENCE_NOISE, @@ -137,13 +140,13 @@ export const prepareLinearUIBatch = ( }); } - if (graph.nodes[METADATA_ACCUMULATOR]) { - firstBatchDatumList.push({ - node_path: METADATA_ACCUMULATOR, - field_name: 'positive_prompt', - items: extendedPrompts, - }); - } + // add to metadata + removeMetadata(graph, 'positive_prompt'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'positive_prompt', + items: extendedPrompts, + }); if (shouldConcatSDXLStylePrompt && model?.base_model === 'sdxl') { unset(graph.nodes[METADATA_ACCUMULATOR], 'positive_style_prompt'); @@ -160,13 +163,13 @@ export const prepareLinearUIBatch = ( }); } - if (graph.nodes[METADATA_ACCUMULATOR]) { - firstBatchDatumList.push({ - node_path: METADATA_ACCUMULATOR, - field_name: 'positive_style_prompt', - items: stylePrompts, - }); - } + // add to metadata + removeMetadata(graph, 'positive_style_prompt'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'positive_style_prompt', + items: extendedPrompts, + }); } data.push(firstBatchDatumList); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index 0eeba988f2..3b13c746c9 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -21,13 +21,13 @@ import { IMAGE_TO_LATENTS, LATENTS_TO_IMAGE, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, RESIZE, SEAMLESS, } from './constants'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Image to Image tab graph. @@ -311,10 +311,7 @@ export const buildLinearImageToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'img2img', cfg_scale, height, @@ -326,25 +323,9 @@ export const buildLinearImageToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], // populated in addT2IAdapterToLinearGraph clip_skip: clipSkip, strength, init_image: initialImage.imageName, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: LATENTS_TO_IMAGE, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index f818768fb5..54f8e05d21 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -18,7 +18,6 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { IMAGE_TO_LATENTS, LATENTS_TO_IMAGE, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, @@ -30,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt'; +import { addCoreMetadataNode } from './metadata'; /** * Builds the Image to Image tab graph. @@ -331,10 +331,7 @@ export const buildLinearSDXLImageToImageGraph = ( }); } - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'sdxl_img2img', cfg_scale, height, @@ -346,26 +343,10 @@ export const buildLinearSDXLImageToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, - controlnets: [], - loras: [], - ipAdapters: [], - t2iAdapters: [], - strength: strength, + strength, init_image: initialImage.imageName, positive_style_prompt: positiveStylePrompt, negative_style_prompt: negativeStylePrompt, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: LATENTS_TO_IMAGE, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index 4cb90678c3..37fbbf7f43 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -11,9 +11,9 @@ import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; +import { addCoreMetadataNode } from './metadata'; import { LATENTS_TO_IMAGE, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, @@ -225,10 +225,7 @@ export const buildLinearSDXLTextToImageGraph = ( ], }; - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'sdxl_txt2img', cfg_scale, height, @@ -240,24 +237,8 @@ export const buildLinearSDXLTextToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, - controlnets: [], - loras: [], - ipAdapters: [], - t2iAdapters: [], positive_style_prompt: positiveStylePrompt, negative_style_prompt: negativeStylePrompt, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: LATENTS_TO_IMAGE, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts index e692e12fa4..8e0143f180 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -15,12 +15,12 @@ import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; +import { addCoreMetadataNode } from './metadata'; import { CLIP_SKIP, DENOISE_LATENTS, LATENTS_TO_IMAGE, MAIN_MODEL_LOADER, - METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, NOISE, ONNX_MODEL_LOADER, @@ -48,10 +48,6 @@ export const buildLinearTextToImageGraph = ( seamlessXAxis, seamlessYAxis, seed, - hrfWidth, - hrfHeight, - hrfStrength, - hrfEnabled: hrfEnabled, } = state.generation; const use_cpu = shouldUseCpuNoise; @@ -238,10 +234,7 @@ export const buildLinearTextToImageGraph = ( ], }; - // add metadata accumulator, which is only mostly populated - some fields are added later - graph.nodes[METADATA_ACCUMULATOR] = { - id: METADATA_ACCUMULATOR, - type: 'metadata_accumulator', + addCoreMetadataNode(graph, { generation_mode: 'txt2img', cfg_scale, height, @@ -253,26 +246,7 @@ export const buildLinearTextToImageGraph = ( steps, rand_device: use_cpu ? 'cpu' : 'cuda', scheduler, - vae: undefined, // option; set in addVAEToGraph - controlnets: [], // populated in addControlNetToLinearGraph - loras: [], // populated in addLoRAsToGraph - ipAdapters: [], // populated in addIPAdapterToLinearGraph - t2iAdapters: [], // populated in addT2IAdapterToLinearGraph clip_skip: clipSkip, - hrf_width: hrfEnabled ? hrfWidth : undefined, - hrf_height: hrfEnabled ? hrfHeight : undefined, - hrf_strength: hrfEnabled ? hrfStrength : undefined, - }; - - graph.edges.push({ - source: { - node_id: METADATA_ACCUMULATOR, - field: 'metadata', - }, - destination: { - node_id: LATENTS_TO_IMAGE, - field: 'metadata', - }, }); // Add Seamless To Graph diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts index 7be06ac110..4437e14f66 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts @@ -35,7 +35,7 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => { const { nodes, edges } = nodesState; const filteredNodes = nodes.filter(isInvocationNode); - const workflowJSON = JSON.stringify(buildWorkflow(nodesState)); + // const workflowJSON = JSON.stringify(buildWorkflow(nodesState)); // Reduce the node editor nodes into invocation graph nodes const parsedNodes = filteredNodes.reduce>( @@ -68,7 +68,8 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => { if (embedWorkflow) { // add the workflow to the node - Object.assign(graphNode, { workflow: workflowJSON }); + // Object.assign(graphNode, { workflow: workflowJSON }); + Object.assign(graphNode, { workflow: buildWorkflow(nodesState) }); } // Add it to the nodes object diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts index 7d547d09e6..e0dc52063b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts @@ -56,7 +56,15 @@ export const IP_ADAPTER = 'ip_adapter'; export const DYNAMIC_PROMPT = 'dynamic_prompt'; export const IMAGE_COLLECTION = 'image_collection'; export const IMAGE_COLLECTION_ITERATE = 'image_collection_iterate'; +export const METADATA = 'core_metadata'; +export const BATCH_METADATA = 'batch_metadata'; +export const BATCH_METADATA_COLLECT = 'batch_metadata_collect'; +export const BATCH_SEED = 'batch_seed'; +export const BATCH_PROMPT = 'batch_prompt'; +export const BATCH_STYLE_PROMPT = 'batch_style_prompt'; +export const METADATA_COLLECT = 'metadata_collect'; export const METADATA_ACCUMULATOR = 'metadata_accumulator'; +export const MERGE_METADATA = 'merge_metadata'; export const REALESRGAN = 'esrgan'; export const DIVIDE = 'divide'; export const SCALE = 'scale_image'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts new file mode 100644 index 0000000000..547c45addf --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts @@ -0,0 +1,58 @@ +import { NonNullableGraph } from 'features/nodes/types/types'; +import { CoreMetadataInvocation } from 'services/api/types'; +import { JsonObject } from 'type-fest'; +import { METADATA, SAVE_IMAGE } from './constants'; + +export const addCoreMetadataNode = ( + graph: NonNullableGraph, + metadata: Partial | JsonObject +): void => { + graph.nodes[METADATA] = { + id: METADATA, + type: 'core_metadata', + ...metadata, + }; + + graph.edges.push({ + source: { + node_id: METADATA, + field: 'metadata', + }, + destination: { + node_id: SAVE_IMAGE, + field: 'metadata', + }, + }); + + return; +}; + +export const upsertMetadata = ( + graph: NonNullableGraph, + metadata: Partial | JsonObject +): void => { + const metadataNode = graph.nodes[METADATA] as + | CoreMetadataInvocation + | undefined; + + if (!metadataNode) { + return; + } + + Object.assign(metadataNode, metadata); +}; + +export const removeMetadata = ( + graph: NonNullableGraph, + key: keyof CoreMetadataInvocation +): void => { + const metadataNode = graph.nodes[METADATA] as + | CoreMetadataInvocation + | undefined; + + if (!metadataNode) { + return; + } + + delete metadataNode[key]; +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index 93cd75dd75..7c6f4e638f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -4,7 +4,6 @@ import { reduce, startCase } from 'lodash-es'; import { OpenAPIV3_1 } from 'openapi-types'; import { AnyInvocationType } from 'services/events/types'; import { - FieldType, InputFieldTemplate, InvocationSchemaObject, InvocationTemplate, @@ -16,18 +15,11 @@ import { } from '../types/types'; import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders'; -const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata', 'use_cache']; +const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'use_cache']; const RESERVED_OUTPUT_FIELD_NAMES = ['type']; -const RESERVED_FIELD_TYPES = [ - 'WorkflowField', - 'MetadataField', - 'IsIntermediate', -]; +const RESERVED_FIELD_TYPES = ['IsIntermediate']; -const invocationDenylist: AnyInvocationType[] = [ - 'graph', - 'metadata_accumulator', -]; +const invocationDenylist: AnyInvocationType[] = ['graph']; const isReservedInputField = (nodeType: string, fieldName: string) => { if (RESERVED_INPUT_FIELD_NAMES.includes(fieldName)) { @@ -42,7 +34,7 @@ const isReservedInputField = (nodeType: string, fieldName: string) => { return false; }; -const isReservedFieldType = (fieldType: FieldType) => { +const isReservedFieldType = (fieldType: string) => { if (RESERVED_FIELD_TYPES.includes(fieldType)) { return true; } @@ -86,6 +78,7 @@ export const parseSchema = ( const tags = schema.tags ?? []; const description = schema.description ?? ''; const version = schema.version; + let withWorkflow = false; const inputs = reduce( schema.properties, @@ -112,7 +105,7 @@ export const parseSchema = ( const fieldType = property.ui_type ?? getFieldType(property); - if (!isFieldType(fieldType)) { + if (!fieldType) { logger('nodes').warn( { node: type, @@ -120,11 +113,16 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping unknown input field type' + 'Missing input field type' ); return inputsAccumulator; } + if (fieldType === 'WorkflowField') { + withWorkflow = true; + return inputsAccumulator; + } + if (isReservedFieldType(fieldType)) { logger('nodes').trace( { @@ -133,7 +131,20 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping reserved field type' + `Skipping reserved input field type: ${fieldType}` + ); + return inputsAccumulator; + } + + if (!isFieldType(fieldType)) { + logger('nodes').warn( + { + node: type, + fieldName: propertyName, + fieldType, + field: parseify(property), + }, + `Skipping unknown input field type: ${fieldType}` ); return inputsAccumulator; } @@ -146,7 +157,7 @@ export const parseSchema = ( ); if (!field) { - logger('nodes').debug( + logger('nodes').warn( { node: type, fieldName: propertyName, @@ -248,6 +259,7 @@ export const parseSchema = ( inputs, outputs, useCache, + withWorkflow, }; Object.assign(invocationsAccumulator, { [type]: invocation }); diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index c8d42d17f6..36c00ee1c9 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -1,6 +1,7 @@ import { EntityState, Update } from '@reduxjs/toolkit'; import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query'; import { PatchCollection } from '@reduxjs/toolkit/dist/query/core/buildThunks'; +import { logger } from 'app/logging/logger'; import { ASSETS_CATEGORIES, BoardId, @@ -8,6 +9,7 @@ import { IMAGE_LIMIT, } from 'features/gallery/store/types'; import { + CoreMetadata, ImageMetadataAndWorkflow, zCoreMetadata, } from 'features/nodes/types/types'; @@ -23,7 +25,6 @@ import { ListImagesArgs, OffsetPaginatedResults_ImageDTO_, PostUploadAction, - UnsafeImageMetadata, } from '../types'; import { getCategories, @@ -114,11 +115,24 @@ export const imagesApi = api.injectEndpoints({ ], keepUnusedDataFor: 86400, // 24 hours }), - getImageMetadata: build.query({ + getImageMetadata: build.query({ query: (image_name) => ({ url: `images/i/${image_name}/metadata` }), providesTags: (result, error, image_name) => [ { type: 'ImageMetadata', id: image_name }, ], + transformResponse: ( + response: paths['/api/v1/images/i/{image_name}/metadata']['get']['responses']['200']['content']['application/json'] + ) => { + if (response) { + const result = zCoreMetadata.safeParse(response); + if (result.success) { + return result.data; + } else { + logger('images').warn('Problem parsing metadata'); + } + } + return; + }, keepUnusedDataFor: 86400, // 24 hours }), getImageMetadataFromFile: build.query< diff --git a/invokeai/frontend/web/src/services/api/endpoints/workflows.ts b/invokeai/frontend/web/src/services/api/endpoints/workflows.ts new file mode 100644 index 0000000000..4c69d2e286 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/endpoints/workflows.ts @@ -0,0 +1,31 @@ +import { logger } from 'app/logging/logger'; +import { Workflow, zWorkflow } from 'features/nodes/types/types'; +import { api } from '..'; +import { paths } from '../schema'; + +export const workflowsApi = api.injectEndpoints({ + endpoints: (build) => ({ + getWorkflow: build.query({ + query: (workflow_id) => `workflows/i/${workflow_id}`, + keepUnusedDataFor: 86400, // 24 hours + providesTags: (result, error, workflow_id) => [ + { type: 'Workflow', id: workflow_id }, + ], + transformResponse: ( + response: paths['/api/v1/workflows/i/{workflow_id}']['get']['responses']['200']['content']['application/json'] + ) => { + if (response) { + const result = zWorkflow.safeParse(response); + if (result.success) { + return result.data; + } else { + logger('images').warn('Problem parsing metadata'); + } + } + return; + }, + }), + }), +}); + +export const { useGetWorkflowQuery } = workflowsApi; diff --git a/invokeai/frontend/web/src/services/api/index.ts b/invokeai/frontend/web/src/services/api/index.ts index f423b2b0ed..b7595b3d52 100644 --- a/invokeai/frontend/web/src/services/api/index.ts +++ b/invokeai/frontend/web/src/services/api/index.ts @@ -37,6 +37,7 @@ export const tagTypes = [ 'ControlNetModel', 'LoRAModel', 'SDXLRefinerModel', + 'Workflow', ] as const; export type ApiTagDescription = TagDescription<(typeof tagTypes)[number]>; export const LIST_TAG = 'LIST'; diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 62f60c1dbc..932891c862 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -378,6 +378,13 @@ export type paths = { */ put: operations["cancel_queue_item"]; }; + "/api/v1/workflows/i/{workflow_id}": { + /** + * Get Workflow + * @description Gets a workflow + */ + get: operations["get_workflow"]; + }; }; export type webhooks = Record; @@ -413,17 +420,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * A * @description The first number @@ -572,6 +574,10 @@ export type components = { * @description Creates a blank image and forwards it to the pipeline */ BlankImageInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -583,17 +589,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Width * @description The width of the image @@ -646,17 +647,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Latents tensor */ latents_a?: components["schemas"]["LatentsField"]; /** @description Latents tensor */ @@ -899,17 +895,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of boolean values @@ -955,17 +946,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The boolean value @@ -1033,6 +1019,10 @@ export type components = { * @description Infills transparent areas of an image using OpenCV Inpainting */ CV2InfillInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -1044,17 +1034,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** @@ -1080,6 +1065,10 @@ export type components = { * @description Canny edge detection for ControlNet */ CannyImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -1091,17 +1080,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -1167,17 +1151,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count @@ -1229,17 +1208,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection Item * @description The item to collect (all inputs must be of the same type) @@ -1294,6 +1268,10 @@ export type components = { * using a mask to only color-correct certain regions of the target image. */ ColorCorrectInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -1305,17 +1283,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to color-correct */ image?: components["schemas"]["ImageField"]; /** @description Reference image for color-correction */ @@ -1377,17 +1350,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * @description The color value * @default { @@ -1410,6 +1378,10 @@ export type components = { * @description Generates a color map from the provided image */ ColorMapImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -1421,17 +1393,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -1477,17 +1444,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Prompt * @description Prompt to be parsed by Compel to create a conditioning tensor @@ -1522,17 +1484,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of conditioning tensors @@ -1589,17 +1546,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Conditioning tensor */ conditioning?: components["schemas"]["ConditioningField"]; /** @@ -1628,6 +1580,10 @@ export type components = { * @description Applies content shuffle processing to image */ ContentShuffleImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -1639,17 +1595,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -1744,17 +1695,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The control image */ image?: components["schemas"]["ImageField"]; /** @description ControlNet model to load */ @@ -1872,26 +1818,33 @@ export type components = { type: "control_output"; }; /** - * CoreMetadata - * @description Core generation metadata for an image generated in InvokeAI. + * Core Metadata + * @description Collects core generation metadata into a MetadataField */ - CoreMetadata: { + CoreMetadataInvocation: { /** - * App Version - * @description The version of InvokeAI used to generate this image - * @default 3.3.0 + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. */ - app_version?: string; + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean | null; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; /** * Generation Mode * @description The generation mode that output this image + * @enum {string} */ - generation_mode?: string | null; - /** - * Created By - * @description The name of the creator of the image - */ - created_by?: string | null; + generation_mode?: "txt2img" | "img2img" | "inpaint" | "outpaint"; /** * Positive Prompt * @description The positive prompt parameter @@ -1937,6 +1890,16 @@ export type components = { * @description The scheduler used for inference */ scheduler?: string | null; + /** + * Seamless X + * @description Whether seamless tiling was used on the X axis + */ + seamless_x?: boolean | null; + /** + * Seamless Y + * @description Whether seamless tiling was used on the Y axis + */ + seamless_y?: boolean | null; /** * Clip Skip * @description The number of skipped CLIP layers @@ -1964,8 +1927,6 @@ export type components = { * @description The LoRAs used for inference */ loras?: components["schemas"]["LoRAMetadataField"][] | null; - /** @description The VAE used for decoding, if the main model's default was not used */ - vae?: components["schemas"]["VAEModelField"] | null; /** * Strength * @description The strength used for latents-to-latents @@ -1976,6 +1937,23 @@ export type components = { * @description The name of the initial image */ init_image?: string | null; + /** @description The VAE used for decoding, if the main model's default was not used */ + vae?: components["schemas"]["VAEModelField"] | null; + /** + * Hrf Width + * @description The high resolution fix height and width multipler. + */ + hrf_width?: number | null; + /** + * Hrf Height + * @description The high resolution fix height and width multipler. + */ + hrf_height?: number | null; + /** + * Hrf Strength + * @description The high resolution fix img2img strength used in the upscale pass. + */ + hrf_strength?: number | null; /** * Positive Style Prompt * @description The positive style prompt parameter @@ -2018,6 +1996,13 @@ export type components = { * @description The start value used for refiner denoising */ refiner_start?: number | null; + /** + * type + * @default core_metadata + * @constant + */ + type: "core_metadata"; + [key: string]: unknown; }; /** * Create Denoise Mask @@ -2035,17 +2020,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description VAE */ vae?: components["schemas"]["VaeField"]; /** @description Image which will be masked */ @@ -2094,6 +2074,10 @@ export type components = { * @description Simple inpaint using opencv. */ CvInpaintInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -2105,17 +2089,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to inpaint */ image?: components["schemas"]["ImageField"]; /** @description The mask to use when inpainting */ @@ -2166,17 +2145,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Positive conditioning tensor */ positive_conditioning?: components["schemas"]["ConditioningField"]; /** @description Negative conditioning tensor */ @@ -2288,17 +2262,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * A * @description The first number @@ -2334,17 +2303,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default false + * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Prompt * @description The prompt to parse with dynamicprompts @@ -2381,6 +2345,10 @@ export type components = { * @description Upscales an image using RealESRGAN. */ ESRGANInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -2392,17 +2360,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The input image */ image?: components["schemas"]["ImageField"]; /** @@ -2475,6 +2438,10 @@ export type components = { * @description Outputs an image with detected face IDs printed on each face. For use with other FaceTools. */ FaceIdentifierInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -2486,17 +2453,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Image to face detect */ image?: components["schemas"]["ImageField"]; /** @@ -2523,6 +2485,10 @@ export type components = { * @description Face mask creation using mediapipe face detection */ FaceMaskInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -2534,17 +2500,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Image to face detect */ image?: components["schemas"]["ImageField"]; /** @@ -2621,6 +2582,10 @@ export type components = { * @description Bound, extract, and mask a face from an image using MediaPipe detection */ FaceOffInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -2632,17 +2597,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Image for face detection */ image?: components["schemas"]["ImageField"]; /** @@ -2740,17 +2700,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of float values @@ -2796,17 +2751,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The float value @@ -2836,17 +2786,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Start * @description The first value of the range @@ -2888,17 +2833,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Operation * @description The operation to perform @@ -2958,17 +2898,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The value to round @@ -3007,7 +2942,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlendLatentsInvocation"]; + [key: string]: components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["GraphInvocation"]; }; /** * Edges @@ -3044,7 +2979,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["IntegerOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["String2Output"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ClipSkipInvocationOutput"]; + [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["String2Output"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["LatentsOutput"]; }; /** * Errors @@ -3084,17 +3019,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The graph to run */ graph?: components["schemas"]["Graph"]; /** @@ -3123,6 +3053,10 @@ export type components = { * @description Applies HED edge detection to image */ HedImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3134,17 +3068,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -3218,17 +3147,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Image * @description The IP-Adapter image prompt(s). @@ -3264,17 +3188,21 @@ export type components = { */ type: "ip_adapter"; }; - /** IPAdapterMetadataField */ + /** + * IPAdapterMetadataField + * @description IP Adapter Field, minus the CLIP Vision Encoder model + */ IPAdapterMetadataField: { /** @description The IP-Adapter image prompt. */ image: components["schemas"]["ImageField"]; - /** @description The IP-Adapter model to use. */ + /** @description The IP-Adapter model. */ ip_adapter_model: components["schemas"]["IPAdapterModelField"]; /** * Weight - * @description The weight of the IP-Adapter model + * @description The weight given to the IP-Adapter + * @default 1 */ - weight: number; + weight?: number | number[]; /** * Begin Step Percent * @description When the IP-Adapter is first applied (% of total steps) @@ -3339,6 +3267,10 @@ export type components = { * @description Blurs an image */ ImageBlurInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3350,17 +3282,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to blur */ image?: components["schemas"]["ImageField"]; /** @@ -3400,6 +3327,10 @@ export type components = { * @description Gets a channel from an image. */ ImageChannelInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3411,17 +3342,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to get the channel from */ image?: components["schemas"]["ImageField"]; /** @@ -3443,6 +3369,10 @@ export type components = { * @description Scale a specific color channel of an image. */ ImageChannelMultiplyInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3454,17 +3384,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** @@ -3497,6 +3422,10 @@ export type components = { * @description Add or subtract a value from a specific color channel of an image. */ ImageChannelOffsetInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3508,17 +3437,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** @@ -3556,17 +3480,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of image values @@ -3601,6 +3520,10 @@ export type components = { * @description Converts an image to a different mode. */ ImageConvertInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3612,17 +3535,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to convert */ image?: components["schemas"]["ImageField"]; /** @@ -3644,6 +3562,10 @@ export type components = { * @description Crops an image to a specified box. The box can be outside of the image. */ ImageCropInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3655,17 +3577,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to crop */ image?: components["schemas"]["ImageField"]; /** @@ -3758,6 +3675,11 @@ export type components = { * @description The session ID that generated this image, if it is a generated image. */ session_id?: string | null; + /** + * Workflow Id + * @description The workflow that generated this image. + */ + workflow_id?: string | null; /** * Node Id * @description The node ID that generated this image, if it is a generated image. @@ -3790,6 +3712,10 @@ export type components = { * @description Adjusts the Hue of an image. */ ImageHueAdjustmentInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3801,17 +3727,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** @@ -3832,6 +3753,10 @@ export type components = { * @description Inverse linear interpolation of all pixels of an image */ ImageInverseLerpInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3843,17 +3768,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** @@ -3891,17 +3811,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to load */ image?: components["schemas"]["ImageField"]; /** @@ -3916,6 +3831,10 @@ export type components = { * @description Linear interpolation of all pixels of an image */ ImageLerpInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3927,17 +3846,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** @@ -3959,27 +3873,15 @@ export type components = { */ type: "img_lerp"; }; - /** - * ImageMetadata - * @description An image's generation metadata - */ - ImageMetadata: { - /** - * Metadata - * @description The image's core metadata, if it was created in the Linear or Canvas UI - */ - metadata?: Record | null; - /** - * Graph - * @description The graph that created the image - */ - graph?: Record | null; - }; /** * Multiply Images * @description Multiplies two images together using `PIL.ImageChops.multiply()`. */ ImageMultiplyInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -3991,17 +3893,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The first image to multiply */ image1?: components["schemas"]["ImageField"]; /** @description The second image to multiply */ @@ -4018,6 +3915,10 @@ export type components = { * @description Add blur to NSFW-flagged images */ ImageNSFWBlurInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4029,21 +3930,14 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to check */ image?: components["schemas"]["ImageField"]; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; /** * type * @default img_nsfw @@ -4080,6 +3974,10 @@ export type components = { * @description Pastes an image into another image. */ ImagePasteInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4091,17 +3989,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The base image */ base_image?: components["schemas"]["ImageField"]; /** @description The image to paste */ @@ -4168,6 +4061,10 @@ export type components = { * @description Resizes an image to specific dimensions */ ImageResizeInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4179,17 +4076,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to resize */ image?: components["schemas"]["ImageField"]; /** @@ -4211,8 +4103,6 @@ export type components = { * @enum {string} */ resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos"; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; /** * type * @default img_resize @@ -4225,6 +4115,10 @@ export type components = { * @description Scales an image by a factor */ ImageScaleInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4236,17 +4130,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to scale */ image?: components["schemas"]["ImageField"]; /** @@ -4285,17 +4174,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to encode */ image?: components["schemas"]["ImageField"]; /** @description VAE */ @@ -4345,6 +4229,10 @@ export type components = { * @description Add an invisible watermark to an image */ ImageWatermarkInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4356,17 +4244,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to check */ image?: components["schemas"]["ImageField"]; /** @@ -4375,8 +4258,6 @@ export type components = { * @default InvokeAI */ text?: string; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; /** * type * @default img_watermark @@ -4405,6 +4286,10 @@ export type components = { * @description Infills transparent areas of an image with a solid color */ InfillColorInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4416,17 +4301,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** @@ -4451,6 +4331,10 @@ export type components = { * @description Infills transparent areas of an image using the PatchMatch algorithm */ InfillPatchMatchInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4462,17 +4346,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** @@ -4500,6 +4379,10 @@ export type components = { * @description Infills transparent areas of an image with tiles of the image */ InfillTileInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4511,17 +4394,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** @@ -4558,17 +4436,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of integer values @@ -4614,17 +4487,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The integer value @@ -4654,17 +4522,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Operation * @description The operation to perform @@ -4752,17 +4615,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The list of items to iterate over @@ -4803,6 +4661,10 @@ export type components = { * @description Infills transparent areas of an image using the LaMa model */ LaMaInfillInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4814,17 +4676,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** @@ -4850,17 +4707,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of latents tensors @@ -4922,17 +4774,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The latents tensor */ latents?: components["schemas"]["LatentsField"]; /** @@ -4971,6 +4818,10 @@ export type components = { * @description Generates an image from latents. */ LatentsToImageInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -4982,17 +4833,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** @description VAE */ @@ -5009,8 +4855,6 @@ export type components = { * @default false */ fp32?: boolean; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; /** * type * @default l2i @@ -5023,6 +4867,10 @@ export type components = { * @description Applies leres processing to image */ LeresImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5034,17 +4882,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5089,6 +4932,10 @@ export type components = { * @description Applies line art anime processing to image */ LineartAnimeImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5100,17 +4947,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5137,6 +4979,10 @@ export type components = { * @description Applies line art processing to image */ LineartImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5148,17 +4994,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5188,14 +5029,14 @@ export type components = { }; /** * LoRAMetadataField - * @description LoRA metadata for an image generated in InvokeAI. + * @description LoRA Metadata Field */ LoRAMetadataField: { - /** @description The LoRA model */ + /** @description LoRA model to load */ lora: components["schemas"]["LoRAModelField"]; /** * Weight - * @description The weight of the LoRA model + * @description The weight at which the LoRA is applied to each model */ weight: number; }; @@ -5275,17 +5116,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * LoRA * @description LoRA model to load @@ -5367,17 +5203,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["MainModelField"]; /** @@ -5392,6 +5223,10 @@ export type components = { * @description Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`. */ MaskCombineInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5403,17 +5238,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The first mask to combine */ mask1?: components["schemas"]["ImageField"]; /** @description The second image to combine */ @@ -5430,6 +5260,10 @@ export type components = { * @description Applies an edge mask to an image */ MaskEdgeInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5441,17 +5275,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to apply the mask to */ image?: components["schemas"]["ImageField"]; /** @@ -5486,6 +5315,10 @@ export type components = { * @description Extracts the alpha channel of an image as a mask. */ MaskFromAlphaInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5497,17 +5330,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to create the mask from */ image?: components["schemas"]["ImageField"]; /** @@ -5528,6 +5356,10 @@ export type components = { * @description Applies mediapipe face processing to image */ MediapipeFaceProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5539,17 +5371,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5576,6 +5403,40 @@ export type components = { * @enum {string} */ MergeInterpolationMethod: "weighted_sum" | "sigmoid" | "inv_sigmoid" | "add_difference"; + /** + * Metadata Merge + * @description Merged a collection of MetadataDict into a single MetadataDict. + */ + MergeMetadataInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean | null; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** + * Collection + * @description Collection of Metadata + */ + collection?: components["schemas"]["MetadataField"][]; + /** + * type + * @default merge_metadata + * @constant + */ + type: "merge_metadata"; + }; /** MergeModelsBody */ MergeModelsBody: { /** @@ -5609,10 +5470,16 @@ export type components = { merge_dest_directory?: string | null; }; /** - * Metadata Accumulator - * @description Outputs a Core Metadata Object + * MetadataField + * @description Pydantic model for metadata with custom root of type dict[str, Any]. + * Metadata is stored without a strict schema. */ - MetadataAccumulatorInvocation: { + MetadataField: Record; + /** + * Metadata + * @description Takes a MetadataItem or collection of MetadataItems and outputs a MetadataDict. + */ + MetadataInvocation: { /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5625,188 +5492,109 @@ export type components = { */ is_intermediate?: boolean | null; /** - * Workflow - * @description The workflow to save with the image + * Use Cache + * @description Whether or not to use the cache + * @default true */ - workflow?: string | null; + use_cache?: boolean; + /** + * Items + * @description A single metadata item or collection of metadata items + */ + items?: components["schemas"]["MetadataItemField"][] | components["schemas"]["MetadataItemField"]; + /** + * type + * @default metadata + * @constant + */ + type: "metadata"; + }; + /** MetadataItemField */ + MetadataItemField: { + /** + * Label + * @description Label for this metadata item + */ + label: string; + /** + * Value + * @description The value for this metadata item (may be any type) + */ + value: unknown; + }; + /** + * Metadata Item + * @description Used to create an arbitrary metadata item. Provide "label" and make a connection to "value" to store that data as the value. + */ + MetadataItemInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** - * Generation Mode - * @description The generation mode that output this image + * Label + * @description Label for this metadata item */ - generation_mode?: string | null; + label?: string; /** - * Positive Prompt - * @description The positive prompt parameter + * Value + * @description The value for this metadata item (may be any type) */ - positive_prompt?: string | null; - /** - * Negative Prompt - * @description The negative prompt parameter - */ - negative_prompt?: string | null; - /** - * Width - * @description The width parameter - */ - width?: number | null; - /** - * Height - * @description The height parameter - */ - height?: number | null; - /** - * Seed - * @description The seed used for noise generation - */ - seed?: number | null; - /** - * Rand Device - * @description The device used for random number generation - */ - rand_device?: string | null; - /** - * Cfg Scale - * @description The classifier-free guidance scale parameter - */ - cfg_scale?: number | null; - /** - * Steps - * @description The number of steps used for inference - */ - steps?: number | null; - /** - * Scheduler - * @description The scheduler used for inference - */ - scheduler?: string | null; - /** - * Clip Skip - * @description The number of skipped CLIP layers - */ - clip_skip?: number | null; - /** @description The main model used for inference */ - model?: components["schemas"]["MainModelField"] | null; - /** - * Controlnets - * @description The ControlNets used for inference - */ - controlnets?: components["schemas"]["ControlField"][] | null; - /** - * Ipadapters - * @description The IP Adapters used for inference - */ - ipAdapters?: components["schemas"]["IPAdapterMetadataField"][] | null; - /** - * T2Iadapters - * @description The IP Adapters used for inference - */ - t2iAdapters?: components["schemas"]["T2IAdapterField"][] | null; - /** - * Loras - * @description The LoRAs used for inference - */ - loras?: components["schemas"]["LoRAMetadataField"][] | null; - /** - * Strength - * @description The strength used for latents-to-latents - */ - strength?: number | null; - /** - * Init Image - * @description The name of the initial image - */ - init_image?: string | null; - /** @description The VAE used for decoding, if the main model's default was not used */ - vae?: components["schemas"]["VAEModelField"] | null; - /** - * Hrf Width - * @description The high resolution fix height and width multipler. - */ - hrf_width?: number | null; - /** - * Hrf Height - * @description The high resolution fix height and width multipler. - */ - hrf_height?: number | null; - /** - * Hrf Strength - * @description The high resolution fix img2img strength used in the upscale pass. - */ - hrf_strength?: number | null; - /** - * Positive Style Prompt - * @description The positive style prompt parameter - */ - positive_style_prompt?: string | null; - /** - * Negative Style Prompt - * @description The negative style prompt parameter - */ - negative_style_prompt?: string | null; - /** @description The SDXL Refiner model used */ - refiner_model?: components["schemas"]["MainModelField"] | null; - /** - * Refiner Cfg Scale - * @description The classifier-free guidance scale parameter used for the refiner - */ - refiner_cfg_scale?: number | null; - /** - * Refiner Steps - * @description The number of steps used for the refiner - */ - refiner_steps?: number | null; - /** - * Refiner Scheduler - * @description The scheduler used for the refiner - */ - refiner_scheduler?: string | null; - /** - * Refiner Positive Aesthetic Score - * @description The aesthetic score used for the refiner - */ - refiner_positive_aesthetic_score?: number | null; - /** - * Refiner Negative Aesthetic Score - * @description The aesthetic score used for the refiner - */ - refiner_negative_aesthetic_score?: number | null; - /** - * Refiner Start - * @description The start value used for refiner denoising - */ - refiner_start?: number | null; + value?: unknown; /** * type - * @default metadata_accumulator + * @default metadata_item * @constant */ - type: "metadata_accumulator"; + type: "metadata_item"; }; /** - * MetadataAccumulatorOutput - * @description The output of the MetadataAccumulator node + * MetadataItemOutput + * @description Metadata Item Output */ - MetadataAccumulatorOutput: { - /** @description The core metadata for the image */ - metadata: components["schemas"]["CoreMetadata"]; + MetadataItemOutput: { + /** @description Metadata Item */ + item: components["schemas"]["MetadataItemField"]; /** * type - * @default metadata_accumulator_output + * @default metadata_item_output * @constant */ - type: "metadata_accumulator_output"; + type: "metadata_item_output"; + }; + /** MetadataOutput */ + MetadataOutput: { + /** @description Metadata Dict */ + metadata: components["schemas"]["MetadataField"]; + /** + * type + * @default metadata_output + * @constant + */ + type: "metadata_output"; }; /** * Midas Depth Processor * @description Applies Midas depth processing to image */ MidasDepthImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5818,17 +5606,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5855,6 +5638,10 @@ export type components = { * @description Applies MLSD processing to image */ MlsdImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -5866,17 +5653,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -5987,17 +5769,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * A * @description The first number @@ -6051,17 +5828,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Seed * @description Seed for random number generation @@ -6121,6 +5893,10 @@ export type components = { * @description Applies NormalBae processing to image */ NormalbaeImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -6132,17 +5908,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -6169,6 +5940,10 @@ export type components = { * @description Generates an image from latents. */ ONNXLatentsToImageInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -6180,23 +5955,16 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Denoised latents tensor */ latents?: components["schemas"]["LatentsField"]; /** @description VAE */ vae?: components["schemas"]["VaeField"]; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; /** * type * @default l2i_onnx @@ -6249,17 +6017,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Prompt * @description Raw prompt text (no parsing) @@ -6340,17 +6103,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Positive conditioning tensor */ positive_conditioning?: components["schemas"]["ConditioningField"]; /** @description Negative conditioning tensor */ @@ -6474,17 +6232,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description ONNX Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["OnnxModelField"]; /** @@ -6499,6 +6252,10 @@ export type components = { * @description Applies Openpose processing to image */ OpenposeImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -6510,17 +6267,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -6553,6 +6305,10 @@ export type components = { * @description Applies PIDI processing to image */ PidiImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -6564,17 +6320,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -6624,17 +6375,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * File Path * @description Path to prompt text file @@ -6696,17 +6442,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default false + * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Low * @description The inclusive low value @@ -6748,17 +6489,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default false + * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Low * @description The inclusive low value @@ -6794,17 +6530,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default false + * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Low * @description The inclusive low value @@ -6851,17 +6582,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Start * @description The start of the range @@ -6903,17 +6629,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Start * @description The start of the range @@ -6963,17 +6684,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** @@ -7032,17 +6748,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The float value @@ -7078,17 +6789,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Prompt * @description Prompt to be parsed by Compel to create a conditioning tensor @@ -7164,17 +6870,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * LoRA * @description LoRA model to load @@ -7251,17 +6952,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load */ model: components["schemas"]["MainModelField"]; /** @@ -7319,17 +7015,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Style * @description Prompt to be parsed by Compel to create a conditioning tensor @@ -7387,17 +7078,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load */ model: components["schemas"]["MainModelField"]; /** @@ -7439,6 +7125,10 @@ export type components = { * @description Saves an image. Unlike an image primitive, this invocation stores a copy of the image. */ SaveImageInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -7450,23 +7140,16 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default false + * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @description The board to save the image to */ - board?: components["schemas"]["BoardField"] | null; - /** @description Optional core metadata to be written to image */ - metadata?: components["schemas"]["CoreMetadata"] | null; + board?: components["schemas"]["BoardField"]; /** * type * @default save_image @@ -7490,17 +7173,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** @@ -7544,17 +7222,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Scheduler * @description Scheduler to use during inference @@ -7605,17 +7278,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * UNet * @description UNet (scheduler, LoRAs) @@ -7672,6 +7340,10 @@ export type components = { * @description Applies segment anything processing to image */ SegmentAnythingProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -7683,17 +7355,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -7927,17 +7594,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to show */ image?: components["schemas"]["ImageField"]; /** @@ -8119,17 +7781,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Easing * @description The easing function to use @@ -8234,17 +7891,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Collection * @description The collection of string values @@ -8290,17 +7942,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * Value * @description The string value @@ -8330,17 +7977,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * String Left * @description String Left @@ -8376,17 +8018,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * String Left * @description String Left @@ -8467,17 +8104,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * String * @description String to work on @@ -8525,17 +8157,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * String * @description String to split @@ -8571,17 +8198,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * String * @description String to split @@ -8616,17 +8238,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * A * @description The first number @@ -8694,17 +8311,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The IP-Adapter image prompt. */ image?: components["schemas"]["ImageField"]; /** @@ -8814,6 +8426,10 @@ export type components = { * @description Tile resampler processor */ TileResamplerProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -8825,17 +8441,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -8920,17 +8531,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** * VAE * @description VAE model to load @@ -8992,11 +8598,21 @@ export type components = { /** Error Type */ type: string; }; + /** + * WorkflowField + * @description Pydantic model for workflows with custom root of type dict[str, Any]. + * Workflows are stored without a strict schema. + */ + WorkflowField: Record; /** * Zoe (Depth) Processor * @description Applies Zoe depth processing to image */ ZoeDepthImageProcessorInvocation: { + /** @description Optional workflow to be saved with the image */ + workflow?: components["schemas"]["WorkflowField"] | null; + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; /** * Id * @description The id of this instance of an invocation. Must be unique among all instances of invocations. @@ -9008,17 +8624,12 @@ export type components = { * @default false */ is_intermediate?: boolean | null; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean | null; + use_cache?: boolean; /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** @@ -9079,7 +8690,7 @@ export type components = { * If a field should be provided a data type that does not exactly match the python type of the field, use this to provide the type that should be used instead. See the node development docs for detail on adding a new field type, which involves client-side changes. * @enum {string} */ - UIType: "boolean" | "ColorField" | "ConditioningField" | "ControlField" | "float" | "ImageField" | "integer" | "LatentsField" | "string" | "BooleanCollection" | "ColorCollection" | "ConditioningCollection" | "ControlCollection" | "FloatCollection" | "ImageCollection" | "IntegerCollection" | "LatentsCollection" | "StringCollection" | "BooleanPolymorphic" | "ColorPolymorphic" | "ConditioningPolymorphic" | "ControlPolymorphic" | "FloatPolymorphic" | "ImagePolymorphic" | "IntegerPolymorphic" | "LatentsPolymorphic" | "StringPolymorphic" | "MainModelField" | "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VaeModelField" | "LoRAModelField" | "ControlNetModelField" | "IPAdapterModelField" | "UNetField" | "VaeField" | "ClipField" | "Collection" | "CollectionItem" | "enum" | "Scheduler" | "WorkflowField" | "IsIntermediate" | "MetadataField" | "BoardField"; + UIType: "boolean" | "ColorField" | "ConditioningField" | "ControlField" | "float" | "ImageField" | "integer" | "LatentsField" | "string" | "BooleanCollection" | "ColorCollection" | "ConditioningCollection" | "ControlCollection" | "FloatCollection" | "ImageCollection" | "IntegerCollection" | "LatentsCollection" | "StringCollection" | "BooleanPolymorphic" | "ColorPolymorphic" | "ConditioningPolymorphic" | "ControlPolymorphic" | "FloatPolymorphic" | "ImagePolymorphic" | "IntegerPolymorphic" | "LatentsPolymorphic" | "StringPolymorphic" | "MainModelField" | "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VaeModelField" | "LoRAModelField" | "ControlNetModelField" | "IPAdapterModelField" | "UNetField" | "VaeField" | "ClipField" | "Collection" | "CollectionItem" | "enum" | "Scheduler" | "WorkflowField" | "IsIntermediate" | "BoardField" | "Any" | "MetadataItem" | "MetadataItemCollection" | "MetadataItemPolymorphic" | "MetadataDict"; /** * _InputField * @description *DO NOT USE* @@ -9116,24 +8727,18 @@ export type components = { /** Ui Order */ ui_order: number | null; }; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; - /** - * T2IAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - T2IAdapterModelFormat: "diffusers"; /** * ControlNetModelFormat * @description An enumeration. * @enum {string} */ ControlNetModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * IPAdapterModelFormat * @description An enumeration. @@ -9146,24 +8751,30 @@ export type components = { * @enum {string} */ CLIPVisionModelFormat: "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionOnnxModelFormat: "olive" | "onnx"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * T2IAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + T2IAdapterModelFormat: "diffusers"; }; responses: never; parameters: never; @@ -9724,7 +9335,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["ImageMetadata"]; + "application/json": components["schemas"]["MetadataField"] | null; }; }; /** @description Validation Error */ @@ -10701,4 +10312,30 @@ export type operations = { }; }; }; + /** + * Get Workflow + * @description Gets a workflow + */ + get_workflow: { + parameters: { + path: { + /** @description The workflow to get */ + workflow_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowField"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; }; diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 63617a4eb5..085ea65327 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -27,14 +27,6 @@ export type BatchConfig = export type EnqueueBatchResult = components['schemas']['EnqueueBatchResult']; -/** - * This is an unsafe type; the object inside is not guaranteed to be valid. - */ -export type UnsafeImageMetadata = { - metadata: s['CoreMetadata']; - graph: NonNullable; -}; - export type _InputField = s['_InputField']; export type _OutputField = s['_OutputField']; @@ -50,7 +42,6 @@ export type ImageChanges = s['ImageRecordChanges']; export type ImageCategory = s['ImageCategory']; export type ResourceOrigin = s['ResourceOrigin']; export type ImageField = s['ImageField']; -export type ImageMetadata = s['ImageMetadata']; export type OffsetPaginatedResults_BoardDTO_ = s['OffsetPaginatedResults_BoardDTO_']; export type OffsetPaginatedResults_ImageDTO_ = @@ -145,13 +136,19 @@ export type ImageCollectionInvocation = s['ImageCollectionInvocation']; export type MainModelLoaderInvocation = s['MainModelLoaderInvocation']; export type OnnxModelLoaderInvocation = s['OnnxModelLoaderInvocation']; export type LoraLoaderInvocation = s['LoraLoaderInvocation']; -export type MetadataAccumulatorInvocation = s['MetadataAccumulatorInvocation']; export type ESRGANInvocation = s['ESRGANInvocation']; export type DivideInvocation = s['DivideInvocation']; export type ImageNSFWBlurInvocation = s['ImageNSFWBlurInvocation']; export type ImageWatermarkInvocation = s['ImageWatermarkInvocation']; export type SeamlessModeInvocation = s['SeamlessModeInvocation']; export type SaveImageInvocation = s['SaveImageInvocation']; +export type MetadataInvocation = s['MetadataInvocation']; +export type CoreMetadataInvocation = s['CoreMetadataInvocation']; +export type MetadataItemInvocation = s['MetadataItemInvocation']; +export type MergeMetadataInvocation = s['MergeMetadataInvocation']; +export type IPAdapterMetadataField = s['IPAdapterMetadataField']; +export type T2IAdapterField = s['T2IAdapterField']; +export type LoRAMetadataField = s['LoRAMetadataField']; // ControlNet Nodes export type ControlNetInvocation = s['ControlNetInvocation']; diff --git a/tests/nodes/test_node_graph.py b/tests/nodes/test_node_graph.py index 3c965895f9..d1ece0336a 100644 --- a/tests/nodes/test_node_graph.py +++ b/tests/nodes/test_node_graph.py @@ -10,7 +10,12 @@ from invokeai.app.invocations.baseinvocation import ( ) from invokeai.app.invocations.image import ShowImageInvocation from invokeai.app.invocations.math import AddInvocation, SubtractInvocation -from invokeai.app.invocations.primitives import FloatInvocation, IntegerInvocation +from invokeai.app.invocations.primitives import ( + FloatCollectionInvocation, + FloatInvocation, + IntegerInvocation, + StringInvocation, +) from invokeai.app.invocations.upscale import ESRGANInvocation from invokeai.app.services.shared.default_graphs import create_text_to_image from invokeai.app.services.shared.graph import ( @@ -27,8 +32,11 @@ from invokeai.app.services.shared.graph import ( ) from .test_nodes import ( + AnyTypeTestInvocation, ImageToImageTestInvocation, ListPassThroughInvocation, + PolymorphicStringTestInvocation, + PromptCollectionTestInvocation, PromptTestInvocation, TextToImageTestInvocation, ) @@ -692,6 +700,144 @@ def test_ints_do_not_accept_floats(): g.add_edge(e) +def test_polymorphic_accepts_single(): + g = Graph() + n1 = StringInvocation(id="1", value="banana") + n2 = PolymorphicStringTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e1 = create_edge(n1.id, "value", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e1) + + +def test_polymorphic_accepts_collection_of_same_base_type(): + g = Graph() + n1 = PromptCollectionTestInvocation(id="1", collection=["banana", "sundae"]) + n2 = PolymorphicStringTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e1 = create_edge(n1.id, "collection", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e1) + + +def test_polymorphic_does_not_accept_collection_of_different_base_type(): + g = Graph() + n1 = FloatCollectionInvocation(id="1", collection=[1.0, 2.0, 3.0]) + n2 = PolymorphicStringTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e1 = create_edge(n1.id, "collection", n2.id, "value") + with pytest.raises(InvalidEdgeError): + g.add_edge(e1) + + +def test_polymorphic_does_not_accept_generic_collection(): + g = Graph() + n1 = IntegerInvocation(id="1", value=1) + n2 = IntegerInvocation(id="2", value=2) + n3 = CollectInvocation(id="3") + n4 = PolymorphicStringTestInvocation(id="4") + g.add_node(n1) + g.add_node(n2) + g.add_node(n3) + g.add_node(n4) + e1 = create_edge(n1.id, "value", n3.id, "item") + e2 = create_edge(n2.id, "value", n3.id, "item") + e3 = create_edge(n3.id, "collection", n4.id, "value") + g.add_edge(e1) + g.add_edge(e2) + with pytest.raises(InvalidEdgeError): + g.add_edge(e3) + + +def test_any_accepts_integer(): + g = Graph() + n1 = IntegerInvocation(id="1", value=1) + n2 = AnyTypeTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e = create_edge(n1.id, "value", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e) + + +def test_any_accepts_string(): + g = Graph() + n1 = StringInvocation(id="1", value="banana sundae") + n2 = AnyTypeTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e = create_edge(n1.id, "value", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e) + + +def test_any_accepts_generic_collection(): + g = Graph() + n1 = IntegerInvocation(id="1", value=1) + n2 = IntegerInvocation(id="2", value=2) + n3 = CollectInvocation(id="3") + n4 = AnyTypeTestInvocation(id="4") + g.add_node(n1) + g.add_node(n2) + g.add_node(n3) + g.add_node(n4) + e1 = create_edge(n1.id, "value", n3.id, "item") + e2 = create_edge(n2.id, "value", n3.id, "item") + e3 = create_edge(n3.id, "collection", n4.id, "value") + g.add_edge(e1) + g.add_edge(e2) + # Not throwing on this line is sufficient + g.add_edge(e3) + + +def test_any_accepts_prompt_collection(): + g = Graph() + n1 = PromptCollectionTestInvocation(id="1", collection=["banana", "sundae"]) + n2 = AnyTypeTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e = create_edge(n1.id, "collection", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e) + + +def test_any_accepts_any(): + g = Graph() + n1 = AnyTypeTestInvocation(id="1") + n2 = AnyTypeTestInvocation(id="2") + g.add_node(n1) + g.add_node(n2) + e = create_edge(n1.id, "value", n2.id, "value") + # Not throwing on this line is sufficient + g.add_edge(e) + + +def test_iterate_accepts_collection(): + """We need to update the validation for Collect -> Iterate to traverse to the Iterate + node's output and compare that against the item type of the Collect node's collection. Until + then, Collect nodes may not output into Iterate nodes.""" + g = Graph() + n1 = IntegerInvocation(id="1", value=1) + n2 = IntegerInvocation(id="2", value=2) + n3 = CollectInvocation(id="3") + n4 = IterateInvocation(id="4") + g.add_node(n1) + g.add_node(n2) + g.add_node(n3) + g.add_node(n4) + e1 = create_edge(n1.id, "value", n3.id, "item") + e2 = create_edge(n2.id, "value", n3.id, "item") + e3 = create_edge(n3.id, "collection", n4.id, "collection") + g.add_edge(e1) + g.add_edge(e2) + # Once we fix the validation logic as described, this should should not raise an error + with pytest.raises(InvalidEdgeError, match="Cannot connect collector to iterator"): + g.add_edge(e3) + + def test_graph_can_generate_schema(): # Not throwing on this line is sufficient # NOTE: if this test fails, it's PROBABLY because a new invocation type is breaking schema generation diff --git a/tests/nodes/test_nodes.py b/tests/nodes/test_nodes.py index 471c72a005..7807a56879 100644 --- a/tests/nodes/test_nodes.py +++ b/tests/nodes/test_nodes.py @@ -81,6 +81,29 @@ class PromptCollectionTestInvocation(BaseInvocation): return PromptCollectionTestInvocationOutput(collection=self.collection.copy()) +@invocation_output("test_any_output") +class AnyTypeTestInvocationOutput(BaseInvocationOutput): + value: Any = Field() + + +@invocation("test_any") +class AnyTypeTestInvocation(BaseInvocation): + value: Any = Field(default=None) + + def invoke(self, context: InvocationContext) -> AnyTypeTestInvocationOutput: + return AnyTypeTestInvocationOutput(value=self.value) + + +@invocation("test_polymorphic") +class PolymorphicStringTestInvocation(BaseInvocation): + value: Union[str, list[str]] = Field(default="") + + def invoke(self, context: InvocationContext) -> PromptCollectionTestInvocationOutput: + if isinstance(self.value, str): + return PromptCollectionTestInvocationOutput(collection=[self.value]) + return PromptCollectionTestInvocationOutput(collection=self.value) + + # Importing these must happen after test invocations are defined or they won't register from invokeai.app.services.events.events_base import EventServiceBase # noqa: E402 from invokeai.app.services.shared.graph import Edge, EdgeConnection # noqa: E402 From 5a163f02a66a75b373fe86bbf8b5f92c0de71ee3 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:08:01 +1100 Subject: [PATCH 037/119] fix(nodes): fix metadata/workflow serialization --- invokeai/app/invocations/baseinvocation.py | 3 --- .../app/services/workflow_records/workflow_records_common.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 39df4971a6..162b22b28d 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -830,9 +830,6 @@ class MetadataField(RootModel): root: dict[str, Any] = Field(description="A dictionary of metadata, shape of which is arbitrary") - def model_dump(self, *args, **kwargs) -> dict[str, Any]: - return super().model_dump(*args, **kwargs)["root"] - type_adapter_MetadataField = TypeAdapter(MetadataField) diff --git a/invokeai/app/services/workflow_records/workflow_records_common.py b/invokeai/app/services/workflow_records/workflow_records_common.py index d548656dab..32046328bb 100644 --- a/invokeai/app/services/workflow_records/workflow_records_common.py +++ b/invokeai/app/services/workflow_records/workflow_records_common.py @@ -15,8 +15,5 @@ class WorkflowField(RootModel): root: dict[str, Any] = Field(description="Workflow dict") - def model_dump(self, *args, **kwargs) -> dict[str, Any]: - return super().model_dump(*args, **kwargs)["root"] - type_adapter_WorkflowField = TypeAdapter(WorkflowField) From 3c4f43314ccd9e552e6637ccdbe1f84b86ed52ce Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:42:02 +1100 Subject: [PATCH 038/119] feat: move workflow/metadata models to `baseinvocation.py` needed to prevent circular imports --- invokeai/app/api/routers/images.py | 7 +++++-- invokeai/app/api/routers/workflows.py | 2 +- invokeai/app/invocations/baseinvocation.py | 20 ++++++++++++------- invokeai/app/invocations/metadata.py | 6 +++++- .../services/image_files/image_files_base.py | 3 +-- .../services/image_files/image_files_disk.py | 3 +-- invokeai/app/services/images/images_base.py | 3 +-- .../app/services/images/images_default.py | 3 +-- .../workflow_records/workflow_records_base.py | 2 +- .../workflow_records_common.py | 17 ---------------- .../workflow_records_sqlite.py | 7 ++----- 11 files changed, 31 insertions(+), 42 deletions(-) diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index f462437700..625fb3c43b 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -7,11 +7,14 @@ from fastapi.routing import APIRouter from PIL import Image from pydantic import BaseModel, Field, ValidationError -from invokeai.app.invocations.baseinvocation import MetadataField, type_adapter_MetadataField +from invokeai.app.invocations.baseinvocation import ( + MetadataField, + type_adapter_MetadataField, + type_adapter_WorkflowField, +) from invokeai.app.services.image_records.image_records_common import ImageCategory, ImageRecordChanges, ResourceOrigin from invokeai.app.services.images.images_common import ImageDTO, ImageUrlsDTO from invokeai.app.services.shared.pagination import OffsetPaginatedResults -from invokeai.app.services.workflow_records.workflow_records_common import type_adapter_WorkflowField from ..dependencies import ApiDependencies diff --git a/invokeai/app/api/routers/workflows.py b/invokeai/app/api/routers/workflows.py index 57a33fe73f..36de31fb51 100644 --- a/invokeai/app/api/routers/workflows.py +++ b/invokeai/app/api/routers/workflows.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, Path from invokeai.app.api.dependencies import ApiDependencies -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField +from invokeai.app.invocations.baseinvocation import WorkflowField workflows_router = APIRouter(prefix="/v1/workflows", tags=["workflows"]) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 162b22b28d..50ce8de7d3 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -15,7 +15,6 @@ from pydantic.fields import _Unset from pydantic_core import PydanticUndefined from invokeai.app.services.config.config_default import InvokeAIAppConfig -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField from invokeai.app.util.misc import uuid_string if TYPE_CHECKING: @@ -813,22 +812,29 @@ def invocation_output( return wrapper +class WorkflowField(RootModel): + """ + Pydantic model for workflows with custom root of type dict[str, Any]. + Workflows are stored without a strict schema. + """ + + root: dict[str, Any] = Field(description="The workflow") + + +type_adapter_WorkflowField = TypeAdapter(WorkflowField) + + class WithWorkflow(BaseModel): workflow: Optional[WorkflowField] = InputField(default=None, description=FieldDescriptions.workflow) -class MetadataItemField(BaseModel): - label: str = Field(description=FieldDescriptions.metadata_item_label) - value: Any = Field(description=FieldDescriptions.metadata_item_value) - - class MetadataField(RootModel): """ Pydantic model for metadata with custom root of type dict[str, Any]. Metadata is stored without a strict schema. """ - root: dict[str, Any] = Field(description="A dictionary of metadata, shape of which is arbitrary") + root: dict[str, Any] = Field(description="The metadata") type_adapter_MetadataField = TypeAdapter(MetadataField) diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 205dbef814..98f5f0e830 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -9,7 +9,6 @@ from invokeai.app.invocations.baseinvocation import ( InputField, InvocationContext, MetadataField, - MetadataItemField, OutputField, UIType, invocation, @@ -24,6 +23,11 @@ from invokeai.app.invocations.t2i_adapter import T2IAdapterField from ...version import __version__ +class MetadataItemField(BaseModel): + label: str = Field(description=FieldDescriptions.metadata_item_label) + value: Any = Field(description=FieldDescriptions.metadata_item_value) + + class LoRAMetadataField(BaseModel): """LoRA Metadata Field""" diff --git a/invokeai/app/services/image_files/image_files_base.py b/invokeai/app/services/image_files/image_files_base.py index 3f6e797225..91e18f30fc 100644 --- a/invokeai/app/services/image_files/image_files_base.py +++ b/invokeai/app/services/image_files/image_files_base.py @@ -4,8 +4,7 @@ from typing import Optional from PIL.Image import Image as PILImageType -from invokeai.app.invocations.metadata import MetadataField -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField +from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField class ImageFileStorageBase(ABC): diff --git a/invokeai/app/services/image_files/image_files_disk.py b/invokeai/app/services/image_files/image_files_disk.py index 57c05562d5..e8a733d619 100644 --- a/invokeai/app/services/image_files/image_files_disk.py +++ b/invokeai/app/services/image_files/image_files_disk.py @@ -7,9 +7,8 @@ from PIL import Image, PngImagePlugin from PIL.Image import Image as PILImageType from send2trash import send2trash -from invokeai.app.invocations.metadata import MetadataField +from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField from invokeai.app.services.invoker import Invoker -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField from invokeai.app.util.thumbnails import get_thumbnail_name, make_thumbnail from .image_files_base import ImageFileStorageBase diff --git a/invokeai/app/services/images/images_base.py b/invokeai/app/services/images/images_base.py index ebb40424bc..50a3a5fb82 100644 --- a/invokeai/app/services/images/images_base.py +++ b/invokeai/app/services/images/images_base.py @@ -3,7 +3,7 @@ from typing import Callable, Optional from PIL.Image import Image as PILImageType -from invokeai.app.invocations.metadata import MetadataField +from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField from invokeai.app.services.image_records.image_records_common import ( ImageCategory, ImageRecord, @@ -12,7 +12,6 @@ from invokeai.app.services.image_records.image_records_common import ( ) from invokeai.app.services.images.images_common import ImageDTO from invokeai.app.services.shared.pagination import OffsetPaginatedResults -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField class ImageServiceABC(ABC): diff --git a/invokeai/app/services/images/images_default.py b/invokeai/app/services/images/images_default.py index e466e809b1..a0d59470fc 100644 --- a/invokeai/app/services/images/images_default.py +++ b/invokeai/app/services/images/images_default.py @@ -2,10 +2,9 @@ from typing import Optional from PIL.Image import Image as PILImageType -from invokeai.app.invocations.metadata import MetadataField +from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField from invokeai.app.services.invoker import Invoker from invokeai.app.services.shared.pagination import OffsetPaginatedResults -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField from ..image_files.image_files_common import ( ImageFileDeleteException, diff --git a/invokeai/app/services/workflow_records/workflow_records_base.py b/invokeai/app/services/workflow_records/workflow_records_base.py index 97f7cfe3c0..d5a4b25ce4 100644 --- a/invokeai/app/services/workflow_records/workflow_records_base.py +++ b/invokeai/app/services/workflow_records/workflow_records_base.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod -from invokeai.app.services.workflow_records.workflow_records_common import WorkflowField +from invokeai.app.invocations.baseinvocation import WorkflowField class WorkflowRecordsStorageBase(ABC): diff --git a/invokeai/app/services/workflow_records/workflow_records_common.py b/invokeai/app/services/workflow_records/workflow_records_common.py index 32046328bb..3a2b13f565 100644 --- a/invokeai/app/services/workflow_records/workflow_records_common.py +++ b/invokeai/app/services/workflow_records/workflow_records_common.py @@ -1,19 +1,2 @@ -from typing import Any - -from pydantic import Field, RootModel, TypeAdapter - - class WorkflowNotFoundError(Exception): """Raised when a workflow is not found""" - - -class WorkflowField(RootModel): - """ - Pydantic model for workflows with custom root of type dict[str, Any]. - Workflows are stored without a strict schema. - """ - - root: dict[str, Any] = Field(description="Workflow dict") - - -type_adapter_WorkflowField = TypeAdapter(WorkflowField) diff --git a/invokeai/app/services/workflow_records/workflow_records_sqlite.py b/invokeai/app/services/workflow_records/workflow_records_sqlite.py index 2b284ac03f..e3c11cfa4b 100644 --- a/invokeai/app/services/workflow_records/workflow_records_sqlite.py +++ b/invokeai/app/services/workflow_records/workflow_records_sqlite.py @@ -1,14 +1,11 @@ import sqlite3 import threading +from invokeai.app.invocations.baseinvocation import WorkflowField, type_adapter_WorkflowField from invokeai.app.services.invoker import Invoker from invokeai.app.services.shared.sqlite import SqliteDatabase from invokeai.app.services.workflow_records.workflow_records_base import WorkflowRecordsStorageBase -from invokeai.app.services.workflow_records.workflow_records_common import ( - WorkflowField, - WorkflowNotFoundError, - type_adapter_WorkflowField, -) +from invokeai.app.services.workflow_records.workflow_records_common import WorkflowNotFoundError from invokeai.app.util.misc import uuid_string From 4012388f0aca3836714cbd6bba02f4ccda61b5ce Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:46:37 +1100 Subject: [PATCH 039/119] feat: use `ModelValidator` naming convention for pydantic type adapters This is the naming convention in the docs and is also clear. --- invokeai/app/api/routers/images.py | 8 ++++---- invokeai/app/api/routers/models.py | 20 +++++++++---------- invokeai/app/invocations/baseinvocation.py | 4 ++-- .../image_records/image_records_sqlite.py | 4 ++-- .../item_storage/item_storage_sqlite.py | 10 +++++----- .../session_queue/session_queue_common.py | 8 ++++---- .../workflow_records_sqlite.py | 4 ++-- tests/nodes/test_node_graph.py | 4 ++-- tests/nodes/test_session_queue.py | 10 +++++----- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 625fb3c43b..c27ec1e0d9 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -9,8 +9,8 @@ from pydantic import BaseModel, Field, ValidationError from invokeai.app.invocations.baseinvocation import ( MetadataField, - type_adapter_MetadataField, - type_adapter_WorkflowField, + MetadataFieldValidator, + WorkflowFieldValidator, ) from invokeai.app.services.image_records.image_records_common import ImageCategory, ImageRecordChanges, ResourceOrigin from invokeai.app.services.images.images_common import ImageDTO, ImageUrlsDTO @@ -66,7 +66,7 @@ async def upload_image( metadata_raw = pil_image.info.get("invokeai_metadata", None) if metadata_raw: try: - metadata = type_adapter_MetadataField.validate_json(metadata_raw) + metadata = MetadataFieldValidator.validate_json(metadata_raw) except ValidationError: ApiDependencies.invoker.services.logger.warn("Failed to parse metadata for uploaded image") pass @@ -75,7 +75,7 @@ async def upload_image( workflow_raw = pil_image.info.get("invokeai_workflow", None) if workflow_raw is not None: try: - workflow = type_adapter_WorkflowField.validate_json(workflow_raw) + workflow = WorkflowFieldValidator.validate_json(workflow_raw) except ValidationError: ApiDependencies.invoker.services.logger.warn("Failed to parse metadata for uploaded image") pass diff --git a/invokeai/app/api/routers/models.py b/invokeai/app/api/routers/models.py index 018f3af02b..afa7d8df82 100644 --- a/invokeai/app/api/routers/models.py +++ b/invokeai/app/api/routers/models.py @@ -23,13 +23,13 @@ from ..dependencies import ApiDependencies models_router = APIRouter(prefix="/v1/models", tags=["models"]) UpdateModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] -update_models_response_adapter = TypeAdapter(UpdateModelResponse) +UpdateModelResponseValidator = TypeAdapter(UpdateModelResponse) ImportModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] -import_models_response_adapter = TypeAdapter(ImportModelResponse) +ImportModelResponseValidator = TypeAdapter(ImportModelResponse) ConvertModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] -convert_models_response_adapter = TypeAdapter(ConvertModelResponse) +ConvertModelResponseValidator = TypeAdapter(ConvertModelResponse) MergeModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] ImportModelAttributes = Union[tuple(OPENAPI_MODEL_CONFIGS)] @@ -41,7 +41,7 @@ class ModelsList(BaseModel): model_config = ConfigDict(use_enum_values=True) -models_list_adapter = TypeAdapter(ModelsList) +ModelsListValidator = TypeAdapter(ModelsList) @models_router.get( @@ -60,7 +60,7 @@ async def list_models( models_raw.extend(ApiDependencies.invoker.services.model_manager.list_models(base_model, model_type)) else: models_raw = ApiDependencies.invoker.services.model_manager.list_models(None, model_type) - models = models_list_adapter.validate_python({"models": models_raw}) + models = ModelsListValidator.validate_python({"models": models_raw}) return models @@ -131,7 +131,7 @@ async def update_model( base_model=base_model, model_type=model_type, ) - model_response = update_models_response_adapter.validate_python(model_raw) + model_response = UpdateModelResponseValidator.validate_python(model_raw) except ModelNotFoundException as e: raise HTTPException(status_code=404, detail=str(e)) except ValueError as e: @@ -186,7 +186,7 @@ async def import_model( model_raw = ApiDependencies.invoker.services.model_manager.list_model( model_name=info.name, base_model=info.base_model, model_type=info.model_type ) - return import_models_response_adapter.validate_python(model_raw) + return ImportModelResponseValidator.validate_python(model_raw) except ModelNotFoundException as e: logger.error(str(e)) @@ -231,7 +231,7 @@ async def add_model( base_model=info.base_model, model_type=info.model_type, ) - return import_models_response_adapter.validate_python(model_raw) + return ImportModelResponseValidator.validate_python(model_raw) except ModelNotFoundException as e: logger.error(str(e)) raise HTTPException(status_code=404, detail=str(e)) @@ -302,7 +302,7 @@ async def convert_model( model_raw = ApiDependencies.invoker.services.model_manager.list_model( model_name, base_model=base_model, model_type=model_type ) - response = convert_models_response_adapter.validate_python(model_raw) + response = ConvertModelResponseValidator.validate_python(model_raw) except ModelNotFoundException as e: raise HTTPException(status_code=404, detail=f"Model '{model_name}' not found: {str(e)}") except ValueError as e: @@ -417,7 +417,7 @@ async def merge_models( base_model=base_model, model_type=ModelType.Main, ) - response = convert_models_response_adapter.validate_python(model_raw) + response = ConvertModelResponseValidator.validate_python(model_raw) except ModelNotFoundException: raise HTTPException( status_code=404, diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 50ce8de7d3..5f1ff0395f 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -821,7 +821,7 @@ class WorkflowField(RootModel): root: dict[str, Any] = Field(description="The workflow") -type_adapter_WorkflowField = TypeAdapter(WorkflowField) +WorkflowFieldValidator = TypeAdapter(WorkflowField) class WithWorkflow(BaseModel): @@ -837,7 +837,7 @@ class MetadataField(RootModel): root: dict[str, Any] = Field(description="The metadata") -type_adapter_MetadataField = TypeAdapter(MetadataField) +MetadataFieldValidator = TypeAdapter(MetadataField) class WithMetadata(BaseModel): diff --git a/invokeai/app/services/image_records/image_records_sqlite.py b/invokeai/app/services/image_records/image_records_sqlite.py index 7b60ec3d5b..dcabe55829 100644 --- a/invokeai/app/services/image_records/image_records_sqlite.py +++ b/invokeai/app/services/image_records/image_records_sqlite.py @@ -3,7 +3,7 @@ import threading from datetime import datetime from typing import Optional, Union, cast -from invokeai.app.invocations.baseinvocation import MetadataField, type_adapter_MetadataField +from invokeai.app.invocations.baseinvocation import MetadataField, MetadataFieldValidator from invokeai.app.services.shared.pagination import OffsetPaginatedResults from invokeai.app.services.shared.sqlite import SqliteDatabase @@ -170,7 +170,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): as_dict = dict(result) metadata_raw = cast(Optional[str], as_dict.get("metadata", None)) - return type_adapter_MetadataField.validate_json(metadata_raw) if metadata_raw is not None else None + return MetadataFieldValidator.validate_json(metadata_raw) if metadata_raw is not None else None except sqlite3.Error as e: self._conn.rollback() raise ImageRecordNotFoundException from e diff --git a/invokeai/app/services/item_storage/item_storage_sqlite.py b/invokeai/app/services/item_storage/item_storage_sqlite.py index 1bb9429130..d0249ebfa6 100644 --- a/invokeai/app/services/item_storage/item_storage_sqlite.py +++ b/invokeai/app/services/item_storage/item_storage_sqlite.py @@ -18,7 +18,7 @@ class SqliteItemStorage(ItemStorageABC, Generic[T]): _cursor: sqlite3.Cursor _id_field: str _lock: threading.RLock - _adapter: Optional[TypeAdapter[T]] + _validator: Optional[TypeAdapter[T]] def __init__(self, db: SqliteDatabase, table_name: str, id_field: str = "id"): super().__init__() @@ -28,7 +28,7 @@ class SqliteItemStorage(ItemStorageABC, Generic[T]): self._table_name = table_name self._id_field = id_field # TODO: validate that T has this field self._cursor = self._conn.cursor() - self._adapter: Optional[TypeAdapter[T]] = None + self._validator: Optional[TypeAdapter[T]] = None self._create_table() @@ -47,14 +47,14 @@ class SqliteItemStorage(ItemStorageABC, Generic[T]): self._lock.release() def _parse_item(self, item: str) -> T: - if self._adapter is None: + if self._validator is None: """ We don't get access to `__orig_class__` in `__init__()`, and we need this before start(), so we can create it when it is first needed instead. __orig_class__ is technically an implementation detail of the typing module, not a supported API """ - self._adapter = TypeAdapter(get_args(self.__orig_class__)[0]) # type: ignore [attr-defined] - return self._adapter.validate_json(item) + self._validator = TypeAdapter(get_args(self.__orig_class__)[0]) # type: ignore [attr-defined] + return self._validator.validate_json(item) def set(self, item: T): try: diff --git a/invokeai/app/services/session_queue/session_queue_common.py b/invokeai/app/services/session_queue/session_queue_common.py index cbf2154b66..69e6a3ab87 100644 --- a/invokeai/app/services/session_queue/session_queue_common.py +++ b/invokeai/app/services/session_queue/session_queue_common.py @@ -147,20 +147,20 @@ DEFAULT_QUEUE_ID = "default" QUEUE_ITEM_STATUS = Literal["pending", "in_progress", "completed", "failed", "canceled"] -adapter_NodeFieldValue = TypeAdapter(list[NodeFieldValue]) +NodeFieldValueValidator = TypeAdapter(list[NodeFieldValue]) def get_field_values(queue_item_dict: dict) -> Optional[list[NodeFieldValue]]: field_values_raw = queue_item_dict.get("field_values", None) - return adapter_NodeFieldValue.validate_json(field_values_raw) if field_values_raw is not None else None + return NodeFieldValueValidator.validate_json(field_values_raw) if field_values_raw is not None else None -adapter_GraphExecutionState = TypeAdapter(GraphExecutionState) +GraphExecutionStateValidator = TypeAdapter(GraphExecutionState) def get_session(queue_item_dict: dict) -> GraphExecutionState: session_raw = queue_item_dict.get("session", "{}") - session = adapter_GraphExecutionState.validate_json(session_raw, strict=False) + session = GraphExecutionStateValidator.validate_json(session_raw, strict=False) return session diff --git a/invokeai/app/services/workflow_records/workflow_records_sqlite.py b/invokeai/app/services/workflow_records/workflow_records_sqlite.py index e3c11cfa4b..2d9e1f26e8 100644 --- a/invokeai/app/services/workflow_records/workflow_records_sqlite.py +++ b/invokeai/app/services/workflow_records/workflow_records_sqlite.py @@ -1,7 +1,7 @@ import sqlite3 import threading -from invokeai.app.invocations.baseinvocation import WorkflowField, type_adapter_WorkflowField +from invokeai.app.invocations.baseinvocation import WorkflowField, WorkflowFieldValidator from invokeai.app.services.invoker import Invoker from invokeai.app.services.shared.sqlite import SqliteDatabase from invokeai.app.services.workflow_records.workflow_records_base import WorkflowRecordsStorageBase @@ -39,7 +39,7 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase): row = self._cursor.fetchone() if row is None: raise WorkflowNotFoundError(f"Workflow with id {workflow_id} not found") - return type_adapter_WorkflowField.validate_json(row[0]) + return WorkflowFieldValidator.validate_json(row[0]) except Exception: self._conn.rollback() raise diff --git a/tests/nodes/test_node_graph.py b/tests/nodes/test_node_graph.py index d1ece0336a..e2a50e61e5 100644 --- a/tests/nodes/test_node_graph.py +++ b/tests/nodes/test_node_graph.py @@ -615,8 +615,8 @@ def test_graph_can_deserialize(): g.add_edge(e) json = g.model_dump_json() - adapter_graph = TypeAdapter(Graph) - g2 = adapter_graph.validate_json(json) + GraphValidator = TypeAdapter(Graph) + g2 = GraphValidator.validate_json(json) assert g2 is not None assert g2.nodes["1"] is not None diff --git a/tests/nodes/test_session_queue.py b/tests/nodes/test_session_queue.py index 731316068c..cdab5729f8 100644 --- a/tests/nodes/test_session_queue.py +++ b/tests/nodes/test_session_queue.py @@ -150,9 +150,9 @@ def test_prepare_values_to_insert(batch_data_collection, batch_graph): values = prepare_values_to_insert(queue_id="default", batch=b, priority=0, max_new_queue_items=1000) assert len(values) == 8 - session_adapter = TypeAdapter(GraphExecutionState) + GraphExecutionStateValidator = TypeAdapter(GraphExecutionState) # graph should be serialized - ges = session_adapter.validate_json(values[0].session) + ges = GraphExecutionStateValidator.validate_json(values[0].session) # graph values should be populated assert ges.graph.get_node("1").prompt == "Banana sushi" @@ -161,16 +161,16 @@ def test_prepare_values_to_insert(batch_data_collection, batch_graph): assert ges.graph.get_node("4").prompt == "Nissan" # session ids should match deserialized graph - assert [v.session_id for v in values] == [session_adapter.validate_json(v.session).id for v in values] + assert [v.session_id for v in values] == [GraphExecutionStateValidator.validate_json(v.session).id for v in values] # should unique session ids sids = [v.session_id for v in values] assert len(sids) == len(set(sids)) - nfv_list_adapter = TypeAdapter(list[NodeFieldValue]) + NodeFieldValueValidator = TypeAdapter(list[NodeFieldValue]) # should have 3 node field values assert type(values[0].field_values) is str - assert len(nfv_list_adapter.validate_json(values[0].field_values)) == 3 + assert len(NodeFieldValueValidator.validate_json(values[0].field_values)) == 3 # should have batch id and priority assert all(v.batch_id == b.batch_id for v in values) From 8910e912c791e7c08b330204f4db5b64f1d07354 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:48:47 +1100 Subject: [PATCH 040/119] chore(ui): regen types --- .../frontend/web/src/services/api/schema.d.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 932891c862..6092e822d6 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -2942,7 +2942,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["GraphInvocation"]; + [key: string]: components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["InfillColorInvocation"]; }; /** * Edges @@ -2979,7 +2979,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["String2Output"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["LatentsOutput"]; + [key: string]: components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ImageOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FaceMaskOutput"]; }; /** * Errors @@ -8728,23 +8728,11 @@ export type components = { ui_order: number | null; }; /** - * ControlNetModelFormat + * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ - ControlNetModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * IPAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - IPAdapterModelFormat: "invokeai"; + StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** * CLIPVisionModelFormat * @description An enumeration. @@ -8752,17 +8740,23 @@ export type components = { */ CLIPVisionModelFormat: "diffusers"; /** - * StableDiffusion1ModelFormat + * ControlNetModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; + ControlNetModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusionOnnxModelFormat + * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; + IPAdapterModelFormat: "invokeai"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. @@ -8775,6 +8769,12 @@ export type components = { * @enum {string} */ T2IAdapterModelFormat: "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; From bbae4045c9f5e643d3ee11611991a141c682ea96 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:22:30 +1100 Subject: [PATCH 041/119] fix(nodes): `GraphInvocation` should use `InputField` --- invokeai/app/services/shared/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/services/shared/graph.py b/invokeai/app/services/shared/graph.py index 0f703db749..e9a4c73d4e 100644 --- a/invokeai/app/services/shared/graph.py +++ b/invokeai/app/services/shared/graph.py @@ -193,7 +193,7 @@ class GraphInvocation(BaseInvocation): """Execute a graph""" # TODO: figure out how to create a default here - graph: "Graph" = Field(description="The graph to run", default=None) + graph: Optional["Graph"] = InputField(description="The graph to run", default=None) def invoke(self, context: InvocationContext) -> GraphInvocationOutput: """Invoke with provided services and return outputs.""" From 7b6e2bc37fd1381a944768d19bb50b0cb27ee1ad Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:23:17 +1100 Subject: [PATCH 042/119] feat(nodes): add field name validation Protect against using reserved field names --- invokeai/app/invocations/baseinvocation.py | 109 ++++++++++++++++++--- 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 5f1ff0395f..25589510a6 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -2,6 +2,7 @@ from __future__ import annotations +import inspect import re from abc import ABC, abstractmethod from enum import Enum @@ -11,7 +12,7 @@ from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Literal, Op import semver from pydantic import BaseModel, ConfigDict, Field, RootModel, TypeAdapter, create_model -from pydantic.fields import _Unset +from pydantic.fields import FieldInfo, _Unset from pydantic_core import PydanticUndefined from invokeai.app.services.config.config_default import InvokeAIAppConfig @@ -25,6 +26,10 @@ class InvalidVersionError(ValueError): pass +class InvalidFieldError(TypeError): + pass + + class FieldDescriptions: denoising_start = "When to start denoising, expressed a percentage of total steps" denoising_end = "When to stop denoising, expressed a percentage of total steps" @@ -302,6 +307,7 @@ def InputField( ui_order=ui_order, item_default=item_default, ui_choice_labels=ui_choice_labels, + _field_kind="input", ) field_args = dict( @@ -444,6 +450,7 @@ def OutputField( ui_type=ui_type, ui_hidden=ui_hidden, ui_order=ui_order, + _field_kind="output", ), ) @@ -527,6 +534,7 @@ class BaseInvocationOutput(BaseModel): schema["required"].extend(["type"]) model_config = ConfigDict( + protected_namespaces=(), validate_assignment=True, json_schema_serialization_defaults_required=True, json_schema_extra=json_schema_extra, @@ -549,9 +557,6 @@ class MissingInputException(Exception): class BaseInvocation(ABC, BaseModel): """ - A node to process inputs and produce outputs. - May use dependency injection in __init__ to receive providers. - All invocations must use the `@invocation` decorator to provide their unique type. """ @@ -667,17 +672,21 @@ class BaseInvocation(ABC, BaseModel): id: str = Field( default_factory=uuid_string, description="The id of this instance of an invocation. Must be unique among all instances of invocations.", + json_schema_extra=dict(_field_kind="internal"), ) - is_intermediate: Optional[bool] = Field( + is_intermediate: bool = Field( default=False, description="Whether or not this is an intermediate invocation.", - json_schema_extra=dict(ui_type=UIType.IsIntermediate), + json_schema_extra=dict(ui_type=UIType.IsIntermediate, _field_kind="internal"), + ) + use_cache: bool = Field( + default=True, description="Whether or not to use the cache", json_schema_extra=dict(_field_kind="internal") ) - use_cache: bool = InputField(default=True, description="Whether or not to use the cache") UIConfig: ClassVar[Type[UIConfigBase]] model_config = ConfigDict( + protected_namespaces=(), validate_assignment=True, json_schema_extra=json_schema_extra, json_schema_serialization_defaults_required=True, @@ -688,6 +697,70 @@ class BaseInvocation(ABC, BaseModel): TBaseInvocation = TypeVar("TBaseInvocation", bound=BaseInvocation) +RESERVED_INPUT_FIELD_NAMES = { + "id", + "is_intermediate", + "use_cache", + "type", + "workflow", + "metadata", +} + +RESERVED_OUTPUT_FIELD_NAMES = {"type"} + + +class _Model(BaseModel): + pass + + +# Get all pydantic model attrs, methods, etc +RESERVED_PYDANTIC_FIELD_NAMES = set(map(lambda m: m[0], inspect.getmembers(_Model()))) + +print(RESERVED_PYDANTIC_FIELD_NAMES) + + +def validate_fields(model_fields: dict[str, FieldInfo], model_type: str) -> None: + """ + Validates the fields of an invocation or invocation output: + - must not override any pydantic reserved fields + - must be created via `InputField`, `OutputField`, or be an internal field defined in this file + """ + for name, field in model_fields.items(): + if name in RESERVED_PYDANTIC_FIELD_NAMES: + raise InvalidFieldError(f'Invalid field name "{name}" on "{model_type}" (reserved by pydantic)') + + field_kind = ( + # _field_kind is defined via InputField(), OutputField() or by one of the internal fields defined in this file + field.json_schema_extra.get("_field_kind", None) + if field.json_schema_extra + else None + ) + + # must have a field_kind + if field_kind is None or field_kind not in {"input", "output", "internal"}: + raise InvalidFieldError( + f'Invalid field definition for "{name}" on "{model_type}" (maybe it\'s not an InputField or OutputField?)' + ) + + if field_kind == "input" and name in RESERVED_INPUT_FIELD_NAMES: + raise InvalidFieldError(f'Invalid field name "{name}" on "{model_type}" (reserved input field name)') + + if field_kind == "output" and name in RESERVED_OUTPUT_FIELD_NAMES: + raise InvalidFieldError(f'Invalid field name "{name}" on "{model_type}" (reserved output field name)') + + # internal fields *must* be in the reserved list + if ( + field_kind == "internal" + and name not in RESERVED_INPUT_FIELD_NAMES + and name not in RESERVED_OUTPUT_FIELD_NAMES + ): + raise InvalidFieldError( + f'Invalid field name "{name}" on "{model_type}" (internal field without reserved name)' + ) + + return None + + def invocation( invocation_type: str, title: Optional[str] = None, @@ -697,7 +770,7 @@ def invocation( use_cache: Optional[bool] = True, ) -> Callable[[Type[TBaseInvocation]], Type[TBaseInvocation]]: """ - Adds metadata to an invocation. + Registers an invocation. :param str invocation_type: The type of the invocation. Must be unique among all invocations. :param Optional[str] title: Adds a title to the invocation. Use if the auto-generated title isn't quite right. Defaults to None. @@ -716,6 +789,8 @@ def invocation( if invocation_type in BaseInvocation.get_invocation_types(): raise ValueError(f'Invocation type "{invocation_type}" already exists') + validate_fields(cls.model_fields, invocation_type) + # Add OpenAPI schema extras uiconf_name = cls.__qualname__ + ".UIConfig" if not hasattr(cls, "UIConfig") or cls.UIConfig.__qualname__ != uiconf_name: @@ -746,8 +821,7 @@ def invocation( invocation_type_annotation = Literal[invocation_type] # type: ignore invocation_type_field = Field( - title="type", - default=invocation_type, + title="type", default=invocation_type, json_schema_extra=dict(_field_kind="internal") ) docstring = cls.__doc__ @@ -788,13 +862,12 @@ def invocation_output( if output_type in BaseInvocationOutput.get_output_types(): raise ValueError(f'Invocation type "{output_type}" already exists') + validate_fields(cls.model_fields, output_type) + # Add the output type to the model. output_type_annotation = Literal[output_type] # type: ignore - output_type_field = Field( - title="type", - default=output_type, - ) + output_type_field = Field(title="type", default=output_type, json_schema_extra=dict(_field_kind="internal")) docstring = cls.__doc__ cls = create_model( @@ -825,7 +898,9 @@ WorkflowFieldValidator = TypeAdapter(WorkflowField) class WithWorkflow(BaseModel): - workflow: Optional[WorkflowField] = InputField(default=None, description=FieldDescriptions.workflow) + workflow: Optional[WorkflowField] = Field( + default=None, description=FieldDescriptions.workflow, json_schema_extra=dict(_field_kind="internal") + ) class MetadataField(RootModel): @@ -841,4 +916,6 @@ MetadataFieldValidator = TypeAdapter(MetadataField) class WithMetadata(BaseModel): - metadata: Optional[MetadataField] = InputField(default=None, description=FieldDescriptions.metadata) + metadata: Optional[MetadataField] = Field( + default=None, description=FieldDescriptions.metadata, json_schema_extra=dict(_field_kind="internal") + ) From e3e8d8af0233ef9d2bdfc9fef889c864836fc2ff Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:38:12 +1100 Subject: [PATCH 043/119] fix(ui): fix log message --- invokeai/frontend/web/src/services/api/endpoints/workflows.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/services/api/endpoints/workflows.ts b/invokeai/frontend/web/src/services/api/endpoints/workflows.ts index 4c69d2e286..7ddd9c5606 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/workflows.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/workflows.ts @@ -19,7 +19,7 @@ export const workflowsApi = api.injectEndpoints({ if (result.success) { return result.data; } else { - logger('images').warn('Problem parsing metadata'); + logger('images').warn('Problem parsing workflow'); } } return; From d32caf7cb1205475ffec054640da5beca959c9c2 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:38:27 +1100 Subject: [PATCH 044/119] fix(ui): remove references to metadata accumulator --- .../nodes/util/graphBuilders/buildLinearBatchConfig.ts | 5 +---- .../web/src/features/nodes/util/graphBuilders/constants.ts | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts index 313826452c..8bf9a2785a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts @@ -2,13 +2,12 @@ import { NUMPY_RAND_MAX } from 'app/constants'; import { RootState } from 'app/store/store'; import { generateSeeds } from 'common/util/generateSeeds'; import { NonNullableGraph } from 'features/nodes/types/types'; -import { range, unset } from 'lodash-es'; +import { range } from 'lodash-es'; import { components } from 'services/api/schema'; import { Batch, BatchConfig } from 'services/api/types'; import { CANVAS_COHERENCE_NOISE, METADATA, - METADATA_ACCUMULATOR, NOISE, POSITIVE_CONDITIONING, } from './constants'; @@ -149,8 +148,6 @@ export const prepareLinearUIBatch = ( }); if (shouldConcatSDXLStylePrompt && model?.base_model === 'sdxl') { - unset(graph.nodes[METADATA_ACCUMULATOR], 'positive_style_prompt'); - const stylePrompts = extendedPrompts.map((p) => [p, positiveStylePrompt].join(' ') ); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts index e0dc52063b..51dc94769f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts @@ -63,7 +63,6 @@ export const BATCH_SEED = 'batch_seed'; export const BATCH_PROMPT = 'batch_prompt'; export const BATCH_STYLE_PROMPT = 'batch_style_prompt'; export const METADATA_COLLECT = 'metadata_collect'; -export const METADATA_ACCUMULATOR = 'metadata_accumulator'; export const MERGE_METADATA = 'merge_metadata'; export const REALESRGAN = 'esrgan'; export const DIVIDE = 'divide'; From 86c3acf18499db50839b85399b5e8cdfb96b3b7a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:14:22 +1100 Subject: [PATCH 045/119] fix(nodes): revert optional graph --- invokeai/app/services/shared/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/services/shared/graph.py b/invokeai/app/services/shared/graph.py index e9a4c73d4e..b84d456071 100644 --- a/invokeai/app/services/shared/graph.py +++ b/invokeai/app/services/shared/graph.py @@ -193,7 +193,7 @@ class GraphInvocation(BaseInvocation): """Execute a graph""" # TODO: figure out how to create a default here - graph: Optional["Graph"] = InputField(description="The graph to run", default=None) + graph: "Graph" = InputField(description="The graph to run", default=None) def invoke(self, context: InvocationContext) -> GraphInvocationOutput: """Invoke with provided services and return outputs.""" From 6d776bad7e8ff21d608651228c8bda27b238352f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:15:01 +1100 Subject: [PATCH 046/119] fix(nodes): remove errant print --- invokeai/app/invocations/baseinvocation.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 25589510a6..945df4bd83 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -716,8 +716,6 @@ class _Model(BaseModel): # Get all pydantic model attrs, methods, etc RESERVED_PYDANTIC_FIELD_NAMES = set(map(lambda m: m[0], inspect.getmembers(_Model()))) -print(RESERVED_PYDANTIC_FIELD_NAMES) - def validate_fields(model_fields: dict[str, FieldInfo], model_type: str) -> None: """ From 0cda7943fa1fd2f215e5238b753a817752a8761b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:16:36 +1100 Subject: [PATCH 047/119] feat(api): add workflow_images junction table similar to boards, images and workflows may be associated via junction table --- invokeai/app/api/dependencies.py | 3 + invokeai/app/api/routers/images.py | 3 + .../image_records/image_records_base.py | 1 - .../image_records/image_records_common.py | 8 -- .../image_records/image_records_sqlite.py | 15 +-- invokeai/app/services/images/images_common.py | 7 + .../app/services/images/images_default.py | 34 +++-- invokeai/app/services/invocation_services.py | 4 + .../workflow_image_records/__init__.py | 0 .../workflow_image_records_base.py | 23 ++++ .../workflow_image_records_sqlite.py | 123 ++++++++++++++++++ 11 files changed, 189 insertions(+), 32 deletions(-) create mode 100644 invokeai/app/services/workflow_image_records/__init__.py create mode 100644 invokeai/app/services/workflow_image_records/workflow_image_records_base.py create mode 100644 invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index ae4882c0d0..4746eeae3f 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -1,6 +1,7 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) from logging import Logger +from invokeai.app.services.workflow_image_records.workflow_image_records_sqlite import SqliteWorkflowImageRecordsStorage from invokeai.backend.util.logging import InvokeAILogger from invokeai.version.invokeai_version import __version__ @@ -91,6 +92,7 @@ class ApiDependencies: session_processor = DefaultSessionProcessor() session_queue = SqliteSessionQueue(db=db) urls = LocalUrlService() + workflow_image_records = SqliteWorkflowImageRecordsStorage(db=db) workflow_records = SqliteWorkflowRecordsStorage(db=db) services = InvocationServices( @@ -116,6 +118,7 @@ class ApiDependencies: session_processor=session_processor, session_queue=session_queue, urls=urls, + workflow_image_records=workflow_image_records, workflow_records=workflow_records, ) diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index c27ec1e0d9..429eaef37c 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -1,4 +1,5 @@ import io +import traceback from typing import Optional from fastapi import Body, HTTPException, Path, Query, Request, Response, UploadFile @@ -60,6 +61,7 @@ async def upload_image( pil_image = pil_image.crop(bbox) except Exception: # Error opening the image + ApiDependencies.invoker.services.logger.error(traceback.format_exc()) raise HTTPException(status_code=415, detail="Failed to read image") # attempt to parse metadata from image @@ -97,6 +99,7 @@ async def upload_image( return image_dto except Exception: + ApiDependencies.invoker.services.logger.error(traceback.format_exc()) raise HTTPException(status_code=500, detail="Failed to create image") diff --git a/invokeai/app/services/image_records/image_records_base.py b/invokeai/app/services/image_records/image_records_base.py index cd1db81857..655e4b4fb8 100644 --- a/invokeai/app/services/image_records/image_records_base.py +++ b/invokeai/app/services/image_records/image_records_base.py @@ -80,7 +80,6 @@ class ImageRecordStorageBase(ABC): session_id: Optional[str] = None, node_id: Optional[str] = None, metadata: Optional[MetadataField] = None, - workflow_id: Optional[str] = None, ) -> datetime: """Saves an image record.""" pass diff --git a/invokeai/app/services/image_records/image_records_common.py b/invokeai/app/services/image_records/image_records_common.py index 6576fb9647..5a6e5652c9 100644 --- a/invokeai/app/services/image_records/image_records_common.py +++ b/invokeai/app/services/image_records/image_records_common.py @@ -100,7 +100,6 @@ IMAGE_DTO_COLS = ", ".join( "width", "height", "session_id", - "workflow_id", "node_id", "is_intermediate", "created_at", @@ -141,11 +140,6 @@ class ImageRecord(BaseModelExcludeNull): description="The session ID that generated this image, if it is a generated image.", ) """The session ID that generated this image, if it is a generated image.""" - workflow_id: Optional[str] = Field( - default=None, - description="The workflow that generated this image.", - ) - """The workflow that generated this image.""" node_id: Optional[str] = Field( default=None, description="The node ID that generated this image, if it is a generated image.", @@ -190,7 +184,6 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord: width = image_dict.get("width", 0) height = image_dict.get("height", 0) session_id = image_dict.get("session_id", None) - workflow_id = image_dict.get("workflow_id", None) node_id = image_dict.get("node_id", None) created_at = image_dict.get("created_at", get_iso_timestamp()) updated_at = image_dict.get("updated_at", get_iso_timestamp()) @@ -205,7 +198,6 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord: width=width, height=height, session_id=session_id, - workflow_id=workflow_id, node_id=node_id, created_at=created_at, updated_at=updated_at, diff --git a/invokeai/app/services/image_records/image_records_sqlite.py b/invokeai/app/services/image_records/image_records_sqlite.py index dcabe55829..239917b728 100644 --- a/invokeai/app/services/image_records/image_records_sqlite.py +++ b/invokeai/app/services/image_records/image_records_sqlite.py @@ -76,16 +76,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): """ ) - if "workflow_id" not in columns: - self._cursor.execute( - """--sql - ALTER TABLE images - ADD COLUMN workflow_id TEXT; - -- TODO: This requires a migration: - -- FOREIGN KEY (workflow_id) REFERENCES workflows (workflow_id) ON DELETE SET NULL; - """ - ) - # Create the `images` table indices. self._cursor.execute( """--sql @@ -423,7 +413,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): session_id: Optional[str] = None, node_id: Optional[str] = None, metadata: Optional[MetadataField] = None, - workflow_id: Optional[str] = None, ) -> datetime: try: metadata_json = metadata.model_dump_json() if metadata is not None else None @@ -439,11 +428,10 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): node_id, session_id, metadata, - workflow_id, is_intermediate, starred ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, ( image_name, @@ -454,7 +442,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): node_id, session_id, metadata_json, - workflow_id, is_intermediate, starred, ), diff --git a/invokeai/app/services/images/images_common.py b/invokeai/app/services/images/images_common.py index 0464244b94..198c26c3a2 100644 --- a/invokeai/app/services/images/images_common.py +++ b/invokeai/app/services/images/images_common.py @@ -24,6 +24,11 @@ class ImageDTO(ImageRecord, ImageUrlsDTO): default=None, description="The id of the board the image belongs to, if one exists." ) """The id of the board the image belongs to, if one exists.""" + workflow_id: Optional[str] = Field( + default=None, + description="The workflow that generated this image.", + ) + """The workflow that generated this image.""" def image_record_to_dto( @@ -31,6 +36,7 @@ def image_record_to_dto( image_url: str, thumbnail_url: str, board_id: Optional[str], + workflow_id: Optional[str], ) -> ImageDTO: """Converts an image record to an image DTO.""" return ImageDTO( @@ -38,4 +44,5 @@ def image_record_to_dto( image_url=image_url, thumbnail_url=thumbnail_url, board_id=board_id, + workflow_id=workflow_id, ) diff --git a/invokeai/app/services/images/images_default.py b/invokeai/app/services/images/images_default.py index a0d59470fc..8eb768a1b9 100644 --- a/invokeai/app/services/images/images_default.py +++ b/invokeai/app/services/images/images_default.py @@ -74,11 +74,12 @@ class ImageService(ImageServiceABC): # Nullable fields node_id=node_id, metadata=metadata, - workflow_id=workflow_id, session_id=session_id, ) if board_id is not None: self.__invoker.services.board_image_records.add_image_to_board(board_id=board_id, image_name=image_name) + if workflow_id is not None: + self.__invoker.services.workflow_image_records.create(workflow_id=workflow_id, image_name=image_name) self.__invoker.services.image_files.save( image_name=image_name, image=image, metadata=metadata, workflow=workflow ) @@ -138,10 +139,11 @@ class ImageService(ImageServiceABC): image_record = self.__invoker.services.image_records.get(image_name) image_dto = image_record_to_dto( - image_record, - self.__invoker.services.urls.get_image_url(image_name), - self.__invoker.services.urls.get_image_url(image_name, True), - self.__invoker.services.board_image_records.get_board_for_image(image_name), + image_record=image_record, + image_url=self.__invoker.services.urls.get_image_url(image_name), + thumbnail_url=self.__invoker.services.urls.get_image_url(image_name, True), + board_id=self.__invoker.services.board_image_records.get_board_for_image(image_name), + workflow_id=self.__invoker.services.workflow_image_records.get_workflow_for_image(image_name), ) return image_dto @@ -162,6 +164,19 @@ class ImageService(ImageServiceABC): self.__invoker.services.logger.error("Problem getting image DTO") raise e + def get_workflow(self, image_name: str) -> Optional[WorkflowField]: + try: + workflow_id = self.__invoker.services.workflow_image_records.get_workflow_for_image(image_name) + if workflow_id is None: + return None + return self.__invoker.services.workflow_records.get(workflow_id) + except ImageRecordNotFoundException: + self.__invoker.services.logger.error("Image record not found") + raise + except Exception as e: + self.__invoker.services.logger.error("Problem getting image DTO") + raise e + def get_path(self, image_name: str, thumbnail: bool = False) -> str: try: return str(self.__invoker.services.image_files.get_path(image_name, thumbnail)) @@ -205,10 +220,11 @@ class ImageService(ImageServiceABC): image_dtos = list( map( lambda r: image_record_to_dto( - r, - self.__invoker.services.urls.get_image_url(r.image_name), - self.__invoker.services.urls.get_image_url(r.image_name, True), - self.__invoker.services.board_image_records.get_board_for_image(r.image_name), + image_record=r, + image_url=self.__invoker.services.urls.get_image_url(r.image_name), + thumbnail_url=self.__invoker.services.urls.get_image_url(r.image_name, True), + board_id=self.__invoker.services.board_image_records.get_board_for_image(r.image_name), + workflow_id=self.__invoker.services.workflow_image_records.get_workflow_for_image(r.image_name), ), results.items, ) diff --git a/invokeai/app/services/invocation_services.py b/invokeai/app/services/invocation_services.py index 94db75d810..804b1b6884 100644 --- a/invokeai/app/services/invocation_services.py +++ b/invokeai/app/services/invocation_services.py @@ -28,6 +28,7 @@ if TYPE_CHECKING: from .shared.graph import GraphExecutionState, LibraryGraph from .urls.urls_base import UrlServiceBase from .workflow_records.workflow_records_base import WorkflowRecordsStorageBase + from .workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase class InvocationServices: @@ -56,6 +57,7 @@ class InvocationServices: invocation_cache: "InvocationCacheBase" names: "NameServiceBase" urls: "UrlServiceBase" + workflow_image_records: "WorkflowImageRecordsStorageBase" workflow_records: "WorkflowRecordsStorageBase" def __init__( @@ -82,6 +84,7 @@ class InvocationServices: invocation_cache: "InvocationCacheBase", names: "NameServiceBase", urls: "UrlServiceBase", + workflow_image_records: "WorkflowImageRecordsStorageBase", workflow_records: "WorkflowRecordsStorageBase", ): self.board_images = board_images @@ -106,4 +109,5 @@ class InvocationServices: self.invocation_cache = invocation_cache self.names = names self.urls = urls + self.workflow_image_records = workflow_image_records self.workflow_records = workflow_records diff --git a/invokeai/app/services/workflow_image_records/__init__.py b/invokeai/app/services/workflow_image_records/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/invokeai/app/services/workflow_image_records/workflow_image_records_base.py b/invokeai/app/services/workflow_image_records/workflow_image_records_base.py new file mode 100644 index 0000000000..d99a2ba106 --- /dev/null +++ b/invokeai/app/services/workflow_image_records/workflow_image_records_base.py @@ -0,0 +1,23 @@ +from abc import ABC, abstractmethod +from typing import Optional + + +class WorkflowImageRecordsStorageBase(ABC): + """Abstract base class for the one-to-many workflow-image relationship record storage.""" + + @abstractmethod + def create( + self, + workflow_id: str, + image_name: str, + ) -> None: + """Creates a workflow-image record.""" + pass + + @abstractmethod + def get_workflow_for_image( + self, + image_name: str, + ) -> Optional[str]: + """Gets an image's workflow id, if it has one.""" + pass diff --git a/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py new file mode 100644 index 0000000000..1a5de672bc --- /dev/null +++ b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py @@ -0,0 +1,123 @@ +import sqlite3 +import threading +from typing import Optional, cast +from invokeai.app.services.shared.sqlite import SqliteDatabase + +from invokeai.app.services.workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase + + +class SqliteWorkflowImageRecordsStorage(WorkflowImageRecordsStorageBase): + """SQLite implementation of WorkflowImageRecordsStorageBase.""" + + _conn: sqlite3.Connection + _cursor: sqlite3.Cursor + _lock: threading.RLock + + def __init__(self, db: SqliteDatabase) -> None: + super().__init__() + self._lock = db.lock + self._conn = db.conn + self._cursor = self._conn.cursor() + + try: + self._lock.acquire() + self._create_tables() + self._conn.commit() + finally: + self._lock.release() + + def _create_tables(self) -> None: + # Create the `workflow_images` junction table. + self._cursor.execute( + """--sql + CREATE TABLE IF NOT EXISTS workflow_images ( + workflow_id TEXT NOT NULL, + image_name TEXT NOT NULL, + created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), + -- updated via trigger + updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), + -- Soft delete, currently unused + deleted_at DATETIME, + -- enforce one-to-many relationship between workflows and images using PK + -- (we can extend this to many-to-many later) + PRIMARY KEY (image_name), + FOREIGN KEY (workflow_id) REFERENCES workflows (workflow_id) ON DELETE CASCADE, + FOREIGN KEY (image_name) REFERENCES images (image_name) ON DELETE CASCADE + ); + """ + ) + + # Add index for workflow id + self._cursor.execute( + """--sql + CREATE INDEX IF NOT EXISTS idx_workflow_images_workflow_id ON workflow_images (workflow_id); + """ + ) + + # Add index for workflow id, sorted by created_at + self._cursor.execute( + """--sql + CREATE INDEX IF NOT EXISTS idx_workflow_images_workflow_id_created_at ON workflow_images (workflow_id, created_at); + """ + ) + + # Add trigger for `updated_at`. + self._cursor.execute( + """--sql + CREATE TRIGGER IF NOT EXISTS tg_workflow_images_updated_at + AFTER UPDATE + ON workflow_images FOR EACH ROW + BEGIN + UPDATE workflow_images SET updated_at = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') + WHERE workflow_id = old.workflow_id AND image_name = old.image_name; + END; + """ + ) + + def create( + self, + workflow_id: str, + image_name: str, + ) -> None: + """Creates a workflow-image record.""" + try: + self._lock.acquire() + self._cursor.execute( + """--sql + INSERT INTO workflow_images (workflow_id, image_name) + VALUES (?, ?) + ON CONFLICT (image_name) DO UPDATE SET workflow_id = ?; + """, + (workflow_id, image_name, workflow_id), + ) + self._conn.commit() + except sqlite3.Error as e: + self._conn.rollback() + raise e + finally: + self._lock.release() + + def get_workflow_for_image( + self, + image_name: str, + ) -> Optional[str]: + """Gets an image's workflow id, if it has one.""" + try: + self._lock.acquire() + self._cursor.execute( + """--sql + SELECT workflow_id + FROM workflow_images + WHERE image_name = ?; + """, + (image_name,), + ) + result = self._cursor.fetchone() + if result is None: + return None + return cast(str, result[0]) + except sqlite3.Error as e: + self._conn.rollback() + raise e + finally: + self._lock.release() From 23fa2e560aaa0625936faea8c073623f29f0dc2e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:27:29 +1100 Subject: [PATCH 048/119] fix: fix tests --- tests/nodes/test_graph_execution_state.py | 1 + tests/nodes/test_invoker.py | 1 + tests/nodes/test_nodes.py | 31 ++++++++++++----------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/nodes/test_graph_execution_state.py b/tests/nodes/test_graph_execution_state.py index e2d435e621..171cdfdb6f 100644 --- a/tests/nodes/test_graph_execution_state.py +++ b/tests/nodes/test_graph_execution_state.py @@ -76,6 +76,7 @@ def mock_services() -> InvocationServices: session_queue=None, # type: ignore urls=None, # type: ignore workflow_records=None, # type: ignore + workflow_image_records=None, # type: ignore ) diff --git a/tests/nodes/test_invoker.py b/tests/nodes/test_invoker.py index 9774f07fdd..25b02955b0 100644 --- a/tests/nodes/test_invoker.py +++ b/tests/nodes/test_invoker.py @@ -81,6 +81,7 @@ def mock_services() -> InvocationServices: session_queue=None, # type: ignore urls=None, # type: ignore workflow_records=None, # type: ignore + workflow_image_records=None, # type: ignore ) diff --git a/tests/nodes/test_nodes.py b/tests/nodes/test_nodes.py index 7807a56879..1d7f2e4194 100644 --- a/tests/nodes/test_nodes.py +++ b/tests/nodes/test_nodes.py @@ -1,11 +1,12 @@ from typing import Any, Callable, Union -from pydantic import Field from invokeai.app.invocations.baseinvocation import ( BaseInvocation, BaseInvocationOutput, + InputField, InvocationContext, + OutputField, invocation, invocation_output, ) @@ -15,12 +16,12 @@ from invokeai.app.invocations.image import ImageField # Define test invocations before importing anything that uses invocations @invocation_output("test_list_output") class ListPassThroughInvocationOutput(BaseInvocationOutput): - collection: list[ImageField] = Field(default_factory=list) + collection: list[ImageField] = OutputField(default_factory=list) @invocation("test_list") class ListPassThroughInvocation(BaseInvocation): - collection: list[ImageField] = Field(default_factory=list) + collection: list[ImageField] = InputField(default_factory=list) def invoke(self, context: InvocationContext) -> ListPassThroughInvocationOutput: return ListPassThroughInvocationOutput(collection=self.collection) @@ -28,12 +29,12 @@ class ListPassThroughInvocation(BaseInvocation): @invocation_output("test_prompt_output") class PromptTestInvocationOutput(BaseInvocationOutput): - prompt: str = Field(default="") + prompt: str = OutputField(default="") @invocation("test_prompt") class PromptTestInvocation(BaseInvocation): - prompt: str = Field(default="") + prompt: str = InputField(default="") def invoke(self, context: InvocationContext) -> PromptTestInvocationOutput: return PromptTestInvocationOutput(prompt=self.prompt) @@ -47,13 +48,13 @@ class ErrorInvocation(BaseInvocation): @invocation_output("test_image_output") class ImageTestInvocationOutput(BaseInvocationOutput): - image: ImageField = Field() + image: ImageField = OutputField() @invocation("test_text_to_image") class TextToImageTestInvocation(BaseInvocation): - prompt: str = Field(default="") - prompt2: str = Field(default="") + prompt: str = InputField(default="") + prompt2: str = InputField(default="") def invoke(self, context: InvocationContext) -> ImageTestInvocationOutput: return ImageTestInvocationOutput(image=ImageField(image_name=self.id)) @@ -61,8 +62,8 @@ class TextToImageTestInvocation(BaseInvocation): @invocation("test_image_to_image") class ImageToImageTestInvocation(BaseInvocation): - prompt: str = Field(default="") - image: Union[ImageField, None] = Field(default=None) + prompt: str = InputField(default="") + image: Union[ImageField, None] = InputField(default=None) def invoke(self, context: InvocationContext) -> ImageTestInvocationOutput: return ImageTestInvocationOutput(image=ImageField(image_name=self.id)) @@ -70,12 +71,12 @@ class ImageToImageTestInvocation(BaseInvocation): @invocation_output("test_prompt_collection_output") class PromptCollectionTestInvocationOutput(BaseInvocationOutput): - collection: list[str] = Field(default_factory=list) + collection: list[str] = OutputField(default_factory=list) @invocation("test_prompt_collection") class PromptCollectionTestInvocation(BaseInvocation): - collection: list[str] = Field() + collection: list[str] = InputField() def invoke(self, context: InvocationContext) -> PromptCollectionTestInvocationOutput: return PromptCollectionTestInvocationOutput(collection=self.collection.copy()) @@ -83,12 +84,12 @@ class PromptCollectionTestInvocation(BaseInvocation): @invocation_output("test_any_output") class AnyTypeTestInvocationOutput(BaseInvocationOutput): - value: Any = Field() + value: Any = OutputField() @invocation("test_any") class AnyTypeTestInvocation(BaseInvocation): - value: Any = Field(default=None) + value: Any = InputField(default=None) def invoke(self, context: InvocationContext) -> AnyTypeTestInvocationOutput: return AnyTypeTestInvocationOutput(value=self.value) @@ -96,7 +97,7 @@ class AnyTypeTestInvocation(BaseInvocation): @invocation("test_polymorphic") class PolymorphicStringTestInvocation(BaseInvocation): - value: Union[str, list[str]] = Field(default="") + value: Union[str, list[str]] = InputField(default="") def invoke(self, context: InvocationContext) -> PromptCollectionTestInvocationOutput: if isinstance(self.value, str): From 2faed653d75547ac40b955971b6ca481b82586d7 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 20:10:17 +1100 Subject: [PATCH 049/119] fix(api): deduplicate metadata/workflow extraction logic --- invokeai/app/api/routers/images.py | 2 +- .../services/image_files/image_files_disk.py | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 429eaef37c..a57414e17f 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -60,10 +60,10 @@ async def upload_image( bbox = pil_image.getbbox() pil_image = pil_image.crop(bbox) except Exception: - # Error opening the image ApiDependencies.invoker.services.logger.error(traceback.format_exc()) raise HTTPException(status_code=415, detail="Failed to read image") + # TODO: retain non-invokeai metadata on upload? # attempt to parse metadata from image metadata_raw = pil_image.info.get("invokeai_metadata", None) if metadata_raw: diff --git a/invokeai/app/services/image_files/image_files_disk.py b/invokeai/app/services/image_files/image_files_disk.py index e8a733d619..91c1e14789 100644 --- a/invokeai/app/services/image_files/image_files_disk.py +++ b/invokeai/app/services/image_files/image_files_disk.py @@ -65,20 +65,10 @@ class DiskImageFileStorage(ImageFileStorageBase): pnginfo = PngImagePlugin.PngInfo() - if metadata is not None or workflow is not None: - if metadata is not None: - pnginfo.add_text("invokeai_metadata", metadata.model_dump_json()) - if workflow is not None: - pnginfo.add_text("invokeai_workflow", workflow.model_dump_json()) - else: - # For uploaded images, we want to retain metadata. PIL strips it on save; manually add it back - # TODO: retain non-invokeai metadata on save... - original_metadata = image.info.get("invokeai_metadata", None) - if original_metadata is not None: - pnginfo.add_text("invokeai_metadata", original_metadata) - original_workflow = image.info.get("invokeai_workflow", None) - if original_workflow is not None: - pnginfo.add_text("invokeai_workflow", original_workflow) + if metadata is not None: + pnginfo.add_text("invokeai_metadata", metadata.model_dump_json()) + if workflow is not None: + pnginfo.add_text("invokeai_workflow", workflow.model_dump_json()) image.save( image_path, From f04462973b091f02ef15046cecfaf266de7ab0bb Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:23:09 +1100 Subject: [PATCH 050/119] feat(ui): create debounced metadata/workflow query hooks Also added config options for metadata and workflow debounce times (`metadataFetchDebounce` & `workflowFetchDebounce`). Falls back to 0 if not provided. In OSS, because we have no major latency concerns, the debounce is 0. But in other environments, it may be desirable to set this to something like 300ms. --- .../frontend/web/src/app/types/invokeai.ts | 2 ++ .../CurrentImage/CurrentImageButtons.tsx | 22 ++++++------------- .../SingleSelectionMenuItems.tsx | 19 ++++++---------- .../ImageMetadataViewer.tsx | 18 ++++----------- .../src/services/api/endpoints/workflows.ts | 1 - .../api/hooks/useDebouncedMetadata.ts | 21 ++++++++++++++++++ .../api/hooks/useDebouncedWorkflow.ts | 21 ++++++++++++++++++ 7 files changed, 62 insertions(+), 42 deletions(-) create mode 100644 invokeai/frontend/web/src/services/api/hooks/useDebouncedMetadata.ts create mode 100644 invokeai/frontend/web/src/services/api/hooks/useDebouncedWorkflow.ts diff --git a/invokeai/frontend/web/src/app/types/invokeai.ts b/invokeai/frontend/web/src/app/types/invokeai.ts index 39e4ffd27a..0fe7a36052 100644 --- a/invokeai/frontend/web/src/app/types/invokeai.ts +++ b/invokeai/frontend/web/src/app/types/invokeai.ts @@ -59,6 +59,8 @@ export type AppConfig = { nodesAllowlist: string[] | undefined; nodesDenylist: string[] | undefined; maxUpscalePixels?: number; + metadataFetchDebounce?: number; + workflowFetchDebounce?: number; sd: { defaultModel?: string; disabledControlNetModels: string[]; diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx index 4c0aa5e0e8..36a251952c 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx @@ -38,15 +38,12 @@ import { FaSeedling, } from 'react-icons/fa'; import { FaCircleNodes, FaEllipsis } from 'react-icons/fa6'; -import { - useGetImageDTOQuery, - useGetImageMetadataQuery, -} from 'services/api/endpoints/images'; +import { useGetImageDTOQuery } from 'services/api/endpoints/images'; +import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata'; +import { useDebouncedWorkflow } from 'services/api/hooks/useDebouncedWorkflow'; import { menuListMotionProps } from 'theme/components/menu'; -import { useDebounce } from 'use-debounce'; import { sentImageToImg2Img } from '../../store/actions'; import SingleSelectionMenuItems from '../ImageContextMenu/SingleSelectionMenuItems'; -import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; const currentImageButtonsSelector = createSelector( [stateSelector, activeTabNameSelector], @@ -105,17 +102,12 @@ const CurrentImageButtons = () => { lastSelectedImage?.image_name ?? skipToken ); - const [debouncedImageName] = useDebounce(lastSelectedImage?.image_name, 300); - const [debouncedWorkflowId] = useDebounce( - lastSelectedImage?.workflow_id, - 300 + const { metadata, isLoading: isLoadingMetadata } = useDebouncedMetadata( + lastSelectedImage?.image_name ); - const { data: metadata, isLoading: isLoadingMetadata } = - useGetImageMetadataQuery(debouncedImageName ?? skipToken); - - const { data: workflow, isLoading: isLoadingWorkflow } = useGetWorkflowQuery( - debouncedWorkflowId ?? skipToken + const { workflow, isLoading: isLoadingWorkflow } = useDebouncedWorkflow( + lastSelectedImage?.workflow_id ); const handleLoadWorkflow = useCallback(() => { diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 38de235e38..ed12eb5ff4 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -1,6 +1,5 @@ import { Flex, MenuItem, Spinner } from '@chakra-ui/react'; import { useStore } from '@nanostores/react'; -import { skipToken } from '@reduxjs/toolkit/dist/query'; import { useAppToaster } from 'app/components/Toaster'; import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { useAppDispatch } from 'app/store/storeHooks'; @@ -33,13 +32,12 @@ import { import { FaCircleNodes } from 'react-icons/fa6'; import { MdStar, MdStarBorder } from 'react-icons/md'; import { - useGetImageMetadataQuery, useStarImagesMutation, useUnstarImagesMutation, } from 'services/api/endpoints/images'; -import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; +import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata'; +import { useDebouncedWorkflow } from 'services/api/hooks/useDebouncedWorkflow'; import { ImageDTO } from 'services/api/types'; -import { useDebounce } from 'use-debounce'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; type SingleSelectionMenuItemsProps = { @@ -57,14 +55,11 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; const customStarUi = useStore($customStarUI); - const [debouncedImageName] = useDebounce(imageDTO?.image_name, 300); - const [debouncedWorkflowId] = useDebounce(imageDTO?.workflow_id, 300); - - const { data: metadata, isLoading: isLoadingMetadata } = - useGetImageMetadataQuery(debouncedImageName ?? skipToken); - - const { data: workflow, isLoading: isLoadingWorkflow } = useGetWorkflowQuery( - debouncedWorkflowId ?? skipToken + const { metadata, isLoading: isLoadingMetadata } = useDebouncedMetadata( + imageDTO?.image_name + ); + const { workflow, isLoading: isLoadingWorkflow } = useDebouncedWorkflow( + imageDTO?.workflow_id ); const [starImages] = useStarImagesMutation(); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx index f6820b9d20..29637e4a3c 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx @@ -9,15 +9,13 @@ import { Tabs, Text, } from '@chakra-ui/react'; -import { skipToken } from '@reduxjs/toolkit/dist/query'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useGetImageMetadataQuery } from 'services/api/endpoints/images'; -import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; +import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata'; +import { useDebouncedWorkflow } from 'services/api/hooks/useDebouncedWorkflow'; import { ImageDTO } from 'services/api/types'; -import { useDebounce } from 'use-debounce'; import DataViewer from './DataViewer'; import ImageMetadataActions from './ImageMetadataActions'; @@ -33,16 +31,8 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => { // }); const { t } = useTranslation(); - const [debouncedImageName] = useDebounce(image.image_name, 300); - const [debouncedWorkflowId] = useDebounce(image.workflow_id, 300); - - const { data: metadata } = useGetImageMetadataQuery( - debouncedImageName ?? skipToken - ); - - const { data: workflow } = useGetWorkflowQuery( - debouncedWorkflowId ?? skipToken - ); + const { metadata } = useDebouncedMetadata(image.image_name); + const { workflow } = useDebouncedWorkflow(image.workflow_id); return ( ({ getWorkflow: build.query({ query: (workflow_id) => `workflows/i/${workflow_id}`, - keepUnusedDataFor: 86400, // 24 hours providesTags: (result, error, workflow_id) => [ { type: 'Workflow', id: workflow_id }, ], diff --git a/invokeai/frontend/web/src/services/api/hooks/useDebouncedMetadata.ts b/invokeai/frontend/web/src/services/api/hooks/useDebouncedMetadata.ts new file mode 100644 index 0000000000..023b3c140c --- /dev/null +++ b/invokeai/frontend/web/src/services/api/hooks/useDebouncedMetadata.ts @@ -0,0 +1,21 @@ +import { skipToken } from '@reduxjs/toolkit/query'; +import { useDebounce } from 'use-debounce'; +import { useGetImageMetadataQuery } from '../endpoints/images'; +import { useAppSelector } from 'app/store/storeHooks'; + +export const useDebouncedMetadata = (imageName?: string | null) => { + const metadataFetchDebounce = useAppSelector( + (state) => state.config.metadataFetchDebounce + ); + + const [debouncedImageName] = useDebounce( + imageName, + metadataFetchDebounce ?? 0 + ); + + const { data: metadata, isLoading } = useGetImageMetadataQuery( + debouncedImageName ?? skipToken + ); + + return { metadata, isLoading }; +}; diff --git a/invokeai/frontend/web/src/services/api/hooks/useDebouncedWorkflow.ts b/invokeai/frontend/web/src/services/api/hooks/useDebouncedWorkflow.ts new file mode 100644 index 0000000000..2731597b2c --- /dev/null +++ b/invokeai/frontend/web/src/services/api/hooks/useDebouncedWorkflow.ts @@ -0,0 +1,21 @@ +import { skipToken } from '@reduxjs/toolkit/query'; +import { useAppSelector } from 'app/store/storeHooks'; +import { useDebounce } from 'use-debounce'; +import { useGetWorkflowQuery } from '../endpoints/workflows'; + +export const useDebouncedWorkflow = (workflowId?: string | null) => { + const workflowFetchDebounce = useAppSelector( + (state) => state.config.workflowFetchDebounce + ); + + const [debouncedWorkflowID] = useDebounce( + workflowId, + workflowFetchDebounce ?? 0 + ); + + const { data: workflow, isLoading } = useGetWorkflowQuery( + debouncedWorkflowID ?? skipToken + ); + + return { workflow, isLoading }; +}; From 91049799430b67cb3c86d42a5e33b4dc586bc357 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:24:07 +1100 Subject: [PATCH 051/119] chore(ui): regen types --- .../frontend/web/src/services/api/schema.d.ts | 298 +++++++++--------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 6092e822d6..5541fa20e9 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -419,7 +419,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -588,7 +588,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -646,7 +646,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -894,7 +894,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -945,7 +945,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1033,7 +1033,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1079,7 +1079,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1150,7 +1150,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1207,7 +1207,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1282,7 +1282,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1349,7 +1349,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1392,7 +1392,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1443,7 +1443,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1483,7 +1483,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1545,7 +1545,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1594,7 +1594,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1694,7 +1694,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -1832,7 +1832,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2019,7 +2019,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2088,7 +2088,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2144,7 +2144,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2261,7 +2261,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2302,11 +2302,11 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ use_cache?: boolean; /** @@ -2359,7 +2359,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2452,7 +2452,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2499,7 +2499,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2596,7 +2596,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2699,7 +2699,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2750,7 +2750,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2785,7 +2785,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2832,7 +2832,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2897,7 +2897,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -2942,7 +2942,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["InfillColorInvocation"]; + [key: string]: components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ImageMultiplyInvocation"]; }; /** * Edges @@ -2979,7 +2979,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ImageOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FaceMaskOutput"]; + [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["String2Output"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["FaceMaskOutput"]; }; /** * Errors @@ -3018,7 +3018,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3067,7 +3067,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3146,7 +3146,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3281,7 +3281,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3341,7 +3341,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3383,7 +3383,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3436,7 +3436,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3479,7 +3479,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3534,7 +3534,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3576,7 +3576,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3675,11 +3675,6 @@ export type components = { * @description The session ID that generated this image, if it is a generated image. */ session_id?: string | null; - /** - * Workflow Id - * @description The workflow that generated this image. - */ - workflow_id?: string | null; /** * Node Id * @description The node ID that generated this image, if it is a generated image. @@ -3695,6 +3690,11 @@ export type components = { * @description The id of the board the image belongs to, if one exists. */ board_id?: string | null; + /** + * Workflow Id + * @description The workflow that generated this image. + */ + workflow_id?: string | null; }; /** * ImageField @@ -3726,7 +3726,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3767,7 +3767,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3810,7 +3810,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3845,7 +3845,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3892,7 +3892,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3929,7 +3929,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -3988,7 +3988,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4075,7 +4075,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4129,7 +4129,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4173,7 +4173,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4243,7 +4243,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4300,7 +4300,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4345,7 +4345,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4393,7 +4393,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4435,7 +4435,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4486,7 +4486,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4521,7 +4521,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4614,7 +4614,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4675,7 +4675,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4706,7 +4706,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4773,7 +4773,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4832,7 +4832,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4881,7 +4881,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4946,7 +4946,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -4993,7 +4993,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5115,7 +5115,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5202,7 +5202,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5237,7 +5237,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5274,7 +5274,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5329,7 +5329,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5370,7 +5370,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5418,7 +5418,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5490,7 +5490,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5537,7 +5537,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5605,7 +5605,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5652,7 +5652,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5768,7 +5768,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5827,7 +5827,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5907,7 +5907,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -5954,7 +5954,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6016,7 +6016,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6102,7 +6102,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6231,7 +6231,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6266,7 +6266,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6319,7 +6319,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6374,7 +6374,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6441,11 +6441,11 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ use_cache?: boolean; /** @@ -6488,11 +6488,11 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ use_cache?: boolean; /** @@ -6529,11 +6529,11 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ use_cache?: boolean; /** @@ -6581,7 +6581,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6628,7 +6628,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6683,7 +6683,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6747,7 +6747,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6788,7 +6788,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6869,7 +6869,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -6951,7 +6951,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7014,7 +7014,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7077,7 +7077,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7139,11 +7139,11 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ use_cache?: boolean; /** @description The image to process */ @@ -7172,7 +7172,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7221,7 +7221,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7277,7 +7277,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7354,7 +7354,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7593,7 +7593,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7780,7 +7780,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7890,7 +7890,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7941,7 +7941,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -7976,7 +7976,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8017,7 +8017,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8103,7 +8103,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8156,7 +8156,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8197,7 +8197,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8237,7 +8237,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8310,7 +8310,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8440,7 +8440,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8530,7 +8530,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8623,7 +8623,7 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean | null; + is_intermediate?: boolean; /** * Use Cache * @description Whether or not to use the cache @@ -8728,11 +8728,11 @@ export type components = { ui_order: number | null; }; /** - * StableDiffusionOnnxModelFormat + * StableDiffusion2ModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * CLIPVisionModelFormat * @description An enumeration. @@ -8740,11 +8740,23 @@ export type components = { */ CLIPVisionModelFormat: "diffusers"; /** - * ControlNetModelFormat + * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ - ControlNetModelFormat: "checkpoint" | "diffusers"; + StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusionOnnxModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** * IPAdapterModelFormat * @description An enumeration. @@ -8752,29 +8764,17 @@ export type components = { */ IPAdapterModelFormat: "invokeai"; /** - * StableDiffusion2ModelFormat + * ControlNetModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusionXLModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + ControlNetModelFormat: "checkpoint" | "diffusers"; /** * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ T2IAdapterModelFormat: "diffusers"; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; From b5940039f3051c3b9ed0474b6428ac1981e06893 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:24:21 +1100 Subject: [PATCH 052/119] chore: lint --- invokeai/app/api/dependencies.py | 2 +- invokeai/app/api/routers/images.py | 6 +----- invokeai/app/services/invocation_services.py | 2 +- .../workflow_image_records/workflow_image_records_sqlite.py | 2 +- tests/nodes/test_nodes.py | 1 - 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index 4746eeae3f..e7c8fa7fae 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -1,8 +1,8 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) from logging import Logger -from invokeai.app.services.workflow_image_records.workflow_image_records_sqlite import SqliteWorkflowImageRecordsStorage +from invokeai.app.services.workflow_image_records.workflow_image_records_sqlite import SqliteWorkflowImageRecordsStorage from invokeai.backend.util.logging import InvokeAILogger from invokeai.version.invokeai_version import __version__ diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index a57414e17f..e8c8c693b3 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -8,11 +8,7 @@ from fastapi.routing import APIRouter from PIL import Image from pydantic import BaseModel, Field, ValidationError -from invokeai.app.invocations.baseinvocation import ( - MetadataField, - MetadataFieldValidator, - WorkflowFieldValidator, -) +from invokeai.app.invocations.baseinvocation import MetadataField, MetadataFieldValidator, WorkflowFieldValidator from invokeai.app.services.image_records.image_records_common import ImageCategory, ImageRecordChanges, ResourceOrigin from invokeai.app.services.images.images_common import ImageDTO, ImageUrlsDTO from invokeai.app.services.shared.pagination import OffsetPaginatedResults diff --git a/invokeai/app/services/invocation_services.py b/invokeai/app/services/invocation_services.py index 804b1b6884..d405201f4e 100644 --- a/invokeai/app/services/invocation_services.py +++ b/invokeai/app/services/invocation_services.py @@ -27,8 +27,8 @@ if TYPE_CHECKING: from .session_queue.session_queue_base import SessionQueueBase from .shared.graph import GraphExecutionState, LibraryGraph from .urls.urls_base import UrlServiceBase - from .workflow_records.workflow_records_base import WorkflowRecordsStorageBase from .workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase + from .workflow_records.workflow_records_base import WorkflowRecordsStorageBase class InvocationServices: diff --git a/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py index 1a5de672bc..912d80cbf6 100644 --- a/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py +++ b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py @@ -1,8 +1,8 @@ import sqlite3 import threading from typing import Optional, cast -from invokeai.app.services.shared.sqlite import SqliteDatabase +from invokeai.app.services.shared.sqlite import SqliteDatabase from invokeai.app.services.workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase diff --git a/tests/nodes/test_nodes.py b/tests/nodes/test_nodes.py index 1d7f2e4194..51b33dd4c7 100644 --- a/tests/nodes/test_nodes.py +++ b/tests/nodes/test_nodes.py @@ -1,6 +1,5 @@ from typing import Any, Callable, Union - from invokeai.app.invocations.baseinvocation import ( BaseInvocation, BaseInvocationOutput, From 16dacb5f430072a2b86feb7983d8055264fda82a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:36:29 +1100 Subject: [PATCH 053/119] fix(nodes): remove constraints on ip adapter metadata fields --- invokeai/app/invocations/metadata.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 98f5f0e830..1ed399873b 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -43,16 +43,10 @@ class IPAdapterMetadataField(BaseModel): description="The IP-Adapter model.", ) weight: Union[float, list[float]] = Field( - default=1, - ge=0, description="The weight given to the IP-Adapter", ) - begin_step_percent: float = Field( - default=0, ge=-1, le=2, description="When the IP-Adapter is first applied (% of total steps)" - ) - end_step_percent: float = Field( - default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)" - ) + 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)") @invocation_output("metadata_item_output") From 52fbd1b222866ba151a7c6b4044d17e063e2fd59 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:18:06 +1100 Subject: [PATCH 054/119] fix(ui): remove errant comment --- .../src/features/nodes/util/graphBuilders/buildNodesGraph.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts index 4437e14f66..eb782f456a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildNodesGraph.ts @@ -35,7 +35,6 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => { const { nodes, edges } = nodesState; const filteredNodes = nodes.filter(isInvocationNode); - // const workflowJSON = JSON.stringify(buildWorkflow(nodesState)); // Reduce the node editor nodes into invocation graph nodes const parsedNodes = filteredNodes.reduce>( @@ -68,7 +67,6 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => { if (embedWorkflow) { // add the workflow to the node - // Object.assign(graphNode, { workflow: workflowJSON }); Object.assign(graphNode, { workflow: buildWorkflow(nodesState) }); } From 301a8fef92d15d485be5b20b9c8d4a6b65729624 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:33:17 +1100 Subject: [PATCH 055/119] fix(ui): fix batch metadata logic when graph has no metadata On canvas, images have no metadata yet, so this needs to be handled --- .../graphBuilders/buildLinearBatchConfig.ts | 74 +++++++++++-------- .../nodes/util/graphBuilders/metadata.ts | 8 ++ 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts index 8bf9a2785a..59f8d4123f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearBatchConfig.ts @@ -11,7 +11,7 @@ import { NOISE, POSITIVE_CONDITIONING, } from './constants'; -import { removeMetadata } from './metadata'; +import { getHasMetadata, removeMetadata } from './metadata'; export const prepareLinearUIBatch = ( state: RootState, @@ -40,13 +40,15 @@ export const prepareLinearUIBatch = ( }); } - // add to metadata - removeMetadata(graph, 'seed'); - zipped.push({ - node_path: METADATA, - field_name: 'seed', - items: seeds, - }); + if (getHasMetadata(graph)) { + // add to metadata + removeMetadata(graph, 'seed'); + zipped.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); + } if (graph.nodes[CANVAS_COHERENCE_NOISE]) { zipped.push({ @@ -78,12 +80,14 @@ export const prepareLinearUIBatch = ( } // add to metadata - removeMetadata(graph, 'seed'); - firstBatchDatumList.push({ - node_path: METADATA, - field_name: 'seed', - items: seeds, - }); + if (getHasMetadata(graph)) { + removeMetadata(graph, 'seed'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); + } if (graph.nodes[CANVAS_COHERENCE_NOISE]) { firstBatchDatumList.push({ @@ -108,12 +112,14 @@ export const prepareLinearUIBatch = ( } // add to metadata - removeMetadata(graph, 'seed'); - secondBatchDatumList.push({ - node_path: METADATA, - field_name: 'seed', - items: seeds, - }); + if (getHasMetadata(graph)) { + removeMetadata(graph, 'seed'); + secondBatchDatumList.push({ + node_path: METADATA, + field_name: 'seed', + items: seeds, + }); + } if (graph.nodes[CANVAS_COHERENCE_NOISE]) { secondBatchDatumList.push({ @@ -140,12 +146,14 @@ export const prepareLinearUIBatch = ( } // add to metadata - removeMetadata(graph, 'positive_prompt'); - firstBatchDatumList.push({ - node_path: METADATA, - field_name: 'positive_prompt', - items: extendedPrompts, - }); + if (getHasMetadata(graph)) { + removeMetadata(graph, 'positive_prompt'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'positive_prompt', + items: extendedPrompts, + }); + } if (shouldConcatSDXLStylePrompt && model?.base_model === 'sdxl') { const stylePrompts = extendedPrompts.map((p) => @@ -161,12 +169,14 @@ export const prepareLinearUIBatch = ( } // add to metadata - removeMetadata(graph, 'positive_style_prompt'); - firstBatchDatumList.push({ - node_path: METADATA, - field_name: 'positive_style_prompt', - items: extendedPrompts, - }); + if (getHasMetadata(graph)) { + removeMetadata(graph, 'positive_style_prompt'); + firstBatchDatumList.push({ + node_path: METADATA, + field_name: 'positive_style_prompt', + items: extendedPrompts, + }); + } } data.push(firstBatchDatumList); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts index 547c45addf..5cc397ce68 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts @@ -56,3 +56,11 @@ export const removeMetadata = ( delete metadataNode[key]; }; + +export const getHasMetadata = (graph: NonNullableGraph): boolean => { + const metadataNode = graph.nodes[METADATA] as + | CoreMetadataInvocation + | undefined; + + return Boolean(metadataNode); +}; From 2f4f83280b7240a1aeeddc09a3395b32c19185f3 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 19 Oct 2023 07:37:28 +1100 Subject: [PATCH 056/119] fix(db): remove extraneous conflict handling in workflow image records --- .../workflow_image_records/workflow_image_records_sqlite.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py index 912d80cbf6..ec7a73f1d5 100644 --- a/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py +++ b/invokeai/app/services/workflow_image_records/workflow_image_records_sqlite.py @@ -85,10 +85,9 @@ class SqliteWorkflowImageRecordsStorage(WorkflowImageRecordsStorageBase): self._cursor.execute( """--sql INSERT INTO workflow_images (workflow_id, image_name) - VALUES (?, ?) - ON CONFLICT (image_name) DO UPDATE SET workflow_id = ?; + VALUES (?, ?); """, - (workflow_id, image_name, workflow_id), + (workflow_id, image_name), ) self._conn.commit() except sqlite3.Error as e: From c071262c20b7912e6d262a54097806e16ad226f9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 19 Oct 2023 08:16:28 +1100 Subject: [PATCH 057/119] fix(ui): remove getMetadataFromFile query & util This will all be handled by python going forward --- .../getMetadataAndWorkflowFromImageBlob.ts | 45 ------------ .../web/src/services/api/endpoints/images.ts | 72 +------------------ 2 files changed, 1 insertion(+), 116 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts diff --git a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts deleted file mode 100644 index b46a701757..0000000000 --- a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as png from '@stevebel/png'; -import { logger } from 'app/logging/logger'; -import { parseify } from 'common/util/serialize'; -import { - ImageMetadataAndWorkflow, - zCoreMetadata, - zWorkflow, -} from 'features/nodes/types/types'; -import { get } from 'lodash-es'; - -export const getMetadataAndWorkflowFromImageBlob = async ( - image: Blob -): Promise => { - const data: ImageMetadataAndWorkflow = {}; - const buffer = await image.arrayBuffer(); - const text = png.decode(buffer).text; - - const rawMetadata = get(text, 'invokeai_metadata'); - if (rawMetadata) { - const metadataResult = zCoreMetadata.safeParse(JSON.parse(rawMetadata)); - if (metadataResult.success) { - data.metadata = metadataResult.data; - } else { - logger('system').error( - { error: parseify(metadataResult.error) }, - 'Problem reading metadata from image' - ); - } - } - - const rawWorkflow = get(text, 'invokeai_workflow'); - if (rawWorkflow) { - const workflowResult = zWorkflow.safeParse(JSON.parse(rawWorkflow)); - if (workflowResult.success) { - data.workflow = workflowResult.data; - } else { - logger('system').error( - { error: parseify(workflowResult.error) }, - 'Problem reading workflow from image' - ); - } - } - - return data; -}; diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index 36c00ee1c9..166d00a3db 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -1,5 +1,4 @@ import { EntityState, Update } from '@reduxjs/toolkit'; -import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query'; import { PatchCollection } from '@reduxjs/toolkit/dist/query/core/buildThunks'; import { logger } from 'app/logging/logger'; import { @@ -8,15 +7,9 @@ import { IMAGE_CATEGORIES, IMAGE_LIMIT, } from 'features/gallery/store/types'; -import { - CoreMetadata, - ImageMetadataAndWorkflow, - zCoreMetadata, -} from 'features/nodes/types/types'; -import { getMetadataAndWorkflowFromImageBlob } from 'features/nodes/util/getMetadataAndWorkflowFromImageBlob'; +import { CoreMetadata, zCoreMetadata } from 'features/nodes/types/types'; import { keyBy } from 'lodash-es'; import { ApiTagDescription, LIST_TAG, api } from '..'; -import { $authToken, $projectId } from '../client'; import { components, paths } from '../schema'; import { DeleteBoardResult, @@ -135,68 +128,6 @@ export const imagesApi = api.injectEndpoints({ }, keepUnusedDataFor: 86400, // 24 hours }), - getImageMetadataFromFile: build.query< - ImageMetadataAndWorkflow, - { image: ImageDTO; shouldFetchMetadataFromApi: boolean } - >({ - queryFn: async ( - args: { image: ImageDTO; shouldFetchMetadataFromApi: boolean }, - api, - extraOptions, - fetchWithBaseQuery - ) => { - if (args.shouldFetchMetadataFromApi) { - let metadata; - const metadataResponse = await fetchWithBaseQuery( - `images/i/${args.image.image_name}/metadata` - ); - if (metadataResponse.data) { - const metadataResult = zCoreMetadata.safeParse( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (metadataResponse.data as any)?.metadata - ); - if (metadataResult.success) { - metadata = metadataResult.data; - } - } - return { data: { metadata } }; - } else { - const authToken = $authToken.get(); - const projectId = $projectId.get(); - const customBaseQuery = fetchBaseQuery({ - baseUrl: '', - prepareHeaders: (headers) => { - if (authToken) { - headers.set('Authorization', `Bearer ${authToken}`); - } - if (projectId) { - headers.set('project-id', projectId); - } - - return headers; - }, - responseHandler: async (res) => { - return await res.blob(); - }, - }); - - const response = await customBaseQuery( - args.image.image_url, - api, - extraOptions - ); - const data = await getMetadataAndWorkflowFromImageBlob( - response.data as Blob - ); - - return { data }; - } - }, - providesTags: (result, error, { image }) => [ - { type: 'ImageMetadataFromFile', id: image.image_name }, - ], - keepUnusedDataFor: 86400, // 24 hours - }), deleteImage: build.mutation({ query: ({ image_name }) => ({ url: `images/i/${image_name}`, @@ -1643,6 +1574,5 @@ export const { useDeleteBoardMutation, useStarImagesMutation, useUnstarImagesMutation, - useGetImageMetadataFromFileQuery, useBulkDownloadImagesMutation, } = imagesApi; From dcd11327c1105715b52b6ccb2e13ff1edf2dd956 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 20 Oct 2023 11:41:05 +1100 Subject: [PATCH 058/119] fix(db): remove unused, commented out methods --- .../workflow_records_sqlite.py | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/invokeai/app/services/workflow_records/workflow_records_sqlite.py b/invokeai/app/services/workflow_records/workflow_records_sqlite.py index 2d9e1f26e8..e9e2bdca3a 100644 --- a/invokeai/app/services/workflow_records/workflow_records_sqlite.py +++ b/invokeai/app/services/workflow_records/workflow_records_sqlite.py @@ -100,46 +100,3 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase): raise finally: self._lock.release() - - # def update(self, workflow_id: str, workflow: Workflow) -> Workflow: - # """Updates a workflow record.""" - # try: - # workflow_id = workflow.get("id", None) - # if type(workflow_id) is not str: - # raise WorkflowNotFoundError(f"Workflow does not have a valid id, got {workflow_id}") - # self._lock.acquire() - # self._cursor.execute( - # """--sql - # UPDATE workflows - # SET workflow = ? - # WHERE workflow_id = ? - # """, - # (workflow, workflow_id), - # ) - # self._conn.commit() - # except Exception: - # self._conn.rollback() - # raise - # finally: - # self._lock.release() - # return self.get(workflow_id) - - # def delete(self, workflow_id: str) -> Workflow: - # """Updates a workflow record.""" - # workflow = self.get(workflow_id) - # try: - # self._lock.acquire() - # self._cursor.execute( - # """--sql - # DELETE FROM workflows - # WHERE workflow_id = ? - # """, - # (workflow_id,), - # ) - # self._conn.commit() - # except Exception: - # self._conn.rollback() - # raise - # finally: - # self._lock.release() - # return workflow From b7f63a40653bb92ab4dd128e154fac18aa8a30e9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:58:53 +1100 Subject: [PATCH 059/119] fix(ui): fix canvas color picker when value is zero good ol' zero is false-y --- .../web/src/features/canvas/hooks/useColorUnderCursor.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts index 0ade036987..5bdc59d345 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts @@ -37,7 +37,12 @@ const useColorPicker = () => { 1 ).data; - if (!(a && r && g && b)) { + if ( + r === undefined || + g === undefined || + b === undefined || + a === undefined + ) { return; } From 8604943e89fb26c2c74ef9c4b4501e4b1a4a4dbd Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:51:55 +1100 Subject: [PATCH 060/119] feat(nodes): simple custom nodes Custom nodes may be places in `$INVOKEAI_ROOT/nodes/` (configurable with `custom_nodes_dir` option). On app startup, an `__init__.py` is copied into the custom nodes dir, which recursively loads all python files in the directory as modules (files starting with `_` are ignored). The custom nodes dir is now a python module itself. When we `from invocations import *` to load init all invocations, we load the custom nodes dir, registering all custom nodes. --- invokeai/app/invocations/__init__.py | 29 ++++++++++++--- .../app/invocations/_custom_nodes_init.py | 37 +++++++++++++++++++ .../app/services/config/config_default.py | 8 ++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 invokeai/app/invocations/_custom_nodes_init.py diff --git a/invokeai/app/invocations/__init__.py b/invokeai/app/invocations/__init__.py index 6407a1cdee..91a2edc680 100644 --- a/invokeai/app/invocations/__init__.py +++ b/invokeai/app/invocations/__init__.py @@ -1,8 +1,25 @@ -import os +import shutil +import sys +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path -__all__ = [] +from invokeai.app.services.config.config_default import InvokeAIAppConfig -dirname = os.path.dirname(os.path.abspath(__file__)) -for f in os.listdir(dirname): - if f != "__init__.py" and os.path.isfile("%s/%s" % (dirname, f)) and f[-3:] == ".py": - __all__.append(f[:-3]) +custom_nodes_path = Path(InvokeAIAppConfig.get_config().custom_nodes_path.absolute()) +custom_nodes_path.mkdir(parents=True, exist_ok=True) +custom_nodes_init_path = str(custom_nodes_path / "__init__.py") + +# copy our custom nodes __init__.py to the custom nodes directory +shutil.copy(Path(__file__).parent / "_custom_nodes_init.py", custom_nodes_init_path) + +# Import custom nodes, see https://docs.python.org/3/library/importlib.html#importing-programmatically +spec = spec_from_file_location("custom_nodes", custom_nodes_init_path) +if spec is None or spec.loader is None: + raise RuntimeError(f"Could not load custom nodes from {custom_nodes_init_path}") +module = module_from_spec(spec) +sys.modules[spec.name] = module +spec.loader.exec_module(module) + +# add core nodes to __all__ +python_files = filter(lambda f: not f.name.startswith("_"), Path(__file__).parent.rglob("*.py")) +__all__ = list(f.stem for f in python_files) # type: ignore diff --git a/invokeai/app/invocations/_custom_nodes_init.py b/invokeai/app/invocations/_custom_nodes_init.py new file mode 100644 index 0000000000..561f6de382 --- /dev/null +++ b/invokeai/app/invocations/_custom_nodes_init.py @@ -0,0 +1,37 @@ +""" +InvokeAI custom nodes initialization + +This file is responsible for loading all custom nodes from this directory. + +All python files are loaded on app startup. Custom nodes will be initialized and available for use +in workflows. + +The app must be restarted for changes to be picked up. + +This file is overwritten on launch. Do not edit this file directly. +""" +import sys +from importlib import import_module +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path + +from invokeai.backend.util.logging import InvokeAILogger + +logger = InvokeAILogger.get_logger() +count = 0 +for f in Path(__file__).parent.rglob("*.py"): + module_name = f.stem + if (not module_name.startswith("_")) and (module_name not in globals()): + spec = spec_from_file_location(module_name, f.absolute()) + if spec is None or spec.loader is None: + logger.warn(f"Could not load {f}") + continue + module = module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + count += 1 + del f, module_name + +logger.info(f"Loaded {count} modules from {Path(__file__).parent}") + +del import_module, Path diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index df01b65882..a877c465d2 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -243,6 +243,7 @@ class InvokeAIAppConfig(InvokeAISettings): db_dir : Optional[Path] = Field(default=Path('databases'), description='Path to InvokeAI databases directory', json_schema_extra=Categories.Paths) outdir : Optional[Path] = Field(default=Path('outputs'), description='Default folder for output images', json_schema_extra=Categories.Paths) use_memory_db : bool = Field(default=False, description='Use in-memory database for storing image metadata', json_schema_extra=Categories.Paths) + custom_nodes_dir : Path = Field(default=Path('nodes'), description='Path to directory for custom nodes', json_schema_extra=Categories.Paths) from_file : Optional[Path] = Field(default=None, description='Take command input from the indicated file (command-line client only)', json_schema_extra=Categories.Paths) # LOGGING @@ -410,6 +411,13 @@ class InvokeAIAppConfig(InvokeAISettings): """ return self._resolve(self.models_dir) + @property + def custom_nodes_path(self) -> Path: + """ + Path to the custom nodes directory + """ + return self._resolve(self.custom_nodes_dir) + # the following methods support legacy calls leftover from the Globals era @property def full_precision(self) -> bool: From 824702de99a09d18e5fae065bda2cc67568908f2 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:50:55 +1100 Subject: [PATCH 061/119] feat(nodes): change expected structure for custom nodes --- invokeai/app/invocations/__init__.py | 7 ++- .../app/invocations/_custom_nodes_init.py | 37 -------------- .../app/invocations/custom_nodes/README.md | 51 +++++++++++++++++++ invokeai/app/invocations/custom_nodes/init.py | 51 +++++++++++++++++++ 4 files changed, 107 insertions(+), 39 deletions(-) delete mode 100644 invokeai/app/invocations/_custom_nodes_init.py create mode 100644 invokeai/app/invocations/custom_nodes/README.md create mode 100644 invokeai/app/invocations/custom_nodes/init.py diff --git a/invokeai/app/invocations/__init__.py b/invokeai/app/invocations/__init__.py index 91a2edc680..32cf73d215 100644 --- a/invokeai/app/invocations/__init__.py +++ b/invokeai/app/invocations/__init__.py @@ -7,10 +7,13 @@ from invokeai.app.services.config.config_default import InvokeAIAppConfig custom_nodes_path = Path(InvokeAIAppConfig.get_config().custom_nodes_path.absolute()) custom_nodes_path.mkdir(parents=True, exist_ok=True) + custom_nodes_init_path = str(custom_nodes_path / "__init__.py") +custom_nodes_readme_path = str(custom_nodes_path / "README.md") # copy our custom nodes __init__.py to the custom nodes directory -shutil.copy(Path(__file__).parent / "_custom_nodes_init.py", custom_nodes_init_path) +shutil.copy(Path(__file__).parent / "custom_nodes/init.py", custom_nodes_init_path) +shutil.copy(Path(__file__).parent / "custom_nodes/README.md", custom_nodes_readme_path) # Import custom nodes, see https://docs.python.org/3/library/importlib.html#importing-programmatically spec = spec_from_file_location("custom_nodes", custom_nodes_init_path) @@ -21,5 +24,5 @@ sys.modules[spec.name] = module spec.loader.exec_module(module) # add core nodes to __all__ -python_files = filter(lambda f: not f.name.startswith("_"), Path(__file__).parent.rglob("*.py")) +python_files = filter(lambda f: not f.name.startswith("_"), Path(__file__).parent.glob("*.py")) __all__ = list(f.stem for f in python_files) # type: ignore diff --git a/invokeai/app/invocations/_custom_nodes_init.py b/invokeai/app/invocations/_custom_nodes_init.py deleted file mode 100644 index 561f6de382..0000000000 --- a/invokeai/app/invocations/_custom_nodes_init.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -InvokeAI custom nodes initialization - -This file is responsible for loading all custom nodes from this directory. - -All python files are loaded on app startup. Custom nodes will be initialized and available for use -in workflows. - -The app must be restarted for changes to be picked up. - -This file is overwritten on launch. Do not edit this file directly. -""" -import sys -from importlib import import_module -from importlib.util import module_from_spec, spec_from_file_location -from pathlib import Path - -from invokeai.backend.util.logging import InvokeAILogger - -logger = InvokeAILogger.get_logger() -count = 0 -for f in Path(__file__).parent.rglob("*.py"): - module_name = f.stem - if (not module_name.startswith("_")) and (module_name not in globals()): - spec = spec_from_file_location(module_name, f.absolute()) - if spec is None or spec.loader is None: - logger.warn(f"Could not load {f}") - continue - module = module_from_spec(spec) - sys.modules[spec.name] = module - spec.loader.exec_module(module) - count += 1 - del f, module_name - -logger.info(f"Loaded {count} modules from {Path(__file__).parent}") - -del import_module, Path diff --git a/invokeai/app/invocations/custom_nodes/README.md b/invokeai/app/invocations/custom_nodes/README.md new file mode 100644 index 0000000000..d93bb65539 --- /dev/null +++ b/invokeai/app/invocations/custom_nodes/README.md @@ -0,0 +1,51 @@ +# Custom Nodes / Node Packs + +Copy your node packs to this directory. + +When nodes are added or changed, you must restart the app to see the changes. + +## Directory Structure + +For a node pack to be loaded, it must be placed in a directory alongside this +file. Here's an example structure: + +```py +. +├── __init__.py # Invoke-managed custom node loader +│ +├── cool_node +│ ├── __init__.py # see example below +│ └── cool_node.py +│ +└── my_node_pack + ├── __init__.py # see example below + ├── tasty_node.py + ├── bodacious_node.py + ├── utils.py + └── extra_nodes + └── fancy_node.py +``` + +## Node Pack `__init__.py` + +Each node pack must have an `__init__.py` file that imports its nodes. + +The structure of each node or node pack is otherwise not important. + +Here are examples, based on the example directory structure. + +### `cool_node/__init__.py` + +```py +from .cool_node import CoolInvocation +``` + +### `my_node_pack/__init__.py` + +```py +from .tasty_node import TastyInvocation +from .bodacious_node import BodaciousInvocation +from .extra_nodes.fancy_node import FancyInvocation +``` + +Only nodes imported in the `__init__.py` file are loaded. diff --git a/invokeai/app/invocations/custom_nodes/init.py b/invokeai/app/invocations/custom_nodes/init.py new file mode 100644 index 0000000000..c6708e95a7 --- /dev/null +++ b/invokeai/app/invocations/custom_nodes/init.py @@ -0,0 +1,51 @@ +""" +Invoke-managed custom node loader. See README.md for more information. +""" + +import sys +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path + +from invokeai.backend.util.logging import InvokeAILogger + +logger = InvokeAILogger.get_logger() +loaded_count = 0 + + +for d in Path(__file__).parent.iterdir(): + # skip files + if not d.is_dir(): + continue + + # skip hidden directories + if d.name.startswith("_") or d.name.startswith("."): + continue + + # skip directories without an `__init__.py` + init = d / "__init__.py" + if not init.exists(): + continue + + module_name = init.parent.stem + + # skip if already imported + if module_name in globals(): + continue + + # we have a legit module to import + spec = spec_from_file_location(module_name, init.absolute()) + + if spec is None or spec.loader is None: + logger.warn(f"Could not load {init}") + continue + + module = module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + + loaded_count += 1 + + del init, module_name + + +logger.info(f"Loaded {loaded_count} modules from {Path(__file__).parent}") From 3d33b3e1f5e81a76dba69d9d9446463ae7772346 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 20 Oct 2023 15:18:29 +1100 Subject: [PATCH 062/119] fix(nodes): explicitly include custom nodes files setuptools ignores markdown files - explicitly include all files in `"invokeai.app.invocations"` to ensure all custom node files are included --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2bcaea2efa..693d4c9ed1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,6 +171,7 @@ version = { attr = "invokeai.version.__version__" } "invokeai.configs" = ["*.example", "**/*.yaml", "*.txt"] "invokeai.frontend.web.dist" = ["**"] "invokeai.frontend.web.static" = ["**"] +"invokeai.app.invocations" = ["**"] #=== Begin: PyTest and Coverage [tool.pytest.ini_options] From eeeb5dc4513515a16a7a4019cebd66228e332e2e Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 20 Oct 2023 04:11:01 +0000 Subject: [PATCH 063/119] translationBot(ui): update translation (Dutch) Currently translated at 99.9% (1216 of 1217 strings) Co-authored-by: Dennis Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/nl/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/nl.json | 114 +++++++++---------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/invokeai/frontend/web/public/locales/nl.json b/invokeai/frontend/web/public/locales/nl.json index 5c08f65d21..2d50a602d1 100644 --- a/invokeai/frontend/web/public/locales/nl.json +++ b/invokeai/frontend/web/public/locales/nl.json @@ -106,9 +106,9 @@ "allImagesLoaded": "Alle afbeeldingen geladen", "loadMore": "Laad meer", "noImagesInGallery": "Geen afbeeldingen om te tonen", - "deleteImage": "Wis afbeelding", - "deleteImageBin": "Gewiste afbeeldingen worden naar de prullenbak van je besturingssysteem gestuurd.", - "deleteImagePermanent": "Gewiste afbeeldingen kunnen niet worden hersteld.", + "deleteImage": "Verwijder afbeelding", + "deleteImageBin": "Verwijderde afbeeldingen worden naar de prullenbak van je besturingssysteem gestuurd.", + "deleteImagePermanent": "Verwijderde afbeeldingen kunnen niet worden hersteld.", "assets": "Eigen onderdelen", "images": "Afbeeldingen", "autoAssignBoardOnClick": "Ken automatisch bord toe bij klikken", @@ -386,11 +386,11 @@ "deleteModel": "Verwijder model", "deleteConfig": "Verwijder configuratie", "deleteMsg1": "Weet je zeker dat je dit model wilt verwijderen uit InvokeAI?", - "deleteMsg2": "Hiermee ZAL het model van schijf worden verwijderd als het zich bevindt in de InvokeAI-beginmap. Als je het model vanaf een eigen locatie gebruikt, dan ZAL het model NIET van schijf worden verwijderd.", + "deleteMsg2": "Hiermee ZAL het model van schijf worden verwijderd als het zich bevindt in de beginmap van InvokeAI. Als je het model vanaf een eigen locatie gebruikt, dan ZAL het model NIET van schijf worden verwijderd.", "formMessageDiffusersVAELocationDesc": "Indien niet opgegeven, dan zal InvokeAI kijken naar het VAE-bestand in de hierboven gegeven modellocatie.", "repoIDValidationMsg": "Online repository van je model", "formMessageDiffusersModelLocation": "Locatie Diffusers-model", - "convertToDiffusersHelpText3": "Je checkpoint-bestand op schijf ZAL worden verwijderd als het zich in de InvokeAI root map bevindt. Het zal NIET worden verwijderd als het zich in een andere locatie bevindt.", + "convertToDiffusersHelpText3": "Je checkpoint-bestand op de schijf ZAL worden verwijderd als het zich in de beginmap van InvokeAI bevindt. Het ZAL NIET worden verwijderd als het zich in een andere locatie bevindt.", "convertToDiffusersHelpText6": "Wil je dit model omzetten?", "allModels": "Alle modellen", "checkpointModels": "Checkpoints", @@ -458,11 +458,11 @@ "noCustomLocationProvided": "Geen Aangepaste Locatie Opgegeven", "syncModels": "Synchroniseer Modellen", "modelsSynced": "Modellen Gesynchroniseerd", - "modelSyncFailed": "Synchronisatie Modellen Gefaald", + "modelSyncFailed": "Synchronisatie modellen mislukt", "modelDeleteFailed": "Model kon niet verwijderd worden", "convertingModelBegin": "Model aan het converteren. Even geduld.", "importModels": "Importeer Modellen", - "syncModelsDesc": "Als je modellen niet meer synchroon zijn met de backend, kan je ze met deze optie verversen. Dit wordt typisch gebruikt in het geval je het models.yaml bestand met de hand bewerkt of als je modellen aan de InvokeAI root map toevoegt nadat de applicatie gestart werd.", + "syncModelsDesc": "Als je modellen niet meer synchroon zijn met de backend, kan je ze met deze optie vernieuwen. Dit wordt meestal gebruikt in het geval je het bestand models.yaml met de hand bewerkt of als je modellen aan de beginmap van InvokeAI toevoegt nadat de applicatie gestart is.", "loraModels": "LoRA's", "onnxModels": "Onnx", "oliveModels": "Olives", @@ -615,14 +615,14 @@ "resetWebUI": "Herstel web-UI", "resetWebUIDesc1": "Herstel web-UI herstelt alleen de lokale afbeeldingscache en de onthouden instellingen van je browser. Het verwijdert geen afbeeldingen van schijf.", "resetWebUIDesc2": "Als afbeeldingen niet getoond worden in de galerij of iets anders werkt niet, probeer dan eerst deze herstelfunctie voordat je een fout aanmeldt op GitHub.", - "resetComplete": "Webgebruikersinterface is hersteld.", + "resetComplete": "Webinterface is hersteld.", "useSlidersForAll": "Gebruik schuifbalken voor alle opties", - "consoleLogLevel": "Logboekniveau", + "consoleLogLevel": "Niveau logboek", "shouldLogToConsole": "Schrijf logboek naar console", "developer": "Ontwikkelaar", "general": "Algemeen", "showProgressInViewer": "Toon voortgangsafbeeldingen in viewer", - "generation": "Generatie", + "generation": "Genereren", "ui": "Gebruikersinterface", "antialiasProgressImages": "Voer anti-aliasing uit op voortgangsafbeeldingen", "showAdvancedOptions": "Toon uitgebreide opties", @@ -631,16 +631,16 @@ "beta": "Bèta", "experimental": "Experimenteel", "alternateCanvasLayout": "Omwisselen Canvas Layout", - "enableNodesEditor": "Knopen Editor Inschakelen", - "autoChangeDimensions": "Werk bij wijziging afmetingen bij naar modelstandaard", + "enableNodesEditor": "Schakel Knooppunteditor in", + "autoChangeDimensions": "Werk B/H bij naar modelstandaard bij wijziging", "clearIntermediates": "Wis tussentijdse afbeeldingen", "clearIntermediatesDesc3": "Je galerijafbeeldingen zullen niet worden verwijderd.", "clearIntermediatesWithCount_one": "Wis {{count}} tussentijdse afbeelding", "clearIntermediatesWithCount_other": "Wis {{count}} tussentijdse afbeeldingen", - "clearIntermediatesDesc2": "Tussentijdse afbeeldingen zijn nevenproducten bij een generatie, die afwijken van de uitvoerafbeeldingen in de galerij. Het wissen van tussentijdse afbeeldingen zal schijfruimte vrijmaken.", + "clearIntermediatesDesc2": "Tussentijdse afbeeldingen zijn nevenproducten bij het genereren. Deze wijken af van de uitvoerafbeeldingen in de galerij. Als je tussentijdse afbeeldingen wist, wordt schijfruimte vrijgemaakt.", "intermediatesCleared_one": "{{count}} tussentijdse afbeelding gewist", "intermediatesCleared_other": "{{count}} tussentijdse afbeeldingen gewist", - "clearIntermediatesDesc1": "Het wissen van tussentijdse onderdelen zet de staat van je canvas en ControlNet terug.", + "clearIntermediatesDesc1": "Als je tussentijdse afbeeldingen wist, dan wordt de staat hersteld van je canvas en van ControlNet.", "intermediatesClearedFailed": "Fout bij wissen van tussentijdse afbeeldingen" }, "toast": { @@ -881,7 +881,7 @@ "conditioningCollectionDescription": "Conditionering kan worden doorgegeven tussen knooppunten.", "colorPolymorphic": "Polymorfisme kleur", "colorCodeEdgesHelp": "Kleurgecodeerde randen op basis van hun verbonden velden", - "collectionDescription": "Beschrijving", + "collectionDescription": "TODO", "float": "Zwevende-kommagetal", "workflowContact": "Contactpersoon", "skippingReservedFieldType": "Overslaan van gereserveerd veldsoort", @@ -898,7 +898,7 @@ "sourceNode": "Bronknooppunt", "nodeOpacity": "Dekking knooppunt", "pickOne": "Kies er een", - "collectionItemDescription": "Beschrijving", + "collectionItemDescription": "TODO", "integerDescription": "Gehele getallen zijn getallen zonder een decimaalteken.", "outputField": "Uitvoerveld", "unableToLoadWorkflow": "Kan werkstroom niet valideren", @@ -944,7 +944,7 @@ "inputNode": "Invoerknooppunt", "enumDescription": "Enumeraties zijn waarden die uit een aantal opties moeten worden gekozen.", "unkownInvocation": "Onbekende aanroepsoort", - "loRAModelFieldDescription": "Beschrijving", + "loRAModelFieldDescription": "TODO", "imageField": "Afbeelding", "skippedReservedOutput": "Overgeslagen gereserveerd uitvoerveld", "animatedEdgesHelp": "Animeer gekozen randen en randen verbonden met de gekozen knooppunten", @@ -953,7 +953,7 @@ "unknownTemplate": "Onbekend sjabloon", "noWorkflow": "Geen werkstroom", "removeLinearView": "Verwijder uit lineaire weergave", - "colorCollectionDescription": "Beschrijving", + "colorCollectionDescription": "TODO", "integerCollectionDescription": "Een verzameling gehele getallen.", "colorPolymorphicDescription": "Een verzameling kleuren.", "sDXLMainModelField": "SDXL-model", @@ -1028,7 +1028,7 @@ "loadingNodes": "Bezig met laden van knooppunten...", "snapToGridHelp": "Lijn knooppunten uit op raster bij verplaatsing", "workflowSettings": "Instellingen werkstroomeditor", - "mainModelFieldDescription": "Beschrijving", + "mainModelFieldDescription": "TODO", "sDXLRefinerModelField": "Verfijningsmodel", "loRAModelField": "LoRA", "unableToParseEdge": "Kan rand niet inlezen", @@ -1039,13 +1039,13 @@ "controlnet": { "amult": "a_mult", "resize": "Schaal", - "showAdvanced": "Toon uitgebreid", + "showAdvanced": "Toon uitgebreide opties", "contentShuffleDescription": "Verschuift het materiaal in de afbeelding", "bgth": "bg_th", "addT2IAdapter": "Voeg $t(common.t2iAdapter) toe", "pidi": "PIDI", "importImageFromCanvas": "Importeer afbeelding uit canvas", - "lineartDescription": "Zet afbeelding om naar lineart", + "lineartDescription": "Zet afbeelding om naar line-art", "normalBae": "Normale BAE", "importMaskFromCanvas": "Importeer masker uit canvas", "hed": "HED", @@ -1053,7 +1053,7 @@ "contentShuffle": "Verschuif materiaal", "controlNetEnabledT2IDisabled": "$t(common.controlNet) ingeschakeld, $t(common.t2iAdapter)s uitgeschakeld", "ipAdapterModel": "Adaptermodel", - "resetControlImage": "Zet controle-afbeelding terug", + "resetControlImage": "Herstel controle-afbeelding", "beginEndStepPercent": "Percentage begin-/eindstap", "mlsdDescription": "Minimalistische herkenning lijnsegmenten", "duplicate": "Maak kopie", @@ -1061,8 +1061,8 @@ "f": "F", "h": "H", "prompt": "Prompt", - "depthMidasDescription": "Generatie van diepteblad via Midas", - "controlnet": "$t(controlnet.controlAdapter) #{{number}} ($t(common.controlNet))", + "depthMidasDescription": "Genereer diepteblad via Midas", + "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))", "openPoseDescription": "Menselijke pose-benadering via Openpose", "control": "Controle", "resizeMode": "Modus schaling", @@ -1080,7 +1080,7 @@ "enableControlnet": "Schakel ControlNet in", "detectResolution": "Herken resolutie", "controlNetT2IMutexDesc": "Gelijktijdig gebruik van $t(common.controlNet) en $t(common.t2iAdapter) wordt op dit moment niet ondersteund.", - "ip_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.ipAdapter))", + "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))", "pidiDescription": "PIDI-afbeeldingsverwerking", "mediapipeFace": "Mediapipe - Gezicht", "mlsd": "M-LSD", @@ -1088,10 +1088,10 @@ "fill": "Vul", "cannyDescription": "Herkenning Canny-rand", "addIPAdapter": "Voeg $t(common.ipAdapter) toe", - "lineart": "Lineart", + "lineart": "Line-art", "colorMapDescription": "Genereert een kleurenblad van de afbeelding", "lineartAnimeDescription": "Lineartverwerking in anime-stijl", - "t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.t2iAdapter))", + "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))", "minConfidence": "Min. vertrouwensniveau", "imageResolution": "Resolutie afbeelding", "megaControl": "Zeer veel controle", @@ -1110,15 +1110,15 @@ "controlAdapter_other": "Control-adapters", "safe": "Veilig", "colorMapTileSize": "Grootte tegel", - "lineartAnime": "Lineart-anime", + "lineartAnime": "Line-art voor anime", "ipAdapterImageFallback": "Geen IP-adapterafbeelding gekozen", "mediapipeFaceDescription": "Gezichtsherkenning met Mediapipe", "canny": "Canny", - "depthZoeDescription": "Generatie van diepteblad via Zoe", + "depthZoeDescription": "Genereer diepteblad via Zoe", "hedDescription": "Herkenning van holistisch-geneste randen", "setControlImageDimensions": "Stel afmetingen controle-afbeelding in op B/H", "scribble": "Krabbel", - "resetIPAdapterImage": "Zet IP-adapterafbeelding terug", + "resetIPAdapterImage": "Herstel IP-adapterafbeelding", "handAndFace": "Hand en gezicht", "enableIPAdapter": "Schakel IP-adapter in", "maxFaces": "Max. gezichten" @@ -1132,7 +1132,7 @@ "label": "Gedrag seedwaarde" }, "enableDynamicPrompts": "Schakel dynamische prompts in", - "combinatorial": "Combinatorische generatie", + "combinatorial": "Combinatorisch genereren", "maxPrompts": "Max. prompts", "promptsWithCount_one": "{{count}} prompt", "promptsWithCount_other": "{{count}} prompts", @@ -1141,7 +1141,7 @@ "popovers": { "noiseUseCPU": { "paragraphs": [ - "Bestuurt of ruis wordt gegenereerd op de CPU of de GPU.", + "Bepaalt of ruis wordt gegenereerd op de CPU of de GPU.", "Met CPU-ruis ingeschakeld zal een bepaalde seedwaarde dezelfde afbeelding opleveren op welke machine dan ook.", "Er is geen prestatieverschil bij het inschakelen van CPU-ruis." ], @@ -1149,7 +1149,7 @@ }, "paramScheduler": { "paragraphs": [ - "De planner bepaalt hoe per keer ruis wordt toegevoegd aan een afbeelding of hoe een monster wordt bijgewerkt op basis van de uitvoer van een model." + "De planner bepaalt hoe ruis per iteratie wordt toegevoegd aan een afbeelding of hoe een monster wordt bijgewerkt op basis van de uitvoer van een model." ], "heading": "Planner" }, @@ -1220,8 +1220,8 @@ }, "paramSeed": { "paragraphs": [ - "Bestuurt de startruis die gebruikt wordt bij het genereren.", - "Schakel \"Willekeurige seedwaarde\" uit om identieke resultaten te krijgen met dezelfde generatie-instellingen." + "Bepaalt de startruis die gebruikt wordt bij het genereren.", + "Schakel \"Willekeurige seedwaarde\" uit om identieke resultaten te krijgen met dezelfde genereer-instellingen." ], "heading": "Seedwaarde" }, @@ -1240,7 +1240,7 @@ }, "dynamicPromptsSeedBehaviour": { "paragraphs": [ - "Bestuurt hoe de seedwaarde wordt gebruikt bij het genereren van prompts.", + "Bepaalt hoe de seedwaarde wordt gebruikt bij het genereren van prompts.", "Per iteratie zal een unieke seedwaarde worden gebruikt voor elke iteratie. Gebruik dit om de promptvariaties binnen een enkele seedwaarde te verkennen.", "Bijvoorbeeld: als je vijf prompts heb, dan zal voor elke afbeelding dezelfde seedwaarde gebruikt worden.", "De optie Per afbeelding zal een unieke seedwaarde voor elke afbeelding gebruiken. Dit biedt meer variatie." @@ -1259,7 +1259,7 @@ "heading": "Model", "paragraphs": [ "Model gebruikt voor de ontruisingsstappen.", - "Verschillende modellen zijn meestal getraind zich te specialiseren in het maken van bepaalde esthetische resultaten en materiaal." + "Verschillende modellen zijn meestal getraind om zich te specialiseren in het maken van bepaalde esthetische resultaten en materiaal." ] }, "compositingCoherencePass": { @@ -1271,7 +1271,7 @@ "paramDenoisingStrength": { "paragraphs": [ "Hoeveel ruis wordt toegevoegd aan de invoerafbeelding.", - "0 geeft een identieke afbeelding, waarbij 1 een volledig nieuwe afbeelding geeft." + "0 levert een identieke afbeelding op, waarbij 1 een volledig nieuwe afbeelding oplevert." ], "heading": "Ontruisingssterkte" }, @@ -1284,7 +1284,7 @@ }, "paramNegativeConditioning": { "paragraphs": [ - "Het generatieproces voorkomt de gegeven begrippen in de negatieve prompt. Gebruik dit om bepaalde zaken of voorwerpen uit te sluiten van de uitvoerafbeelding.", + "Het genereerproces voorkomt de gegeven begrippen in de negatieve prompt. Gebruik dit om bepaalde zaken of voorwerpen uit te sluiten van de uitvoerafbeelding.", "Ondersteunt Compel-syntax en -embeddingen." ], "heading": "Negatieve prompt" @@ -1316,13 +1316,13 @@ "controlNet": { "heading": "ControlNet", "paragraphs": [ - "ControlNets biedt begeleiding aan het generatieproces, waarbij hulp wordt geboden bij het maken van afbeelding met aangestuurde compositie, structuur of stijl, afhankelijk van het gekozen model." + "ControlNets begeleidt het genereerproces, waarbij geholpen wordt bij het maken van afbeeldingen met aangestuurde compositie, structuur of stijl, afhankelijk van het gekozen model." ] }, "paramCFGScale": { "heading": "CFG-schaal", "paragraphs": [ - "Bestuurt hoeveel je prompt invloed heeft op het generatieproces." + "Bepaalt hoeveel je prompt invloed heeft op het genereerproces." ] }, "controlNetControlMode": { @@ -1335,7 +1335,7 @@ "heading": "Stappen", "paragraphs": [ "Het aantal uit te voeren stappen tijdens elke generatie.", - "Hogere stappenaantallen geven meestal betere afbeeldingen ten koste van een grotere benodigde generatietijd." + "Een hoger aantal stappen geven meestal betere afbeeldingen, ten koste van een hogere benodigde tijd om te genereren." ] }, "paramPositiveConditioning": { @@ -1356,7 +1356,7 @@ "seamless": "Naadloos", "positivePrompt": "Positieve prompt", "negativePrompt": "Negatieve prompt", - "generationMode": "Generatiemodus", + "generationMode": "Genereermodus", "Threshold": "Drempelwaarde ruis", "metadata": "Metagegevens", "strength": "Sterkte Afbeelding naar afbeelding", @@ -1382,13 +1382,13 @@ }, "queue": { "status": "Status", - "pruneSucceeded": "{{item_count}} voltooide onderdelen uit wachtrij gesnoeid", + "pruneSucceeded": "{{item_count}} voltooide onderdelen uit wachtrij opgeruimd", "cancelTooltip": "Annuleer huidig onderdeel", "queueEmpty": "Wachtrij leeg", "pauseSucceeded": "Verwerker onderbroken", "in_progress": "Bezig", - "queueFront": "Voeg toe aan voorkant van wachtrij", - "notReady": "Kan niet in wachtrij plaatsen", + "queueFront": "Voeg vooraan toe in wachtrij", + "notReady": "Fout bij plaatsen in wachtrij", "batchFailedToQueue": "Fout bij reeks in wachtrij plaatsen", "completed": "Voltooid", "queueBack": "Voeg toe aan wachtrij", @@ -1402,22 +1402,22 @@ "front": "begin", "clearSucceeded": "Wachtrij gewist", "pause": "Onderbreek", - "pruneTooltip": "Snoei {{item_count}} voltooide onderdelen", + "pruneTooltip": "Ruim {{item_count}} voltooide onderdelen op", "cancelSucceeded": "Onderdeel geannuleerd", "batchQueuedDesc_one": "Voeg {{count}} sessie toe aan het {{direction}} van de wachtrij", "batchQueuedDesc_other": "Voeg {{count}} sessies toe aan het {{direction}} van de wachtrij", "graphQueued": "Graaf in wachtrij geplaatst", "queue": "Wachtrij", "batch": "Reeks", - "clearQueueAlertDialog": "Als je de wachtrij onmiddellijk wist, dan worden alle onderdelen die bezig zijn geannuleerd en wordt de gehele wachtrij gewist.", + "clearQueueAlertDialog": "Als je de wachtrij onmiddellijk wist, dan worden alle onderdelen die bezig zijn geannuleerd en wordt de wachtrij volledig gewist.", "pending": "Wachtend", "completedIn": "Voltooid na", "resumeFailed": "Fout bij hervatten verwerker", "clear": "Wis", - "prune": "Snoei", + "prune": "Ruim op", "total": "Totaal", "canceled": "Geannuleerd", - "pruneFailed": "Fout bij snoeien van wachtrij", + "pruneFailed": "Fout bij opruimen van wachtrij", "cancelBatchSucceeded": "Reeks geannuleerd", "clearTooltip": "Annuleer en wis alle onderdelen", "current": "Huidig", @@ -1431,7 +1431,7 @@ "session": "Sessie", "queueTotal": "Totaal {{total}}", "resumeSucceeded": "Verwerker hervat", - "enqueueing": "Toevoegen van reeks aan wachtrij", + "enqueueing": "Bezig met toevoegen van reeks aan wachtrij", "resumeTooltip": "Hervat verwerker", "queueMaxExceeded": "Max. aantal van {{max_queue_size}} overschreden, {{skip}} worden overgeslagen", "resume": "Hervat", @@ -1441,18 +1441,18 @@ "graphFailedToQueue": "Fout bij toevoegen graaf aan wachtrij" }, "sdxl": { - "refinerStart": "Startwaarde verfijner", + "refinerStart": "Startwaarde verfijning", "selectAModel": "Kies een model", "scheduler": "Planner", "cfgScale": "CFG-schaal", "negStylePrompt": "Negatieve-stijlprompt", "noModelsAvailable": "Geen modellen beschikbaar", - "refiner": "Verfijner", - "negAestheticScore": "Negatieve aantrekkelijkheidsscore", - "useRefiner": "Gebruik verfijner", + "refiner": "Verfijning", + "negAestheticScore": "Negatieve esthetische score", + "useRefiner": "Gebruik verfijning", "denoisingStrength": "Sterkte ontruising", - "refinermodel": "Verfijnermodel", - "posAestheticScore": "Positieve aantrekkelijkheidsscore", + "refinermodel": "Verfijningsmodel", + "posAestheticScore": "Positieve esthetische score", "concatPromptStyle": "Plak prompt- en stijltekst aan elkaar", "loading": "Bezig met laden...", "steps": "Stappen", From 8615d53e654ecaf20960c9110b47a098756b5962 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:22:56 +1100 Subject: [PATCH 064/119] fix(nodes): fix missing generation modes Lax typing on the metadata util functions allowed a typing issue to slip through. Fixed the lax typing, updated core metadata node. --- invokeai/app/invocations/metadata.py | 7 +- .../graphBuilders/buildAdHocUpscaleGraph.ts | 5 +- .../nodes/util/graphBuilders/metadata.ts | 2 +- .../frontend/web/src/services/api/schema.d.ts | 152 +++++++++++++----- 4 files changed, 126 insertions(+), 40 deletions(-) diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 1ed399873b..0f45fc5a36 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -107,11 +107,16 @@ class MergeMetadataInvocation(BaseInvocation): return MetadataOutput(metadata=MetadataField.model_validate(data)) +GENERATION_MODES = Literal[ + "txt2img", "img2img", "inpaint", "outpaint", "sdxl_txt2img", "sdxl_img2img", "sdxl_inpaint", "sdxl_outpaint" +] + + @invocation("core_metadata", title="Core Metadata", tags=["metadata"], category="metadata", version="1.0.0") class CoreMetadataInvocation(BaseInvocation): """Collects core generation metadata into a MetadataField""" - generation_mode: Literal["txt2img", "img2img", "inpaint", "outpaint"] = InputField( + generation_mode: Optional[GENERATION_MODES] = InputField( default=None, description="The generation mode that output this image", ) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts index 46e415a886..5af8edbdfc 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildAdHocUpscaleGraph.ts @@ -7,7 +7,7 @@ import { SaveImageInvocation, } from 'services/api/types'; import { REALESRGAN as ESRGAN, SAVE_IMAGE } from './constants'; -import { addCoreMetadataNode } from './metadata'; +import { addCoreMetadataNode, upsertMetadata } from './metadata'; type Arg = { image_name: string; @@ -56,7 +56,8 @@ export const buildAdHocUpscaleGraph = ({ ], }; - addCoreMetadataNode(graph, { + addCoreMetadataNode(graph, {}); + upsertMetadata(graph, { esrgan_model: esrganModelName, }); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts index 5cc397ce68..b673be9e4a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/metadata.ts @@ -5,7 +5,7 @@ import { METADATA, SAVE_IMAGE } from './constants'; export const addCoreMetadataNode = ( graph: NonNullableGraph, - metadata: Partial | JsonObject + metadata: Partial ): void => { graph.nodes[METADATA] = { id: METADATA, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 5541fa20e9..6ff9d49bf9 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -1842,9 +1842,8 @@ export type components = { /** * Generation Mode * @description The generation mode that output this image - * @enum {string} */ - generation_mode?: "txt2img" | "img2img" | "inpaint" | "outpaint"; + generation_mode?: ("txt2img" | "img2img" | "inpaint" | "outpaint" | "sdxl_txt2img" | "sdxl_img2img" | "sdxl_inpaint" | "sdxl_outpaint") | null; /** * Positive Prompt * @description The positive prompt parameter @@ -2942,7 +2941,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ImageMultiplyInvocation"]; + [key: string]: components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["TestInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["TestInvocation3"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["TestInvocation2"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["StringReplaceInvocation"]; }; /** * Edges @@ -2979,7 +2978,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["FaceOffOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["String2Output"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["FaceMaskOutput"]; + [key: string]: components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ImageOutput"]; }; /** * Errors @@ -3200,21 +3199,18 @@ export type components = { /** * Weight * @description The weight given to the IP-Adapter - * @default 1 */ - weight?: number | number[]; + weight: number | number[]; /** * Begin Step Percent * @description When the IP-Adapter is first applied (% of total steps) - * @default 0 */ - begin_step_percent?: number; + begin_step_percent: number; /** * End Step Percent * @description When the IP-Adapter is last applied (% of total steps) - * @default 1 */ - end_step_percent?: number; + end_step_percent: number; }; /** IPAdapterModelField */ IPAdapterModelField: { @@ -8402,6 +8398,90 @@ export type components = { */ type: "t2i_adapter_output"; }; + /** TestInvocation */ + TestInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** A */ + a?: string; + /** + * type + * @default test_invocation + * @constant + */ + type: "test_invocation"; + }; + /** TestInvocation2 */ + TestInvocation2: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** A */ + a?: string; + /** + * type + * @default test_invocation_2 + * @constant + */ + type: "test_invocation_2"; + }; + /** TestInvocation3 */ + TestInvocation3: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** A */ + a?: string; + /** + * type + * @default test_invocation_3 + * @constant + */ + type: "test_invocation_3"; + }; /** TextualInversionModelConfig */ TextualInversionModelConfig: { /** Model Name */ @@ -8727,30 +8807,6 @@ export type components = { /** Ui Order */ ui_order: number | null; }; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * CLIPVisionModelFormat - * @description An enumeration. - * @enum {string} - */ - CLIPVisionModelFormat: "diffusers"; - /** - * StableDiffusionXLModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. @@ -8763,6 +8819,30 @@ export type components = { * @enum {string} */ IPAdapterModelFormat: "invokeai"; + /** + * T2IAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + T2IAdapterModelFormat: "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + /** + * CLIPVisionModelFormat + * @description An enumeration. + * @enum {string} + */ + CLIPVisionModelFormat: "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * ControlNetModelFormat * @description An enumeration. @@ -8770,11 +8850,11 @@ export type components = { */ ControlNetModelFormat: "checkpoint" | "diffusers"; /** - * T2IAdapterModelFormat + * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ - T2IAdapterModelFormat: "diffusers"; + StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; From 8e948d3f17c7a93fcae95f71fda863d069cfa4de Mon Sep 17 00:00:00 2001 From: Eugene Brodsky Date: Thu, 19 Oct 2023 12:13:36 -0400 Subject: [PATCH 065/119] fix(assets): re-add missing caution image --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 693d4c9ed1..d67b096ddc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -166,6 +166,7 @@ version = { attr = "invokeai.version.__version__" } ] [tool.setuptools.package-data] +"invokeai.app.assets" = ["**/*.png"] "invokeai.assets.fonts" = ["**/*.ttf"] "invokeai.backend" = ["**.png"] "invokeai.configs" = ["*.example", "**/*.yaml", "*.txt"] From 3546c41f4a361dfc4be0f7cd97005b41ba191e73 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 23 Oct 2023 18:48:14 -0400 Subject: [PATCH 066/119] close #4975 --- invokeai/app/services/model_manager/__init__.py | 1 + invokeai/backend/training/textual_inversion_training.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/app/services/model_manager/__init__.py b/invokeai/app/services/model_manager/__init__.py index e69de29bb2..da54cbf89f 100644 --- a/invokeai/app/services/model_manager/__init__.py +++ b/invokeai/app/services/model_manager/__init__.py @@ -0,0 +1 @@ +from .model_manager_default import ModelManagerService diff --git a/invokeai/backend/training/textual_inversion_training.py b/invokeai/backend/training/textual_inversion_training.py index 153bd0fcc4..9bc1d188bc 100644 --- a/invokeai/backend/training/textual_inversion_training.py +++ b/invokeai/backend/training/textual_inversion_training.py @@ -41,7 +41,7 @@ from transformers import CLIPTextModel, CLIPTokenizer # invokeai stuff from invokeai.app.services.config import InvokeAIAppConfig, PagingArgumentParser -from invokeai.app.services.model_manager_service import ModelManagerService +from invokeai.app.services.model_manager import ModelManagerService from invokeai.backend.model_management.models import SubModelType if version.parse(version.parse(PIL.__version__).base_version) >= version.parse("9.1.0"): From c14aa30956c4255f49dce00d20c3e5a2b1df6a1e Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 23 Oct 2023 20:37:33 -0400 Subject: [PATCH 067/119] fix the merge script to correctly display models sorted by base --- invokeai/frontend/merge/merge_diffusers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/merge/merge_diffusers.py b/invokeai/frontend/merge/merge_diffusers.py index 8fa02cb49c..f3672acbf2 100644 --- a/invokeai/frontend/merge/merge_diffusers.py +++ b/invokeai/frontend/merge/merge_diffusers.py @@ -131,6 +131,7 @@ class mergeModelsForm(npyscreen.FormMultiPageAction): values=[ "Models Built on SD-1.x", "Models Built on SD-2.x", + "Models Built on SDXL", ], value=[self.current_base], columns=4, @@ -309,7 +310,7 @@ class mergeModelsForm(npyscreen.FormMultiPageAction): else: return True - def get_model_names(self, base_model: Optional[BaseModelType] = None) -> List[str]: + def get_model_names(self, base_model: BaseModelType = BaseModelType.StableDiffusion1) -> List[str]: model_names = [ info["model_name"] for info in self.model_manager.list_models(model_type=ModelType.Main, base_model=base_model) @@ -318,7 +319,8 @@ class mergeModelsForm(npyscreen.FormMultiPageAction): return sorted(model_names) def _populate_models(self, value=None): - base_model = tuple(BaseModelType)[value[0]] + bases = ["sd-1", "sd-2", "sdxl"] + base_model = BaseModelType(bases[value[0]]) self.model_names = self.get_model_names(base_model) models_plus_none = self.model_names.copy() From 6cbc69f3b7785531b49470ca93399d917fff832d Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 23 Oct 2023 22:06:10 -0400 Subject: [PATCH 068/119] support conversion of controlnets from safetensors to diffusers --- .../backend/install/model_install_backend.py | 6 ++ .../model_management/models/controlnet.py | 3 +- invokeai/configs/controlnet/cldm_v15.yaml | 79 +++++++++++++++++ invokeai/configs/controlnet/cldm_v21.yaml | 85 +++++++++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 invokeai/configs/controlnet/cldm_v15.yaml create mode 100644 invokeai/configs/controlnet/cldm_v21.yaml diff --git a/invokeai/backend/install/model_install_backend.py b/invokeai/backend/install/model_install_backend.py index 9224f5c8b2..9784aa0ac2 100644 --- a/invokeai/backend/install/model_install_backend.py +++ b/invokeai/backend/install/model_install_backend.py @@ -460,6 +460,12 @@ class ModelInstall(object): possible_conf = path.with_suffix(".yaml") if possible_conf.exists(): legacy_conf = str(self.relative_to_root(possible_conf)) + else: + legacy_conf = Path( + self.config.root_path, + "configs/controlnet", + ("cldm_v15.yaml" if info.base_type == BaseModelType("sd-1") else "cldm_v21.yaml"), + ) if legacy_conf: attributes.update(dict(config=str(legacy_conf))) diff --git a/invokeai/backend/model_management/models/controlnet.py b/invokeai/backend/model_management/models/controlnet.py index 359df91a82..6a42b59fe1 100644 --- a/invokeai/backend/model_management/models/controlnet.py +++ b/invokeai/backend/model_management/models/controlnet.py @@ -132,13 +132,14 @@ def _convert_controlnet_ckpt_and_cache( model_path: str, output_path: str, base_model: BaseModelType, - model_config: ControlNetModel.CheckpointConfig, + model_config: str, ) -> str: """ Convert the controlnet from checkpoint format to diffusers format, cache it to disk, and return Path to converted file. If already on disk then just returns Path. """ + print(f"DEBUG: controlnet config = {model_config}") app_config = InvokeAIAppConfig.get_config() weights = app_config.root_path / model_path output_path = Path(output_path) diff --git a/invokeai/configs/controlnet/cldm_v15.yaml b/invokeai/configs/controlnet/cldm_v15.yaml new file mode 100644 index 0000000000..fde1825577 --- /dev/null +++ b/invokeai/configs/controlnet/cldm_v15.yaml @@ -0,0 +1,79 @@ +model: + target: cldm.cldm.ControlLDM + params: + linear_start: 0.00085 + linear_end: 0.0120 + num_timesteps_cond: 1 + log_every_t: 200 + timesteps: 1000 + first_stage_key: "jpg" + cond_stage_key: "txt" + control_key: "hint" + image_size: 64 + channels: 4 + cond_stage_trainable: false + conditioning_key: crossattn + monitor: val/loss_simple_ema + scale_factor: 0.18215 + use_ema: False + only_mid_control: False + + control_stage_config: + target: cldm.cldm.ControlNet + params: + image_size: 32 # unused + in_channels: 4 + hint_channels: 3 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_heads: 8 + use_spatial_transformer: True + transformer_depth: 1 + context_dim: 768 + use_checkpoint: True + legacy: False + + unet_config: + target: cldm.cldm.ControlledUnetModel + params: + image_size: 32 # unused + in_channels: 4 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_heads: 8 + use_spatial_transformer: True + transformer_depth: 1 + context_dim: 768 + use_checkpoint: True + legacy: False + + first_stage_config: + target: ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + cond_stage_config: + target: ldm.modules.encoders.modules.FrozenCLIPEmbedder diff --git a/invokeai/configs/controlnet/cldm_v21.yaml b/invokeai/configs/controlnet/cldm_v21.yaml new file mode 100644 index 0000000000..fc65193647 --- /dev/null +++ b/invokeai/configs/controlnet/cldm_v21.yaml @@ -0,0 +1,85 @@ +model: + target: cldm.cldm.ControlLDM + params: + linear_start: 0.00085 + linear_end: 0.0120 + num_timesteps_cond: 1 + log_every_t: 200 + timesteps: 1000 + first_stage_key: "jpg" + cond_stage_key: "txt" + control_key: "hint" + image_size: 64 + channels: 4 + cond_stage_trainable: false + conditioning_key: crossattn + monitor: val/loss_simple_ema + scale_factor: 0.18215 + use_ema: False + only_mid_control: False + + control_stage_config: + target: cldm.cldm.ControlNet + params: + use_checkpoint: True + image_size: 32 # unused + in_channels: 4 + hint_channels: 3 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + legacy: False + + unet_config: + target: cldm.cldm.ControlledUnetModel + params: + use_checkpoint: True + image_size: 32 # unused + in_channels: 4 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + legacy: False + + first_stage_config: + target: ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + cond_stage_config: + target: ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" From 3b7e17c0ccafa5bc8a074d52820e1317b4cdcdc6 Mon Sep 17 00:00:00 2001 From: Gille Date: Mon, 23 Oct 2023 21:46:51 -0600 Subject: [PATCH 069/119] Update communityNodes.md Update to Load Video Frame node to reflect changes made in link locations... a.k.a. fixing broken links. --- docs/nodes/communityNodes.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index cec5d18df6..9f997776fe 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -177,12 +177,8 @@ This includes 15 Nodes: **Node Link:** https://github.com/helix4u/load_video_frame -**Example Node Graph:** https://github.com/helix4u/load_video_frame/blob/main/Example_Workflow.json - **Output Example:** - - -[Full mp4 of Example Output test.mp4](https://github.com/helix4u/load_video_frame/blob/main/test.mp4) + -------------------------------- ### Make 3D From 4f74549f17bf50e61978468cef84b0c567b716ea Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Fri, 27 Oct 2023 19:12:48 -0400 Subject: [PATCH 070/119] prevent prereleases from showing up in updater --- invokeai/frontend/install/invokeai_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/install/invokeai_update.py b/invokeai/frontend/install/invokeai_update.py index 87661da79f..cf017dcfeb 100644 --- a/invokeai/frontend/install/invokeai_update.py +++ b/invokeai/frontend/install/invokeai_update.py @@ -91,7 +91,7 @@ def get_extras(): def main(): - versions = get_versions() + versions = [x for x in get_versions() if not (x['draft'] or x['prerelease'])] if invokeai_is_running(): print(":exclamation: [bold red]Please terminate all running instances of InvokeAI before updating.[/red bold]") input("Press any key to continue...") From fe5d2c023b21ca958a8e439a72c96bd3bb727bd7 Mon Sep 17 00:00:00 2001 From: Jonathan <34005131+JPPhoto@users.noreply.github.com> Date: Sat, 28 Oct 2023 08:13:51 -0500 Subject: [PATCH 071/119] Update communityNodes.md Added Average Images node --- docs/nodes/communityNodes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index 9f997776fe..f394a7c9bd 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -9,6 +9,7 @@ To download a node, simply download the `.py` node file from the link and add it To use a community workflow, download the the `.json` node graph file and load it into Invoke AI via the **Load Workflow** button in the Workflow Editor. - Community Nodes + + [Average Images](#average-images) + [Depth Map from Wavefront OBJ](#depth-map-from-wavefront-obj) + [Film Grain](#film-grain) + [Generative Grammar-Based Prompt Nodes](#generative-grammar-based-prompt-nodes) @@ -33,6 +34,13 @@ To use a community workflow, download the the `.json` node graph file and load i - [Help](#help) +-------------------------------- +### Average Images + +**Description:** This node takes in a collection of images of the same size and averages them as output. It converts everything to RGB mode first. + +**Node Link:** https://github.com/JPPhoto/average-images-node + -------------------------------- ### Depth Map from Wavefront OBJ From 859e3d5a6156fcad8d102a8ac751e27fef78ae8a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:49:07 -0500 Subject: [PATCH 072/119] chore: flake8 --- invokeai/app/services/model_manager/__init__.py | 2 +- invokeai/frontend/merge/merge_diffusers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/services/model_manager/__init__.py b/invokeai/app/services/model_manager/__init__.py index da54cbf89f..3d6a9c248c 100644 --- a/invokeai/app/services/model_manager/__init__.py +++ b/invokeai/app/services/model_manager/__init__.py @@ -1 +1 @@ -from .model_manager_default import ModelManagerService +from .model_manager_default import ModelManagerService # noqa F401 diff --git a/invokeai/frontend/merge/merge_diffusers.py b/invokeai/frontend/merge/merge_diffusers.py index f3672acbf2..51602b75d1 100644 --- a/invokeai/frontend/merge/merge_diffusers.py +++ b/invokeai/frontend/merge/merge_diffusers.py @@ -9,7 +9,7 @@ import curses import sys from argparse import Namespace from pathlib import Path -from typing import List, Optional +from typing import List import npyscreen from npyscreen import widget From 6e052928135fd0f64c69ca8b085a9390097474d1 Mon Sep 17 00:00:00 2001 From: Riccardo Giovanetti Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 073/119] translationBot(ui): update translation (Italian) Currently translated at 97.6% (1188 of 1217 strings) Co-authored-by: Riccardo Giovanetti Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/it/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/it.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index c69879cfcf..49b258c95d 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.json @@ -1116,7 +1116,8 @@ "controlAdapter_other": "Adattatori di Controllo", "megaControl": "Mega ControlNet", "minConfidence": "Confidenza minima", - "scribble": "Scribble" + "scribble": "Scribble", + "amult": "Angolo di illuminazione" }, "queue": { "queueFront": "Aggiungi all'inizio della coda", From 69ba3a72787257ee32bc42dbc0d0a61b7a6e842a Mon Sep 17 00:00:00 2001 From: Gohsuke Shimada Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 074/119] translationBot(ui): update translation (Japanese) Currently translated at 56.1% (683 of 1217 strings) translationBot(ui): update translation (Japanese) Currently translated at 40.3% (491 of 1217 strings) Co-authored-by: Gohsuke Shimada Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ja/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/ja.json | 370 ++++++++++++++++++- 1 file changed, 360 insertions(+), 10 deletions(-) diff --git a/invokeai/frontend/web/public/locales/ja.json b/invokeai/frontend/web/public/locales/ja.json index a53ea50b46..c7718e7b7c 100644 --- a/invokeai/frontend/web/public/locales/ja.json +++ b/invokeai/frontend/web/public/locales/ja.json @@ -1,6 +1,6 @@ { "common": { - "languagePickerLabel": "言語選択", + "languagePickerLabel": "言語", "reportBugLabel": "バグ報告", "settingsLabel": "設定", "langJapanese": "日本語", @@ -63,11 +63,34 @@ "langFrench": "Français", "langGerman": "Deutsch", "langPortuguese": "Português", - "nodes": "ノード", + "nodes": "ワークフローエディター", "langKorean": "한국어", "langPolish": "Polski", "txt2img": "txt2img", - "postprocessing": "Post Processing" + "postprocessing": "Post Processing", + "t2iAdapter": "T2I アダプター", + "communityLabel": "コミュニティ", + "dontAskMeAgain": "次回から確認しない", + "areYouSure": "本当によろしいですか?", + "on": "オン", + "nodeEditor": "ノードエディター", + "ipAdapter": "IPアダプター", + "controlAdapter": "コントロールアダプター", + "auto": "自動", + "openInNewTab": "新しいタブで開く", + "controlNet": "コントロールネット", + "statusProcessing": "処理中", + "linear": "リニア", + "imageFailedToLoad": "画像が読み込めません", + "imagePrompt": "画像プロンプト", + "modelManager": "モデルマネージャー", + "lightMode": "ライトモード", + "generate": "生成", + "learnMore": "もっと学ぶ", + "darkMode": "ダークモード", + "random": "ランダム", + "batch": "バッチマネージャー", + "advanced": "高度な設定" }, "gallery": { "uploads": "アップロード", @@ -274,7 +297,7 @@ "config": "Config", "configValidationMsg": "モデルの設定ファイルへのパス", "modelLocation": "モデルの場所", - "modelLocationValidationMsg": "モデルが配置されている場所へのパス。", + "modelLocationValidationMsg": "ディフューザーモデルのあるローカルフォルダーのパスを入力してください", "repo_id": "Repo ID", "repoIDValidationMsg": "モデルのリモートリポジトリ", "vaeLocation": "VAEの場所", @@ -309,12 +332,79 @@ "delete": "削除", "deleteModel": "モデルを削除", "deleteConfig": "設定を削除", - "deleteMsg1": "InvokeAIからこのモデルエントリーを削除してよろしいですか?", - "deleteMsg2": "これは、ドライブからモデルのCheckpointファイルを削除するものではありません。必要であればそれらを読み込むことができます。", + "deleteMsg1": "InvokeAIからこのモデルを削除してよろしいですか?", + "deleteMsg2": "これは、モデルがInvokeAIルートフォルダ内にある場合、ディスクからモデルを削除します。カスタム保存場所を使用している場合、モデルはディスクから削除されません。", "formMessageDiffusersModelLocation": "Diffusersモデルの場所", "formMessageDiffusersModelLocationDesc": "最低でも1つは入力してください。", "formMessageDiffusersVAELocation": "VAEの場所s", - "formMessageDiffusersVAELocationDesc": "指定しない場合、InvokeAIは上記のモデルの場所にあるVAEファイルを探します。" + "formMessageDiffusersVAELocationDesc": "指定しない場合、InvokeAIは上記のモデルの場所にあるVAEファイルを探します。", + "importModels": "モデルをインポート", + "custom": "カスタム", + "none": "なし", + "convert": "変換", + "statusConverting": "変換中", + "cannotUseSpaces": "スペースは使えません", + "convertToDiffusersHelpText6": "このモデルを変換しますか?", + "checkpointModels": "チェックポイント", + "settings": "設定", + "convertingModelBegin": "モデルを変換しています...", + "baseModel": "ベースモデル", + "modelDeleteFailed": "モデルの削除ができませんでした", + "convertToDiffusers": "ディフューザーに変換", + "alpha": "アルファ", + "diffusersModels": "ディフューザー", + "pathToCustomConfig": "カスタム設定のパス", + "noCustomLocationProvided": "カスタムロケーションが指定されていません", + "modelConverted": "モデル変換が完了しました", + "weightedSum": "重み付け総和", + "inverseSigmoid": "逆シグモイド", + "invokeAIFolder": "Invoke AI フォルダ", + "syncModelsDesc": "モデルがバックエンドと同期していない場合、このオプションを使用してモデルを更新できます。通常、モデル.yamlファイルを手動で更新したり、アプリケーションの起動後にモデルをInvokeAIルートフォルダに追加した場合に便利です。", + "noModels": "モデルが見つかりません", + "sigmoid": "シグモイド", + "merge": "マージ", + "modelMergeInterpAddDifferenceHelp": "このモードでは、モデル3がまずモデル2から減算されます。その結果得られたバージョンが、上記で設定されたアルファ率でモデル1とブレンドされます。", + "customConfig": "カスタム設定", + "predictionType": "予測タイプ(安定したディフュージョン 2.x モデルおよび一部の安定したディフュージョン 1.x モデル用)", + "selectModel": "モデルを選択", + "modelSyncFailed": "モデルの同期に失敗しました", + "quickAdd": "クイック追加", + "simpleModelDesc": "ローカルのDiffusersモデル、ローカルのチェックポイント/safetensorsモデル、HuggingFaceリポジトリのID、またはチェックポイント/ DiffusersモデルのURLへのパスを指定してください。", + "customSaveLocation": "カスタム保存場所", + "advanced": "高度な設定", + "modelDeleted": "モデルが削除されました", + "convertToDiffusersHelpText2": "このプロセスでは、モデルマネージャーのエントリーを同じモデルのディフューザーバージョンに置き換えます。", + "modelUpdateFailed": "モデル更新が失敗しました", + "useCustomConfig": "カスタム設定を使用する", + "convertToDiffusersHelpText5": "十分なディスク空き容量があることを確認してください。モデルは一般的に2GBから7GBのサイズがあります。", + "modelConversionFailed": "モデル変換が失敗しました", + "modelEntryDeleted": "モデルエントリーが削除されました", + "syncModels": "モデルを同期", + "mergedModelSaveLocation": "保存場所", + "closeAdvanced": "高度な設定を閉じる", + "modelType": "モデルタイプ", + "modelsMerged": "モデルマージ完了", + "modelsMergeFailed": "モデルマージ失敗", + "scanForModels": "モデルをスキャン", + "customConfigFileLocation": "カスタム設定ファイルの場所", + "convertToDiffusersHelpText1": "このモデルは 🧨 Diffusers フォーマットに変換されます。", + "modelsSynced": "モデルが同期されました", + "invokeRoot": "InvokeAIフォルダ", + "mergedModelCustomSaveLocation": "カスタムパス", + "mergeModels": "マージモデル", + "interpolationType": "補間タイプ", + "modelMergeHeaderHelp2": "マージできるのはDiffusersのみです。チェックポイントモデルをマージしたい場合は、まずDiffusersに変換してください。", + "convertToDiffusersSaveLocation": "保存場所", + "pickModelType": "モデルタイプを選択", + "sameFolder": "同じフォルダ", + "convertToDiffusersHelpText3": "チェックポイントファイルは、InvokeAIルートフォルダ内にある場合、ディスクから削除されます。カスタムロケーションにある場合は、削除されません。", + "loraModels": "LoRA", + "modelMergeAlphaHelp": "アルファはモデルのブレンド強度を制御します。アルファ値が低いと、2番目のモデルの影響が低くなります。", + "addDifference": "差分を追加", + "modelMergeHeaderHelp1": "あなたのニーズに適したブレンドを作成するために、異なるモデルを最大3つまでマージすることができます。", + "ignoreMismatch": "選択されたモデル間の不一致を無視する", + "convertToDiffusersHelpText4": "これは一回限りのプロセスです。コンピュータの仕様によっては、約30秒から60秒かかる可能性があります。", + "mergedModelName": "マージされたモデル名" }, "parameters": { "images": "画像", @@ -440,7 +530,8 @@ "next": "次", "accept": "同意", "showHide": "表示/非表示", - "discardAll": "すべて破棄" + "discardAll": "すべて破棄", + "snapToGrid": "グリッドにスナップ" }, "accessibility": { "modelSelect": "モデルを選択", @@ -452,7 +543,7 @@ "useThisParameter": "このパラメータを使用する", "copyMetadataJson": "メタデータをコピー(JSON)", "zoomIn": "ズームイン", - "exitViewer": "ExitViewer", + "exitViewer": "ビューアーを終了", "zoomOut": "ズームアウト", "rotateCounterClockwise": "反時計回りに回転", "rotateClockwise": "時計回りに回転", @@ -461,6 +552,265 @@ "toggleAutoscroll": "自動スクロールの切替", "modifyConfig": "Modify Config", "toggleLogViewer": "Log Viewerの切替", - "showOptionsPanel": "オプションパネルを表示" + "showOptionsPanel": "サイドパネルを表示", + "showGalleryPanel": "ギャラリーパネルを表示", + "menu": "メニュー", + "loadMore": "さらに読み込む" + }, + "controlnet": { + "resize": "リサイズ", + "showAdvanced": "高度な設定を表示", + "addT2IAdapter": "$t(common.t2iAdapter)を追加", + "importImageFromCanvas": "キャンバスから画像をインポート", + "lineartDescription": "画像を線画に変換", + "importMaskFromCanvas": "キャンバスからマスクをインポート", + "hideAdvanced": "高度な設定を非表示", + "ipAdapterModel": "アダプターモデル", + "resetControlImage": "コントロール画像をリセット", + "beginEndStepPercent": "開始 / 終了ステップパーセンテージ", + "duplicate": "複製", + "balanced": "バランス", + "prompt": "プロンプト", + "depthMidasDescription": "Midasを使用して深度マップを生成", + "openPoseDescription": "Openposeを使用してポーズを推定", + "control": "コントロール", + "resizeMode": "リサイズモード", + "weight": "重み", + "selectModel": "モデルを選択", + "crop": "切り抜き", + "w": "幅", + "processor": "プロセッサー", + "addControlNet": "$t(common.controlNet)を追加", + "none": "なし", + "incompatibleBaseModel": "互換性のないベースモデル:", + "enableControlnet": "コントロールネットを有効化", + "detectResolution": "検出解像度", + "controlNetT2IMutexDesc": "$t(common.controlNet)と$t(common.t2iAdapter)の同時使用は現在サポートされていません。", + "pidiDescription": "PIDI画像処理", + "controlMode": "コントロールモード", + "fill": "塗りつぶし", + "cannyDescription": "Canny 境界検出", + "addIPAdapter": "$t(common.ipAdapter)を追加", + "colorMapDescription": "画像からカラーマップを生成", + "lineartAnimeDescription": "アニメスタイルの線画処理", + "imageResolution": "画像解像度", + "megaControl": "メガコントロール", + "lowThreshold": "最低閾値", + "autoConfigure": "プロセッサーを自動設定", + "highThreshold": "最大閾値", + "saveControlImage": "コントロール画像を保存", + "toggleControlNet": "このコントロールネットを切り替え", + "delete": "削除", + "controlAdapter_other": "コントロールアダプター", + "colorMapTileSize": "タイルサイズ", + "ipAdapterImageFallback": "IP Adapterの画像が選択されていません", + "mediapipeFaceDescription": "Mediapipeを使用して顔を検出", + "depthZoeDescription": "Zoeを使用して深度マップを生成", + "setControlImageDimensions": "コントロール画像のサイズを幅と高さにセット", + "resetIPAdapterImage": "IP Adapterの画像をリセット", + "handAndFace": "手と顔", + "enableIPAdapter": "IP Adapterを有効化", + "amult": "a_mult", + "contentShuffleDescription": "画像の内容をシャッフルします", + "bgth": "bg_th", + "controlNetEnabledT2IDisabled": "$t(common.controlNet) が有効化され、$t(common.t2iAdapter)s が無効化されました", + "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))", + "t2iEnabledControlNetDisabled": "$t(common.t2iAdapter) が有効化され、$t(common.controlNet)s が無効化されました", + "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))", + "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))", + "minConfidence": "最小確信度", + "colorMap": "Color", + "noneDescription": "処理は行われていません", + "canny": "Canny", + "hedDescription": "階層的エッジ検出", + "maxFaces": "顔の最大数" + }, + "metadata": { + "seamless": "シームレス", + "Threshold": "ノイズ閾値", + "seed": "シード", + "width": "幅", + "workflow": "ワークフロー", + "steps": "ステップ", + "scheduler": "スケジューラー", + "positivePrompt": "ポジティブプロンプト", + "strength": "Image to Image 強度", + "perlin": "パーリンノイズ", + "recallParameters": "パラメータを呼び出す" + }, + "queue": { + "queueEmpty": "キューが空です", + "pauseSucceeded": "処理が一時停止されました", + "queueFront": "キューの先頭へ追加", + "queueBack": "キューに追加", + "queueCountPrediction": "{{predicted}}をキューに追加", + "queuedCount": "保留中 {{pending}}", + "pause": "一時停止", + "queue": "キュー", + "pauseTooltip": "処理を一時停止", + "cancel": "キャンセル", + "queueTotal": "合計 {{total}}", + "resumeSucceeded": "処理が再開されました", + "resumeTooltip": "処理を再開", + "resume": "再会", + "status": "ステータス", + "pruneSucceeded": "キューから完了アイテム{{item_count}}件を削除しました", + "cancelTooltip": "現在のアイテムをキャンセル", + "in_progress": "進行中", + "notReady": "キューに追加できません", + "batchFailedToQueue": "バッチをキューに追加できませんでした", + "completed": "完了", + "batchValues": "バッチの値", + "cancelFailed": "アイテムのキャンセルに問題があります", + "batchQueued": "バッチをキューに追加しました", + "pauseFailed": "処理の一時停止に問題があります", + "clearFailed": "キューのクリアに問題があります", + "front": "先頭", + "clearSucceeded": "キューがクリアされました", + "pruneTooltip": "{{item_count}} の完了アイテムを削除", + "cancelSucceeded": "アイテムがキャンセルされました", + "batchQueuedDesc_other": "{{count}} セッションをキューの{{direction}}に追加しました", + "graphQueued": "グラフをキューに追加しました", + "batch": "バッチ", + "clearQueueAlertDialog": "キューをクリアすると、処理中のアイテムは直ちにキャンセルされ、キューは完全にクリアされます。", + "pending": "保留中", + "resumeFailed": "処理の再開に問題があります", + "clear": "クリア", + "total": "合計", + "canceled": "キャンセル", + "pruneFailed": "キューの削除に問題があります", + "cancelBatchSucceeded": "バッチがキャンセルされました", + "clearTooltip": "全てのアイテムをキャンセルしてクリア", + "current": "現在", + "failed": "失敗", + "cancelItem": "項目をキャンセル", + "next": "次", + "cancelBatch": "バッチをキャンセル", + "session": "セッション", + "enqueueing": "バッチをキューに追加", + "queueMaxExceeded": "{{max_queue_size}} の最大値を超えたため、{{skip}} をスキップします", + "cancelBatchFailed": "バッチのキャンセルに問題があります", + "clearQueueAlertDialog2": "キューをクリアしてもよろしいですか?", + "item": "アイテム", + "graphFailedToQueue": "グラフをキューに追加できませんでした" + }, + "models": { + "noMatchingModels": "一致するモデルがありません", + "loading": "読み込み中", + "noMatchingLoRAs": "一致するLoRAがありません", + "noLoRAsAvailable": "使用可能なLoRAがありません", + "noModelsAvailable": "使用可能なモデルがありません", + "selectModel": "モデルを選択してください", + "selectLoRA": "LoRAを選択してください" + }, + "nodes": { + "addNode": "ノードを追加", + "boardField": "ボード", + "boolean": "ブーリアン", + "boardFieldDescription": "ギャラリーボード", + "addNodeToolTip": "ノードを追加 (Shift+A, Space)", + "booleanPolymorphicDescription": "ブーリアンのコレクション。", + "inputField": "入力フィールド", + "latentsFieldDescription": "潜在空間はノード間で伝達できます。", + "floatCollectionDescription": "浮動小数点のコレクション。", + "missingTemplate": "テンプレートが見つかりません", + "ipAdapterPolymorphicDescription": "IP-Adaptersのコレクション。", + "latentsPolymorphicDescription": "潜在空間はノード間で伝達できます。", + "colorFieldDescription": "RGBAカラー。", + "ipAdapterCollection": "IP-Adapterコレクション", + "conditioningCollection": "条件付きコレクション", + "hideGraphNodes": "グラフオーバーレイを非表示", + "loadWorkflow": "ワークフローを読み込み", + "integerPolymorphicDescription": "整数のコレクション。", + "hideLegendNodes": "フィールドタイプの凡例を非表示", + "float": "浮動小数点", + "booleanCollectionDescription": "ブーリアンのコレクション。", + "integer": "整数", + "colorField": "カラー", + "nodeTemplate": "ノードテンプレート", + "integerDescription": "整数は小数点を持たない数値です。", + "imagePolymorphicDescription": "画像のコレクション。", + "doesNotExist": "存在しません", + "ipAdapterCollectionDescription": "IP-Adaptersのコレクション。", + "inputMayOnlyHaveOneConnection": "入力は1つの接続しか持つことができません", + "nodeOutputs": "ノード出力", + "currentImageDescription": "ノードエディタ内の現在の画像を表示", + "downloadWorkflow": "ワークフローのJSONをダウンロード", + "integerCollection": "整数コレクション", + "collectionItem": "コレクションアイテム", + "fieldTypesMustMatch": "フィールドタイプが一致している必要があります", + "edge": "輪郭", + "inputNode": "入力ノード", + "imageField": "画像", + "animatedEdgesHelp": "選択したエッジおよび選択したノードに接続されたエッジをアニメーション化します", + "cannotDuplicateConnection": "重複した接続は作れません", + "noWorkflow": "ワークフローがありません", + "integerCollectionDescription": "整数のコレクション。", + "colorPolymorphicDescription": "カラーのコレクション。", + "missingCanvaInitImage": "キャンバスの初期画像が見つかりません", + "clipFieldDescription": "トークナイザーとテキストエンコーダーサブモデル。", + "fullyContainNodesHelp": "ノードは選択ボックス内に完全に存在する必要があります", + "clipField": "クリップ", + "nodeType": "ノードタイプ", + "executionStateInProgress": "処理中", + "executionStateError": "エラー", + "ipAdapterModel": "IP-Adapterモデル", + "ipAdapterDescription": "イメージプロンプトアダプター(IP-Adapter)。", + "missingCanvaInitMaskImages": "キャンバスの初期画像およびマスクが見つかりません", + "hideMinimapnodes": "ミニマップを非表示", + "fitViewportNodes": "全体を表示", + "executionStateCompleted": "完了", + "node": "ノード", + "currentImage": "現在の画像", + "controlField": "コントロール", + "booleanDescription": "ブーリアンはtrueかfalseです。", + "collection": "コレクション", + "ipAdapterModelDescription": "IP-Adapterモデルフィールド", + "cannotConnectInputToInput": "入力から入力には接続できません", + "invalidOutputSchema": "無効な出力スキーマ", + "floatDescription": "浮動小数点は、小数点を持つ数値です。", + "floatPolymorphicDescription": "浮動小数点のコレクション。", + "floatCollection": "浮動小数点コレクション", + "latentsField": "潜在空間", + "cannotConnectOutputToOutput": "出力から出力には接続できません", + "booleanCollection": "ブーリアンコレクション", + "cannotConnectToSelf": "自身のノードには接続できません", + "inputFields": "入力フィールド(複数)", + "colorCodeEdges": "カラー-Code Edges", + "imageCollectionDescription": "画像のコレクション。", + "loadingNodes": "ノードを読み込み中...", + "imageCollection": "画像コレクション" + }, + "boards": { + "autoAddBoard": "自動追加するボード", + "move": "移動", + "menuItemAutoAdd": "このボードに自動追加", + "myBoard": "マイボード", + "searchBoard": "ボードを検索...", + "noMatching": "一致するボードがありません", + "selectBoard": "ボードを選択", + "cancel": "キャンセル", + "addBoard": "ボードを追加", + "uncategorized": "未分類", + "downloadBoard": "ボードをダウンロード", + "changeBoard": "ボードを変更", + "loading": "ロード中...", + "topMessage": "このボードには、以下の機能で使用されている画像が含まれています:", + "bottomMessage": "このボードおよび画像を削除すると、現在これらを利用している機能はリセットされます。", + "clearSearch": "検索をクリア" + }, + "embedding": { + "noMatchingEmbedding": "一致する埋め込みがありません", + "addEmbedding": "埋め込みを追加", + "incompatibleModel": "互換性のないベースモデル:" + }, + "invocationCache": { + "invocationCache": "呼び出しキャッシュ", + "clearSucceeded": "呼び出しキャッシュをクリアしました", + "clearFailed": "呼び出しキャッシュのクリアに問題があります", + "enable": "有効", + "clear": "クリア", + "maxCacheSize": "最大キャッシュサイズ", + "cacheSize": "キャッシュサイズ" } } From 09bb61f630ed50a95b6645534ba8a3de09120e67 Mon Sep 17 00:00:00 2001 From: Fabian Bahl Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 075/119] translationBot(ui): update translation (English) Currently translated at 100.0% (1217 of 1217 strings) Co-authored-by: Fabian Bahl Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/en/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/en.json | 25 +++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 818f9f4fa9..04d817428c 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -70,8 +70,8 @@ "langDutch": "Nederlands", "langEnglish": "English", "langFrench": "Français", - "langGerman": "Deutsch", - "langHebrew": "עברית", + "langGerman": "German", + "langHebrew": "Hebrew", "langItalian": "Italiano", "langJapanese": "日本語", "langKorean": "한국어", @@ -1122,7 +1122,6 @@ "clearIntermediates": "Clear Intermediates", "clearIntermediatesWithCount_one": "Clear {{count}} Intermediate", "clearIntermediatesWithCount_other": "Clear {{count}} Intermediates", - "clearIntermediatesWithCount_zero": "No Intermediates to Clear", "intermediatesCleared_one": "Cleared {{count}} Intermediate", "intermediatesCleared_other": "Cleared {{count}} Intermediates", "intermediatesClearedFailed": "Problem Clearing Intermediates" @@ -1257,11 +1256,15 @@ }, "compositingBlur": { "heading": "Blur", - "paragraphs": ["The blur radius of the mask."] + "paragraphs": [ + "The blur radius of the mask." + ] }, "compositingBlurMethod": { "heading": "Blur Method", - "paragraphs": ["The method of blur applied to the masked area."] + "paragraphs": [ + "The method of blur applied to the masked area." + ] }, "compositingCoherencePass": { "heading": "Coherence Pass", @@ -1271,7 +1274,9 @@ }, "compositingCoherenceMode": { "heading": "Mode", - "paragraphs": ["The mode of the Coherence Pass."] + "paragraphs": [ + "The mode of the Coherence Pass." + ] }, "compositingCoherenceSteps": { "heading": "Steps", @@ -1289,7 +1294,9 @@ }, "compositingMaskAdjustments": { "heading": "Mask Adjustments", - "paragraphs": ["Adjust the mask."] + "paragraphs": [ + "Adjust the mask." + ] }, "controlNetBeginEnd": { "heading": "Begin / End Step Percentage", @@ -1347,7 +1354,9 @@ }, "infillMethod": { "heading": "Infill Method", - "paragraphs": ["Method to infill the selected area."] + "paragraphs": [ + "Method to infill the selected area." + ] }, "lora": { "heading": "LoRA Weight", From 67fb2c81295206340e49cc78055e454ed96ae358 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 076/119] translationBot(ui): update translation (German) Currently translated at 35.5% (433 of 1217 strings) Co-authored-by: Alexander Eichhorn Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 61 +++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 9baa6eb6a2..c8e653d971 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -4,7 +4,7 @@ "reportBugLabel": "Fehler melden", "settingsLabel": "Einstellungen", "img2img": "Bild zu Bild", - "nodes": "Knoten", + "nodes": "Knoten Editor", "langGerman": "Deutsch", "nodesDesc": "Ein knotenbasiertes System, für die Erzeugung von Bildern, ist derzeit in der Entwicklung. Bleiben Sie gespannt auf Updates zu dieser fantastischen Funktion.", "postProcessing": "Nachbearbeitung", @@ -38,7 +38,7 @@ "statusUpscalingESRGAN": "Hochskalierung (ESRGAN)", "statusLoadingModel": "Laden des Modells", "statusModelChanged": "Modell Geändert", - "cancel": "Abbruch", + "cancel": "Abbrechen", "accept": "Annehmen", "back": "Zurück", "langEnglish": "Englisch", @@ -58,7 +58,33 @@ "langArabic": "Arabisch", "langKorean": "Koreanisch", "langHebrew": "Hebräisch", - "langSpanish": "Spanisch" + "langSpanish": "Spanisch", + "t2iAdapter": "T2I Adapter", + "communityLabel": "Gemeinschaft", + "dontAskMeAgain": "Frag mich nicht nochmal", + "loadingInvokeAI": "Lade Invoke AI", + "statusMergedModels": "Modelle zusammengeführt", + "areYouSure": "Bist du dir sicher?", + "statusConvertingModel": "Model konvertieren", + "on": "An", + "nodeEditor": "Knoten Editor", + "statusMergingModels": "Modelle zusammenführen", + "langSimplifiedChinese": "Vereinfachtes Chinesisch", + "ipAdapter": "IP Adapter", + "controlAdapter": "Control Adapter", + "auto": "Automatisch", + "controlNet": "ControlNet", + "imageFailedToLoad": "Kann Bild nicht laden", + "statusModelConverted": "Model konvertiert", + "modelManager": "Model Manager", + "lightMode": "Heller Modus", + "generate": "Erstellen", + "learnMore": "Mehr lernen", + "darkMode": "Dunkler Modus", + "loading": "Laden", + "random": "Zufall", + "batch": "Batch-Manager", + "advanced": "Erweitert" }, "gallery": { "generations": "Erzeugungen", @@ -166,7 +192,7 @@ }, "toggleGalleryPin": { "title": "Galerie anheften umschalten", - "desc": "Heftet die Galerie an die Benutzeroberfläche bzw. löst die sie." + "desc": "Heftet die Galerie an die Benutzeroberfläche bzw. löst die sie" }, "increaseGalleryThumbSize": { "title": "Größe der Galeriebilder erhöhen", @@ -295,7 +321,7 @@ "config": "Konfiguration", "configValidationMsg": "Pfad zur Konfigurationsdatei Ihres Models.", "modelLocation": "Ort des Models", - "modelLocationValidationMsg": "Pfad zum Speicherort Ihres Models.", + "modelLocationValidationMsg": "Pfad zum Speicherort Ihres Models", "vaeLocation": "VAE Ort", "vaeLocationValidationMsg": "Pfad zum Speicherort Ihres VAE.", "width": "Breite", @@ -508,7 +534,7 @@ "uploadImage": "Bild hochladen", "previousImage": "Voriges Bild", "useThisParameter": "Benutze diesen Parameter", - "copyMetadataJson": "Kopiere metadata JSON", + "copyMetadataJson": "Kopiere Metadaten JSON", "zoomIn": "Vergrößern", "rotateClockwise": "Im Uhrzeigersinn drehen", "flipHorizontally": "Horizontal drehen", @@ -520,6 +546,27 @@ "reset": "Zurücksetzen", "nextImage": "Nächstes Bild", "zoomOut": "Verkleinern", - "rotateCounterClockwise": "Gegen den Uhrzeigersinn verdrehen" + "rotateCounterClockwise": "Gegen den Uhrzeigersinn verdrehen", + "showGalleryPanel": "Galeriefenster anzeigen", + "exitViewer": "Betrachten beenden", + "menu": "Menü", + "loadMore": "Mehr laden" + }, + "boards": { + "autoAddBoard": "Automatisches Hinzufügen zum Ordner", + "topMessage": "Dieser Ordner enthält Bilder die in den folgenden Funktionen verwendet werden:", + "move": "Bewegen", + "menuItemAutoAdd": "Automatisches Hinzufügen zu diesem Ordner", + "myBoard": "Meine Ordner", + "searchBoard": "Ordner durchsuchen...", + "noMatching": "Keine passenden Ordner", + "selectBoard": "Ordner aussuchen", + "cancel": "Abbrechen", + "addBoard": "Ordner hinzufügen", + "uncategorized": "Nicht kategorisiert", + "downloadBoard": "Ordner runterladen", + "changeBoard": "Ordner wechseln", + "loading": "Laden...", + "clearSearch": "Suche leeren" } } From 60a105103b2bd8ab90b64a108229e3a8700d7a2a Mon Sep 17 00:00:00 2001 From: Jaulustus Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 077/119] translationBot(ui): update translation (German) Currently translated at 36.0% (439 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 35.5% (433 of 1217 strings) Co-authored-by: Jaulustus Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index c8e653d971..381d5ecbb4 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -543,14 +543,15 @@ "toggleAutoscroll": "Auroscroll ein/ausschalten", "toggleLogViewer": "Log Betrachter ein/ausschalten", "showOptionsPanel": "Zeige Optionen", - "reset": "Zurücksetzen", + "reset": "Zurücksetzten", "nextImage": "Nächstes Bild", "zoomOut": "Verkleinern", "rotateCounterClockwise": "Gegen den Uhrzeigersinn verdrehen", "showGalleryPanel": "Galeriefenster anzeigen", "exitViewer": "Betrachten beenden", "menu": "Menü", - "loadMore": "Mehr laden" + "loadMore": "Mehr laden", + "invokeProgressBar": "Invoke Fortschrittsanzeige" }, "boards": { "autoAddBoard": "Automatisches Hinzufügen zum Ordner", From 54b0c4f3c967da9c9e2054e1f03749266bef8e87 Mon Sep 17 00:00:00 2001 From: Fabian Bahl Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 078/119] translationBot(ui): update translation (German) Currently translated at 37.7% (460 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 36.4% (444 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 36.4% (443 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 36.0% (439 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 35.5% (433 of 1217 strings) Co-authored-by: Fabian Bahl Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 32 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 381d5ecbb4..46fc3f32ac 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -11,7 +11,7 @@ "postProcessDesc1": "InvokeAI bietet eine breite Palette von Nachbearbeitungsfunktionen. Bildhochskalierung und Gesichtsrekonstruktion sind bereits in der WebUI verfügbar. Sie können sie über das Menü Erweiterte Optionen der Reiter Text in Bild und Bild in Bild aufrufen. Sie können Bilder auch direkt bearbeiten, indem Sie die Schaltflächen für Bildaktionen oberhalb der aktuellen Bildanzeige oder im Viewer verwenden.", "postProcessDesc2": "Eine spezielle Benutzeroberfläche wird in Kürze veröffentlicht, um erweiterte Nachbearbeitungs-Workflows zu erleichtern.", "postProcessDesc3": "Die InvokeAI Kommandozeilen-Schnittstelle bietet verschiedene andere Funktionen, darunter Embiggen.", - "training": "Training", + "training": "trainieren", "trainingDesc1": "Ein spezieller Arbeitsablauf zum Trainieren Ihrer eigenen Embeddings und Checkpoints mit Textual Inversion und Dreambooth über die Weboberfläche.", "trainingDesc2": "InvokeAI unterstützt bereits das Training von benutzerdefinierten Embeddings mit Textual Inversion unter Verwendung des Hauptskripts.", "upload": "Hochladen", @@ -84,7 +84,8 @@ "loading": "Laden", "random": "Zufall", "batch": "Batch-Manager", - "advanced": "Erweitert" + "advanced": "Erweitert", + "langBrPortuguese": "Portugiesisch (Brasilien)" }, "gallery": { "generations": "Erzeugungen", @@ -358,7 +359,32 @@ "customConfig": "Benutzerdefinierte Konfiguration", "invokeRoot": "InvokeAI Ordner", "formMessageDiffusersVAELocationDesc": "Falls nicht angegeben, sucht InvokeAI nach der VAE-Datei innerhalb des oben angegebenen Modell Speicherortes.", - "checkpointModels": "Kontrollpunkte" + "checkpointModels": "Kontrollpunkte", + "convert": "Umwandeln", + "addCheckpointModel": "Kontrollpunkt / SafeTensors Modell hinzufügen", + "allModels": "Alle Modelle", + "alpha": "Alpha", + "addDifference": "Unterschied hinzufügen", + "convertToDiffusersHelpText2": "Bei diesem Vorgang wird Ihr Eintrag im Modell-Manager durch die Diffusor-Version desselben Modells ersetzt.", + "convertToDiffusersHelpText5": "Bitte stellen Sie sicher, dass Sie über genügend Speicherplatz verfügen. Die Modelle sind in der Regel zwischen 4 GB und 7 GB groß.", + "convertToDiffusersHelpText3": "Ihre Kontrollpunktdatei auf der Festplatte wird NICHT gelöscht oder in irgendeiner Weise verändert. Sie können Ihren Kontrollpunkt dem Modell-Manager wieder hinzufügen, wenn Sie dies wünschen.", + "convertToDiffusersHelpText4": "Dies ist ein einmaliger Vorgang. Er kann je nach den Spezifikationen Ihres Computers etwa 30-60 Sekunden dauern.", + "convertToDiffusersHelpText6": "Möchten Sie dieses Modell umbauen?", + "custom": "Benutzerdefiniert", + "modelConverted": "Modell umgewandelt", + "inverseSigmoid": "Inverses Sigmoid", + "invokeAIFolder": "Invoke AI Ordner", + "formMessageDiffusersModelLocationDesc": "Bitte geben Sie mindestens einen an.", + "customSaveLocation": "Benutzerdefinierter Speicherort", + "formMessageDiffusersVAELocation": "VAE Speicherort", + "mergedModelCustomSaveLocation": "Benutzerdefinierter Pfad", + "modelMergeHeaderHelp2": "Nur Diffuser sind für die Zusammenführung verfügbar. Wenn Sie ein Kontrollpunktmodell zusammenführen möchten, konvertieren Sie es bitte zuerst in Diffusoren.", + "manual": "Manuell", + "modelManager": "Modell Manager", + "modelMergeAlphaHelp": "Alpha steuert die Überblendungsstärke für die Modelle. Niedrigere Alphawerte führen zu einem geringeren Einfluss des zweiten Modells.", + "modelMergeHeaderHelp1": "Sie können bis zu drei verschiedene Modelle miteinander kombinieren, um eine Mischung zu erstellen, die Ihren Bedürfnissen entspricht.", + "ignoreMismatch": "Unstimmigkeiten zwischen ausgewählten Modellen ignorieren", + "model": "Modell" }, "parameters": { "images": "Bilder", From 015cec197b6f9b512c37dfa57ea5847e60d461fc Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Sun, 29 Oct 2023 12:10:12 +0100 Subject: [PATCH 079/119] translationBot(ui): update translation (German) Currently translated at 37.7% (460 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 36.4% (444 of 1217 strings) translationBot(ui): update translation (German) Currently translated at 36.0% (439 of 1217 strings) Co-authored-by: Alexander Eichhorn Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 46fc3f32ac..9f3bd847a0 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -45,7 +45,7 @@ "langDutch": "Niederländisch", "langFrench": "Französisch", "langItalian": "Italienisch", - "langPortuguese": "Portogisisch", + "langPortuguese": "Portugiesisch", "langRussian": "Russisch", "langUkranian": "Ukrainisch", "hotkeysLabel": "Tastenkombinationen", @@ -81,16 +81,17 @@ "generate": "Erstellen", "learnMore": "Mehr lernen", "darkMode": "Dunkler Modus", - "loading": "Laden", + "loading": "Lade", "random": "Zufall", "batch": "Batch-Manager", "advanced": "Erweitert", - "langBrPortuguese": "Portugiesisch (Brasilien)" + "langBrPortuguese": "Portugiesisch (Brasilien)", + "unifiedCanvas": "Einheitliche Leinwand" }, "gallery": { "generations": "Erzeugungen", "showGenerations": "Zeige Erzeugnisse", - "uploads": "Hochgelades", + "uploads": "Uploads", "showUploads": "Zeige Uploads", "galleryImageSize": "Bildgröße", "galleryImageResetSize": "Größe zurücksetzen", @@ -366,10 +367,10 @@ "alpha": "Alpha", "addDifference": "Unterschied hinzufügen", "convertToDiffusersHelpText2": "Bei diesem Vorgang wird Ihr Eintrag im Modell-Manager durch die Diffusor-Version desselben Modells ersetzt.", - "convertToDiffusersHelpText5": "Bitte stellen Sie sicher, dass Sie über genügend Speicherplatz verfügen. Die Modelle sind in der Regel zwischen 4 GB und 7 GB groß.", + "convertToDiffusersHelpText5": "Bitte stellen Sie sicher, dass Sie über genügend Speicherplatz verfügen. Die Modelle sind in der Regel zwischen 2 GB und 7 GB groß.", "convertToDiffusersHelpText3": "Ihre Kontrollpunktdatei auf der Festplatte wird NICHT gelöscht oder in irgendeiner Weise verändert. Sie können Ihren Kontrollpunkt dem Modell-Manager wieder hinzufügen, wenn Sie dies wünschen.", "convertToDiffusersHelpText4": "Dies ist ein einmaliger Vorgang. Er kann je nach den Spezifikationen Ihres Computers etwa 30-60 Sekunden dauern.", - "convertToDiffusersHelpText6": "Möchten Sie dieses Modell umbauen?", + "convertToDiffusersHelpText6": "Möchten Sie dieses Modell konvertieren?", "custom": "Benutzerdefiniert", "modelConverted": "Modell umgewandelt", "inverseSigmoid": "Inverses Sigmoid", @@ -384,7 +385,8 @@ "modelMergeAlphaHelp": "Alpha steuert die Überblendungsstärke für die Modelle. Niedrigere Alphawerte führen zu einem geringeren Einfluss des zweiten Modells.", "modelMergeHeaderHelp1": "Sie können bis zu drei verschiedene Modelle miteinander kombinieren, um eine Mischung zu erstellen, die Ihren Bedürfnissen entspricht.", "ignoreMismatch": "Unstimmigkeiten zwischen ausgewählten Modellen ignorieren", - "model": "Modell" + "model": "Modell", + "convertToDiffusersSaveLocation": "Speicherort" }, "parameters": { "images": "Bilder", From 8109bc5316bdad78f07178484a50a0016862cb0d Mon Sep 17 00:00:00 2001 From: Fabian Bahl Date: Sun, 29 Oct 2023 14:49:38 +0000 Subject: [PATCH 080/119] translationBot(ui): update translation (German) Currently translated at 40.3% (491 of 1217 strings) Co-authored-by: Fabian Bahl Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 30 +++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 9f3bd847a0..19a6eb51e1 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -386,7 +386,20 @@ "modelMergeHeaderHelp1": "Sie können bis zu drei verschiedene Modelle miteinander kombinieren, um eine Mischung zu erstellen, die Ihren Bedürfnissen entspricht.", "ignoreMismatch": "Unstimmigkeiten zwischen ausgewählten Modellen ignorieren", "model": "Modell", - "convertToDiffusersSaveLocation": "Speicherort" + "convertToDiffusersSaveLocation": "Speicherort", + "pathToCustomConfig": "Pfad zur benutzerdefinierten Konfiguration", + "v1": "v1", + "modelMergeInterpAddDifferenceHelp": "In diesem Modus wird zunächst Modell 3 von Modell 2 subtrahiert. Die resultierende Version wird mit Modell 1 mit dem oben eingestellten Alphasatz gemischt.", + "modelTwo": "Modell 2", + "modelOne": "Modell 1", + "v2_base": "v2 (512px)", + "scanForModels": "Nach Modellen suchen", + "name": "Name", + "safetensorModels": "SafeTensors", + "pickModelType": "Modell Typ auswählen", + "sameFolder": "Gleicher Ordner", + "modelThree": "Modell 3", + "v2_768": "v2 (768px)" }, "parameters": { "images": "Bilder", @@ -423,7 +436,7 @@ "seamCorrectionHeader": "Nahtkorrektur", "infillScalingHeader": "Infill und Skalierung", "img2imgStrength": "Bild-zu-Bild-Stärke", - "toggleLoopback": "Toggle Loopback", + "toggleLoopback": "Loopback umschalten", "sendTo": "Senden an", "sendToImg2Img": "Senden an Bild zu Bild", "sendToUnifiedCanvas": "Senden an Unified Canvas", @@ -438,8 +451,17 @@ "initialImage": "Ursprüngliches Bild", "showOptionsPanel": "Optionsleiste zeigen", "cancel": { - "setType": "Abbruchart festlegen" - } + "setType": "Abbruchart festlegen", + "immediate": "Sofort abbrechen", + "schedule": "Abbrechen nach der aktuellen Iteration", + "isScheduled": "Abbrechen" + }, + "copyImage": "Bild kopieren", + "denoisingStrength": "Stärke der Entrauschung", + "symmetry": "Symmetrie", + "imageToImage": "Bild zu Bild", + "info": "Information", + "general": "Allgemein" }, "settings": { "displayInProgress": "Bilder in Bearbeitung anzeigen", From 249618f6b43afd2acee116d3e0185c05daec9ad6 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Sun, 29 Oct 2023 14:49:39 +0000 Subject: [PATCH 081/119] translationBot(ui): update translation (German) Currently translated at 40.3% (491 of 1217 strings) Co-authored-by: Alexander Eichhorn Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 19a6eb51e1..b483d61928 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -379,7 +379,7 @@ "customSaveLocation": "Benutzerdefinierter Speicherort", "formMessageDiffusersVAELocation": "VAE Speicherort", "mergedModelCustomSaveLocation": "Benutzerdefinierter Pfad", - "modelMergeHeaderHelp2": "Nur Diffuser sind für die Zusammenführung verfügbar. Wenn Sie ein Kontrollpunktmodell zusammenführen möchten, konvertieren Sie es bitte zuerst in Diffusoren.", + "modelMergeHeaderHelp2": "Nur Diffusers sind für die Zusammenführung verfügbar. Wenn Sie ein Kontrollpunktmodell zusammenführen möchten, konvertieren Sie es bitte zuerst in Diffusers.", "manual": "Manuell", "modelManager": "Modell Manager", "modelMergeAlphaHelp": "Alpha steuert die Überblendungsstärke für die Modelle. Niedrigere Alphawerte führen zu einem geringeren Einfluss des zweiten Modells.", @@ -399,7 +399,10 @@ "pickModelType": "Modell Typ auswählen", "sameFolder": "Gleicher Ordner", "modelThree": "Modell 3", - "v2_768": "v2 (768px)" + "v2_768": "v2 (768px)", + "none": "Nix", + "repoIDValidationMsg": "Online Repo Ihres Modells", + "vaeRepoIDValidationMsg": "Online Repo Ihrer VAE" }, "parameters": { "images": "Bilder", @@ -461,7 +464,10 @@ "symmetry": "Symmetrie", "imageToImage": "Bild zu Bild", "info": "Information", - "general": "Allgemein" + "general": "Allgemein", + "hiresStrength": "High Res Stärke", + "hidePreview": "Verstecke Vorschau", + "showPreview": "Zeige Vorschau" }, "settings": { "displayInProgress": "Bilder in Bearbeitung anzeigen", @@ -472,7 +478,9 @@ "resetWebUI": "Web-Oberfläche zurücksetzen", "resetWebUIDesc1": "Das Zurücksetzen der Web-Oberfläche setzt nur den lokalen Cache des Browsers mit Ihren Bildern und gespeicherten Einstellungen zurück. Es werden keine Bilder von der Festplatte gelöscht.", "resetWebUIDesc2": "Wenn die Bilder nicht in der Galerie angezeigt werden oder etwas anderes nicht funktioniert, versuchen Sie bitte, die Einstellungen zurückzusetzen, bevor Sie einen Fehler auf GitHub melden.", - "resetComplete": "Die Web-Oberfläche wurde zurückgesetzt. Aktualisieren Sie die Seite, um sie neu zu laden." + "resetComplete": "Die Web-Oberfläche wurde zurückgesetzt. Aktualisieren Sie die Seite, um sie neu zu laden.", + "models": "Modelle", + "useSlidersForAll": "Schieberegler für alle Optionen verwenden" }, "toast": { "tempFoldersEmptied": "Temp-Ordner geleert", @@ -552,7 +560,7 @@ "autoSaveToGallery": "Automatisch in Galerie speichern", "saveBoxRegionOnly": "Nur Auswahlbox speichern", "limitStrokesToBox": "Striche auf Box beschränken", - "showCanvasDebugInfo": "Leinwand-Debug-Infos anzeigen", + "showCanvasDebugInfo": "Zusätzliche Informationen zur Leinwand anzeigen", "clearCanvasHistory": "Leinwand-Verlauf löschen", "clearHistory": "Verlauf löschen", "clearCanvasHistoryMessage": "Wenn Sie den Verlauf der Leinwand löschen, bleibt die aktuelle Leinwand intakt, aber der Verlauf der Rückgängig- und Wiederherstellung wird unwiderruflich gelöscht.", From 224b09f8fd83b394ffa060a31124099304dd7d9f Mon Sep 17 00:00:00 2001 From: Eugene Brodsky Date: Mon, 30 Oct 2023 12:34:30 -0400 Subject: [PATCH 082/119] Enforce Unix line endings in container (#4990) * (fix) enforce Unix (LF) line endings in docker/ directory * (fix) update docker docs wrt line endings on Windows * (fix) static check fixes --- .gitattributes | 1 + docs/installation/040_INSTALL_DOCKER.md | 11 +++++++++++ invokeai/frontend/install/invokeai_update.py | 2 +- pyproject.toml | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 23dfb4efbd..4c9fc0120e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ # Only affects text files and ignores other file types. # For more info see: https://www.aleksandrhovhannisyan.com/blog/crlf-vs-lf-normalizing-line-endings-in-git/ * text=auto +docker/** text eol=lf \ No newline at end of file diff --git a/docs/installation/040_INSTALL_DOCKER.md b/docs/installation/040_INSTALL_DOCKER.md index a672f71ba8..a550056ce1 100644 --- a/docs/installation/040_INSTALL_DOCKER.md +++ b/docs/installation/040_INSTALL_DOCKER.md @@ -99,3 +99,14 @@ If using an AMD GPU: Use the standard `docker compose up` command, and generally the `docker compose` [CLI](https://docs.docker.com/compose/reference/) as usual. Once the container starts up (and configures the InvokeAI root directory if this is a new installation), you can access InvokeAI at [http://localhost:9090](http://localhost:9090) + +## Troubleshooting / FAQ + +- Q: I am running on Windows under WSL2, and am seeing a "no such file or directory" error. +- A: Your `docker-entrypoint.sh` file likely has Windows (CRLF) as opposed to Unix (LF) line endings, + and you may have cloned this repository before the issue was fixed. To solve this, please change + the line endings in the `docker-entrypoint.sh` file to `LF`. You can do this in VSCode + (`Ctrl+P` and search for "line endings"), or by using the `dos2unix` utility in WSL. + Finally, you may delete `docker-entrypoint.sh` followed by `git pull; git checkout docker/docker-entrypoint.sh` + to reset the file to its most recent version. + For more information on this issue, please see the [Docker Desktop documentation](https://docs.docker.com/desktop/troubleshoot/topics/#avoid-unexpected-syntax-errors-use-unix-style-line-endings-for-files-in-containers) diff --git a/invokeai/frontend/install/invokeai_update.py b/invokeai/frontend/install/invokeai_update.py index cf017dcfeb..ed54a8f10b 100644 --- a/invokeai/frontend/install/invokeai_update.py +++ b/invokeai/frontend/install/invokeai_update.py @@ -91,7 +91,7 @@ def get_extras(): def main(): - versions = [x for x in get_versions() if not (x['draft'] or x['prerelease'])] + versions = [x for x in get_versions() if not (x["draft"] or x["prerelease"])] if invokeai_is_running(): print(":exclamation: [bold red]Please terminate all running instances of InvokeAI before updating.[/red bold]") input("Press any key to continue...") diff --git a/pyproject.toml b/pyproject.toml index d67b096ddc..c0d91cf330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -206,6 +206,7 @@ exclude = [ "build", "dist", "invokeai/frontend/web/node_modules/", + ".venv*", ] [tool.black] From 55bfadfd0b2d642aee54f4ac11d77c678f269177 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:36:16 -0500 Subject: [PATCH 083/119] fix(nodes): fix DenoiseMaskField.masked_latents_name This optional field needs to have a default of `None`. --- invokeai/app/invocations/primitives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/invocations/primitives.py b/invokeai/app/invocations/primitives.py index 88ede88cde..537d616f1f 100644 --- a/invokeai/app/invocations/primitives.py +++ b/invokeai/app/invocations/primitives.py @@ -293,7 +293,7 @@ class DenoiseMaskField(BaseModel): """An inpaint mask field""" mask_name: str = Field(description="The name of the mask image") - masked_latents_name: Optional[str] = Field(description="The name of the masked image latents") + masked_latents_name: Optional[str] = Field(default=None, description="The name of the masked image latents") @invocation_output("denoise_mask_output") From 03a64275c696b4bdc8ddb0b0a815f056502d354a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:15:26 -0500 Subject: [PATCH 084/119] fix(db): fix deprecated pydantic `.json()` method --- .../app/services/workflow_records/workflow_records_sqlite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/services/workflow_records/workflow_records_sqlite.py b/invokeai/app/services/workflow_records/workflow_records_sqlite.py index e9e2bdca3a..b0952e8234 100644 --- a/invokeai/app/services/workflow_records/workflow_records_sqlite.py +++ b/invokeai/app/services/workflow_records/workflow_records_sqlite.py @@ -57,7 +57,7 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase): INSERT INTO workflows(workflow) VALUES (?); """, - (workflow.json(),), + (workflow.model_dump_json(),), ) self._conn.commit() except Exception: From 9721e1382d417ebe4ec665e33159b15c6075295b Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 30 Oct 2023 15:49:27 -0400 Subject: [PATCH 085/119] add option to install latest prerelease --- invokeai/frontend/install/invokeai_update.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/invokeai/frontend/install/invokeai_update.py b/invokeai/frontend/install/invokeai_update.py index ed54a8f10b..b065fcfe5b 100644 --- a/invokeai/frontend/install/invokeai_update.py +++ b/invokeai/frontend/install/invokeai_update.py @@ -50,7 +50,7 @@ def invokeai_is_running() -> bool: return False -def welcome(versions: dict): +def welcome(latest_release: str, latest_prerelease: str): @group() def text(): yield f"InvokeAI Version: [bold yellow]{__version__}" @@ -61,7 +61,8 @@ def welcome(versions: dict): yield "making the web frontend unusable. Please downgrade to the latest release if this happens." yield "" yield "[bold yellow]Options:" - yield f"""[1] Update to the latest official release ([italic]{versions[0]['tag_name']}[/italic]) + yield f"""[1] Update to the latest [bold]official release[/bold] ([italic]{latest_release}[/italic]) +[2] Update to the latest [bold]pre-release[/bold] (may be buggy; caveat emptor!) ([italic]{latest_prerelease}[/italic]) [2] Manually enter the [bold]tag name[/bold] for the version you wish to update to [3] Manually enter the [bold]branch name[/bold] for the version you wish to update to""" @@ -91,13 +92,18 @@ def get_extras(): def main(): - versions = [x for x in get_versions() if not (x["draft"] or x["prerelease"])] + versions = get_versions() + released_versions = [x for x in versions if not (x["draft"] or x["prerelease"])] + prerelease_versions = [x for x in versions if not x["draft"] and x["prerelease"]] + latest_release = released_versions[0]["tag_name"] if len(released_versions) else None + latest_prerelease = prerelease_versions[0]["tag_name"] if len(prerelease_versions) else None + if invokeai_is_running(): print(":exclamation: [bold red]Please terminate all running instances of InvokeAI before updating.[/red bold]") input("Press any key to continue...") return - welcome(versions) + welcome(latest_release, latest_prerelease) tag = None branch = None @@ -105,11 +111,13 @@ def main(): choice = Prompt.ask("Choice:", choices=["1", "2", "3", "4"], default="1") if choice == "1": - release = versions[0]["tag_name"] + release = latest_release elif choice == "2": + release = latest_prerelease + elif choice == "3": while not tag: tag = Prompt.ask("Enter an InvokeAI tag name") - elif choice == "3": + elif choice == "4": while not branch: branch = Prompt.ask("Enter an InvokeAI branch name") From bb68175fd050cdd46f5d61504f154ed5c8613e0e Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Fri, 20 Oct 2023 23:01:13 -0400 Subject: [PATCH 086/119] Add negative IP Adapter support --- invokeai/app/invocations/ip_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/invocations/ip_adapter.py b/invokeai/app/invocations/ip_adapter.py index 8902152538..4fa256552d 100644 --- a/invokeai/app/invocations/ip_adapter.py +++ b/invokeai/app/invocations/ip_adapter.py @@ -67,7 +67,7 @@ class IPAdapterInvocation(BaseInvocation): # weight: float = InputField(default=1.0, description="The weight of the IP-Adapter.", ui_type=UIType.Float) weight: Union[float, List[float]] = InputField( - default=1, ge=0, description="The weight given to the IP-Adapter", ui_type=UIType.Float, title="Weight" + default=1, ge=-1, description="The weight given to the IP-Adapter", ui_type=UIType.Float, title="Weight" ) begin_step_percent: float = InputField( From 8481db96edd3df2cae9e0af56be4eb5b06aee824 Mon Sep 17 00:00:00 2001 From: Millun Atluri Date: Tue, 31 Oct 2023 16:06:48 +1100 Subject: [PATCH 087/119] Updated workflows --- docs/nodes/exampleWorkflows.md | 12 +- ...N_img2img_upscale_w_Canny_ControlNet.json} | 1382 ++++++----- docs/workflows/FaceMask.json | 822 +++---- docs/workflows/FaceOff_FaceScale2x.json | 1356 +++++------ ...ce_Detailer_with_IP-Adapter_and_Canny.json | 2032 +++++++++++++++++ .../Multi_ControlNet_Canny_and_Depth.json | 985 ++++++++ docs/workflows/Prompt_from_File.json | 719 ++++++ docs/workflows/QR_Code_Monster.json | 758 ++++++ docs/workflows/SDXL_Text_to_Image.json | 432 ++-- .../SDXL_w_Refiner_Text_to_Image.json | 973 ++++---- docs/workflows/Text_to_Image.json | 366 +-- 11 files changed, 7230 insertions(+), 2607 deletions(-) rename docs/workflows/{ESRGAN_img2img_upscale w_Canny_ControlNet.json => ESRGAN_img2img_upscale_w_Canny_ControlNet.json} (55%) create mode 100644 docs/workflows/Face_Detailer_with_IP-Adapter_and_Canny.json create mode 100644 docs/workflows/Multi_ControlNet_Canny_and_Depth.json create mode 100644 docs/workflows/Prompt_from_File.json create mode 100644 docs/workflows/QR_Code_Monster.json diff --git a/docs/nodes/exampleWorkflows.md b/docs/nodes/exampleWorkflows.md index f0159bd77c..568283585c 100644 --- a/docs/nodes/exampleWorkflows.md +++ b/docs/nodes/exampleWorkflows.md @@ -2,13 +2,17 @@ We've curated some example workflows for you to get started with Workflows in InvokeAI -To use them, right click on your desired workflow, press "Download Linked File". You can then use the "Load Workflow" functionality in InvokeAI to load the workflow and start generating images! +To use them, right click on your desired workflow, follow the link to GitHub and click the "⬇" button to download the raw file. You can then use the "Load Workflow" functionality in InvokeAI to load the workflow and start generating images! If you're interested in finding more workflows, checkout the [#share-your-workflows](https://discord.com/channels/1020123559063990373/1130291608097661000) channel in the InvokeAI Discord. * [SD1.5 / SD2 Text to Image](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/Text_to_Image.json) -* [SDXL Text to Image](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/SDXL_Text_to_Image.json) -* [SDXL (with Refiner) Text to Image](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/SDXL_Text_to_Image.json) -* [Tiled Upscaling with ControlNet](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/ESRGAN_img2img_upscale w_Canny_ControlNet.json) +* [SDXL Text to Image](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/SDXL_Text_to_Image.json) +* [SDXL Text to Image with Refiner](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/SDXL_w_Refiner_Text_to_Image.json) +* [Multi ControlNet (Canny & Depth)](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/Multi_ControlNet_Canny_and_Depth.json) +* [Tiled Upscaling with ControlNet](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/ESRGAN_img2img_upscale_w_Canny_ControlNet.json) +* [Prompt From File](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/Prompt_from_File.json) +* [Face Detailer with IP-Adapter & ControlNet](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/Face_Detailer_with_IP-Adapter_and_Canny.json.json) * [FaceMask](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/FaceMask.json) * [FaceOff with 2x Face Scaling](https://github.com/invoke-ai/InvokeAI/blob/main/docs/workflows/FaceOff_FaceScale2x.json) +* [QR Code Monster](https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/QR_Code_Monster.json) \ No newline at end of file diff --git a/docs/workflows/ESRGAN_img2img_upscale w_Canny_ControlNet.json b/docs/workflows/ESRGAN_img2img_upscale_w_Canny_ControlNet.json similarity index 55% rename from docs/workflows/ESRGAN_img2img_upscale w_Canny_ControlNet.json rename to docs/workflows/ESRGAN_img2img_upscale_w_Canny_ControlNet.json index c963ace025..17222aa002 100644 --- a/docs/workflows/ESRGAN_img2img_upscale w_Canny_ControlNet.json +++ b/docs/workflows/ESRGAN_img2img_upscale_w_Canny_ControlNet.json @@ -1,5 +1,5 @@ { - "name": "ESRGAN img2img upscale w_ Lineart ControlNet", + "name": "ESRGAN img2img upscale w_ Canny ControlNet", "author": "InvokeAI", "description": "Sample workflow for using Upscaling with ControlNet with SD1.5", "version": "1.0.1", @@ -8,20 +8,16 @@ "notes": "", "exposedFields": [ { - "nodeId": "aba70c57-2495-4ec1-8d23-02b1d11445c7", + "nodeId": "d8ace142-c05f-4f1d-8982-88dc7473958d", "fieldName": "model" }, { - "nodeId": "c394834e-cab7-4c0c-919e-2e35eba7f34e", - "fieldName": "prompt" - }, - { - "nodeId": "465c7e6e-278f-49b0-87ab-642e88cd076f", - "fieldName": "prompt" - }, - { - "nodeId": "4e2833b2-5d35-45ec-ae65-89ea1846a3f4", + "nodeId": "771bdf6a-0813-4099-a5d8-921a138754d4", "fieldName": "image" + }, + { + "nodeId": "63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16b", + "fieldName": "prompt" } ], "meta": { @@ -29,14 +25,60 @@ }, "nodes": [ { - "id": "aba70c57-2495-4ec1-8d23-02b1d11445c7", + "id": "e8bf67fe-67de-4227-87eb-79e86afdfc74", "type": "invocation", "data": { - "id": "aba70c57-2495-4ec1-8d23-02b1d11445c7", + "id": "e8bf67fe-67de-4227-87eb-79e86afdfc74", + "type": "compel", + "inputs": { + "prompt": { + "id": "5f762fae-d791-42d9-8ab5-2b830c33ff20", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "8ac95f40-317d-4513-bbba-b99effd3b438", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "46c65b2b-c0b5-40c2-b183-74e9451c6d56", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 1261.0015571435993, + "y": 1513.9276360694537 + } + }, + { + "id": "d8ace142-c05f-4f1d-8982-88dc7473958d", + "type": "invocation", + "data": { + "id": "d8ace142-c05f-4f1d-8982-88dc7473958d", "type": "main_model_loader", "inputs": { "model": { - "id": "4fcc98ee-1c70-4ad3-aaee-df72e0d4ecb9", + "id": "b35ae88a-f2d2-43f6-958c-8c624391250f", "name": "model", "type": "MainModelField", "fieldKind": "input", @@ -50,19 +92,19 @@ }, "outputs": { "unet": { - "id": "3ecbc0ff-a7b0-43de-a81f-039210cbda50", + "id": "02f243cb-c6e2-42c5-8be9-ef0519d54383", "name": "unet", "type": "UNetField", "fieldKind": "output" }, "clip": { - "id": "4e55bd72-5409-4fba-9929-4177e4ae9c34", + "id": "7762ed13-5b28-40f4-85f1-710942ceb92a", "name": "clip", "type": "ClipField", "fieldKind": "output" }, "vae": { - "id": "0095495c-4424-451f-a8f5-26dc840a3c56", + "id": "69566153-1918-417d-a3bb-32e9e857ef6b", "name": "vae", "type": "VaeField", "fieldKind": "output" @@ -72,256 +114,26 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 202, + "height": 226, "position": { - "x": 175, - "y": 300 + "x": 433.44132965778, + "y": 1419.9552496403696 } }, { - "id": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", + "id": "771bdf6a-0813-4099-a5d8-921a138754d4", "type": "invocation", "data": { - "id": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", - "type": "noise", - "inputs": { - "seed": { - "id": "a64e30f7-f9f4-4d67-a5aa-af5924205f92", - "name": "seed", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "width": { - "id": "054eaa35-63af-41c9-b13f-e9c2aaeeca43", - "name": "width", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 512 - }, - "height": { - "id": "6e9a642c-fe1d-477f-ae66-1706471f7d73", - "name": "height", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 512 - }, - "use_cpu": { - "id": "caa3c8ba-aed5-44d8-88d9-4f48a75d59a4", - "name": "use_cpu", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": true - } - }, - "outputs": { - "noise": { - "id": "133dbb18-f862-430b-b9a0-613aa8e61c7d", - "name": "noise", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "2e31961a-af0c-497b-9ae2-429cb6c2f5a1", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "eca33bb8-37bb-4bfd-b7c7-3dba01207374", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": false, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 32, - "position": { - "x": 1400, - "y": 650 - } - }, - { - "id": "c2172a8b-1b5f-4330-acbe-dd2565c3b988", - "type": "invocation", - "data": { - "id": "c2172a8b-1b5f-4330-acbe-dd2565c3b988", - "type": "l2i", - "inputs": { - "tiled": { - "id": "406bccc1-d757-4578-b46e-be6141c03385", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "960ec115-547c-45c8-af2a-569214d9409c", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "latents": { - "id": "c8658cc5-3762-499d-9cad-eceb8f9dde4e", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "c35cf05c-0985-4bc4-9b05-0c89799bb888", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "25afb2bc-c964-4cd3-8332-4d0e9ea65d3a", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "aff7065e-8ce0-44aa-bb6e-d16925279fdd", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "6f5e8706-7a9b-4455-beb8-3d2e2ceabbc2", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false - }, - "width": 320, - "height": 266, - "position": { - "x": 2225, - "y": 450 - } - }, - { - "id": "c394834e-cab7-4c0c-919e-2e35eba7f34e", - "type": "invocation", - "data": { - "id": "c394834e-cab7-4c0c-919e-2e35eba7f34e", - "type": "compel", - "inputs": { - "prompt": { - "id": "fef594dd-07d3-47e6-97d0-1803b55a0f26", - "name": "prompt", - "type": "string", - "fieldKind": "input", - "label": "Positive Prompt", - "value": "tiger" - }, - "clip": { - "id": "e5639045-aa13-48c2-a172-869774aecab6", - "name": "clip", - "type": "ClipField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "conditioning": { - "id": "3249093e-0bc4-42a7-8a9b-2172fb89e915", - "name": "conditioning", - "type": "ConditioningField", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 235, - "position": { - "x": 975, - "y": -25 - } - }, - { - "id": "465c7e6e-278f-49b0-87ab-642e88cd076f", - "type": "invocation", - "data": { - "id": "465c7e6e-278f-49b0-87ab-642e88cd076f", - "type": "compel", - "inputs": { - "prompt": { - "id": "9a3ac8ea-7655-4806-ab8c-b7a18a253181", - "name": "prompt", - "type": "string", - "fieldKind": "input", - "label": "Negative Prompt", - "value": "" - }, - "clip": { - "id": "1d348def-bb7d-4bab-b983-9f55c933ea67", - "name": "clip", - "type": "ClipField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "conditioning": { - "id": "f92febc1-67c4-45d4-b2e4-9ba470e4ccef", - "name": "conditioning", - "type": "ConditioningField", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 235, - "position": { - "x": 975, - "y": 250 - } - }, - { - "id": "4e2833b2-5d35-45ec-ae65-89ea1846a3f4", - "type": "invocation", - "data": { - "id": "4e2833b2-5d35-45ec-ae65-89ea1846a3f4", + "id": "771bdf6a-0813-4099-a5d8-921a138754d4", "type": "image", "inputs": { "image": { - "id": "0b2f59b4-9994-4c99-9309-5434c746abb9", + "id": "0f6d68a2-38bd-4f65-a112-0a256c7a2678", "name": "image", "type": "ImageField", "fieldKind": "input", @@ -330,19 +142,19 @@ }, "outputs": { "image": { - "id": "9a41092e-50ec-4530-95b2-33d9207a8f50", + "id": "76f6f9b6-755b-4373-93fa-6a779998d2c8", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "6462e3b2-6450-45fd-9fee-0fbe25537ed0", + "id": "6858e46b-707c-444f-beda-9b5f4aecfdf8", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "94c0d477-8753-4976-ba91-b9eb7ad71285", + "id": "421bdc6e-ecd1-4935-9665-d38ab8314f79", "name": "height", "type": "integer", "fieldKind": "output" @@ -352,299 +164,70 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 225, "position": { - "x": 50, - "y": 750 + "x": 11.612243766002848, + "y": 1989.909405085168 } }, { - "id": "a7f1336d-516d-4735-826f-3c633dfaa5e8", + "id": "f7564dd2-9539-47f2-ac13-190804461f4e", "type": "invocation", "data": { - "id": "a7f1336d-516d-4735-826f-3c633dfaa5e8", - "type": "i2l", - "inputs": { - "image": { - "id": "b69df743-8045-4ffe-bb14-71b7f9c17c5f", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "a98a3497-34c5-46f7-9eaf-c24eab5d481a", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - }, - "tiled": { - "id": "706dc2c8-1820-42a7-98e1-bcd631737e7b", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "5fc3bc04-c66e-46db-be2a-470c9d64b0d8", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - } - }, - "outputs": { - "latents": { - "id": "50b89da5-e7ed-45cd-b74e-83c07e510ccd", - "name": "latents", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "7be69dad-837f-4c98-8ae2-c7aacaa44b52", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "66e3c7ec-3848-4afb-84bb-ff3a09e47089", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 299, - "position": { - "x": 975, - "y": 525 - } - }, - { - "id": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "type": "invocation", - "data": { - "id": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "type": "denoise_latents", - "inputs": { - "noise": { - "id": "6b894db2-ee45-45b6-b531-573311ddea73", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "7e7693fe-6c0c-464a-8535-2ed517766c19", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 64 - }, - "cfg_scale": { - "id": "890ba738-690c-44a3-97cd-c589257b531a", - "name": "cfg_scale", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 7.5 - }, - "denoising_start": { - "id": "0e157ca8-5c06-499a-be6d-283fb834df32", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.7 - }, - "denoising_end": { - "id": "915bc497-cb58-40a5-8089-2ece7213be21", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 1 - }, - "scheduler": { - "id": "694471cd-8708-411b-9d88-2ae725254ff0", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler_a" - }, - "control": { - "id": "b14cff5e-30ea-4d61-b27c-8247063699ad", - "name": "control", - "type": "ControlField", - "fieldKind": "input", - "label": "" - }, - "latents": { - "id": "0528dbfd-d661-4c73-b493-722b27e37201", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "denoise_mask": { - "id": "ea7d6070-4f00-4b77-b49e-ffe1ca0e3fea", - "name": "denoise_mask", - "type": "DenoiseMaskField", - "fieldKind": "input", - "label": "" - }, - "positive_conditioning": { - "id": "56a3fa76-9eb4-4680-8a4d-169696034525", - "name": "positive_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "negative_conditioning": { - "id": "0eed85bc-d5bd-4de4-8155-0c08f1ac5e32", - "name": "negative_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "87ab9e45-a92f-4d47-a9f6-a65fe23373de", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "latents": { - "id": "d12e0bd6-7d35-4d12-84c0-540c26ba01c8", - "name": "latents", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "201ca444-2d10-4bab-b6be-e1b5be97e1b0", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "74ce84a5-b68c-4503-8a7d-bc017024678a", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 558, - "position": { - "x": 1800, - "y": 350 - } - }, - { - "id": "39abdb3e-f8d1-4b0a-bab1-547d9e25b78e", - "type": "invocation", - "data": { - "id": "39abdb3e-f8d1-4b0a-bab1-547d9e25b78e", - "type": "rand_int", - "inputs": { - "low": { - "id": "10eff2d0-929f-45ca-a1ba-68c3e742db71", - "name": "low", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "high": { - "id": "b6e39169-e6ee-496a-8046-5444497036c2", - "name": "high", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 2147483647 - } - }, - "outputs": { - "value": { - "id": "cc477a7a-36bc-458f-b7ac-6717bac6f12b", - "name": "value", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": false, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 32, - "position": { - "x": 975, - "y": 850 - } - }, - { - "id": "08c41d50-fb10-43a9-a58b-fc15ee678a83", - "type": "invocation", - "data": { - "id": "08c41d50-fb10-43a9-a58b-fc15ee678a83", + "id": "f7564dd2-9539-47f2-ac13-190804461f4e", "type": "esrgan", "inputs": { + "metadata": { + "id": "8fa0c7eb-5bd3-4575-98e7-72285c532504", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, "image": { - "id": "01b92996-26aa-412b-9eba-d13cb7b370a8", + "id": "3c949799-a504-41c9-b342-cff4b8146c48", "name": "image", "type": "ImageField", "fieldKind": "input", "label": "" }, "model_name": { - "id": "3fc7bf6a-e181-4236-b746-48b011351af1", + "id": "77cb4750-53d6-4c2c-bb5c-145981acbf17", "name": "model_name", "type": "enum", "fieldKind": "input", "label": "", - "value": "RealESRGAN_x2plus.pth" + "value": "RealESRGAN_x4plus.pth" + }, + "tile_size": { + "id": "7787b3ad-46ee-4248-995f-bc740e1f988b", + "name": "tile_size", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 400 } }, "outputs": { "image": { - "id": "6feb0664-c61d-4fcd-8226-ed81591dcb0c", + "id": "37e6308e-e926-4e07-b0db-4e8601f495d0", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "61650a80-7d2f-4509-8600-574c5cc6e569", + "id": "c194d84a-fac7-4856-b646-d08477a5ad2b", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "fcb00841-f068-475e-ac90-0874313fd7fa", + "id": "b2a6206c-a9c8-4271-a055-0b93a7f7d505", "name": "height", "type": "integer", "fieldKind": "output" @@ -654,31 +237,106 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.1.0" }, "width": 320, - "height": 282, + "height": 339, "position": { - "x": 475, - "y": 725 + "x": 436.07457889056195, + "y": 1967.3109314112623 } }, { - "id": "30598d37-cf80-4e12-896a-7683cf727e77", + "id": "1d887701-df21-4966-ae6e-a7d82307d7bd", "type": "invocation", "data": { - "id": "30598d37-cf80-4e12-896a-7683cf727e77", + "id": "1d887701-df21-4966-ae6e-a7d82307d7bd", + "type": "canny_image_processor", + "inputs": { + "metadata": { + "id": "52c877c8-25d9-4949-8518-f536fcdd152d", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "e0af11fe-4f95-4193-a599-cf40b6a963f5", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "low_threshold": { + "id": "ab775f7b-f556-4298-a9d6-2274f3a6c77c", + "name": "low_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 100 + }, + "high_threshold": { + "id": "9e58b615-06e4-417f-b0d8-63f1574cd174", + "name": "high_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 200 + } + }, + "outputs": { + "image": { + "id": "61feb8bf-95c9-4634-87e2-887fc43edbdf", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "9e203e41-73f7-4cfa-bdca-5040e5e60c55", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "ec7d99dc-0d82-4495-a759-6423808bff1c", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 1221.7155516160597, + "y": 1971.0099052871012 + } + }, + { + "id": "ca1d020c-89a8-4958-880a-016d28775cfa", + "type": "invocation", + "data": { + "id": "ca1d020c-89a8-4958-880a-016d28775cfa", "type": "controlnet", "inputs": { "image": { - "id": "d44259eb-bc93-4d4b-9665-a7895e5a77ab", + "id": "2973c126-e301-4595-a7dc-d6e1729ccdbf", "name": "image", "type": "ImageField", "fieldKind": "input", "label": "" }, "control_model": { - "id": "2021065f-d5c9-47ad-bfea-03eea03a19ce", + "id": "4bb4d987-8491-4839-b41b-6e2f546fe2d0", "name": "control_model", "type": "ControlNetModelField", "fieldKind": "input", @@ -689,15 +347,15 @@ } }, "control_weight": { - "id": "f856e29f-303f-4507-8c39-71ccc636f67c", + "id": "a3cf387a-b58f-4058-858f-6a918efac609", "name": "control_weight", - "type": "float", + "type": "FloatPolymorphic", "fieldKind": "input", "label": "", "value": 1 }, "begin_step_percent": { - "id": "f9187fa7-1510-439d-9c9b-e5fa990639b0", + "id": "e0614f69-8a58-408b-9238-d3a44a4db4e0", "name": "begin_step_percent", "type": "float", "fieldKind": "input", @@ -705,7 +363,7 @@ "value": 0 }, "end_step_percent": { - "id": "3f7c15c3-2b80-49a8-8eec-57d277c37364", + "id": "ac683539-b6ed-4166-9294-2040e3ede206", "name": "end_step_percent", "type": "float", "fieldKind": "input", @@ -713,7 +371,7 @@ "value": 1 }, "control_mode": { - "id": "f34cb991-ecb5-423c-865f-9890b2fa9d23", + "id": "f00b21de-cbd7-4901-8efc-e7134a2dc4c8", "name": "control_mode", "type": "enum", "fieldKind": "input", @@ -721,7 +379,7 @@ "value": "balanced" }, "resize_mode": { - "id": "552142f6-f6a6-4291-803c-68caefec7c6d", + "id": "cafb60ee-3959-4d57-a06c-13b83be6ea4f", "name": "resize_mode", "type": "enum", "fieldKind": "input", @@ -731,7 +389,7 @@ }, "outputs": { "control": { - "id": "6160265b-4a8d-4fc5-8e1f-d793a353d2db", + "id": "dfb88dd1-12bf-4034-9268-e726f894c131", "name": "control", "type": "ControlField", "fieldKind": "output" @@ -741,101 +399,218 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 480, + "height": 508, "position": { - "x": 1375, - "y": 875 + "x": 1681.7783532660528, + "y": 1845.0516454465633 } }, { - "id": "b79732f8-6126-4d06-9c8a-4e84bd5b1ac9", + "id": "f50624ce-82bf-41d0-bdf7-8aab11a80d48", "type": "invocation", "data": { - "id": "b79732f8-6126-4d06-9c8a-4e84bd5b1ac9", - "type": "vae_loader", + "id": "f50624ce-82bf-41d0-bdf7-8aab11a80d48", + "type": "noise", "inputs": { - "vae_model": { - "id": "b68038ae-b8cb-4e29-9581-da50d55af462", - "name": "vae_model", - "type": "VaeModelField", - "fieldKind": "input", - "label": "", - "value": { - "model_name": "sd-vae-ft-mse", - "base_model": "sd-1" - } - } - }, - "outputs": { - "vae": { - "id": "82f4ba9d-5e3a-4b48-b7a4-37de956663d7", - "name": "vae", - "type": "VaeField", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 138, - "position": { - "x": 175, - "y": 525 - } - }, - { - "id": "b10d39ab-7bc9-48bc-b883-2fd50920876d", - "type": "invocation", - "data": { - "id": "b10d39ab-7bc9-48bc-b883-2fd50920876d", - "type": "canny_image_processor", - "inputs": { - "image": { - "id": "dee9cdf2-9b3f-4d20-8433-ef7d6f6526bd", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "low_threshold": { - "id": "4eaefd37-9fbe-4b73-8a17-c60d4e1d7e39", - "name": "low_threshold", + "seed": { + "id": "f76b0e01-b601-423f-9b5f-ab7a1f10fe82", + "name": "seed", "type": "integer", "fieldKind": "input", "label": "", - "value": 100 + "value": 0 }, - "high_threshold": { - "id": "c394720b-546b-464e-8f53-d20bfda4ee04", - "name": "high_threshold", + "width": { + "id": "eec326d6-710c-45de-a25c-95704c80d7e2", + "name": "width", "type": "integer", "fieldKind": "input", "label": "", - "value": 200 + "value": 512 + }, + "height": { + "id": "2794a27d-5337-43ca-95d9-41b673642c94", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "use_cpu": { + "id": "ae7654e3-979e-44a1-8968-7e3199e91e66", + "name": "use_cpu", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true } }, "outputs": { - "image": { - "id": "80fcdf76-dfc3-41a1-99ea-5ab2aa5fde07", - "name": "image", - "type": "ImageField", + "noise": { + "id": "8b6dc166-4ead-4124-8ac9-529814b0cbb9", + "name": "noise", + "type": "LatentsField", "fieldKind": "output" }, "width": { - "id": "3fa5e5a9-ff60-44d2-8d91-635d0c798f15", + "id": "e3fe3940-a277-4838-a448-5f81f2a7d99d", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "01a10c42-d485-4436-af8b-03d71c59bc8c", + "id": "48ecd6ef-c216-40d5-9d1b-d37bd00c82e7", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": false, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 32, + "position": { + "x": 1660.5387878479382, + "y": 1664.7391082353483 + } + }, + { + "id": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "type": "invocation", + "data": { + "id": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "e127084b-72f5-4fe4-892b-84f34f88bce9", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "72cde4ee-55de-4d3e-9057-74e741c04e20", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "747f7023-1c19-465b-bec8-1d9695dd3505", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "80860292-633c-46f2-83d0-60d0029b65d2", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "ebc71e6f-9148-4f12-b455-5e1f179d1c3a", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "ced44b8f-3bad-4c34-8113-13bc0faed28a", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "79bf4b77-3502-4f72-ba8b-269c4c3c5c72", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "ed56e2b8-f477-41a2-b9f5-f15f4933ae65", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "146b790c-b08e-437c-a2e1-e393c2c1c41a", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "75ed3df1-d261-4b8e-a89b-341c4d7161fb", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "eab9a61d-9b64-44d3-8d90-4686f5887cb0", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "2dc8d637-58fd-4069-ad33-85c32d958b7b", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "6767e40a-97c6-4487-b3c9-cad1c150bf9f", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "6251efda-d97d-4ff1-94b5-8cc6b458c184", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "4e7986a4-dff2-4448-b16b-1af477b81f8b", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "dad525dd-d2f8-4f07-8c8d-51f2a3c5456e", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "af03a089-4739-40c6-8b48-25d458d63c2f", "name": "height", "type": "integer", "fieldKind": "output" @@ -845,165 +620,344 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" }, "width": 320, - "height": 339, + "height": 646, "position": { - "x": 925, - "y": 925 + "x": 2128.740065979906, + "y": 1232.6219060454753 + } + }, + { + "id": "3ed9b2ef-f4ec-40a7-94db-92e63b583ec0", + "type": "invocation", + "data": { + "id": "3ed9b2ef-f4ec-40a7-94db-92e63b583ec0", + "type": "l2i", + "inputs": { + "metadata": { + "id": "9f7a1a9f-7861-4f09-874b-831af89b7474", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "a5b42432-8ee7-48cd-b61c-b97be6e490a2", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "890de106-e6c3-4c2c-8d67-b368def64894", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "b8e5a2ca-5fbc-49bd-ad4c-ea0e109d46e3", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "fdaf6264-4593-4bd2-ac71-8a0acff261af", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "94c5877d-6c78-4662-a836-8a84fc75d0a0", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "2a854e42-1616-42f5-b9ef-7b73c40afc1d", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "dd649053-1433-4f31-90b3-8bb103efc5b1", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": false, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 2559.4751127537957, + "y": 1246.6000376741406 + } + }, + { + "id": "5ca498a4-c8c8-4580-a396-0c984317205d", + "type": "invocation", + "data": { + "id": "5ca498a4-c8c8-4580-a396-0c984317205d", + "type": "i2l", + "inputs": { + "image": { + "id": "9e6c4010-0f79-4587-9062-29d9a8f96b3b", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "b9ed2ec4-e8e3-4d69-8a42-27f2d983bcd6", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "bb48d10b-2440-4c46-b835-646ae5ebc013", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "1048612c-c0f4-4abf-a684-0045e7d158f8", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "latents": { + "id": "55301367-0578-4dee-8060-031ae13c7bf8", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "2eb65690-1f20-4070-afbd-1e771b9f8ca9", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "d5bf64c7-c30f-43b8-9bc2-95e7718c1bdc", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 325, + "position": { + "x": 848.091172736516, + "y": 1618.7467772496016 + } + }, + { + "id": "63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16b", + "type": "invocation", + "data": { + "id": "63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16b", + "type": "compel", + "inputs": { + "prompt": { + "id": "5f762fae-d791-42d9-8ab5-2b830c33ff20", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "8ac95f40-317d-4513-bbba-b99effd3b438", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "46c65b2b-c0b5-40c2-b183-74e9451c6d56", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 1280.0309709777139, + "y": 1213.3027983934699 } } ], "edges": [ { - "source": "39abdb3e-f8d1-4b0a-bab1-547d9e25b78e", - "target": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", - "id": "39abdb3e-f8d1-4b0a-bab1-547d9e25b78e-167ffc36-4cb7-425c-ae55-e88f80a1d6fe-collapsed", - "type": "collapsed" - }, - { - "source": "aba70c57-2495-4ec1-8d23-02b1d11445c7", - "sourceHandle": "clip", - "target": "c394834e-cab7-4c0c-919e-2e35eba7f34e", - "targetHandle": "clip", - "id": "reactflow__edge-aba70c57-2495-4ec1-8d23-02b1d11445c7clip-c394834e-cab7-4c0c-919e-2e35eba7f34eclip", + "source": "771bdf6a-0813-4099-a5d8-921a138754d4", + "sourceHandle": "image", + "target": "f7564dd2-9539-47f2-ac13-190804461f4e", + "targetHandle": "image", + "id": "reactflow__edge-771bdf6a-0813-4099-a5d8-921a138754d4image-f7564dd2-9539-47f2-ac13-190804461f4eimage", "type": "default" }, { - "source": "aba70c57-2495-4ec1-8d23-02b1d11445c7", - "sourceHandle": "clip", - "target": "465c7e6e-278f-49b0-87ab-642e88cd076f", - "targetHandle": "clip", - "id": "reactflow__edge-aba70c57-2495-4ec1-8d23-02b1d11445c7clip-465c7e6e-278f-49b0-87ab-642e88cd076fclip", + "source": "f7564dd2-9539-47f2-ac13-190804461f4e", + "sourceHandle": "image", + "target": "1d887701-df21-4966-ae6e-a7d82307d7bd", + "targetHandle": "image", + "id": "reactflow__edge-f7564dd2-9539-47f2-ac13-190804461f4eimage-1d887701-df21-4966-ae6e-a7d82307d7bdimage", "type": "default" }, { - "source": "aba70c57-2495-4ec1-8d23-02b1d11445c7", - "sourceHandle": "vae", - "target": "a7f1336d-516d-4735-826f-3c633dfaa5e8", - "targetHandle": "vae", - "id": "reactflow__edge-aba70c57-2495-4ec1-8d23-02b1d11445c7vae-a7f1336d-516d-4735-826f-3c633dfaa5e8vae", - "type": "default" - }, - { - "source": "aba70c57-2495-4ec1-8d23-02b1d11445c7", - "sourceHandle": "unet", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "targetHandle": "unet", - "id": "reactflow__edge-aba70c57-2495-4ec1-8d23-02b1d11445c7unet-61613ab2-784d-4a5c-8576-18fd5da065efunet", - "type": "default" - }, - { - "source": "465c7e6e-278f-49b0-87ab-642e88cd076f", - "sourceHandle": "conditioning", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "targetHandle": "negative_conditioning", - "id": "reactflow__edge-465c7e6e-278f-49b0-87ab-642e88cd076fconditioning-61613ab2-784d-4a5c-8576-18fd5da065efnegative_conditioning", - "type": "default" - }, - { - "source": "c394834e-cab7-4c0c-919e-2e35eba7f34e", - "sourceHandle": "conditioning", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-c394834e-cab7-4c0c-919e-2e35eba7f34econditioning-61613ab2-784d-4a5c-8576-18fd5da065efpositive_conditioning", - "type": "default" - }, - { - "source": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", - "sourceHandle": "noise", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "targetHandle": "noise", - "id": "reactflow__edge-167ffc36-4cb7-425c-ae55-e88f80a1d6fenoise-61613ab2-784d-4a5c-8576-18fd5da065efnoise", - "type": "default" - }, - { - "source": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "sourceHandle": "latents", - "target": "c2172a8b-1b5f-4330-acbe-dd2565c3b988", - "targetHandle": "latents", - "id": "reactflow__edge-61613ab2-784d-4a5c-8576-18fd5da065eflatents-c2172a8b-1b5f-4330-acbe-dd2565c3b988latents", - "type": "default" - }, - { - "source": "a7f1336d-516d-4735-826f-3c633dfaa5e8", - "sourceHandle": "latents", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", - "targetHandle": "latents", - "id": "reactflow__edge-a7f1336d-516d-4735-826f-3c633dfaa5e8latents-61613ab2-784d-4a5c-8576-18fd5da065eflatents", - "type": "default" - }, - { - "source": "39abdb3e-f8d1-4b0a-bab1-547d9e25b78e", - "sourceHandle": "value", - "target": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", - "targetHandle": "seed", - "id": "reactflow__edge-39abdb3e-f8d1-4b0a-bab1-547d9e25b78evalue-167ffc36-4cb7-425c-ae55-e88f80a1d6feseed", - "type": "default" - }, - { - "source": "a7f1336d-516d-4735-826f-3c633dfaa5e8", + "source": "5ca498a4-c8c8-4580-a396-0c984317205d", "sourceHandle": "width", - "target": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", + "target": "f50624ce-82bf-41d0-bdf7-8aab11a80d48", "targetHandle": "width", - "id": "reactflow__edge-a7f1336d-516d-4735-826f-3c633dfaa5e8width-167ffc36-4cb7-425c-ae55-e88f80a1d6fewidth", + "id": "reactflow__edge-5ca498a4-c8c8-4580-a396-0c984317205dwidth-f50624ce-82bf-41d0-bdf7-8aab11a80d48width", "type": "default" }, { - "source": "a7f1336d-516d-4735-826f-3c633dfaa5e8", + "source": "5ca498a4-c8c8-4580-a396-0c984317205d", "sourceHandle": "height", - "target": "167ffc36-4cb7-425c-ae55-e88f80a1d6fe", + "target": "f50624ce-82bf-41d0-bdf7-8aab11a80d48", "targetHandle": "height", - "id": "reactflow__edge-a7f1336d-516d-4735-826f-3c633dfaa5e8height-167ffc36-4cb7-425c-ae55-e88f80a1d6feheight", + "id": "reactflow__edge-5ca498a4-c8c8-4580-a396-0c984317205dheight-f50624ce-82bf-41d0-bdf7-8aab11a80d48height", "type": "default" }, { - "source": "4e2833b2-5d35-45ec-ae65-89ea1846a3f4", + "source": "f50624ce-82bf-41d0-bdf7-8aab11a80d48", + "sourceHandle": "noise", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "targetHandle": "noise", + "id": "reactflow__edge-f50624ce-82bf-41d0-bdf7-8aab11a80d48noise-c3737554-8d87-48ff-a6f8-e71d2867f434noise", + "type": "default" + }, + { + "source": "5ca498a4-c8c8-4580-a396-0c984317205d", + "sourceHandle": "latents", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "targetHandle": "latents", + "id": "reactflow__edge-5ca498a4-c8c8-4580-a396-0c984317205dlatents-c3737554-8d87-48ff-a6f8-e71d2867f434latents", + "type": "default" + }, + { + "source": "e8bf67fe-67de-4227-87eb-79e86afdfc74", + "sourceHandle": "conditioning", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-e8bf67fe-67de-4227-87eb-79e86afdfc74conditioning-c3737554-8d87-48ff-a6f8-e71d2867f434negative_conditioning", + "type": "default" + }, + { + "source": "63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16b", + "sourceHandle": "conditioning", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16bconditioning-c3737554-8d87-48ff-a6f8-e71d2867f434positive_conditioning", + "type": "default" + }, + { + "source": "d8ace142-c05f-4f1d-8982-88dc7473958d", + "sourceHandle": "clip", + "target": "63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16b", + "targetHandle": "clip", + "id": "reactflow__edge-d8ace142-c05f-4f1d-8982-88dc7473958dclip-63b6ab7e-5b05-4d1b-a3b1-42d8e53ce16bclip", + "type": "default" + }, + { + "source": "d8ace142-c05f-4f1d-8982-88dc7473958d", + "sourceHandle": "clip", + "target": "e8bf67fe-67de-4227-87eb-79e86afdfc74", + "targetHandle": "clip", + "id": "reactflow__edge-d8ace142-c05f-4f1d-8982-88dc7473958dclip-e8bf67fe-67de-4227-87eb-79e86afdfc74clip", + "type": "default" + }, + { + "source": "1d887701-df21-4966-ae6e-a7d82307d7bd", "sourceHandle": "image", - "target": "08c41d50-fb10-43a9-a58b-fc15ee678a83", + "target": "ca1d020c-89a8-4958-880a-016d28775cfa", "targetHandle": "image", - "id": "reactflow__edge-4e2833b2-5d35-45ec-ae65-89ea1846a3f4image-08c41d50-fb10-43a9-a58b-fc15ee678a83image", + "id": "reactflow__edge-1d887701-df21-4966-ae6e-a7d82307d7bdimage-ca1d020c-89a8-4958-880a-016d28775cfaimage", "type": "default" }, { - "source": "08c41d50-fb10-43a9-a58b-fc15ee678a83", - "sourceHandle": "image", - "target": "a7f1336d-516d-4735-826f-3c633dfaa5e8", - "targetHandle": "image", - "id": "reactflow__edge-08c41d50-fb10-43a9-a58b-fc15ee678a83image-a7f1336d-516d-4735-826f-3c633dfaa5e8image", - "type": "default" - }, - { - "source": "30598d37-cf80-4e12-896a-7683cf727e77", + "source": "ca1d020c-89a8-4958-880a-016d28775cfa", "sourceHandle": "control", - "target": "61613ab2-784d-4a5c-8576-18fd5da065ef", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", "targetHandle": "control", - "id": "reactflow__edge-30598d37-cf80-4e12-896a-7683cf727e77control-61613ab2-784d-4a5c-8576-18fd5da065efcontrol", + "id": "reactflow__edge-ca1d020c-89a8-4958-880a-016d28775cfacontrol-c3737554-8d87-48ff-a6f8-e71d2867f434control", "type": "default" }, { - "source": "b79732f8-6126-4d06-9c8a-4e84bd5b1ac9", + "source": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "sourceHandle": "latents", + "target": "3ed9b2ef-f4ec-40a7-94db-92e63b583ec0", + "targetHandle": "latents", + "id": "reactflow__edge-c3737554-8d87-48ff-a6f8-e71d2867f434latents-3ed9b2ef-f4ec-40a7-94db-92e63b583ec0latents", + "type": "default" + }, + { + "source": "d8ace142-c05f-4f1d-8982-88dc7473958d", "sourceHandle": "vae", - "target": "c2172a8b-1b5f-4330-acbe-dd2565c3b988", + "target": "3ed9b2ef-f4ec-40a7-94db-92e63b583ec0", "targetHandle": "vae", - "id": "reactflow__edge-b79732f8-6126-4d06-9c8a-4e84bd5b1ac9vae-c2172a8b-1b5f-4330-acbe-dd2565c3b988vae", + "id": "reactflow__edge-d8ace142-c05f-4f1d-8982-88dc7473958dvae-3ed9b2ef-f4ec-40a7-94db-92e63b583ec0vae", "type": "default" }, { - "source": "08c41d50-fb10-43a9-a58b-fc15ee678a83", + "source": "f7564dd2-9539-47f2-ac13-190804461f4e", "sourceHandle": "image", - "target": "b10d39ab-7bc9-48bc-b883-2fd50920876d", + "target": "5ca498a4-c8c8-4580-a396-0c984317205d", "targetHandle": "image", - "id": "reactflow__edge-08c41d50-fb10-43a9-a58b-fc15ee678a83image-b10d39ab-7bc9-48bc-b883-2fd50920876dimage", + "id": "reactflow__edge-f7564dd2-9539-47f2-ac13-190804461f4eimage-5ca498a4-c8c8-4580-a396-0c984317205dimage", "type": "default" }, { - "source": "b10d39ab-7bc9-48bc-b883-2fd50920876d", - "sourceHandle": "image", - "target": "30598d37-cf80-4e12-896a-7683cf727e77", - "targetHandle": "image", - "id": "reactflow__edge-b10d39ab-7bc9-48bc-b883-2fd50920876dimage-30598d37-cf80-4e12-896a-7683cf727e77image", + "source": "d8ace142-c05f-4f1d-8982-88dc7473958d", + "sourceHandle": "unet", + "target": "c3737554-8d87-48ff-a6f8-e71d2867f434", + "targetHandle": "unet", + "id": "reactflow__edge-d8ace142-c05f-4f1d-8982-88dc7473958dunet-c3737554-8d87-48ff-a6f8-e71d2867f434unet", "type": "default" } ] diff --git a/docs/workflows/FaceMask.json b/docs/workflows/FaceMask.json index 589ac097e4..54c1f800b6 100644 --- a/docs/workflows/FaceMask.json +++ b/docs/workflows/FaceMask.json @@ -1,7 +1,7 @@ { "name": "FaceMask", "author": "YMGenesis", - "description": "21 September 2023\n\nPlace an image with recognizable face(s) in Image Primitive, and write what sort of new face you want in the top prompt text box. See Notes for more info.", + "description": "Place an image with recognizable face(s) in Image Primitive, and write what sort of new face you want in the top prompt text box. See Notes for more info.", "version": "1.0", "contact": "YMGenesis on InvokeAI Discord", "tags": "facemask, facetools", @@ -56,14 +56,14 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 226, "position": { - "x": 4625, - "y": 1275 + "x": 4103.832039728059, + "y": 1987.4435345183065 } }, { @@ -102,14 +102,14 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 259, + "height": 261, "position": { - "x": 5025, - "y": 1275 + "x": 4988.591898842789, + "y": 1700.8901379603535 } }, { @@ -148,14 +148,14 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 259, + "height": 261, "position": { - "x": 5025, - "y": 1550 + "x": 4986.228031951785, + "y": 1987.19695578231 } }, { @@ -219,91 +219,18 @@ } }, "label": "", - "isOpen": true, + "isOpen": false, "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 388, + "height": 32, "position": { - "x": 5425, - "y": 1525 - } - }, - { - "id": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "type": "invocation", - "data": { - "id": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "type": "l2i", - "inputs": { - "tiled": { - "id": "8265e595-8f76-4615-8b70-3a0fca854cbf", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "cc2dd2ee-63f6-40e7-937e-d82086685abe", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "latents": { - "id": "fbbab00e-b47f-4f45-801a-a719873429ca", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "476e6075-c62d-4d42-afcf-a18e4c4a47fb", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "65086674-a0f7-4d6c-a02e-101010b34d74", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "e32514a9-50d5-423e-95d3-5d9fd460adaa", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "4d6557ec-2967-40ec-bcae-52725ffe766c", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true, - "version": "1.0.0", - "useCache": true - }, - "width": 320, - "height": 266, - "position": { - "x": 5825, - "y": 1275 + "x": 5398.389401611981, + "y": 2019.4053462371755 } }, { @@ -339,18 +266,18 @@ } }, "label": "", - "isOpen": true, + "isOpen": false, "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": false + "useCache": false, + "version": "1.0.0" }, "width": 320, - "height": 218, + "height": 32, "position": { - "x": 5425, - "y": 1275 + "x": 5386.304039775159, + "y": 1979.791644235275 } }, { @@ -407,18 +334,18 @@ } }, "label": "", - "isOpen": true, + "isOpen": false, "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 316, + "height": 32, "position": { - "x": 5025, - "y": 2175 + "x": 5009.179957658444, + "y": 2346.7322639404283 } }, { @@ -461,86 +388,14 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 225, "position": { - "x": 4625, - "y": 1525 - } - }, - { - "id": "31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7", - "type": "invocation", - "data": { - "id": "31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7", - "type": "color_correct", - "inputs": { - "image": { - "id": "8523ebb4-b6ef-4ba2-a0fc-32a5beb69c65", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "reference": { - "id": "b4d476d4-cdca-4757-a7e3-509614ce956e", - "name": "reference", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "mask": { - "id": "66b192f5-50a6-4241-aac8-4ed68a34ac90", - "name": "mask", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "mask_blur_radius": { - "id": "deac73dc-2ad0-4e31-9519-920c56746c4e", - "name": "mask_blur_radius", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 8 - } - }, - "outputs": { - "image": { - "id": "d5eb4f4e-e277-435c-a960-0cf1731cac4b", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "9fef7aab-0294-43ac-adcf-f53fe3188823", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "148b6497-7a4e-43b4-bbba-a18e9426db37", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false, - "version": "1.0.0", - "useCache": true - }, - "width": 320, - "height": 396, - "position": { - "x": 5825, - "y": 1575 + "x": 4107.933245141945, + "y": 2255.443448115275 } }, { @@ -602,44 +457,197 @@ } }, "label": "", + "isOpen": false, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 32, + "position": { + "x": 5006.155303630073, + "y": 2277.2727128782517 + } + }, + { + "id": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", + "type": "invocation", + "data": { + "id": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", + "type": "denoise_latents", + "inputs": { + "noise": { + "id": "175b4d0a-3017-46e2-933f-c02f1cfb29b2", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "dd174b3e-3f6c-46cb-a703-3c6f3b3c72f1", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "0ea30aa7-8747-4c93-87e8-3c84e0dfd187", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "a6392edb-8895-41ed-918b-0ba8d2ac72ac", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "1d1807cc-a24d-426e-9de5-a7e61d45c006", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "947a5212-8923-4d5d-934c-dbc5879b9d07", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "control": { + "id": "585378b9-2686-4573-b762-3dc2d6179193", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "191f4687-fdcc-45da-859f-71fd5091a8bd", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "39fc54ae-2141-4cab-9c01-c6c415f964cd", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "7f1a388e-8355-496c-a45d-fce5b8685a63", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "de922941-b2d8-4c57-92a7-201f9ddaf262", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + }, + "positive_conditioning": { + "id": "2b42b4e8-4795-4fcc-bef1-c08cb8e25e0a", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "ff29b7d7-1bff-4aa9-b5c0-f8786a55023a", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "unet": { + "id": "0155f1cb-152b-4097-9395-afcc745c697b", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "03cfb327-02a1-4fbe-b7ce-b07fd501d2b8", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "3ffb87d7-b5a6-4b35-bdf1-2bb9b718d815", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "2c1f0588-943a-4fd1-b75b-48d04c944296", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", "isOpen": true, "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.3.0" }, "width": 320, - "height": 323, + "height": 646, "position": { - "x": 5025, - "y": 1825 + "x": 5512.059705982663, + "y": 2103.8364934988267 } }, { - "id": "c2032405-817c-494d-b1e5-441e74d248d2", + "id": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", "type": "invocation", "data": { - "id": "c2032405-817c-494d-b1e5-441e74d248d2", + "id": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", "type": "face_mask_detection", "inputs": { + "metadata": { + "id": "a56bf310-b5c3-4440-8ba6-79f5e434a9e6", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, "image": { - "id": "e04ef12b-5eb8-40ba-9e46-93f360be12e6", + "id": "11ece2fd-57ee-4504-b1f5-8d0c9332d785", "name": "image", "type": "ImageField", "fieldKind": "input", "label": "" }, "face_ids": { - "id": "63ce222d-2dd3-41a3-976d-a15e5c6bc6d2", + "id": "c5eaafc3-70f4-4bcd-9df7-0d4cd26e1734", "name": "face_ids", "type": "string", "fieldKind": "input", "label": "", - "value": "0" + "value": "" }, "minimum_confidence": { - "id": "0b5969ae-afa6-4007-be70-4dc2a86dda4a", + "id": "ab85fdbd-d61e-4584-8595-c1cea1ffb288", "name": "minimum_confidence", "type": "float", "fieldKind": "input", @@ -647,7 +655,7 @@ "value": 0.5 }, "x_offset": { - "id": "5dc14f5e-02ad-42c9-809c-e708f107c2cd", + "id": "e381e04d-b54d-4457-9b6e-b3b554a8e343", "name": "x_offset", "type": "float", "fieldKind": "input", @@ -655,7 +663,7 @@ "value": 0 }, "y_offset": { - "id": "0d84f0c3-6983-4902-b3ed-d8cd8797e35d", + "id": "98e771c8-df97-4a57-a5d4-9601dac68338", "name": "y_offset", "type": "float", "fieldKind": "input", @@ -663,7 +671,7 @@ "value": 0 }, "chunk": { - "id": "00edd0c0-ee3f-4739-8a22-895b88d83d78", + "id": "ae4af045-99f9-4d84-81d2-438dc3d13b8d", "name": "chunk", "type": "boolean", "fieldKind": "input", @@ -671,7 +679,7 @@ "value": false }, "invert_mask": { - "id": "cbf70aeb-ceec-45c2-8042-3921c3134baf", + "id": "a6a0fe16-da45-46aa-9f85-9469fde40d71", "name": "invert_mask", "type": "boolean", "fieldKind": "input", @@ -681,25 +689,25 @@ }, "outputs": { "image": { - "id": "fe460f4c-7aa2-409a-bc02-a07e69cf9f2a", + "id": "7de8643a-c6b1-4260-b843-728c8d0fc6d4", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "26cf35c6-2ccd-4298-a7db-b1c2fddb3fc9", + "id": "fb1450b6-de42-465a-98d7-1dc93ceb20d7", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "3c4e7666-d039-49a5-b4c6-c5d9ba11f1bb", + "id": "cea5abb6-1584-440a-9ee2-1e4c926235e7", "name": "height", "type": "integer", "fieldKind": "output" }, "mask": { - "id": "35f88fb5-94c1-4643-a5c6-cc288602f37d", + "id": "272e4224-1736-42de-895d-096309259ac7", "name": "mask", "type": "ImageField", "fieldKind": "output" @@ -710,135 +718,76 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.0.0", - "useCache": true + "useCache": true, + "version": "1.0.2" }, "width": 320, - "height": 583, + "height": 585, "position": { - "x": 4625, - "y": 1900 + "x": 4559.385043470649, + "y": 2082.7157021692556 } }, { - "id": "441fdd15-1a49-413c-bd2a-637a105ad370", + "id": "e4681270-ea7e-4063-9116-880408854eee", "type": "invocation", "data": { - "id": "441fdd15-1a49-413c-bd2a-637a105ad370", - "type": "denoise_latents", + "id": "e4681270-ea7e-4063-9116-880408854eee", + "type": "l2i", "inputs": { - "noise": { - "id": "86b6226c-1780-49d7-bbed-c4a5440eebb2", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "f3cae478-9f7c-4836-b8f8-3a83ef2fdcc3", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 20 - }, - "cfg_scale": { - "id": "f7d64dc5-ea3d-44a8-8951-56622f0548ee", - "name": "cfg_scale", - "type": "FloatPolymorphic", - "fieldKind": "input", - "label": "", - "value": 5 - }, - "denoising_start": { - "id": "01409326-116d-41b5-9c3d-abaa2a5182aa", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.3 - }, - "denoising_end": { - "id": "445b857b-a136-4736-b677-b2a701d651d4", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 1 - }, - "scheduler": { - "id": "8e7d75ef-6cf0-467e-8067-595bb96c9636", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler" - }, - "control": { - "id": "ad0c589a-b5e9-4892-9173-a709ee8672db", - "name": "control", - "type": "ControlPolymorphic", - "fieldKind": "input", - "label": "" - }, - "ip_adapter": { - "id": "843f92c7-2714-46ea-ab9d-fc568aa684f3", - "name": "ip_adapter", - "type": "IPAdapterField", + "metadata": { + "id": "1632b6ac-605d-42a7-853c-65539a6f664e", + "name": "metadata", + "type": "MetadataField", "fieldKind": "input", "label": "" }, "latents": { - "id": "d21e2b79-344d-438f-8841-c5c2dcb82e77", + "id": "9986c874-6d4b-47fc-895a-88933ef2b473", "name": "latents", "type": "LatentsField", "fieldKind": "input", "label": "" }, - "denoise_mask": { - "id": "e8cf20d0-76e0-4543-b11f-2a4d209a6489", - "name": "denoise_mask", - "type": "DenoiseMaskField", + "vae": { + "id": "d5842416-e575-4e35-a5d0-fd1ce4401b52", + "name": "vae", + "type": "VaeField", "fieldKind": "input", "label": "" }, - "positive_conditioning": { - "id": "3ab3bd3b-4ecd-4b87-9ab3-5de24828f3cd", - "name": "positive_conditioning", - "type": "ConditioningField", + "tiled": { + "id": "6a84e45e-5f54-4952-9285-9dedc6d056d5", + "name": "tiled", + "type": "boolean", "fieldKind": "input", - "label": "" + "label": "", + "value": false }, - "negative_conditioning": { - "id": "6e2907e9-779d-4984-9c79-6032bf75ab0c", - "name": "negative_conditioning", - "type": "ConditioningField", + "fp32": { + "id": "2fa37674-8685-4ec4-87d9-d4683131d79c", + "name": "fp32", + "type": "boolean", "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "bb038dd9-cb2e-41df-a830-a5e1d5696c31", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" + "label": "", + "value": false } }, "outputs": { - "latents": { - "id": "82c61fed-7cf5-44d4-8d00-f42350619487", - "name": "latents", - "type": "LatentsField", + "image": { + "id": "b1856446-1b03-4825-aae0-0859e27c3c8c", + "name": "image", + "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "73ab2f4f-898f-44a1-a46c-c0d4aaa9c2e3", + "id": "c95d92f6-2416-4fc8-a542-998c7c3fac73", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "92b783b2-8741-4089-8125-1ff2f2d15372", + "id": "7033a118-3b20-4c25-8450-e15d7fc8657c", "name": "height", "type": "integer", "fieldKind": "output" @@ -849,18 +798,109 @@ "notes": "", "embedWorkflow": false, "isIntermediate": true, - "version": "1.1.0", - "useCache": true + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 614, + "height": 267, "position": { - "x": 5425, - "y": 1925 + "x": 5941.909912847396, + "y": 2111.4771842290065 + } + }, + { + "id": "7bc3c331-4658-46fd-8736-fe3043fcd9d1", + "type": "invocation", + "data": { + "id": "7bc3c331-4658-46fd-8736-fe3043fcd9d1", + "type": "color_correct", + "inputs": { + "metadata": { + "id": "203d08d1-586f-47c9-95a1-2afa1db23751", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "50bc42c6-c3b8-44c4-89fe-ef2edd9b67f4", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "reference": { + "id": "2eef99df-b1f8-441c-a316-466a46812df0", + "name": "reference", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "mask": { + "id": "6cfde62b-e6fc-4f13-91dc-e679b26ec04b", + "name": "mask", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "mask_blur_radius": { + "id": "51125aec-bbcb-4ae0-b618-a9bc632a5a86", + "name": "mask_blur_radius", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 8 + } + }, + "outputs": { + "image": { + "id": "4c82dcb2-1c55-4b6d-a42c-061478881393", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "b7d23fea-e361-468d-96e7-9b243592e904", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "d056d182-d261-4037-bb5e-caec9bda9ca6", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 396, + "position": { + "x": 6399.947577155154, + "y": 2127.7477011465667 } } ], "edges": [ + { + "source": "27dd9fc3-8c6e-4602-8754-e9ca2f478d68", + "target": "098898c8-7a20-4d78-9363-296d42e3d8da", + "id": "27dd9fc3-8c6e-4602-8754-e9ca2f478d68-098898c8-7a20-4d78-9363-296d42e3d8da-collapsed", + "type": "collapsed" + }, + { + "source": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", + "target": "098898c8-7a20-4d78-9363-296d42e3d8da", + "id": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d-098898c8-7a20-4d78-9363-296d42e3d8da-collapsed", + "type": "collapsed" + }, { "source": "c9897be0-7f59-4388-816d-86cb72cc4036", "sourceHandle": "clip", @@ -877,14 +917,6 @@ "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036clip-7c4e5071-5b76-4d42-b340-68b52c5ded7aclip", "type": "default" }, - { - "source": "c9897be0-7f59-4388-816d-86cb72cc4036", - "sourceHandle": "vae", - "target": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "targetHandle": "vae", - "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036vae-3b2ebc7f-251d-4726-b1b8-5331355f8626vae", - "type": "default" - }, { "source": "27dd9fc3-8c6e-4602-8754-e9ca2f478d68", "sourceHandle": "value", @@ -926,115 +958,123 @@ "type": "default" }, { - "source": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "sourceHandle": "image", - "target": "31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7", - "targetHandle": "image", - "id": "reactflow__edge-3b2ebc7f-251d-4726-b1b8-5331355f8626image-31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7image", - "type": "default" - }, - { - "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", - "sourceHandle": "image", - "target": "31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7", - "targetHandle": "reference", - "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7reference", - "type": "default" - }, - { - "source": "c2032405-817c-494d-b1e5-441e74d248d2", - "sourceHandle": "mask", - "target": "31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7", - "targetHandle": "mask", - "id": "reactflow__edge-c2032405-817c-494d-b1e5-441e74d248d2mask-31e99fe1-c39d-4cca-bd89-9ec27cb3a8a7mask", - "type": "default" - }, - { - "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", - "sourceHandle": "image", - "target": "c2032405-817c-494d-b1e5-441e74d248d2", - "targetHandle": "image", - "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-c2032405-817c-494d-b1e5-441e74d248d2image", - "type": "default" - }, - { - "source": "c2032405-817c-494d-b1e5-441e74d248d2", - "sourceHandle": "image", - "target": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", - "targetHandle": "image", - "id": "reactflow__edge-c2032405-817c-494d-b1e5-441e74d248d2image-a6d08bcb-0b52-4dd8-9247-8b6480238c6dimage", - "type": "default" - }, - { - "source": "c2032405-817c-494d-b1e5-441e74d248d2", - "sourceHandle": "image", - "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", - "targetHandle": "image", - "id": "reactflow__edge-c2032405-817c-494d-b1e5-441e74d248d2image-bcbdc4ea-1fad-40d4-8632-70f84116f4b6image", - "type": "default" - }, - { - "source": "c2032405-817c-494d-b1e5-441e74d248d2", - "sourceHandle": "mask", - "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", - "targetHandle": "mask", - "id": "reactflow__edge-c2032405-817c-494d-b1e5-441e74d248d2mask-bcbdc4ea-1fad-40d4-8632-70f84116f4b6mask", - "type": "default" - }, - { - "source": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", - "sourceHandle": "latents", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", - "targetHandle": "latents", - "id": "reactflow__edge-a6d08bcb-0b52-4dd8-9247-8b6480238c6dlatents-441fdd15-1a49-413c-bd2a-637a105ad370latents", - "type": "default" - }, - { - "source": "fb7e72d9-51cb-432a-b511-c6c608d07413", - "sourceHandle": "conditioning", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-fb7e72d9-51cb-432a-b511-c6c608d07413conditioning-441fdd15-1a49-413c-bd2a-637a105ad370positive_conditioning", + "source": "c9897be0-7f59-4388-816d-86cb72cc4036", + "sourceHandle": "unet", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", + "targetHandle": "unet", + "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036unet-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9unet", "type": "default" }, { "source": "7c4e5071-5b76-4d42-b340-68b52c5ded7a", "sourceHandle": "conditioning", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", "targetHandle": "negative_conditioning", - "id": "reactflow__edge-7c4e5071-5b76-4d42-b340-68b52c5ded7aconditioning-441fdd15-1a49-413c-bd2a-637a105ad370negative_conditioning", + "id": "reactflow__edge-7c4e5071-5b76-4d42-b340-68b52c5ded7aconditioning-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9negative_conditioning", "type": "default" }, { - "source": "c9897be0-7f59-4388-816d-86cb72cc4036", - "sourceHandle": "unet", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", - "targetHandle": "unet", - "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036unet-441fdd15-1a49-413c-bd2a-637a105ad370unet", + "source": "fb7e72d9-51cb-432a-b511-c6c608d07413", + "sourceHandle": "conditioning", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-fb7e72d9-51cb-432a-b511-c6c608d07413conditioning-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9positive_conditioning", "type": "default" }, { "source": "098898c8-7a20-4d78-9363-296d42e3d8da", "sourceHandle": "noise", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", "targetHandle": "noise", - "id": "reactflow__edge-098898c8-7a20-4d78-9363-296d42e3d8danoise-441fdd15-1a49-413c-bd2a-637a105ad370noise", + "id": "reactflow__edge-098898c8-7a20-4d78-9363-296d42e3d8danoise-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9noise", "type": "default" }, { "source": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", "sourceHandle": "denoise_mask", - "target": "441fdd15-1a49-413c-bd2a-637a105ad370", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", "targetHandle": "denoise_mask", - "id": "reactflow__edge-bcbdc4ea-1fad-40d4-8632-70f84116f4b6denoise_mask-441fdd15-1a49-413c-bd2a-637a105ad370denoise_mask", + "id": "reactflow__edge-bcbdc4ea-1fad-40d4-8632-70f84116f4b6denoise_mask-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9denoise_mask", "type": "default" }, { - "source": "441fdd15-1a49-413c-bd2a-637a105ad370", + "source": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", "sourceHandle": "latents", - "target": "3b2ebc7f-251d-4726-b1b8-5331355f8626", + "target": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", "targetHandle": "latents", - "id": "reactflow__edge-441fdd15-1a49-413c-bd2a-637a105ad370latents-3b2ebc7f-251d-4726-b1b8-5331355f8626latents", + "id": "reactflow__edge-a6d08bcb-0b52-4dd8-9247-8b6480238c6dlatents-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9latents", + "type": "default" + }, + { + "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", + "sourceHandle": "image", + "target": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", + "targetHandle": "image", + "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-eb725b0b-1fa6-4f79-aedb-52c19afcfad9image", + "type": "default" + }, + { + "source": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", + "sourceHandle": "image", + "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", + "targetHandle": "image", + "id": "reactflow__edge-eb725b0b-1fa6-4f79-aedb-52c19afcfad9image-bcbdc4ea-1fad-40d4-8632-70f84116f4b6image", + "type": "default" + }, + { + "source": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", + "sourceHandle": "mask", + "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", + "targetHandle": "mask", + "id": "reactflow__edge-eb725b0b-1fa6-4f79-aedb-52c19afcfad9mask-bcbdc4ea-1fad-40d4-8632-70f84116f4b6mask", + "type": "default" + }, + { + "source": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", + "sourceHandle": "image", + "target": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", + "targetHandle": "image", + "id": "reactflow__edge-eb725b0b-1fa6-4f79-aedb-52c19afcfad9image-a6d08bcb-0b52-4dd8-9247-8b6480238c6dimage", + "type": "default" + }, + { + "source": "c9897be0-7f59-4388-816d-86cb72cc4036", + "sourceHandle": "vae", + "target": "e4681270-ea7e-4063-9116-880408854eee", + "targetHandle": "vae", + "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036vae-e4681270-ea7e-4063-9116-880408854eeevae", + "type": "default" + }, + { + "source": "d14b4d95-bf74-4ec5-827b-4c9e797c7ae9", + "sourceHandle": "latents", + "target": "e4681270-ea7e-4063-9116-880408854eee", + "targetHandle": "latents", + "id": "reactflow__edge-d14b4d95-bf74-4ec5-827b-4c9e797c7ae9latents-e4681270-ea7e-4063-9116-880408854eeelatents", + "type": "default" + }, + { + "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", + "sourceHandle": "image", + "target": "7bc3c331-4658-46fd-8736-fe3043fcd9d1", + "targetHandle": "reference", + "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-7bc3c331-4658-46fd-8736-fe3043fcd9d1reference", + "type": "default" + }, + { + "source": "e4681270-ea7e-4063-9116-880408854eee", + "sourceHandle": "image", + "target": "7bc3c331-4658-46fd-8736-fe3043fcd9d1", + "targetHandle": "image", + "id": "reactflow__edge-e4681270-ea7e-4063-9116-880408854eeeimage-7bc3c331-4658-46fd-8736-fe3043fcd9d1image", + "type": "default" + }, + { + "source": "eb725b0b-1fa6-4f79-aedb-52c19afcfad9", + "sourceHandle": "mask", + "target": "7bc3c331-4658-46fd-8736-fe3043fcd9d1", + "targetHandle": "mask", + "id": "reactflow__edge-eb725b0b-1fa6-4f79-aedb-52c19afcfad9mask-7bc3c331-4658-46fd-8736-fe3043fcd9d1mask", "type": "default" } ] diff --git a/docs/workflows/FaceOff_FaceScale2x.json b/docs/workflows/FaceOff_FaceScale2x.json index fa3cb80e9b..d1707e5e73 100644 --- a/docs/workflows/FaceOff_FaceScale2x.json +++ b/docs/workflows/FaceOff_FaceScale2x.json @@ -227,85 +227,12 @@ "version": "1.0.0" }, "width": 320, - "height": 388, + "height": 389, "position": { "x": 5425, "y": 1525 } }, - { - "id": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "type": "invocation", - "data": { - "id": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "type": "l2i", - "inputs": { - "tiled": { - "id": "8265e595-8f76-4615-8b70-3a0fca854cbf", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "cc2dd2ee-63f6-40e7-937e-d82086685abe", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "latents": { - "id": "fbbab00e-b47f-4f45-801a-a719873429ca", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "476e6075-c62d-4d42-afcf-a18e4c4a47fb", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "65086674-a0f7-4d6c-a02e-101010b34d74", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "e32514a9-50d5-423e-95d3-5d9fd460adaa", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "4d6557ec-2967-40ec-bcae-52725ffe766c", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true, - "useCache": true, - "version": "1.0.0" - }, - "width": 320, - "height": 266, - "position": { - "x": 5825, - "y": 1275 - } - }, { "id": "27dd9fc3-8c6e-4602-8754-e9ca2f478d68", "type": "invocation", @@ -415,7 +342,7 @@ "version": "1.0.0" }, "width": 320, - "height": 316, + "height": 318, "position": { "x": 5025, "y": 2175 @@ -471,94 +398,6 @@ "y": 1525 } }, - { - "id": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", - "type": "invocation", - "data": { - "id": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", - "type": "img_paste", - "inputs": { - "base_image": { - "id": "67487235-b302-4636-b8d5-b893bbd56db1", - "name": "base_image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "image": { - "id": "049e467a-2a5f-4017-b330-3ec97519eeef", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "mask": { - "id": "39396a0b-c12d-4384-bd24-f9358ece80b0", - "name": "mask", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "x": { - "id": "39bf90a6-8db3-4b12-8c3c-97a665e0d319", - "name": "x", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "y": { - "id": "7352707c-a833-45b3-83a5-c7b733741a5e", - "name": "y", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "crop": { - "id": "c9225c97-04a8-42f5-9cda-333a9c475abb", - "name": "crop", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - } - }, - "outputs": { - "image": { - "id": "a8a59a34-59d6-4edf-972c-d5b189e488a2", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "151b99f7-4736-4d87-b49b-a82d18b70a6f", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "a3b4856e-6136-4d29-a2d5-b8db7d1f7f55", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false, - "useCache": true, - "version": "1.0.1" - }, - "width": 320, - "height": 502, - "position": { - "x": 5825, - "y": 2300 - } - }, { "id": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", "type": "invocation", @@ -626,340 +465,51 @@ "version": "1.0.0" }, "width": 320, - "height": 323, + "height": 325, "position": { "x": 5025, "y": 1825 } }, { - "id": "233aeb43-980a-4578-bdb7-5488d54d1bbf", + "id": "01a35dfd-b4bd-4901-8088-49972eac7582", "type": "invocation", "data": { - "id": "233aeb43-980a-4578-bdb7-5488d54d1bbf", - "type": "img_scale", + "id": "01a35dfd-b4bd-4901-8088-49972eac7582", + "type": "l2i", "inputs": { - "image": { - "id": "81fe81ca-7532-472f-a1a7-84123ce007cd", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "scale_factor": { - "id": "0c0092eb-90c9-44d3-9388-421071352571", - "name": "scale_factor", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 2 - }, - "resample_mode": { - "id": "521fa4d3-7117-48e6-82c5-27c83822cf2f", - "name": "resample_mode", - "type": "enum", - "fieldKind": "input", - "label": "", - "value": "bicubic" - } - }, - "outputs": { - "image": { - "id": "0110d34f-0cd0-456a-9f76-e6e2feb8e495", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "e9daa3a1-11ff-41f8-bc72-aa96c497ff13", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "0d52aba2-9181-4822-ba97-c947e455c9e2", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "Scale Image (Mask Up)", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true, - "useCache": true, - "version": "1.0.0" - }, - "width": 320, - "height": 339, - "position": { - "x": 5025, - "y": 2500 - } - }, - { - "id": "8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6", - "type": "invocation", - "data": { - "id": "8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6", - "type": "img_scale", - "inputs": { - "image": { - "id": "432f3c88-285d-42b7-a42e-24ae97a4751a", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "scale_factor": { - "id": "b3dd9aff-0c84-4ad7-bfd9-a8fa1ccae58b", - "name": "scale_factor", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.5 - }, - "resample_mode": { - "id": "2eb9d0a7-d0f8-474e-b238-548d864fbd8e", - "name": "resample_mode", - "type": "enum", - "fieldKind": "input", - "label": "", - "value": "bicubic" - } - }, - "outputs": { - "image": { - "id": "9c089c7e-930c-4d1f-b2ab-a957ecf288aa", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "f880ce2a-5f1c-4f0c-9398-095cf082d353", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "fde5f8e6-d5fc-4d06-a1b1-9880baabf3a6", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "Scale Image (Face Down)", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true, - "useCache": true, - "version": "1.0.0" - }, - "width": 320, - "height": 339, - "position": { - "x": 5825, - "y": 1550 - } - }, - { - "id": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "type": "invocation", - "data": { - "id": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "type": "denoise_latents", - "inputs": { - "noise": { - "id": "d7a78bb2-e3d2-4e5d-b494-1cc1e5f0cc84", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "2d9aba03-011e-4858-b5e2-a1301565dde9", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 20 - }, - "cfg_scale": { - "id": "3528c5bb-12a2-4094-a35f-c5d07ddae5ee", - "name": "cfg_scale", - "type": "FloatPolymorphic", - "fieldKind": "input", - "label": "", - "value": 5 - }, - "denoising_start": { - "id": "c997229c-8f35-4427-8fcc-99a3dcaaf5a3", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.3 - }, - "denoising_end": { - "id": "abbb8f6b-f643-4cb2-9147-227feafd8aa6", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 1 - }, - "scheduler": { - "id": "2fcd2bdc-de01-422f-963d-551ff58f7b70", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler" - }, - "control": { - "id": "1ad815aa-0957-420b-a782-7e07a5e16a05", - "name": "control", - "type": "ControlPolymorphic", - "fieldKind": "input", - "label": "" - }, - "ip_adapter": { - "id": "8350154f-b179-44d6-88c8-08c8fa940648", - "name": "ip_adapter", - "type": "IPAdapterField", + "metadata": { + "id": "ce479dbf-d12f-43e7-9047-ec0e6bd838a7", + "name": "metadata", + "type": "MetadataField", "fieldKind": "input", "label": "" }, "latents": { - "id": "bf8c9465-743e-4b27-b370-e63053dc2175", + "id": "0d3f0abc-5c60-495e-af10-8136b25532d0", "name": "latents", "type": "LatentsField", "fieldKind": "input", "label": "" }, - "denoise_mask": { - "id": "4487f154-4f2f-459b-8a69-561ea892eea7", - "name": "denoise_mask", - "type": "DenoiseMaskField", + "vae": { + "id": "c0563226-c977-456a-8cf5-2873ab56a9f4", + "name": "vae", + "type": "VaeField", "fieldKind": "input", "label": "" }, - "positive_conditioning": { - "id": "a757a5d4-3aaa-4cd9-9a9d-bfb01b0676e4", - "name": "positive_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "negative_conditioning": { - "id": "68d0ce84-615a-4062-96bc-3599029a4b63", - "name": "negative_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "0de640f1-2170-4983-88d3-5af648da1b5d", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "latents": { - "id": "3198ada0-5926-41b3-89f0-8b572af78824", - "name": "latents", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "3cea129c-3145-4f89-a5f1-849863e05001", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "ed204db5-ce67-4795-873a-67b5d6a099a6", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true, - "useCache": true, - "version": "1.1.0" - }, - "width": 320, - "height": 614, - "position": { - "x": 5425, - "y": 1925 - } - }, - { - "id": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "type": "invocation", - "data": { - "id": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "type": "face_off", - "inputs": { - "image": { - "id": "4c4611d3-baab-47e8-a814-18ea86f1aff2", - "name": "image", - "type": "ImageField", - "fieldKind": "input", - "label": "" - }, - "face_id": { - "id": "cfc00e4b-c60e-44b4-b0da-f26da1b4060e", - "name": "face_id", - "type": "integer", + "tiled": { + "id": "f909d67c-f789-4daa-8528-50113bba78ea", + "name": "tiled", + "type": "boolean", "fieldKind": "input", "label": "", - "value": 0 + "value": false }, - "minimum_confidence": { - "id": "4ba35ea2-d1b3-4d24-88c5-737fdd396210", - "name": "minimum_confidence", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.5 - }, - "x_offset": { - "id": "c79b5f0a-df14-41e1-9f17-11f6b3ace52f", - "name": "x_offset", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "y_offset": { - "id": "ec8eb73f-2853-41b8-aa9d-c93b6f9f08bd", - "name": "y_offset", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "padding": { - "id": "a7a649f9-0b79-4f12-a482-b3af800b6584", - "name": "padding", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "chunk": { - "id": "df654e9c-dda3-414d-b11b-51b36071ae62", - "name": "chunk", + "fp32": { + "id": "d7c26ac3-df0f-47ab-aa91-0c5bfbe1ea38", + "name": "fp32", "type": "boolean", "fieldKind": "input", "label": "", @@ -968,40 +518,22 @@ }, "outputs": { "image": { - "id": "4292e151-cd37-4cdf-9f1b-2b3e0cc6d831", + "id": "380a7af7-bba5-434b-9996-47b8194d69d4", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "8e83877f-36ed-470c-889a-174a35259e6f", + "id": "a0f2a9cf-77f6-42a5-801d-30f635d1de26", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "40487efd-937a-491e-a1c3-e791afe32cd6", + "id": "890ec07c-9bc0-46f6-b962-8a6fd149d562", "name": "height", "type": "integer", "fieldKind": "output" - }, - "mask": { - "id": "2cc63f32-0f8e-46a9-bed3-9f47a8b834f2", - "name": "mask", - "type": "ImageField", - "fieldKind": "output" - }, - "x": { - "id": "12451165-986b-4eab-8159-55b8d7ce87ab", - "name": "x", - "type": "integer", - "fieldKind": "output" - }, - "y": { - "id": "928c0d08-613c-4c03-9a7e-a3087f45032b", - "name": "y", - "type": "integer", - "fieldKind": "output" } }, "label": "", @@ -1013,28 +545,35 @@ "version": "1.0.0" }, "width": 320, - "height": 655, + "height": 267, "position": { - "x": 4625, - "y": 1800 + "x": 5810.2137275110845, + "y": 1270.641572039504 } }, { - "id": "7ad41b86-c089-430c-b70c-3c1cbf886ed9", + "id": "43c00342-9ca3-498a-8635-c4c716e32d5f", "type": "invocation", "data": { - "id": "7ad41b86-c089-430c-b70c-3c1cbf886ed9", + "id": "43c00342-9ca3-498a-8635-c4c716e32d5f", "type": "img_scale", "inputs": { + "metadata": { + "id": "d35fa75e-439b-4fda-9064-4ed73f378de6", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, "image": { - "id": "6db4f3c8-ade5-46c7-8c39-f8b8bd949912", + "id": "e8c46885-2ec1-4fb9-8d34-07534e62ec97", "name": "image", "type": "ImageField", "fieldKind": "input", "label": "" }, "scale_factor": { - "id": "ac4f04dc-2fc8-424f-bcab-292d6139a763", + "id": "94b04846-9f70-44ac-ae82-99af13632255", "name": "scale_factor", "type": "float", "fieldKind": "input", @@ -1042,7 +581,7 @@ "value": 2 }, "resample_mode": { - "id": "1f2fdad6-1d75-42a9-8f20-dfe5361804ad", + "id": "2fbcd8bb-6668-4661-868a-1452f0e73e6d", "name": "resample_mode", "type": "enum", "fieldKind": "input", @@ -1052,25 +591,25 @@ }, "outputs": { "image": { - "id": "ab6ca82e-f936-47be-8640-1b1649032dfd", + "id": "96600931-0da3-4c68-842f-d06f2d93f383", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "bf4f0ecd-7628-46b8-9654-e728dc69985b", + "id": "ff158681-580c-4a51-a2c8-c4bd2058a011", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "07e63e0c-2da3-445f-bb34-82b9eef6edfb", + "id": "2a332d0e-4442-4a6e-8cf9-5e2e42f713c6", "name": "height", "type": "integer", "fieldKind": "output" } }, - "label": "Scale Image (Face Up)", + "label": "", "isOpen": true, "notes": "", "embedWorkflow": false, @@ -1081,40 +620,47 @@ "width": 320, "height": 339, "position": { - "x": 4625, - "y": 2500 + "x": 5808.235568293352, + "y": 1551.540180957498 } }, { - "id": "98a614c8-24df-413f-b001-a728b354e931", + "id": "0c71919b-a030-44fb-8c09-1baf37088d20", "type": "invocation", "data": { - "id": "98a614c8-24df-413f-b001-a728b354e931", + "id": "0c71919b-a030-44fb-8c09-1baf37088d20", "type": "color_correct", "inputs": { + "metadata": { + "id": "89536a0d-1c62-4975-ada9-33f359837481", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, "image": { - "id": "0f45f05a-192c-4951-9b94-32b32cc68cc2", + "id": "10d7c1da-e8e1-4226-ad9f-1bde9816c118", "name": "image", "type": "ImageField", "fieldKind": "input", "label": "" }, "reference": { - "id": "4a430d07-f13e-4889-a58e-a241e05bf142", + "id": "9c7354ed-33dc-462a-bc57-717082eb3f45", "name": "reference", "type": "ImageField", "fieldKind": "input", "label": "" }, "mask": { - "id": "c3bf8c13-0766-49e5-96cc-26a6e9dbafc9", + "id": "03aee643-6873-421c-8caf-1e05e85f6a9d", "name": "mask", "type": "ImageField", "fieldKind": "input", "label": "" }, "mask_blur_radius": { - "id": "c0a35154-41dc-494c-8807-f4cca2b996e9", + "id": "2d2dffa6-f719-4ec9-a201-c07a3a914c77", "name": "mask_blur_radius", "type": "float", "fieldKind": "input", @@ -1124,19 +670,19 @@ }, "outputs": { "image": { - "id": "27559b60-0a58-4615-8f5a-a46d85be1d89", + "id": "b652c45e-e797-47d2-9175-aa77ede6a8f5", "name": "image", "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "f03d5175-d0d8-4f4f-970f-7792d72a69c7", + "id": "385015ed-2c6b-4b72-adda-ba5639841352", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "7a7b98e5-8b34-411c-b51c-e3174a9de7f6", + "id": "fe6632e0-560c-4c56-9b52-6e5e5d7eb642", "name": "height", "type": "integer", "fieldKind": "output" @@ -1153,8 +699,518 @@ "width": 320, "height": 396, "position": { - "x": 5825, - "y": 1900 + "x": 5806.25740907562, + "y": 1903.6525217138576 + } + }, + { + "id": "4e11665c-b932-493d-ab4f-019bed730b47", + "type": "invocation", + "data": { + "id": "4e11665c-b932-493d-ab4f-019bed730b47", + "type": "img_paste", + "inputs": { + "metadata": { + "id": "6f365d9d-bf84-4053-b936-8035a4c7c991", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "base_image": { + "id": "fb323f35-d1fd-4d20-b145-9a3db7a57a28", + "name": "base_image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "ea76a063-ec51-4b2b-bfa8-8df9c64ecc2e", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "mask": { + "id": "9b3f194a-d7f1-45f3-989a-6b2096dd3fd6", + "name": "mask", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "x": { + "id": "d74b8e26-bc59-4a27-bb00-f769b81e8ef0", + "name": "x", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "y": { + "id": "6ada744a-8f67-49c6-a8b6-df03b3397d73", + "name": "y", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "crop": { + "id": "dec1e8e1-2fb0-43e8-9ddf-0eb478e5e567", + "name": "crop", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "4a01e54d-9a7b-458d-aa87-640ce8c5cd62", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "be903c7c-b867-4938-9a0e-de8a6676ae89", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "7dbb23a1-bedc-418c-8c27-09cf24e0e777", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.1" + }, + "width": 320, + "height": 504, + "position": { + "x": 5810.103371182836, + "y": 2315.9071582023707 + } + }, + { + "id": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "type": "invocation", + "data": { + "id": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "1039d676-b54f-4848-903d-a5e3eef84781", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "52e4b032-e32f-48b1-ac02-b17f0dff78f6", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "7c6c35bb-576c-42fa-8191-169afff13d73", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "e0df62c7-edb8-4777-8ca1-c7a6fb30f6a2", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "e1a87d18-671d-4a6e-a528-7d4376500211", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "60ab8906-162c-4817-bd46-f5d7a93aa213", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "c8f73ade-d5a4-4e69-8462-c0f9ee3dfb96", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "e2872b56-4250-4a0d-86b3-37c60485fdc7", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "b1f93d41-b399-4774-a913-4a0c0c6d5f66", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "89315aa7-95d7-463b-86fd-a8064092503c", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "370ded4f-ef23-4741-9e4c-1f3d1d429cfd", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "dac77b99-0cc9-46c5-9d17-66ddbabdb7f8", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "229e7492-abfd-47cb-9218-67c1ba75c4b4", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "1248eb2e-d362-446c-8ffc-ddab52b7c20f", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "de5c8012-df50-4fae-a4b7-ca09aaa181ca", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "ba1e5e4f-3ba9-467b-b80d-3c85aa97afab", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "b0fa6029-ede9-45be-b1ec-b1ec469bfeb6", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 5468.65700494231, + "y": 1926.1754472409636 + } + }, + { + "id": "98048fa7-dd08-49ec-92b8-76c9017e5444", + "type": "invocation", + "data": { + "id": "98048fa7-dd08-49ec-92b8-76c9017e5444", + "type": "img_scale", + "inputs": { + "metadata": { + "id": "02fa128c-3d3b-4083-aa73-fb7acbfb072a", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "8008b9db-bd61-4a89-b2df-de444961bc5b", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "scale_factor": { + "id": "45268d5f-b8f9-49ee-b770-a6876100878a", + "name": "scale_factor", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 2 + }, + "resample_mode": { + "id": "645b99b1-fd64-429b-b61d-caf739830efa", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "ff088e78-dd52-4605-a14d-d10d7c0015a5", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "b0bede16-55d6-4fee-8709-6bce92118431", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "88dc53cd-9d12-4f95-b23a-382b3db92db9", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 5026.491824134117, + "y": 2513.056664333261 + } + }, + { + "id": "894b9ca6-e7bc-428e-87e9-cce64095bce9", + "type": "invocation", + "data": { + "id": "894b9ca6-e7bc-428e-87e9-cce64095bce9", + "type": "img_scale", + "inputs": { + "metadata": { + "id": "ae97ac6c-6dc7-4c01-955a-ae98a608db4b", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "56d9afd5-b1c6-4b62-b332-a5585e863000", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "scale_factor": { + "id": "cdeeecb8-8f12-4d2b-b961-4d18cca858de", + "name": "scale_factor", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 2 + }, + "resample_mode": { + "id": "b120b6a1-dbdb-4989-80fb-af0a682e124c", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "7888a231-4f89-4ad7-a216-d5664a96eb7d", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "9030b8fd-4963-4bc7-86a2-5a964443fc41", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "4beb6975-4ec2-4c76-8916-81331a2d2230", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 4624.131880974906, + "y": 2614.5694940293906 + } + }, + { + "id": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "type": "invocation", + "data": { + "id": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "type": "face_off", + "inputs": { + "metadata": { + "id": "4e7eb36f-3742-49d9-91b4-092b955ef588", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "003c3ff3-d0d0-464e-85ed-fb4df75fd513", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "face_id": { + "id": "9281074a-be25-4e43-8b80-9504b2365999", + "name": "face_id", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "minimum_confidence": { + "id": "808efdd1-41d5-4c3c-9ea3-0a1854503087", + "name": "minimum_confidence", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0.5 + }, + "x_offset": { + "id": "fd4fedf5-7fba-4687-864b-bfd018c296cf", + "name": "x_offset", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "y_offset": { + "id": "3d64697c-707e-404b-8261-9665c78f686d", + "name": "y_offset", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "padding": { + "id": "1f147de3-8fde-4bcc-8c68-a6617feed334", + "name": "padding", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "chunk": { + "id": "e60fae93-2056-4621-a6bf-d0248df6f538", + "name": "chunk", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "1c6aa0cf-4bb8-4236-b92e-a862036c9522", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "8dac27bd-7d72-471b-a310-bb7dae686a0b", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "4bfb3364-fe37-4fb8-b8a0-75d1038ce726", + "name": "height", + "type": "integer", + "fieldKind": "output" + }, + "mask": { + "id": "221c6022-5314-4f8f-afb0-4b00ceea8ecd", + "name": "mask", + "type": "ImageField", + "fieldKind": "output" + }, + "x": { + "id": "657fa37b-6e9c-4c04-b5d2-e3e659fcb0f3", + "name": "x", + "type": "integer", + "fieldKind": "output" + }, + "y": { + "id": "bc5cf72e-0389-4b8c-b886-40d145b6b73a", + "name": "y", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.2" + }, + "width": 320, + "height": 656, + "position": { + "x": 4618.594817536934, + "y": 1836.6663791833205 } } ], @@ -1175,14 +1231,6 @@ "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036clip-7c4e5071-5b76-4d42-b340-68b52c5ded7aclip", "type": "default" }, - { - "source": "c9897be0-7f59-4388-816d-86cb72cc4036", - "sourceHandle": "vae", - "target": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "targetHandle": "vae", - "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036vae-3b2ebc7f-251d-4726-b1b8-5331355f8626vae", - "type": "default" - }, { "source": "27dd9fc3-8c6e-4602-8754-e9ca2f478d68", "sourceHandle": "value", @@ -1191,22 +1239,6 @@ "id": "reactflow__edge-27dd9fc3-8c6e-4602-8754-e9ca2f478d68value-098898c8-7a20-4d78-9363-296d42e3d8daseed", "type": "default" }, - { - "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", - "sourceHandle": "image", - "target": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", - "targetHandle": "base_image", - "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-5b15322a-1ea2-4f23-b422-c2dea5f594e2base_image", - "type": "default" - }, - { - "source": "233aeb43-980a-4578-bdb7-5488d54d1bbf", - "sourceHandle": "image", - "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", - "targetHandle": "mask", - "id": "reactflow__edge-233aeb43-980a-4578-bdb7-5488d54d1bbfimage-bcbdc4ea-1fad-40d4-8632-70f84116f4b6mask", - "type": "default" - }, { "source": "c9897be0-7f59-4388-816d-86cb72cc4036", "sourceHandle": "vae", @@ -1239,156 +1271,180 @@ "id": "reactflow__edge-a6d08bcb-0b52-4dd8-9247-8b6480238c6dheight-098898c8-7a20-4d78-9363-296d42e3d8daheight", "type": "default" }, - { - "source": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "sourceHandle": "image", - "target": "8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6", - "targetHandle": "image", - "id": "reactflow__edge-3b2ebc7f-251d-4726-b1b8-5331355f8626image-8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6image", - "type": "default" - }, - { - "source": "fb7e72d9-51cb-432a-b511-c6c608d07413", - "sourceHandle": "conditioning", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-fb7e72d9-51cb-432a-b511-c6c608d07413conditioning-9e356e8e-d03d-4de9-b522-026c8751d6d4positive_conditioning", - "type": "default" - }, - { - "source": "7c4e5071-5b76-4d42-b340-68b52c5ded7a", - "sourceHandle": "conditioning", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "negative_conditioning", - "id": "reactflow__edge-7c4e5071-5b76-4d42-b340-68b52c5ded7aconditioning-9e356e8e-d03d-4de9-b522-026c8751d6d4negative_conditioning", - "type": "default" - }, { "source": "c9897be0-7f59-4388-816d-86cb72cc4036", - "sourceHandle": "unet", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "unet", - "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036unet-9e356e8e-d03d-4de9-b522-026c8751d6d4unet", + "sourceHandle": "vae", + "target": "01a35dfd-b4bd-4901-8088-49972eac7582", + "targetHandle": "vae", + "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036vae-01a35dfd-b4bd-4901-8088-49972eac7582vae", "type": "default" }, { - "source": "098898c8-7a20-4d78-9363-296d42e3d8da", - "sourceHandle": "noise", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "noise", - "id": "reactflow__edge-098898c8-7a20-4d78-9363-296d42e3d8danoise-9e356e8e-d03d-4de9-b522-026c8751d6d4noise", + "source": "01a35dfd-b4bd-4901-8088-49972eac7582", + "sourceHandle": "image", + "target": "43c00342-9ca3-498a-8635-c4c716e32d5f", + "targetHandle": "image", + "id": "reactflow__edge-01a35dfd-b4bd-4901-8088-49972eac7582image-43c00342-9ca3-498a-8635-c4c716e32d5fimage", "type": "default" }, { - "source": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", - "sourceHandle": "denoise_mask", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "denoise_mask", - "id": "reactflow__edge-bcbdc4ea-1fad-40d4-8632-70f84116f4b6denoise_mask-9e356e8e-d03d-4de9-b522-026c8751d6d4denoise_mask", - "type": "default" - }, - { - "source": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "sourceHandle": "latents", - "target": "3b2ebc7f-251d-4726-b1b8-5331355f8626", - "targetHandle": "latents", - "id": "reactflow__edge-9e356e8e-d03d-4de9-b522-026c8751d6d4latents-3b2ebc7f-251d-4726-b1b8-5331355f8626latents", - "type": "default" - }, - { - "source": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", - "sourceHandle": "latents", - "target": "9e356e8e-d03d-4de9-b522-026c8751d6d4", - "targetHandle": "latents", - "id": "reactflow__edge-a6d08bcb-0b52-4dd8-9247-8b6480238c6dlatents-9e356e8e-d03d-4de9-b522-026c8751d6d4latents", + "source": "43c00342-9ca3-498a-8635-c4c716e32d5f", + "sourceHandle": "image", + "target": "0c71919b-a030-44fb-8c09-1baf37088d20", + "targetHandle": "image", + "id": "reactflow__edge-43c00342-9ca3-498a-8635-c4c716e32d5fimage-0c71919b-a030-44fb-8c09-1baf37088d20image", "type": "default" }, { "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", "sourceHandle": "image", - "target": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "targetHandle": "image", - "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95image", + "target": "4e11665c-b932-493d-ab4f-019bed730b47", + "targetHandle": "base_image", + "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-4e11665c-b932-493d-ab4f-019bed730b47base_image", "type": "default" }, { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "sourceHandle": "mask", - "target": "233aeb43-980a-4578-bdb7-5488d54d1bbf", - "targetHandle": "image", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95mask-233aeb43-980a-4578-bdb7-5488d54d1bbfimage", - "type": "default" - }, - { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "sourceHandle": "x", - "target": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", - "targetHandle": "x", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95x-5b15322a-1ea2-4f23-b422-c2dea5f594e2x", - "type": "default" - }, - { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "sourceHandle": "y", - "target": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", - "targetHandle": "y", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95y-5b15322a-1ea2-4f23-b422-c2dea5f594e2y", - "type": "default" - }, - { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", + "source": "0c71919b-a030-44fb-8c09-1baf37088d20", "sourceHandle": "image", - "target": "7ad41b86-c089-430c-b70c-3c1cbf886ed9", + "target": "4e11665c-b932-493d-ab4f-019bed730b47", "targetHandle": "image", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95image-7ad41b86-c089-430c-b70c-3c1cbf886ed9image", + "id": "reactflow__edge-0c71919b-a030-44fb-8c09-1baf37088d20image-4e11665c-b932-493d-ab4f-019bed730b47image", "type": "default" }, { - "source": "7ad41b86-c089-430c-b70c-3c1cbf886ed9", + "source": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "sourceHandle": "latents", + "target": "01a35dfd-b4bd-4901-8088-49972eac7582", + "targetHandle": "latents", + "id": "reactflow__edge-9a6a35cd-5c05-4df1-81bf-e40a1954c618latents-01a35dfd-b4bd-4901-8088-49972eac7582latents", + "type": "default" + }, + { + "source": "c9897be0-7f59-4388-816d-86cb72cc4036", + "sourceHandle": "unet", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "unet", + "id": "reactflow__edge-c9897be0-7f59-4388-816d-86cb72cc4036unet-9a6a35cd-5c05-4df1-81bf-e40a1954c618unet", + "type": "default" + }, + { + "source": "7c4e5071-5b76-4d42-b340-68b52c5ded7a", + "sourceHandle": "conditioning", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-7c4e5071-5b76-4d42-b340-68b52c5ded7aconditioning-9a6a35cd-5c05-4df1-81bf-e40a1954c618negative_conditioning", + "type": "default" + }, + { + "source": "fb7e72d9-51cb-432a-b511-c6c608d07413", + "sourceHandle": "conditioning", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-fb7e72d9-51cb-432a-b511-c6c608d07413conditioning-9a6a35cd-5c05-4df1-81bf-e40a1954c618positive_conditioning", + "type": "default" + }, + { + "source": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", + "sourceHandle": "denoise_mask", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "denoise_mask", + "id": "reactflow__edge-bcbdc4ea-1fad-40d4-8632-70f84116f4b6denoise_mask-9a6a35cd-5c05-4df1-81bf-e40a1954c618denoise_mask", + "type": "default" + }, + { + "source": "098898c8-7a20-4d78-9363-296d42e3d8da", + "sourceHandle": "noise", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "noise", + "id": "reactflow__edge-098898c8-7a20-4d78-9363-296d42e3d8danoise-9a6a35cd-5c05-4df1-81bf-e40a1954c618noise", + "type": "default" + }, + { + "source": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", + "sourceHandle": "latents", + "target": "9a6a35cd-5c05-4df1-81bf-e40a1954c618", + "targetHandle": "latents", + "id": "reactflow__edge-a6d08bcb-0b52-4dd8-9247-8b6480238c6dlatents-9a6a35cd-5c05-4df1-81bf-e40a1954c618latents", + "type": "default" + }, + { + "source": "98048fa7-dd08-49ec-92b8-76c9017e5444", "sourceHandle": "image", "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", - "targetHandle": "image", - "id": "reactflow__edge-7ad41b86-c089-430c-b70c-3c1cbf886ed9image-bcbdc4ea-1fad-40d4-8632-70f84116f4b6image", + "targetHandle": "mask", + "id": "reactflow__edge-98048fa7-dd08-49ec-92b8-76c9017e5444image-bcbdc4ea-1fad-40d4-8632-70f84116f4b6mask", "type": "default" }, { - "source": "7ad41b86-c089-430c-b70c-3c1cbf886ed9", + "source": "894b9ca6-e7bc-428e-87e9-cce64095bce9", "sourceHandle": "image", "target": "a6d08bcb-0b52-4dd8-9247-8b6480238c6d", "targetHandle": "image", - "id": "reactflow__edge-7ad41b86-c089-430c-b70c-3c1cbf886ed9image-a6d08bcb-0b52-4dd8-9247-8b6480238c6dimage", + "id": "reactflow__edge-894b9ca6-e7bc-428e-87e9-cce64095bce9image-a6d08bcb-0b52-4dd8-9247-8b6480238c6dimage", "type": "default" }, { - "source": "8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6", + "source": "894b9ca6-e7bc-428e-87e9-cce64095bce9", "sourceHandle": "image", - "target": "98a614c8-24df-413f-b001-a728b354e931", + "target": "bcbdc4ea-1fad-40d4-8632-70f84116f4b6", "targetHandle": "image", - "id": "reactflow__edge-8bdaaacf-077d-4b73-b03c-ad7a2fdcc0b6image-98a614c8-24df-413f-b001-a728b354e931image", + "id": "reactflow__edge-894b9ca6-e7bc-428e-87e9-cce64095bce9image-bcbdc4ea-1fad-40d4-8632-70f84116f4b6image", "type": "default" }, { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", - "sourceHandle": "mask", - "target": "98a614c8-24df-413f-b001-a728b354e931", - "targetHandle": "mask", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95mask-98a614c8-24df-413f-b001-a728b354e931mask", - "type": "default" - }, - { - "source": "cd886d23-b786-4d0e-83e6-b6f1cf0ddc95", + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", "sourceHandle": "image", - "target": "98a614c8-24df-413f-b001-a728b354e931", + "target": "894b9ca6-e7bc-428e-87e9-cce64095bce9", + "targetHandle": "image", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfimage-894b9ca6-e7bc-428e-87e9-cce64095bce9image", + "type": "default" + }, + { + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "sourceHandle": "image", + "target": "0c71919b-a030-44fb-8c09-1baf37088d20", "targetHandle": "reference", - "id": "reactflow__edge-cd886d23-b786-4d0e-83e6-b6f1cf0ddc95image-98a614c8-24df-413f-b001-a728b354e931reference", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfimage-0c71919b-a030-44fb-8c09-1baf37088d20reference", "type": "default" }, { - "source": "98a614c8-24df-413f-b001-a728b354e931", - "sourceHandle": "image", - "target": "5b15322a-1ea2-4f23-b422-c2dea5f594e2", + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "sourceHandle": "mask", + "target": "98048fa7-dd08-49ec-92b8-76c9017e5444", "targetHandle": "image", - "id": "reactflow__edge-98a614c8-24df-413f-b001-a728b354e931image-5b15322a-1ea2-4f23-b422-c2dea5f594e2image", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfmask-98048fa7-dd08-49ec-92b8-76c9017e5444image", + "type": "default" + }, + { + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "sourceHandle": "mask", + "target": "0c71919b-a030-44fb-8c09-1baf37088d20", + "targetHandle": "mask", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfmask-0c71919b-a030-44fb-8c09-1baf37088d20mask", + "type": "default" + }, + { + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "sourceHandle": "x", + "target": "4e11665c-b932-493d-ab4f-019bed730b47", + "targetHandle": "x", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfx-4e11665c-b932-493d-ab4f-019bed730b47x", + "type": "default" + }, + { + "source": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "sourceHandle": "y", + "target": "4e11665c-b932-493d-ab4f-019bed730b47", + "targetHandle": "y", + "id": "reactflow__edge-efea8306-de20-418f-806c-31ae4e5eb6bfy-4e11665c-b932-493d-ab4f-019bed730b47y", + "type": "default" + }, + { + "source": "3fac3aa6-910a-4a90-a8b6-5b7e1611efba", + "sourceHandle": "image", + "target": "efea8306-de20-418f-806c-31ae4e5eb6bf", + "targetHandle": "image", + "id": "reactflow__edge-3fac3aa6-910a-4a90-a8b6-5b7e1611efbaimage-efea8306-de20-418f-806c-31ae4e5eb6bfimage", "type": "default" } ] diff --git a/docs/workflows/Face_Detailer_with_IP-Adapter_and_Canny.json b/docs/workflows/Face_Detailer_with_IP-Adapter_and_Canny.json new file mode 100644 index 0000000000..3ef8d720f8 --- /dev/null +++ b/docs/workflows/Face_Detailer_with_IP-Adapter_and_Canny.json @@ -0,0 +1,2032 @@ +{ + "name": "Face Detailer with IP-Adapter & Canny", + "author": "@kosmoskatten", + "description": "A workflow to automatically improve faces in an image using IP-Adapter and Canny ControlNet. ", + "version": "0.1.0", + "contact": "@kosmoskatten via Discord", + "tags": "face, detailer, SD1.5", + "notes": "", + "exposedFields": [ + { + "nodeId": "cdfa5ab0-b3e2-43ed-85bb-2ac4aa83bc05", + "fieldName": "value" + }, + { + "nodeId": "64712037-92e8-483f-9f6e-87588539c1b8", + "fieldName": "value" + }, + { + "nodeId": "f0de6c44-4515-4f79-bcc0-dee111bcfe31", + "fieldName": "value" + }, + { + "nodeId": "2c9bc2a6-6c03-4861-aad4-db884a7682f8", + "fieldName": "image" + } + ], + "meta": { + "version": "1.0.0" + }, + "nodes": [ + { + "id": "44f2c190-eb03-460d-8d11-a94d13b33f19", + "type": "invocation", + "data": { + "id": "44f2c190-eb03-460d-8d11-a94d13b33f19", + "type": "compel", + "inputs": { + "prompt": { + "id": "916b229a-38e1-45a2-a433-cca97495b143", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "ae9aeb1a-4ebd-4bc3-b6e6-a8c9adca01f6", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "4d59bad1-99a9-43e2-bdb4-7a0f3dd5b787", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 3176.5748307120457, + "y": -605.7792243912572 + } + }, + { + "id": "2c9bc2a6-6c03-4861-aad4-db884a7682f8", + "type": "invocation", + "data": { + "id": "2c9bc2a6-6c03-4861-aad4-db884a7682f8", + "type": "image", + "inputs": { + "image": { + "id": "729c571b-d5a0-4b53-8f50-5e11eb744f66", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "Original Image", + "value": { + "image_name": "013a13e0-3af3-4fd8-8e6e-9dafb658e0bb.png" + } + } + }, + "outputs": { + "image": { + "id": "3632a144-58d6-4447-bafc-e4f7d6ca96bf", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "30faefcc-81a1-445b-a3fe-0110ceb56772", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "d173d225-849a-4498-a75d-ba17210dbd3e", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 225, + "position": { + "x": 1787.0260885895482, + "y": 171.61158302175093 + } + }, + { + "id": "de8b1a48-a2e4-42ca-90bb-66058bffd534", + "type": "invocation", + "data": { + "id": "de8b1a48-a2e4-42ca-90bb-66058bffd534", + "type": "i2l", + "inputs": { + "image": { + "id": "6c4d2827-4995-49d4-94ce-0ba0541d8839", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "9d6e3ab6-b6a4-45ac-ad75-0a96efba4c2f", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "9c258141-a75d-4ffd-bce5-f3fb3d90b720", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "2235cc48-53c9-4e8a-a74a-ed41c61f2993", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true + } + }, + "outputs": { + "latents": { + "id": "8eb9293f-8f43-4c0c-b0fb-8c4db1200f87", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "ce493959-d308-423c-b0f5-db05912e0318", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "827bf290-94fb-455f-a970-f98ba8800eac", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 325, + "position": { + "x": 3165.534313998739, + "y": -261.54699233490976 + } + }, + { + "id": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "type": "invocation", + "data": { + "id": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "type": "noise", + "inputs": { + "seed": { + "id": "c6b5bc5e-ef09-4f9c-870e-1110a0f5017f", + "name": "seed", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 123451234 + }, + "width": { + "id": "7bdd24b6-4f14-4d0a-b8fc-9b24145b4ba9", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "dc15bf97-b8d5-49c6-999b-798b33679418", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "use_cpu": { + "id": "00626297-19dd-4989-9688-e8d527c9eacf", + "name": "use_cpu", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true + } + }, + "outputs": { + "noise": { + "id": "2915f8ae-0f6e-4f26-8541-0ebf477586b6", + "name": "noise", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "26587461-a24a-434d-9ae5-8d8f36fea221", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "335d08fc-8bf1-4393-8902-2c579f327b51", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 389, + "position": { + "x": 4101.873817022418, + "y": -826.2333237957032 + } + }, + { + "id": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "type": "invocation", + "data": { + "id": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "type": "lscale", + "inputs": { + "latents": { + "id": "79e8f073-ddc3-416e-b818-6ef8ec73cc07", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "scale_factor": { + "id": "23f78d24-72df-4bde-8d3c-8593ce507205", + "name": "scale_factor", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1.5 + }, + "mode": { + "id": "4ab30c38-57d3-480d-8b34-918887e92340", + "name": "mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bilinear" + }, + "antialias": { + "id": "22b39171-0003-44f0-9c04-d241581d2a39", + "name": "antialias", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true + } + }, + "outputs": { + "latents": { + "id": "f6d71aef-6251-4d51-afa8-f692a72bfd1f", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "8db4cf33-5489-4887-a5f6-5e926d959c40", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "74e1ec7c-50b6-4e97-a7b8-6602e6d78c08", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 332, + "position": { + "x": 3693.9622528252976, + "y": -448.17155148430743 + } + }, + { + "id": "cdfa5ab0-b3e2-43ed-85bb-2ac4aa83bc05", + "type": "invocation", + "data": { + "id": "cdfa5ab0-b3e2-43ed-85bb-2ac4aa83bc05", + "type": "float", + "inputs": { + "value": { + "id": "d5d8063d-44f6-4e20-b557-2f4ce093c7ef", + "name": "value", + "type": "float", + "fieldKind": "input", + "label": "Orignal Image Percentage", + "value": 0.4 + } + }, + "outputs": { + "value": { + "id": "562416a4-0d75-48aa-835e-5e2d221dfbb7", + "name": "value", + "type": "float", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 161, + "position": { + "x": 3709.006050756633, + "y": -84.77200251095934 + } + }, + { + "id": "64712037-92e8-483f-9f6e-87588539c1b8", + "type": "invocation", + "data": { + "id": "64712037-92e8-483f-9f6e-87588539c1b8", + "type": "float", + "inputs": { + "value": { + "id": "750358d5-251d-4fe6-a673-2cde21995da2", + "name": "value", + "type": "float", + "fieldKind": "input", + "label": "CFG Main", + "value": 6 + } + }, + "outputs": { + "value": { + "id": "eea7f6d2-92e4-4581-b555-64a44fda2be9", + "name": "value", + "type": "float", + "fieldKind": "output" + } + }, + "label": "CFG Main", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 161, + "position": { + "x": 4064.218597371266, + "y": 221.28424598733164 + } + }, + { + "id": "c865f39f-f830-4ed7-88a5-e935cfe050a9", + "type": "invocation", + "data": { + "id": "c865f39f-f830-4ed7-88a5-e935cfe050a9", + "type": "rand_int", + "inputs": { + "low": { + "id": "31e29709-9f19-45b0-a2de-fdee29a50393", + "name": "low", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "high": { + "id": "d47d875c-509d-4fa3-9112-e335d3144a17", + "name": "high", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 2147483647 + } + }, + "outputs": { + "value": { + "id": "15b8d1ea-d2ac-4b3a-9619-57bba9a6da75", + "name": "value", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" + }, + "width": 320, + "height": 218, + "position": { + "x": 3662.7851649243958, + "y": -784.114001413615 + } + }, + { + "id": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "type": "invocation", + "data": { + "id": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "type": "main_model_loader", + "inputs": { + "model": { + "id": "54e737f9-2547-4bd9-a607-733d02f0c990", + "name": "model", + "type": "MainModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "stable-diffusion-v1-5", + "base_model": "sd-1", + "model_type": "main" + } + } + }, + "outputs": { + "unet": { + "id": "3483ea21-f0b3-4422-894b-36c5d7701365", + "name": "unet", + "type": "UNetField", + "fieldKind": "output" + }, + "clip": { + "id": "dddd055f-5c1b-4e61-977b-6393da9006fa", + "name": "clip", + "type": "ClipField", + "fieldKind": "output" + }, + "vae": { + "id": "879893b4-3415-4879-8dff-aa1727ef5e63", + "name": "vae", + "type": "VaeField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 226, + "position": { + "x": 2517.1672231749144, + "y": -751.385499561434 + } + }, + { + "id": "f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65", + "type": "invocation", + "data": { + "id": "f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65", + "type": "compel", + "inputs": { + "prompt": { + "id": "916b229a-38e1-45a2-a433-cca97495b143", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "ae9aeb1a-4ebd-4bc3-b6e6-a8c9adca01f6", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "4d59bad1-99a9-43e2-bdb4-7a0f3dd5b787", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 3174.140478653321, + "y": -874.0896905277255 + } + }, + { + "id": "f60b6161-8f26-42f6-89ff-545e6011e501", + "type": "invocation", + "data": { + "id": "f60b6161-8f26-42f6-89ff-545e6011e501", + "type": "controlnet", + "inputs": { + "image": { + "id": "96434c75-abd8-4b73-ab82-0b358e4735bf", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "control_model": { + "id": "21551ac2-ee50-4fe8-b06c-5be00680fb5c", + "name": "control_model", + "type": "ControlNetModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "sd-controlnet-canny", + "base_model": "sd-1" + } + }, + "control_weight": { + "id": "1dacac0a-b985-4bdf-b4b5-b960f4cff6ed", + "name": "control_weight", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 0.5 + }, + "begin_step_percent": { + "id": "b2a3f128-7fc1-4c12-acc8-540f013c856b", + "name": "begin_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "end_step_percent": { + "id": "0e701834-f7ba-4a6e-b9cb-6d4aff5dacd8", + "name": "end_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0.5 + }, + "control_mode": { + "id": "f9a5f038-ae80-4b6e-8a48-362a2c858299", + "name": "control_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "balanced" + }, + "resize_mode": { + "id": "5369dd44-a708-4b66-8182-fea814d2a0ae", + "name": "resize_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "just_resize" + } + }, + "outputs": { + "control": { + "id": "f470a1af-7b68-4849-a144-02bc345fd810", + "name": "control", + "type": "ControlField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 508, + "position": { + "x": 3926.9358191964657, + "y": 538.0129522372209 + } + }, + { + "id": "f0de6c44-4515-4f79-bcc0-dee111bcfe31", + "type": "invocation", + "data": { + "id": "f0de6c44-4515-4f79-bcc0-dee111bcfe31", + "type": "float", + "inputs": { + "value": { + "id": "9b51a26f-af3c-4caa-940a-5183234b1ed7", + "name": "value", + "type": "float", + "fieldKind": "input", + "label": "Face Detail Scale", + "value": 1.5 + } + }, + "outputs": { + "value": { + "id": "c7c87b77-c149-4e9c-8ed1-beb1ba013055", + "name": "value", + "type": "float", + "fieldKind": "output" + } + }, + "label": "Face Detail Scale", + "isOpen": true, + "notes": "The image is cropped to the face and scaled to 512x512. This value can scale even more. Best result with value between 1-2.\n\n1 = 512\n2 = 1024\n\n", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 161, + "position": { + "x": 2505.1027422955735, + "y": -447.7244534284996 + } + }, + { + "id": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "type": "invocation", + "data": { + "id": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "type": "denoise_latents", + "inputs": { + "noise": { + "id": "2223c30c-e3ef-4a2b-9ae8-31f9f2b38f68", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "09c2a8c9-0771-4e35-b674-26633fe5d740", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "dcef4b34-926f-46c1-9e57-c6401f1ac901", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "efb48776-93b4-4a1b-9b9e-ea173720850d", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "acedd753-b95c-4c23-91a8-398bc85f03cb", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "d6aedf09-ad0e-433f-9d70-fcf43303840d", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "control": { + "id": "f83850ba-d6d6-4ba9-9f41-424427a005f4", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "6e42ab48-8eaf-4d05-ba5e-0b7d7667249d", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "32c2f9c1-ae8a-4f9b-9e06-30debb6b1190", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "79479fdb-82b6-4b7f-8a4a-e658c2ff0d2f", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "c76b77a3-bcde-4425-bfdd-638becefb4ba", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + }, + "positive_conditioning": { + "id": "f14ea66a-5e7b-400b-a835-049286aa0c82", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "ce94941f-9e4e-41f4-b33f-1d6907919964", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "unet": { + "id": "290f45fa-1543-4e41-ab6f-63e139556dfc", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "ab8a8305-e6e7-4569-956c-02d5d0fa2989", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "161773a7-4e7b-44b6-98d9-f565036f190b", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "4fe54d15-d9b9-4fd0-b8ac-a1b2a11f3243", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.3.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 4482.62568856733, + "y": -385.4092574423216 + } + }, + { + "id": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "type": "invocation", + "data": { + "id": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "type": "face_off", + "inputs": { + "metadata": { + "id": "6ad02931-9067-43e3-bc2b-29ce5388b317", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "01e0d368-7712-4c5b-8f73-18d3d3459d82", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "face_id": { + "id": "563cd209-2adf-4249-97df-0d13818ae057", + "name": "face_id", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "minimum_confidence": { + "id": "2cb09928-911c-43d7-8cbb-be13aed8f9a4", + "name": "minimum_confidence", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0.5 + }, + "x_offset": { + "id": "80d5fa06-a719-454f-9641-8ca5e2889d2d", + "name": "x_offset", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "y_offset": { + "id": "ff03fe44-26d1-4d8b-a012-3e05c918d56f", + "name": "y_offset", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "padding": { + "id": "05db8638-24f4-4a0a-9040-ae9beabd194b", + "name": "padding", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "chunk": { + "id": "d6a556b3-f1c7-480b-b1a2-e9441a3bb344", + "name": "chunk", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "963b445d-a35f-476b-b164-c61a35b86ef1", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "fa64b386-f45f-4979-8004-c1cf21b83d9c", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "bf7711ec-7788-4d9b-9abf-8cc0638f264d", + "name": "height", + "type": "integer", + "fieldKind": "output" + }, + "mask": { + "id": "c6dcf700-e903-4c9e-bd84-94f169c6d04c", + "name": "mask", + "type": "ImageField", + "fieldKind": "output" + }, + "x": { + "id": "d4993748-913b-4490-b71f-9400c1fe9f2d", + "name": "x", + "type": "integer", + "fieldKind": "output" + }, + "y": { + "id": "af9c4994-4f1b-4715-aa44-6c5b21274af4", + "name": "y", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.2" + }, + "width": 320, + "height": 656, + "position": { + "x": 2414.612131259088, + "y": 291.78659156828013 + } + }, + { + "id": "e3383c2f-828e-4b9c-94bb-9f10de86cc7f", + "type": "invocation", + "data": { + "id": "e3383c2f-828e-4b9c-94bb-9f10de86cc7f", + "type": "img_resize", + "inputs": { + "metadata": { + "id": "01bd4648-7c80-497c-823d-48ad41ce1cd2", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "1893f2cc-344a-4f15-8f01-85ba99da518b", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "width": { + "id": "123d1849-df1b-4e36-8329-f45235f857cf", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "ebdf1684-abe5-42e1-b16e-797ffdfee7a2", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "resample_mode": { + "id": "e83edb34-9391-4830-a1fb-fe0e0f5087bd", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "0c369a81-bdd3-4b4c-9626-95ce47375ed1", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "560d5588-8df8-41e8-aa69-fb8c95cdb4e2", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "2b04576b-7b22-4b2a-9fb6-57c1fd86a506", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 396, + "position": { + "x": 2447.826252430936, + "y": -201.68035155632666 + } + }, + { + "id": "60343212-208e-4ec5-97c4-df78e30a3066", + "type": "invocation", + "data": { + "id": "60343212-208e-4ec5-97c4-df78e30a3066", + "type": "img_scale", + "inputs": { + "metadata": { + "id": "607e3b73-c76e-477e-8479-8130d3a25028", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "b04d11ba-cc0c-48d5-ab9e-f3958a5e8839", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "scale_factor": { + "id": "79656494-c8c0-4096-b25a-628d9c37f071", + "name": "scale_factor", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 2 + }, + "resample_mode": { + "id": "92176f78-e21a-4085-884d-c66c7135c714", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "2321a8bf-3f55-470d-afe3-b8760240d59a", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "62005d4a-7961-439c-9357-9de5fc53b51b", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "3f0a7f7f-ea40-48de-8b1b-8570595e94ef", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 3007.7214378992408, + "y": 211.12372586521934 + } + }, + { + "id": "07099eb0-9d58-4e0b-82f8-3063c3af2689", + "type": "invocation", + "data": { + "id": "07099eb0-9d58-4e0b-82f8-3063c3af2689", + "type": "canny_image_processor", + "inputs": { + "metadata": { + "id": "7d38d9d6-029b-4de6-aabf-5aa46c508291", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "656409a8-aa89-4ecb-bb6c-8d5e612aa814", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "low_threshold": { + "id": "1879f7c5-dd3a-4770-a260-b18111577e63", + "name": "low_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 100 + }, + "high_threshold": { + "id": "b84b6aad-cb83-40d3-85a6-e18dc440d89b", + "name": "high_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 200 + } + }, + "outputs": { + "image": { + "id": "98e8c22c-43cb-41a3-9e8c-c4fdc3cbe749", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "a8eaa116-2bc1-4dab-84bf-4e21c6e14296", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "ddab1f63-c0c8-4ff7-9124-f0c6cdda81f8", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 3444.7466139600724, + "y": 586.5162666396674 + } + }, + { + "id": "a50af8a0-7b7e-4cb8-a116-89f2d83f33ed", + "type": "invocation", + "data": { + "id": "a50af8a0-7b7e-4cb8-a116-89f2d83f33ed", + "type": "ip_adapter", + "inputs": { + "image": { + "id": "1cee5c9b-8d23-4b11-a699-5919c86a972f", + "name": "image", + "type": "ImagePolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter_model": { + "id": "3ca282f7-be7c-44a1-8a5a-94afdecae0ae", + "name": "ip_adapter_model", + "type": "IPAdapterModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "ip_adapter_plus_face_sd15", + "base_model": "sd-1" + } + }, + "weight": { + "id": "eee84151-d5a0-4970-a984-9b0c26e3a58a", + "name": "weight", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "begin_step_percent": { + "id": "0ed4cc66-5688-4554-9f2b-acf0a33415a1", + "name": "begin_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "end_step_percent": { + "id": "9544971a-8963-43da-abf4-0920781209ca", + "name": "end_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + } + }, + "outputs": { + "ip_adapter": { + "id": "03814df3-0117-434e-b35b-7902fc519e80", + "name": "ip_adapter", + "type": "IPAdapterField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.1.0" + }, + "width": 320, + "height": 394, + "position": { + "x": 3486.4422814170716, + "y": 112.39273647258193 + } + }, + { + "id": "03df59d0-a061-430c-a76f-5a4cf3e14378", + "type": "invocation", + "data": { + "id": "03df59d0-a061-430c-a76f-5a4cf3e14378", + "type": "img_resize", + "inputs": { + "metadata": { + "id": "9fbe66f2-700c-457a-ab06-434a8f8169e9", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "37914278-90ba-4095-8c13-067a90a256cc", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "width": { + "id": "9d2b22b0-0a2a-4da8-aec0-c50f419bd134", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "d5590b6b-96c3-4d7d-b472-56269515e1ad", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "resample_mode": { + "id": "975d601c-8801-4881-b138-a43afccb89e9", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "75099113-a677-4a05-96a6-e680c00c2c01", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "15132cfa-f46d-44df-9272-0b5abdd101b2", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "0f80c001-cee0-4a20-92a4-3a7b01130ffe", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 396, + "position": { + "x": 4423.278808515647, + "y": 350.94607680079463 + } + }, + { + "id": "8bb08a28-0a64-4da9-9bf4-4526ea40f437", + "type": "invocation", + "data": { + "id": "8bb08a28-0a64-4da9-9bf4-4526ea40f437", + "type": "img_blur", + "inputs": { + "metadata": { + "id": "ccbff6e7-4138-462c-bc2f-ea14bda4faa8", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "1c47e5ea-4f6e-4608-a15a-2eed4052d895", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "radius": { + "id": "646349d2-25ac-49ac-9aa9-bcd78a3362ab", + "name": "radius", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 8 + }, + "blur_type": { + "id": "0d3c8ada-0743-4f73-a29a-b359022b3745", + "name": "blur_type", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "gaussian" + } + }, + "outputs": { + "image": { + "id": "f775bed9-bb8e-47b1-b08a-cfb9a5d2501d", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "1ec74094-1181-41cb-9a11-6f93e4997913", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "7b91bdb5-27c0-4cee-8005-854675c2dedd", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 4876.996101782848, + "y": 349.1456113513215 + } + }, + { + "id": "227f0e19-3a4e-44f0-9f52-a8591b719bbe", + "type": "invocation", + "data": { + "id": "227f0e19-3a4e-44f0-9f52-a8591b719bbe", + "type": "mask_combine", + "inputs": { + "metadata": { + "id": "39eb7bba-0668-4349-9093-6aede07bec66", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "mask1": { + "id": "0ee7c237-b775-4470-8061-29eee0b1c9ae", + "name": "mask1", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "mask2": { + "id": "6231f048-0165-4bb8-b468-446f71b882bb", + "name": "mask2", + "type": "ImageField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "image": { + "id": "321dde14-3a6d-4606-af05-477e92735a14", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "0801ee9e-a19b-46ca-b919-747e81323aa9", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "7d2614d3-3ac8-44f0-9726-b1591057670f", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 282, + "position": { + "x": 5346.9175840953085, + "y": 374.352127643944 + } + }, + { + "id": "0d05a218-0208-4038-a3e7-867bd9367593", + "type": "invocation", + "data": { + "id": "0d05a218-0208-4038-a3e7-867bd9367593", + "type": "l2i", + "inputs": { + "metadata": { + "id": "a2f3806c-f4ea-41f2-b213-c049197bbeb4", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "e5a25c64-bafe-4fae-b066-21062f18582c", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "af671339-cc72-4fab-8908-1ede72ffbe23", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "a5d71aea-2e23-4517-be62-948fc70f0cfa", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "c2b8897e-67cb-43a5-a448-834ea9ce0ba0", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "93f1ba9e-5cfe-4282-91ed-fc5b586d3961", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "8f844f95-9ee6-469d-9706-9b48fb616a23", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "bac22e85-9bdd-468d-b3e3-a94325ea2f85", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 4966.928144382504, + "y": -294.018133443524 + } + }, + { + "id": "db4981fd-e6eb-42b3-910b-b15443fa863d", + "type": "invocation", + "data": { + "id": "db4981fd-e6eb-42b3-910b-b15443fa863d", + "type": "img_resize", + "inputs": { + "metadata": { + "id": "37f62260-8cf9-443d-8838-8acece688821", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "9e95616d-2079-4d48-bb7d-b641b4cd1d69", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "width": { + "id": "96cc2cac-69e8-40f8-9e0e-b23ee7db9e08", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "eb9b8960-6f63-43be-aba5-2c165a46bfcf", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "resample_mode": { + "id": "bafe9aef-0e59-49d3-97bf-00df38dd7e11", + "name": "resample_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "bicubic" + } + }, + "outputs": { + "image": { + "id": "9f3e1433-5ab1-4c2e-8adb-aafcc051054b", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "a8433208-ea4a-417e-a1ac-6fa4ca8a6537", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "29bceb69-05a9-463a-b003-75e337ad5be0", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 396, + "position": { + "x": 5379.153347937034, + "y": -198.406964558253 + } + }, + { + "id": "ab1387b7-6b00-4e20-acae-2ca2c1597896", + "type": "invocation", + "data": { + "id": "ab1387b7-6b00-4e20-acae-2ca2c1597896", + "type": "img_paste", + "inputs": { + "metadata": { + "id": "91fa397b-cadb-42ca-beee-e9437f6ddd3d", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "base_image": { + "id": "d2073c40-9299-438f-ab7b-b9fe85f5550d", + "name": "base_image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "c880fd54-a830-4f16-a1fe-c07d8ecd5d96", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "mask": { + "id": "a8ae99d0-7e67-4064-9f34-4c4cebfcdca9", + "name": "mask", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "x": { + "id": "bd874e6d-ec17-496e-864a-0a6f613ef3f2", + "name": "x", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "y": { + "id": "8fcb1a55-3275-448a-8571-f93909468cdc", + "name": "y", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "crop": { + "id": "54fad883-e0d8-46e8-a933-7bac0e8977eb", + "name": "crop", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "c9e38cb4-daad-4ed2-87e1-cf36cc4fccc4", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "93832b00-1691-475d-a04b-277598ca33e0", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "9e57e4da-e349-4356-956f-b50f41f7f19b", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": false, + "useCache": true, + "version": "1.0.1" + }, + "width": 320, + "height": 504, + "position": { + "x": 6054.981342632396, + "y": -107.76717121720509 + } + } + ], + "edges": [ + { + "source": "de8b1a48-a2e4-42ca-90bb-66058bffd534", + "sourceHandle": "latents", + "target": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "targetHandle": "latents", + "id": "reactflow__edge-de8b1a48-a2e4-42ca-90bb-66058bffd534latents-2974e5b3-3d41-4b6f-9953-cd21e8f3a323latents", + "type": "default" + }, + { + "source": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "sourceHandle": "width", + "target": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "targetHandle": "width", + "id": "reactflow__edge-2974e5b3-3d41-4b6f-9953-cd21e8f3a323width-35623411-ba3a-4eaa-91fd-1e0fda0a5b42width", + "type": "default" + }, + { + "source": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "sourceHandle": "height", + "target": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "targetHandle": "height", + "id": "reactflow__edge-2974e5b3-3d41-4b6f-9953-cd21e8f3a323height-35623411-ba3a-4eaa-91fd-1e0fda0a5b42height", + "type": "default" + }, + { + "source": "c865f39f-f830-4ed7-88a5-e935cfe050a9", + "sourceHandle": "value", + "target": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "targetHandle": "seed", + "id": "reactflow__edge-c865f39f-f830-4ed7-88a5-e935cfe050a9value-35623411-ba3a-4eaa-91fd-1e0fda0a5b42seed", + "type": "default" + }, + { + "source": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "sourceHandle": "clip", + "target": "f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65", + "targetHandle": "clip", + "id": "reactflow__edge-76ea1e31-eabe-4080-935e-e74ce20e2805clip-f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65clip", + "type": "default" + }, + { + "source": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "sourceHandle": "vae", + "target": "de8b1a48-a2e4-42ca-90bb-66058bffd534", + "targetHandle": "vae", + "id": "reactflow__edge-76ea1e31-eabe-4080-935e-e74ce20e2805vae-de8b1a48-a2e4-42ca-90bb-66058bffd534vae", + "type": "default" + }, + { + "source": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "sourceHandle": "clip", + "target": "44f2c190-eb03-460d-8d11-a94d13b33f19", + "targetHandle": "clip", + "id": "reactflow__edge-76ea1e31-eabe-4080-935e-e74ce20e2805clip-44f2c190-eb03-460d-8d11-a94d13b33f19clip", + "type": "default" + }, + { + "source": "f0de6c44-4515-4f79-bcc0-dee111bcfe31", + "sourceHandle": "value", + "target": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "targetHandle": "scale_factor", + "id": "reactflow__edge-f0de6c44-4515-4f79-bcc0-dee111bcfe31value-2974e5b3-3d41-4b6f-9953-cd21e8f3a323scale_factor", + "type": "default" + }, + { + "source": "2974e5b3-3d41-4b6f-9953-cd21e8f3a323", + "sourceHandle": "latents", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "latents", + "id": "reactflow__edge-2974e5b3-3d41-4b6f-9953-cd21e8f3a323latents-e41c9dcc-a460-439a-85f3-eb18c74d9411latents", + "type": "default" + }, + { + "source": "f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65", + "sourceHandle": "conditioning", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-f4d15b64-c4a6-42a5-90fc-e4ed07a0ca65conditioning-e41c9dcc-a460-439a-85f3-eb18c74d9411positive_conditioning", + "type": "default" + }, + { + "source": "44f2c190-eb03-460d-8d11-a94d13b33f19", + "sourceHandle": "conditioning", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-44f2c190-eb03-460d-8d11-a94d13b33f19conditioning-e41c9dcc-a460-439a-85f3-eb18c74d9411negative_conditioning", + "type": "default" + }, + { + "source": "76ea1e31-eabe-4080-935e-e74ce20e2805", + "sourceHandle": "unet", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "unet", + "id": "reactflow__edge-76ea1e31-eabe-4080-935e-e74ce20e2805unet-e41c9dcc-a460-439a-85f3-eb18c74d9411unet", + "type": "default" + }, + { + "source": "f60b6161-8f26-42f6-89ff-545e6011e501", + "sourceHandle": "control", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "control", + "id": "reactflow__edge-f60b6161-8f26-42f6-89ff-545e6011e501control-e41c9dcc-a460-439a-85f3-eb18c74d9411control", + "type": "default" + }, + { + "source": "64712037-92e8-483f-9f6e-87588539c1b8", + "sourceHandle": "value", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "cfg_scale", + "id": "reactflow__edge-64712037-92e8-483f-9f6e-87588539c1b8value-e41c9dcc-a460-439a-85f3-eb18c74d9411cfg_scale", + "type": "default" + }, + { + "source": "35623411-ba3a-4eaa-91fd-1e0fda0a5b42", + "sourceHandle": "noise", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "noise", + "id": "reactflow__edge-35623411-ba3a-4eaa-91fd-1e0fda0a5b42noise-e41c9dcc-a460-439a-85f3-eb18c74d9411noise", + "type": "default" + }, + { + "source": "cdfa5ab0-b3e2-43ed-85bb-2ac4aa83bc05", + "sourceHandle": "value", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "denoising_start", + "id": "reactflow__edge-cdfa5ab0-b3e2-43ed-85bb-2ac4aa83bc05value-e41c9dcc-a460-439a-85f3-eb18c74d9411denoising_start", + "type": "default" + }, + { + "source": "2c9bc2a6-6c03-4861-aad4-db884a7682f8", + "sourceHandle": "image", + "target": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "targetHandle": "image", + "id": "reactflow__edge-2c9bc2a6-6c03-4861-aad4-db884a7682f8image-1bb5d85c-fc4d-41ed-94c6-88559f497491image", + "type": "default" + }, + { + "source": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "sourceHandle": "image", + "target": "e3383c2f-828e-4b9c-94bb-9f10de86cc7f", + "targetHandle": "image", + "id": "reactflow__edge-1bb5d85c-fc4d-41ed-94c6-88559f497491image-e3383c2f-828e-4b9c-94bb-9f10de86cc7fimage", + "type": "default" + }, + { + "source": "e3383c2f-828e-4b9c-94bb-9f10de86cc7f", + "sourceHandle": "image", + "target": "de8b1a48-a2e4-42ca-90bb-66058bffd534", + "targetHandle": "image", + "id": "reactflow__edge-e3383c2f-828e-4b9c-94bb-9f10de86cc7fimage-de8b1a48-a2e4-42ca-90bb-66058bffd534image", + "type": "default" + }, + { + "source": "e3383c2f-828e-4b9c-94bb-9f10de86cc7f", + "sourceHandle": "image", + "target": "60343212-208e-4ec5-97c4-df78e30a3066", + "targetHandle": "image", + "id": "reactflow__edge-e3383c2f-828e-4b9c-94bb-9f10de86cc7fimage-60343212-208e-4ec5-97c4-df78e30a3066image", + "type": "default" + }, + { + "source": "f0de6c44-4515-4f79-bcc0-dee111bcfe31", + "sourceHandle": "value", + "target": "60343212-208e-4ec5-97c4-df78e30a3066", + "targetHandle": "scale_factor", + "id": "reactflow__edge-f0de6c44-4515-4f79-bcc0-dee111bcfe31value-60343212-208e-4ec5-97c4-df78e30a3066scale_factor", + "type": "default" + }, + { + "source": "60343212-208e-4ec5-97c4-df78e30a3066", + "sourceHandle": "image", + "target": "07099eb0-9d58-4e0b-82f8-3063c3af2689", + "targetHandle": "image", + "id": "reactflow__edge-60343212-208e-4ec5-97c4-df78e30a3066image-07099eb0-9d58-4e0b-82f8-3063c3af2689image", + "type": "default" + }, + { + "source": "07099eb0-9d58-4e0b-82f8-3063c3af2689", + "sourceHandle": "image", + "target": "f60b6161-8f26-42f6-89ff-545e6011e501", + "targetHandle": "image", + "id": "reactflow__edge-07099eb0-9d58-4e0b-82f8-3063c3af2689image-f60b6161-8f26-42f6-89ff-545e6011e501image", + "type": "default" + }, + { + "source": "60343212-208e-4ec5-97c4-df78e30a3066", + "sourceHandle": "image", + "target": "a50af8a0-7b7e-4cb8-a116-89f2d83f33ed", + "targetHandle": "image", + "id": "reactflow__edge-60343212-208e-4ec5-97c4-df78e30a3066image-a50af8a0-7b7e-4cb8-a116-89f2d83f33edimage", + "type": "default" + }, + { + "source": "a50af8a0-7b7e-4cb8-a116-89f2d83f33ed", + "sourceHandle": "ip_adapter", + "target": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "targetHandle": "ip_adapter", + "id": "reactflow__edge-a50af8a0-7b7e-4cb8-a116-89f2d83f33edip_adapter-e41c9dcc-a460-439a-85f3-eb18c74d9411ip_adapter", + "type": "default" + }, + { + "source": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "sourceHandle": "width", + "target": "03df59d0-a061-430c-a76f-5a4cf3e14378", + "targetHandle": "width", + "id": "reactflow__edge-1bb5d85c-fc4d-41ed-94c6-88559f497491width-03df59d0-a061-430c-a76f-5a4cf3e14378width", + "type": "default" + }, + { + "source": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "sourceHandle": "height", + "target": "03df59d0-a061-430c-a76f-5a4cf3e14378", + "targetHandle": "height", + "id": "reactflow__edge-1bb5d85c-fc4d-41ed-94c6-88559f497491height-03df59d0-a061-430c-a76f-5a4cf3e14378height", + "type": "default" + }, + { + "source": "1bb5d85c-fc4d-41ed-94c6-88559f497491", + "sourceHandle": "mask", + "target": "8bb08a28-0a64-4da9-9bf4-4526ea40f437", + "targetHandle": "image", + "id": "reactflow__edge-1bb5d85c-fc4d-41ed-94c6-88559f497491mask-8bb08a28-0a64-4da9-9bf4-4526ea40f437image", + "type": "default" + }, + { + "source": "8bb08a28-0a64-4da9-9bf4-4526ea40f437", + "sourceHandle": "image", + "target": "227f0e19-3a4e-44f0-9f52-a8591b719bbe", + "targetHandle": "mask1", + "id": "reactflow__edge-8bb08a28-0a64-4da9-9bf4-4526ea40f437image-227f0e19-3a4e-44f0-9f52-a8591b719bbemask1", + "type": "default" + }, + { + "source": "03df59d0-a061-430c-a76f-5a4cf3e14378", + "sourceHandle": "image", + "target": "227f0e19-3a4e-44f0-9f52-a8591b719bbe", + "targetHandle": "mask2", + "id": "reactflow__edge-03df59d0-a061-430c-a76f-5a4cf3e14378image-227f0e19-3a4e-44f0-9f52-a8591b719bbemask2", + "type": "default" + }, + { + "source": "e41c9dcc-a460-439a-85f3-eb18c74d9411", + "sourceHandle": "latents", + "target": "0d05a218-0208-4038-a3e7-867bd9367593", + "targetHandle": "latents", + "id": "reactflow__edge-e41c9dcc-a460-439a-85f3-eb18c74d9411latents-0d05a218-0208-4038-a3e7-867bd9367593latents", + "type": "default" + }, + { + "source": "0d05a218-0208-4038-a3e7-867bd9367593", + "sourceHandle": "image", + "target": "db4981fd-e6eb-42b3-910b-b15443fa863d", + "targetHandle": "image", + "id": "reactflow__edge-0d05a218-0208-4038-a3e7-867bd9367593image-db4981fd-e6eb-42b3-910b-b15443fa863dimage", + "type": "default" + }, + { + "source": "db4981fd-e6eb-42b3-910b-b15443fa863d", + "sourceHandle": "image", + "target": "ab1387b7-6b00-4e20-acae-2ca2c1597896", + "targetHandle": "image", + "id": "reactflow__edge-db4981fd-e6eb-42b3-910b-b15443fa863dimage-ab1387b7-6b00-4e20-acae-2ca2c1597896image", + "type": "default" + }, + { + "source": "2c9bc2a6-6c03-4861-aad4-db884a7682f8", + "sourceHandle": "image", + "target": "ab1387b7-6b00-4e20-acae-2ca2c1597896", + "targetHandle": "base_image", + "id": "reactflow__edge-2c9bc2a6-6c03-4861-aad4-db884a7682f8image-ab1387b7-6b00-4e20-acae-2ca2c1597896base_image", + "type": "default" + }, + { + "source": "227f0e19-3a4e-44f0-9f52-a8591b719bbe", + "sourceHandle": "image", + "target": "ab1387b7-6b00-4e20-acae-2ca2c1597896", + "targetHandle": "mask", + "id": "reactflow__edge-227f0e19-3a4e-44f0-9f52-a8591b719bbeimage-ab1387b7-6b00-4e20-acae-2ca2c1597896mask", + "type": "default" + } + ] +} \ No newline at end of file diff --git a/docs/workflows/Multi_ControlNet_Canny_and_Depth.json b/docs/workflows/Multi_ControlNet_Canny_and_Depth.json new file mode 100644 index 0000000000..09c9ff72ea --- /dev/null +++ b/docs/workflows/Multi_ControlNet_Canny_and_Depth.json @@ -0,0 +1,985 @@ +{ + "name": "Multi ControlNet (Canny & Depth)", + "author": "Millu", + "description": "A sample workflow using canny & depth ControlNets to guide the generation process. ", + "version": "0.1.0", + "contact": "millun@invoke.ai", + "tags": "ControlNet, canny, depth", + "notes": "", + "exposedFields": [ + { + "nodeId": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "fieldName": "model" + }, + { + "nodeId": "7ce68934-3419-42d4-ac70-82cfc9397306", + "fieldName": "prompt" + }, + { + "nodeId": "273e3f96-49ea-4dc5-9d5b-9660390f14e1", + "fieldName": "prompt" + }, + { + "nodeId": "c4b23e64-7986-40c4-9cad-46327b12e204", + "fieldName": "image" + }, + { + "nodeId": "8e860e51-5045-456e-bf04-9a62a2a5c49e", + "fieldName": "image" + } + ], + "meta": { + "version": "1.0.0" + }, + "nodes": [ + { + "id": "8e860e51-5045-456e-bf04-9a62a2a5c49e", + "type": "invocation", + "data": { + "id": "8e860e51-5045-456e-bf04-9a62a2a5c49e", + "type": "image", + "inputs": { + "image": { + "id": "189c8adf-68cc-4774-a729-49da89f6fdf1", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "Depth Input Image" + } + }, + "outputs": { + "image": { + "id": "1a31cacd-9d19-4f32-b558-c5e4aa39ce73", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "12f298fd-1d11-4cca-9426-01240f7ec7cf", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "c47dabcb-44e8-40c9-992d-81dca59f598e", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 225, + "position": { + "x": 3617.163483500202, + "y": 40.5529847930888 + } + }, + { + "id": "a33199c2-8340-401e-b8a2-42ffa875fc1c", + "type": "invocation", + "data": { + "id": "a33199c2-8340-401e-b8a2-42ffa875fc1c", + "type": "controlnet", + "inputs": { + "image": { + "id": "4e0a3172-d3c2-4005-a84c-fa12a404f8a0", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "control_model": { + "id": "8cb2d998-4086-430a-8b13-94cbc81e3ca3", + "name": "control_model", + "type": "ControlNetModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "sd-controlnet-depth", + "base_model": "sd-1" + } + }, + "control_weight": { + "id": "5e32bd8a-9dc8-42d8-9bcc-c2b0460c0b0f", + "name": "control_weight", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "begin_step_percent": { + "id": "c258a276-352a-416c-8358-152f11005c0c", + "name": "begin_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "end_step_percent": { + "id": "43001125-0d70-4f87-8e79-da6603ad6c33", + "name": "end_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "control_mode": { + "id": "d2f14561-9443-4374-9270-e2f05007944e", + "name": "control_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "balanced" + }, + "resize_mode": { + "id": "727ee7d3-8bf6-4c7d-8b8a-43546b3b59cd", + "name": "resize_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "just_resize" + } + }, + "outputs": { + "control": { + "id": "b034aa0f-4d0d-46e4-b5e3-e25a9588d087", + "name": "control", + "type": "ControlField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 508, + "position": { + "x": 4477.604342844504, + "y": -49.39005411272677 + } + }, + { + "id": "273e3f96-49ea-4dc5-9d5b-9660390f14e1", + "type": "invocation", + "data": { + "id": "273e3f96-49ea-4dc5-9d5b-9660390f14e1", + "type": "compel", + "inputs": { + "prompt": { + "id": "7c2c4771-2161-4d77-aced-ff8c4b3f1c15", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "Negative Prompt", + "value": "" + }, + "clip": { + "id": "06d59e91-9cca-411d-bf05-86b099b3e8f7", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "858bc33c-134c-4bf6-8855-f943e1d26f14", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 4444.706437017514, + "y": -924.0715320874991 + } + }, + { + "id": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "type": "invocation", + "data": { + "id": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "type": "main_model_loader", + "inputs": { + "model": { + "id": "f4a915a5-593e-4b6d-9198-c78eb5cefaed", + "name": "model", + "type": "MainModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "stable-diffusion-v1-5", + "base_model": "sd-1", + "model_type": "main" + } + } + }, + "outputs": { + "unet": { + "id": "ee24fb16-da38-4c66-9fbc-e8f296ed40d2", + "name": "unet", + "type": "UNetField", + "fieldKind": "output" + }, + "clip": { + "id": "f3fb0524-8803-41c1-86db-a61a13ee6a33", + "name": "clip", + "type": "ClipField", + "fieldKind": "output" + }, + "vae": { + "id": "5c4878a8-b40f-44ab-b146-1c1f42c860b3", + "name": "vae", + "type": "VaeField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 226, + "position": { + "x": 3837.096149678291, + "y": -1050.015351148365 + } + }, + { + "id": "7ce68934-3419-42d4-ac70-82cfc9397306", + "type": "invocation", + "data": { + "id": "7ce68934-3419-42d4-ac70-82cfc9397306", + "type": "compel", + "inputs": { + "prompt": { + "id": "7c2c4771-2161-4d77-aced-ff8c4b3f1c15", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "Positive Prompt", + "value": "" + }, + "clip": { + "id": "06d59e91-9cca-411d-bf05-86b099b3e8f7", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "858bc33c-134c-4bf6-8855-f943e1d26f14", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 4449.356038911986, + "y": -1201.659695420063 + } + }, + { + "id": "d204d184-f209-4fae-a0a1-d152800844e1", + "type": "invocation", + "data": { + "id": "d204d184-f209-4fae-a0a1-d152800844e1", + "type": "controlnet", + "inputs": { + "image": { + "id": "4e0a3172-d3c2-4005-a84c-fa12a404f8a0", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "control_model": { + "id": "8cb2d998-4086-430a-8b13-94cbc81e3ca3", + "name": "control_model", + "type": "ControlNetModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "sd-controlnet-canny", + "base_model": "sd-1" + } + }, + "control_weight": { + "id": "5e32bd8a-9dc8-42d8-9bcc-c2b0460c0b0f", + "name": "control_weight", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "begin_step_percent": { + "id": "c258a276-352a-416c-8358-152f11005c0c", + "name": "begin_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "end_step_percent": { + "id": "43001125-0d70-4f87-8e79-da6603ad6c33", + "name": "end_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "control_mode": { + "id": "d2f14561-9443-4374-9270-e2f05007944e", + "name": "control_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "balanced" + }, + "resize_mode": { + "id": "727ee7d3-8bf6-4c7d-8b8a-43546b3b59cd", + "name": "resize_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "just_resize" + } + }, + "outputs": { + "control": { + "id": "b034aa0f-4d0d-46e4-b5e3-e25a9588d087", + "name": "control", + "type": "ControlField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 508, + "position": { + "x": 4479.68542130465, + "y": -618.4221638099414 + } + }, + { + "id": "c4b23e64-7986-40c4-9cad-46327b12e204", + "type": "invocation", + "data": { + "id": "c4b23e64-7986-40c4-9cad-46327b12e204", + "type": "image", + "inputs": { + "image": { + "id": "189c8adf-68cc-4774-a729-49da89f6fdf1", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "Canny Input Image" + } + }, + "outputs": { + "image": { + "id": "1a31cacd-9d19-4f32-b558-c5e4aa39ce73", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "12f298fd-1d11-4cca-9426-01240f7ec7cf", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "c47dabcb-44e8-40c9-992d-81dca59f598e", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 225, + "position": { + "x": 3593.7474460420153, + "y": -538.1200472386865 + } + }, + { + "id": "ca4d5059-8bfb-447f-b415-da0faba5a143", + "type": "invocation", + "data": { + "id": "ca4d5059-8bfb-447f-b415-da0faba5a143", + "type": "collect", + "inputs": { + "item": { + "id": "b16ae602-8708-4b1b-8d4f-9e0808d429ab", + "name": "item", + "type": "CollectionItem", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "collection": { + "id": "d8987dd8-dec8-4d94-816a-3e356af29884", + "name": "collection", + "type": "Collection", + "fieldKind": "output" + } + }, + "label": "ControlNet Collection", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 104, + "position": { + "x": 4866.191497139488, + "y": -299.0538619537037 + } + }, + { + "id": "018b1214-c2af-43a7-9910-fb687c6726d7", + "type": "invocation", + "data": { + "id": "018b1214-c2af-43a7-9910-fb687c6726d7", + "type": "midas_depth_image_processor", + "inputs": { + "metadata": { + "id": "77f91980-c696-4a18-a9ea-6e2fc329a747", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "50710a20-2af5-424d-9d17-aa08167829c6", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "a_mult": { + "id": "f3b26f9d-2498-415e-9c01-197a8d06c0a5", + "name": "a_mult", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 2 + }, + "bg_th": { + "id": "4b1eb3ae-9d4a-47d6-b0ed-da62501e007f", + "name": "bg_th", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0.1 + } + }, + "outputs": { + "image": { + "id": "b4ed637c-c4a0-4fdd-a24e-36d6412e4ccf", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "6bf9b609-d72c-4239-99bd-390a73cc3a9c", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "3e8aef09-cf44-4e3e-a490-d3c9e7b23119", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 4054.229311491893, + "y": -31.611411056365725 + } + }, + { + "id": "c826ba5e-9676-4475-b260-07b85e88753c", + "type": "invocation", + "data": { + "id": "c826ba5e-9676-4475-b260-07b85e88753c", + "type": "canny_image_processor", + "inputs": { + "metadata": { + "id": "08331ea6-99df-4e61-a919-204d9bfa8fb2", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "image": { + "id": "33a37284-06ac-459c-ba93-1655e4f69b2d", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "low_threshold": { + "id": "21ec18a3-50c5-4ba1-9642-f921744d594f", + "name": "low_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 100 + }, + "high_threshold": { + "id": "ebeab271-a5ff-4c88-acfd-1d0271ab6ed4", + "name": "high_threshold", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 200 + } + }, + "outputs": { + "image": { + "id": "c0caadbf-883f-4cb4-a62d-626b9c81fc4e", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "df225843-8098-49c0-99d1-3b0b6600559f", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "e4abe0de-aa16-41f3-9cd7-968b49db5da3", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 339, + "position": { + "x": 4095.757337055795, + "y": -455.63440891935863 + } + }, + { + "id": "9db25398-c869-4a63-8815-c6559341ef12", + "type": "invocation", + "data": { + "id": "9db25398-c869-4a63-8815-c6559341ef12", + "type": "l2i", + "inputs": { + "metadata": { + "id": "2f269793-72e5-4ff3-b76c-fab4f93e983f", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "4aaedd3b-cc77-420c-806e-c7fa74ec4cdf", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "432b066a-2462-4d18-83d9-64620b72df45", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "61f86e0f-7c46-40f8-b3f5-fe2f693595ca", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "39b6c89a-37ef-4a7e-9509-daeca49d5092", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "6204e9b0-61dd-4250-b685-2092ba0e28e6", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "b4140649-8d5d-4d2d-bfa6-09e389ede5f9", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "f3a0c0c8-fc24-4646-8be1-ed8cdd140828", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": false, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 5678.726701377887, + "y": -351.6792416734579 + } + }, + { + "id": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "type": "invocation", + "data": { + "id": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "869cd309-c238-444b-a1a0-5021f99785ba", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "343447b4-1e37-4e9e-8ac7-4d04864066af", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "b556571e-0cf9-4e03-8cfc-5caad937d957", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "a3b3d2de-9308-423e-b00d-c209c3e6e808", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "b13c50a4-ec7e-4579-b0ef-2fe5df2605ea", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "57d5d755-f58f-4347-b991-f0bca4a0ab29", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "323e78a6-880a-4d73-a62c-70faff965aa6", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "c25fdc17-a089-43ac-953e-067c45d5c76b", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "6cde662b-e633-4569-b6b4-ec87c52c9c11", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "276a4df9-bb26-4505-a4d3-a94e18c7b541", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "48d40c51-b5e2-4457-a428-eef0696695e8", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "75dd8af2-e7d7-48b4-a574-edd9f6e686ad", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "9223d67b-1dd7-4b34-a45f-ed0a725d9702", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "4ee99177-6923-4b7f-8fe0-d721dd7cb05b", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "7fb4e326-a974-43e8-9ee7-2e3ab235819d", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "6bb8acd0-8973-4195-a095-e376385dc705", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "795dea52-1c7d-4e64-99f7-2f60ec6e3ab9", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 5274.672987098195, + "y": -823.0752416664332 + } + } + ], + "edges": [ + { + "source": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "sourceHandle": "clip", + "target": "7ce68934-3419-42d4-ac70-82cfc9397306", + "targetHandle": "clip", + "id": "reactflow__edge-54486974-835b-4d81-8f82-05f9f32ce9e9clip-7ce68934-3419-42d4-ac70-82cfc9397306clip", + "type": "default" + }, + { + "source": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "sourceHandle": "clip", + "target": "273e3f96-49ea-4dc5-9d5b-9660390f14e1", + "targetHandle": "clip", + "id": "reactflow__edge-54486974-835b-4d81-8f82-05f9f32ce9e9clip-273e3f96-49ea-4dc5-9d5b-9660390f14e1clip", + "type": "default" + }, + { + "source": "a33199c2-8340-401e-b8a2-42ffa875fc1c", + "sourceHandle": "control", + "target": "ca4d5059-8bfb-447f-b415-da0faba5a143", + "targetHandle": "item", + "id": "reactflow__edge-a33199c2-8340-401e-b8a2-42ffa875fc1ccontrol-ca4d5059-8bfb-447f-b415-da0faba5a143item", + "type": "default" + }, + { + "source": "d204d184-f209-4fae-a0a1-d152800844e1", + "sourceHandle": "control", + "target": "ca4d5059-8bfb-447f-b415-da0faba5a143", + "targetHandle": "item", + "id": "reactflow__edge-d204d184-f209-4fae-a0a1-d152800844e1control-ca4d5059-8bfb-447f-b415-da0faba5a143item", + "type": "default" + }, + { + "source": "8e860e51-5045-456e-bf04-9a62a2a5c49e", + "sourceHandle": "image", + "target": "018b1214-c2af-43a7-9910-fb687c6726d7", + "targetHandle": "image", + "id": "reactflow__edge-8e860e51-5045-456e-bf04-9a62a2a5c49eimage-018b1214-c2af-43a7-9910-fb687c6726d7image", + "type": "default" + }, + { + "source": "018b1214-c2af-43a7-9910-fb687c6726d7", + "sourceHandle": "image", + "target": "a33199c2-8340-401e-b8a2-42ffa875fc1c", + "targetHandle": "image", + "id": "reactflow__edge-018b1214-c2af-43a7-9910-fb687c6726d7image-a33199c2-8340-401e-b8a2-42ffa875fc1cimage", + "type": "default" + }, + { + "source": "c4b23e64-7986-40c4-9cad-46327b12e204", + "sourceHandle": "image", + "target": "c826ba5e-9676-4475-b260-07b85e88753c", + "targetHandle": "image", + "id": "reactflow__edge-c4b23e64-7986-40c4-9cad-46327b12e204image-c826ba5e-9676-4475-b260-07b85e88753cimage", + "type": "default" + }, + { + "source": "c826ba5e-9676-4475-b260-07b85e88753c", + "sourceHandle": "image", + "target": "d204d184-f209-4fae-a0a1-d152800844e1", + "targetHandle": "image", + "id": "reactflow__edge-c826ba5e-9676-4475-b260-07b85e88753cimage-d204d184-f209-4fae-a0a1-d152800844e1image", + "type": "default" + }, + { + "source": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "sourceHandle": "vae", + "target": "9db25398-c869-4a63-8815-c6559341ef12", + "targetHandle": "vae", + "id": "reactflow__edge-54486974-835b-4d81-8f82-05f9f32ce9e9vae-9db25398-c869-4a63-8815-c6559341ef12vae", + "type": "default" + }, + { + "source": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "sourceHandle": "latents", + "target": "9db25398-c869-4a63-8815-c6559341ef12", + "targetHandle": "latents", + "id": "reactflow__edge-ac481b7f-08bf-4a9d-9e0c-3a82ea5243celatents-9db25398-c869-4a63-8815-c6559341ef12latents", + "type": "default" + }, + { + "source": "ca4d5059-8bfb-447f-b415-da0faba5a143", + "sourceHandle": "collection", + "target": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "targetHandle": "control", + "id": "reactflow__edge-ca4d5059-8bfb-447f-b415-da0faba5a143collection-ac481b7f-08bf-4a9d-9e0c-3a82ea5243cecontrol", + "type": "default" + }, + { + "source": "54486974-835b-4d81-8f82-05f9f32ce9e9", + "sourceHandle": "unet", + "target": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "targetHandle": "unet", + "id": "reactflow__edge-54486974-835b-4d81-8f82-05f9f32ce9e9unet-ac481b7f-08bf-4a9d-9e0c-3a82ea5243ceunet", + "type": "default" + }, + { + "source": "273e3f96-49ea-4dc5-9d5b-9660390f14e1", + "sourceHandle": "conditioning", + "target": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-273e3f96-49ea-4dc5-9d5b-9660390f14e1conditioning-ac481b7f-08bf-4a9d-9e0c-3a82ea5243cenegative_conditioning", + "type": "default" + }, + { + "source": "7ce68934-3419-42d4-ac70-82cfc9397306", + "sourceHandle": "conditioning", + "target": "ac481b7f-08bf-4a9d-9e0c-3a82ea5243ce", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-7ce68934-3419-42d4-ac70-82cfc9397306conditioning-ac481b7f-08bf-4a9d-9e0c-3a82ea5243cepositive_conditioning", + "type": "default" + } + ] +} \ No newline at end of file diff --git a/docs/workflows/Prompt_from_File.json b/docs/workflows/Prompt_from_File.json new file mode 100644 index 0000000000..0a273d3b50 --- /dev/null +++ b/docs/workflows/Prompt_from_File.json @@ -0,0 +1,719 @@ +{ + "name": "Prompt from File", + "author": "InvokeAI", + "description": "Sample workflow using prompt from file capabilities of InvokeAI ", + "version": "0.1.0", + "contact": "millun@invoke.ai", + "tags": "text2image, prompt from file, default", + "notes": "", + "exposedFields": [ + { + "nodeId": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "fieldName": "model" + }, + { + "nodeId": "1b7e0df8-8589-4915-a4ea-c0088f15d642", + "fieldName": "file_path" + } + ], + "meta": { + "version": "1.0.0" + }, + "nodes": [ + { + "id": "c2eaf1ba-5708-4679-9e15-945b8b432692", + "type": "invocation", + "data": { + "id": "c2eaf1ba-5708-4679-9e15-945b8b432692", + "type": "compel", + "inputs": { + "prompt": { + "id": "dcdf3f6d-9b96-4bcd-9b8d-f992fefe4f62", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "3f1981c9-d8a9-42eb-a739-4f120eb80745", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "46205e6c-c5e2-44cb-9c82-1cd20b95674a", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 1177.3417789657444, + "y": -102.0924766641035 + } + }, + { + "id": "1b7e0df8-8589-4915-a4ea-c0088f15d642", + "type": "invocation", + "data": { + "id": "1b7e0df8-8589-4915-a4ea-c0088f15d642", + "type": "prompt_from_file", + "inputs": { + "file_path": { + "id": "37e37684-4f30-4ec8-beae-b333e550f904", + "name": "file_path", + "type": "string", + "fieldKind": "input", + "label": "Prompts File Path", + "value": "" + }, + "pre_prompt": { + "id": "7de02feb-819a-4992-bad3-72a30920ddea", + "name": "pre_prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "post_prompt": { + "id": "95f191d8-a282-428e-bd65-de8cb9b7513a", + "name": "post_prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "start_line": { + "id": "efee9a48-05ab-4829-8429-becfa64a0782", + "name": "start_line", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "max_prompts": { + "id": "abebb428-3d3d-49fd-a482-4e96a16fff08", + "name": "max_prompts", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 1 + } + }, + "outputs": { + "collection": { + "id": "77d5d7f1-9877-4ab1-9a8c-33e9ffa9abf3", + "name": "collection", + "type": "StringCollection", + "fieldKind": "output" + } + }, + "label": "Prompts from File", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 589, + "position": { + "x": 394.181884547075, + "y": -423.5345157864633 + } + }, + { + "id": "1b89067c-3f6b-42c8-991f-e3055789b251", + "type": "invocation", + "data": { + "id": "1b89067c-3f6b-42c8-991f-e3055789b251", + "type": "iterate", + "inputs": { + "collection": { + "id": "4c564bf8-5ed6-441e-ad2c-dda265d5785f", + "name": "collection", + "type": "Collection", + "fieldKind": "input", + "label": "", + "value": [] + } + }, + "outputs": { + "item": { + "id": "36340f9a-e7a5-4afa-b4b5-313f4e292380", + "name": "item", + "type": "CollectionItem", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 104, + "position": { + "x": 792.8735298060233, + "y": -432.6964953027252 + } + }, + { + "id": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "type": "invocation", + "data": { + "id": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "type": "main_model_loader", + "inputs": { + "model": { + "id": "3f264259-3418-47d5-b90d-b6600e36ae46", + "name": "model", + "type": "MainModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "stable-diffusion-v1-5", + "base_model": "sd-1", + "model_type": "main" + } + } + }, + "outputs": { + "unet": { + "id": "8e182ea2-9d0a-4c02-9407-27819288d4b5", + "name": "unet", + "type": "UNetField", + "fieldKind": "output" + }, + "clip": { + "id": "d67d9d30-058c-46d5-bded-3d09d6d1aa39", + "name": "clip", + "type": "ClipField", + "fieldKind": "output" + }, + "vae": { + "id": "89641601-0429-4448-98d5-190822d920d8", + "name": "vae", + "type": "VaeField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 226, + "position": { + "x": -47.66201354137797, + "y": -299.218193067033 + } + }, + { + "id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6", + "type": "invocation", + "data": { + "id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6", + "type": "compel", + "inputs": { + "prompt": { + "id": "dcdf3f6d-9b96-4bcd-9b8d-f992fefe4f62", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "", + "value": "" + }, + "clip": { + "id": "3f1981c9-d8a9-42eb-a739-4f120eb80745", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "46205e6c-c5e2-44cb-9c82-1cd20b95674a", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 1175.0187896425462, + "y": -420.64289413577114 + } + }, + { + "id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77", + "type": "invocation", + "data": { + "id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77", + "type": "noise", + "inputs": { + "seed": { + "id": "b722d84a-eeee-484f-bef2-0250c027cb67", + "name": "seed", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "width": { + "id": "d5f8ce11-0502-4bfc-9a30-5757dddf1f94", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "f187d5ff-38a5-4c3f-b780-fc5801ef34af", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "use_cpu": { + "id": "12f112b8-8b76-4816-b79e-662edc9f9aa5", + "name": "use_cpu", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true + } + }, + "outputs": { + "noise": { + "id": "08576ad1-96d9-42d2-96ef-6f5c1961933f", + "name": "noise", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "f3e1f94a-258d-41ff-9789-bd999bd9f40d", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "6cefc357-4339-415e-a951-49b9c2be32f4", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 389, + "position": { + "x": 809.1964864135837, + "y": 183.2735123359796 + } + }, + { + "id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5", + "type": "invocation", + "data": { + "id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5", + "type": "rand_int", + "inputs": { + "low": { + "id": "b9fc6cf1-469c-4037-9bf0-04836965826f", + "name": "low", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "high": { + "id": "06eac725-0f60-4ba2-b8cd-7ad9f757488c", + "name": "high", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 2147483647 + } + }, + "outputs": { + "value": { + "id": "df08c84e-7346-4e92-9042-9e5cb773aaff", + "name": "value", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" + }, + "width": 320, + "height": 218, + "position": { + "x": 354.19913145404166, + "y": 301.86324846905165 + } + }, + { + "id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1", + "type": "invocation", + "data": { + "id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1", + "type": "l2i", + "inputs": { + "metadata": { + "id": "022e4b33-562b-438d-b7df-41c3fd931f40", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "67cb6c77-a394-4a66-a6a9-a0a7dcca69ec", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "7b3fd9ad-a4ef-4e04-89fa-3832a9902dbd", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "5ac5680d-3add-4115-8ec0-9ef5bb87493b", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "db8297f5-55f8-452f-98cf-6572c2582152", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "d8778d0c-592a-4960-9280-4e77e00a7f33", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "c8b0a75a-f5de-4ff2-9227-f25bb2b97bec", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "83c05fbf-76b9-49ab-93c4-fa4b10e793e4", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 2037.861329274915, + "y": -329.8393457509562 + } + }, + { + "id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "type": "invocation", + "data": { + "id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "751fb35b-3f23-45ce-af1c-053e74251337", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "b9dc06b6-7481-4db1-a8c2-39d22a5eacff", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "6e15e439-3390-48a4-8031-01e0e19f0e1d", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "bfdfb3df-760b-4d51-b17b-0abb38b976c2", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "47770858-322e-41af-8494-d8b63ed735f3", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "2ba78720-ee02-4130-a348-7bc3531f790b", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "a874dffb-d433-4d1a-9f59-af4367bb05e4", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "36e021ad-b762-4fe4-ad4d-17f0291c40b2", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "98d3282d-f9f6-4b5e-b9e8-58658f1cac78", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "f2ea3216-43d5-42b4-887f-36e8f7166d53", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "d0780610-a298-47c8-a54e-70e769e0dfe2", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "fdb40970-185e-4ea8-8bb5-88f06f91f46a", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "e05b538a-1b5a-4aa5-84b1-fd2361289a81", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "463a419e-df30-4382-8ffb-b25b25abe425", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "559ee688-66cf-4139-8b82-3d3aa69995ce", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "0b4285c2-e8b9-48e5-98f6-0a49d3f98fd2", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "8b0881b9-45e5-47d5-b526-24b6661de0ee", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 1570.9941088179146, + "y": -407.6505491604564 + } + } + ], + "edges": [ + { + "source": "1b7e0df8-8589-4915-a4ea-c0088f15d642", + "sourceHandle": "collection", + "target": "1b89067c-3f6b-42c8-991f-e3055789b251", + "targetHandle": "collection", + "id": "reactflow__edge-1b7e0df8-8589-4915-a4ea-c0088f15d642collection-1b89067c-3f6b-42c8-991f-e3055789b251collection", + "type": "default" + }, + { + "source": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "sourceHandle": "clip", + "target": "fc9d0e35-a6de-4a19-84e1-c72497c823f6", + "targetHandle": "clip", + "id": "reactflow__edge-d6353b7f-b447-4e17-8f2e-80a88c91d426clip-fc9d0e35-a6de-4a19-84e1-c72497c823f6clip", + "type": "default" + }, + { + "source": "1b89067c-3f6b-42c8-991f-e3055789b251", + "sourceHandle": "item", + "target": "fc9d0e35-a6de-4a19-84e1-c72497c823f6", + "targetHandle": "prompt", + "id": "reactflow__edge-1b89067c-3f6b-42c8-991f-e3055789b251item-fc9d0e35-a6de-4a19-84e1-c72497c823f6prompt", + "type": "default" + }, + { + "source": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "sourceHandle": "clip", + "target": "c2eaf1ba-5708-4679-9e15-945b8b432692", + "targetHandle": "clip", + "id": "reactflow__edge-d6353b7f-b447-4e17-8f2e-80a88c91d426clip-c2eaf1ba-5708-4679-9e15-945b8b432692clip", + "type": "default" + }, + { + "source": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5", + "sourceHandle": "value", + "target": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77", + "targetHandle": "seed", + "id": "reactflow__edge-dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5value-0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77seed", + "type": "default" + }, + { + "source": "fc9d0e35-a6de-4a19-84e1-c72497c823f6", + "sourceHandle": "conditioning", + "target": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-fc9d0e35-a6de-4a19-84e1-c72497c823f6conditioning-2fb1577f-0a56-4f12-8711-8afcaaaf1d5epositive_conditioning", + "type": "default" + }, + { + "source": "c2eaf1ba-5708-4679-9e15-945b8b432692", + "sourceHandle": "conditioning", + "target": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-c2eaf1ba-5708-4679-9e15-945b8b432692conditioning-2fb1577f-0a56-4f12-8711-8afcaaaf1d5enegative_conditioning", + "type": "default" + }, + { + "source": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77", + "sourceHandle": "noise", + "target": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "targetHandle": "noise", + "id": "reactflow__edge-0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77noise-2fb1577f-0a56-4f12-8711-8afcaaaf1d5enoise", + "type": "default" + }, + { + "source": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "sourceHandle": "unet", + "target": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "targetHandle": "unet", + "id": "reactflow__edge-d6353b7f-b447-4e17-8f2e-80a88c91d426unet-2fb1577f-0a56-4f12-8711-8afcaaaf1d5eunet", + "type": "default" + }, + { + "source": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e", + "sourceHandle": "latents", + "target": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1", + "targetHandle": "latents", + "id": "reactflow__edge-2fb1577f-0a56-4f12-8711-8afcaaaf1d5elatents-491ec988-3c77-4c37-af8a-39a0c4e7a2a1latents", + "type": "default" + }, + { + "source": "d6353b7f-b447-4e17-8f2e-80a88c91d426", + "sourceHandle": "vae", + "target": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1", + "targetHandle": "vae", + "id": "reactflow__edge-d6353b7f-b447-4e17-8f2e-80a88c91d426vae-491ec988-3c77-4c37-af8a-39a0c4e7a2a1vae", + "type": "default" + } + ] +} \ No newline at end of file diff --git a/docs/workflows/QR_Code_Monster.json b/docs/workflows/QR_Code_Monster.json new file mode 100644 index 0000000000..f0ae5d74fd --- /dev/null +++ b/docs/workflows/QR_Code_Monster.json @@ -0,0 +1,758 @@ +{ + "name": "QR Code Monster", + "author": "InvokeAI", + "description": "Sample workflow for create images with QR code Monster ControlNet", + "version": "1.0.1", + "contact": "invoke@invoke.ai", + "tags": "qrcode, controlnet, default", + "notes": "", + "exposedFields": [ + { + "nodeId": "a6cc0986-f928-4a7e-8d44-ba2d4b36f54a", + "fieldName": "image" + }, + { + "nodeId": "aca3b054-bfba-4392-bd20-6476f59504df", + "fieldName": "prompt" + }, + { + "nodeId": "3db7cee0-31e2-4a3d-94a1-268cb16177dd", + "fieldName": "prompt" + } + ], + "meta": { + "version": "1.0.0" + }, + "nodes": [ + { + "id": "3db7cee0-31e2-4a3d-94a1-268cb16177dd", + "type": "invocation", + "data": { + "id": "3db7cee0-31e2-4a3d-94a1-268cb16177dd", + "type": "compel", + "inputs": { + "prompt": { + "id": "6a1fe244-5656-4f8c-91d1-1fb474e28807", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "Negative Prompt", + "value": "" + }, + "clip": { + "id": "f24688f3-29b8-4a2d-8603-046e5a5c7250", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "700528eb-3f8b-4745-b540-34f919b5b228", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "Prompt", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 773.0502679628016, + "y": 1622.4836086770556 + } + }, + { + "id": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "type": "invocation", + "data": { + "id": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "type": "main_model_loader", + "inputs": { + "model": { + "id": "cb36b6d3-6c1f-4911-a200-646745b0ff74", + "name": "model", + "type": "MainModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "stable-diffusion-v1-5", + "base_model": "sd-1", + "model_type": "main" + } + } + }, + "outputs": { + "unet": { + "id": "7246895b-b252-49bc-b952-8d801b4672f7", + "name": "unet", + "type": "UNetField", + "fieldKind": "output" + }, + "clip": { + "id": "3c2aedb8-30d5-4d4b-99df-d06a0d7bedc6", + "name": "clip", + "type": "ClipField", + "fieldKind": "output" + }, + "vae": { + "id": "b9743815-5501-4bbb-8bde-8bd6ba298a4e", + "name": "vae", + "type": "VaeField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 226, + "position": { + "x": 211.58866462619744, + "y": 1376.0542388105248 + } + }, + { + "id": "aca3b054-bfba-4392-bd20-6476f59504df", + "type": "invocation", + "data": { + "id": "aca3b054-bfba-4392-bd20-6476f59504df", + "type": "compel", + "inputs": { + "prompt": { + "id": "6a1fe244-5656-4f8c-91d1-1fb474e28807", + "name": "prompt", + "type": "string", + "fieldKind": "input", + "label": "Positive Prompt", + "value": "" + }, + "clip": { + "id": "f24688f3-29b8-4a2d-8603-046e5a5c7250", + "name": "clip", + "type": "ClipField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "conditioning": { + "id": "700528eb-3f8b-4745-b540-34f919b5b228", + "name": "conditioning", + "type": "ConditioningField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 261, + "position": { + "x": 770.6491131680111, + "y": 1316.379247112241 + } + }, + { + "id": "a6cc0986-f928-4a7e-8d44-ba2d4b36f54a", + "type": "invocation", + "data": { + "id": "a6cc0986-f928-4a7e-8d44-ba2d4b36f54a", + "type": "image", + "inputs": { + "image": { + "id": "89ba5d58-28c9-4e04-a5df-79fb7a6f3531", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "QR Code / Hidden Image" + } + }, + "outputs": { + "image": { + "id": "54335653-0e17-42da-b9e8-83c5fb5af670", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "a3c65953-39ea-4d97-8858-d65154ff9d11", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "2c7db511-ebc9-4286-a46b-bc11e0fd779f", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 225, + "position": { + "x": 700.5034176864369, + "y": 1981.749600549388 + } + }, + { + "id": "280fd8a7-3b0c-49fe-8be4-6246e08b6c9a", + "type": "invocation", + "data": { + "id": "280fd8a7-3b0c-49fe-8be4-6246e08b6c9a", + "type": "noise", + "inputs": { + "seed": { + "id": "7c6c76dd-127b-4829-b1ec-430790cb7ed7", + "name": "seed", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "width": { + "id": "8ec6a525-a421-40d8-a17e-39e7b6836438", + "name": "width", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "height": { + "id": "6af1e58a-e2ee-4ec4-9f06-d8d0412922ca", + "name": "height", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 512 + }, + "use_cpu": { + "id": "26662e99-5720-43a6-a5d8-06c9dab0e261", + "name": "use_cpu", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": true + } + }, + "outputs": { + "noise": { + "id": "cb4c4dfc-a744-49eb-af4f-677448e28407", + "name": "noise", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "97e87be6-e81f-40a3-a522-28ebe4aad0ac", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "80784420-f1e1-47b0-bd1d-1d381a15e22d", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": false, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 32, + "position": { + "x": 1182.460291960481, + "y": 1759.592972960265 + } + }, + { + "id": "2ac03cf6-0326-454a-bed0-d8baef2bf30d", + "type": "invocation", + "data": { + "id": "2ac03cf6-0326-454a-bed0-d8baef2bf30d", + "type": "controlnet", + "inputs": { + "image": { + "id": "1f683889-9f14-40c8-af29-4b991b211a3a", + "name": "image", + "type": "ImageField", + "fieldKind": "input", + "label": "" + }, + "control_model": { + "id": "a933b21d-22c1-4e06-818f-15416b971282", + "name": "control_model", + "type": "ControlNetModelField", + "fieldKind": "input", + "label": "", + "value": { + "model_name": "qrcode_monster", + "base_model": "sd-1" + } + }, + "control_weight": { + "id": "198a0825-e55e-4496-bc54-c3d7b02f3d75", + "name": "control_weight", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 1.4 + }, + "begin_step_percent": { + "id": "c85ce42f-22af-42a0-8993-676002fb275e", + "name": "begin_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "end_step_percent": { + "id": "a61a65c4-9e6f-4fe2-96a5-1294d17ec6e4", + "name": "end_step_percent", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "control_mode": { + "id": "1aa45cfa-0249-46b7-bf24-3e38e92f5fa0", + "name": "control_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "balanced" + }, + "resize_mode": { + "id": "a89d3cb9-a141-4cea-bb49-977bf267377b", + "name": "resize_mode", + "type": "enum", + "fieldKind": "input", + "label": "", + "value": "just_resize" + } + }, + "outputs": { + "control": { + "id": "c9a1fc7e-cb25-45a9-adff-1a97c9ff04d6", + "name": "control", + "type": "ControlField", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 508, + "position": { + "x": 1165.434407461108, + "y": 1862.916856351665 + } + }, + { + "id": "28542b66-5a00-4780-a318-0a036d2df914", + "type": "invocation", + "data": { + "id": "28542b66-5a00-4780-a318-0a036d2df914", + "type": "l2i", + "inputs": { + "metadata": { + "id": "a38e8f55-7f2c-4fcc-a71f-d51e2eb0374a", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "80e97bc8-e716-4175-9115-5b58495aa30c", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "5641bce6-ac2b-47eb-bb32-2f290026b7e1", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "9e75eb16-ae48-47ed-b180-e0409d377436", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "0518b0ce-ee37-437b-8437-cc2976a3279f", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "ec2ff985-a7eb-401f-92c4-1217cddad6a2", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "ba1d1720-6d67-4eca-9e9d-b97d08636774", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "10bcf8f4-6394-422f-b0c0-51680f3bfb25", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 2110.8415693683014, + "y": 1487.253341116115 + } + }, + { + "id": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "type": "invocation", + "data": { + "id": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "8e6aceaa-a986-4ab2-9c04-5b1027b3daf6", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "fbbaa712-ca1a-420b-9016-763f2a29d68c", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "a3b3d5d2-c0f9-4b89-a9b3-8de9418f7bb5", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "e491e664-2f8c-4f49-b3e4-57b051fbb9c5", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "f0318abd-ed65-4cad-86a7-48d1c19a6d14", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "f7c24c51-496f-44c4-836a-c734e529fec0", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "54f7656a-fb0d-4d9e-a459-f700f7dccd2e", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "363ee440-040d-499b-bf84-bf5391b08681", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "5c93d4e5-1064-4700-ab1d-d12e1e9b5ba7", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "e1948eb3-7407-43b0-93e3-139470f186b7", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "5675b2c3-adfb-49ee-b33c-26bdbfab1fed", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "89cd4ab3-3bfc-4063-9de5-91d42305c651", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "ec01df90-5042-418d-b6d6-86b251c13770", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "561cde00-cb20-42ae-9bd3-4f477f73fbe1", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "f9addefe-efcc-4e01-8945-6ebbc934b002", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "6d48f78b-d681-422a-8677-0111bd0625f1", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "f25997b8-6316-44ce-b696-b82e4ed51ae5", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 1597.9598293300219, + "y": 1420.4637727891632 + } + }, + { + "id": "59349822-af20-4e0e-a53f-3ba135d00c3f", + "type": "invocation", + "data": { + "id": "59349822-af20-4e0e-a53f-3ba135d00c3f", + "type": "rand_int", + "inputs": { + "low": { + "id": "051f22f9-2d4f-414f-bc51-84af2d626efa", + "name": "low", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "high": { + "id": "77206186-f264-4224-9589-f925cf903dc9", + "name": "high", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 2147483647 + } + }, + "outputs": { + "value": { + "id": "a7ed9387-3a24-4d34-b7c5-f713bd544ab1", + "name": "value", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": false, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" + }, + "width": 320, + "height": 32, + "position": { + "x": 1178.16746986153, + "y": 1663.9433412808876 + } + } + ], + "edges": [ + { + "source": "59349822-af20-4e0e-a53f-3ba135d00c3f", + "target": "280fd8a7-3b0c-49fe-8be4-6246e08b6c9a", + "id": "59349822-af20-4e0e-a53f-3ba135d00c3f-280fd8a7-3b0c-49fe-8be4-6246e08b6c9a-collapsed", + "type": "collapsed" + }, + { + "source": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "sourceHandle": "clip", + "target": "aca3b054-bfba-4392-bd20-6476f59504df", + "targetHandle": "clip", + "id": "reactflow__edge-610384f1-6f0c-4847-a9a2-37ce7f456ed1clip-aca3b054-bfba-4392-bd20-6476f59504dfclip", + "type": "default" + }, + { + "source": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "sourceHandle": "clip", + "target": "3db7cee0-31e2-4a3d-94a1-268cb16177dd", + "targetHandle": "clip", + "id": "reactflow__edge-610384f1-6f0c-4847-a9a2-37ce7f456ed1clip-3db7cee0-31e2-4a3d-94a1-268cb16177ddclip", + "type": "default" + }, + { + "source": "a6cc0986-f928-4a7e-8d44-ba2d4b36f54a", + "sourceHandle": "image", + "target": "2ac03cf6-0326-454a-bed0-d8baef2bf30d", + "targetHandle": "image", + "id": "reactflow__edge-a6cc0986-f928-4a7e-8d44-ba2d4b36f54aimage-2ac03cf6-0326-454a-bed0-d8baef2bf30dimage", + "type": "default" + }, + { + "source": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "sourceHandle": "vae", + "target": "28542b66-5a00-4780-a318-0a036d2df914", + "targetHandle": "vae", + "id": "reactflow__edge-610384f1-6f0c-4847-a9a2-37ce7f456ed1vae-28542b66-5a00-4780-a318-0a036d2df914vae", + "type": "default" + }, + { + "source": "280fd8a7-3b0c-49fe-8be4-6246e08b6c9a", + "sourceHandle": "noise", + "target": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "targetHandle": "noise", + "id": "reactflow__edge-280fd8a7-3b0c-49fe-8be4-6246e08b6c9anoise-9755ae4c-ef30-4db3-80f6-a31f98979a11noise", + "type": "default" + }, + { + "source": "3db7cee0-31e2-4a3d-94a1-268cb16177dd", + "sourceHandle": "conditioning", + "target": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-3db7cee0-31e2-4a3d-94a1-268cb16177ddconditioning-9755ae4c-ef30-4db3-80f6-a31f98979a11negative_conditioning", + "type": "default" + }, + { + "source": "aca3b054-bfba-4392-bd20-6476f59504df", + "sourceHandle": "conditioning", + "target": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-aca3b054-bfba-4392-bd20-6476f59504dfconditioning-9755ae4c-ef30-4db3-80f6-a31f98979a11positive_conditioning", + "type": "default" + }, + { + "source": "610384f1-6f0c-4847-a9a2-37ce7f456ed1", + "sourceHandle": "unet", + "target": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "targetHandle": "unet", + "id": "reactflow__edge-610384f1-6f0c-4847-a9a2-37ce7f456ed1unet-9755ae4c-ef30-4db3-80f6-a31f98979a11unet", + "type": "default" + }, + { + "source": "2ac03cf6-0326-454a-bed0-d8baef2bf30d", + "sourceHandle": "control", + "target": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "targetHandle": "control", + "id": "reactflow__edge-2ac03cf6-0326-454a-bed0-d8baef2bf30dcontrol-9755ae4c-ef30-4db3-80f6-a31f98979a11control", + "type": "default" + }, + { + "source": "9755ae4c-ef30-4db3-80f6-a31f98979a11", + "sourceHandle": "latents", + "target": "28542b66-5a00-4780-a318-0a036d2df914", + "targetHandle": "latents", + "id": "reactflow__edge-9755ae4c-ef30-4db3-80f6-a31f98979a11latents-28542b66-5a00-4780-a318-0a036d2df914latents", + "type": "default" + }, + { + "source": "59349822-af20-4e0e-a53f-3ba135d00c3f", + "sourceHandle": "value", + "target": "280fd8a7-3b0c-49fe-8be4-6246e08b6c9a", + "targetHandle": "seed", + "id": "reactflow__edge-59349822-af20-4e0e-a53f-3ba135d00c3fvalue-280fd8a7-3b0c-49fe-8be4-6246e08b6c9aseed", + "type": "default" + } + ] +} \ No newline at end of file diff --git a/docs/workflows/SDXL_Text_to_Image.json b/docs/workflows/SDXL_Text_to_Image.json index 57f95293eb..af11731703 100644 --- a/docs/workflows/SDXL_Text_to_Image.json +++ b/docs/workflows/SDXL_Text_to_Image.json @@ -26,10 +26,6 @@ { "nodeId": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", "fieldName": "style" - }, - { - "nodeId": "87ee6243-fb0d-4f77-ad5f-56591659339e", - "fieldName": "steps" } ], "meta": { @@ -40,7 +36,6 @@ "id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", "type": "invocation", "data": { - "version": "1.0.0", "id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", "type": "sdxl_compel_prompt", "inputs": { @@ -135,10 +130,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 764, + "height": 793, "position": { "x": 1275, "y": -350 @@ -148,7 +145,6 @@ "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "invocation", "data": { - "version": "1.0.0", "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "noise", "inputs": { @@ -209,7 +205,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -218,83 +216,10 @@ "y": -300 } }, - { - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "invocation", - "data": { - "version": "1.0.0", - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "l2i", - "inputs": { - "tiled": { - "id": "24f5bc7b-f6a1-425d-8ab1-f50b4db5d0df", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "b146d873-ffb9-4767-986a-5360504841a2", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": true - }, - "latents": { - "id": "65441abd-7713-4b00-9d8d-3771404002e8", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "a478b833-6e13-4611-9a10-842c89603c74", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "c87ae925-f858-417a-8940-8708ba9b4b53", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "4bcb8512-b5a1-45f1-9e52-6e92849f9d6c", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "23e41c00-a354-48e8-8f59-5875679c27ab", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false - }, - "width": 320, - "height": 224, - "position": { - "x": 2025, - "y": -250 - } - }, { "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "invocation", "data": { - "version": "1.0.0", "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "rand_int", "inputs": { @@ -327,7 +252,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -340,7 +267,6 @@ "id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "type": "invocation", "data": { - "version": "1.0.0", "id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "type": "sdxl_model_loader", "inputs": { @@ -351,7 +277,7 @@ "fieldKind": "input", "label": "", "value": { - "model_name": "stable-diffusion-xl-base-1.0", + "model_name": "stable-diffusion-xl-base-1-0", "base_model": "sdxl", "model_type": "main" } @@ -387,10 +313,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 234, + "height": 258, "position": { "x": 475, "y": 25 @@ -400,7 +328,6 @@ "id": "faf965a4-7530-427b-b1f3-4ba6505c2a08", "type": "invocation", "data": { - "version": "1.0.0", "id": "faf965a4-7530-427b-b1f3-4ba6505c2a08", "type": "sdxl_compel_prompt", "inputs": { @@ -495,128 +422,77 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 764, + "height": 793, "position": { "x": 900, "y": -350 } }, { - "id": "87ee6243-fb0d-4f77-ad5f-56591659339e", + "id": "63e91020-83b2-4f35-b174-ad9692aabb48", "type": "invocation", "data": { - "version": "1.0.0", - "id": "87ee6243-fb0d-4f77-ad5f-56591659339e", - "type": "denoise_latents", + "id": "63e91020-83b2-4f35-b174-ad9692aabb48", + "type": "l2i", "inputs": { - "noise": { - "id": "4884a4b7-cc19-4fea-83c7-1f940e6edd24", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "4c61675c-b6b9-41ac-b187-b5c13b587039", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 36 - }, - "cfg_scale": { - "id": "f8213f35-4637-4a1a-83f4-1f8cfb9ccd2c", - "name": "cfg_scale", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 7.5 - }, - "denoising_start": { - "id": "01e2f30d-0acd-4e21-98b9-a9b8e24c6db2", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "denoising_end": { - "id": "3db95479-a73b-4c75-9b44-08daec16b224", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 1 - }, - "scheduler": { - "id": "db8430a9-64c3-4c54-ae38-9f597cf7b6d5", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler" - }, - "control": { - "id": "599b49e8-6435-4576-be41-a5155f3a17e3", - "name": "control", - "type": "ControlField", + "metadata": { + "id": "88971324-3fdb-442d-b8b7-7612478a8622", + "name": "metadata", + "type": "MetadataField", "fieldKind": "input", "label": "" }, "latents": { - "id": "226f9e91-454e-4159-9fa6-019c0cf29277", + "id": "da0e40cb-c49f-4fa5-9856-338b91a65f6b", "name": "latents", "type": "LatentsField", "fieldKind": "input", "label": "" }, - "denoise_mask": { - "id": "de019cb6-7fb5-45bf-a266-22e20889893f", - "name": "denoise_mask", - "type": "DenoiseMaskField", + "vae": { + "id": "ae5164ce-1710-4ec5-a83a-6113a0d1b5c0", + "name": "vae", + "type": "VaeField", "fieldKind": "input", "label": "" }, - "positive_conditioning": { - "id": "02fc400a-110d-470e-8411-f404f966a949", - "name": "positive_conditioning", - "type": "ConditioningField", + "tiled": { + "id": "2ccfd535-1a7b-4ecf-84db-9430a64fb3d7", + "name": "tiled", + "type": "boolean", "fieldKind": "input", - "label": "" + "label": "", + "value": false }, - "negative_conditioning": { - "id": "4bd3bdfa-fcf4-42be-8e47-1e314255798f", - "name": "negative_conditioning", - "type": "ConditioningField", + "fp32": { + "id": "64f07d5a-54a2-429c-8c5b-0c2a3a8e5cd5", + "name": "fp32", + "type": "boolean", "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "7c2d58a8-b5f1-4e63-8ffd-8ada52c35832", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" + "label": "", + "value": false } }, "outputs": { - "latents": { - "id": "6a6fa492-de26-4e95-b1d9-a322fe37eb13", - "name": "latents", - "type": "LatentsField", + "image": { + "id": "9b281eaa-6504-407d-a5ca-1e5e8020a4bf", + "name": "image", + "type": "ImageField", "fieldKind": "output" }, "width": { - "id": "a9790729-7d6c-4418-903d-4da961fccf56", + "id": "98e545f3-b53b-490d-b94d-bed9418ccc75", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "fa74efe5-7330-4a3c-b256-c82a544585b4", + "id": "4a74bd43-d7f7-4c7f-bb3b-d09bb2992c46", "name": "height", "type": "integer", "fieldKind": "output" @@ -626,13 +502,161 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": false, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 558, + "height": 267, "position": { - "x": 1650, - "y": -250 + "x": 2112.5626808057173, + "y": -174.24042139280238 + } + }, + { + "id": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", + "type": "invocation", + "data": { + "id": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "29b73dfa-a06e-4b4a-a844-515b9eb93a81", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "a81e6f5b-f4de-4919-b483-b6e2f067465a", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "4ba06bb7-eb45-4fb9-9984-31001b545587", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "36ee8a45-ca69-44bc-9bc3-aa881e6045c0", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "2a2024e0-a736-46ec-933c-c1c1ebe96943", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "be219d5e-41b7-430a-8fb5-bc21a31ad219", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "3adfb7ae-c9f7-4a40-b6e0-4c2050bd1a99", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "14423e0d-7215-4ee0-b065-f9e95eaa8d7d", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "e73bbf98-6489-492b-b83c-faed215febac", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "dab351b3-0c86-4ea5-9782-4e8edbfb0607", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "192daea0-a90a-43cc-a2ee-0114a8e90318", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "ee386a55-d4c7-48c1-ac57-7bc4e3aada7a", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "3a922c6a-3d8c-4c9e-b3ec-2f4d81cda077", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "cd7ce032-835f-495f-8b45-d57272f33132", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "6260b84f-8361-470a-98d8-5b22a45c2d8c", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "aede0ecf-25b6-46be-aa30-b77f79715deb", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "519abf62-d475-48ef-ab8f-66136bc0e499", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 1642.955772577545, + "y": -230.2485847594651 } } ], @@ -686,50 +710,42 @@ { "source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "sourceHandle": "vae", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", + "target": "63e91020-83b2-4f35-b174-ad9692aabb48", "targetHandle": "vae", - "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22vae-dbcd2f98-d809-48c8-bf64-2635f88a2fe9vae", - "type": "default" - }, - { - "source": "87ee6243-fb0d-4f77-ad5f-56591659339e", - "sourceHandle": "latents", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "targetHandle": "latents", - "id": "reactflow__edge-87ee6243-fb0d-4f77-ad5f-56591659339elatents-dbcd2f98-d809-48c8-bf64-2635f88a2fe9latents", - "type": "default" - }, - { - "source": "faf965a4-7530-427b-b1f3-4ba6505c2a08", - "sourceHandle": "conditioning", - "target": "87ee6243-fb0d-4f77-ad5f-56591659339e", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-faf965a4-7530-427b-b1f3-4ba6505c2a08conditioning-87ee6243-fb0d-4f77-ad5f-56591659339epositive_conditioning", - "type": "default" - }, - { - "source": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", - "sourceHandle": "conditioning", - "target": "87ee6243-fb0d-4f77-ad5f-56591659339e", - "targetHandle": "negative_conditioning", - "id": "reactflow__edge-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204conditioning-87ee6243-fb0d-4f77-ad5f-56591659339enegative_conditioning", + "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22vae-63e91020-83b2-4f35-b174-ad9692aabb48vae", "type": "default" }, { "source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "sourceHandle": "unet", - "target": "87ee6243-fb0d-4f77-ad5f-56591659339e", + "target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", "targetHandle": "unet", - "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22unet-87ee6243-fb0d-4f77-ad5f-56591659339eunet", + "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22unet-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbunet", + "type": "default" + }, + { + "source": "faf965a4-7530-427b-b1f3-4ba6505c2a08", + "sourceHandle": "conditioning", + "target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-faf965a4-7530-427b-b1f3-4ba6505c2a08conditioning-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbpositive_conditioning", + "type": "default" + }, + { + "source": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", + "sourceHandle": "conditioning", + "target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204conditioning-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbnegative_conditioning", "type": "default" }, { "source": "55705012-79b9-4aac-9f26-c0b10309785b", "sourceHandle": "noise", - "target": "87ee6243-fb0d-4f77-ad5f-56591659339e", + "target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb", "targetHandle": "noise", - "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-87ee6243-fb0d-4f77-ad5f-56591659339enoise", + "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbnoise", "type": "default" } ] -} +} \ No newline at end of file diff --git a/docs/workflows/SDXL_w_Refiner_Text_to_Image.json b/docs/workflows/SDXL_w_Refiner_Text_to_Image.json index 22ffb8262d..f70d974702 100644 --- a/docs/workflows/SDXL_w_Refiner_Text_to_Image.json +++ b/docs/workflows/SDXL_w_Refiner_Text_to_Image.json @@ -11,10 +11,6 @@ "nodeId": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "fieldName": "model" }, - { - "nodeId": "65b56526-ef0a-4c1f-adda-1017c925b063", - "fieldName": "steps" - }, { "nodeId": "06a30867-1e9d-461f-bd58-14a63cc997dd", "fieldName": "scheduler" @@ -23,10 +19,6 @@ "nodeId": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", "fieldName": "model" }, - { - "nodeId": "a9352523-613a-43e3-b97f-dade7ec317e5", - "fieldName": "steps" - }, { "nodeId": "b2b35add-929d-4538-aecb-02c661768b29", "fieldName": "value" @@ -48,142 +40,10 @@ "version": "1.0.0" }, "nodes": [ - { - "id": "a9352523-613a-43e3-b97f-dade7ec317e5", - "type": "invocation", - "data": { - "version": "1.0.0", - "id": "a9352523-613a-43e3-b97f-dade7ec317e5", - "type": "denoise_latents", - "inputs": { - "noise": { - "id": "962fb1ba-341c-441c-940b-1543caafab29", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "2b76247b-cc60-4ef0-8a51-290700590805", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "Refiner Steps", - "value": 36 - }, - "cfg_scale": { - "id": "f13c5cf5-6198-4183-9b47-0a44c5666a2a", - "name": "cfg_scale", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 7.5 - }, - "denoising_start": { - "id": "397bb49d-7d00-465b-a918-456910d7fedb", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.8 - }, - "denoising_end": { - "id": "dac6aa2a-d074-4e86-af0c-def573dd69ac", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 1 - }, - "scheduler": { - "id": "34f9f11c-f2fc-48b2-b015-ededbf2d000f", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler" - }, - "control": { - "id": "80c69321-e712-453b-b8a8-b4e03d37844c", - "name": "control", - "type": "ControlField", - "fieldKind": "input", - "label": "" - }, - "latents": { - "id": "8122d26c-ad2f-4f65-93d5-9ebb426bdba4", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "denoise_mask": { - "id": "5dc048d6-28c3-4db4-9e8b-652006616c17", - "name": "denoise_mask", - "type": "DenoiseMaskField", - "fieldKind": "input", - "label": "" - }, - "positive_conditioning": { - "id": "dd5cab6f-6dbd-4791-a21a-ef0544f26f8f", - "name": "positive_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "negative_conditioning": { - "id": "5efedcb9-3286-426a-ad57-f77b2d7d1898", - "name": "negative_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "3ebc07f0-4cd7-4f4d-a5b3-a8ce13383305", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "latents": { - "id": "ca9c565a-1dda-428c-9fdf-7c51eb7fa9c5", - "name": "latents", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "d91b7cbd-fe5c-4c92-923e-241d1a63648c", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "af9ee999-a666-42a8-8e5c-d04518c4aa8e", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 558, - "position": { - "x": 1650, - "y": -150 - } - }, { "id": "b2b35add-929d-4538-aecb-02c661768b29", "type": "invocation", "data": { - "version": "1.0.0", "id": "b2b35add-929d-4538-aecb-02c661768b29", "type": "string", "inputs": { @@ -208,7 +68,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -221,7 +83,6 @@ "id": "8d54b9db-3662-43af-8369-9a277e063f3b", "type": "invocation", "data": { - "version": "1.0.0", "id": "8d54b9db-3662-43af-8369-9a277e063f3b", "type": "string", "inputs": { @@ -246,7 +107,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -259,7 +122,6 @@ "id": "f1a6a160-4c36-4902-8eeb-8b1c23e81bc8", "type": "invocation", "data": { - "version": "1.0.0", "id": "f1a6a160-4c36-4902-8eeb-8b1c23e81bc8", "type": "string", "inputs": { @@ -284,7 +146,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -297,7 +161,6 @@ "id": "fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1", "type": "invocation", "data": { - "version": "1.0.0", "id": "fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1", "type": "sdxl_refiner_compel_prompt", "inputs": { @@ -369,10 +232,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 520, + "height": 547, "position": { "x": 1625, "y": -925 @@ -382,7 +247,6 @@ "id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", "type": "invocation", "data": { - "version": "1.0.0", "id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", "type": "sdxl_compel_prompt", "inputs": { @@ -477,10 +341,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 764, + "height": 793, "position": { "x": 900, "y": -925 @@ -490,7 +356,6 @@ "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "invocation", "data": { - "version": "1.0.0", "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "noise", "inputs": { @@ -551,7 +416,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -560,83 +427,10 @@ "y": -200 } }, - { - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "invocation", - "data": { - "version": "1.0.0", - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "l2i", - "inputs": { - "tiled": { - "id": "24f5bc7b-f6a1-425d-8ab1-f50b4db5d0df", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "b146d873-ffb9-4767-986a-5360504841a2", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": true - }, - "latents": { - "id": "65441abd-7713-4b00-9d8d-3771404002e8", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "a478b833-6e13-4611-9a10-842c89603c74", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "c87ae925-f858-417a-8940-8708ba9b4b53", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "4bcb8512-b5a1-45f1-9e52-6e92849f9d6c", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "23e41c00-a354-48e8-8f59-5875679c27ab", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false - }, - "width": 320, - "height": 266, - "position": { - "x": 2075, - "y": -400 - } - }, { "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "invocation", "data": { - "version": "1.0.0", "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "rand_int", "inputs": { @@ -669,7 +463,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -682,7 +478,6 @@ "id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "type": "invocation", "data": { - "version": "1.0.0", "id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", "type": "sdxl_model_loader", "inputs": { @@ -729,7 +524,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -742,7 +539,6 @@ "id": "faf965a4-7530-427b-b1f3-4ba6505c2a08", "type": "invocation", "data": { - "version": "1.0.0", "id": "faf965a4-7530-427b-b1f3-4ba6505c2a08", "type": "sdxl_compel_prompt", "inputs": { @@ -837,10 +633,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 764, + "height": 793, "position": { "x": 550, "y": -925 @@ -850,7 +648,6 @@ "id": "f0e06b70-9f53-44e3-8f5f-63d813b6b579", "type": "invocation", "data": { - "version": "1.0.0", "id": "f0e06b70-9f53-44e3-8f5f-63d813b6b579", "type": "sdxl_refiner_compel_prompt", "inputs": { @@ -922,10 +719,12 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 520, + "height": 547, "position": { "x": 1275, "y": -925 @@ -935,7 +734,6 @@ "id": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", "type": "invocation", "data": { - "version": "1.0.0", "id": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", "type": "sdxl_refiner_model_loader", "inputs": { @@ -976,7 +774,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -989,7 +789,6 @@ "id": "5639e3bc-b769-4ae5-9262-72db703c5a7b", "type": "invocation", "data": { - "version": "1.0.0", "id": "5639e3bc-b769-4ae5-9262-72db703c5a7b", "type": "string", "inputs": { @@ -1014,7 +813,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -1023,142 +824,10 @@ "y": 25 } }, - { - "id": "65b56526-ef0a-4c1f-adda-1017c925b063", - "type": "invocation", - "data": { - "version": "1.0.0", - "id": "65b56526-ef0a-4c1f-adda-1017c925b063", - "type": "denoise_latents", - "inputs": { - "noise": { - "id": "962fb1ba-341c-441c-940b-1543caafab29", - "name": "noise", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "steps": { - "id": "2b76247b-cc60-4ef0-8a51-290700590805", - "name": "steps", - "type": "integer", - "fieldKind": "input", - "label": "", - "value": 36 - }, - "cfg_scale": { - "id": "f13c5cf5-6198-4183-9b47-0a44c5666a2a", - "name": "cfg_scale", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 7.5 - }, - "denoising_start": { - "id": "397bb49d-7d00-465b-a918-456910d7fedb", - "name": "denoising_start", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0 - }, - "denoising_end": { - "id": "dac6aa2a-d074-4e86-af0c-def573dd69ac", - "name": "denoising_end", - "type": "float", - "fieldKind": "input", - "label": "", - "value": 0.8 - }, - "scheduler": { - "id": "34f9f11c-f2fc-48b2-b015-ededbf2d000f", - "name": "scheduler", - "type": "Scheduler", - "fieldKind": "input", - "label": "", - "value": "euler" - }, - "control": { - "id": "80c69321-e712-453b-b8a8-b4e03d37844c", - "name": "control", - "type": "ControlField", - "fieldKind": "input", - "label": "" - }, - "latents": { - "id": "8122d26c-ad2f-4f65-93d5-9ebb426bdba4", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "denoise_mask": { - "id": "5dc048d6-28c3-4db4-9e8b-652006616c17", - "name": "denoise_mask", - "type": "DenoiseMaskField", - "fieldKind": "input", - "label": "" - }, - "positive_conditioning": { - "id": "dd5cab6f-6dbd-4791-a21a-ef0544f26f8f", - "name": "positive_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "negative_conditioning": { - "id": "5efedcb9-3286-426a-ad57-f77b2d7d1898", - "name": "negative_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "3ebc07f0-4cd7-4f4d-a5b3-a8ce13383305", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "latents": { - "id": "ca9c565a-1dda-428c-9fdf-7c51eb7fa9c5", - "name": "latents", - "type": "LatentsField", - "fieldKind": "output" - }, - "width": { - "id": "d91b7cbd-fe5c-4c92-923e-241d1a63648c", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "af9ee999-a666-42a8-8e5c-d04518c4aa8e", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": false, - "isIntermediate": true - }, - "width": 320, - "height": 558, - "position": { - "x": 1275, - "y": -150 - } - }, { "id": "06a30867-1e9d-461f-bd58-14a63cc997dd", "type": "invocation", "data": { - "version": "1.0.0", "id": "06a30867-1e9d-461f-bd58-14a63cc997dd", "type": "scheduler", "inputs": { @@ -1183,7 +852,9 @@ "isOpen": false, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, "height": 32, @@ -1191,6 +862,378 @@ "x": 700, "y": 125 } + }, + { + "id": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "type": "invocation", + "data": { + "id": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "73b2ebc2-4a56-4809-b8ab-b78fde786961", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "04d1bfbb-6cdc-4c16-8e08-290ba86ca8ba", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "39ea4659-ea69-415f-85c0-a06f94d53e14", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "dfd3c295-adae-499a-8c94-3c6c6d9ece0e", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "2ae0c196-8c94-4ea8-a9fc-1be06938a0c3", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "3d085ec1-14de-4eef-9853-2edf5d81daac", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "1a820924-15ca-4ba5-b981-6b588e486a5b", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "d0d19fab-5001-4c5d-b664-031df1a65311", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "efbdecd1-5c07-420c-bd58-52de43fcde4c", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "e1a457c4-5546-4c02-83e1-092776b27cd1", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "d4082d78-7f17-4f87-af05-5a76129737ba", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "4841595c-f81b-440a-9377-fe89b26b42ac", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "60bbfc7e-6641-4354-b678-12029c580aa9", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "b2876171-e4c5-45cf-a352-852047c902fc", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "62705a29-cc3a-4154-8f62-a8f821daf861", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "eb2e2312-1e64-4008-a64f-6783d49dde29", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "7bd8d012-edcf-4def-98eb-7ebdd724c7c5", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 1269.2683722842958, + "y": -119.4839111990423 + } + }, + { + "id": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "type": "invocation", + "data": { + "id": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "type": "denoise_latents", + "inputs": { + "positive_conditioning": { + "id": "a9c932a9-6164-4333-bade-3909c9a3ce59", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "a57fced5-aca6-40c9-8197-ce4f01433111", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "noise": { + "id": "b4cbec14-c24e-4ec2-bda3-8fc19c089717", + "name": "noise", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "steps": { + "id": "24dd36f7-fdf1-40c9-945c-216471b44a2f", + "name": "steps", + "type": "integer", + "fieldKind": "input", + "label": "", + "value": 10 + }, + "cfg_scale": { + "id": "5f3a7f0c-5088-49e9-b490-75822d0c20cc", + "name": "cfg_scale", + "type": "FloatPolymorphic", + "fieldKind": "input", + "label": "", + "value": 7.5 + }, + "denoising_start": { + "id": "b326ffde-625c-49c5-b5e1-90b79df80979", + "name": "denoising_start", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 0 + }, + "denoising_end": { + "id": "d4a458ef-5576-4c5d-8e6d-ee04c9c7c4dc", + "name": "denoising_end", + "type": "float", + "fieldKind": "input", + "label": "", + "value": 1 + }, + "scheduler": { + "id": "95aba2d0-c470-44f2-a25c-a192600be6da", + "name": "scheduler", + "type": "Scheduler", + "fieldKind": "input", + "label": "", + "value": "euler" + }, + "unet": { + "id": "68a8636e-3b2f-4a95-bd05-d86a01edb74a", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, + "control": { + "id": "508e68a6-1cfc-4121-baed-b829b2886474", + "name": "control", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "e976e72f-8bd1-44d4-ad75-8410db221e3f", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "38e15c99-ff72-443a-bddc-440fab9ccefc", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "f6d628e8-05ca-4ee3-a5a4-35323ebeb853", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "denoise_mask": { + "id": "e2385456-d127-4793-98ca-d93b4aee3481", + "name": "denoise_mask", + "type": "DenoiseMaskField", + "fieldKind": "input", + "label": "" + } + }, + "outputs": { + "latents": { + "id": "a61efc39-ba21-468b-ae58-5922337cf399", + "name": "latents", + "type": "LatentsField", + "fieldKind": "output" + }, + "width": { + "id": "9093043b-808b-4ac6-ab18-7d721a7e39d7", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "5ff472a4-ee22-4988-bcf7-7d6116a37e5a", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" + }, + "width": 320, + "height": 646, + "position": { + "x": 1672.552348276784, + "y": -118.3156091718022 + } + }, + { + "id": "17eb4b88-bdd8-4984-affa-26586b146866", + "type": "invocation", + "data": { + "id": "17eb4b88-bdd8-4984-affa-26586b146866", + "type": "l2i", + "inputs": { + "metadata": { + "id": "04f49f70-8ee6-43e3-ac63-af02e5b34204", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "d27c4313-01db-45cb-b9f4-6a827d0d766a", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "3751b0f6-69f3-4f95-a7f9-476b2d31e9f9", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "07e5e79a-b452-4beb-b26f-715da2387ac7", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "afe954f6-ecaf-4eac-98ee-23f4d0eb7a6b", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "98515f37-9fe7-420e-839b-6e349d9407df", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "5203f61f-02db-423c-9c85-80aa20816dea", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "499e6152-c604-4dad-84c3-8c5b26a39919", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": false, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 2045.2934900771834, + "y": -362.2916292593367 + } } ], "edges": [ @@ -1296,102 +1339,6 @@ "id": "reactflow__edge-8d54b9db-3662-43af-8369-9a277e063f3bvalue-fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1style", "type": "default" }, - { - "source": "faf965a4-7530-427b-b1f3-4ba6505c2a08", - "sourceHandle": "conditioning", - "target": "65b56526-ef0a-4c1f-adda-1017c925b063", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-faf965a4-7530-427b-b1f3-4ba6505c2a08conditioning-65b56526-ef0a-4c1f-adda-1017c925b063positive_conditioning", - "type": "default" - }, - { - "source": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", - "sourceHandle": "conditioning", - "target": "65b56526-ef0a-4c1f-adda-1017c925b063", - "targetHandle": "negative_conditioning", - "id": "reactflow__edge-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204conditioning-65b56526-ef0a-4c1f-adda-1017c925b063negative_conditioning", - "type": "default" - }, - { - "source": "55705012-79b9-4aac-9f26-c0b10309785b", - "sourceHandle": "noise", - "target": "65b56526-ef0a-4c1f-adda-1017c925b063", - "targetHandle": "noise", - "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-65b56526-ef0a-4c1f-adda-1017c925b063noise", - "type": "default" - }, - { - "source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", - "sourceHandle": "unet", - "target": "65b56526-ef0a-4c1f-adda-1017c925b063", - "targetHandle": "unet", - "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22unet-65b56526-ef0a-4c1f-adda-1017c925b063unet", - "type": "default" - }, - { - "source": "fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1", - "sourceHandle": "conditioning", - "target": "a9352523-613a-43e3-b97f-dade7ec317e5", - "targetHandle": "negative_conditioning", - "id": "reactflow__edge-fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1conditioning-a9352523-613a-43e3-b97f-dade7ec317e5negative_conditioning", - "type": "default" - }, - { - "source": "f0e06b70-9f53-44e3-8f5f-63d813b6b579", - "sourceHandle": "conditioning", - "target": "a9352523-613a-43e3-b97f-dade7ec317e5", - "targetHandle": "positive_conditioning", - "id": "reactflow__edge-f0e06b70-9f53-44e3-8f5f-63d813b6b579conditioning-a9352523-613a-43e3-b97f-dade7ec317e5positive_conditioning", - "type": "default" - }, - { - "source": "a9352523-613a-43e3-b97f-dade7ec317e5", - "sourceHandle": "latents", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "targetHandle": "latents", - "id": "reactflow__edge-a9352523-613a-43e3-b97f-dade7ec317e5latents-dbcd2f98-d809-48c8-bf64-2635f88a2fe9latents", - "type": "default" - }, - { - "source": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", - "sourceHandle": "vae", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "targetHandle": "vae", - "id": "reactflow__edge-62bdf243-d98f-4508-b6b5-c3af00ef49f0vae-dbcd2f98-d809-48c8-bf64-2635f88a2fe9vae", - "type": "default" - }, - { - "source": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", - "sourceHandle": "unet", - "target": "a9352523-613a-43e3-b97f-dade7ec317e5", - "targetHandle": "unet", - "id": "reactflow__edge-62bdf243-d98f-4508-b6b5-c3af00ef49f0unet-a9352523-613a-43e3-b97f-dade7ec317e5unet", - "type": "default" - }, - { - "source": "65b56526-ef0a-4c1f-adda-1017c925b063", - "sourceHandle": "latents", - "target": "a9352523-613a-43e3-b97f-dade7ec317e5", - "targetHandle": "latents", - "id": "reactflow__edge-65b56526-ef0a-4c1f-adda-1017c925b063latents-a9352523-613a-43e3-b97f-dade7ec317e5latents", - "type": "default" - }, - { - "source": "06a30867-1e9d-461f-bd58-14a63cc997dd", - "sourceHandle": "scheduler", - "target": "65b56526-ef0a-4c1f-adda-1017c925b063", - "targetHandle": "scheduler", - "id": "reactflow__edge-06a30867-1e9d-461f-bd58-14a63cc997ddscheduler-65b56526-ef0a-4c1f-adda-1017c925b063scheduler", - "type": "default" - }, - { - "source": "06a30867-1e9d-461f-bd58-14a63cc997dd", - "sourceHandle": "scheduler", - "target": "a9352523-613a-43e3-b97f-dade7ec317e5", - "targetHandle": "scheduler", - "id": "reactflow__edge-06a30867-1e9d-461f-bd58-14a63cc997ddscheduler-a9352523-613a-43e3-b97f-dade7ec317e5scheduler", - "type": "default" - }, { "source": "8d54b9db-3662-43af-8369-9a277e063f3b", "sourceHandle": "value", @@ -1399,6 +1346,94 @@ "targetHandle": "style", "id": "reactflow__edge-8d54b9db-3662-43af-8369-9a277e063f3bvalue-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204style", "type": "default" + }, + { + "source": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204", + "sourceHandle": "conditioning", + "target": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204conditioning-84df8f00-ea7e-499f-ab86-d019ddea5393negative_conditioning", + "type": "default" + }, + { + "source": "faf965a4-7530-427b-b1f3-4ba6505c2a08", + "sourceHandle": "conditioning", + "target": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-faf965a4-7530-427b-b1f3-4ba6505c2a08conditioning-84df8f00-ea7e-499f-ab86-d019ddea5393positive_conditioning", + "type": "default" + }, + { + "source": "55705012-79b9-4aac-9f26-c0b10309785b", + "sourceHandle": "noise", + "target": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "targetHandle": "noise", + "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-84df8f00-ea7e-499f-ab86-d019ddea5393noise", + "type": "default" + }, + { + "source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22", + "sourceHandle": "unet", + "target": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "targetHandle": "unet", + "id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22unet-84df8f00-ea7e-499f-ab86-d019ddea5393unet", + "type": "default" + }, + { + "source": "06a30867-1e9d-461f-bd58-14a63cc997dd", + "sourceHandle": "scheduler", + "target": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "targetHandle": "scheduler", + "id": "reactflow__edge-06a30867-1e9d-461f-bd58-14a63cc997ddscheduler-84df8f00-ea7e-499f-ab86-d019ddea5393scheduler", + "type": "default" + }, + { + "source": "84df8f00-ea7e-499f-ab86-d019ddea5393", + "sourceHandle": "latents", + "target": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "targetHandle": "latents", + "id": "reactflow__edge-84df8f00-ea7e-499f-ab86-d019ddea5393latents-3d40eda5-ff7b-4dff-8d2e-4f44742faa1blatents", + "type": "default" + }, + { + "source": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", + "sourceHandle": "unet", + "target": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "targetHandle": "unet", + "id": "reactflow__edge-62bdf243-d98f-4508-b6b5-c3af00ef49f0unet-3d40eda5-ff7b-4dff-8d2e-4f44742faa1bunet", + "type": "default" + }, + { + "source": "f0e06b70-9f53-44e3-8f5f-63d813b6b579", + "sourceHandle": "conditioning", + "target": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "targetHandle": "positive_conditioning", + "id": "reactflow__edge-f0e06b70-9f53-44e3-8f5f-63d813b6b579conditioning-3d40eda5-ff7b-4dff-8d2e-4f44742faa1bpositive_conditioning", + "type": "default" + }, + { + "source": "fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1", + "sourceHandle": "conditioning", + "target": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "targetHandle": "negative_conditioning", + "id": "reactflow__edge-fbb2f1a0-2e68-411d-a955-60c3b8a6f2d1conditioning-3d40eda5-ff7b-4dff-8d2e-4f44742faa1bnegative_conditioning", + "type": "default" + }, + { + "source": "3d40eda5-ff7b-4dff-8d2e-4f44742faa1b", + "sourceHandle": "latents", + "target": "17eb4b88-bdd8-4984-affa-26586b146866", + "targetHandle": "latents", + "id": "reactflow__edge-3d40eda5-ff7b-4dff-8d2e-4f44742faa1blatents-17eb4b88-bdd8-4984-affa-26586b146866latents", + "type": "default" + }, + { + "source": "62bdf243-d98f-4508-b6b5-c3af00ef49f0", + "sourceHandle": "vae", + "target": "17eb4b88-bdd8-4984-affa-26586b146866", + "targetHandle": "vae", + "id": "reactflow__edge-62bdf243-d98f-4508-b6b5-c3af00ef49f0vae-17eb4b88-bdd8-4984-affa-26586b146866vae", + "type": "default" } ] -} +} \ No newline at end of file diff --git a/docs/workflows/Text_to_Image.json b/docs/workflows/Text_to_Image.json index 7239a2247f..a49ce7bf93 100644 --- a/docs/workflows/Text_to_Image.json +++ b/docs/workflows/Text_to_Image.json @@ -18,10 +18,6 @@ { "nodeId": "93dc02a4-d05b-48ed-b99c-c9b616af3402", "fieldName": "prompt" - }, - { - "nodeId": "75899702-fa44-46d2-b2d5-3e17f234c3e7", - "fieldName": "steps" } ], "meta": { @@ -32,7 +28,6 @@ "id": "93dc02a4-d05b-48ed-b99c-c9b616af3402", "type": "invocation", "data": { - "version": "1.0.0", "id": "93dc02a4-d05b-48ed-b99c-c9b616af3402", "type": "compel", "inputs": { @@ -64,20 +59,21 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 235, + "height": 261, "position": { - "x": 1400, - "y": -75 + "x": 995.7263915923627, + "y": 239.67783573351227 } }, { "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "invocation", "data": { - "version": "1.0.0", "id": "55705012-79b9-4aac-9f26-c0b10309785b", "type": "noise", "inputs": { @@ -138,92 +134,21 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 364, + "height": 389, "position": { - "x": 1000, - "y": 350 - } - }, - { - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "invocation", - "data": { - "version": "1.0.0", - "id": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "type": "l2i", - "inputs": { - "tiled": { - "id": "24f5bc7b-f6a1-425d-8ab1-f50b4db5d0df", - "name": "tiled", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "fp32": { - "id": "b146d873-ffb9-4767-986a-5360504841a2", - "name": "fp32", - "type": "boolean", - "fieldKind": "input", - "label": "", - "value": false - }, - "latents": { - "id": "65441abd-7713-4b00-9d8d-3771404002e8", - "name": "latents", - "type": "LatentsField", - "fieldKind": "input", - "label": "" - }, - "vae": { - "id": "a478b833-6e13-4611-9a10-842c89603c74", - "name": "vae", - "type": "VaeField", - "fieldKind": "input", - "label": "" - } - }, - "outputs": { - "image": { - "id": "c87ae925-f858-417a-8940-8708ba9b4b53", - "name": "image", - "type": "ImageField", - "fieldKind": "output" - }, - "width": { - "id": "4bcb8512-b5a1-45f1-9e52-6e92849f9d6c", - "name": "width", - "type": "integer", - "fieldKind": "output" - }, - "height": { - "id": "23e41c00-a354-48e8-8f59-5875679c27ab", - "name": "height", - "type": "integer", - "fieldKind": "output" - } - }, - "label": "", - "isOpen": true, - "notes": "", - "embedWorkflow": true, - "isIntermediate": false - }, - "width": 320, - "height": 266, - "position": { - "x": 1800, - "y": 200 + "x": 993.4442117555518, + "y": 605.6757415334787 } }, { "id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8", "type": "invocation", "data": { - "version": "1.0.0", "id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8", "type": "main_model_loader", "inputs": { @@ -261,23 +186,24 @@ } }, "label": "", - "isOpen": false, + "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 32, + "height": 226, "position": { - "x": 1000, - "y": 200 + "x": 163.04436745878343, + "y": 254.63156870373479 } }, { "id": "7d8bf987-284f-413a-b2fd-d825445a5d6c", "type": "invocation", "data": { - "version": "1.0.0", "id": "7d8bf987-284f-413a-b2fd-d825445a5d6c", "type": "compel", "inputs": { @@ -309,20 +235,21 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.0.0" }, "width": 320, - "height": 235, + "height": 261, "position": { - "x": 1000, - "y": -75 + "x": 595.7263915923627, + "y": 239.67783573351227 } }, { "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "invocation", "data": { - "version": "1.0.0", "id": "ea94bc37-d995-4a83-aa99-4af42479f2f2", "type": "rand_int", "inputs": { @@ -352,51 +279,66 @@ } }, "label": "Random Seed", - "isOpen": false, + "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": false, + "version": "1.0.0" }, "width": 320, - "height": 32, + "height": 218, "position": { - "x": 1000, - "y": 275 + "x": 541.094822888628, + "y": 694.5704476446829 } }, { - "id": "75899702-fa44-46d2-b2d5-3e17f234c3e7", + "id": "eea2702a-19fb-45b5-9d75-56b4211ec03c", "type": "invocation", "data": { - "version": "1.0.0", - "id": "75899702-fa44-46d2-b2d5-3e17f234c3e7", + "id": "eea2702a-19fb-45b5-9d75-56b4211ec03c", "type": "denoise_latents", "inputs": { + "positive_conditioning": { + "id": "90b7f4f8-ada7-4028-8100-d2e54f192052", + "name": "positive_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, + "negative_conditioning": { + "id": "9393779e-796c-4f64-b740-902a1177bf53", + "name": "negative_conditioning", + "type": "ConditioningField", + "fieldKind": "input", + "label": "" + }, "noise": { - "id": "8b18f3eb-40d2-45c1-9a9d-28d6af0dce2b", + "id": "8e17f1e5-4f98-40b1-b7f4-86aeeb4554c1", "name": "noise", "type": "LatentsField", "fieldKind": "input", "label": "" }, "steps": { - "id": "0be4373c-46f3-441c-80a7-a4bb6ceb498c", + "id": "9b63302d-6bd2-42c9-ac13-9b1afb51af88", "name": "steps", "type": "integer", "fieldKind": "input", "label": "", - "value": 36 + "value": 10 }, "cfg_scale": { - "id": "107267ce-4666-4cd7-94b3-7476b7973ae9", + "id": "87dd04d3-870e-49e1-98bf-af003a810109", "name": "cfg_scale", - "type": "float", + "type": "FloatPolymorphic", "fieldKind": "input", "label": "", "value": 7.5 }, "denoising_start": { - "id": "d2ce9f0f-5fc2-48b2-b917-53442941e9a1", + "id": "f369d80f-4931-4740-9bcd-9f0620719fab", "name": "denoising_start", "type": "float", "fieldKind": "input", @@ -404,7 +346,7 @@ "value": 0 }, "denoising_end": { - "id": "8ad51505-b8d0-422a-beb8-96fc6fc6b65f", + "id": "747d10e5-6f02-445c-994c-0604d814de8c", "name": "denoising_end", "type": "float", "fieldKind": "input", @@ -412,71 +354,71 @@ "value": 1 }, "scheduler": { - "id": "53092874-a43b-4623-91a2-76e62fdb1f2e", + "id": "1de84a4e-3a24-4ec8-862b-16ce49633b9b", "name": "scheduler", "type": "Scheduler", "fieldKind": "input", "label": "", "value": "euler" }, + "unet": { + "id": "ffa6fef4-3ce2-4bdb-9296-9a834849489b", + "name": "unet", + "type": "UNetField", + "fieldKind": "input", + "label": "" + }, "control": { - "id": "7abe57cc-469d-437e-ad72-a18efa28215f", + "id": "077b64cb-34be-4fcc-83f2-e399807a02bd", "name": "control", - "type": "ControlField", + "type": "ControlPolymorphic", + "fieldKind": "input", + "label": "" + }, + "ip_adapter": { + "id": "1d6948f7-3a65-4a65-a20c-768b287251aa", + "name": "ip_adapter", + "type": "IPAdapterPolymorphic", + "fieldKind": "input", + "label": "" + }, + "t2i_adapter": { + "id": "75e67b09-952f-4083-aaf4-6b804d690412", + "name": "t2i_adapter", + "type": "T2IAdapterPolymorphic", "fieldKind": "input", "label": "" }, "latents": { - "id": "add8bbe5-14d0-42d4-a867-9c65ab8dd129", + "id": "334d4ba3-5a99-4195-82c5-86fb3f4f7d43", "name": "latents", "type": "LatentsField", "fieldKind": "input", "label": "" }, "denoise_mask": { - "id": "f373a190-0fc8-45b7-ae62-c4aa8e9687e1", + "id": "0d3dbdbf-b014-4e95-8b18-ff2ff9cb0bfa", "name": "denoise_mask", "type": "DenoiseMaskField", "fieldKind": "input", "label": "" - }, - "positive_conditioning": { - "id": "c7160303-8a23-4f15-9197-855d48802a7f", - "name": "positive_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "negative_conditioning": { - "id": "fd750efa-1dfc-4d0b-accb-828e905ba320", - "name": "negative_conditioning", - "type": "ConditioningField", - "fieldKind": "input", - "label": "" - }, - "unet": { - "id": "af1f41ba-ce2a-4314-8d7f-494bb5800381", - "name": "unet", - "type": "UNetField", - "fieldKind": "input", - "label": "" } }, "outputs": { "latents": { - "id": "8508d04d-f999-4a44-94d0-388ab1401d27", + "id": "70fa5bbc-0c38-41bb-861a-74d6d78d2f38", "name": "latents", "type": "LatentsField", "fieldKind": "output" }, "width": { - "id": "93dc8287-0a2a-4320-83a4-5e994b7ba23e", + "id": "98ee0e6c-82aa-4e8f-8be5-dc5f00ee47f0", "name": "width", "type": "integer", "fieldKind": "output" }, "height": { - "id": "d9862f5c-0ab5-46fa-8c29-5059bb581d96", + "id": "e8cb184a-5e1a-47c8-9695-4b8979564f5d", "name": "height", "type": "integer", "fieldKind": "output" @@ -486,13 +428,95 @@ "isOpen": true, "notes": "", "embedWorkflow": false, - "isIntermediate": true + "isIntermediate": true, + "useCache": true, + "version": "1.4.0" }, "width": 320, - "height": 558, + "height": 646, "position": { - "x": 1400, - "y": 200 + "x": 1476.5794704734735, + "y": 256.80174342731783 + } + }, + { + "id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f", + "type": "invocation", + "data": { + "id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f", + "type": "l2i", + "inputs": { + "metadata": { + "id": "ab375f12-0042-4410-9182-29e30db82c85", + "name": "metadata", + "type": "MetadataField", + "fieldKind": "input", + "label": "" + }, + "latents": { + "id": "3a7e7efd-bff5-47d7-9d48-615127afee78", + "name": "latents", + "type": "LatentsField", + "fieldKind": "input", + "label": "" + }, + "vae": { + "id": "a1f5f7a1-0795-4d58-b036-7820c0b0ef2b", + "name": "vae", + "type": "VaeField", + "fieldKind": "input", + "label": "" + }, + "tiled": { + "id": "da52059a-0cee-4668-942f-519aa794d739", + "name": "tiled", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + }, + "fp32": { + "id": "c4841df3-b24e-4140-be3b-ccd454c2522c", + "name": "fp32", + "type": "boolean", + "fieldKind": "input", + "label": "", + "value": false + } + }, + "outputs": { + "image": { + "id": "72d667d0-cf85-459d-abf2-28bd8b823fe7", + "name": "image", + "type": "ImageField", + "fieldKind": "output" + }, + "width": { + "id": "c8c907d8-1066-49d1-b9a6-83bdcd53addc", + "name": "width", + "type": "integer", + "fieldKind": "output" + }, + "height": { + "id": "230f359c-b4ea-436c-b372-332d7dcdca85", + "name": "height", + "type": "integer", + "fieldKind": "output" + } + }, + "label": "", + "isOpen": true, + "notes": "", + "embedWorkflow": false, + "isIntermediate": false, + "useCache": true, + "version": "1.0.0" + }, + "width": 320, + "height": 267, + "position": { + "x": 2037.9648469717395, + "y": 426.10844427600136 } } ], @@ -522,52 +546,52 @@ "type": "default" }, { - "source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8", - "sourceHandle": "vae", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "targetHandle": "vae", - "id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8vae-dbcd2f98-d809-48c8-bf64-2635f88a2fe9vae", - "type": "default" - }, - { - "source": "75899702-fa44-46d2-b2d5-3e17f234c3e7", - "sourceHandle": "latents", - "target": "dbcd2f98-d809-48c8-bf64-2635f88a2fe9", - "targetHandle": "latents", - "id": "reactflow__edge-75899702-fa44-46d2-b2d5-3e17f234c3e7latents-dbcd2f98-d809-48c8-bf64-2635f88a2fe9latents", + "source": "55705012-79b9-4aac-9f26-c0b10309785b", + "sourceHandle": "noise", + "target": "eea2702a-19fb-45b5-9d75-56b4211ec03c", + "targetHandle": "noise", + "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-eea2702a-19fb-45b5-9d75-56b4211ec03cnoise", "type": "default" }, { "source": "7d8bf987-284f-413a-b2fd-d825445a5d6c", "sourceHandle": "conditioning", - "target": "75899702-fa44-46d2-b2d5-3e17f234c3e7", + "target": "eea2702a-19fb-45b5-9d75-56b4211ec03c", "targetHandle": "positive_conditioning", - "id": "reactflow__edge-7d8bf987-284f-413a-b2fd-d825445a5d6cconditioning-75899702-fa44-46d2-b2d5-3e17f234c3e7positive_conditioning", + "id": "reactflow__edge-7d8bf987-284f-413a-b2fd-d825445a5d6cconditioning-eea2702a-19fb-45b5-9d75-56b4211ec03cpositive_conditioning", "type": "default" }, { "source": "93dc02a4-d05b-48ed-b99c-c9b616af3402", "sourceHandle": "conditioning", - "target": "75899702-fa44-46d2-b2d5-3e17f234c3e7", + "target": "eea2702a-19fb-45b5-9d75-56b4211ec03c", "targetHandle": "negative_conditioning", - "id": "reactflow__edge-93dc02a4-d05b-48ed-b99c-c9b616af3402conditioning-75899702-fa44-46d2-b2d5-3e17f234c3e7negative_conditioning", + "id": "reactflow__edge-93dc02a4-d05b-48ed-b99c-c9b616af3402conditioning-eea2702a-19fb-45b5-9d75-56b4211ec03cnegative_conditioning", "type": "default" }, { "source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8", "sourceHandle": "unet", - "target": "75899702-fa44-46d2-b2d5-3e17f234c3e7", + "target": "eea2702a-19fb-45b5-9d75-56b4211ec03c", "targetHandle": "unet", - "id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8unet-75899702-fa44-46d2-b2d5-3e17f234c3e7unet", + "id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8unet-eea2702a-19fb-45b5-9d75-56b4211ec03cunet", "type": "default" }, { - "source": "55705012-79b9-4aac-9f26-c0b10309785b", - "sourceHandle": "noise", - "target": "75899702-fa44-46d2-b2d5-3e17f234c3e7", - "targetHandle": "noise", - "id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-75899702-fa44-46d2-b2d5-3e17f234c3e7noise", + "source": "eea2702a-19fb-45b5-9d75-56b4211ec03c", + "sourceHandle": "latents", + "target": "58c957f5-0d01-41fc-a803-b2bbf0413d4f", + "targetHandle": "latents", + "id": "reactflow__edge-eea2702a-19fb-45b5-9d75-56b4211ec03clatents-58c957f5-0d01-41fc-a803-b2bbf0413d4flatents", + "type": "default" + }, + { + "source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8", + "sourceHandle": "vae", + "target": "58c957f5-0d01-41fc-a803-b2bbf0413d4f", + "targetHandle": "vae", + "id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8vae-58c957f5-0d01-41fc-a803-b2bbf0413d4fvae", "type": "default" } ] -} +} \ No newline at end of file From 63548c5ea7761053ec7bbf98ab4a106c68c4a21f Mon Sep 17 00:00:00 2001 From: Millun Atluri Date: Tue, 31 Oct 2023 16:26:53 +1100 Subject: [PATCH 088/119] Update community node installation instructions --- docs/features/CONTROLNET.md | 1 - docs/nodes/communityNodes.md | 10 +++++++--- docs/nodes/contributingNodes.md | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/features/CONTROLNET.md b/docs/features/CONTROLNET.md index f55194207c..dc773f1ec9 100644 --- a/docs/features/CONTROLNET.md +++ b/docs/features/CONTROLNET.md @@ -150,7 +150,6 @@ Start/End - 0 represents the start of the generation, 1 represents the end. The Additionally, each section can be expanded with the "Show Advanced" button in order to manipulate settings for the image pre-processor that adjusts your uploaded image before using it in during the generation process. -**Note:** T2I-Adapter models and ControlNet models cannot currently be used together. ## IP-Adapter diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index f394a7c9bd..d24873b24c 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -4,7 +4,11 @@ These are nodes that have been developed by the community, for the community. If If you'd like to submit a node for the community, please refer to the [node creation overview](contributingNodes.md). -To download a node, simply download the `.py` node file from the link and add it to the `invokeai/app/invocations` folder in your Invoke AI install location. If you used the automated installation, this can be found inside the `.venv` folder. Along with the node, an example node graph should be provided to help you get started with the node. +To use a node, add the node to the `nodes` folder found in your InvokeAI install location. + +The suggested method is to use `git clone` to clone the repository the node is found in. This allows for easy updates of the node in the future. + +If you'd prefer, you can also just download the `.py` file from the linked repository and add it to the `nodes` folder. To use a community workflow, download the the `.json` node graph file and load it into Invoke AI via the **Load Workflow** button in the Workflow Editor. @@ -329,9 +333,9 @@ See full docs here: https://github.com/skunkworxdark/XYGrid_nodes/edit/main/READ **Description:** This node allows you to do super cool things with InvokeAI. -**Node Link:** https://github.com/invoke-ai/InvokeAI/fake_node.py +**Node Link:** https://github.com/invoke-ai/InvokeAI/blob/main/invokeai/app/invocations/prompt.py -**Example Node Graph:** https://github.com/invoke-ai/InvokeAI/fake_node_graph.json +**Example Workflow:** https://github.com/invoke-ai/InvokeAI/blob/docs/main/docs/workflows/Prompt_from_File.json **Output Examples** diff --git a/docs/nodes/contributingNodes.md b/docs/nodes/contributingNodes.md index c58a56e4e6..a2fd066eb8 100644 --- a/docs/nodes/contributingNodes.md +++ b/docs/nodes/contributingNodes.md @@ -4,7 +4,7 @@ To learn about the specifics of creating a new node, please visit our [Node crea Once you’ve created a node and confirmed that it behaves as expected locally, follow these steps: -- Make sure the node is contained in a new Python (.py) file. Preferrably, the node is in a repo with a README detaling the nodes usage & examples to help others more easily use your node. +- Make sure the node is contained in a new Python (.py) file. Preferably, the node is in a repo with a README detailing the nodes usage & examples to help others more easily use your node. Including the term "InvokeAI Node" in your repository's README can also help other users find it more easily. - Submit a pull request with a link to your node(s) repo in GitHub against the `main` branch to add the node to the [Community Nodes](communityNodes.md) list - Make sure you are following the template below and have provided all relevant details about the node and what it does. Example output images and workflows are very helpful for other users looking to use your node. - A maintainer will review the pull request and node. If the node is aligned with the direction of the project, you may be asked for permission to include it in the core project. From ed81d6d533366c84d65e2f2868ed72b066c4ebd3 Mon Sep 17 00:00:00 2001 From: Millun Atluri Date: Tue, 31 Oct 2023 16:29:29 +1100 Subject: [PATCH 089/119] Update contributingNodes.md --- docs/nodes/contributingNodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/nodes/contributingNodes.md b/docs/nodes/contributingNodes.md index a2fd066eb8..7a30c8aeb0 100644 --- a/docs/nodes/contributingNodes.md +++ b/docs/nodes/contributingNodes.md @@ -4,7 +4,7 @@ To learn about the specifics of creating a new node, please visit our [Node crea Once you’ve created a node and confirmed that it behaves as expected locally, follow these steps: -- Make sure the node is contained in a new Python (.py) file. Preferably, the node is in a repo with a README detailing the nodes usage & examples to help others more easily use your node. Including the term "InvokeAI Node" in your repository's README can also help other users find it more easily. +- Make sure the node is contained in a new Python (.py) file. Preferably, the node is in a repo with a README detailing the nodes usage & examples to help others more easily use your node. Including the tag "invokeai-node" in your repository's README can also help other users find it more easily. - Submit a pull request with a link to your node(s) repo in GitHub against the `main` branch to add the node to the [Community Nodes](communityNodes.md) list - Make sure you are following the template below and have provided all relevant details about the node and what it does. Example output images and workflows are very helpful for other users looking to use your node. - A maintainer will review the pull request and node. If the node is aligned with the direction of the project, you may be asked for permission to include it in the core project. From a79c86b901e20f136b91e69214fc247a88d59d3a Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Tue, 31 Oct 2023 15:00:38 +0100 Subject: [PATCH 090/119] translationBot(ui): update translation (German) Currently translated at 51.7% (630 of 1217 strings) Co-authored-by: Alexander Eichhorn Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 179 ++++++++++++++++++- 1 file changed, 170 insertions(+), 9 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index b483d61928..c06ad56492 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -86,7 +86,10 @@ "batch": "Batch-Manager", "advanced": "Erweitert", "langBrPortuguese": "Portugiesisch (Brasilien)", - "unifiedCanvas": "Einheitliche Leinwand" + "unifiedCanvas": "Einheitliche Leinwand", + "openInNewTab": "In einem neuem Tab öffnen", + "statusProcessing": "wird bearbeitet", + "linear": "Linear" }, "gallery": { "generations": "Erzeugungen", @@ -101,7 +104,15 @@ "singleColumnLayout": "Einspaltiges Layout", "allImagesLoaded": "Alle Bilder geladen", "loadMore": "Mehr laden", - "noImagesInGallery": "Keine Bilder in der Galerie" + "noImagesInGallery": "Keine Bilder in der Galerie", + "loading": "Lade", + "preparingDownload": "bereite Download vor", + "preparingDownloadFailed": "Problem beim Download vorbereiten", + "deleteImage": "Lösche Bild", + "images": "Bilder", + "copy": "Kopieren", + "download": "Runterladen", + "setCurrentImage": "Setze aktuelle Bild" }, "hotkeys": { "keyboardShortcuts": "Tastenkürzel", @@ -110,7 +121,8 @@ "galleryHotkeys": "Galerie Tastenkürzel", "unifiedCanvasHotkeys": "Unified Canvas Tastenkürzel", "invoke": { - "desc": "Ein Bild erzeugen" + "desc": "Ein Bild erzeugen", + "title": "Invoke" }, "cancel": { "title": "Abbrechen", @@ -307,6 +319,10 @@ "acceptStagingImage": { "title": "Staging-Bild akzeptieren", "desc": "Akzeptieren Sie das aktuelle Bild des Staging-Bereichs" + }, + "nodesHotkeys": "Knoten Tastenkürzel", + "addNodes": { + "title": "Knotenpunkt hinzufügen" } }, "modelManager": { @@ -356,7 +372,7 @@ "deleteModel": "Model löschen", "deleteConfig": "Konfiguration löschen", "deleteMsg1": "Möchten Sie diesen Model-Eintrag wirklich aus InvokeAI löschen?", - "deleteMsg2": "Dadurch wird die Modellprüfpunktdatei nicht von Ihrer Festplatte gelöscht. Sie können sie bei Bedarf erneut hinzufügen.", + "deleteMsg2": "Dadurch WIRD das Modell von der Festplatte gelöscht WENN es im InvokeAI Root Ordner liegt. Wenn es in einem anderem Ordner liegt wird das Modell NICHT von der Festplatte gelöscht.", "customConfig": "Benutzerdefinierte Konfiguration", "invokeRoot": "InvokeAI Ordner", "formMessageDiffusersVAELocationDesc": "Falls nicht angegeben, sucht InvokeAI nach der VAE-Datei innerhalb des oben angegebenen Modell Speicherortes.", @@ -402,7 +418,17 @@ "v2_768": "v2 (768px)", "none": "Nix", "repoIDValidationMsg": "Online Repo Ihres Modells", - "vaeRepoIDValidationMsg": "Online Repo Ihrer VAE" + "vaeRepoIDValidationMsg": "Online Repo Ihrer VAE", + "importModels": "Importiere Modelle", + "merge": "Zusammenführen", + "addDiffuserModel": "Diffusers hinzufügen", + "advanced": "Erweitert", + "closeAdvanced": "Schließe Erweitert", + "convertingModelBegin": "Konvertiere Modell. Bitte warten.", + "customConfigFileLocation": "Benutzerdefinierte Konfiguration Datei Speicherort", + "baseModel": "Basis Modell", + "convertToDiffusers": "Konvertiere zu Diffusers", + "diffusersModels": "Diffusers" }, "parameters": { "images": "Bilder", @@ -422,7 +448,7 @@ "type": "Art", "strength": "Stärke", "upscaling": "Hochskalierung", - "upscale": "Hochskalieren", + "upscale": "Hochskalieren (Shift + U)", "upscaleImage": "Bild hochskalieren", "scale": "Maßstab", "otherOptions": "Andere Optionen", @@ -478,7 +504,7 @@ "resetWebUI": "Web-Oberfläche zurücksetzen", "resetWebUIDesc1": "Das Zurücksetzen der Web-Oberfläche setzt nur den lokalen Cache des Browsers mit Ihren Bildern und gespeicherten Einstellungen zurück. Es werden keine Bilder von der Festplatte gelöscht.", "resetWebUIDesc2": "Wenn die Bilder nicht in der Galerie angezeigt werden oder etwas anderes nicht funktioniert, versuchen Sie bitte, die Einstellungen zurückzusetzen, bevor Sie einen Fehler auf GitHub melden.", - "resetComplete": "Die Web-Oberfläche wurde zurückgesetzt. Aktualisieren Sie die Seite, um sie neu zu laden.", + "resetComplete": "Die Web-Oberfläche wurde zurückgesetzt.", "models": "Modelle", "useSlidersForAll": "Schieberegler für alle Optionen verwenden" }, @@ -490,7 +516,7 @@ "imageCopied": "Bild kopiert", "imageLinkCopied": "Bildlink kopiert", "imageNotLoaded": "Kein Bild geladen", - "imageNotLoadedDesc": "Kein Bild gefunden, das an das Bild zu Bild-Modul gesendet werden kann", + "imageNotLoadedDesc": "Konnte kein Bild finden", "imageSavedToGallery": "Bild in die Galerie gespeichert", "canvasMerged": "Leinwand zusammengeführt", "sentToImageToImage": "Gesendet an Bild zu Bild", @@ -585,7 +611,10 @@ "betaClear": "Löschen", "betaDarkenOutside": "Außen abdunkeln", "betaLimitToBox": "Begrenzung auf das Feld", - "betaPreserveMasked": "Maskiertes bewahren" + "betaPreserveMasked": "Maskiertes bewahren", + "antialiasing": "Kantenglättung", + "showResultsOn": "Zeige Ergebnisse (An)", + "showResultsOff": "Zeige Ergebnisse (Aus)" }, "accessibility": { "modelSelect": "Model Auswahl", @@ -627,5 +656,137 @@ "changeBoard": "Ordner wechseln", "loading": "Laden...", "clearSearch": "Suche leeren" + }, + "controlnet": { + "showAdvanced": "Zeige Erweitert", + "contentShuffleDescription": "Mischt den Inhalt von einem Bild", + "addT2IAdapter": "$t(common.t2iAdapter) hinzufügen", + "importImageFromCanvas": "Importieren Bild von Zeichenfläche", + "lineartDescription": "Konvertiere Bild zu Lineart", + "importMaskFromCanvas": "Importiere Maske von Zeichenfläche", + "hed": "HED", + "hideAdvanced": "Verstecke Erweitert", + "contentShuffle": "Inhalt mischen", + "controlNetEnabledT2IDisabled": "$t(common.controlNet) ist aktiv, $t(common.t2iAdapter) ist deaktiviert", + "ipAdapterModel": "Adapter Modell", + "beginEndStepPercent": "Start / Ende Step Prozent", + "duplicate": "Kopieren", + "f": "F", + "h": "H", + "depthMidasDescription": "Tiefenmap erstellen mit Midas", + "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))", + "t2iEnabledControlNetDisabled": "$t(common.t2iAdapter) ist aktiv, $t(common.controlNet) ist deaktiviert", + "weight": "Breite", + "selectModel": "Wähle ein Modell", + "depthMidas": "Tiefe (Midas)", + "w": "W", + "addControlNet": "$t(common.controlNet) hinzufügen", + "none": "Kein", + "incompatibleBaseModel": "Inkompatibles Basismodell:", + "enableControlnet": "Aktiviere ControlNet", + "detectResolution": "Auflösung erkennen", + "controlNetT2IMutexDesc": "$t(common.controlNet) und $t(common.t2iAdapter) zur gleichen Zeit wird nicht unterstützt.", + "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))", + "fill": "Füllen", + "addIPAdapter": "$t(common.ipAdapter) hinzufügen", + "colorMapDescription": "Erstelle eine Farbkarte von diesem Bild", + "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))", + "imageResolution": "Bild Auflösung", + "depthZoe": "Tiefe (Zoe)", + "colorMap": "Farbe", + "lowThreshold": "Niedrige Schwelle", + "highThreshold": "Hohe Schwelle", + "toggleControlNet": "Schalten ControlNet um", + "delete": "Löschen", + "controlAdapter_one": "Control Adapter", + "controlAdapter_other": "Control Adapters", + "colorMapTileSize": "Tile Größe", + "depthZoeDescription": "Tiefenmap erstellen mit Zoe", + "setControlImageDimensions": "Setze Control Bild Auflösung auf Breite/Höhe", + "handAndFace": "Hand und Gesicht", + "enableIPAdapter": "Aktiviere IP Adapter" + }, + "queue": { + "status": "Status", + "cancelTooltip": "Aktuellen Aufgabe abbrechen", + "queueEmpty": "Warteschlange leer", + "in_progress": "In Arbeit", + "queueFront": "An den Anfang der Warteschlange tun", + "completed": "Fertig", + "queueBack": "In die Warteschlange", + "clearFailed": "Probleme beim leeren der Warteschlange", + "clearSucceeded": "Warteschlange geleert", + "pause": "Pause", + "cancelSucceeded": "Auftrag abgebrochen", + "queue": "Warteschlange", + "batch": "Stapel", + "pending": "Ausstehend", + "clear": "Leeren", + "prune": "Leeren", + "total": "Gesamt", + "canceled": "Abgebrochen", + "clearTooltip": "Abbrechen und alle Aufträge leeren", + "current": "Aktuell", + "failed": "Fehler", + "cancelItem": "Abbruch Auftrag", + "next": "Nächste", + "cancel": "Abbruch", + "session": "Sitzung", + "queueTotal": "{{total}} Gesamt", + "resume": "Wieder aufnehmen", + "item": "Auftrag" + }, + "metadata": { + "negativePrompt": "Negativ Beschreibung", + "metadata": "Meta-Data", + "strength": "Bild zu Bild stärke", + "imageDetails": "Bild Details", + "model": "Modell", + "noImageDetails": "Keine Bild Details gefunden", + "cfgScale": "CFG-Skala", + "fit": "Bild zu Bild passen", + "height": "Höhe", + "noMetaData": "Keine Meta-Data gefunden", + "width": "Breite", + "createdBy": "Erstellt von", + "steps": "Schritte" + }, + "popovers": { + "noiseUseCPU": { + "heading": "Nutze Prozessor rauschen" + }, + "paramModel": { + "heading": "Modell" + }, + "paramIterations": { + "heading": "Iterationen" + }, + "paramCFGScale": { + "heading": "CFG-Skala" + }, + "paramSteps": { + "heading": "Schritte" + }, + "lora": { + "heading": "LoRA Gewichte" + }, + "infillMethod": { + "heading": "Füllmethode" + }, + "paramVAE": { + "heading": "VAE" + } + }, + "ui": { + "lockRatio": "Verhältnis sperren", + "hideProgressImages": "Verstecke Prozess Bild", + "showProgressImages": "Zeige Prozess Bild" + }, + "invocationCache": { + "disable": "Deaktivieren", + "misses": "Cache Nötig", + "hits": "Cache Treffer", + "enable": "Aktivieren", + "clear": "Leeren" } } From 94055ae54a644cd1d7026cd1fae9b575629501f2 Mon Sep 17 00:00:00 2001 From: nemuruibai Date: Tue, 31 Oct 2023 15:00:38 +0100 Subject: [PATCH 091/119] translationBot(ui): update translation (Chinese (Simplified)) Currently translated at 99.8% (1215 of 1217 strings) Co-authored-by: nemuruibai Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/zh_Hans/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/zh_CN.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/invokeai/frontend/web/public/locales/zh_CN.json b/invokeai/frontend/web/public/locales/zh_CN.json index 3f896076d4..729d7652e3 100644 --- a/invokeai/frontend/web/public/locales/zh_CN.json +++ b/invokeai/frontend/web/public/locales/zh_CN.json @@ -866,7 +866,7 @@ "version": "版本", "validateConnections": "验证连接和节点图", "inputMayOnlyHaveOneConnection": "输入仅能有一个连接", - "notes": "节点", + "notes": "注释", "nodeOutputs": "节点输出", "currentImageDescription": "在节点编辑器中显示当前图像", "validateConnectionsHelp": "防止建立无效连接和调用无效节点图", @@ -892,11 +892,11 @@ "currentImage": "当前图像", "workflowName": "名称", "cannotConnectInputToInput": "无法将输入连接到输入", - "workflowNotes": "节点", + "workflowNotes": "注释", "cannotConnectOutputToOutput": "无法将输出连接到输出", "connectionWouldCreateCycle": "连接将创建一个循环", "cannotConnectToSelf": "无法连接自己", - "notesDescription": "添加有关您的工作流的节点", + "notesDescription": "添加有关您的工作流的注释", "unknownField": "未知", "colorCodeEdges": "边缘颜色编码", "unknownNode": "未知节点", From 584b5130381094d8a56bcc9a62d71a273d8988c9 Mon Sep 17 00:00:00 2001 From: Millun Atluri Date: Wed, 1 Nov 2023 08:55:06 +1100 Subject: [PATCH 092/119] Remove LowRA from Initial Models --- invokeai/configs/INITIAL_MODELS.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/invokeai/configs/INITIAL_MODELS.yaml b/invokeai/configs/INITIAL_MODELS.yaml index b6883ea915..67fcad4055 100644 --- a/invokeai/configs/INITIAL_MODELS.yaml +++ b/invokeai/configs/INITIAL_MODELS.yaml @@ -117,9 +117,6 @@ sd-1/embedding/EasyNegative: recommended: True sd-1/embedding/ahx-beta-453407d: repo_id: sd-concepts-library/ahx-beta-453407d -sd-1/lora/LowRA: - path: https://civitai.com/api/download/models/63006 - recommended: True sd-1/lora/Ink scenery: path: https://civitai.com/api/download/models/83390 sd-1/ip_adapter/ip_adapter_sd15: From 6c66adcd90313bd0861db4239ed4b22db9eca496 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 31 Oct 2023 21:55:46 -0500 Subject: [PATCH 093/119] fix(ui): show collapse labels only if not default value --- .../components/ParamDynamicPromptsCollapse.tsx | 8 +++----- .../Parameters/Advanced/ParamAdvancedCollapse.tsx | 4 +--- .../Parameters/HighResFix/ParamHrfCollapse.tsx | 12 ++++++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCollapse.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCollapse.tsx index f34235bab2..3ce6cdc99e 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCollapse.tsx +++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCollapse.tsx @@ -16,15 +16,13 @@ const ParamDynamicPromptsCollapse = () => { () => createSelector(stateSelector, ({ dynamicPrompts }) => { const count = dynamicPrompts.prompts.length; - if (count === 1) { - return t('dynamicPrompts.promptsWithCount_one', { - count, - }); - } else { + if (count > 1) { return t('dynamicPrompts.promptsWithCount_other', { count, }); } + + return; }), [t] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx index 85b6eaa903..718b38cfba 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx @@ -28,9 +28,7 @@ export default function ParamAdvancedCollapse() { const activeLabel = useMemo(() => { const activeLabel: string[] = []; - if (shouldUseCpuNoise) { - activeLabel.push(t('parameters.cpuNoise')); - } else { + if (!shouldUseCpuNoise) { activeLabel.push(t('parameters.gpuNoise')); } diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfCollapse.tsx index ef0db1af6d..63709f23aa 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfCollapse.tsx @@ -4,12 +4,13 @@ import { RootState, stateSelector } from 'app/store/store'; import { useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAICollapse from 'common/components/IAICollapse'; +import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import ParamHrfHeight from './ParamHrfHeight'; import ParamHrfStrength from './ParamHrfStrength'; import ParamHrfToggle from './ParamHrfToggle'; import ParamHrfWidth from './ParamHrfWidth'; -import ParamHrfHeight from './ParamHrfHeight'; -import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; const selector = createSelector( stateSelector, @@ -22,15 +23,14 @@ const selector = createSelector( ); export default function ParamHrfCollapse() { + const { t } = useTranslation(); const isHRFFeatureEnabled = useFeatureStatus('hrf').isFeatureEnabled; const { hrfEnabled } = useAppSelector(selector); const activeLabel = useMemo(() => { if (hrfEnabled) { - return 'On'; - } else { - return 'Off'; + return t('common.on'); } - }, [hrfEnabled]); + }, [t, hrfEnabled]); if (!isHRFFeatureEnabled) { return null; From 7f4ce518b7cbb90175fce0b91741c8c119ffd258 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 19 Oct 2023 15:18:32 -0400 Subject: [PATCH 094/119] auto-format lora.py --- invokeai/backend/model_management/lora.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index bb44455c88..fc2b764a43 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -196,7 +196,9 @@ class ModelPatcher: if model_embeddings.weight.data[token_id].shape != embedding.shape: raise ValueError( - f"Cannot load embedding for {trigger}. It was trained on a model with token dimension {embedding.shape[0]}, but the current model has token dimension {model_embeddings.weight.data[token_id].shape[0]}." + f"Cannot load embedding for {trigger}. It was trained on a model with token dimension" + f" {embedding.shape[0]}, but the current model has token dimension" + f" {model_embeddings.weight.data[token_id].shape[0]}." ) model_embeddings.weight.data[token_id] = embedding.to( @@ -257,7 +259,8 @@ class TextualInversionModel: if "string_to_param" in state_dict: if len(state_dict["string_to_param"]) > 1: print( - f'Warn: Embedding "{file_path.name}" contains multiple tokens, which is not supported. The first token will be used.' + f'Warn: Embedding "{file_path.name}" contains multiple tokens, which is not supported. The first' + " token will be used." ) result.embedding = next(iter(state_dict["string_to_param"].values())) @@ -470,7 +473,9 @@ class ONNXModelPatcher: if embeddings[token_id].shape != embedding.shape: raise ValueError( - f"Cannot load embedding for {trigger}. It was trained on a model with token dimension {embedding.shape[0]}, but the current model has token dimension {embeddings[token_id].shape[0]}." + f"Cannot load embedding for {trigger}. It was trained on a model with token dimension" + f" {embedding.shape[0]}, but the current model has token dimension" + f" {embeddings[token_id].shape[0]}." ) embeddings[token_id] = embedding From 2ba5b44ec49ad8a28d3bc7bca69f96889c3e9638 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 19 Oct 2023 15:20:13 -0400 Subject: [PATCH 095/119] Remove unused _lora_forward_hook(...). --- invokeai/backend/model_management/lora.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index fc2b764a43..e4f5aeb98e 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -54,24 +54,6 @@ class ModelPatcher: return (module_key, module) - @staticmethod - def _lora_forward_hook( - applied_loras: List[Tuple[LoRAModel, float]], - layer_name: str, - ): - def lora_forward(module, input_h, output): - if len(applied_loras) == 0: - return output - - for lora, weight in applied_loras: - layer = lora.layers.get(layer_name, None) - if layer is None: - continue - output += layer.forward(module, input_h, weight) - return output - - return lora_forward - @classmethod @contextmanager def apply_lora_unet( From 545c811bf10184150cc6567d927c8dab59cc29cd Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 31 Oct 2023 15:15:03 -0400 Subject: [PATCH 096/119] Remove device and dtype members from LoRAModelRaw, they can too easily get out-of-sync with the underlying layer states. --- .../backend/model_management/models/lora.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/invokeai/backend/model_management/models/lora.py b/invokeai/backend/model_management/models/lora.py index b6f321d60b..6ececa7df1 100644 --- a/invokeai/backend/model_management/models/lora.py +++ b/invokeai/backend/model_management/models/lora.py @@ -440,33 +440,19 @@ class IA3Layer(LoRALayerBase): class LoRAModelRaw: # (torch.nn.Module): _name: str layers: Dict[str, LoRALayer] - _device: torch.device - _dtype: torch.dtype def __init__( self, name: str, layers: Dict[str, LoRALayer], - device: torch.device, - dtype: torch.dtype, ): self._name = name - self._device = device or torch.cpu - self._dtype = dtype or torch.float32 self.layers = layers @property def name(self): return self._name - @property - def device(self): - return self._device - - @property - def dtype(self): - return self._dtype - def to( self, device: Optional[torch.device] = None, @@ -475,8 +461,6 @@ class LoRAModelRaw: # (torch.nn.Module): # TODO: try revert if exception? for key, layer in self.layers.items(): layer.to(device=device, dtype=dtype) - self._device = device - self._dtype = dtype def calc_size(self) -> int: model_size = 0 @@ -557,8 +541,6 @@ class LoRAModelRaw: # (torch.nn.Module): file_path = Path(file_path) model = cls( - device=device, - dtype=dtype, name=file_path.stem, # TODO: layers=dict(), ) From 379d68f595afda20d2496f6b6f129b9bde9050e9 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Tue, 31 Oct 2023 15:39:54 -0400 Subject: [PATCH 097/119] Patch LoRA on device when model is already on device. --- invokeai/app/invocations/compel.py | 6 ++++-- invokeai/app/invocations/latent.py | 3 ++- invokeai/backend/model_management/lora.py | 26 +++++++++++++++++------ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/invokeai/app/invocations/compel.py b/invokeai/app/invocations/compel.py index b3ebc92320..3a7d5e9e4d 100644 --- a/invokeai/app/invocations/compel.py +++ b/invokeai/app/invocations/compel.py @@ -108,13 +108,14 @@ class CompelInvocation(BaseInvocation): print(f'Warn: trigger: "{trigger}" not found') with ( - ModelPatcher.apply_lora_text_encoder(text_encoder_info.context.model, _lora_loader()), ModelPatcher.apply_ti(tokenizer_info.context.model, text_encoder_info.context.model, ti_list) as ( tokenizer, ti_manager, ), ModelPatcher.apply_clip_skip(text_encoder_info.context.model, self.clip.skipped_layers), text_encoder_info as text_encoder, + # Apply the LoRA after text_encoder has been moved to its target device for faster patching. + ModelPatcher.apply_lora_text_encoder(text_encoder, _lora_loader()), ): compel = Compel( tokenizer=tokenizer, @@ -229,13 +230,14 @@ class SDXLPromptInvocationBase: print(f'Warn: trigger: "{trigger}" not found') with ( - ModelPatcher.apply_lora(text_encoder_info.context.model, _lora_loader(), lora_prefix), ModelPatcher.apply_ti(tokenizer_info.context.model, text_encoder_info.context.model, ti_list) as ( tokenizer, ti_manager, ), ModelPatcher.apply_clip_skip(text_encoder_info.context.model, clip_field.skipped_layers), text_encoder_info as text_encoder, + # Apply the LoRA after text_encoder has been moved to its target device for faster patching. + ModelPatcher.apply_lora(text_encoder, _lora_loader(), lora_prefix), ): compel = Compel( tokenizer=tokenizer, diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index a537972c0b..56c13e6816 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -710,9 +710,10 @@ class DenoiseLatentsInvocation(BaseInvocation): ) with ( ExitStack() as exit_stack, - ModelPatcher.apply_lora_unet(unet_info.context.model, _lora_loader()), set_seamless(unet_info.context.model, self.unet.seamless_axes), unet_info as unet, + # Apply the LoRA after unet has been moved to its target device for faster patching. + ModelPatcher.apply_lora_unet(unet, _lora_loader()), ): latents = latents.to(device=unet.device, dtype=unet.dtype) if noise is not None: diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index e4f5aeb98e..eb6c50bf0d 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -112,20 +112,34 @@ class ModelPatcher: continue module_key, module = cls._resolve_lora_key(model, layer_key, prefix) - if module_key not in original_weights: - original_weights[module_key] = module.weight.detach().to(device="cpu", copy=True) - # enable autocast to calc fp16 loras on cpu - # with torch.autocast(device_type="cpu"): + # All of the LoRA weight calculations will be done on the same device as the module weight. + # (Performance will be best if this is a CUDA device.) + device = module.weight.device + dtype = module.weight.dtype + + if module_key not in original_weights: + original_weights[module_key] = module.weight.to(device="cpu") + + # We intentionally move to the device first, then cast. Experimentally, this was found to + # be significantly faster for 16-bit CPU tensors being moved to a CUDA device than doing the + # same thing in a single call to '.to(...)'. + tmp_weight = module.weight.to(device=device, copy=True).to(dtype=torch.float32) + + # We intentionally move to the target device first, then cast. Experimentally, this was found to + # be significantly faster for 16-bit CPU tensors being moved to a CUDA device than doing the + # same thing in a single call to '.to(...)'. + layer.to(device=device) layer.to(dtype=torch.float32) layer_scale = layer.alpha / layer.rank if (layer.alpha and layer.rank) else 1.0 - layer_weight = layer.get_weight(original_weights[module_key]) * lora_weight * layer_scale + layer_weight = layer.get_weight(tmp_weight) * (lora_weight * layer_scale) + layer.to(device="cpu") if module.weight.shape != layer_weight.shape: # TODO: debug on lycoris layer_weight = layer_weight.reshape(module.weight.shape) - module.weight += layer_weight.to(device=module.weight.device, dtype=module.weight.dtype) + module.weight = torch.nn.Parameter((tmp_weight + layer_weight).to(dtype=dtype)) yield # wait for context manager exit From 61b17c475ae256b991efd795e55d06625d978320 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 1 Nov 2023 09:34:52 -0400 Subject: [PATCH 098/119] Add TODO note about improving _resolve_lora_key(...). --- invokeai/backend/model_management/lora.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index eb6c50bf0d..1eaaa22adc 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -111,6 +111,13 @@ class ModelPatcher: if not layer_key.startswith(prefix): continue + # TODO(ryand): A non-negligible amount of time is currently spent resolving LoRA keys. This + # should be improved in the following ways: + # 1. The key mapping could be more-efficiently pre-computed. This would save time every time a + # LoRA model is applied. + # 2. From an API perspective, there's no reason that the `ModelPatcher` should be aware of the + # intricacies of Stable Diffusion key resolution. It should just expect the input LoRA + # weights to have valid keys. module_key, module = cls._resolve_lora_key(model, layer_key, prefix) # All of the LoRA weight calculations will be done on the same device as the module weight. From e92b84955c65fe4a17edf69edc8aa3f19f92e3f5 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 1 Nov 2023 10:52:51 -0400 Subject: [PATCH 099/119] Add minimal unit tests for ModelPatcher.apply_lora(...) --- tests/backend/model_management/test_lora.py | 102 ++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/backend/model_management/test_lora.py diff --git a/tests/backend/model_management/test_lora.py b/tests/backend/model_management/test_lora.py new file mode 100644 index 0000000000..14bcc87c89 --- /dev/null +++ b/tests/backend/model_management/test_lora.py @@ -0,0 +1,102 @@ +# test that if the model's device changes while the lora is applied, the weights can still be restored + +# test that LoRA patching works on both CPU and CUDA + +import pytest +import torch + +from invokeai.backend.model_management.lora import ModelPatcher +from invokeai.backend.model_management.models.lora import LoRALayer, LoRAModelRaw + + +@pytest.mark.parametrize( + "device", + [ + "cpu", + pytest.param("cuda", marks=pytest.mark.skipif(not torch.cuda.is_available(), reason="requires CUDA device")), + ], +) +@torch.no_grad() +def test_apply_lora(device): + """Test the basic behavior of ModelPatcher.apply_lora(...). Check that patching and unpatching produce the correct + result, and that model/LoRA tensors are moved between devices as expected. + """ + + linear_in_features = 4 + linear_out_features = 8 + lora_dim = 2 + model = torch.nn.ModuleDict( + {"linear_layer_1": torch.nn.Linear(linear_in_features, linear_out_features, device=device, dtype=torch.float16)} + ) + + lora_layers = { + "linear_layer_1": LoRALayer( + layer_key="linear_layer_1", + values={ + "lora_down.weight": torch.ones((lora_dim, linear_in_features), device="cpu", dtype=torch.float16), + "lora_up.weight": torch.ones((linear_out_features, lora_dim), device="cpu", dtype=torch.float16), + }, + ) + } + lora = LoRAModelRaw("lora_name", lora_layers) + + lora_weight = 0.5 + orig_linear_weight = model["linear_layer_1"].weight.data.detach().clone() + expected_patched_linear_weight = orig_linear_weight + (lora_dim * lora_weight) + + with ModelPatcher.apply_lora(model, [(lora, lora_weight)], prefix=""): + # After patching, all LoRA layer weights should have been moved back to the cpu. + assert lora_layers["linear_layer_1"].up.device.type == "cpu" + assert lora_layers["linear_layer_1"].down.device.type == "cpu" + + # After patching, the patched model should still be on its original device. + assert model["linear_layer_1"].weight.data.device.type == device + + torch.testing.assert_close(model["linear_layer_1"].weight.data, expected_patched_linear_weight) + + # After unpatching, the original model weights should have been restored on the original device. + assert model["linear_layer_1"].weight.data.device.type == device + torch.testing.assert_close(model["linear_layer_1"].weight.data, orig_linear_weight) + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason="requires CUDA device") +@torch.no_grad() +def test_apply_lora_change_device(): + """Test that if LoRA patching is applied on the CPU, and then the patched model is moved to the GPU, unpatching + still behaves correctly. + """ + linear_in_features = 4 + linear_out_features = 8 + lora_dim = 2 + # Initialize the model on the CPU. + model = torch.nn.ModuleDict( + {"linear_layer_1": torch.nn.Linear(linear_in_features, linear_out_features, device="cpu", dtype=torch.float16)} + ) + + lora_layers = { + "linear_layer_1": LoRALayer( + layer_key="linear_layer_1", + values={ + "lora_down.weight": torch.ones((lora_dim, linear_in_features), device="cpu", dtype=torch.float16), + "lora_up.weight": torch.ones((linear_out_features, lora_dim), device="cpu", dtype=torch.float16), + }, + ) + } + lora = LoRAModelRaw("lora_name", lora_layers) + + orig_linear_weight = model["linear_layer_1"].weight.data.detach().clone() + + with ModelPatcher.apply_lora(model, [(lora, 0.5)], prefix=""): + # After patching, all LoRA layer weights should have been moved back to the cpu. + assert lora_layers["linear_layer_1"].up.device.type == "cpu" + assert lora_layers["linear_layer_1"].down.device.type == "cpu" + + # After patching, the patched model should still be on the CPU. + assert model["linear_layer_1"].weight.data.device.type == "cpu" + + # Move the model to the GPU. + assert model.to("cuda") + + # After unpatching, the original model weights should have been restored on the GPU. + assert model["linear_layer_1"].weight.data.device.type == "cuda" + torch.testing.assert_close(model["linear_layer_1"].weight.data, orig_linear_weight, check_device=False) From fa7f6a6a10f01b496bbb384462918c85279bc404 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 1 Nov 2023 11:45:39 -0400 Subject: [PATCH 100/119] Further tidying of LoRA patching. Revert some changes that didn't end up being important under the constraint that calculations are done on the same device as the model. --- invokeai/backend/model_management/lora.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index 1eaaa22adc..5002f278cc 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -126,27 +126,25 @@ class ModelPatcher: dtype = module.weight.dtype if module_key not in original_weights: - original_weights[module_key] = module.weight.to(device="cpu") + original_weights[module_key] = module.weight.detach().to(device="cpu", copy=True) - # We intentionally move to the device first, then cast. Experimentally, this was found to - # be significantly faster for 16-bit CPU tensors being moved to a CUDA device than doing the - # same thing in a single call to '.to(...)'. - tmp_weight = module.weight.to(device=device, copy=True).to(dtype=torch.float32) + layer_scale = layer.alpha / layer.rank if (layer.alpha and layer.rank) else 1.0 # We intentionally move to the target device first, then cast. Experimentally, this was found to # be significantly faster for 16-bit CPU tensors being moved to a CUDA device than doing the # same thing in a single call to '.to(...)'. layer.to(device=device) layer.to(dtype=torch.float32) - layer_scale = layer.alpha / layer.rank if (layer.alpha and layer.rank) else 1.0 - layer_weight = layer.get_weight(tmp_weight) * (lora_weight * layer_scale) + # TODO(ryand): Using torch.autocast(...) over explicit casting may offer a speed benefit on CUDA + # devices here. Experimentally, it was found to be very slow on CPU. More investigation needed. + layer_weight = layer.get_weight(module.weight) * (lora_weight * layer_scale) layer.to(device="cpu") if module.weight.shape != layer_weight.shape: # TODO: debug on lycoris layer_weight = layer_weight.reshape(module.weight.shape) - module.weight = torch.nn.Parameter((tmp_weight + layer_weight).to(dtype=dtype)) + module.weight += layer_weight.to(dtype=dtype) yield # wait for context manager exit From bac2a757e8f77d875cd3356f58a52dc0ea3ad518 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 15:49:44 -0400 Subject: [PATCH 101/119] Replace deepcopy with a pickle roundtrip in apply_ti(...) to improve speed. --- invokeai/backend/model_management/lora.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/model_management/lora.py b/invokeai/backend/model_management/lora.py index 5002f278cc..2a0e465e03 100644 --- a/invokeai/backend/model_management/lora.py +++ b/invokeai/backend/model_management/lora.py @@ -1,6 +1,6 @@ from __future__ import annotations -import copy +import pickle from contextlib import contextmanager from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union @@ -165,7 +165,13 @@ class ModelPatcher: new_tokens_added = None try: - ti_tokenizer = copy.deepcopy(tokenizer) + # HACK: The CLIPTokenizer API does not include a way to remove tokens after calling add_tokens(...). As a + # workaround, we create a full copy of `tokenizer` so that its original behavior can be restored after + # exiting this `apply_ti(...)` context manager. + # + # In a previous implementation, the deep copy was obtained with `ti_tokenizer = copy.deepcopy(tokenizer)`, + # but a pickle roundtrip was found to be much faster (1 sec vs. 0.05 secs). + ti_tokenizer = pickle.loads(pickle.dumps(tokenizer)) ti_manager = TextualInversionManager(ti_tokenizer) init_tokens_count = text_encoder.resize_token_embeddings(None).num_embeddings @@ -439,7 +445,13 @@ class ONNXModelPatcher: orig_embeddings = None try: - ti_tokenizer = copy.deepcopy(tokenizer) + # HACK: The CLIPTokenizer API does not include a way to remove tokens after calling add_tokens(...). As a + # workaround, we create a full copy of `tokenizer` so that its original behavior can be restored after + # exiting this `apply_ti(...)` context manager. + # + # In a previous implementation, the deep copy was obtained with `ti_tokenizer = copy.deepcopy(tokenizer)`, + # but a pickle roundtrip was found to be much faster (1 sec vs. 0.05 secs). + ti_tokenizer = pickle.loads(pickle.dumps(tokenizer)) ti_manager = TextualInversionManager(ti_tokenizer) def _get_trigger(ti_name, index): From 8ff49109a8881d1306b146a5249c8eccbd402aad Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 11:55:24 -0400 Subject: [PATCH 102/119] Update get_pretty_snapshot_diff(...) to handle None-snapshots. --- invokeai/backend/model_management/memory_snapshot.py | 5 ++++- .../backend/model_management/test_memory_snapshot.py | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/invokeai/backend/model_management/memory_snapshot.py b/invokeai/backend/model_management/memory_snapshot.py index 01f1328114..fe54af191c 100644 --- a/invokeai/backend/model_management/memory_snapshot.py +++ b/invokeai/backend/model_management/memory_snapshot.py @@ -64,7 +64,7 @@ class MemorySnapshot: return cls(process_ram, vram, malloc_info) -def get_pretty_snapshot_diff(snapshot_1: MemorySnapshot, snapshot_2: MemorySnapshot) -> str: +def get_pretty_snapshot_diff(snapshot_1: Optional[MemorySnapshot], snapshot_2: Optional[MemorySnapshot]) -> str: """Get a pretty string describing the difference between two `MemorySnapshot`s.""" def get_msg_line(prefix: str, val1: int, val2: int): @@ -73,6 +73,9 @@ def get_pretty_snapshot_diff(snapshot_1: MemorySnapshot, snapshot_2: MemorySnaps msg = "" + if snapshot_1 is None or snapshot_2 is None: + return msg + msg += get_msg_line("Process RAM", snapshot_1.process_ram, snapshot_2.process_ram) if snapshot_1.malloc_info is not None and snapshot_2.malloc_info is not None: diff --git a/tests/backend/model_management/test_memory_snapshot.py b/tests/backend/model_management/test_memory_snapshot.py index 80aed7b7ba..dcbb173e96 100644 --- a/tests/backend/model_management/test_memory_snapshot.py +++ b/tests/backend/model_management/test_memory_snapshot.py @@ -17,6 +17,7 @@ snapshots = [ MemorySnapshot(process_ram=1.0, vram=2.0, malloc_info=None), MemorySnapshot(process_ram=1.0, vram=None, malloc_info=Struct_mallinfo2()), MemorySnapshot(process_ram=1.0, vram=None, malloc_info=None), + None, ] @@ -26,10 +27,12 @@ def test_get_pretty_snapshot_diff(snapshot_1, snapshot_2): """Test that get_pretty_snapshot_diff() works with various combinations of missing MemorySnapshot fields.""" msg = get_pretty_snapshot_diff(snapshot_1, snapshot_2) - expected_lines = 1 - if snapshot_1.vram is not None and snapshot_2.vram is not None: + expected_lines = 0 + if snapshot_1 is not None and snapshot_2 is not None: expected_lines += 1 - if snapshot_1.malloc_info is not None and snapshot_2.malloc_info is not None: - expected_lines += 5 + if snapshot_1.vram is not None and snapshot_2.vram is not None: + expected_lines += 1 + if snapshot_1.malloc_info is not None and snapshot_2.malloc_info is not None: + expected_lines += 5 assert len(msg.splitlines()) == expected_lines From 267e709ba2d963f722f1571afaf5188ef5770ad1 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 11:56:38 -0400 Subject: [PATCH 103/119] (minor) Fix int literal typing error. --- tests/backend/model_management/test_memory_snapshot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/backend/model_management/test_memory_snapshot.py b/tests/backend/model_management/test_memory_snapshot.py index dcbb173e96..216cd62171 100644 --- a/tests/backend/model_management/test_memory_snapshot.py +++ b/tests/backend/model_management/test_memory_snapshot.py @@ -13,10 +13,10 @@ def test_memory_snapshot_capture(): snapshots = [ - MemorySnapshot(process_ram=1.0, vram=2.0, malloc_info=Struct_mallinfo2()), - MemorySnapshot(process_ram=1.0, vram=2.0, malloc_info=None), - MemorySnapshot(process_ram=1.0, vram=None, malloc_info=Struct_mallinfo2()), - MemorySnapshot(process_ram=1.0, vram=None, malloc_info=None), + MemorySnapshot(process_ram=1, vram=2, malloc_info=Struct_mallinfo2()), + MemorySnapshot(process_ram=1, vram=2, malloc_info=None), + MemorySnapshot(process_ram=1, vram=None, malloc_info=Struct_mallinfo2()), + MemorySnapshot(process_ram=1, vram=None, malloc_info=None), None, ] From 3781e56e573e9d12f3c3bb5beae4abcf8609f6b9 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 12:00:07 -0400 Subject: [PATCH 104/119] Add log_memory_usage param to ModelCache. --- .../backend/model_management/model_cache.py | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index 2a6079b2c4..baf232df66 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -117,6 +117,7 @@ class ModelCache(object): lazy_offloading: bool = True, sha_chunksize: int = 16777216, logger: types.ModuleType = logger, + log_memory_usage: bool = False, ): """ :param max_cache_size: Maximum size of the RAM cache [6.0 GB] @@ -126,6 +127,10 @@ class ModelCache(object): :param lazy_offloading: Keep model in VRAM until another model needs to be loaded :param sequential_offload: Conserve VRAM by loading and unloading each stage of the pipeline sequentially :param sha_chunksize: Chunksize to use when calculating sha256 model hash + :param log_memory_usage: If True, a memory snapshot will be captured before and after every model cache + operation, and the result will be logged (at debug level). There is a time cost to capturing the memory + snapshots, so it is recommended to disable this feature unless you are actively inspecting the model cache's + behaviour. """ self.model_infos: Dict[str, ModelBase] = dict() # allow lazy offloading only when vram cache enabled @@ -137,6 +142,7 @@ class ModelCache(object): self.storage_device: torch.device = storage_device self.sha_chunksize = sha_chunksize self.logger = logger + self._log_memory_usage = log_memory_usage # used for stats collection self.stats = None @@ -144,6 +150,11 @@ class ModelCache(object): self._cached_models = dict() self._cache_stack = list() + def _capture_memory_snapshot(self) -> Optional[MemorySnapshot]: + if self._log_memory_usage: + return MemorySnapshot.capture() + return None + def get_key( self, model_path: str, @@ -223,10 +234,10 @@ class ModelCache(object): # Load the model from disk and capture a memory snapshot before/after. start_load_time = time.time() - snapshot_before = MemorySnapshot.capture() + snapshot_before = self._capture_memory_snapshot() with skip_torch_weight_init(): model = model_info.get_model(child_type=submodel, torch_dtype=self.precision) - snapshot_after = MemorySnapshot.capture() + snapshot_after = self._capture_memory_snapshot() end_load_time = time.time() self_reported_model_size_after_load = model_info.get_size(submodel) @@ -275,9 +286,9 @@ class ModelCache(object): return start_model_to_time = time.time() - snapshot_before = MemorySnapshot.capture() + snapshot_before = self._capture_memory_snapshot() cache_entry.model.to(target_device) - snapshot_after = MemorySnapshot.capture() + snapshot_after = self._capture_memory_snapshot() end_model_to_time = time.time() self.logger.debug( f"Moved model '{key}' from {source_device} to" @@ -286,7 +297,12 @@ class ModelCache(object): f"{get_pretty_snapshot_diff(snapshot_before, snapshot_after)}" ) - if snapshot_before.vram is not None and snapshot_after.vram is not None: + if ( + snapshot_before is not None + and snapshot_after is not None + and snapshot_before.vram is not None + and snapshot_after.vram is not None + ): vram_change = abs(snapshot_before.vram - snapshot_after.vram) # If the estimated model size does not match the change in VRAM, log a warning. From 4a683cc669992bb23ff43bea48799aa879e2d3cf Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 12:07:48 -0400 Subject: [PATCH 105/119] Add a app config parameter to control the ModelCache logging behavior. --- invokeai/app/services/config/config_default.py | 3 +++ invokeai/backend/model_management/model_manager.py | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index a877c465d2..23436a9172 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -45,6 +45,7 @@ InvokeAI: ram: 13.5 vram: 0.25 lazy_offload: true + log_memory_usage: false Device: device: auto precision: auto @@ -261,6 +262,8 @@ class InvokeAIAppConfig(InvokeAISettings): ram : float = Field(default=7.5, gt=0, description="Maximum memory amount used by model cache for rapid switching (floating point number, GB)", json_schema_extra=Categories.ModelCache, ) vram : float = Field(default=0.25, ge=0, description="Amount of VRAM reserved for model storage (floating point number, GB)", json_schema_extra=Categories.ModelCache, ) lazy_offload : bool = Field(default=True, description="Keep models in VRAM until their space is needed", json_schema_extra=Categories.ModelCache, ) + log_memory_usage : bool = Field(default=False, description="If True, a memory snapshot will be captured before and after every model cache operation, and the result will be logged (at debug level). There is a time cost to capturing the memory snapshots, so it is recommended to only enable this feature unless you are actively inspecting the model cache's behaviour.", json_schema_extra=Categories.ModelCache) + # DEVICE device : Literal["auto", "cpu", "cuda", "cuda:1", "mps"] = Field(default="auto", description="Generation device", json_schema_extra=Categories.Device) diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index 9390c8ce54..e63b559970 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -351,6 +351,7 @@ class ModelManager(object): precision=precision, sequential_offload=sequential_offload, logger=logger, + log_memory_usage=self.app_config.log_memory_usage, ) self._read_models(config) @@ -933,8 +934,7 @@ class ModelManager(object): """ Returns the preamble for the config file. """ - return textwrap.dedent( - """ + return textwrap.dedent(""" # This file describes the alternative machine learning models # available to InvokeAI script. # @@ -942,8 +942,7 @@ class ModelManager(object): # model requires a model config file, a weights file, # and the width and height of the images it # was trained on. - """ - ) + """) def scan_models_directory( self, From 6e7a3f05467c45a5418405ac4ff01412cd8b6c2d Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 13:31:10 -0400 Subject: [PATCH 106/119] (minor) Fix static checks and typo. --- invokeai/app/services/config/config_default.py | 3 +-- invokeai/backend/model_management/model_manager.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index 23436a9172..f0e9dbcda4 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -262,8 +262,7 @@ class InvokeAIAppConfig(InvokeAISettings): ram : float = Field(default=7.5, gt=0, description="Maximum memory amount used by model cache for rapid switching (floating point number, GB)", json_schema_extra=Categories.ModelCache, ) vram : float = Field(default=0.25, ge=0, description="Amount of VRAM reserved for model storage (floating point number, GB)", json_schema_extra=Categories.ModelCache, ) lazy_offload : bool = Field(default=True, description="Keep models in VRAM until their space is needed", json_schema_extra=Categories.ModelCache, ) - log_memory_usage : bool = Field(default=False, description="If True, a memory snapshot will be captured before and after every model cache operation, and the result will be logged (at debug level). There is a time cost to capturing the memory snapshots, so it is recommended to only enable this feature unless you are actively inspecting the model cache's behaviour.", json_schema_extra=Categories.ModelCache) - + log_memory_usage : bool = Field(default=False, description="If True, a memory snapshot will be captured before and after every model cache operation, and the result will be logged (at debug level). There is a time cost to capturing the memory snapshots, so it is recommended to only enable this feature if you are actively inspecting the model cache's behaviour.", json_schema_extra=Categories.ModelCache) # DEVICE device : Literal["auto", "cpu", "cuda", "cuda:1", "mps"] = Field(default="auto", description="Generation device", json_schema_extra=Categories.Device) diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index e63b559970..da4239fa07 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -934,7 +934,8 @@ class ModelManager(object): """ Returns the preamble for the config file. """ - return textwrap.dedent(""" + return textwrap.dedent( + """ # This file describes the alternative machine learning models # available to InvokeAI script. # @@ -942,7 +943,8 @@ class ModelManager(object): # model requires a model config file, a weights file, # and the width and height of the images it # was trained on. - """) + """ + ) def scan_models_directory( self, From e391f3c9a80224646ed6f8ad5d80d970fbf52ce7 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Thu, 2 Nov 2023 11:03:16 -0400 Subject: [PATCH 107/119] Skip torch.nn.Embedding.reset_parameters(...) when loading a text encoder model. --- .../backend/model_management/model_load_optimizations.py | 2 +- .../model_management/test_model_load_optimization.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/model_management/model_load_optimizations.py b/invokeai/backend/model_management/model_load_optimizations.py index f835079213..8dc8a8793e 100644 --- a/invokeai/backend/model_management/model_load_optimizations.py +++ b/invokeai/backend/model_management/model_load_optimizations.py @@ -17,7 +17,7 @@ def skip_torch_weight_init(): completely unnecessary if the intent is to load checkpoint weights from disk for the layer. This context manager monkey-patches common torch layers to skip the weight initialization step. """ - torch_modules = [torch.nn.Linear, torch.nn.modules.conv._ConvNd] + torch_modules = [torch.nn.Linear, torch.nn.modules.conv._ConvNd, torch.nn.Embedding] saved_functions = [m.reset_parameters for m in torch_modules] try: diff --git a/tests/backend/model_management/test_model_load_optimization.py b/tests/backend/model_management/test_model_load_optimization.py index 43f007e972..a4fe1dd597 100644 --- a/tests/backend/model_management/test_model_load_optimization.py +++ b/tests/backend/model_management/test_model_load_optimization.py @@ -11,6 +11,7 @@ from invokeai.backend.model_management.model_load_optimizations import _no_op, s (torch.nn.Conv1d, {"in_channels": 10, "out_channels": 20, "kernel_size": 3}), (torch.nn.Conv2d, {"in_channels": 10, "out_channels": 20, "kernel_size": 3}), (torch.nn.Conv3d, {"in_channels": 10, "out_channels": 20, "kernel_size": 3}), + (torch.nn.Embedding, {"num_embeddings": 10, "embedding_dim": 10}), ], ) def test_skip_torch_weight_init_linear(torch_module, layer_args): @@ -36,12 +37,14 @@ def test_skip_torch_weight_init_linear(torch_module, layer_args): # Check that reset_parameters is skipped while `skip_torch_weight_init()` is active. assert reset_params_fn_during == _no_op assert not torch.allclose(layer_before.weight, layer_during.weight) - assert not torch.allclose(layer_before.bias, layer_during.bias) + if hasattr(layer_before, "bias"): + assert not torch.allclose(layer_before.bias, layer_during.bias) # Check that the original behavior is restored after `skip_torch_weight_init()` ends. assert reset_params_fn_before is reset_params_fn_after assert torch.allclose(layer_before.weight, layer_after.weight) - assert torch.allclose(layer_before.bias, layer_after.bias) + if hasattr(layer_before, "bias"): + assert torch.allclose(layer_before.bias, layer_after.bias) def test_skip_torch_weight_init_restores_base_class_behavior(): From 3d32ce2b58dd81462d8f71d73b67c8e3cb7fc2d0 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 31 Oct 2023 22:19:39 -0500 Subject: [PATCH 108/119] fix(ui): hide refiner collapse if refiner not installed --- .../features/sdxl/components/ParamSDXLRefinerCollapse.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx index 6ac3034834..395ef302ed 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx @@ -14,6 +14,7 @@ import ParamSDXLRefinerStart from './SDXLRefiner/ParamSDXLRefinerStart'; import ParamSDXLRefinerSteps from './SDXLRefiner/ParamSDXLRefinerSteps'; import ParamUseSDXLRefiner from './SDXLRefiner/ParamUseSDXLRefiner'; import { useTranslation } from 'react-i18next'; +import { useIsRefinerAvailable } from 'services/api/hooks/useIsRefinerAvailable'; const selector = createSelector( stateSelector, @@ -31,6 +32,11 @@ const selector = createSelector( const ParamSDXLRefinerCollapse = () => { const { activeLabel, shouldUseSliders } = useAppSelector(selector); const { t } = useTranslation(); + const isRefinerAvailable = useIsRefinerAvailable(); + + if (!isRefinerAvailable) { + return null; + } return ( From 5b420653f97ede5d96f3bb09f4bdb16eedf0bd10 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 1 Nov 2023 20:27:28 -0500 Subject: [PATCH 109/119] feat(ui): show placeholder in refiner collapse instead of hiding it, if no refiner models installed --- invokeai/frontend/web/public/locales/en.json | 4 +++- .../src/features/lora/components/ParamLoraSelect.tsx | 5 +++-- .../sdxl/components/ParamSDXLRefinerCollapse.tsx | 12 ++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 04d817428c..564ed174a8 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -722,7 +722,9 @@ "noMatchingModels": "No matching Models", "noModelsAvailable": "No models available", "selectLoRA": "Select a LoRA", - "selectModel": "Select a Model" + "selectModel": "Select a Model", + "noLoRAsInstalled": "No LoRAs installed", + "noRefinerModelsInstalled": "No SDXL Refiner models installed" }, "nodes": { "addNode": "Add Node", diff --git a/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx b/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx index ef90e14656..6048e4a159 100644 --- a/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx +++ b/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx @@ -10,6 +10,7 @@ import { loraAdded } from 'features/lora/store/loraSlice'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { forEach } from 'lodash-es'; import { memo, useCallback, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useGetLoRAModelsQuery } from 'services/api/endpoints/models'; const selector = createSelector( @@ -24,7 +25,7 @@ const ParamLoRASelect = () => { const dispatch = useAppDispatch(); const { loras } = useAppSelector(selector); const { data: loraModels } = useGetLoRAModelsQuery(); - + const { t } = useTranslation(); const currentMainModel = useAppSelector( (state: RootState) => state.generation.model ); @@ -79,7 +80,7 @@ const ParamLoRASelect = () => { return ( - No LoRAs Loaded + {t('models.noLoRAsInstalled')} ); diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx index 395ef302ed..ac33891a6c 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx @@ -1,4 +1,4 @@ -import { Flex } from '@chakra-ui/react'; +import { Flex, Text } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppSelector } from 'app/store/storeHooks'; @@ -35,7 +35,15 @@ const ParamSDXLRefinerCollapse = () => { const isRefinerAvailable = useIsRefinerAvailable(); if (!isRefinerAvailable) { - return null; + return ( + + + + {t('models.noRefinerModelsInstalled')} + + + + ); } return ( From 43b300498f9802493fa61cbe4d17e9e7105813c7 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 3 Nov 2023 11:08:09 -0400 Subject: [PATCH 110/119] Remove explicit gc.collect() after transferring models from device to CPU. I'm not sure why this was there in the first place, but it was taking a significant amount of time (up to ~1sec in my tests). --- invokeai/backend/model_management/model_cache.py | 1 - 1 file changed, 1 deletion(-) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index baf232df66..7a162e3f99 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -507,7 +507,6 @@ class ModelCache(object): vram_in_use = torch.cuda.memory_allocated() self.logger.debug(f"{(vram_in_use/GIG):.2f}GB VRAM used for models; max allowed={(reserved/GIG):.2f}GB") - gc.collect() torch.cuda.empty_cache() if choose_torch_device() == torch.device("mps"): mps.empty_cache() From 875231ed3d1a32f1141aaf38d33f491c3ce69273 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 3 Nov 2023 15:14:04 -0400 Subject: [PATCH 111/119] Add reminder to clean up our model cache clearing logic. --- invokeai/backend/model_management/model_cache.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index 7a162e3f99..1c3ad06e8e 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -444,6 +444,10 @@ class ModelCache(object): refs = sys.getrefcount(cache_entry.model) + # HACK: This is a workaround for a memory-management issue that we haven't tracked down yet. We are directly + # going against the advice in the Python docs by using `gc.get_referrers(...)` in this way: + # https://docs.python.org/3/library/gc.html#gc.get_referrers + # manualy clear local variable references of just finished function calls # for some reason python don't want to collect it even by gc.collect() immidiately if refs > 2: From 8488ab01347488d9a41b360aaad1658c2dab4b7a Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 3 Nov 2023 15:19:45 -0400 Subject: [PATCH 112/119] Reduce frequency that we call gc.collect() in the model cache. --- .../backend/model_management/model_cache.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index 1c3ad06e8e..2385fd9bec 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -438,6 +438,7 @@ class ModelCache(object): self.logger.debug(f"Before unloading: cached_models={len(self._cached_models)}") pos = 0 + models_cleared = 0 while current_size + bytes_needed > maximum_size and pos < len(self._cache_stack): model_key = self._cache_stack[pos] cache_entry = self._cached_models[model_key] @@ -482,6 +483,7 @@ class ModelCache(object): f"Unloading model {model_key} to free {(model_size/GIG):.2f} GB (-{(cache_entry.size/GIG):.2f} GB)" ) current_size -= cache_entry.size + models_cleared += 1 if self.stats: self.stats.cleared += 1 del self._cache_stack[pos] @@ -491,7 +493,20 @@ class ModelCache(object): else: pos += 1 - gc.collect() + if models_cleared < 0: + # There would likely be some 'garbage' to be collected regardless of whether a model was cleared or not, but + # there is a significant time cost to calling `gc.collect()`, so we want to use it sparingly. (The time cost + # is high even if no garbage gets collected.) + # + # Calling gc.collect(...) when a model is cleared seems like a good middle-ground: + # - If models had to be cleared, it's a signal that we are close to our memory limit. + # - If models were cleared, there's a good chance that there's a significant amount of garbage to be + # collected. + # + # Keep in mind that gc is only responsible for handling reference cycles. Most objects should be cleaned up + # immediately when their reference count hits 0. + gc.collect() + torch.cuda.empty_cache() if choose_torch_device() == torch.device("mps"): mps.empty_cache() From fb3d0c4b124ecf1e6fb46121f4c8a1ee2cee6cf6 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 3 Nov 2023 15:21:27 -0400 Subject: [PATCH 113/119] Fix bug in model cache reference count checking. --- invokeai/backend/model_management/model_cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index 2385fd9bec..0b2a8b8df7 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -474,11 +474,11 @@ class ModelCache(object): f" refs: {refs}" ) - # 2 refs: + # Expected refs: # 1 from cache_entry # 1 from getrefcount function # 1 from onnx runtime object - if not cache_entry.locked and refs <= 3 if "onnx" in model_key else 2: + if not cache_entry.locked and refs <= (3 if "onnx" in model_key else 2): self.logger.debug( f"Unloading model {model_key} to free {(model_size/GIG):.2f} GB (-{(cache_entry.size/GIG):.2f} GB)" ) From aa02ebf8f5c2f8a90737c5a9607fccb5bca00437 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Sat, 4 Nov 2023 08:52:10 -0400 Subject: [PATCH 114/119] Fix model cache gc.collect() condition. --- invokeai/backend/model_management/model_cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/backend/model_management/model_cache.py b/invokeai/backend/model_management/model_cache.py index 0b2a8b8df7..83af789219 100644 --- a/invokeai/backend/model_management/model_cache.py +++ b/invokeai/backend/model_management/model_cache.py @@ -493,7 +493,7 @@ class ModelCache(object): else: pos += 1 - if models_cleared < 0: + if models_cleared > 0: # There would likely be some 'garbage' to be collected regardless of whether a model was cleared or not, but # there is a significant time cost to calling `gc.collect()`, so we want to use it sparingly. (The time cost # is high even if no garbage gets collected.) From 5a821384d3b5390a2a62a6121c3be4306766bf14 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sat, 4 Nov 2023 11:12:29 -0400 Subject: [PATCH 115/119] fix model-not-found error --- invokeai/frontend/merge/merge_diffusers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/merge/merge_diffusers.py b/invokeai/frontend/merge/merge_diffusers.py index 51602b75d1..d515c5b4ee 100644 --- a/invokeai/frontend/merge/merge_diffusers.py +++ b/invokeai/frontend/merge/merge_diffusers.py @@ -274,9 +274,10 @@ class mergeModelsForm(npyscreen.FormMultiPageAction): else: interp = self.interpolations[self.merge_method.value[0]] + bases = ["sd-1", "sd-2", "sdxl"] args = dict( model_names=models, - base_model=tuple(BaseModelType)[self.base_select.value[0]], + base_model=BaseModelType(bases[self.base_select.value[0]]), alpha=self.alpha.value, interp=interp, force=self.force.value, From 6334c4adf52729076f15da2bfdbd9572e00c7269 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Sat, 4 Nov 2023 09:53:33 +0100 Subject: [PATCH 116/119] translationBot(ui): update translation (German) Currently translated at 53.8% (657 of 1219 strings) Co-authored-by: Alexander Eichhorn Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/de/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/de.json | 39 +++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index c06ad56492..4f91f84b35 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -83,13 +83,14 @@ "darkMode": "Dunkler Modus", "loading": "Lade", "random": "Zufall", - "batch": "Batch-Manager", + "batch": "Stapel-Manager", "advanced": "Erweitert", "langBrPortuguese": "Portugiesisch (Brasilien)", "unifiedCanvas": "Einheitliche Leinwand", "openInNewTab": "In einem neuem Tab öffnen", "statusProcessing": "wird bearbeitet", - "linear": "Linear" + "linear": "Linear", + "imagePrompt": "Bild Prompt" }, "gallery": { "generations": "Erzeugungen", @@ -655,7 +656,8 @@ "downloadBoard": "Ordner runterladen", "changeBoard": "Ordner wechseln", "loading": "Laden...", - "clearSearch": "Suche leeren" + "clearSearch": "Suche leeren", + "bottomMessage": "Durch das Löschen dieses Ordners und seiner Bilder werden alle Funktionen zurückgesetzt, die sie derzeit verwenden." }, "controlnet": { "showAdvanced": "Zeige Erweitert", @@ -704,7 +706,17 @@ "depthZoeDescription": "Tiefenmap erstellen mit Zoe", "setControlImageDimensions": "Setze Control Bild Auflösung auf Breite/Höhe", "handAndFace": "Hand und Gesicht", - "enableIPAdapter": "Aktiviere IP Adapter" + "enableIPAdapter": "Aktiviere IP Adapter", + "resize": "Größe ändern", + "resetControlImage": "Zurücksetzen vom Referenz Bild", + "balanced": "Ausgewogen", + "prompt": "Prompt", + "resizeMode": "Größenänderungsmodus", + "processor": "Prozessor", + "saveControlImage": "Speichere Referenz Bild", + "safe": "Speichern", + "ipAdapterImageFallback": "Kein IP Adapter Bild ausgewählt", + "resetIPAdapterImage": "Zurücksetzen vom IP Adapter Bild" }, "queue": { "status": "Status", @@ -734,7 +746,19 @@ "session": "Sitzung", "queueTotal": "{{total}} Gesamt", "resume": "Wieder aufnehmen", - "item": "Auftrag" + "item": "Auftrag", + "notReady": "Warteschlange noch nicht bereit", + "batchValues": "Stapel Werte", + "queueCountPrediction": "{{predicted}} zur Warteschlange hinzufügen", + "queuedCount": "{{pending}} wartenden Elemente", + "clearQueueAlertDialog": "Die Warteschlange leeren, stoppt den aktuellen Prozess und leert die Warteschlange komplett.", + "completedIn": "Fertig in", + "cancelBatchSucceeded": "Stapel abgebrochen", + "cancelBatch": "Stapel stoppen", + "enqueueing": "Stapel in der Warteschlange", + "queueMaxExceeded": "Maximum von {{max_queue_size}} Elementen erreicht, würde {{skip}} Elemente überspringen", + "cancelBatchFailed": "Problem beim Abbruch vom Stapel", + "clearQueueAlertDialog2": "bist du sicher die Warteschlange zu leeren?" }, "metadata": { "negativePrompt": "Negativ Beschreibung", @@ -788,5 +812,10 @@ "hits": "Cache Treffer", "enable": "Aktivieren", "clear": "Leeren" + }, + "embedding": { + "noMatchingEmbedding": "Keine passenden Embeddings", + "addEmbedding": "Embedding hinzufügen", + "incompatibleModel": "Inkompatibles Basismodell:" } } From 4e6b579526b6fc368fac4284e9ffbf700543ef61 Mon Sep 17 00:00:00 2001 From: Riccardo Giovanetti Date: Sat, 4 Nov 2023 09:53:33 +0100 Subject: [PATCH 117/119] translationBot(ui): update translation (Italian) Currently translated at 97.6% (1190 of 1219 strings) Co-authored-by: Riccardo Giovanetti Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/it/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/it.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index 49b258c95d..4815bc2482 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.json @@ -1192,7 +1192,9 @@ "noLoRAsAvailable": "Nessun LoRA disponibile", "noModelsAvailable": "Nessun modello disponibile", "selectModel": "Seleziona un modello", - "selectLoRA": "Seleziona un LoRA" + "selectLoRA": "Seleziona un LoRA", + "noRefinerModelsInstalled": "Nessun modello SDXL Refiner installato", + "noLoRAsInstalled": "Nessun LoRA installato" }, "invocationCache": { "disable": "Disabilita", From 7f650d00de9563da2b5c55b3ac184ed44fa96e77 Mon Sep 17 00:00:00 2001 From: Riccardo Giovanetti Date: Sun, 5 Nov 2023 14:42:41 +0100 Subject: [PATCH 118/119] translationBot(ui): update translation (Italian) Currently translated at 97.7% (1191 of 1219 strings) Co-authored-by: Riccardo Giovanetti Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/it/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/it.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index 4815bc2482..c358f415b2 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.json @@ -1025,7 +1025,8 @@ "imageFieldDescription": "Le immagini possono essere passate tra i nodi.", "unableToParseEdge": "Impossibile analizzare il bordo", "latentsCollectionDescription": "Le immagini latenti possono essere passate tra i nodi.", - "imageCollection": "Raccolta Immagini" + "imageCollection": "Raccolta Immagini", + "loRAModelField": "LoRA" }, "boards": { "autoAddBoard": "Aggiungi automaticamente bacheca", From 546aaedbe4b3cf85d370496a43c550287576341e Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:15:57 -0500 Subject: [PATCH 119/119] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c0d91cf330..89f4ea2b45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ dependencies = [ "datasets", # When bumping diffusers beyond 0.21, make sure to address this: # https://github.com/invoke-ai/InvokeAI/blob/fc09ab7e13cb7ca5389100d149b6422ace7b8ed3/invokeai/app/invocations/latent.py#L513 - "diffusers[torch]~=0.21.0", + "diffusers[torch]~=0.22.0", "dnspython~=2.4.0", "dynamicprompts", "easing-functions",