diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 9e58fb3ae0..5b7d2cd2fa 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -28,7 +28,7 @@ jobs: run: twine check dist/* - name: check PyPI versions - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2.3' || github.ref == 'refs/heads/v3.3.0post1' + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') run: | pip install --upgrade requests python -c "\ 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/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index 47ed407695..d5a5d5654f 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -8,28 +8,42 @@ 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 + + [Depth Map from Wavefront OBJ](#depth-map-from-wavefront-obj) + + [Film Grain](#film-grain) + + [Generative Grammar-Based Prompt Nodes](#generative-grammar-based-prompt-nodes) + + [GPT2RandomPromptMaker](#gpt2randompromptmaker) + + [Grid to Gif](#grid-to-gif) + + [Halftone](#halftone) + + [Ideal Size](#ideal-size) + + [Image and Mask Composition Pack](#image-and-mask-composition-pack) + + [Image to Character Art Image Nodes](#image-to-character-art-image-nodes) + + [Image Picker](#image-picker) + + [Load Video Frame](#load-video-frame) + + [Make 3D](#make-3d) + + [Oobabooga](#oobabooga) + + [Prompt Tools](#prompt-tools) + + [Retroize](#retroize) + + [Size Stepper Nodes](#size-stepper-nodes) + + [Text font to Image](#text-font-to-image) + + [Thresholding](#thresholding) + + [XY Image to Grid and Images to Grids nodes](#xy-image-to-grid-and-images-to-grids-nodes) +- [Example Node Template](#example-node-template) +- [Disclaimer](#disclaimer) +- [Help](#help) + -------------------------------- -### Make 3D +### Depth Map from Wavefront OBJ -**Description:** Create compelling 3D stereo images from 2D originals. +**Description:** Render depth maps from Wavefront .obj files (triangulated) using this simple 3D renderer utilizing numpy and matplotlib to compute and color the scene. There are simple parameters to change the FOV, camera position, and model orientation. -**Node Link:** [https://gitlab.com/srcrr/shift3d/-/raw/main/make3d.py](https://gitlab.com/srcrr/shift3d) +To be imported, an .obj must use triangulated meshes, so make sure to enable that option if exporting from a 3D modeling program. This renderer makes each triangle a solid color based on its average depth, so it will cause anomalies if your .obj has large triangles. In Blender, the Remesh modifier can be helpful to subdivide a mesh into small pieces that work well given these limitations. -**Example Node Graph:** https://gitlab.com/srcrr/shift3d/-/raw/main/example-workflow.json?ref_type=heads&inline=false +**Node Link:** https://github.com/dwringer/depth-from-obj-node -**Output Examples** - -![Painting of a cozy delapidated house](https://gitlab.com/srcrr/shift3d/-/raw/main/example-1.png){: style="height:512px;width:512px"} -![Photo of cute puppies](https://gitlab.com/srcrr/shift3d/-/raw/main/example-2.png){: style="height:512px;width:512px"} - --------------------------------- -### Ideal Size - -**Description:** This node calculates an ideal image size for a first pass of a multi-pass upscaling. The aim is to avoid duplication that results from choosing a size larger than the model is capable of. - -**Node Link:** https://github.com/JPPhoto/ideal-size-node +**Example Usage:** +
-------------------------------- ### Film Grain @@ -39,68 +53,19 @@ To use a community workflow, download the the `.json` node graph file and load i **Node Link:** https://github.com/JPPhoto/film-grain-node -------------------------------- -### Image Picker +### Generative Grammar-Based Prompt Nodes -**Description:** This InvokeAI node takes in a collection of images and randomly chooses one. This can be useful when you have a number of poses to choose from for a ControlNet node, or a number of input images for another purpose. +**Description:** This set of 3 nodes generates prompts from simple user-defined grammar rules (loaded from custom files - examples provided below). The prompts are made by recursively expanding a special template string, replacing nonterminal "parts-of-speech" until no nonterminal terms remain in the string. -**Node Link:** https://github.com/JPPhoto/image-picker-node +This includes 3 Nodes: +- *Lookup Table from File* - loads a YAML file "prompt" section (or of a whole folder of YAML's) into a JSON-ified dictionary (Lookups output) +- *Lookups Entry from Prompt* - places a single entry in a new Lookups output under the specified heading +- *Prompt from Lookup Table* - uses a Collection of Lookups as grammar rules from which to randomly generate prompts. --------------------------------- -### Thresholding +**Node Link:** https://github.com/dwringer/generative-grammar-prompt-nodes -**Description:** This node generates masks for highlights, midtones, and shadows given an input image. You can optionally specify a blur for the lookup table used in making those masks from the source image. - -**Node Link:** https://github.com/JPPhoto/thresholding-node - -**Examples** - -Input: - -![image](https://github.com/invoke-ai/InvokeAI/assets/34005131/c88ada13-fb3d-484c-a4fe-947b44712632){: style="height:512px;width:512px"} - -Highlights/Midtones/Shadows: - - - - - -Highlights/Midtones/Shadows (with LUT blur enabled): - - - - - --------------------------------- -### Halftone - -**Description**: Halftone converts the source image to grayscale and then performs halftoning. CMYK Halftone converts the image to CMYK and applies a per-channel halftoning to make the source image look like a magazine or newspaper. For both nodes, you can specify angles and halftone dot spacing. - -**Node Link:** https://github.com/JPPhoto/halftone-node - -**Example** - -Input: - -![image](https://github.com/invoke-ai/InvokeAI/assets/34005131/fd5efb9f-4355-4409-a1c2-c1ca99e0cab4){: style="height:512px;width:512px"} - -Halftone Output: - -![image](https://github.com/invoke-ai/InvokeAI/assets/34005131/7e606f29-e68f-4d46-b3d5-97f799a4ec2f){: style="height:512px;width:512px"} - -CMYK Halftone Output: - -![image](https://github.com/invoke-ai/InvokeAI/assets/34005131/c59c578f-db8e-4d66-8c66-2851752d75ea){: style="height:512px;width:512px"} - --------------------------------- -### Retroize - -**Description:** Retroize is a collection of nodes for InvokeAI to "Retroize" images. Any image can be given a fresh coat of retro paint with these nodes, either from your gallery or from within the graph itself. It includes nodes to pixelize, quantize, palettize, and ditherize images; as well as to retrieve palettes from existing images. - -**Node Link:** https://github.com/Ar7ific1al/invokeai-retroizeinode/ - -**Retroize Output Examples** - -![image](https://github.com/Ar7ific1al/InvokeAI_nodes_retroize/assets/2306586/de8b4fa6-324c-4c2d-b36c-297600c73974) +**Example Usage:** +
-------------------------------- ### GPT2RandomPromptMaker @@ -113,76 +78,49 @@ CMYK Halftone Output: Generated Prompt: An enchanted weapon will be usable by any character regardless of their alignment. -![9acf5aef-7254-40dd-95b3-8eac431dfab0 (1)](https://github.com/mickr777/InvokeAI/assets/115216705/8496ba09-bcdd-4ff7-8076-ff213b6a1e4c) + -------------------------------- -### Load Video Frame +### Grid to Gif -**Description:** This is a video frame image provider + indexer/video creation nodes for hooking up to iterators and ranges and ControlNets and such forĀ invokeAIĀ node experimentation. Think animation + ControlNet outputs. +**Description:** One node that turns a grid image into an image collection, one node that turns an image collection into a gif. -**Node Link:** https://github.com/helix4u/load_video_frame +**Node Link:** https://github.com/mildmisery/invokeai-GridToGifNode/blob/main/GridToGif.py -**Example Node Graph:** https://github.com/helix4u/load_video_frame/blob/main/Example_Workflow.json +**Example Node Graph:** https://github.com/mildmisery/invokeai-GridToGifNode/blob/main/Grid%20to%20Gif%20Example%20Workflow.json -**Output Example:** +**Output Examples** -![Example animation](https://github.com/helix4u/load_video_frame/blob/main/testmp4_embed_converted.gif) -[Full mp4 of Example Output test.mp4](https://github.com/helix4u/load_video_frame/blob/main/test.mp4) + + -------------------------------- +### Halftone -### Oobabooga +**Description**: Halftone converts the source image to grayscale and then performs halftoning. CMYK Halftone converts the image to CMYK and applies a per-channel halftoning to make the source image look like a magazine or newspaper. For both nodes, you can specify angles and halftone dot spacing. -**Description:** asks a local LLM running in Oobabooga's Text-Generation-Webui to write a prompt based on the user input. +**Node Link:** https://github.com/JPPhoto/halftone-node -**Link:** https://github.com/sammyf/oobabooga-node +**Example** +Input: -**Example:** + -"describe a new mystical creature in its natural environment" +Halftone Output: -*can return* + -"The mystical creature I am describing to you is called the "Glimmerwing". It is a majestic, iridescent being that inhabits the depths of the most enchanted forests and glimmering lakes. Its body is covered in shimmering scales that reflect every color of the rainbow, and it has delicate, translucent wings that sparkle like diamonds in the sunlight. The Glimmerwing's home is a crystal-clear lake, surrounded by towering trees with leaves that shimmer like jewels. In this serene environment, the Glimmerwing spends its days swimming gracefully through the water, chasing schools of glittering fish and playing with the gentle ripples of the lake's surface. -As the sun sets, the Glimmerwing perches on a branch of one of the trees, spreading its wings to catch the last rays of light. The creature's scales glow softly, casting a rainbow of colors across the forest floor. The Glimmerwing sings a haunting melody, its voice echoing through the stillness of the night air. Its song is said to have the power to heal the sick and bring peace to troubled souls. Those who are lucky enough to hear the Glimmerwing's song are forever changed by its beauty and grace." +CMYK Halftone Output: -![glimmerwing_small](https://github.com/sammyf/oobabooga-node/assets/42468608/cecdd820-93dd-4c35-abbf-607e001fb2ed) - -**Requirement** - -a Text-Generation-Webui instance (might work remotely too, but I never tried it) and obviously InvokeAI 3.x - -**Note** - -This node works best with SDXL models, especially as the style can be described independantly of the LLM's output. + -------------------------------- -### Depth Map from Wavefront OBJ +### Ideal Size -**Description:** Render depth maps from Wavefront .obj files (triangulated) using this simple 3D renderer utilizing numpy and matplotlib to compute and color the scene. There are simple parameters to change the FOV, camera position, and model orientation. +**Description:** This node calculates an ideal image size for a first pass of a multi-pass upscaling. The aim is to avoid duplication that results from choosing a size larger than the model is capable of. -To be imported, an .obj must use triangulated meshes, so make sure to enable that option if exporting from a 3D modeling program. This renderer makes each triangle a solid color based on its average depth, so it will cause anomalies if your .obj has large triangles. In Blender, the Remesh modifier can be helpful to subdivide a mesh into small pieces that work well given these limitations. - -**Node Link:** https://github.com/dwringer/depth-from-obj-node - -**Example Usage:** -![depth from obj usage graph](https://raw.githubusercontent.com/dwringer/depth-from-obj-node/main/depth_from_obj_usage.jpg) - --------------------------------- -### Generative Grammar-Based Prompt Nodes - -**Description:** This set of 3 nodes generates prompts from simple user-defined grammar rules (loaded from custom files - examples provided below). The prompts are made by recursively expanding a special template string, replacing nonterminal "parts-of-speech" until no more nonterminal terms remain in the string. - -This includes 3 Nodes: -- *Lookup Table from File* - loads a YAML file "prompt" section (or of a whole folder of YAML's) into a JSON-ified dictionary (Lookups output) -- *Lookups Entry from Prompt* - places a single entry in a new Lookups output under the specified heading -- *Prompt from Lookup Table* - uses a Collection of Lookups as grammar rules from which to randomly generate prompts. - -**Node Link:** https://github.com/dwringer/generative-grammar-prompt-nodes - -**Example Usage:** -![lookups usage example graph](https://raw.githubusercontent.com/dwringer/generative-grammar-prompt-nodes/main/lookuptables_usage.jpg) +**Node Link:** https://github.com/JPPhoto/ideal-size-node -------------------------------- ### Image and Mask Composition Pack @@ -208,45 +146,88 @@ This includes 15 Nodes: - *Text Mask (simple 2D)* - create and position a white on black (or black on white) line of text using any font locally available to Invoke. **Node Link:** https://github.com/dwringer/composition-nodes - -**Nodes and Output Examples:** -![composition nodes usage graph](https://raw.githubusercontent.com/dwringer/composition-nodes/main/composition_pack_overview.jpg) + +
-------------------------------- -### Size Stepper Nodes +### Image to Character Art Image Nodes -**Description:** This is a set of nodes for calculating the necessary size increments for doing upscaling workflows. Use the *Final Size & Orientation* node to enter your full size dimensions and orientation (portrait/landscape/random), then plug that and your initial generation dimensions into the *Ideal Size Stepper* and get 1, 2, or 3 intermediate pairs of dimensions for upscaling. Note this does not output the initial size or full size dimensions: the 1, 2, or 3 outputs of this node are only the intermediate sizes. +**Description:** Group of nodes to convert an input image into ascii/unicode art Image -A third node is included, *Random Switch (Integers)*, which is just a generic version of Final Size with no orientation selection. - -**Node Link:** https://github.com/dwringer/size-stepper-nodes - -**Example Usage:** -![size stepper usage graph](https://raw.githubusercontent.com/dwringer/size-stepper-nodes/main/size_nodes_usage.jpg) - --------------------------------- - -### Text font to Image - -**Description:** text font to text image node for InvokeAI, download a font to use (or if in font cache uses it from there), the text is always resized to the image size, but can control that with padding, optional 2nd line - -**Node Link:** https://github.com/mickr777/textfontimage +**Node Link:** https://github.com/mickr777/imagetoasciiimage **Output Examples** -![a3609d48-d9b7-41f0-b280-063d857986fb](https://github.com/mickr777/InvokeAI/assets/115216705/c21b0af3-d9c6-4c16-9152-846a23effd36) - -Results after using the depth controlnet - -![9133eabb-bcda-4326-831e-1b641228b178](https://github.com/mickr777/InvokeAI/assets/115216705/915f1a53-968e-43eb-aa61-07cd8f1a733a) -![4f9a3fa8-9be9-4236-8a3e-fcec66decd2a](https://github.com/mickr777/InvokeAI/assets/115216705/821ef89e-8a60-44f5-b94e-471a9d8690cc) -![babd69c4-9d60-4a55-a834-5e8397f62610](https://github.com/mickr777/InvokeAI/assets/115216705/2befcb6d-49f4-4bfd-b5fc-1fee19274f89) +
+ + -------------------------------- +### Image Picker + +**Description:** This InvokeAI node takes in a collection of images and randomly chooses one. This can be useful when you have a number of poses to choose from for a ControlNet node, or a number of input images for another purpose. + +**Node Link:** https://github.com/JPPhoto/image-picker-node + +-------------------------------- +### Load Video Frame + +**Description:** This is a video frame image provider + indexer/video creation nodes for hooking up to iterators and ranges and ControlNets and such for invokeAI node experimentation. Think animation + ControlNet outputs. + +**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 + +**Description:** Create compelling 3D stereo images from 2D originals. + +**Node Link:** [https://gitlab.com/srcrr/shift3d/-/raw/main/make3d.py](https://gitlab.com/srcrr/shift3d) + +**Example Node Graph:** https://gitlab.com/srcrr/shift3d/-/raw/main/example-workflow.json?ref_type=heads&inline=false + +**Output Examples** + + + + +-------------------------------- +### Oobabooga + +**Description:** asks a local LLM running in Oobabooga's Text-Generation-Webui to write a prompt based on the user input. + +**Link:** https://github.com/sammyf/oobabooga-node + +**Example:** + +"describe a new mystical creature in its natural environment" + +*can return* + +"The mystical creature I am describing to you is called the "Glimmerwing". It is a majestic, iridescent being that inhabits the depths of the most enchanted forests and glimmering lakes. Its body is covered in shimmering scales that reflect every color of the rainbow, and it has delicate, translucent wings that sparkle like diamonds in the sunlight. The Glimmerwing's home is a crystal-clear lake, surrounded by towering trees with leaves that shimmer like jewels. In this serene environment, the Glimmerwing spends its days swimming gracefully through the water, chasing schools of glittering fish and playing with the gentle ripples of the lake's surface. +As the sun sets, the Glimmerwing perches on a branch of one of the trees, spreading its wings to catch the last rays of light. The creature's scales glow softly, casting a rainbow of colors across the forest floor. The Glimmerwing sings a haunting melody, its voice echoing through the stillness of the night air. Its song is said to have the power to heal the sick and bring peace to troubled souls. Those who are lucky enough to hear the Glimmerwing's song are forever changed by its beauty and grace." + + + +**Requirement** + +a Text-Generation-Webui instance (might work remotely too, but I never tried it) and obviously InvokeAI 3.x + +**Note** + +This node works best with SDXL models, especially as the style can be described independently of the LLM's output. + +-------------------------------- ### Prompt Tools -**Description:** A set of InvokeAI nodes that add general prompt manipulation tools. These where written to accompany the PromptsFromFile node and other prompt generation nodes. +**Description:** A set of InvokeAI nodes that add general prompt manipulation tools. These were written to accompany the PromptsFromFile node and other prompt generation nodes. 1. PromptJoin - Joins to prompts into one. 2. PromptReplace - performs a search and replace on a prompt. With the option of using regex. @@ -263,51 +244,83 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai **Node Link:** https://github.com/skunkworxdark/Prompt-tools-nodes -------------------------------- +### Retroize +**Description:** Retroize is a collection of nodes for InvokeAI to "Retroize" images. Any image can be given a fresh coat of retro paint with these nodes, either from your gallery or from within the graph itself. It includes nodes to pixelize, quantize, palettize, and ditherize images; as well as to retrieve palettes from existing images. + +**Node Link:** https://github.com/Ar7ific1al/invokeai-retroizeinode/ + +**Retroize Output Examples** + + + +-------------------------------- +### Size Stepper Nodes + +**Description:** This is a set of nodes for calculating the necessary size increments for doing upscaling workflows. Use the *Final Size & Orientation* node to enter your full size dimensions and orientation (portrait/landscape/random), then plug that and your initial generation dimensions into the *Ideal Size Stepper* and get 1, 2, or 3 intermediate pairs of dimensions for upscaling. Note this does not output the initial size or full size dimensions: the 1, 2, or 3 outputs of this node are only the intermediate sizes. + +A third node is included, *Random Switch (Integers)*, which is just a generic version of Final Size with no orientation selection. + +**Node Link:** https://github.com/dwringer/size-stepper-nodes + +**Example Usage:** +
+ +-------------------------------- +### Text font to Image + +**Description:** text font to text image node for InvokeAI, download a font to use (or if in font cache uses it from there), the text is always resized to the image size, but can control that with padding, optional 2nd line + +**Node Link:** https://github.com/mickr777/textfontimage + +**Output Examples** + + + +Results after using the depth controlnet + + + + + +-------------------------------- +### Thresholding + +**Description:** This node generates masks for highlights, midtones, and shadows given an input image. You can optionally specify a blur for the lookup table used in making those masks from the source image. + +**Node Link:** https://github.com/JPPhoto/thresholding-node + +**Examples** + +Input: + + + +Highlights/Midtones/Shadows: + + + + + +Highlights/Midtones/Shadows (with LUT blur enabled): + + + + + +-------------------------------- ### XY Image to Grid and Images to Grids nodes **Description:** Image to grid nodes and supporting tools. -1. "Images To Grids" node - Takes a collection of images and creates a grid(s) of images. If there are more images than the size of a single grid then mutilple grids will be created until it runs out of images. -2. "XYImage To Grid" node - Converts a collection of XYImages into a labeled Grid of images. The XYImages collection has to be built using the supporoting nodes. See example node setups for more details. - +1. "Images To Grids" node - Takes a collection of images and creates a grid(s) of images. If there are more images than the size of a single grid then multiple grids will be created until it runs out of images. +2. "XYImage To Grid" node - Converts a collection of XYImages into a labeled Grid of images. The XYImages collection has to be built using the supporting nodes. See example node setups for more details. See full docs here: https://github.com/skunkworxdark/XYGrid_nodes/edit/main/README.md **Node Link:** https://github.com/skunkworxdark/XYGrid_nodes -------------------------------- - -### Image to Character Art Image Node's - -**Description:** Group of nodes to convert an input image into ascii/unicode art Image - -**Node Link:** https://github.com/mickr777/imagetoasciiimage - -**Output Examples** - - -
- - - --------------------------------- - -### Grid to Gif - -**Description:** One node that turns a grid image into an image colletion, one node that turns an image collection into a gif - -**Node Link:** https://github.com/mildmisery/invokeai-GridToGifNode/blob/main/GridToGif.py - -**Example Node Graph:** https://github.com/mildmisery/invokeai-GridToGifNode/blob/main/Grid%20to%20Gif%20Example%20Workflow.json - -**Output Examples** - - - - --------------------------------- - ### Example Node Template **Description:** This node allows you to do super cool things with InvokeAI. @@ -318,7 +331,7 @@ See full docs here: https://github.com/skunkworxdark/XYGrid_nodes/edit/main/READ **Output Examples** -![Example Image](https://invoke-ai.github.io/InvokeAI/assets/invoke_ai_banner.png){: style="height:115px;width:240px"} +
## Disclaimer 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/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 7b61887eb8..43a72943ee 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -42,7 +42,7 @@ async def upload_image( crop_visible: Optional[bool] = Query(default=False, description="Whether to crop the image"), ) -> ImageDTO: """Uploads an image""" - if not file.content_type.startswith("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() diff --git a/invokeai/app/api/routers/models.py b/invokeai/app/api/routers/models.py index ebc40f5ce5..018f3af02b 100644 --- a/invokeai/app/api/routers/models.py +++ b/invokeai/app/api/routers/models.py @@ -2,11 +2,11 @@ import pathlib -from typing import List, Literal, Optional, Union +from typing import Annotated, List, Literal, Optional, Union from fastapi import Body, Path, Query, Response from fastapi.routing import APIRouter -from pydantic import BaseModel, parse_obj_as +from pydantic import BaseModel, ConfigDict, Field, TypeAdapter from starlette.exceptions import HTTPException from invokeai.backend import BaseModelType, ModelType @@ -23,8 +23,14 @@ from ..dependencies import ApiDependencies models_router = APIRouter(prefix="/v1/models", tags=["models"]) UpdateModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] +update_models_response_adapter = TypeAdapter(UpdateModelResponse) + ImportModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] +import_models_response_adapter = TypeAdapter(ImportModelResponse) + ConvertModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] +convert_models_response_adapter = TypeAdapter(ConvertModelResponse) + MergeModelResponse = Union[tuple(OPENAPI_MODEL_CONFIGS)] ImportModelAttributes = Union[tuple(OPENAPI_MODEL_CONFIGS)] @@ -32,6 +38,11 @@ ImportModelAttributes = Union[tuple(OPENAPI_MODEL_CONFIGS)] class ModelsList(BaseModel): models: list[Union[tuple(OPENAPI_MODEL_CONFIGS)]] + model_config = ConfigDict(use_enum_values=True) + + +models_list_adapter = TypeAdapter(ModelsList) + @models_router.get( "/", @@ -49,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 = parse_obj_as(ModelsList, {"models": models_raw}) + models = models_list_adapter.validate_python({"models": models_raw}) return models @@ -105,11 +116,14 @@ async def update_model( info.path = new_info.get("path") # replace empty string values with None/null to avoid phenomenon of vae: '' - info_dict = info.dict() + info_dict = info.model_dump() info_dict = {x: info_dict[x] if info_dict[x] else None for x in info_dict.keys()} ApiDependencies.invoker.services.model_manager.update_model( - model_name=model_name, base_model=base_model, model_type=model_type, model_attributes=info_dict + model_name=model_name, + base_model=base_model, + model_type=model_type, + model_attributes=info_dict, ) model_raw = ApiDependencies.invoker.services.model_manager.list_model( @@ -117,7 +131,7 @@ async def update_model( base_model=base_model, model_type=model_type, ) - model_response = parse_obj_as(UpdateModelResponse, model_raw) + model_response = update_models_response_adapter.validate_python(model_raw) except ModelNotFoundException as e: raise HTTPException(status_code=404, detail=str(e)) except ValueError as e: @@ -152,13 +166,15 @@ async def import_model( ) -> ImportModelResponse: """Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically""" + location = location.strip("\"' ") items_to_import = {location} prediction_types = {x.value: x for x in SchedulerPredictionType} logger = ApiDependencies.invoker.services.logger try: installed_models = ApiDependencies.invoker.services.model_manager.heuristic_import( - items_to_import=items_to_import, prediction_type_helper=lambda x: prediction_types.get(prediction_type) + items_to_import=items_to_import, + prediction_type_helper=lambda x: prediction_types.get(prediction_type), ) info = installed_models.get(location) @@ -170,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 parse_obj_as(ImportModelResponse, model_raw) + return import_models_response_adapter.validate_python(model_raw) except ModelNotFoundException as e: logger.error(str(e)) @@ -204,13 +220,18 @@ async def add_model( try: ApiDependencies.invoker.services.model_manager.add_model( - info.model_name, info.base_model, info.model_type, model_attributes=info.dict() + info.model_name, + info.base_model, + info.model_type, + model_attributes=info.model_dump(), ) logger.info(f"Successfully added {info.model_name}") model_raw = ApiDependencies.invoker.services.model_manager.list_model( - model_name=info.model_name, base_model=info.base_model, model_type=info.model_type + model_name=info.model_name, + base_model=info.base_model, + model_type=info.model_type, ) - return parse_obj_as(ImportModelResponse, model_raw) + return import_models_response_adapter.validate_python(model_raw) except ModelNotFoundException as e: logger.error(str(e)) raise HTTPException(status_code=404, detail=str(e)) @@ -222,7 +243,10 @@ async def add_model( @models_router.delete( "/{base_model}/{model_type}/{model_name}", operation_id="del_model", - responses={204: {"description": "Model deleted successfully"}, 404: {"description": "Model not found"}}, + responses={ + 204: {"description": "Model deleted successfully"}, + 404: {"description": "Model not found"}, + }, status_code=204, response_model=None, ) @@ -278,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 = parse_obj_as(ConvertModelResponse, model_raw) + response = convert_models_response_adapter.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: @@ -301,7 +325,8 @@ async def search_for_models( ) -> List[pathlib.Path]: if not search_path.is_dir(): raise HTTPException( - status_code=404, detail=f"The search path '{search_path}' does not exist or is not directory" + status_code=404, + detail=f"The search path '{search_path}' does not exist or is not directory", ) return ApiDependencies.invoker.services.model_manager.search_for_models(search_path) @@ -336,6 +361,26 @@ async def sync_to_config() -> bool: return True +# There's some weird pydantic-fastapi behaviour that requires this to be a separate class +# TODO: After a few updates, see if it works inside the route operation handler? +class MergeModelsBody(BaseModel): + model_names: List[str] = Field(description="model name", min_length=2, max_length=3) + merged_model_name: Optional[str] = Field(description="Name of destination model") + alpha: Optional[float] = Field(description="Alpha weighting strength to apply to 2d and 3d models", default=0.5) + interp: Optional[MergeInterpolationMethod] = Field(description="Interpolation method") + force: Optional[bool] = Field( + description="Force merging of models created with different versions of diffusers", + default=False, + ) + + merge_dest_directory: Optional[str] = Field( + description="Save the merged model to the designated directory (with 'merged_model_name' appended)", + default=None, + ) + + model_config = ConfigDict(protected_namespaces=()) + + @models_router.put( "/merge/{base_model}", operation_id="merge_models", @@ -348,31 +393,23 @@ async def sync_to_config() -> bool: response_model=MergeModelResponse, ) async def merge_models( + body: Annotated[MergeModelsBody, Body(description="Model configuration", embed=True)], base_model: BaseModelType = Path(description="Base model"), - model_names: List[str] = Body(description="model name", min_items=2, max_items=3), - merged_model_name: Optional[str] = Body(description="Name of destination model"), - alpha: Optional[float] = Body(description="Alpha weighting strength to apply to 2d and 3d models", default=0.5), - interp: Optional[MergeInterpolationMethod] = Body(description="Interpolation method"), - force: Optional[bool] = Body( - description="Force merging of models created with different versions of diffusers", default=False - ), - merge_dest_directory: Optional[str] = Body( - description="Save the merged model to the designated directory (with 'merged_model_name' appended)", - default=None, - ), ) -> MergeModelResponse: """Convert a checkpoint model into a diffusers model""" logger = ApiDependencies.invoker.services.logger try: - logger.info(f"Merging models: {model_names} into {merge_dest_directory or ''}/{merged_model_name}") - dest = pathlib.Path(merge_dest_directory) if merge_dest_directory else None + logger.info( + f"Merging models: {body.model_names} into {body.merge_dest_directory or ''}/{body.merged_model_name}" + ) + dest = pathlib.Path(body.merge_dest_directory) if body.merge_dest_directory else None result = ApiDependencies.invoker.services.model_manager.merge_models( - model_names, - base_model, - merged_model_name=merged_model_name or "+".join(model_names), - alpha=alpha, - interp=interp, - force=force, + model_names=body.model_names, + base_model=base_model, + merged_model_name=body.merged_model_name or "+".join(body.model_names), + alpha=body.alpha, + interp=body.interp, + force=body.force, merge_dest_directory=dest, ) model_raw = ApiDependencies.invoker.services.model_manager.list_model( @@ -380,9 +417,12 @@ async def merge_models( base_model=base_model, model_type=ModelType.Main, ) - response = parse_obj_as(ConvertModelResponse, model_raw) + response = convert_models_response_adapter.validate_python(model_raw) except ModelNotFoundException: - raise HTTPException(status_code=404, detail=f"One or more of the models '{model_names}' not found") + raise HTTPException( + status_code=404, + detail=f"One or more of the models '{body.model_names}' not found", + ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) return response diff --git a/invokeai/app/api/routers/sessions.py b/invokeai/app/api/routers/sessions.py index cd93a267ad..fb850d0b2b 100644 --- a/invokeai/app/api/routers/sessions.py +++ b/invokeai/app/api/routers/sessions.py @@ -1,57 +1,50 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) -from typing import Annotated, Optional, Union -from fastapi import Body, HTTPException, Path, Query, Response +from fastapi import HTTPException, Path from fastapi.routing import APIRouter -from pydantic.fields import Field -from invokeai.app.services.shared.pagination import PaginatedResults - -# Importing * is bad karma but needed here for node detection -from ...invocations import * # noqa: F401 F403 -from ...invocations.baseinvocation import BaseInvocation -from ...services.shared.graph import Edge, EdgeConnection, Graph, GraphExecutionState, NodeAlreadyExecutedError +from ...services.shared.graph import GraphExecutionState from ..dependencies import ApiDependencies session_router = APIRouter(prefix="/v1/sessions", tags=["sessions"]) -@session_router.post( - "/", - operation_id="create_session", - responses={ - 200: {"model": GraphExecutionState}, - 400: {"description": "Invalid json"}, - }, - deprecated=True, -) -async def create_session( - queue_id: str = Query(default="", description="The id of the queue to associate the session with"), - graph: Optional[Graph] = Body(default=None, description="The graph to initialize the session with"), -) -> GraphExecutionState: - """Creates a new session, optionally initializing it with an invocation graph""" - session = ApiDependencies.invoker.create_execution_state(queue_id=queue_id, graph=graph) - return session +# @session_router.post( +# "/", +# operation_id="create_session", +# responses={ +# 200: {"model": GraphExecutionState}, +# 400: {"description": "Invalid json"}, +# }, +# deprecated=True, +# ) +# async def create_session( +# queue_id: str = Query(default="", description="The id of the queue to associate the session with"), +# graph: Optional[Graph] = Body(default=None, description="The graph to initialize the session with"), +# ) -> GraphExecutionState: +# """Creates a new session, optionally initializing it with an invocation graph""" +# session = ApiDependencies.invoker.create_execution_state(queue_id=queue_id, graph=graph) +# return session -@session_router.get( - "/", - operation_id="list_sessions", - responses={200: {"model": PaginatedResults[GraphExecutionState]}}, - deprecated=True, -) -async def list_sessions( - page: int = Query(default=0, description="The page of results to get"), - per_page: int = Query(default=10, description="The number of results per page"), - query: str = Query(default="", description="The query string to search for"), -) -> PaginatedResults[GraphExecutionState]: - """Gets a list of sessions, optionally searching""" - if query == "": - result = ApiDependencies.invoker.services.graph_execution_manager.list(page, per_page) - else: - result = ApiDependencies.invoker.services.graph_execution_manager.search(query, page, per_page) - return result +# @session_router.get( +# "/", +# operation_id="list_sessions", +# responses={200: {"model": PaginatedResults[GraphExecutionState]}}, +# deprecated=True, +# ) +# async def list_sessions( +# page: int = Query(default=0, description="The page of results to get"), +# per_page: int = Query(default=10, description="The number of results per page"), +# query: str = Query(default="", description="The query string to search for"), +# ) -> PaginatedResults[GraphExecutionState]: +# """Gets a list of sessions, optionally searching""" +# if query == "": +# result = ApiDependencies.invoker.services.graph_execution_manager.list(page, per_page) +# else: +# result = ApiDependencies.invoker.services.graph_execution_manager.search(query, page, per_page) +# return result @session_router.get( @@ -61,7 +54,6 @@ async def list_sessions( 200: {"model": GraphExecutionState}, 404: {"description": "Session not found"}, }, - deprecated=True, ) async def get_session( session_id: str = Path(description="The id of the session to get"), @@ -74,211 +66,211 @@ async def get_session( return session -@session_router.post( - "/{session_id}/nodes", - operation_id="add_node", - responses={ - 200: {"model": str}, - 400: {"description": "Invalid node or link"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def add_node( - session_id: str = Path(description="The id of the session"), - node: Annotated[Union[BaseInvocation.get_invocations()], Field(discriminator="type")] = Body( # type: ignore - description="The node to add" - ), -) -> str: - """Adds a node to the graph""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# @session_router.post( +# "/{session_id}/nodes", +# operation_id="add_node", +# responses={ +# 200: {"model": str}, +# 400: {"description": "Invalid node or link"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def add_node( +# session_id: str = Path(description="The id of the session"), +# node: Annotated[Union[BaseInvocation.get_invocations()], Field(discriminator="type")] = Body( # type: ignore +# description="The node to add" +# ), +# ) -> str: +# """Adds a node to the graph""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - try: - session.add_node(node) - ApiDependencies.invoker.services.graph_execution_manager.set( - session - ) # TODO: can this be done automatically, or add node through an API? - return session.id - except NodeAlreadyExecutedError: - raise HTTPException(status_code=400) - except IndexError: - raise HTTPException(status_code=400) +# try: +# session.add_node(node) +# ApiDependencies.invoker.services.graph_execution_manager.set( +# session +# ) # TODO: can this be done automatically, or add node through an API? +# return session.id +# except NodeAlreadyExecutedError: +# raise HTTPException(status_code=400) +# except IndexError: +# raise HTTPException(status_code=400) -@session_router.put( - "/{session_id}/nodes/{node_path}", - operation_id="update_node", - responses={ - 200: {"model": GraphExecutionState}, - 400: {"description": "Invalid node or link"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def update_node( - session_id: str = Path(description="The id of the session"), - node_path: str = Path(description="The path to the node in the graph"), - node: Annotated[Union[BaseInvocation.get_invocations()], Field(discriminator="type")] = Body( # type: ignore - description="The new node" - ), -) -> GraphExecutionState: - """Updates a node in the graph and removes all linked edges""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# @session_router.put( +# "/{session_id}/nodes/{node_path}", +# operation_id="update_node", +# responses={ +# 200: {"model": GraphExecutionState}, +# 400: {"description": "Invalid node or link"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def update_node( +# session_id: str = Path(description="The id of the session"), +# node_path: str = Path(description="The path to the node in the graph"), +# node: Annotated[Union[BaseInvocation.get_invocations()], Field(discriminator="type")] = Body( # type: ignore +# description="The new node" +# ), +# ) -> GraphExecutionState: +# """Updates a node in the graph and removes all linked edges""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - try: - session.update_node(node_path, node) - ApiDependencies.invoker.services.graph_execution_manager.set( - session - ) # TODO: can this be done automatically, or add node through an API? - return session - except NodeAlreadyExecutedError: - raise HTTPException(status_code=400) - except IndexError: - raise HTTPException(status_code=400) +# try: +# session.update_node(node_path, node) +# ApiDependencies.invoker.services.graph_execution_manager.set( +# session +# ) # TODO: can this be done automatically, or add node through an API? +# return session +# except NodeAlreadyExecutedError: +# raise HTTPException(status_code=400) +# except IndexError: +# raise HTTPException(status_code=400) -@session_router.delete( - "/{session_id}/nodes/{node_path}", - operation_id="delete_node", - responses={ - 200: {"model": GraphExecutionState}, - 400: {"description": "Invalid node or link"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def delete_node( - session_id: str = Path(description="The id of the session"), - node_path: str = Path(description="The path to the node to delete"), -) -> GraphExecutionState: - """Deletes a node in the graph and removes all linked edges""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# @session_router.delete( +# "/{session_id}/nodes/{node_path}", +# operation_id="delete_node", +# responses={ +# 200: {"model": GraphExecutionState}, +# 400: {"description": "Invalid node or link"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def delete_node( +# session_id: str = Path(description="The id of the session"), +# node_path: str = Path(description="The path to the node to delete"), +# ) -> GraphExecutionState: +# """Deletes a node in the graph and removes all linked edges""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - try: - session.delete_node(node_path) - ApiDependencies.invoker.services.graph_execution_manager.set( - session - ) # TODO: can this be done automatically, or add node through an API? - return session - except NodeAlreadyExecutedError: - raise HTTPException(status_code=400) - except IndexError: - raise HTTPException(status_code=400) +# try: +# session.delete_node(node_path) +# ApiDependencies.invoker.services.graph_execution_manager.set( +# session +# ) # TODO: can this be done automatically, or add node through an API? +# return session +# except NodeAlreadyExecutedError: +# raise HTTPException(status_code=400) +# except IndexError: +# raise HTTPException(status_code=400) -@session_router.post( - "/{session_id}/edges", - operation_id="add_edge", - responses={ - 200: {"model": GraphExecutionState}, - 400: {"description": "Invalid node or link"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def add_edge( - session_id: str = Path(description="The id of the session"), - edge: Edge = Body(description="The edge to add"), -) -> GraphExecutionState: - """Adds an edge to the graph""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# @session_router.post( +# "/{session_id}/edges", +# operation_id="add_edge", +# responses={ +# 200: {"model": GraphExecutionState}, +# 400: {"description": "Invalid node or link"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def add_edge( +# session_id: str = Path(description="The id of the session"), +# edge: Edge = Body(description="The edge to add"), +# ) -> GraphExecutionState: +# """Adds an edge to the graph""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - try: - session.add_edge(edge) - ApiDependencies.invoker.services.graph_execution_manager.set( - session - ) # TODO: can this be done automatically, or add node through an API? - return session - except NodeAlreadyExecutedError: - raise HTTPException(status_code=400) - except IndexError: - raise HTTPException(status_code=400) +# try: +# session.add_edge(edge) +# ApiDependencies.invoker.services.graph_execution_manager.set( +# session +# ) # TODO: can this be done automatically, or add node through an API? +# return session +# except NodeAlreadyExecutedError: +# raise HTTPException(status_code=400) +# except IndexError: +# raise HTTPException(status_code=400) -# TODO: the edge being in the path here is really ugly, find a better solution -@session_router.delete( - "/{session_id}/edges/{from_node_id}/{from_field}/{to_node_id}/{to_field}", - operation_id="delete_edge", - responses={ - 200: {"model": GraphExecutionState}, - 400: {"description": "Invalid node or link"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def delete_edge( - session_id: str = Path(description="The id of the session"), - from_node_id: str = Path(description="The id of the node the edge is coming from"), - from_field: str = Path(description="The field of the node the edge is coming from"), - to_node_id: str = Path(description="The id of the node the edge is going to"), - to_field: str = Path(description="The field of the node the edge is going to"), -) -> GraphExecutionState: - """Deletes an edge from the graph""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# # TODO: the edge being in the path here is really ugly, find a better solution +# @session_router.delete( +# "/{session_id}/edges/{from_node_id}/{from_field}/{to_node_id}/{to_field}", +# operation_id="delete_edge", +# responses={ +# 200: {"model": GraphExecutionState}, +# 400: {"description": "Invalid node or link"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def delete_edge( +# session_id: str = Path(description="The id of the session"), +# from_node_id: str = Path(description="The id of the node the edge is coming from"), +# from_field: str = Path(description="The field of the node the edge is coming from"), +# to_node_id: str = Path(description="The id of the node the edge is going to"), +# to_field: str = Path(description="The field of the node the edge is going to"), +# ) -> GraphExecutionState: +# """Deletes an edge from the graph""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - try: - edge = Edge( - source=EdgeConnection(node_id=from_node_id, field=from_field), - destination=EdgeConnection(node_id=to_node_id, field=to_field), - ) - session.delete_edge(edge) - ApiDependencies.invoker.services.graph_execution_manager.set( - session - ) # TODO: can this be done automatically, or add node through an API? - return session - except NodeAlreadyExecutedError: - raise HTTPException(status_code=400) - except IndexError: - raise HTTPException(status_code=400) +# try: +# edge = Edge( +# source=EdgeConnection(node_id=from_node_id, field=from_field), +# destination=EdgeConnection(node_id=to_node_id, field=to_field), +# ) +# session.delete_edge(edge) +# ApiDependencies.invoker.services.graph_execution_manager.set( +# session +# ) # TODO: can this be done automatically, or add node through an API? +# return session +# except NodeAlreadyExecutedError: +# raise HTTPException(status_code=400) +# except IndexError: +# raise HTTPException(status_code=400) -@session_router.put( - "/{session_id}/invoke", - operation_id="invoke_session", - responses={ - 200: {"model": None}, - 202: {"description": "The invocation is queued"}, - 400: {"description": "The session has no invocations ready to invoke"}, - 404: {"description": "Session not found"}, - }, - deprecated=True, -) -async def invoke_session( - queue_id: str = Query(description="The id of the queue to associate the session with"), - session_id: str = Path(description="The id of the session to invoke"), - all: bool = Query(default=False, description="Whether or not to invoke all remaining invocations"), -) -> Response: - """Invokes a session""" - session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) - if session is None: - raise HTTPException(status_code=404) +# @session_router.put( +# "/{session_id}/invoke", +# operation_id="invoke_session", +# responses={ +# 200: {"model": None}, +# 202: {"description": "The invocation is queued"}, +# 400: {"description": "The session has no invocations ready to invoke"}, +# 404: {"description": "Session not found"}, +# }, +# deprecated=True, +# ) +# async def invoke_session( +# queue_id: str = Query(description="The id of the queue to associate the session with"), +# session_id: str = Path(description="The id of the session to invoke"), +# all: bool = Query(default=False, description="Whether or not to invoke all remaining invocations"), +# ) -> Response: +# """Invokes a session""" +# session = ApiDependencies.invoker.services.graph_execution_manager.get(session_id) +# if session is None: +# raise HTTPException(status_code=404) - if session.is_complete(): - raise HTTPException(status_code=400) +# if session.is_complete(): +# raise HTTPException(status_code=400) - ApiDependencies.invoker.invoke(queue_id, session, invoke_all=all) - return Response(status_code=202) +# ApiDependencies.invoker.invoke(queue_id, session, invoke_all=all) +# return Response(status_code=202) -@session_router.delete( - "/{session_id}/invoke", - operation_id="cancel_session_invoke", - responses={202: {"description": "The invocation is canceled"}}, - deprecated=True, -) -async def cancel_session_invoke( - session_id: str = Path(description="The id of the session to cancel"), -) -> Response: - """Invokes a session""" - ApiDependencies.invoker.cancel(session_id) - return Response(status_code=202) +# @session_router.delete( +# "/{session_id}/invoke", +# operation_id="cancel_session_invoke", +# responses={202: {"description": "The invocation is canceled"}}, +# deprecated=True, +# ) +# async def cancel_session_invoke( +# session_id: str = Path(description="The id of the session to cancel"), +# ) -> Response: +# """Invokes a session""" +# ApiDependencies.invoker.cancel(session_id) +# return Response(status_code=202) diff --git a/invokeai/app/api/routers/utilities.py b/invokeai/app/api/routers/utilities.py index e664cb9070..476d10e2c0 100644 --- a/invokeai/app/api/routers/utilities.py +++ b/invokeai/app/api/routers/utilities.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Union from dynamicprompts.generators import CombinatorialPromptGenerator, RandomPromptGenerator from fastapi import Body @@ -27,6 +27,7 @@ async def parse_dynamicprompts( combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator"), ) -> DynamicPromptsResponse: """Creates a batch process""" + generator: Union[RandomPromptGenerator, CombinatorialPromptGenerator] try: error: Optional[str] = None if combinatorial: diff --git a/invokeai/app/api/sockets.py b/invokeai/app/api/sockets.py index f41c38786c..5725901de0 100644 --- a/invokeai/app/api/sockets.py +++ b/invokeai/app/api/sockets.py @@ -30,8 +30,8 @@ class SocketIO: async def _handle_sub_queue(self, sid, data, *args, **kwargs): if "queue_id" in data: - self.__sio.enter_room(sid, data["queue_id"]) + await self.__sio.enter_room(sid, data["queue_id"]) async def _handle_unsub_queue(self, sid, data, *args, **kwargs): if "queue_id" in data: - self.__sio.enter_room(sid, data["queue_id"]) + await self.__sio.enter_room(sid, data["queue_id"]) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index fdbd64b30d..e07b037dd1 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -22,7 +22,7 @@ if True: # hack to make flake8 happy with imports coming after setting up the c from fastapi.staticfiles import StaticFiles from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware - from pydantic.schema import schema + from pydantic.json_schema import models_json_schema # noinspection PyUnresolvedReferences import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) @@ -51,7 +51,7 @@ mimetypes.add_type("text/css", ".css") # Create the app # TODO: create this all in a method so configuration/etc. can be passed in? -app = FastAPI(title="Invoke AI", docs_url=None, redoc_url=None) +app = FastAPI(title="Invoke AI", docs_url=None, redoc_url=None, separate_input_output_schemas=False) # Add event handler event_handler_id: int = id(app) @@ -63,18 +63,18 @@ app.add_middleware( socket_io = SocketIO(app) +app.add_middleware( + CORSMiddleware, + allow_origins=app_config.allow_origins, + allow_credentials=app_config.allow_credentials, + allow_methods=app_config.allow_methods, + allow_headers=app_config.allow_headers, +) + # Add startup event to load dependencies @app.on_event("startup") async def startup_event(): - app.add_middleware( - CORSMiddleware, - allow_origins=app_config.allow_origins, - allow_credentials=app_config.allow_credentials, - allow_methods=app_config.allow_methods, - allow_headers=app_config.allow_headers, - ) - ApiDependencies.initialize(config=app_config, event_handler_id=event_handler_id, logger=logger) @@ -85,11 +85,6 @@ async def shutdown_event(): # Include all routers -# TODO: REMOVE -# app.include_router( -# invocation.invocation_router, -# prefix = '/api') - app.include_router(sessions.session_router, prefix="/api") app.include_router(utilities.utilities_router, prefix="/api") @@ -117,6 +112,7 @@ def custom_openapi(): description="An API for invoking AI image operations", version="1.0.0", routes=app.routes, + separate_input_output_schemas=False, # https://fastapi.tiangolo.com/how-to/separate-openapi-schemas/ ) # Add all outputs @@ -127,29 +123,32 @@ def custom_openapi(): output_type = signature(invoker.invoke).return_annotation output_types.add(output_type) - output_schemas = schema(output_types, ref_prefix="#/components/schemas/") - for schema_key, output_schema in output_schemas["definitions"].items(): - output_schema["class"] = "output" - openapi_schema["components"]["schemas"][schema_key] = output_schema - + output_schemas = models_json_schema( + models=[(o, "serialization") for o in output_types], ref_template="#/components/schemas/{model}" + ) + for schema_key, output_schema in output_schemas[1]["$defs"].items(): # TODO: note that we assume the schema_key here is the TYPE.__name__ # This could break in some cases, figure out a better way to do it output_type_titles[schema_key] = output_schema["title"] # Add Node Editor UI helper schemas - ui_config_schemas = schema([UIConfigBase, _InputField, _OutputField], ref_prefix="#/components/schemas/") - for schema_key, ui_config_schema in ui_config_schemas["definitions"].items(): + ui_config_schemas = models_json_schema( + [(UIConfigBase, "serialization"), (_InputField, "serialization"), (_OutputField, "serialization")], + ref_template="#/components/schemas/{model}", + ) + for schema_key, ui_config_schema in ui_config_schemas[1]["$defs"].items(): openapi_schema["components"]["schemas"][schema_key] = ui_config_schema # Add a reference to the output type to additionalProperties of the invoker schema for invoker in all_invocations: invoker_name = invoker.__name__ - output_type = signature(invoker.invoke).return_annotation + output_type = signature(obj=invoker.invoke).return_annotation output_type_title = output_type_titles[output_type.__name__] - invoker_schema = openapi_schema["components"]["schemas"][invoker_name] + invoker_schema = openapi_schema["components"]["schemas"][f"{invoker_name}"] outputs_ref = {"$ref": f"#/components/schemas/{output_type_title}"} invoker_schema["output"] = outputs_ref invoker_schema["class"] = "invocation" + openapi_schema["components"]["schemas"][f"{output_type_title}"]["class"] = "output" from invokeai.backend.model_management.models import get_model_config_enums @@ -172,7 +171,7 @@ def custom_openapi(): return app.openapi_schema -app.openapi = 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") diff --git a/invokeai/app/cli/commands.py b/invokeai/app/cli/commands.py index b000abcf6a..c21c6315ed 100644 --- a/invokeai/app/cli/commands.py +++ b/invokeai/app/cli/commands.py @@ -24,8 +24,8 @@ def add_field_argument(command_parser, name: str, field, default_override=None): if field.default_factory is None else field.default_factory() ) - if get_origin(field.type_) == Literal: - allowed_values = get_args(field.type_) + 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)) @@ -38,15 +38,15 @@ def add_field_argument(command_parser, name: str, field, default_override=None): type=field_type, default=default, choices=allowed_values, - help=field.field_info.description, + help=field.description, ) else: command_parser.add_argument( f"--{name}", dest=name, - type=field.type_, + type=field.annotation, default=default, - help=field.field_info.description, + help=field.description, ) @@ -142,7 +142,6 @@ class BaseCommand(ABC, BaseModel): """A CLI command""" # All commands must include a type name like this: - # type: Literal['your_command_name'] = 'your_command_name' @classmethod def get_all_subclasses(cls): diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index d82b94d0e9..8bd4a89f45 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -7,28 +7,16 @@ import re from abc import ABC, abstractmethod from enum import Enum from inspect import signature -from typing import ( - TYPE_CHECKING, - AbstractSet, - Any, - Callable, - ClassVar, - Literal, - Mapping, - Optional, - Type, - TypeVar, - Union, - get_args, - get_type_hints, -) +from types import UnionType +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Literal, Optional, Type, TypeVar, Union import semver -from pydantic import BaseModel, Field, validator -from pydantic.fields import ModelField, Undefined -from pydantic.typing import NoArgAnyCallable +from pydantic import BaseModel, ConfigDict, Field, create_model, field_validator +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 if TYPE_CHECKING: from ..services.invocation_services import InvocationServices @@ -211,6 +199,11 @@ class _InputField(BaseModel): ui_choice_labels: Optional[dict[str, str]] item_default: Optional[Any] + model_config = ConfigDict( + validate_assignment=True, + json_schema_serialization_defaults_required=True, + ) + class _OutputField(BaseModel): """ @@ -224,34 +217,36 @@ class _OutputField(BaseModel): ui_type: Optional[UIType] ui_order: Optional[int] + model_config = ConfigDict( + validate_assignment=True, + json_schema_serialization_defaults_required=True, + ) + + +def get_type(klass: BaseModel) -> str: + """Helper function to get an invocation or invocation output's type. This is the default value of the `type` field.""" + return klass.model_fields["type"].default + def InputField( - *args: Any, - default: Any = Undefined, - default_factory: Optional[NoArgAnyCallable] = None, - alias: Optional[str] = None, - title: Optional[str] = None, - description: Optional[str] = None, - exclude: Optional[Union[AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any]] = None, - include: Optional[Union[AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any]] = None, - const: Optional[bool] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - multiple_of: Optional[float] = None, - allow_inf_nan: Optional[bool] = None, - max_digits: Optional[int] = None, - decimal_places: Optional[int] = None, - min_items: Optional[int] = None, - max_items: Optional[int] = None, - unique_items: Optional[bool] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - allow_mutation: bool = True, - regex: Optional[str] = None, - discriminator: Optional[str] = None, - repr: bool = True, + # copied from pydantic's Field + default: Any = _Unset, + default_factory: Callable[[], Any] | None = _Unset, + title: str | None = _Unset, + description: str | None = _Unset, + pattern: str | None = _Unset, + strict: bool | None = _Unset, + gt: float | None = _Unset, + ge: float | None = _Unset, + lt: float | None = _Unset, + le: float | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + # custom input: Input = Input.Any, ui_type: Optional[UIType] = None, ui_component: Optional[UIComponent] = None, @@ -259,7 +254,6 @@ def InputField( ui_order: Optional[int] = None, ui_choice_labels: Optional[dict[str, str]] = None, item_default: Optional[Any] = None, - **kwargs: Any, ) -> Any: """ Creates an input field for an invocation. @@ -289,18 +283,26 @@ def InputField( : param int ui_order: [None] Specifies the order in which this field should be rendered in the UI. \ : param bool item_default: [None] Specifies the default item value, if this is a collection input. \ - Ignored for non-collection fields.. + Ignored for non-collection fields. """ - return Field( - *args, + + json_schema_extra_: dict[str, Any] = dict( + input=input, + ui_type=ui_type, + ui_component=ui_component, + ui_hidden=ui_hidden, + ui_order=ui_order, + item_default=item_default, + ui_choice_labels=ui_choice_labels, + ) + + field_args = dict( default=default, default_factory=default_factory, - alias=alias, title=title, description=description, - exclude=exclude, - include=include, - const=const, + pattern=pattern, + strict=strict, gt=gt, ge=ge, lt=lt, @@ -309,57 +311,92 @@ def InputField( allow_inf_nan=allow_inf_nan, max_digits=max_digits, decimal_places=decimal_places, - min_items=min_items, - max_items=max_items, - unique_items=unique_items, min_length=min_length, max_length=max_length, - allow_mutation=allow_mutation, - regex=regex, - discriminator=discriminator, - repr=repr, - input=input, - ui_type=ui_type, - ui_component=ui_component, - ui_hidden=ui_hidden, - ui_order=ui_order, - item_default=item_default, - ui_choice_labels=ui_choice_labels, - **kwargs, + ) + + """ + Invocation definitions have their fields typed correctly for their `invoke()` functions. + This typing is often more specific than the actual invocation definition requires, because + fields may have values provided only by connections. + + For example, consider an ResizeImageInvocation with an `image: ImageField` field. + + `image` is required during the call to `invoke()`, but when the python class is instantiated, + the field may not be present. This is fine, because that image field will be provided by a + an ancestor node that outputs the image. + + So we'd like to type that `image` field as `Optional[ImageField]`. If we do that, however, then + we need to handle a lot of extra logic in the `invoke()` function to check if the field has a + value or not. This is very tedious. + + Ideally, the invocation definition would be able to specify that the field is required during + invocation, but optional during instantiation. So the field would be typed as `image: ImageField`, + but when calling the `invoke()` function, we raise an error if the field is not present. + + To do this, we need to do a bit of fanagling to make the pydantic field optional, and then do + extra validation when calling `invoke()`. + + There is some additional logic here to cleaning create the pydantic field via the wrapper. + """ + + # Filter out field args not provided + provided_args = {k: v for (k, v) in field_args.items() if v is not PydanticUndefined} + + if (default is not PydanticUndefined) and (default_factory is not PydanticUndefined): + raise ValueError("Cannot specify both default and default_factory") + + # because we are manually making fields optional, we need to store the original required bool for reference later + if default is PydanticUndefined and default_factory is PydanticUndefined: + json_schema_extra_.update(dict(orig_required=True)) + else: + json_schema_extra_.update(dict(orig_required=False)) + + # make Input.Any and Input.Connection fields optional, providing None as a default if the field doesn't already have one + if (input is Input.Any or input is Input.Connection) and default_factory is PydanticUndefined: + default_ = None if default is PydanticUndefined else default + provided_args.update(dict(default=default_)) + if default is not PydanticUndefined: + # before invoking, we'll grab the original default value and set it on the field if the field wasn't provided a value + json_schema_extra_.update(dict(default=default)) + json_schema_extra_.update(dict(orig_default=default)) + elif default is not PydanticUndefined and default_factory is PydanticUndefined: + default_ = default + provided_args.update(dict(default=default_)) + json_schema_extra_.update(dict(orig_default=default_)) + elif default_factory is not PydanticUndefined: + provided_args.update(dict(default_factory=default_factory)) + # TODO: cannot serialize default_factory... + # json_schema_extra_.update(dict(orig_default_factory=default_factory)) + + return Field( + **provided_args, + json_schema_extra=json_schema_extra_, ) def OutputField( - *args: Any, - default: Any = Undefined, - default_factory: Optional[NoArgAnyCallable] = None, - alias: Optional[str] = None, - title: Optional[str] = None, - description: Optional[str] = None, - exclude: Optional[Union[AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any]] = None, - include: Optional[Union[AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any]] = None, - const: Optional[bool] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - multiple_of: Optional[float] = None, - allow_inf_nan: Optional[bool] = None, - max_digits: Optional[int] = None, - decimal_places: Optional[int] = None, - min_items: Optional[int] = None, - max_items: Optional[int] = None, - unique_items: Optional[bool] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - allow_mutation: bool = True, - regex: Optional[str] = None, - discriminator: Optional[str] = None, - repr: bool = True, + # copied from pydantic's Field + default: Any = _Unset, + default_factory: Callable[[], Any] | None = _Unset, + title: str | None = _Unset, + description: str | None = _Unset, + pattern: str | None = _Unset, + strict: bool | None = _Unset, + gt: float | None = _Unset, + ge: float | None = _Unset, + lt: float | None = _Unset, + le: float | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + # custom ui_type: Optional[UIType] = None, ui_hidden: bool = False, ui_order: Optional[int] = None, - **kwargs: Any, ) -> Any: """ Creates an output field for an invocation output. @@ -379,15 +416,12 @@ def OutputField( : param int ui_order: [None] Specifies the order in which this field should be rendered in the UI. \ """ return Field( - *args, default=default, default_factory=default_factory, - alias=alias, title=title, description=description, - exclude=exclude, - include=include, - const=const, + pattern=pattern, + strict=strict, gt=gt, ge=ge, lt=lt, @@ -396,19 +430,13 @@ def OutputField( allow_inf_nan=allow_inf_nan, max_digits=max_digits, decimal_places=decimal_places, - min_items=min_items, - max_items=max_items, - unique_items=unique_items, min_length=min_length, max_length=max_length, - allow_mutation=allow_mutation, - regex=regex, - discriminator=discriminator, - repr=repr, - ui_type=ui_type, - ui_hidden=ui_hidden, - ui_order=ui_order, - **kwargs, + json_schema_extra=dict( + ui_type=ui_type, + ui_hidden=ui_hidden, + ui_order=ui_order, + ), ) @@ -422,7 +450,13 @@ class UIConfigBase(BaseModel): title: Optional[str] = Field(default=None, description="The node's display name") category: Optional[str] = Field(default=None, description="The node's category") version: Optional[str] = Field( - default=None, description='The node\'s version. Should be a valid semver string e.g. "1.0.0" or "3.8.13".' + default=None, + description='The node\'s version. Should be a valid semver string e.g. "1.0.0" or "3.8.13".', + ) + + model_config = ConfigDict( + validate_assignment=True, + json_schema_serialization_defaults_required=True, ) @@ -457,23 +491,38 @@ class BaseInvocationOutput(BaseModel): All invocation outputs must use the `@invocation_output` decorator to provide their unique type. """ - @classmethod - def get_all_subclasses_tuple(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 tuple(subclasses) + _output_classes: ClassVar[set[BaseInvocationOutput]] = set() - class Config: - @staticmethod - def schema_extra(schema: dict[str, Any], model_class: Type[BaseModel]) -> None: - if "required" not in schema or not isinstance(schema["required"], list): - schema["required"] = list() - schema["required"].extend(["type"]) + @classmethod + def register_output(cls, output: BaseInvocationOutput) -> None: + cls._output_classes.add(output) + + @classmethod + def get_outputs(cls) -> Iterable[BaseInvocationOutput]: + return cls._output_classes + + @classmethod + def get_outputs_union(cls) -> UnionType: + outputs_union = Union[tuple(cls._output_classes)] # type: ignore [valid-type] + return outputs_union # type: ignore [return-value] + + @classmethod + def get_output_types(cls) -> Iterable[str]: + return map(lambda i: get_type(i), BaseInvocationOutput.get_outputs()) + + @staticmethod + def json_schema_extra(schema: dict[str, Any], model_class: Type[BaseModel]) -> None: + # Because we use a pydantic Literal field with default value for the invocation type, + # it will be typed as optional in the OpenAPI schema. Make it required manually. + if "required" not in schema or not isinstance(schema["required"], list): + schema["required"] = list() + schema["required"].extend(["type"]) + + model_config = ConfigDict( + validate_assignment=True, + json_schema_serialization_defaults_required=True, + json_schema_extra=json_schema_extra, + ) class RequiredConnectionException(Exception): @@ -498,104 +547,91 @@ class BaseInvocation(ABC, BaseModel): All invocations must use the `@invocation` decorator to provide their unique type. """ + _invocation_classes: ClassVar[set[BaseInvocation]] = set() + @classmethod - def get_all_subclasses(cls): + def register_invocation(cls, invocation: BaseInvocation) -> None: + cls._invocation_classes.add(invocation) + + @classmethod + def get_invocations_union(cls) -> UnionType: + invocations_union = Union[tuple(cls._invocation_classes)] # type: ignore [valid-type] + return invocations_union # type: ignore [return-value] + + @classmethod + def get_invocations(cls) -> Iterable[BaseInvocation]: app_config = InvokeAIAppConfig.get_config() - subclasses = [] - toprocess = [cls] - while len(toprocess) > 0: - next = toprocess.pop(0) - next_subclasses = next.__subclasses__() - subclasses.extend(next_subclasses) - toprocess.extend(next_subclasses) - allowed_invocations = [] - for sc in subclasses: + allowed_invocations: set[BaseInvocation] = set() + for sc in cls._invocation_classes: + invocation_type = get_type(sc) is_in_allowlist = ( - sc.__fields__.get("type").default in app_config.allow_nodes - if isinstance(app_config.allow_nodes, list) - else True + invocation_type in app_config.allow_nodes if isinstance(app_config.allow_nodes, list) else True ) - is_in_denylist = ( - sc.__fields__.get("type").default in app_config.deny_nodes - if isinstance(app_config.deny_nodes, list) - else False + invocation_type in app_config.deny_nodes if isinstance(app_config.deny_nodes, list) else False ) - if is_in_allowlist and not is_in_denylist: - allowed_invocations.append(sc) + allowed_invocations.add(sc) return allowed_invocations @classmethod - def get_invocations(cls): - return tuple(BaseInvocation.get_all_subclasses()) - - @classmethod - def get_invocations_map(cls): + def get_invocations_map(cls) -> dict[str, BaseInvocation]: # 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), - BaseInvocation.get_all_subclasses(), + lambda i: (get_type(i), i), + BaseInvocation.get_invocations(), ) ) @classmethod - def get_output_type(cls): + def get_invocation_types(cls) -> Iterable[str]: + return map(lambda i: get_type(i), BaseInvocation.get_invocations()) + + @classmethod + def get_output_type(cls) -> BaseInvocationOutput: return signature(cls.invoke).return_annotation - class Config: - validate_assignment = True - validate_all = True - - @staticmethod - def schema_extra(schema: dict[str, Any], model_class: Type[BaseModel]) -> None: - uiconfig = getattr(model_class, "UIConfig", None) - if uiconfig and hasattr(uiconfig, "title"): - schema["title"] = uiconfig.title - if uiconfig and hasattr(uiconfig, "tags"): - schema["tags"] = uiconfig.tags - if uiconfig and hasattr(uiconfig, "category"): - schema["category"] = uiconfig.category - if uiconfig and hasattr(uiconfig, "version"): - schema["version"] = uiconfig.version - if "required" not in schema or not isinstance(schema["required"], list): - schema["required"] = list() - schema["required"].extend(["type", "id"]) + @staticmethod + def json_schema_extra(schema: dict[str, Any], model_class: Type[BaseModel]) -> None: + # Add the various UI-facing attributes to the schema. These are used to build the invocation templates. + uiconfig = getattr(model_class, "UIConfig", None) + if uiconfig and hasattr(uiconfig, "title"): + schema["title"] = uiconfig.title + if uiconfig and hasattr(uiconfig, "tags"): + schema["tags"] = uiconfig.tags + if uiconfig and hasattr(uiconfig, "category"): + schema["category"] = uiconfig.category + if uiconfig and hasattr(uiconfig, "version"): + schema["version"] = uiconfig.version + if "required" not in schema or not isinstance(schema["required"], list): + schema["required"] = list() + schema["required"].extend(["type", "id"]) @abstractmethod def invoke(self, context: InvocationContext) -> BaseInvocationOutput: """Invoke with provided context and return outputs.""" pass - def __init__(self, **data): - # nodes may have required fields, that can accept input from connections - # on instantiation of the model, we need to exclude these from validation - restore = dict() - try: - field_names = list(self.__fields__.keys()) - for field_name in field_names: - # if the field is required and may get its value from a connection, exclude it from validation - field = self.__fields__[field_name] - _input = field.field_info.extra.get("input", None) - if _input in [Input.Connection, Input.Any] and field.required: - if field_name not in data: - restore[field_name] = self.__fields__.pop(field_name) - # instantiate the node, which will validate the data - super().__init__(**data) - finally: - # restore the removed fields - for field_name, field in restore.items(): - self.__fields__[field_name] = field - def invoke_internal(self, context: InvocationContext) -> BaseInvocationOutput: - for field_name, field in self.__fields__.items(): - _input = field.field_info.extra.get("input", None) - if field.required and not hasattr(self, field_name): - if _input == Input.Connection: - raise RequiredConnectionException(self.__fields__["type"].default, field_name) - elif _input == Input.Any: - raise MissingInputException(self.__fields__["type"].default, field_name) + for field_name, field in self.model_fields.items(): + if not field.json_schema_extra or callable(field.json_schema_extra): + # something has gone terribly awry, we should always have this and it should be a dict + continue + + # Here we handle the case where the field is optional in the pydantic class, but required + # in the `invoke()` method. + + orig_default = field.json_schema_extra.get("orig_default", PydanticUndefined) + orig_required = field.json_schema_extra.get("orig_required", True) + input_ = field.json_schema_extra.get("input", None) + if orig_default is not PydanticUndefined and not hasattr(self, field_name): + setattr(self, field_name, orig_default) + if orig_required and orig_default is PydanticUndefined and getattr(self, field_name) is None: + if input_ == Input.Connection: + raise RequiredConnectionException(self.model_fields["type"].default, field_name) + elif input_ == Input.Any: + raise MissingInputException(self.model_fields["type"].default, field_name) # skip node cache codepath if it's disabled if context.services.configuration.node_cache_size == 0: @@ -618,23 +654,31 @@ class BaseInvocation(ABC, BaseModel): return self.invoke(context) def get_type(self) -> str: - return self.__fields__["type"].default + return self.model_fields["type"].default id: str = Field( - description="The id of this instance of an invocation. Must be unique among all instances of invocations." + default_factory=uuid_string, + description="The id of this instance of an invocation. Must be unique among all instances of invocations.", ) - is_intermediate: bool = InputField( - default=False, description="Whether or not this is an intermediate invocation.", ui_type=UIType.IsIntermediate + is_intermediate: Optional[bool] = Field( + default=False, + description="Whether or not this is an intermediate invocation.", + json_schema_extra=dict(ui_type=UIType.IsIntermediate), ) - workflow: Optional[str] = InputField( + workflow: Optional[str] = Field( default=None, description="The workflow to save with the image", - ui_type=UIType.WorkflowField, + json_schema_extra=dict(ui_type=UIType.WorkflowField), + ) + use_cache: Optional[bool] = Field( + default=True, + description="Whether or not to use the cache", ) - use_cache: bool = InputField(default=True, description="Whether or not to use the cache") - @validator("workflow", pre=True) + @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: @@ -645,8 +689,14 @@ class BaseInvocation(ABC, BaseModel): UIConfig: ClassVar[Type[UIConfigBase]] + model_config = ConfigDict( + validate_assignment=True, + json_schema_extra=json_schema_extra, + json_schema_serialization_defaults_required=True, + ) -GenericBaseInvocation = TypeVar("GenericBaseInvocation", bound=BaseInvocation) + +TBaseInvocation = TypeVar("TBaseInvocation", bound=BaseInvocation) def invocation( @@ -656,7 +706,7 @@ def invocation( category: Optional[str] = None, version: Optional[str] = None, use_cache: Optional[bool] = True, -) -> Callable[[Type[GenericBaseInvocation]], Type[GenericBaseInvocation]]: +) -> Callable[[Type[TBaseInvocation]], Type[TBaseInvocation]]: """ Adds metadata to an invocation. @@ -668,12 +718,15 @@ def invocation( :param Optional[bool] use_cache: Whether or not to use the invocation cache. Defaults to True. The user may override this in the workflow editor. """ - def wrapper(cls: Type[GenericBaseInvocation]) -> Type[GenericBaseInvocation]: + def wrapper(cls: Type[TBaseInvocation]) -> Type[TBaseInvocation]: # Validate invocation types on creation of invocation classes # TODO: ensure unique? if re.compile(r"^\S+$").match(invocation_type) is None: raise ValueError(f'"invocation_type" must consist of non-whitespace characters, got "{invocation_type}"') + if invocation_type in BaseInvocation.get_invocation_types(): + raise ValueError(f'Invocation type "{invocation_type}" already exists') + # Add OpenAPI schema extras uiconf_name = cls.__qualname__ + ".UIConfig" if not hasattr(cls, "UIConfig") or cls.UIConfig.__qualname__ != uiconf_name: @@ -691,59 +744,83 @@ def invocation( raise InvalidVersionError(f'Invalid version string for node "{invocation_type}": "{version}"') from e cls.UIConfig.version = version if use_cache is not None: - cls.__fields__["use_cache"].default = use_cache + cls.model_fields["use_cache"].default = use_cache + + # Add the invocation type to the model. + + # You'd be tempted to just add the type field and rebuild the model, like this: + # cls.model_fields.update(type=FieldInfo.from_annotated_attribute(Literal[invocation_type], invocation_type)) + # cls.model_rebuild() or cls.model_rebuild(force=True) + + # Unfortunately, because the `GraphInvocation` uses a forward ref in its `graph` field's annotation, this does + # not work. Instead, we have to create a new class with the type field and patch the original class with it. - # Add the invocation type to the pydantic model of the invocation invocation_type_annotation = Literal[invocation_type] # type: ignore - invocation_type_field = ModelField.infer( - name="type", - value=invocation_type, - annotation=invocation_type_annotation, - class_validators=None, - config=cls.__config__, + invocation_type_field = Field( + title="type", + default=invocation_type, ) - cls.__fields__.update({"type": invocation_type_field}) - # to support 3.9, 3.10 and 3.11, as described in https://docs.python.org/3/howto/annotations.html - if annotations := cls.__dict__.get("__annotations__", None): - annotations.update({"type": invocation_type_annotation}) + + docstring = cls.__doc__ + cls = create_model( + cls.__qualname__, + __base__=cls, + __module__=cls.__module__, + type=(invocation_type_annotation, invocation_type_field), + ) + cls.__doc__ = docstring + + # TODO: how to type this correctly? it's typed as ModelMetaclass, a private class in pydantic + BaseInvocation.register_invocation(cls) # type: ignore + return cls return wrapper -GenericBaseInvocationOutput = TypeVar("GenericBaseInvocationOutput", bound=BaseInvocationOutput) +TBaseInvocationOutput = TypeVar("TBaseInvocationOutput", bound=BaseInvocationOutput) def invocation_output( output_type: str, -) -> Callable[[Type[GenericBaseInvocationOutput]], Type[GenericBaseInvocationOutput]]: +) -> Callable[[Type[TBaseInvocationOutput]], Type[TBaseInvocationOutput]]: """ Adds metadata to an invocation output. :param str output_type: The type of the invocation output. Must be unique among all invocation outputs. """ - def wrapper(cls: Type[GenericBaseInvocationOutput]) -> Type[GenericBaseInvocationOutput]: + def wrapper(cls: Type[TBaseInvocationOutput]) -> Type[TBaseInvocationOutput]: # Validate output types on creation of invocation output classes # TODO: ensure unique? if re.compile(r"^\S+$").match(output_type) is None: raise ValueError(f'"output_type" must consist of non-whitespace characters, got "{output_type}"') - # Add the output type to the pydantic model of the invocation output - output_type_annotation = Literal[output_type] # type: ignore - output_type_field = ModelField.infer( - name="type", - value=output_type, - annotation=output_type_annotation, - class_validators=None, - config=cls.__config__, - ) - cls.__fields__.update({"type": output_type_field}) + if output_type in BaseInvocationOutput.get_output_types(): + raise ValueError(f'Invocation type "{output_type}" already exists') - # to support 3.9, 3.10 and 3.11, as described in https://docs.python.org/3/howto/annotations.html - if annotations := cls.__dict__.get("__annotations__", None): - annotations.update({"type": output_type_annotation}) + # Add the output type to the model. + + output_type_annotation = Literal[output_type] # type: ignore + output_type_field = Field( + title="type", + default=output_type, + ) + + docstring = cls.__doc__ + cls = create_model( + cls.__qualname__, + __base__=cls, + __module__=cls.__module__, + type=(output_type_annotation, output_type_field), + ) + cls.__doc__ = docstring + + BaseInvocationOutput.register_output(cls) # type: ignore # TODO: how to type this correctly? return cls return wrapper + + +GenericBaseModel = TypeVar("GenericBaseModel", bound=BaseModel) diff --git a/invokeai/app/invocations/collections.py b/invokeai/app/invocations/collections.py index 83863422f8..f26eebe1ff 100644 --- a/invokeai/app/invocations/collections.py +++ b/invokeai/app/invocations/collections.py @@ -2,7 +2,7 @@ import numpy as np -from pydantic import validator +from pydantic import ValidationInfo, field_validator from invokeai.app.invocations.primitives import IntegerCollectionOutput from invokeai.app.util.misc import SEED_MAX, get_random_seed @@ -20,9 +20,9 @@ class RangeInvocation(BaseInvocation): stop: int = InputField(default=10, description="The stop of the range") step: int = InputField(default=1, description="The step of the range") - @validator("stop") - def stop_gt_start(cls, v, values): - if "start" in values and v <= values["start"]: + @field_validator("stop") + def stop_gt_start(cls, v: int, info: ValidationInfo): + if "start" in info.data and v <= info.data["start"]: raise ValueError("stop must be greater than start") return v diff --git a/invokeai/app/invocations/compel.py b/invokeai/app/invocations/compel.py index b2634c2c56..b3ebc92320 100644 --- a/invokeai/app/invocations/compel.py +++ b/invokeai/app/invocations/compel.py @@ -1,6 +1,6 @@ import re from dataclasses import dataclass -from typing import List, Union +from typing import List, Optional, Union import torch from compel import Compel, ReturnedEmbeddingsType @@ -43,7 +43,13 @@ class ConditioningFieldData: # PerpNeg = "perp_neg" -@invocation("compel", title="Prompt", tags=["prompt", "compel"], category="conditioning", version="1.0.0") +@invocation( + "compel", + title="Prompt", + tags=["prompt", "compel"], + category="conditioning", + version="1.0.0", +) class CompelInvocation(BaseInvocation): """Parse prompt using compel package to conditioning.""" @@ -61,17 +67,19 @@ class CompelInvocation(BaseInvocation): @torch.no_grad() def invoke(self, context: InvocationContext) -> ConditioningOutput: tokenizer_info = context.services.model_manager.get_model( - **self.clip.tokenizer.dict(), + **self.clip.tokenizer.model_dump(), context=context, ) text_encoder_info = context.services.model_manager.get_model( - **self.clip.text_encoder.dict(), + **self.clip.text_encoder.model_dump(), context=context, ) def _lora_loader(): for lora in self.clip.loras: - lora_info = context.services.model_manager.get_model(**lora.dict(exclude={"weight"}), context=context) + lora_info = context.services.model_manager.get_model( + **lora.model_dump(exclude={"weight"}), context=context + ) yield (lora_info.context.model, lora.weight) del lora_info return @@ -160,11 +168,11 @@ class SDXLPromptInvocationBase: zero_on_empty: bool, ): tokenizer_info = context.services.model_manager.get_model( - **clip_field.tokenizer.dict(), + **clip_field.tokenizer.model_dump(), context=context, ) text_encoder_info = context.services.model_manager.get_model( - **clip_field.text_encoder.dict(), + **clip_field.text_encoder.model_dump(), context=context, ) @@ -172,7 +180,11 @@ class SDXLPromptInvocationBase: if prompt == "" and zero_on_empty: cpu_text_encoder = text_encoder_info.context.model c = torch.zeros( - (1, cpu_text_encoder.config.max_position_embeddings, cpu_text_encoder.config.hidden_size), + ( + 1, + cpu_text_encoder.config.max_position_embeddings, + cpu_text_encoder.config.hidden_size, + ), dtype=text_encoder_info.context.cache.precision, ) if get_pooled: @@ -186,7 +198,9 @@ class SDXLPromptInvocationBase: def _lora_loader(): for lora in clip_field.loras: - lora_info = context.services.model_manager.get_model(**lora.dict(exclude={"weight"}), context=context) + lora_info = context.services.model_manager.get_model( + **lora.model_dump(exclude={"weight"}), context=context + ) yield (lora_info.context.model, lora.weight) del lora_info return @@ -273,8 +287,16 @@ class SDXLPromptInvocationBase: class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase): """Parse prompt using compel package to conditioning.""" - prompt: str = InputField(default="", description=FieldDescriptions.compel_prompt, ui_component=UIComponent.Textarea) - style: str = InputField(default="", description=FieldDescriptions.compel_prompt, ui_component=UIComponent.Textarea) + prompt: str = InputField( + default="", + description=FieldDescriptions.compel_prompt, + ui_component=UIComponent.Textarea, + ) + style: str = InputField( + default="", + description=FieldDescriptions.compel_prompt, + ui_component=UIComponent.Textarea, + ) original_width: int = InputField(default=1024, description="") original_height: int = InputField(default=1024, description="") crop_top: int = InputField(default=0, description="") @@ -310,7 +332,9 @@ class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase): [ c1, torch.zeros( - (c1.shape[0], c2.shape[1] - c1.shape[1], c1.shape[2]), device=c1.device, dtype=c1.dtype + (c1.shape[0], c2.shape[1] - c1.shape[1], c1.shape[2]), + device=c1.device, + dtype=c1.dtype, ), ], dim=1, @@ -321,7 +345,9 @@ class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase): [ c2, torch.zeros( - (c2.shape[0], c1.shape[1] - c2.shape[1], c2.shape[2]), device=c2.device, dtype=c2.dtype + (c2.shape[0], c1.shape[1] - c2.shape[1], c2.shape[2]), + device=c2.device, + dtype=c2.dtype, ), ], dim=1, @@ -359,7 +385,9 @@ class SDXLRefinerCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase """Parse prompt using compel package to conditioning.""" style: str = InputField( - default="", description=FieldDescriptions.compel_prompt, ui_component=UIComponent.Textarea + default="", + description=FieldDescriptions.compel_prompt, + ui_component=UIComponent.Textarea, ) # TODO: ? original_width: int = InputField(default=1024, description="") original_height: int = InputField(default=1024, description="") @@ -403,10 +431,16 @@ class SDXLRefinerCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase class ClipSkipInvocationOutput(BaseInvocationOutput): """Clip skip node output""" - clip: ClipField = OutputField(default=None, description=FieldDescriptions.clip, title="CLIP") + clip: Optional[ClipField] = OutputField(default=None, description=FieldDescriptions.clip, title="CLIP") -@invocation("clip_skip", title="CLIP Skip", tags=["clipskip", "clip", "skip"], category="conditioning", version="1.0.0") +@invocation( + "clip_skip", + title="CLIP Skip", + tags=["clipskip", "clip", "skip"], + category="conditioning", + version="1.0.0", +) class ClipSkipInvocation(BaseInvocation): """Skip layers in clip text_encoder model.""" @@ -421,7 +455,9 @@ class ClipSkipInvocation(BaseInvocation): def get_max_token_count( - tokenizer, prompt: Union[FlattenedPrompt, Blend, Conjunction], truncate_if_too_long=False + tokenizer, + prompt: Union[FlattenedPrompt, Blend, Conjunction], + truncate_if_too_long=False, ) -> int: if type(prompt) is Blend: blend: Blend = prompt diff --git a/invokeai/app/invocations/controlnet_image_processors.py b/invokeai/app/invocations/controlnet_image_processors.py index 59a36935df..200c37d851 100644 --- a/invokeai/app/invocations/controlnet_image_processors.py +++ b/invokeai/app/invocations/controlnet_image_processors.py @@ -2,7 +2,7 @@ # initial implementation by Gregg Helt, 2023 # heavily leverages controlnet_aux package: https://github.com/patrickvonplaten/controlnet_aux from builtins import bool, float -from typing import Dict, List, Literal, Optional, Union +from typing import Dict, List, Literal, Union import cv2 import numpy as np @@ -24,7 +24,7 @@ from controlnet_aux import ( ) from controlnet_aux.util import HWC3, ade_palette from PIL import Image -from pydantic import BaseModel, Field, validator +from pydantic import BaseModel, ConfigDict, Field, field_validator from invokeai.app.invocations.primitives import ImageField, ImageOutput from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin @@ -57,6 +57,8 @@ class ControlNetModelField(BaseModel): model_name: str = Field(description="Name of the ControlNet model") base_model: BaseModelType = Field(description="Base model") + model_config = ConfigDict(protected_namespaces=()) + class ControlField(BaseModel): image: ImageField = Field(description="The control image") @@ -71,7 +73,7 @@ class ControlField(BaseModel): control_mode: CONTROLNET_MODE_VALUES = Field(default="balanced", description="The control mode to use") resize_mode: CONTROLNET_RESIZE_VALUES = Field(default="just_resize", description="The resize mode to use") - @validator("control_weight") + @field_validator("control_weight") def validate_control_weight(cls, v): """Validate that all control weights in the valid range""" if isinstance(v, list): @@ -124,9 +126,7 @@ class ControlNetInvocation(BaseInvocation): ) -@invocation( - "image_processor", title="Base Image Processor", tags=["controlnet"], category="controlnet", version="1.0.0" -) +# This invocation exists for other invocations to subclass it - do not register with @invocation! class ImageProcessorInvocation(BaseInvocation): """Base class for invocations that preprocess images for ControlNet""" @@ -393,9 +393,9 @@ class ContentShuffleImageProcessorInvocation(ImageProcessorInvocation): detect_resolution: int = InputField(default=512, ge=0, description=FieldDescriptions.detect_res) image_resolution: int = InputField(default=512, ge=0, description=FieldDescriptions.image_res) - h: Optional[int] = InputField(default=512, ge=0, description="Content shuffle `h` parameter") - w: Optional[int] = InputField(default=512, ge=0, description="Content shuffle `w` parameter") - f: Optional[int] = InputField(default=256, ge=0, description="Content shuffle `f` parameter") + h: int = InputField(default=512, ge=0, description="Content shuffle `h` parameter") + w: int = InputField(default=512, ge=0, description="Content shuffle `w` parameter") + f: int = InputField(default=256, ge=0, description="Content shuffle `f` parameter") def run_processor(self, image): content_shuffle_processor = ContentShuffleDetector() @@ -575,14 +575,14 @@ class ColorMapImageProcessorInvocation(ImageProcessorInvocation): def run_processor(self, image: Image.Image): image = image.convert("RGB") - image = np.array(image, dtype=np.uint8) - height, width = image.shape[:2] + np_image = np.array(image, dtype=np.uint8) + height, width = np_image.shape[:2] width_tile_size = min(self.color_map_tile_size, width) height_tile_size = min(self.color_map_tile_size, height) color_map = cv2.resize( - image, + np_image, (width // width_tile_size, height // height_tile_size), interpolation=cv2.INTER_CUBIC, ) diff --git a/invokeai/app/invocations/facetools.py b/invokeai/app/invocations/facetools.py index a433fac792..40e15e9476 100644 --- a/invokeai/app/invocations/facetools.py +++ b/invokeai/app/invocations/facetools.py @@ -8,7 +8,7 @@ import numpy as np from mediapipe.python.solutions.face_mesh import FaceMesh # type: ignore[import] from PIL import Image, ImageDraw, ImageFilter, ImageFont, ImageOps from PIL.Image import Image as ImageType -from pydantic import validator +from pydantic import field_validator import invokeai.assets.fonts as font_assets from invokeai.app.invocations.baseinvocation import ( @@ -46,6 +46,8 @@ class FaceResultData(TypedDict): y_center: float mesh_width: int mesh_height: int + chunk_x_offset: int + chunk_y_offset: int class FaceResultDataWithId(FaceResultData): @@ -78,6 +80,48 @@ FONT_SIZE = 32 FONT_STROKE_WIDTH = 4 +def coalesce_faces(face1: FaceResultData, face2: FaceResultData) -> FaceResultData: + face1_x_offset = face1["chunk_x_offset"] - min(face1["chunk_x_offset"], face2["chunk_x_offset"]) + face2_x_offset = face2["chunk_x_offset"] - min(face1["chunk_x_offset"], face2["chunk_x_offset"]) + face1_y_offset = face1["chunk_y_offset"] - min(face1["chunk_y_offset"], face2["chunk_y_offset"]) + face2_y_offset = face2["chunk_y_offset"] - min(face1["chunk_y_offset"], face2["chunk_y_offset"]) + + new_im_width = ( + max(face1["image"].width, face2["image"].width) + + max(face1["chunk_x_offset"], face2["chunk_x_offset"]) + - min(face1["chunk_x_offset"], face2["chunk_x_offset"]) + ) + new_im_height = ( + max(face1["image"].height, face2["image"].height) + + max(face1["chunk_y_offset"], face2["chunk_y_offset"]) + - min(face1["chunk_y_offset"], face2["chunk_y_offset"]) + ) + pil_image = Image.new(mode=face1["image"].mode, size=(new_im_width, new_im_height)) + pil_image.paste(face1["image"], (face1_x_offset, face1_y_offset)) + pil_image.paste(face2["image"], (face2_x_offset, face2_y_offset)) + + # Mask images are always from the origin + new_mask_im_width = max(face1["mask"].width, face2["mask"].width) + new_mask_im_height = max(face1["mask"].height, face2["mask"].height) + mask_pil = create_white_image(new_mask_im_width, new_mask_im_height) + black_image = create_black_image(face1["mask"].width, face1["mask"].height) + mask_pil.paste(black_image, (0, 0), ImageOps.invert(face1["mask"])) + black_image = create_black_image(face2["mask"].width, face2["mask"].height) + mask_pil.paste(black_image, (0, 0), ImageOps.invert(face2["mask"])) + + new_face = FaceResultData( + image=pil_image, + mask=mask_pil, + x_center=max(face1["x_center"], face2["x_center"]), + y_center=max(face1["y_center"], face2["y_center"]), + mesh_width=max(face1["mesh_width"], face2["mesh_width"]), + mesh_height=max(face1["mesh_height"], face2["mesh_height"]), + chunk_x_offset=max(face1["chunk_x_offset"], face2["chunk_x_offset"]), + chunk_y_offset=max(face2["chunk_y_offset"], face2["chunk_y_offset"]), + ) + return new_face + + def prepare_faces_list( face_result_list: list[FaceResultData], ) -> list[FaceResultDataWithId]: @@ -91,7 +135,7 @@ def prepare_faces_list( should_add = True candidate_x_center = candidate["x_center"] candidate_y_center = candidate["y_center"] - for face in deduped_faces: + for idx, face in enumerate(deduped_faces): face_center_x = face["x_center"] face_center_y = face["y_center"] face_radius_w = face["mesh_width"] / 2 @@ -105,6 +149,7 @@ def prepare_faces_list( ) if p < 1: # Inside of the already-added face's radius + deduped_faces[idx] = coalesce_faces(face, candidate) should_add = False break @@ -138,7 +183,6 @@ def generate_face_box_mask( chunk_x_offset: int = 0, chunk_y_offset: int = 0, draw_mesh: bool = True, - check_bounds: bool = True, ) -> list[FaceResultData]: result = [] mask_pil = None @@ -211,33 +255,20 @@ def generate_face_box_mask( mask_pil = create_white_image(w + chunk_x_offset, h + chunk_y_offset) mask_pil.paste(init_mask_pil, (chunk_x_offset, chunk_y_offset)) - left_side = x_center - mesh_width - right_side = x_center + mesh_width - top_side = y_center - mesh_height - bottom_side = y_center + mesh_height - im_width, im_height = pil_image.size - over_w = im_width * 0.1 - over_h = im_height * 0.1 - if not check_bounds or ( - (left_side >= -over_w) - and (right_side < im_width + over_w) - and (top_side >= -over_h) - and (bottom_side < im_height + over_h) - ): - x_center = float(x_center) - y_center = float(y_center) - face = FaceResultData( - image=pil_image, - mask=mask_pil or create_white_image(*pil_image.size), - x_center=x_center + chunk_x_offset, - y_center=y_center + chunk_y_offset, - mesh_width=mesh_width, - mesh_height=mesh_height, - ) + x_center = float(x_center) + y_center = float(y_center) + face = FaceResultData( + image=pil_image, + mask=mask_pil or create_white_image(*pil_image.size), + x_center=x_center + chunk_x_offset, + y_center=y_center + chunk_y_offset, + mesh_width=mesh_width, + mesh_height=mesh_height, + chunk_x_offset=chunk_x_offset, + chunk_y_offset=chunk_y_offset, + ) - result.append(face) - else: - context.services.logger.info("FaceTools --> Face out of bounds, ignoring.") + result.append(face) return result @@ -346,7 +377,6 @@ def get_faces_list( chunk_x_offset=0, chunk_y_offset=0, draw_mesh=draw_mesh, - check_bounds=False, ) if should_chunk or len(result) == 0: context.services.logger.info("FaceTools --> Chunking image (chunk toggled on, or no face found in full image).") @@ -360,24 +390,26 @@ def get_faces_list( if width > height: # Landscape - slice the image horizontally fx = 0.0 - steps = int(width * 2 / height) + steps = int(width * 2 / height) + 1 + increment = (width - height) / (steps - 1) while fx <= (width - height): x = int(fx) - image_chunks.append(image.crop((x, 0, x + height - 1, height - 1))) + image_chunks.append(image.crop((x, 0, x + height, height))) x_offsets.append(x) y_offsets.append(0) - fx += (width - height) / steps + fx += increment context.services.logger.info(f"FaceTools --> Chunk starting at x = {x}") elif height > width: # Portrait - slice the image vertically fy = 0.0 - steps = int(height * 2 / width) + steps = int(height * 2 / width) + 1 + increment = (height - width) / (steps - 1) while fy <= (height - width): y = int(fy) - image_chunks.append(image.crop((0, y, width - 1, y + width - 1))) + image_chunks.append(image.crop((0, y, width, y + width))) x_offsets.append(0) y_offsets.append(y) - fy += (height - width) / steps + fy += increment context.services.logger.info(f"FaceTools --> Chunk starting at y = {y}") for idx in range(len(image_chunks)): @@ -404,7 +436,7 @@ def get_faces_list( return all_faces -@invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.0.1") +@invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.0.2") class FaceOffInvocation(BaseInvocation): """Bound, extract, and mask a face from an image using MediaPipe detection""" @@ -498,7 +530,7 @@ class FaceOffInvocation(BaseInvocation): return output -@invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.0.1") +@invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.0.2") class FaceMaskInvocation(BaseInvocation): """Face mask creation using mediapipe face detection""" @@ -518,7 +550,7 @@ class FaceMaskInvocation(BaseInvocation): ) invert_mask: bool = InputField(default=False, description="Toggle to invert the mask") - @validator("face_ids") + @field_validator("face_ids") def validate_comma_separated_ints(cls, v) -> str: comma_separated_ints_regex = re.compile(r"^\d*(,\d+)*$") if comma_separated_ints_regex.match(v) is None: @@ -616,7 +648,7 @@ class FaceMaskInvocation(BaseInvocation): @invocation( - "face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.0.1" + "face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.0.2" ) class FaceIdentifierInvocation(BaseInvocation): """Outputs an image with detected face IDs printed on each face. For use with other FaceTools.""" diff --git a/invokeai/app/invocations/image.py b/invokeai/app/invocations/image.py index 2d59a567c0..3a4f4eadac 100644 --- a/invokeai/app/invocations/image.py +++ b/invokeai/app/invocations/image.py @@ -36,7 +36,13 @@ class ShowImageInvocation(BaseInvocation): ) -@invocation("blank_image", title="Blank Image", tags=["image"], category="image", version="1.0.0") +@invocation( + "blank_image", + title="Blank Image", + tags=["image"], + category="image", + version="1.0.0", +) class BlankImageInvocation(BaseInvocation): """Creates a blank image and forwards it to the pipeline""" @@ -65,7 +71,13 @@ class BlankImageInvocation(BaseInvocation): ) -@invocation("img_crop", title="Crop Image", tags=["image", "crop"], category="image", version="1.0.0") +@invocation( + "img_crop", + title="Crop Image", + tags=["image", "crop"], + category="image", + version="1.0.0", +) class ImageCropInvocation(BaseInvocation): """Crops an image to a specified box. The box can be outside of the image.""" @@ -98,7 +110,13 @@ class ImageCropInvocation(BaseInvocation): ) -@invocation("img_paste", title="Paste Image", tags=["image", "paste"], category="image", version="1.0.1") +@invocation( + "img_paste", + title="Paste Image", + tags=["image", "paste"], + category="image", + version="1.0.1", +) class ImagePasteInvocation(BaseInvocation): """Pastes an image into another image.""" @@ -151,7 +169,13 @@ class ImagePasteInvocation(BaseInvocation): ) -@invocation("tomask", title="Mask from Alpha", tags=["image", "mask"], category="image", version="1.0.0") +@invocation( + "tomask", + title="Mask from Alpha", + tags=["image", "mask"], + category="image", + version="1.0.0", +) class MaskFromAlphaInvocation(BaseInvocation): """Extracts the alpha channel of an image as a mask.""" @@ -182,7 +206,13 @@ class MaskFromAlphaInvocation(BaseInvocation): ) -@invocation("img_mul", title="Multiply Images", tags=["image", "multiply"], category="image", version="1.0.0") +@invocation( + "img_mul", + title="Multiply Images", + tags=["image", "multiply"], + category="image", + version="1.0.0", +) class ImageMultiplyInvocation(BaseInvocation): """Multiplies two images together using `PIL.ImageChops.multiply()`.""" @@ -215,7 +245,13 @@ 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") +@invocation( + "img_chan", + title="Extract Image Channel", + tags=["image", "channel"], + category="image", + version="1.0.0", +) class ImageChannelInvocation(BaseInvocation): """Gets a channel from an image.""" @@ -247,7 +283,13 @@ 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") +@invocation( + "img_conv", + title="Convert Image Mode", + tags=["image", "convert"], + category="image", + version="1.0.0", +) class ImageConvertInvocation(BaseInvocation): """Converts an image to a different mode.""" @@ -276,7 +318,13 @@ class ImageConvertInvocation(BaseInvocation): ) -@invocation("img_blur", title="Blur Image", tags=["image", "blur"], category="image", version="1.0.0") +@invocation( + "img_blur", + title="Blur Image", + tags=["image", "blur"], + category="image", + version="1.0.0", +) class ImageBlurInvocation(BaseInvocation): """Blurs an image""" @@ -330,7 +378,13 @@ PIL_RESAMPLING_MAP = { } -@invocation("img_resize", title="Resize Image", tags=["image", "resize"], category="image", version="1.0.0") +@invocation( + "img_resize", + title="Resize Image", + tags=["image", "resize"], + category="image", + version="1.0.0", +) class ImageResizeInvocation(BaseInvocation): """Resizes an image to specific dimensions""" @@ -359,7 +413,7 @@ class ImageResizeInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) @@ -370,7 +424,13 @@ class ImageResizeInvocation(BaseInvocation): ) -@invocation("img_scale", title="Scale Image", tags=["image", "scale"], category="image", version="1.0.0") +@invocation( + "img_scale", + title="Scale Image", + tags=["image", "scale"], + category="image", + version="1.0.0", +) class ImageScaleInvocation(BaseInvocation): """Scales an image by a factor""" @@ -411,7 +471,13 @@ class ImageScaleInvocation(BaseInvocation): ) -@invocation("img_lerp", title="Lerp Image", tags=["image", "lerp"], category="image", version="1.0.0") +@invocation( + "img_lerp", + title="Lerp Image", + tags=["image", "lerp"], + category="image", + version="1.0.0", +) class ImageLerpInvocation(BaseInvocation): """Linear interpolation of all pixels of an image""" @@ -444,7 +510,13 @@ class ImageLerpInvocation(BaseInvocation): ) -@invocation("img_ilerp", title="Inverse Lerp Image", tags=["image", "ilerp"], category="image", version="1.0.0") +@invocation( + "img_ilerp", + title="Inverse Lerp Image", + tags=["image", "ilerp"], + category="image", + version="1.0.0", +) class ImageInverseLerpInvocation(BaseInvocation): """Inverse linear interpolation of all pixels of an image""" @@ -456,7 +528,7 @@ class ImageInverseLerpInvocation(BaseInvocation): image = context.services.images.get_pil_image(self.image.image_name) image_arr = numpy.asarray(image, dtype=numpy.float32) - image_arr = numpy.minimum(numpy.maximum(image_arr - self.min, 0) / float(self.max - self.min), 1) * 255 + image_arr = numpy.minimum(numpy.maximum(image_arr - self.min, 0) / float(self.max - self.min), 1) * 255 # type: ignore [assignment] ilerp_image = Image.fromarray(numpy.uint8(image_arr)) @@ -477,7 +549,13 @@ class ImageInverseLerpInvocation(BaseInvocation): ) -@invocation("img_nsfw", title="Blur NSFW Image", tags=["image", "nsfw"], category="image", version="1.0.0") +@invocation( + "img_nsfw", + title="Blur NSFW Image", + tags=["image", "nsfw"], + category="image", + version="1.0.0", +) class ImageNSFWBlurInvocation(BaseInvocation): """Add blur to NSFW-flagged images""" @@ -505,7 +583,7 @@ class ImageNSFWBlurInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) @@ -515,7 +593,7 @@ class ImageNSFWBlurInvocation(BaseInvocation): height=image_dto.height, ) - def _get_caution_img(self) -> Image: + def _get_caution_img(self) -> Image.Image: import invokeai.app.assets.images as image_assets caution = Image.open(Path(image_assets.__path__[0]) / "caution.png") @@ -523,7 +601,11 @@ class ImageNSFWBlurInvocation(BaseInvocation): @invocation( - "img_watermark", title="Add Invisible Watermark", tags=["image", "watermark"], category="image", version="1.0.0" + "img_watermark", + title="Add Invisible Watermark", + tags=["image", "watermark"], + category="image", + version="1.0.0", ) class ImageWatermarkInvocation(BaseInvocation): """Add an invisible watermark to an image""" @@ -544,7 +626,7 @@ class ImageWatermarkInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) @@ -555,7 +637,13 @@ class ImageWatermarkInvocation(BaseInvocation): ) -@invocation("mask_edge", title="Mask Edge", tags=["image", "mask", "inpaint"], category="image", version="1.0.0") +@invocation( + "mask_edge", + title="Mask Edge", + tags=["image", "mask", "inpaint"], + category="image", + version="1.0.0", +) class MaskEdgeInvocation(BaseInvocation): """Applies an edge mask to an image""" @@ -601,7 +689,11 @@ class MaskEdgeInvocation(BaseInvocation): @invocation( - "mask_combine", title="Combine Masks", tags=["image", "mask", "multiply"], category="image", version="1.0.0" + "mask_combine", + title="Combine Masks", + tags=["image", "mask", "multiply"], + category="image", + version="1.0.0", ) class MaskCombineInvocation(BaseInvocation): """Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`.""" @@ -632,7 +724,13 @@ class MaskCombineInvocation(BaseInvocation): ) -@invocation("color_correct", title="Color Correct", tags=["image", "color"], category="image", version="1.0.0") +@invocation( + "color_correct", + title="Color Correct", + tags=["image", "color"], + category="image", + version="1.0.0", +) class ColorCorrectInvocation(BaseInvocation): """ Shifts the colors of a target image to match the reference image, optionally @@ -742,7 +840,13 @@ class ColorCorrectInvocation(BaseInvocation): ) -@invocation("img_hue_adjust", title="Adjust Image Hue", tags=["image", "hue"], category="image", version="1.0.0") +@invocation( + "img_hue_adjust", + title="Adjust Image Hue", + tags=["image", "hue"], + category="image", + version="1.0.0", +) class ImageHueAdjustmentInvocation(BaseInvocation): """Adjusts the Hue of an image.""" @@ -980,7 +1084,7 @@ class SaveImageInvocation(BaseInvocation): image: ImageField = InputField(description=FieldDescriptions.image) board: Optional[BoardField] = InputField(default=None, description=FieldDescriptions.board, input=Input.Direct) - metadata: CoreMetadata = InputField( + metadata: Optional[CoreMetadata] = InputField( default=None, description=FieldDescriptions.core_metadata, ui_hidden=True, @@ -997,7 +1101,7 @@ class SaveImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) diff --git a/invokeai/app/invocations/ip_adapter.py b/invokeai/app/invocations/ip_adapter.py index 3e3a3d9b1f..81fd1f9f5d 100644 --- a/invokeai/app/invocations/ip_adapter.py +++ b/invokeai/app/invocations/ip_adapter.py @@ -2,7 +2,7 @@ import os from builtins import float from typing import List, Union -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from invokeai.app.invocations.baseinvocation import ( BaseInvocation, @@ -25,11 +25,15 @@ class IPAdapterModelField(BaseModel): model_name: str = Field(description="Name of the IP-Adapter model") base_model: BaseModelType = Field(description="Base model") + model_config = ConfigDict(protected_namespaces=()) + class CLIPVisionModelField(BaseModel): model_name: str = Field(description="Name of the CLIP Vision image encoder model") base_model: BaseModelType = Field(description="Base model (usually 'Any')") + model_config = ConfigDict(protected_namespaces=()) + class IPAdapterField(BaseModel): image: ImageField = Field(description="The IP-Adapter image prompt.") diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 7ca8cbbe6c..7ce0ae7a8a 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -19,7 +19,7 @@ from diffusers.models.attention_processor import ( ) from diffusers.schedulers import DPMSolverSDEScheduler from diffusers.schedulers import SchedulerMixin as Scheduler -from pydantic import validator +from pydantic import field_validator from torchvision.transforms.functional import resize as tv_resize from invokeai.app.invocations.ip_adapter import IPAdapterField @@ -84,12 +84,20 @@ class SchedulerOutput(BaseInvocationOutput): scheduler: SAMPLER_NAME_VALUES = OutputField(description=FieldDescriptions.scheduler, ui_type=UIType.Scheduler) -@invocation("scheduler", title="Scheduler", tags=["scheduler"], category="latents", version="1.0.0") +@invocation( + "scheduler", + title="Scheduler", + tags=["scheduler"], + category="latents", + version="1.0.0", +) class SchedulerInvocation(BaseInvocation): """Selects a scheduler.""" scheduler: SAMPLER_NAME_VALUES = InputField( - default="euler", description=FieldDescriptions.scheduler, ui_type=UIType.Scheduler + default="euler", + description=FieldDescriptions.scheduler, + ui_type=UIType.Scheduler, ) def invoke(self, context: InvocationContext) -> SchedulerOutput: @@ -97,7 +105,11 @@ class SchedulerInvocation(BaseInvocation): @invocation( - "create_denoise_mask", title="Create Denoise Mask", tags=["mask", "denoise"], category="latents", version="1.0.0" + "create_denoise_mask", + title="Create Denoise Mask", + tags=["mask", "denoise"], + category="latents", + version="1.0.0", ) class CreateDenoiseMaskInvocation(BaseInvocation): """Creates mask for denoising model run.""" @@ -106,7 +118,11 @@ class CreateDenoiseMaskInvocation(BaseInvocation): image: Optional[ImageField] = InputField(default=None, description="Image which will be masked", ui_order=1) mask: ImageField = InputField(description="The mask to use when pasting", ui_order=2) tiled: bool = InputField(default=False, description=FieldDescriptions.tiled, ui_order=3) - fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32, ui_order=4) + fp32: bool = InputField( + default=DEFAULT_PRECISION == "float32", + description=FieldDescriptions.fp32, + ui_order=4, + ) def prep_mask_tensor(self, mask_image): if mask_image.mode != "L": @@ -134,7 +150,7 @@ class CreateDenoiseMaskInvocation(BaseInvocation): if image is not None: vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), + **self.vae.vae.model_dump(), context=context, ) @@ -167,7 +183,7 @@ def get_scheduler( ) -> Scheduler: scheduler_class, scheduler_extra_config = SCHEDULER_MAP.get(scheduler_name, SCHEDULER_MAP["ddim"]) orig_scheduler_info = context.services.model_manager.get_model( - **scheduler_info.dict(), + **scheduler_info.model_dump(), context=context, ) with orig_scheduler_info as orig_scheduler: @@ -209,34 +225,64 @@ class DenoiseLatentsInvocation(BaseInvocation): negative_conditioning: ConditioningField = InputField( description=FieldDescriptions.negative_cond, input=Input.Connection, ui_order=1 ) - noise: Optional[LatentsField] = InputField(description=FieldDescriptions.noise, input=Input.Connection, ui_order=3) + noise: Optional[LatentsField] = InputField( + default=None, + description=FieldDescriptions.noise, + input=Input.Connection, + ui_order=3, + ) steps: int = InputField(default=10, gt=0, description=FieldDescriptions.steps) cfg_scale: Union[float, List[float]] = InputField( default=7.5, ge=1, description=FieldDescriptions.cfg_scale, title="CFG Scale" ) - denoising_start: float = InputField(default=0.0, ge=0, le=1, description=FieldDescriptions.denoising_start) + denoising_start: float = InputField( + default=0.0, + ge=0, + le=1, + description=FieldDescriptions.denoising_start, + ) denoising_end: float = InputField(default=1.0, ge=0, le=1, description=FieldDescriptions.denoising_end) scheduler: SAMPLER_NAME_VALUES = InputField( - default="euler", description=FieldDescriptions.scheduler, ui_type=UIType.Scheduler + default="euler", + description=FieldDescriptions.scheduler, + ui_type=UIType.Scheduler, ) - unet: UNetField = InputField(description=FieldDescriptions.unet, input=Input.Connection, title="UNet", ui_order=2) - control: Union[ControlField, list[ControlField]] = InputField( + unet: UNetField = InputField( + description=FieldDescriptions.unet, + input=Input.Connection, + title="UNet", + ui_order=2, + ) + control: Optional[Union[ControlField, list[ControlField]]] = InputField( default=None, input=Input.Connection, ui_order=5, ) ip_adapter: Optional[Union[IPAdapterField, list[IPAdapterField]]] = InputField( - description=FieldDescriptions.ip_adapter, title="IP-Adapter", default=None, input=Input.Connection, ui_order=6 + description=FieldDescriptions.ip_adapter, + title="IP-Adapter", + default=None, + input=Input.Connection, + ui_order=6, ) - t2i_adapter: Union[T2IAdapterField, list[T2IAdapterField]] = InputField( - description=FieldDescriptions.t2i_adapter, title="T2I-Adapter", default=None, input=Input.Connection, ui_order=7 + t2i_adapter: Optional[Union[T2IAdapterField, list[T2IAdapterField]]] = InputField( + description=FieldDescriptions.t2i_adapter, + title="T2I-Adapter", + default=None, + input=Input.Connection, + ui_order=7, + ) + latents: Optional[LatentsField] = InputField( + default=None, description=FieldDescriptions.latents, input=Input.Connection ) - latents: Optional[LatentsField] = InputField(description=FieldDescriptions.latents, input=Input.Connection) denoise_mask: Optional[DenoiseMaskField] = InputField( - default=None, description=FieldDescriptions.mask, input=Input.Connection, ui_order=8 + default=None, + description=FieldDescriptions.mask, + input=Input.Connection, + ui_order=8, ) - @validator("cfg_scale") + @field_validator("cfg_scale") def ge_one(cls, v): """validate that all cfg_scale values are >= 1""" if isinstance(v, list): @@ -259,7 +305,7 @@ class DenoiseLatentsInvocation(BaseInvocation): stable_diffusion_step_callback( context=context, intermediate_state=intermediate_state, - node=self.dict(), + node=self.model_dump(), source_node_id=source_node_id, base_model=base_model, ) @@ -451,9 +497,10 @@ class DenoiseLatentsInvocation(BaseInvocation): # 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 - ) + ( + image_prompt_embeds, + uncond_image_prompt_embeds, + ) = ip_adapter_model.get_image_embeds(input_image, image_encoder_model) conditioning_data.ip_adapter_conditioning.append( IPAdapterConditioningInfo(image_prompt_embeds, uncond_image_prompt_embeds) ) @@ -628,7 +675,10 @@ class DenoiseLatentsInvocation(BaseInvocation): # TODO(ryand): I have hard-coded `do_classifier_free_guidance=True` to mirror the behaviour of ControlNets, # below. Investigate whether this is appropriate. t2i_adapter_data = self.run_t2i_adapters( - context, self.t2i_adapter, latents.shape, do_classifier_free_guidance=True + context, + self.t2i_adapter, + latents.shape, + do_classifier_free_guidance=True, ) # Get the source node id (we are invoking the prepared node) @@ -641,7 +691,7 @@ class DenoiseLatentsInvocation(BaseInvocation): def _lora_loader(): for lora in self.unet.loras: lora_info = context.services.model_manager.get_model( - **lora.dict(exclude={"weight"}), + **lora.model_dump(exclude={"weight"}), context=context, ) yield (lora_info.context.model, lora.weight) @@ -649,7 +699,7 @@ class DenoiseLatentsInvocation(BaseInvocation): return unet_info = context.services.model_manager.get_model( - **self.unet.unet.dict(), + **self.unet.unet.model_dump(), context=context, ) with ( @@ -700,7 +750,10 @@ class DenoiseLatentsInvocation(BaseInvocation): denoising_end=self.denoising_end, ) - result_latents, result_attention_map_saver = pipeline.latents_from_embeddings( + ( + result_latents, + result_attention_map_saver, + ) = pipeline.latents_from_embeddings( latents=latents, timesteps=timesteps, init_timestep=init_timestep, @@ -728,7 +781,11 @@ class DenoiseLatentsInvocation(BaseInvocation): @invocation( - "l2i", title="Latents to Image", tags=["latents", "image", "vae", "l2i"], category="latents", version="1.0.0" + "l2i", + title="Latents to Image", + tags=["latents", "image", "vae", "l2i"], + category="latents", + version="1.0.0", ) class LatentsToImageInvocation(BaseInvocation): """Generates an image from latents.""" @@ -743,7 +800,7 @@ class LatentsToImageInvocation(BaseInvocation): ) tiled: bool = InputField(default=False, description=FieldDescriptions.tiled) fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32) - metadata: CoreMetadata = InputField( + metadata: Optional[CoreMetadata] = InputField( default=None, description=FieldDescriptions.core_metadata, ui_hidden=True, @@ -754,7 +811,7 @@ class LatentsToImageInvocation(BaseInvocation): latents = context.services.latents.get(self.latents.latents_name) vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), + **self.vae.vae.model_dump(), context=context, ) @@ -816,7 +873,7 @@ class LatentsToImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) @@ -830,7 +887,13 @@ class LatentsToImageInvocation(BaseInvocation): LATENTS_INTERPOLATION_MODE = Literal["nearest", "linear", "bilinear", "bicubic", "trilinear", "area", "nearest-exact"] -@invocation("lresize", title="Resize Latents", tags=["latents", "resize"], category="latents", version="1.0.0") +@invocation( + "lresize", + title="Resize Latents", + tags=["latents", "resize"], + category="latents", + version="1.0.0", +) class ResizeLatentsInvocation(BaseInvocation): """Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8.""" @@ -876,7 +939,13 @@ class ResizeLatentsInvocation(BaseInvocation): return build_latents_output(latents_name=name, latents=resized_latents, seed=self.latents.seed) -@invocation("lscale", title="Scale Latents", tags=["latents", "resize"], category="latents", version="1.0.0") +@invocation( + "lscale", + title="Scale Latents", + tags=["latents", "resize"], + category="latents", + version="1.0.0", +) class ScaleLatentsInvocation(BaseInvocation): """Scales latents by a given factor.""" @@ -915,7 +984,11 @@ class ScaleLatentsInvocation(BaseInvocation): @invocation( - "i2l", title="Image to Latents", tags=["latents", "image", "vae", "i2l"], category="latents", version="1.0.0" + "i2l", + title="Image to Latents", + tags=["latents", "image", "vae", "i2l"], + category="latents", + version="1.0.0", ) class ImageToLatentsInvocation(BaseInvocation): """Encodes an image into latents.""" @@ -979,7 +1052,7 @@ class ImageToLatentsInvocation(BaseInvocation): image = context.services.images.get_pil_image(self.image.image_name) vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), + **self.vae.vae.model_dump(), context=context, ) @@ -1007,7 +1080,13 @@ class ImageToLatentsInvocation(BaseInvocation): return vae.encode(image_tensor).latents -@invocation("lblend", title="Blend Latents", tags=["latents", "blend"], category="latents", version="1.0.0") +@invocation( + "lblend", + title="Blend Latents", + tags=["latents", "blend"], + category="latents", + version="1.0.0", +) class BlendLatentsInvocation(BaseInvocation): """Blend two latents using a given alpha. Latents must have same size.""" diff --git a/invokeai/app/invocations/math.py b/invokeai/app/invocations/math.py index b52cbb28bf..2aefa1def4 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 validator +from pydantic import field_validator from invokeai.app.invocations.primitives import FloatOutput, IntegerOutput @@ -72,7 +72,14 @@ class RandomIntInvocation(BaseInvocation): return IntegerOutput(value=np.random.randint(self.low, self.high)) -@invocation("rand_float", title="Random Float", tags=["math", "float", "random"], category="math", version="1.0.0") +@invocation( + "rand_float", + title="Random Float", + tags=["math", "float", "random"], + category="math", + version="1.0.1", + use_cache=False, +) class RandomFloatInvocation(BaseInvocation): """Outputs a single random float""" @@ -178,7 +185,7 @@ class IntegerMathInvocation(BaseInvocation): a: int = InputField(default=0, description=FieldDescriptions.num_1) b: int = InputField(default=0, description=FieldDescriptions.num_2) - @validator("b") + @field_validator("b") def no_unrepresentable_results(cls, v, values): if values["operation"] == "DIV" and v == 0: raise ValueError("Cannot divide by zero") @@ -252,7 +259,7 @@ class FloatMathInvocation(BaseInvocation): a: float = InputField(default=0, description=FieldDescriptions.num_1) b: float = InputField(default=0, description=FieldDescriptions.num_2) - @validator("b") + @field_validator("b") def no_unrepresentable_results(cls, v, values): if values["operation"] == "DIV" and v == 0: raise ValueError("Cannot divide by zero") diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 54e385feb3..4d76926aaa 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -44,28 +44,31 @@ class CoreMetadata(BaseModelExcludeNull): """Core generation metadata for an image generated in InvokeAI.""" app_version: str = Field(default=__version__, description="The version of InvokeAI used to generate this image") - generation_mode: str = Field( + generation_mode: Optional[str] = Field( + default=None, description="The generation mode that output this image", ) - created_by: Optional[str] = Field(description="The name of the creator of the image") - positive_prompt: str = Field(description="The positive prompt parameter") - negative_prompt: str = Field(description="The negative prompt parameter") - width: int = Field(description="The width parameter") - height: int = Field(description="The height parameter") - seed: int = Field(description="The seed used for noise generation") - rand_device: str = Field(description="The device used for random number generation") - cfg_scale: float = Field(description="The classifier-free guidance scale parameter") - steps: int = Field(description="The number of steps used for inference") - scheduler: str = Field(description="The scheduler used for inference") + 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: MainModelField = Field(description="The main model used for inference") - controlnets: list[ControlField] = Field(description="The ControlNets used for inference") - ipAdapters: list[IPAdapterMetadataField] = Field(description="The IP Adapters used for inference") - t2iAdapters: list[T2IAdapterField] = Field(description="The IP Adapters used for inference") - loras: list[LoRAMetadataField] = Field(description="The LoRAs used for inference") + 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", @@ -122,27 +125,34 @@ class MetadataAccumulatorOutput(BaseInvocationOutput): class MetadataAccumulatorInvocation(BaseInvocation): """Outputs a Core Metadata Object""" - generation_mode: str = InputField( + generation_mode: Optional[str] = InputField( + default=None, description="The generation mode that output this image", ) - positive_prompt: str = InputField(description="The positive prompt parameter") - negative_prompt: str = InputField(description="The negative prompt parameter") - width: int = InputField(description="The width parameter") - height: int = InputField(description="The height parameter") - seed: int = InputField(description="The seed used for noise generation") - rand_device: str = InputField(description="The device used for random number generation") - cfg_scale: float = InputField(description="The classifier-free guidance scale parameter") - steps: int = InputField(description="The number of steps used for inference") - scheduler: str = InputField(description="The scheduler used for inference") - clip_skip: Optional[int] = Field( + positive_prompt: Optional[str] = InputField(default=None, description="The positive prompt parameter") + negative_prompt: Optional[str] = InputField(default=None, description="The negative prompt parameter") + width: Optional[int] = InputField(default=None, description="The width parameter") + height: Optional[int] = InputField(default=None, description="The height parameter") + seed: Optional[int] = InputField(default=None, description="The seed used for noise generation") + rand_device: Optional[str] = InputField(default=None, description="The device used for random number generation") + cfg_scale: Optional[float] = InputField(default=None, description="The classifier-free guidance scale parameter") + 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") + clip_skip: Optional[int] = InputField( default=None, description="The number of skipped CLIP layers", ) - model: MainModelField = InputField(description="The main model used for inference") - controlnets: list[ControlField] = InputField(description="The ControlNets used for inference") - ipAdapters: list[IPAdapterMetadataField] = InputField(description="The IP Adapters used for inference") - t2iAdapters: list[T2IAdapterField] = Field(description="The IP Adapters used for inference") - loras: list[LoRAMetadataField] = InputField(description="The LoRAs used for inference") + model: Optional[MainModelField] = InputField(default=None, description="The main model used for inference") + controlnets: Optional[list[ControlField]] = InputField( + default=None, description="The ControlNets used for inference" + ) + ipAdapters: Optional[list[IPAdapterMetadataField]] = InputField( + default=None, description="The IP Adapters used for inference" + ) + t2iAdapters: Optional[list[T2IAdapterField]] = InputField( + default=None, description="The IP Adapters used for inference" + ) + loras: Optional[list[LoRAMetadataField]] = InputField(default=None, description="The LoRAs used for inference") strength: Optional[float] = InputField( default=None, description="The strength used for latents-to-latents", @@ -156,6 +166,20 @@ class MetadataAccumulatorInvocation(BaseInvocation): description="The VAE used for decoding, if the main model's default was not used", ) + # High resolution fix metadata. + hrf_width: Optional[int] = InputField( + default=None, + description="The high resolution fix height and width multipler.", + ) + hrf_height: Optional[int] = InputField( + default=None, + description="The high resolution fix height and width multipler.", + ) + hrf_strength: Optional[float] = InputField( + default=None, + description="The high resolution fix img2img strength used in the upscale pass.", + ) + # SDXL positive_style_prompt: Optional[str] = InputField( default=None, @@ -199,4 +223,4 @@ class MetadataAccumulatorInvocation(BaseInvocation): def invoke(self, context: InvocationContext) -> MetadataAccumulatorOutput: """Collects and outputs a CoreMetadata object""" - return MetadataAccumulatorOutput(metadata=CoreMetadata(**self.dict())) + return MetadataAccumulatorOutput(metadata=CoreMetadata(**self.model_dump())) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 571cb2e730..dfa1075d6e 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -1,7 +1,7 @@ import copy from typing import List, Optional -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from ...backend.model_management import BaseModelType, ModelType, SubModelType from .baseinvocation import ( @@ -24,6 +24,8 @@ class ModelInfo(BaseModel): model_type: ModelType = Field(description="Info to load submodel") submodel: Optional[SubModelType] = Field(default=None, description="Info to load submodel") + model_config = ConfigDict(protected_namespaces=()) + class LoraInfo(ModelInfo): weight: float = Field(description="Lora's weight which to use when apply to model") @@ -65,6 +67,8 @@ class MainModelField(BaseModel): base_model: BaseModelType = Field(description="Base model") model_type: ModelType = Field(description="Model Type") + model_config = ConfigDict(protected_namespaces=()) + class LoRAModelField(BaseModel): """LoRA model field""" @@ -72,8 +76,16 @@ class LoRAModelField(BaseModel): model_name: str = Field(description="Name of the LoRA model") base_model: BaseModelType = Field(description="Base model") + model_config = ConfigDict(protected_namespaces=()) -@invocation("main_model_loader", title="Main Model", tags=["model"], category="model", version="1.0.0") + +@invocation( + "main_model_loader", + title="Main Model", + tags=["model"], + category="model", + version="1.0.0", +) class MainModelLoaderInvocation(BaseInvocation): """Loads a main model, outputting its submodels.""" @@ -180,10 +192,16 @@ class LoraLoaderInvocation(BaseInvocation): lora: LoRAModelField = InputField(description=FieldDescriptions.lora_model, input=Input.Direct, title="LoRA") weight: float = InputField(default=0.75, description=FieldDescriptions.lora_weight) unet: Optional[UNetField] = InputField( - default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" + default=None, + description=FieldDescriptions.unet, + input=Input.Connection, + title="UNet", ) clip: Optional[ClipField] = InputField( - default=None, description=FieldDescriptions.clip, input=Input.Connection, title="CLIP" + default=None, + description=FieldDescriptions.clip, + input=Input.Connection, + title="CLIP", ) def invoke(self, context: InvocationContext) -> LoraLoaderOutput: @@ -244,20 +262,35 @@ class SDXLLoraLoaderOutput(BaseInvocationOutput): clip2: Optional[ClipField] = OutputField(default=None, description=FieldDescriptions.clip, title="CLIP 2") -@invocation("sdxl_lora_loader", title="SDXL LoRA", tags=["lora", "model"], category="model", version="1.0.0") +@invocation( + "sdxl_lora_loader", + title="SDXL LoRA", + tags=["lora", "model"], + category="model", + version="1.0.0", +) class SDXLLoraLoaderInvocation(BaseInvocation): """Apply selected lora to unet and text_encoder.""" lora: LoRAModelField = InputField(description=FieldDescriptions.lora_model, input=Input.Direct, title="LoRA") weight: float = InputField(default=0.75, description=FieldDescriptions.lora_weight) unet: Optional[UNetField] = InputField( - default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" + default=None, + description=FieldDescriptions.unet, + input=Input.Connection, + title="UNet", ) clip: Optional[ClipField] = InputField( - default=None, description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 1" + default=None, + description=FieldDescriptions.clip, + input=Input.Connection, + title="CLIP 1", ) clip2: Optional[ClipField] = InputField( - default=None, description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 2" + default=None, + description=FieldDescriptions.clip, + input=Input.Connection, + title="CLIP 2", ) def invoke(self, context: InvocationContext) -> SDXLLoraLoaderOutput: @@ -330,6 +363,8 @@ class VAEModelField(BaseModel): model_name: str = Field(description="Name of the model") base_model: BaseModelType = Field(description="Base model") + model_config = ConfigDict(protected_namespaces=()) + @invocation_output("vae_loader_output") class VaeLoaderOutput(BaseInvocationOutput): @@ -343,7 +378,10 @@ class VaeLoaderInvocation(BaseInvocation): """Loads a VAE model, outputting a VaeLoaderOutput""" vae_model: VAEModelField = InputField( - description=FieldDescriptions.vae_model, input=Input.Direct, ui_type=UIType.VaeModel, title="VAE" + description=FieldDescriptions.vae_model, + input=Input.Direct, + ui_type=UIType.VaeModel, + title="VAE", ) def invoke(self, context: InvocationContext) -> VaeLoaderOutput: @@ -372,19 +410,31 @@ class VaeLoaderInvocation(BaseInvocation): class SeamlessModeOutput(BaseInvocationOutput): """Modified Seamless Model output""" - unet: Optional[UNetField] = OutputField(description=FieldDescriptions.unet, title="UNet") - vae: Optional[VaeField] = OutputField(description=FieldDescriptions.vae, title="VAE") + unet: Optional[UNetField] = OutputField(default=None, description=FieldDescriptions.unet, title="UNet") + vae: Optional[VaeField] = OutputField(default=None, description=FieldDescriptions.vae, title="VAE") -@invocation("seamless", title="Seamless", tags=["seamless", "model"], category="model", version="1.0.0") +@invocation( + "seamless", + title="Seamless", + tags=["seamless", "model"], + category="model", + version="1.0.0", +) class SeamlessModeInvocation(BaseInvocation): """Applies the seamless transformation to the Model UNet and VAE.""" unet: Optional[UNetField] = InputField( - default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" + default=None, + description=FieldDescriptions.unet, + input=Input.Connection, + title="UNet", ) vae: Optional[VaeField] = InputField( - default=None, description=FieldDescriptions.vae_model, input=Input.Connection, title="VAE" + default=None, + description=FieldDescriptions.vae_model, + input=Input.Connection, + title="VAE", ) seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") diff --git a/invokeai/app/invocations/noise.py b/invokeai/app/invocations/noise.py index c46747aa89..3c1651a2f0 100644 --- a/invokeai/app/invocations/noise.py +++ b/invokeai/app/invocations/noise.py @@ -2,7 +2,7 @@ import torch -from pydantic import validator +from pydantic import field_validator from invokeai.app.invocations.latent import LatentsField from invokeai.app.util.misc import SEED_MAX, get_random_seed @@ -65,7 +65,7 @@ Nodes class NoiseOutput(BaseInvocationOutput): """Invocation noise output""" - noise: LatentsField = OutputField(default=None, description=FieldDescriptions.noise) + noise: LatentsField = OutputField(description=FieldDescriptions.noise) width: int = OutputField(description=FieldDescriptions.width) height: int = OutputField(description=FieldDescriptions.height) @@ -78,7 +78,13 @@ def build_noise_output(latents_name: str, latents: torch.Tensor, seed: int): ) -@invocation("noise", title="Noise", tags=["latents", "noise"], category="latents", version="1.0.0") +@invocation( + "noise", + title="Noise", + tags=["latents", "noise"], + category="latents", + version="1.0.0", +) class NoiseInvocation(BaseInvocation): """Generates latent noise.""" @@ -105,7 +111,7 @@ class NoiseInvocation(BaseInvocation): description="Use CPU for noise generation (for reproducible results across platforms)", ) - @validator("seed", pre=True) + @field_validator("seed", mode="before") def modulo_seed(cls, v): """Returns the seed modulo (SEED_MAX + 1) to ensure it is within the valid range.""" return v % (SEED_MAX + 1) diff --git a/invokeai/app/invocations/onnx.py b/invokeai/app/invocations/onnx.py index 35f8ed965e..3f4f688cf4 100644 --- a/invokeai/app/invocations/onnx.py +++ b/invokeai/app/invocations/onnx.py @@ -9,7 +9,7 @@ from typing import List, Literal, Optional, Union import numpy as np import torch from diffusers.image_processor import VaeImageProcessor -from pydantic import BaseModel, Field, validator +from pydantic import BaseModel, ConfigDict, Field, field_validator from tqdm import tqdm from invokeai.app.invocations.metadata import CoreMetadata @@ -63,14 +63,17 @@ class ONNXPromptInvocation(BaseInvocation): def invoke(self, context: InvocationContext) -> ConditioningOutput: tokenizer_info = context.services.model_manager.get_model( - **self.clip.tokenizer.dict(), + **self.clip.tokenizer.model_dump(), ) text_encoder_info = context.services.model_manager.get_model( - **self.clip.text_encoder.dict(), + **self.clip.text_encoder.model_dump(), ) with tokenizer_info as orig_tokenizer, text_encoder_info as text_encoder: # , ExitStack() as stack: loras = [ - (context.services.model_manager.get_model(**lora.dict(exclude={"weight"})).context.model, lora.weight) + ( + context.services.model_manager.get_model(**lora.model_dump(exclude={"weight"})).context.model, + lora.weight, + ) for lora in self.clip.loras ] @@ -175,14 +178,14 @@ class ONNXTextToLatentsInvocation(BaseInvocation): description=FieldDescriptions.unet, input=Input.Connection, ) - control: Optional[Union[ControlField, list[ControlField]]] = InputField( + control: Union[ControlField, list[ControlField]] = InputField( default=None, description=FieldDescriptions.control, ) # seamless: bool = InputField(default=False, description="Whether or not to generate an image that can tile without seams", ) # seamless_axes: str = InputField(default="", description="The axes to tile the image on, 'x' and/or 'y'") - @validator("cfg_scale") + @field_validator("cfg_scale") def ge_one(cls, v): """validate that all cfg_scale values are >= 1""" if isinstance(v, list): @@ -241,7 +244,7 @@ class ONNXTextToLatentsInvocation(BaseInvocation): stable_diffusion_step_callback( context=context, intermediate_state=intermediate_state, - node=self.dict(), + node=self.model_dump(), source_node_id=source_node_id, ) @@ -254,12 +257,15 @@ class ONNXTextToLatentsInvocation(BaseInvocation): eta=0.0, ) - unet_info = context.services.model_manager.get_model(**self.unet.unet.dict()) + unet_info = context.services.model_manager.get_model(**self.unet.unet.model_dump()) with unet_info as unet: # , ExitStack() as stack: # loras = [(stack.enter_context(context.services.model_manager.get_model(**lora.dict(exclude={"weight"}))), lora.weight) for lora in self.unet.loras] loras = [ - (context.services.model_manager.get_model(**lora.dict(exclude={"weight"})).context.model, lora.weight) + ( + context.services.model_manager.get_model(**lora.model_dump(exclude={"weight"})).context.model, + lora.weight, + ) for lora in self.unet.loras ] @@ -346,7 +352,7 @@ class ONNXLatentsToImageInvocation(BaseInvocation): raise Exception(f"Expected vae_decoder, found: {self.vae.vae.model_type}") vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), + **self.vae.vae.model_dump(), ) # clear memory as vae decode can request a lot @@ -375,7 +381,7 @@ class ONNXLatentsToImageInvocation(BaseInvocation): node_id=self.id, session_id=context.graph_execution_state_id, is_intermediate=self.is_intermediate, - metadata=self.metadata.dict() if self.metadata else None, + metadata=self.metadata.model_dump() if self.metadata else None, workflow=self.workflow, ) @@ -403,6 +409,8 @@ class OnnxModelField(BaseModel): base_model: BaseModelType = Field(description="Base model") model_type: ModelType = Field(description="Model Type") + model_config = ConfigDict(protected_namespaces=()) + @invocation("onnx_model_loader", title="ONNX Main Model", tags=["onnx", "model"], category="model", version="1.0.0") class OnnxModelLoaderInvocation(BaseInvocation): diff --git a/invokeai/app/invocations/param_easing.py b/invokeai/app/invocations/param_easing.py index 7c327a6657..0e86fb978b 100644 --- a/invokeai/app/invocations/param_easing.py +++ b/invokeai/app/invocations/param_easing.py @@ -44,13 +44,22 @@ from invokeai.app.invocations.primitives import FloatCollectionOutput from .baseinvocation import BaseInvocation, InputField, InvocationContext, invocation -@invocation("float_range", title="Float Range", tags=["math", "range"], category="math", version="1.0.0") +@invocation( + "float_range", + title="Float Range", + tags=["math", "range"], + category="math", + version="1.0.0", +) class FloatLinearRangeInvocation(BaseInvocation): """Creates a range""" start: float = InputField(default=5, description="The first value of the range") stop: float = InputField(default=10, description="The last value of the range") - steps: int = InputField(default=30, description="number of values to interpolate over (including start and stop)") + steps: int = InputField( + default=30, + description="number of values to interpolate over (including start and stop)", + ) def invoke(self, context: InvocationContext) -> FloatCollectionOutput: param_list = list(np.linspace(self.start, self.stop, self.steps)) @@ -95,7 +104,13 @@ EASING_FUNCTION_KEYS = Literal[tuple(list(EASING_FUNCTIONS_MAP.keys()))] # actually I think for now could just use CollectionOutput (which is list[Any] -@invocation("step_param_easing", title="Step Param Easing", tags=["step", "easing"], category="step", version="1.0.0") +@invocation( + "step_param_easing", + title="Step Param Easing", + tags=["step", "easing"], + category="step", + version="1.0.0", +) class StepParamEasingInvocation(BaseInvocation): """Experimental per-step parameter easing for denoising steps""" @@ -159,7 +174,9 @@ class StepParamEasingInvocation(BaseInvocation): context.services.logger.debug("base easing duration: " + str(base_easing_duration)) even_num_steps = num_easing_steps % 2 == 0 # even number of steps easing_function = easing_class( - start=self.start_value, end=self.end_value, duration=base_easing_duration - 1 + start=self.start_value, + end=self.end_value, + duration=base_easing_duration - 1, ) base_easing_vals = list() for step_index in range(base_easing_duration): @@ -199,7 +216,11 @@ class StepParamEasingInvocation(BaseInvocation): # else: # no mirroring (default) - easing_function = easing_class(start=self.start_value, end=self.end_value, duration=num_easing_steps - 1) + easing_function = easing_class( + start=self.start_value, + end=self.end_value, + duration=num_easing_steps - 1, + ) for step_index in range(num_easing_steps): step_val = easing_function.ease(step_index) easing_list.append(step_val) diff --git a/invokeai/app/invocations/prompt.py b/invokeai/app/invocations/prompt.py index b3d482b779..cb43a52447 100644 --- a/invokeai/app/invocations/prompt.py +++ b/invokeai/app/invocations/prompt.py @@ -3,7 +3,7 @@ from typing import Optional, Union import numpy as np from dynamicprompts.generators import CombinatorialPromptGenerator, RandomPromptGenerator -from pydantic import validator +from pydantic import field_validator from invokeai.app.invocations.primitives import StringCollectionOutput @@ -21,7 +21,10 @@ from .baseinvocation import BaseInvocation, InputField, InvocationContext, UICom class DynamicPromptInvocation(BaseInvocation): """Parses a prompt using adieyal/dynamicprompts' random or combinatorial generator""" - prompt: str = InputField(description="The prompt to parse with dynamicprompts", ui_component=UIComponent.Textarea) + prompt: str = InputField( + description="The prompt to parse with dynamicprompts", + ui_component=UIComponent.Textarea, + ) max_prompts: int = InputField(default=1, description="The number of prompts to generate") combinatorial: bool = InputField(default=False, description="Whether to use the combinatorial generator") @@ -36,21 +39,31 @@ class DynamicPromptInvocation(BaseInvocation): return StringCollectionOutput(collection=prompts) -@invocation("prompt_from_file", title="Prompts from File", tags=["prompt", "file"], category="prompt", version="1.0.0") +@invocation( + "prompt_from_file", + title="Prompts from File", + tags=["prompt", "file"], + category="prompt", + version="1.0.0", +) class PromptsFromFileInvocation(BaseInvocation): """Loads prompts from a text file""" file_path: str = InputField(description="Path to prompt text file") pre_prompt: Optional[str] = InputField( - default=None, description="String to prepend to each prompt", ui_component=UIComponent.Textarea + default=None, + description="String to prepend to each prompt", + ui_component=UIComponent.Textarea, ) post_prompt: Optional[str] = InputField( - default=None, description="String to append to each prompt", ui_component=UIComponent.Textarea + default=None, + description="String to append to each prompt", + ui_component=UIComponent.Textarea, ) start_line: int = InputField(default=1, ge=1, description="Line in the file to start start from") max_prompts: int = InputField(default=1, ge=0, description="Max lines to read from file (0=all)") - @validator("file_path") + @field_validator("file_path") def file_path_exists(cls, v): if not exists(v): raise ValueError(FileNotFoundError) @@ -79,6 +92,10 @@ class PromptsFromFileInvocation(BaseInvocation): def invoke(self, context: InvocationContext) -> StringCollectionOutput: prompts = self.promptsFromFile( - self.file_path, self.pre_prompt, self.post_prompt, self.start_line, self.max_prompts + self.file_path, + self.pre_prompt, + self.post_prompt, + self.start_line, + self.max_prompts, ) return StringCollectionOutput(collection=prompts) diff --git a/invokeai/app/invocations/t2i_adapter.py b/invokeai/app/invocations/t2i_adapter.py index e1bd8d0d04..76c250a552 100644 --- a/invokeai/app/invocations/t2i_adapter.py +++ b/invokeai/app/invocations/t2i_adapter.py @@ -1,6 +1,6 @@ from typing import Union -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from invokeai.app.invocations.baseinvocation import ( BaseInvocation, @@ -23,6 +23,8 @@ class T2IAdapterModelField(BaseModel): model_name: str = Field(description="Name of the T2I-Adapter model") base_model: BaseModelType = Field(description="Base model") + model_config = ConfigDict(protected_namespaces=()) + class T2IAdapterField(BaseModel): image: ImageField = Field(description="The T2I-Adapter image prompt.") diff --git a/invokeai/app/invocations/upscale.py b/invokeai/app/invocations/upscale.py index e26c1b9084..d30bb71d95 100644 --- a/invokeai/app/invocations/upscale.py +++ b/invokeai/app/invocations/upscale.py @@ -7,6 +7,7 @@ import numpy as np import torch from basicsr.archs.rrdbnet_arch import RRDBNet from PIL import Image +from pydantic import ConfigDict from realesrgan import RealESRGANer from invokeai.app.invocations.primitives import ImageField, ImageOutput @@ -38,6 +39,8 @@ class ESRGANInvocation(BaseInvocation): default=400, ge=0, description="Tile size for tiled ESRGAN upscaling (0=tiling disabled)" ) + model_config = ConfigDict(protected_namespaces=()) + def invoke(self, context: InvocationContext) -> ImageOutput: image = context.services.images.get_pil_image(self.image.image_name) models_path = context.services.configuration.models_path diff --git a/invokeai/app/services/board_image_records/board_image_records_sqlite.py b/invokeai/app/services/board_image_records/board_image_records_sqlite.py index df7505b797..9f4e4379bc 100644 --- a/invokeai/app/services/board_image_records/board_image_records_sqlite.py +++ b/invokeai/app/services/board_image_records/board_image_records_sqlite.py @@ -12,7 +12,7 @@ from .board_image_records_base import BoardImageRecordStorageBase class SqliteBoardImageRecordStorage(BoardImageRecordStorageBase): _conn: sqlite3.Connection _cursor: sqlite3.Cursor - _lock: threading.Lock + _lock: threading.RLock def __init__(self, db: SqliteDatabase) -> None: super().__init__() diff --git a/invokeai/app/services/board_records/board_records_common.py b/invokeai/app/services/board_records/board_records_common.py index e0264dde0d..d08951b499 100644 --- a/invokeai/app/services/board_records/board_records_common.py +++ b/invokeai/app/services/board_records/board_records_common.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import Optional, Union -from pydantic import BaseModel, Extra, Field +from pydantic import BaseModel, Field from invokeai.app.util.misc import get_iso_timestamp from invokeai.app.util.model_exclude_null import BaseModelExcludeNull @@ -18,9 +18,9 @@ class BoardRecord(BaseModelExcludeNull): """The created timestamp of the image.""" updated_at: Union[datetime, str] = Field(description="The updated timestamp of the board.") """The updated timestamp of the image.""" - deleted_at: Union[datetime, str, None] = Field(description="The deleted timestamp of the board.") + deleted_at: Optional[Union[datetime, str]] = Field(default=None, description="The deleted timestamp of the board.") """The updated timestamp of the image.""" - cover_image_name: Optional[str] = Field(description="The name of the cover image of the board.") + cover_image_name: Optional[str] = Field(default=None, description="The name of the cover image of the board.") """The name of the cover image of the board.""" @@ -46,9 +46,9 @@ def deserialize_board_record(board_dict: dict) -> BoardRecord: ) -class BoardChanges(BaseModel, extra=Extra.forbid): - board_name: Optional[str] = Field(description="The board's new name.") - cover_image_name: Optional[str] = Field(description="The name of the board's new cover image.") +class BoardChanges(BaseModel, extra="forbid"): + board_name: Optional[str] = Field(default=None, description="The board's new name.") + cover_image_name: Optional[str] = Field(default=None, description="The name of the board's new cover image.") class BoardRecordNotFoundException(Exception): diff --git a/invokeai/app/services/board_records/board_records_sqlite.py b/invokeai/app/services/board_records/board_records_sqlite.py index b2ddc931f5..9e3423ab19 100644 --- a/invokeai/app/services/board_records/board_records_sqlite.py +++ b/invokeai/app/services/board_records/board_records_sqlite.py @@ -20,7 +20,7 @@ from .board_records_common import ( class SqliteBoardRecordStorage(BoardRecordStorageBase): _conn: sqlite3.Connection _cursor: sqlite3.Cursor - _lock: threading.Lock + _lock: threading.RLock def __init__(self, db: SqliteDatabase) -> None: super().__init__() diff --git a/invokeai/app/services/boards/boards_common.py b/invokeai/app/services/boards/boards_common.py index e22e1915fe..0cb54102bb 100644 --- a/invokeai/app/services/boards/boards_common.py +++ b/invokeai/app/services/boards/boards_common.py @@ -17,7 +17,7 @@ class BoardDTO(BoardRecord): def board_record_to_dto(board_record: BoardRecord, cover_image_name: Optional[str], image_count: int) -> BoardDTO: """Converts a board record to a board DTO.""" return BoardDTO( - **board_record.dict(exclude={"cover_image_name"}), + **board_record.model_dump(exclude={"cover_image_name"}), cover_image_name=cover_image_name, image_count=image_count, ) diff --git a/invokeai/app/services/config/config_base.py b/invokeai/app/services/config/config_base.py index a07e14252a..9405c1dfae 100644 --- a/invokeai/app/services/config/config_base.py +++ b/invokeai/app/services/config/config_base.py @@ -18,7 +18,7 @@ from pathlib import Path from typing import ClassVar, Dict, List, Literal, Optional, Union, get_args, get_origin, get_type_hints from omegaconf import DictConfig, ListConfig, OmegaConf -from pydantic import BaseSettings +from pydantic_settings import BaseSettings, SettingsConfigDict from invokeai.app.services.config.config_common import PagingArgumentParser, int_or_float_or_str @@ -32,12 +32,14 @@ class InvokeAISettings(BaseSettings): initconf: ClassVar[Optional[DictConfig]] = None argparse_groups: ClassVar[Dict] = {} + model_config = SettingsConfigDict(env_file_encoding="utf-8", arbitrary_types_allowed=True, case_sensitive=True) + def parse_args(self, argv: Optional[list] = sys.argv[1:]): parser = self.get_parser() opt, unknown_opts = parser.parse_known_args(argv) if len(unknown_opts) > 0: print("Unknown args:", unknown_opts) - for name in self.__fields__: + for name in self.model_fields: if name not in self._excluded(): value = getattr(opt, name) if isinstance(value, ListConfig): @@ -54,10 +56,12 @@ class InvokeAISettings(BaseSettings): cls = self.__class__ type = get_args(get_type_hints(cls)["type"])[0] field_dict = dict({type: dict()}) - for name, field in self.__fields__.items(): + for name, field in self.model_fields.items(): if name in cls._excluded_from_yaml(): continue - category = field.field_info.extra.get("category") or "Uncategorized" + category = ( + field.json_schema_extra.get("category", "Uncategorized") if field.json_schema_extra else "Uncategorized" + ) value = getattr(self, name) if category not in field_dict[type]: field_dict[type][category] = dict() @@ -73,7 +77,7 @@ class InvokeAISettings(BaseSettings): else: settings_stanza = "Uncategorized" - env_prefix = getattr(cls.Config, "env_prefix", None) + env_prefix = getattr(cls.model_config, "env_prefix", None) env_prefix = env_prefix if env_prefix is not None else settings_stanza.upper() initconf = ( @@ -89,14 +93,18 @@ class InvokeAISettings(BaseSettings): for key, value in os.environ.items(): upcase_environ[key.upper()] = value - fields = cls.__fields__ + fields = cls.model_fields cls.argparse_groups = {} for name, field in fields.items(): if name not in cls._excluded(): current_default = field.default - category = field.field_info.extra.get("category", "Uncategorized") + category = ( + field.json_schema_extra.get("category", "Uncategorized") + if field.json_schema_extra + else "Uncategorized" + ) env_name = env_prefix + "_" + name if category in initconf and name in initconf.get(category): field.default = initconf.get(category).get(name) @@ -146,11 +154,6 @@ class InvokeAISettings(BaseSettings): "tiled_decode", ] - class Config: - env_file_encoding = "utf-8" - arbitrary_types_allowed = True - case_sensitive = True - @classmethod def add_field_argument(cls, command_parser, name: str, field, default_override=None): field_type = get_type_hints(cls).get(name) @@ -161,7 +164,7 @@ class InvokeAISettings(BaseSettings): if field.default_factory is None else field.default_factory() ) - if category := field.field_info.extra.get("category"): + if category := (field.json_schema_extra.get("category", None) if field.json_schema_extra else None): if category not in cls.argparse_groups: cls.argparse_groups[category] = command_parser.add_argument_group(category) argparse_group = cls.argparse_groups[category] @@ -169,7 +172,7 @@ class InvokeAISettings(BaseSettings): argparse_group = command_parser if get_origin(field_type) == Literal: - allowed_values = get_args(field.type_) + allowed_values = get_args(field.annotation) allowed_types = set() for val in allowed_values: allowed_types.add(type(val)) @@ -182,7 +185,7 @@ class InvokeAISettings(BaseSettings): type=field_type, default=default, choices=allowed_values, - help=field.field_info.description, + help=field.description, ) elif get_origin(field_type) == Union: @@ -191,7 +194,7 @@ class InvokeAISettings(BaseSettings): dest=name, type=int_or_float_or_str, default=default, - help=field.field_info.description, + help=field.description, ) elif get_origin(field_type) == list: @@ -199,17 +202,17 @@ class InvokeAISettings(BaseSettings): f"--{name}", dest=name, nargs="*", - type=field.type_, + type=field.annotation, default=default, - action=argparse.BooleanOptionalAction if field.type_ == bool else "store", - help=field.field_info.description, + action=argparse.BooleanOptionalAction if field.annotation == bool else "store", + help=field.description, ) else: argparse_group.add_argument( f"--{name}", dest=name, - type=field.type_, + type=field.annotation, default=default, - action=argparse.BooleanOptionalAction if field.type_ == bool else "store", - help=field.field_info.description, + action=argparse.BooleanOptionalAction if field.annotation == bool else "store", + help=field.description, ) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index 2a42c99bd8..df01b65882 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -144,8 +144,8 @@ which is set to the desired top-level name. For example, to create a class InvokeBatch(InvokeAISettings): type: Literal["InvokeBatch"] = "InvokeBatch" - node_count : int = Field(default=1, description="Number of nodes to run on", category='Resources') - cpu_count : int = Field(default=8, description="Number of GPUs to run on per node", category='Resources') + node_count : int = Field(default=1, description="Number of nodes to run on", json_schema_extra=dict(category='Resources')) + cpu_count : int = Field(default=8, description="Number of GPUs to run on per node", json_schema_extra=dict(category='Resources')) This will now read and write from the "InvokeBatch" section of the config file, look for environment variables named INVOKEBATCH_*, and @@ -175,7 +175,8 @@ from pathlib import Path from typing import ClassVar, Dict, List, Literal, Optional, Union, get_type_hints from omegaconf import DictConfig, OmegaConf -from pydantic import Field, parse_obj_as +from pydantic import Field, TypeAdapter +from pydantic_settings import SettingsConfigDict from .config_base import InvokeAISettings @@ -185,6 +186,21 @@ LEGACY_INIT_FILE = Path("invokeai.init") DEFAULT_MAX_VRAM = 0.5 +class Categories(object): + WebServer = dict(category="Web Server") + Features = dict(category="Features") + Paths = dict(category="Paths") + Logging = dict(category="Logging") + Development = dict(category="Development") + Other = dict(category="Other") + ModelCache = dict(category="Model Cache") + Device = dict(category="Device") + Generation = dict(category="Generation") + Queue = dict(category="Queue") + Nodes = dict(category="Nodes") + MemoryPerformance = dict(category="Memory/Performance") + + class InvokeAIAppConfig(InvokeAISettings): """ Generate images using Stable Diffusion. Use "invokeai" to launch @@ -201,86 +217,88 @@ class InvokeAIAppConfig(InvokeAISettings): type: Literal["InvokeAI"] = "InvokeAI" # WEB - host : str = Field(default="127.0.0.1", description="IP address to bind to", category='Web Server') - port : int = Field(default=9090, description="Port to bind to", category='Web Server') - allow_origins : List[str] = Field(default=[], description="Allowed CORS origins", category='Web Server') - allow_credentials : bool = Field(default=True, description="Allow CORS credentials", category='Web Server') - allow_methods : List[str] = Field(default=["*"], description="Methods allowed for CORS", category='Web Server') - allow_headers : List[str] = Field(default=["*"], description="Headers allowed for CORS", category='Web Server') + host : str = Field(default="127.0.0.1", description="IP address to bind to", json_schema_extra=Categories.WebServer) + port : int = Field(default=9090, description="Port to bind to", json_schema_extra=Categories.WebServer) + allow_origins : List[str] = Field(default=[], description="Allowed CORS origins", json_schema_extra=Categories.WebServer) + allow_credentials : bool = Field(default=True, description="Allow CORS credentials", json_schema_extra=Categories.WebServer) + allow_methods : List[str] = Field(default=["*"], description="Methods allowed for CORS", json_schema_extra=Categories.WebServer) + allow_headers : List[str] = Field(default=["*"], description="Headers allowed for CORS", json_schema_extra=Categories.WebServer) # FEATURES - esrgan : bool = Field(default=True, description="Enable/disable upscaling code", category='Features') - internet_available : bool = Field(default=True, description="If true, attempt to download models on the fly; otherwise only use local models", category='Features') - log_tokenization : bool = Field(default=False, description="Enable logging of parsed prompt tokens.", category='Features') - patchmatch : bool = Field(default=True, description="Enable/disable patchmatch inpaint code", category='Features') - ignore_missing_core_models : bool = Field(default=False, description='Ignore missing models in models/core/convert', category='Features') + esrgan : bool = Field(default=True, description="Enable/disable upscaling code", json_schema_extra=Categories.Features) + internet_available : bool = Field(default=True, description="If true, attempt to download models on the fly; otherwise only use local models", json_schema_extra=Categories.Features) + log_tokenization : bool = Field(default=False, description="Enable logging of parsed prompt tokens.", json_schema_extra=Categories.Features) + patchmatch : bool = Field(default=True, description="Enable/disable patchmatch inpaint code", json_schema_extra=Categories.Features) + ignore_missing_core_models : bool = Field(default=False, description='Ignore missing models in models/core/convert', json_schema_extra=Categories.Features) # PATHS - root : Path = Field(default=None, description='InvokeAI runtime root directory', category='Paths') - autoimport_dir : Path = Field(default='autoimport', description='Path to a directory of models files to be imported on startup.', category='Paths') - lora_dir : Path = Field(default=None, description='Path to a directory of LoRA/LyCORIS models to be imported on startup.', category='Paths') - embedding_dir : Path = Field(default=None, description='Path to a directory of Textual Inversion embeddings to be imported on startup.', category='Paths') - controlnet_dir : Path = Field(default=None, description='Path to a directory of ControlNet embeddings to be imported on startup.', category='Paths') - conf_path : Path = Field(default='configs/models.yaml', description='Path to models definition file', category='Paths') - models_dir : Path = Field(default='models', description='Path to the models directory', category='Paths') - legacy_conf_dir : Path = Field(default='configs/stable-diffusion', description='Path to directory of legacy checkpoint config files', category='Paths') - db_dir : Path = Field(default='databases', description='Path to InvokeAI databases directory', category='Paths') - outdir : Path = Field(default='outputs', description='Default folder for output images', category='Paths') - use_memory_db : bool = Field(default=False, description='Use in-memory database for storing image metadata', category='Paths') - from_file : Path = Field(default=None, description='Take command input from the indicated file (command-line client only)', category='Paths') + root : Optional[Path] = Field(default=None, description='InvokeAI runtime root directory', json_schema_extra=Categories.Paths) + autoimport_dir : Optional[Path] = Field(default=Path('autoimport'), description='Path to a directory of models files to be imported on startup.', json_schema_extra=Categories.Paths) + lora_dir : Optional[Path] = Field(default=None, description='Path to a directory of LoRA/LyCORIS models to be imported on startup.', json_schema_extra=Categories.Paths) + embedding_dir : Optional[Path] = Field(default=None, description='Path to a directory of Textual Inversion embeddings to be imported on startup.', json_schema_extra=Categories.Paths) + controlnet_dir : Optional[Path] = Field(default=None, description='Path to a directory of ControlNet embeddings to be imported on startup.', json_schema_extra=Categories.Paths) + conf_path : Optional[Path] = Field(default=Path('configs/models.yaml'), description='Path to models definition file', json_schema_extra=Categories.Paths) + models_dir : Optional[Path] = Field(default=Path('models'), description='Path to the models directory', json_schema_extra=Categories.Paths) + legacy_conf_dir : Optional[Path] = Field(default=Path('configs/stable-diffusion'), description='Path to directory of legacy checkpoint config files', json_schema_extra=Categories.Paths) + 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) + 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 - log_handlers : List[str] = Field(default=["console"], description='Log handler. Valid options are "console", "file=", "syslog=path|address:host:port", "http="', category="Logging") + log_handlers : List[str] = Field(default=["console"], description='Log handler. Valid options are "console", "file=", "syslog=path|address:host:port", "http="', json_schema_extra=Categories.Logging) # note - would be better to read the log_format values from logging.py, but this creates circular dependencies issues - log_format : Literal['plain', 'color', 'syslog', 'legacy'] = Field(default="color", description='Log format. Use "plain" for text-only, "color" for colorized output, "legacy" for 2.3-style logging and "syslog" for syslog-style', category="Logging") - log_level : Literal["debug", "info", "warning", "error", "critical"] = Field(default="info", description="Emit logging messages at this level or higher", category="Logging") - log_sql : bool = Field(default=False, description="Log SQL queries", category="Logging") + log_format : Literal['plain', 'color', 'syslog', 'legacy'] = Field(default="color", description='Log format. Use "plain" for text-only, "color" for colorized output, "legacy" for 2.3-style logging and "syslog" for syslog-style', json_schema_extra=Categories.Logging) + log_level : Literal["debug", "info", "warning", "error", "critical"] = Field(default="info", description="Emit logging messages at this level or higher", json_schema_extra=Categories.Logging) + log_sql : bool = Field(default=False, description="Log SQL queries", json_schema_extra=Categories.Logging) - dev_reload : bool = Field(default=False, description="Automatically reload when Python sources are changed.", category="Development") + dev_reload : bool = Field(default=False, description="Automatically reload when Python sources are changed.", json_schema_extra=Categories.Development) - version : bool = Field(default=False, description="Show InvokeAI version and exit", category="Other") + version : bool = Field(default=False, description="Show InvokeAI version and exit", json_schema_extra=Categories.Other) # CACHE - ram : float = Field(default=7.5, gt=0, description="Maximum memory amount used by model cache for rapid switching (floating point number, GB)", category="Model Cache", ) - vram : float = Field(default=0.25, ge=0, description="Amount of VRAM reserved for model storage (floating point number, GB)", category="Model Cache", ) - lazy_offload : bool = Field(default=True, description="Keep models in VRAM until their space is needed", category="Model Cache", ) + 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, ) # DEVICE - device : Literal["auto", "cpu", "cuda", "cuda:1", "mps"] = Field(default="auto", description="Generation device", category="Device", ) - precision : Literal["auto", "float16", "float32", "autocast"] = Field(default="auto", description="Floating point precision", category="Device", ) + device : Literal["auto", "cpu", "cuda", "cuda:1", "mps"] = Field(default="auto", description="Generation device", json_schema_extra=Categories.Device) + precision : Literal["auto", "float16", "float32", "autocast"] = Field(default="auto", description="Floating point precision", json_schema_extra=Categories.Device) # GENERATION - sequential_guidance : bool = Field(default=False, description="Whether to calculate guidance in serial instead of in parallel, lowering memory requirements", category="Generation", ) - attention_type : Literal["auto", "normal", "xformers", "sliced", "torch-sdp"] = Field(default="auto", description="Attention type", category="Generation", ) - attention_slice_size: Literal["auto", "balanced", "max", 1, 2, 3, 4, 5, 6, 7, 8] = Field(default="auto", description='Slice size, valid when attention_type=="sliced"', category="Generation", ) - force_tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", category="Generation",) - force_tiled_decode: bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", category="Generation",) - png_compress_level : int = Field(default=6, description="The compress_level setting of PIL.Image.save(), used for PNG encoding. All settings are lossless. 0 = fastest, largest filesize, 9 = slowest, smallest filesize", category="Generation", ) + sequential_guidance : bool = Field(default=False, description="Whether to calculate guidance in serial instead of in parallel, lowering memory requirements", json_schema_extra=Categories.Generation) + attention_type : Literal["auto", "normal", "xformers", "sliced", "torch-sdp"] = Field(default="auto", description="Attention type", json_schema_extra=Categories.Generation) + attention_slice_size: Literal["auto", "balanced", "max", 1, 2, 3, 4, 5, 6, 7, 8] = Field(default="auto", description='Slice size, valid when attention_type=="sliced"', json_schema_extra=Categories.Generation) + force_tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", json_schema_extra=Categories.Generation) + png_compress_level : int = Field(default=6, description="The compress_level setting of PIL.Image.save(), used for PNG encoding. All settings are lossless. 0 = fastest, largest filesize, 9 = slowest, smallest filesize", json_schema_extra=Categories.Generation) # QUEUE - max_queue_size : int = Field(default=10000, gt=0, description="Maximum number of items in the session queue", category="Queue", ) + max_queue_size : int = Field(default=10000, gt=0, description="Maximum number of items in the session queue", json_schema_extra=Categories.Queue) # NODES - allow_nodes : Optional[List[str]] = Field(default=None, description="List of nodes to allow. Omit to allow all.", category="Nodes") - deny_nodes : Optional[List[str]] = Field(default=None, description="List of nodes to deny. Omit to deny none.", category="Nodes") - node_cache_size : int = Field(default=512, description="How many cached nodes to keep in memory", category="Nodes", ) + allow_nodes : Optional[List[str]] = Field(default=None, description="List of nodes to allow. Omit to allow all.", json_schema_extra=Categories.Nodes) + deny_nodes : Optional[List[str]] = Field(default=None, description="List of nodes to deny. Omit to deny none.", json_schema_extra=Categories.Nodes) + node_cache_size : int = Field(default=512, description="How many cached nodes to keep in memory", json_schema_extra=Categories.Nodes) # DEPRECATED FIELDS - STILL HERE IN ORDER TO OBTAN VALUES FROM PRE-3.1 CONFIG FILES - always_use_cpu : bool = Field(default=False, description="If true, use the CPU for rendering even if a GPU is available.", category='Memory/Performance') - free_gpu_mem : Optional[bool] = Field(default=None, description="If true, purge model from GPU after each generation.", category='Memory/Performance') - max_cache_size : Optional[float] = Field(default=None, gt=0, description="Maximum memory amount used by model cache for rapid switching", category='Memory/Performance') - max_vram_cache_size : Optional[float] = Field(default=None, ge=0, description="Amount of VRAM reserved for model storage", category='Memory/Performance') - xformers_enabled : bool = Field(default=True, description="Enable/disable memory-efficient attention", category='Memory/Performance') - tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", category='Memory/Performance') + always_use_cpu : bool = Field(default=False, description="If true, use the CPU for rendering even if a GPU is available.", json_schema_extra=Categories.MemoryPerformance) + free_gpu_mem : Optional[bool] = Field(default=None, description="If true, purge model from GPU after each generation.", json_schema_extra=Categories.MemoryPerformance) + max_cache_size : Optional[float] = Field(default=None, gt=0, description="Maximum memory amount used by model cache for rapid switching", json_schema_extra=Categories.MemoryPerformance) + max_vram_cache_size : Optional[float] = Field(default=None, ge=0, description="Amount of VRAM reserved for model storage", json_schema_extra=Categories.MemoryPerformance) + xformers_enabled : bool = Field(default=True, description="Enable/disable memory-efficient attention", json_schema_extra=Categories.MemoryPerformance) + tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", json_schema_extra=Categories.MemoryPerformance) # See InvokeAIAppConfig subclass below for CACHE and DEVICE categories # fmt: on - class Config: - validate_assignment = True - env_prefix = "INVOKEAI" + model_config = SettingsConfigDict(validate_assignment=True, env_prefix="INVOKEAI") - def parse_args(self, argv: Optional[list[str]] = None, conf: Optional[DictConfig] = None, clobber=False): + def parse_args( + self, + argv: Optional[list[str]] = None, + conf: Optional[DictConfig] = None, + clobber=False, + ): """ Update settings with contents of init file, environment, and command-line settings. @@ -308,7 +326,11 @@ class InvokeAIAppConfig(InvokeAISettings): if self.singleton_init and not clobber: hints = get_type_hints(self.__class__) for k in self.singleton_init: - setattr(self, k, parse_obj_as(hints[k], self.singleton_init[k])) + setattr( + self, + k, + TypeAdapter(hints[k]).validate_python(self.singleton_init[k]), + ) @classmethod def get_config(cls, **kwargs) -> InvokeAIAppConfig: diff --git a/invokeai/app/services/events/events_base.py b/invokeai/app/services/events/events_base.py index 8685db3717..ad00815151 100644 --- a/invokeai/app/services/events/events_base.py +++ b/invokeai/app/services/events/events_base.py @@ -2,7 +2,6 @@ from typing import Any, Optional -from invokeai.app.invocations.model import ModelInfo from invokeai.app.services.invocation_processor.invocation_processor_common import ProgressImage from invokeai.app.services.session_queue.session_queue_common import ( BatchStatus, @@ -11,6 +10,7 @@ from invokeai.app.services.session_queue.session_queue_common import ( SessionQueueStatus, ) from invokeai.app.util.misc import get_timestamp +from invokeai.backend.model_management.model_manager import ModelInfo from invokeai.backend.model_management.models.base import BaseModelType, ModelType, SubModelType @@ -55,7 +55,7 @@ class EventServiceBase: graph_execution_state_id=graph_execution_state_id, node_id=node.get("id"), source_node_id=source_node_id, - progress_image=progress_image.dict() if progress_image is not None else None, + progress_image=progress_image.model_dump() if progress_image is not None else None, step=step, order=order, total_steps=total_steps, @@ -291,8 +291,8 @@ class EventServiceBase: started_at=str(session_queue_item.started_at) if session_queue_item.started_at else None, completed_at=str(session_queue_item.completed_at) if session_queue_item.completed_at else None, ), - batch_status=batch_status.dict(), - queue_status=queue_status.dict(), + batch_status=batch_status.model_dump(), + queue_status=queue_status.model_dump(), ), ) diff --git a/invokeai/app/services/image_files/image_files_base.py b/invokeai/app/services/image_files/image_files_base.py index d998f9024b..5dde7b05d6 100644 --- a/invokeai/app/services/image_files/image_files_base.py +++ b/invokeai/app/services/image_files/image_files_base.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +from pathlib import Path from typing import Optional from PIL.Image import Image as PILImageType @@ -13,7 +14,7 @@ class ImageFileStorageBase(ABC): pass @abstractmethod - def get_path(self, image_name: str, thumbnail: bool = False) -> str: + def get_path(self, image_name: str, thumbnail: bool = False) -> Path: """Gets the internal path to an image or thumbnail.""" pass diff --git a/invokeai/app/services/image_records/image_records_base.py b/invokeai/app/services/image_records/image_records_base.py index 58db6feb23..107ff85f9b 100644 --- a/invokeai/app/services/image_records/image_records_base.py +++ b/invokeai/app/services/image_records/image_records_base.py @@ -34,8 +34,8 @@ class ImageRecordStorageBase(ABC): @abstractmethod def get_many( self, - offset: Optional[int] = None, - limit: Optional[int] = None, + offset: int = 0, + limit: int = 10, image_origin: Optional[ResourceOrigin] = None, categories: Optional[list[ImageCategory]] = None, is_intermediate: Optional[bool] = None, @@ -69,11 +69,11 @@ class ImageRecordStorageBase(ABC): image_category: ImageCategory, width: int, height: int, - session_id: Optional[str], - node_id: Optional[str], - metadata: Optional[dict], - is_intermediate: bool = False, - starred: bool = False, + is_intermediate: Optional[bool] = False, + starred: Optional[bool] = False, + session_id: Optional[str] = None, + node_id: Optional[str] = None, + metadata: Optional[dict] = 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 39fac92048..5a6e5652c9 100644 --- a/invokeai/app/services/image_records/image_records_common.py +++ b/invokeai/app/services/image_records/image_records_common.py @@ -3,7 +3,7 @@ import datetime from enum import Enum from typing import Optional, Union -from pydantic import Extra, Field, StrictBool, StrictStr +from pydantic import Field, StrictBool, StrictStr from invokeai.app.util.metaenum import MetaEnum from invokeai.app.util.misc import get_iso_timestamp @@ -129,7 +129,9 @@ class ImageRecord(BaseModelExcludeNull): """The created timestamp of the image.""" updated_at: Union[datetime.datetime, str] = Field(description="The updated timestamp of the image.") """The updated timestamp of the image.""" - deleted_at: Union[datetime.datetime, str, None] = Field(description="The deleted timestamp of the image.") + deleted_at: Optional[Union[datetime.datetime, str]] = Field( + default=None, description="The deleted timestamp of the image." + ) """The deleted timestamp of the image.""" is_intermediate: bool = Field(description="Whether this is an intermediate image.") """Whether this is an intermediate image.""" @@ -147,7 +149,7 @@ class ImageRecord(BaseModelExcludeNull): """Whether this image is starred.""" -class ImageRecordChanges(BaseModelExcludeNull, extra=Extra.forbid): +class ImageRecordChanges(BaseModelExcludeNull, extra="allow"): """A set of changes to apply to an image record. Only limited changes are valid: diff --git a/invokeai/app/services/image_records/image_records_sqlite.py b/invokeai/app/services/image_records/image_records_sqlite.py index c0783fdf2f..9793236d9c 100644 --- a/invokeai/app/services/image_records/image_records_sqlite.py +++ b/invokeai/app/services/image_records/image_records_sqlite.py @@ -2,7 +2,7 @@ import json import sqlite3 import threading from datetime import datetime -from typing import Optional, cast +from typing import Optional, Union, cast from invokeai.app.services.shared.pagination import OffsetPaginatedResults from invokeai.app.services.shared.sqlite import SqliteDatabase @@ -24,7 +24,7 @@ from .image_records_common import ( class SqliteImageRecordStorage(ImageRecordStorageBase): _conn: sqlite3.Connection _cursor: sqlite3.Cursor - _lock: threading.Lock + _lock: threading.RLock def __init__(self, db: SqliteDatabase) -> None: super().__init__() @@ -117,7 +117,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): """ ) - def get(self, image_name: str) -> Optional[ImageRecord]: + def get(self, image_name: str) -> ImageRecord: try: self._lock.acquire() @@ -223,8 +223,8 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): def get_many( self, - offset: Optional[int] = None, - limit: Optional[int] = None, + offset: int = 0, + limit: int = 10, image_origin: Optional[ResourceOrigin] = None, categories: Optional[list[ImageCategory]] = None, is_intermediate: Optional[bool] = None, @@ -249,7 +249,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): """ query_conditions = "" - query_params = [] + query_params: list[Union[int, str, bool]] = [] if image_origin is not None: query_conditions += """--sql @@ -387,13 +387,13 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): image_name: str, image_origin: ResourceOrigin, image_category: ImageCategory, - session_id: Optional[str], width: int, height: int, - node_id: Optional[str], - metadata: Optional[dict], - is_intermediate: bool = False, - starred: bool = False, + is_intermediate: Optional[bool] = False, + starred: Optional[bool] = False, + session_id: Optional[str] = None, + node_id: Optional[str] = None, + metadata: Optional[dict] = None, ) -> datetime: try: metadata_json = None if metadata is None else json.dumps(metadata) diff --git a/invokeai/app/services/images/images_base.py b/invokeai/app/services/images/images_base.py index 71581099a3..a611e9485d 100644 --- a/invokeai/app/services/images/images_base.py +++ b/invokeai/app/services/images/images_base.py @@ -49,7 +49,7 @@ class ImageServiceABC(ABC): node_id: Optional[str] = None, session_id: Optional[str] = None, board_id: Optional[str] = None, - is_intermediate: bool = False, + is_intermediate: Optional[bool] = False, metadata: Optional[dict] = None, workflow: Optional[str] = None, ) -> ImageDTO: diff --git a/invokeai/app/services/images/images_common.py b/invokeai/app/services/images/images_common.py index f8b63a16c1..325cecdd26 100644 --- a/invokeai/app/services/images/images_common.py +++ b/invokeai/app/services/images/images_common.py @@ -20,7 +20,9 @@ class ImageUrlsDTO(BaseModelExcludeNull): class ImageDTO(ImageRecord, ImageUrlsDTO): """Deserialized image record, enriched for the frontend.""" - board_id: Optional[str] = Field(description="The id of the board the image belongs to, if one exists.") + board_id: Optional[str] = Field( + 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.""" pass @@ -34,7 +36,7 @@ def image_record_to_dto( ) -> ImageDTO: """Converts an image record to an image DTO.""" return ImageDTO( - **image_record.dict(), + **image_record.model_dump(), image_url=image_url, thumbnail_url=thumbnail_url, board_id=board_id, diff --git a/invokeai/app/services/images/images_default.py b/invokeai/app/services/images/images_default.py index 9134b9a4f6..d4e473b8e4 100644 --- a/invokeai/app/services/images/images_default.py +++ b/invokeai/app/services/images/images_default.py @@ -41,7 +41,7 @@ class ImageService(ImageServiceABC): node_id: Optional[str] = None, session_id: Optional[str] = None, board_id: Optional[str] = None, - is_intermediate: bool = False, + is_intermediate: Optional[bool] = False, metadata: Optional[dict] = None, workflow: Optional[str] = None, ) -> ImageDTO: @@ -146,7 +146,7 @@ class ImageService(ImageServiceABC): self.__invoker.services.logger.error("Problem getting image DTO") raise e - def get_metadata(self, image_name: str) -> Optional[ImageMetadata]: + def get_metadata(self, image_name: str) -> ImageMetadata: try: image_record = self.__invoker.services.image_records.get(image_name) metadata = self.__invoker.services.image_records.get_metadata(image_name) @@ -174,7 +174,7 @@ class ImageService(ImageServiceABC): def get_path(self, image_name: str, thumbnail: bool = False) -> str: try: - return self.__invoker.services.image_files.get_path(image_name, thumbnail) + return str(self.__invoker.services.image_files.get_path(image_name, thumbnail)) except Exception as e: self.__invoker.services.logger.error("Problem getting image path") raise e diff --git a/invokeai/app/services/invocation_cache/invocation_cache_memory.py b/invokeai/app/services/invocation_cache/invocation_cache_memory.py index 817dbb958e..4a503b3c6b 100644 --- a/invokeai/app/services/invocation_cache/invocation_cache_memory.py +++ b/invokeai/app/services/invocation_cache/invocation_cache_memory.py @@ -58,7 +58,12 @@ class MemoryInvocationCache(InvocationCacheBase): # If the cache is full, we need to remove the least used number_to_delete = len(self._cache) + 1 - self._max_cache_size self._delete_oldest_access(number_to_delete) - self._cache[key] = CachedItem(invocation_output, invocation_output.json()) + self._cache[key] = CachedItem( + invocation_output, + invocation_output.model_dump_json( + warnings=False, exclude_defaults=True, exclude_unset=True, include={"type"} + ), + ) def _delete_oldest_access(self, number_to_delete: int) -> None: number_to_delete = min(number_to_delete, len(self._cache)) @@ -85,7 +90,7 @@ class MemoryInvocationCache(InvocationCacheBase): @staticmethod def create_key(invocation: BaseInvocation) -> int: - return hash(invocation.json(exclude={"id"})) + return hash(invocation.model_dump_json(exclude={"id"}, warnings=False)) def disable(self) -> None: with self._lock: diff --git a/invokeai/app/services/invocation_processor/invocation_processor_default.py b/invokeai/app/services/invocation_processor/invocation_processor_default.py index 349c4a03e4..c59fb678ef 100644 --- a/invokeai/app/services/invocation_processor/invocation_processor_default.py +++ b/invokeai/app/services/invocation_processor/invocation_processor_default.py @@ -89,7 +89,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): queue_item_id=queue_item.session_queue_item_id, queue_id=queue_item.session_queue_id, graph_execution_state_id=graph_execution_state.id, - node=invocation.dict(), + node=invocation.model_dump(), source_node_id=source_node_id, ) @@ -127,9 +127,9 @@ class DefaultInvocationProcessor(InvocationProcessorABC): queue_item_id=queue_item.session_queue_item_id, queue_id=queue_item.session_queue_id, graph_execution_state_id=graph_execution_state.id, - node=invocation.dict(), + node=invocation.model_dump(), source_node_id=source_node_id, - result=outputs.dict(), + result=outputs.model_dump(), ) self.__invoker.services.performance_statistics.log_stats() @@ -157,7 +157,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): queue_item_id=queue_item.session_queue_item_id, queue_id=queue_item.session_queue_id, graph_execution_state_id=graph_execution_state.id, - node=invocation.dict(), + node=invocation.model_dump(), source_node_id=source_node_id, error_type=e.__class__.__name__, error=error, @@ -187,7 +187,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): queue_item_id=queue_item.session_queue_item_id, queue_id=queue_item.session_queue_id, graph_execution_state_id=graph_execution_state.id, - node=invocation.dict(), + node=invocation.model_dump(), source_node_id=source_node_id, error_type=e.__class__.__name__, error=traceback.format_exc(), diff --git a/invokeai/app/services/invocation_stats/invocation_stats_default.py b/invokeai/app/services/invocation_stats/invocation_stats_default.py index 2041ab6190..be019b6820 100644 --- a/invokeai/app/services/invocation_stats/invocation_stats_default.py +++ b/invokeai/app/services/invocation_stats/invocation_stats_default.py @@ -72,7 +72,7 @@ class InvocationStatsService(InvocationStatsServiceBase): ) self.collector.update_invocation_stats( graph_id=self.graph_id, - invocation_type=self.invocation.type, # type: ignore - `type` is not on the `BaseInvocation` model, but *is* on all invocations + invocation_type=self.invocation.type, # type: ignore # `type` is not on the `BaseInvocation` model, but *is* on all invocations time_used=time.time() - self.start_time, vram_used=torch.cuda.max_memory_allocated() / GIG if torch.cuda.is_available() else 0.0, ) diff --git a/invokeai/app/services/item_storage/item_storage_sqlite.py b/invokeai/app/services/item_storage/item_storage_sqlite.py index b810baf9fd..1bb9429130 100644 --- a/invokeai/app/services/item_storage/item_storage_sqlite.py +++ b/invokeai/app/services/item_storage/item_storage_sqlite.py @@ -2,7 +2,7 @@ import sqlite3 import threading from typing import Generic, Optional, TypeVar, get_args -from pydantic import BaseModel, parse_raw_as +from pydantic import BaseModel, TypeAdapter from invokeai.app.services.shared.pagination import PaginatedResults from invokeai.app.services.shared.sqlite import SqliteDatabase @@ -17,7 +17,8 @@ class SqliteItemStorage(ItemStorageABC, Generic[T]): _conn: sqlite3.Connection _cursor: sqlite3.Cursor _id_field: str - _lock: threading.Lock + _lock: threading.RLock + _adapter: Optional[TypeAdapter[T]] def __init__(self, db: SqliteDatabase, table_name: str, id_field: str = "id"): super().__init__() @@ -27,6 +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._create_table() @@ -45,16 +47,21 @@ class SqliteItemStorage(ItemStorageABC, Generic[T]): self._lock.release() def _parse_item(self, item: str) -> T: - # __orig_class__ is technically an implementation detail of the typing module, not a supported API - item_type = get_args(self.__orig_class__)[0] # type: ignore - return parse_raw_as(item_type, item) + if self._adapter 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) def set(self, item: T): try: self._lock.acquire() self._cursor.execute( f"""INSERT OR REPLACE INTO {self._table_name} (item) VALUES (?);""", - (item.json(),), + (item.model_dump_json(warnings=False, exclude_none=True),), ) self._conn.commit() finally: diff --git a/invokeai/app/services/model_manager/model_manager_base.py b/invokeai/app/services/model_manager/model_manager_base.py index bb9110ba0a..4c2fc4c085 100644 --- a/invokeai/app/services/model_manager/model_manager_base.py +++ b/invokeai/app/services/model_manager/model_manager_base.py @@ -231,7 +231,7 @@ class ModelManagerServiceBase(ABC): def merge_models( self, model_names: List[str] = Field( - default=None, min_items=2, max_items=3, description="List of model names to merge" + default=None, min_length=2, max_length=3, description="List of model names to merge" ), base_model: Union[BaseModelType, str] = Field( default=None, description="Base model shared by all models to be merged" diff --git a/invokeai/app/services/model_manager/model_manager_default.py b/invokeai/app/services/model_manager/model_manager_default.py index 263f804b4d..cdb3e59a91 100644 --- a/invokeai/app/services/model_manager/model_manager_default.py +++ b/invokeai/app/services/model_manager/model_manager_default.py @@ -327,7 +327,7 @@ class ModelManagerService(ModelManagerServiceBase): def merge_models( self, model_names: List[str] = Field( - default=None, min_items=2, max_items=3, description="List of model names to merge" + default=None, min_length=2, max_length=3, description="List of model names to merge" ), base_model: Union[BaseModelType, str] = Field( default=None, description="Base model shared by all models to be merged" diff --git a/invokeai/app/services/session_queue/session_queue_common.py b/invokeai/app/services/session_queue/session_queue_common.py index 2d40a5b0c4..48e1da83b5 100644 --- a/invokeai/app/services/session_queue/session_queue_common.py +++ b/invokeai/app/services/session_queue/session_queue_common.py @@ -3,8 +3,8 @@ import json from itertools import chain, product from typing import Generator, Iterable, Literal, NamedTuple, Optional, TypeAlias, Union, cast -from pydantic import BaseModel, Field, StrictStr, parse_raw_as, root_validator, validator -from pydantic.json import pydantic_encoder +from pydantic import BaseModel, ConfigDict, Field, StrictStr, TypeAdapter, field_validator, model_validator +from pydantic_core import to_jsonable_python from invokeai.app.invocations.baseinvocation import BaseInvocation from invokeai.app.services.shared.graph import Graph, GraphExecutionState, NodeNotFoundError @@ -17,7 +17,7 @@ class BatchZippedLengthError(ValueError): """Raise when a batch has items of different lengths.""" -class BatchItemsTypeError(TypeError): +class BatchItemsTypeError(ValueError): # this cannot be a TypeError in pydantic v2 """Raise when a batch has items of different types.""" @@ -70,7 +70,7 @@ class Batch(BaseModel): default=1, ge=1, description="Int stating how many times to iterate through all possible batch indices" ) - @validator("data") + @field_validator("data") def validate_lengths(cls, v: Optional[BatchDataCollection]): if v is None: return v @@ -81,7 +81,7 @@ class Batch(BaseModel): raise BatchZippedLengthError("Zipped batch items must all have the same length") return v - @validator("data") + @field_validator("data") def validate_types(cls, v: Optional[BatchDataCollection]): if v is None: return v @@ -94,7 +94,7 @@ class Batch(BaseModel): raise BatchItemsTypeError("All items in a batch must have the same type") return v - @validator("data") + @field_validator("data") def validate_unique_field_mappings(cls, v: Optional[BatchDataCollection]): if v is None: return v @@ -107,34 +107,35 @@ class Batch(BaseModel): paths.add(pair) return v - @root_validator(skip_on_failure=True) + @model_validator(mode="after") def validate_batch_nodes_and_edges(cls, values): - batch_data_collection = cast(Optional[BatchDataCollection], values["data"]) + batch_data_collection = cast(Optional[BatchDataCollection], values.data) if batch_data_collection is None: return values - graph = cast(Graph, values["graph"]) + graph = cast(Graph, values.graph) for batch_data_list in batch_data_collection: for batch_data in batch_data_list: try: node = cast(BaseInvocation, graph.get_node(batch_data.node_path)) except NodeNotFoundError: raise NodeNotFoundError(f"Node {batch_data.node_path} not found in graph") - if batch_data.field_name not in node.__fields__: + if batch_data.field_name not in node.model_fields: raise NodeNotFoundError(f"Field {batch_data.field_name} not found in node {batch_data.node_path}") return values - @validator("graph") + @field_validator("graph") def validate_graph(cls, v: Graph): v.validate_self() return v - class Config: - schema_extra = { - "required": [ + model_config = ConfigDict( + json_schema_extra=dict( + required=[ "graph", "runs", ] - } + ) + ) # endregion Batch @@ -146,15 +147,21 @@ DEFAULT_QUEUE_ID = "default" QUEUE_ITEM_STATUS = Literal["pending", "in_progress", "completed", "failed", "canceled"] +adapter_NodeFieldValue = 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 parse_raw_as(list[NodeFieldValue], field_values_raw) if field_values_raw is not None else None + return adapter_NodeFieldValue.validate_json(field_values_raw) if field_values_raw is not None else None + + +adapter_GraphExecutionState = TypeAdapter(GraphExecutionState) def get_session(queue_item_dict: dict) -> GraphExecutionState: session_raw = queue_item_dict.get("session", "{}") - return parse_raw_as(GraphExecutionState, session_raw) + session = adapter_GraphExecutionState.validate_json(session_raw, strict=False) + return session class SessionQueueItemWithoutGraph(BaseModel): @@ -178,14 +185,14 @@ class SessionQueueItemWithoutGraph(BaseModel): ) @classmethod - def from_dict(cls, queue_item_dict: dict) -> "SessionQueueItemDTO": + def queue_item_dto_from_dict(cls, queue_item_dict: dict) -> "SessionQueueItemDTO": # must parse these manually queue_item_dict["field_values"] = get_field_values(queue_item_dict) return SessionQueueItemDTO(**queue_item_dict) - class Config: - schema_extra = { - "required": [ + model_config = ConfigDict( + json_schema_extra=dict( + required=[ "item_id", "status", "batch_id", @@ -196,7 +203,8 @@ class SessionQueueItemWithoutGraph(BaseModel): "created_at", "updated_at", ] - } + ) + ) class SessionQueueItemDTO(SessionQueueItemWithoutGraph): @@ -207,15 +215,15 @@ class SessionQueueItem(SessionQueueItemWithoutGraph): session: GraphExecutionState = Field(description="The fully-populated session to be executed") @classmethod - def from_dict(cls, queue_item_dict: dict) -> "SessionQueueItem": + def queue_item_from_dict(cls, queue_item_dict: dict) -> "SessionQueueItem": # must parse these manually queue_item_dict["field_values"] = get_field_values(queue_item_dict) queue_item_dict["session"] = get_session(queue_item_dict) return SessionQueueItem(**queue_item_dict) - class Config: - schema_extra = { - "required": [ + model_config = ConfigDict( + json_schema_extra=dict( + required=[ "item_id", "status", "batch_id", @@ -227,7 +235,8 @@ class SessionQueueItem(SessionQueueItemWithoutGraph): "created_at", "updated_at", ] - } + ) + ) # endregion Queue Items @@ -321,7 +330,7 @@ def populate_graph(graph: Graph, node_field_values: Iterable[NodeFieldValue]) -> """ Populates the given graph with the given batch data items. """ - graph_clone = graph.copy(deep=True) + graph_clone = graph.model_copy(deep=True) for item in node_field_values: node = graph_clone.get_node(item.node_path) if node is None: @@ -354,7 +363,7 @@ def create_session_nfv_tuples( for item in batch_datum.items ] node_field_values_to_zip.append(node_field_values) - data.append(list(zip(*node_field_values_to_zip))) + data.append(list(zip(*node_field_values_to_zip))) # type: ignore [arg-type] # create generator to yield session,nfv tuples count = 0 @@ -409,11 +418,11 @@ def prepare_values_to_insert(queue_id: str, batch: Batch, priority: int, max_new values_to_insert.append( SessionQueueValueToInsert( queue_id, # queue_id - session.json(), # session (json) + session.model_dump_json(warnings=False, exclude_none=True), # session (json) session.id, # session_id batch.batch_id, # batch_id # must use pydantic_encoder bc field_values is a list of models - json.dumps(field_values, default=pydantic_encoder) if field_values else None, # field_values (json) + json.dumps(field_values, default=to_jsonable_python) if field_values else None, # field_values (json) priority, # priority ) ) @@ -421,3 +430,6 @@ def prepare_values_to_insert(queue_id: str, batch: Batch, priority: int, max_new # endregion Util + +Batch.model_rebuild(force=True) +SessionQueueItem.model_rebuild(force=True) diff --git a/invokeai/app/services/session_queue/session_queue_sqlite.py b/invokeai/app/services/session_queue/session_queue_sqlite.py index 0e12382392..4daab9cdbc 100644 --- a/invokeai/app/services/session_queue/session_queue_sqlite.py +++ b/invokeai/app/services/session_queue/session_queue_sqlite.py @@ -37,7 +37,7 @@ class SqliteSessionQueue(SessionQueueBase): __invoker: Invoker __conn: sqlite3.Connection __cursor: sqlite3.Cursor - __lock: threading.Lock + __lock: threading.RLock def start(self, invoker: Invoker) -> None: self.__invoker = invoker @@ -277,8 +277,8 @@ class SqliteSessionQueue(SessionQueueBase): if result is None: raise SessionQueueItemNotFoundError(f"No queue item with batch id {enqueue_result.batch.batch_id}") return EnqueueGraphResult( - **enqueue_result.dict(), - queue_item=SessionQueueItemDTO.from_dict(dict(result)), + **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: @@ -351,7 +351,7 @@ class SqliteSessionQueue(SessionQueueBase): self.__lock.release() if result is None: return None - queue_item = SessionQueueItem.from_dict(dict(result)) + queue_item = SessionQueueItem.queue_item_from_dict(dict(result)) queue_item = self._set_queue_item_status(item_id=queue_item.item_id, status="in_progress") return queue_item @@ -380,7 +380,7 @@ class SqliteSessionQueue(SessionQueueBase): self.__lock.release() if result is None: return None - return SessionQueueItem.from_dict(dict(result)) + return SessionQueueItem.queue_item_from_dict(dict(result)) def get_current(self, queue_id: str) -> Optional[SessionQueueItem]: try: @@ -404,7 +404,7 @@ class SqliteSessionQueue(SessionQueueBase): self.__lock.release() if result is None: return None - return SessionQueueItem.from_dict(dict(result)) + return SessionQueueItem.queue_item_from_dict(dict(result)) def _set_queue_item_status( self, item_id: int, status: QUEUE_ITEM_STATUS, error: Optional[str] = None @@ -564,7 +564,7 @@ class SqliteSessionQueue(SessionQueueBase): queue_item = self.get_queue_item(item_id) if queue_item.status not in ["canceled", "failed", "completed"]: status = "failed" if error is not None else "canceled" - queue_item = self._set_queue_item_status(item_id=item_id, status=status, error=error) + queue_item = self._set_queue_item_status(item_id=item_id, status=status, error=error) # type: ignore [arg-type] # mypy seems to not narrow the Literals here self.__invoker.services.queue.cancel(queue_item.session_id) self.__invoker.services.events.emit_session_canceled( queue_item_id=queue_item.item_id, @@ -699,7 +699,7 @@ class SqliteSessionQueue(SessionQueueBase): self.__lock.release() if result is None: raise SessionQueueItemNotFoundError(f"No queue item with id {item_id}") - return SessionQueueItem.from_dict(dict(result)) + return SessionQueueItem.queue_item_from_dict(dict(result)) def list_queue_items( self, @@ -751,7 +751,7 @@ class SqliteSessionQueue(SessionQueueBase): params.append(limit + 1) self.__cursor.execute(query, params) results = cast(list[sqlite3.Row], self.__cursor.fetchall()) - items = [SessionQueueItemDTO.from_dict(dict(result)) for result in results] + items = [SessionQueueItemDTO.queue_item_dto_from_dict(dict(result)) for result in results] has_more = False if len(items) > limit: # remove the extra item diff --git a/invokeai/app/services/shared/default_graphs.py b/invokeai/app/services/shared/default_graphs.py index b2d0a1f0b6..9a6e2456cb 100644 --- a/invokeai/app/services/shared/default_graphs.py +++ b/invokeai/app/services/shared/default_graphs.py @@ -80,10 +80,10 @@ def create_system_graphs(graph_library: ItemStorageABC[LibraryGraph]) -> list[Li # TODO: Uncomment this when we are ready to fix this up to prevent breaking changes graphs: list[LibraryGraph] = list() - # text_to_image = graph_library.get(default_text_to_image_graph_id) + text_to_image = graph_library.get(default_text_to_image_graph_id) - # # TODO: Check if the graph is the same as the default one, and if not, update it - # #if text_to_image is None: + # TODO: Check if the graph is the same as the default one, and if not, update it + # if text_to_image is None: text_to_image = create_text_to_image() graph_library.set(text_to_image) diff --git a/invokeai/app/services/shared/graph.py b/invokeai/app/services/shared/graph.py index dab045af9d..8f974f7c6b 100644 --- a/invokeai/app/services/shared/graph.py +++ b/invokeai/app/services/shared/graph.py @@ -5,7 +5,7 @@ import itertools from typing import Annotated, Any, Optional, Union, get_args, get_origin, get_type_hints import networkx as nx -from pydantic import BaseModel, root_validator, validator +from pydantic import BaseModel, ConfigDict, field_validator, model_validator from pydantic.fields import Field # Importing * is bad karma but needed here for node detection @@ -235,7 +235,8 @@ class CollectInvocationOutput(BaseInvocationOutput): class CollectInvocation(BaseInvocation): """Collects values into a collection""" - item: Any = InputField( + item: Optional[Any] = InputField( + default=None, description="The item to collect (all inputs must be of the same type)", ui_type=UIType.CollectionItem, title="Collection Item", @@ -250,8 +251,8 @@ class CollectInvocation(BaseInvocation): return CollectInvocationOutput(collection=copy.copy(self.collection)) -InvocationsUnion = Union[BaseInvocation.get_invocations()] # type: ignore -InvocationOutputsUnion = Union[BaseInvocationOutput.get_all_subclasses_tuple()] # type: ignore +InvocationsUnion: Any = BaseInvocation.get_invocations_union() +InvocationOutputsUnion: Any = BaseInvocationOutput.get_outputs_union() class Graph(BaseModel): @@ -378,13 +379,13 @@ class Graph(BaseModel): raise NodeNotFoundError(f"Edge destination node {edge.destination.node_id} does not exist in the graph") # output fields are not on the node object directly, they are on the output type - if edge.source.field not in source_node.get_output_type().__fields__: + if edge.source.field not in source_node.get_output_type().model_fields: raise NodeFieldNotFoundError( f"Edge source field {edge.source.field} does not exist in node {edge.source.node_id}" ) # input fields are on the node - if edge.destination.field not in destination_node.__fields__: + if edge.destination.field not in destination_node.model_fields: raise NodeFieldNotFoundError( f"Edge destination field {edge.destination.field} does not exist in node {edge.destination.node_id}" ) @@ -395,24 +396,24 @@ class Graph(BaseModel): raise CyclicalGraphError("Graph contains cycles") # Validate all edge connections are valid - for e in self.edges: + for edge in self.edges: if not are_connections_compatible( - self.get_node(e.source.node_id), - e.source.field, - self.get_node(e.destination.node_id), - e.destination.field, + self.get_node(edge.source.node_id), + edge.source.field, + self.get_node(edge.destination.node_id), + edge.destination.field, ): raise InvalidEdgeError( - f"Invalid edge from {e.source.node_id}.{e.source.field} to {e.destination.node_id}.{e.destination.field}" + f"Invalid edge from {edge.source.node_id}.{edge.source.field} to {edge.destination.node_id}.{edge.destination.field}" ) # Validate all iterators & collectors # TODO: may need to validate all iterators & collectors in subgraphs so edge connections in parent graphs will be available - for n in self.nodes.values(): - if isinstance(n, IterateInvocation) and not self._is_iterator_connection_valid(n.id): - raise InvalidEdgeError(f"Invalid iterator node {n.id}") - if isinstance(n, CollectInvocation) and not self._is_collector_connection_valid(n.id): - raise InvalidEdgeError(f"Invalid collector node {n.id}") + for node in self.nodes.values(): + if isinstance(node, IterateInvocation) and not self._is_iterator_connection_valid(node.id): + raise InvalidEdgeError(f"Invalid iterator node {node.id}") + if isinstance(node, CollectInvocation) and not self._is_collector_connection_valid(node.id): + raise InvalidEdgeError(f"Invalid collector node {node.id}") return None @@ -594,7 +595,7 @@ class Graph(BaseModel): def _get_input_edges_and_graphs( self, node_path: str, prefix: Optional[str] = None - ) -> list[tuple["Graph", str, Edge]]: + ) -> list[tuple["Graph", Union[str, None], Edge]]: """Gets all input edges for a node along with the graph they are in and the graph's path""" edges = list() @@ -636,7 +637,7 @@ class Graph(BaseModel): def _get_output_edges_and_graphs( self, node_path: str, prefix: Optional[str] = None - ) -> list[tuple["Graph", str, Edge]]: + ) -> list[tuple["Graph", Union[str, None], Edge]]: """Gets all output edges for a node along with the graph they are in and the graph's path""" edges = list() @@ -817,15 +818,15 @@ class GraphExecutionState(BaseModel): default_factory=dict, ) - @validator("graph") + @field_validator("graph") def graph_is_valid(cls, v: Graph): """Validates that the graph is valid""" v.validate_self() return v - class Config: - schema_extra = { - "required": [ + model_config = ConfigDict( + json_schema_extra=dict( + required=[ "id", "graph", "execution_graph", @@ -836,7 +837,8 @@ class GraphExecutionState(BaseModel): "prepared_source_mapping", "source_prepared_mapping", ] - } + ) + ) def next(self) -> Optional[BaseInvocation]: """Gets the next node ready to execute.""" @@ -910,7 +912,7 @@ class GraphExecutionState(BaseModel): input_collection = getattr(input_collection_prepared_node_output, input_collection_edge.source.field) self_iteration_count = len(input_collection) - new_nodes = list() + new_nodes: list[str] = list() if self_iteration_count == 0: # TODO: should this raise a warning? It might just happen if an empty collection is input, and should be valid. return new_nodes @@ -920,7 +922,7 @@ class GraphExecutionState(BaseModel): # Create new edges for this iteration # For collect nodes, this may contain multiple inputs to the same field - new_edges = list() + new_edges: list[Edge] = list() for edge in input_edges: for input_node_id in (n[1] for n in iteration_node_map if n[0] == edge.source.node_id): new_edge = Edge( @@ -1179,18 +1181,18 @@ class LibraryGraph(BaseModel): description="The outputs exposed by this graph", default_factory=list ) - @validator("exposed_inputs", "exposed_outputs") - def validate_exposed_aliases(cls, v): + @field_validator("exposed_inputs", "exposed_outputs") + def validate_exposed_aliases(cls, v: list[Union[ExposedNodeInput, ExposedNodeOutput]]): if len(v) != len(set(i.alias for i in v)): raise ValueError("Duplicate exposed alias") return v - @root_validator + @model_validator(mode="after") def validate_exposed_nodes(cls, values): - graph = values["graph"] + graph = values.graph # Validate exposed inputs - for exposed_input in values["exposed_inputs"]: + for exposed_input in values.exposed_inputs: if not graph.has_node(exposed_input.node_path): raise ValueError(f"Exposed input node {exposed_input.node_path} does not exist") node = graph.get_node(exposed_input.node_path) @@ -1200,7 +1202,7 @@ class LibraryGraph(BaseModel): ) # Validate exposed outputs - for exposed_output in values["exposed_outputs"]: + for exposed_output in values.exposed_outputs: if not graph.has_node(exposed_output.node_path): raise ValueError(f"Exposed output node {exposed_output.node_path} does not exist") node = graph.get_node(exposed_output.node_path) @@ -1212,4 +1214,6 @@ class LibraryGraph(BaseModel): return values -GraphInvocation.update_forward_refs() +GraphInvocation.model_rebuild(force=True) +Graph.model_rebuild(force=True) +GraphExecutionState.model_rebuild(force=True) diff --git a/invokeai/app/services/shared/pagination.py b/invokeai/app/services/shared/pagination.py index 85c8fb984e..ea342b1101 100644 --- a/invokeai/app/services/shared/pagination.py +++ b/invokeai/app/services/shared/pagination.py @@ -1,12 +1,11 @@ from typing import Generic, TypeVar from pydantic import BaseModel, Field -from pydantic.generics import GenericModel GenericBaseModel = TypeVar("GenericBaseModel", bound=BaseModel) -class CursorPaginatedResults(GenericModel, Generic[GenericBaseModel]): +class CursorPaginatedResults(BaseModel, Generic[GenericBaseModel]): """ Cursor-paginated results Generic must be a Pydantic model @@ -17,7 +16,7 @@ class CursorPaginatedResults(GenericModel, Generic[GenericBaseModel]): items: list[GenericBaseModel] = Field(..., description="Items") -class OffsetPaginatedResults(GenericModel, Generic[GenericBaseModel]): +class OffsetPaginatedResults(BaseModel, Generic[GenericBaseModel]): """ Offset-paginated results Generic must be a Pydantic model @@ -29,7 +28,7 @@ class OffsetPaginatedResults(GenericModel, Generic[GenericBaseModel]): items: list[GenericBaseModel] = Field(description="Items") -class PaginatedResults(GenericModel, Generic[GenericBaseModel]): +class PaginatedResults(BaseModel, Generic[GenericBaseModel]): """ Paginated results Generic must be a Pydantic model diff --git a/invokeai/app/services/shared/sqlite.py b/invokeai/app/services/shared/sqlite.py index c41dbbe606..3c75c3d6a7 100644 --- a/invokeai/app/services/shared/sqlite.py +++ b/invokeai/app/services/shared/sqlite.py @@ -9,7 +9,7 @@ sqlite_memory = ":memory:" class SqliteDatabase: conn: sqlite3.Connection - lock: threading.Lock + lock: threading.RLock _logger: Logger _config: InvokeAIAppConfig @@ -27,7 +27,7 @@ class SqliteDatabase: self._logger.info(f"Using database at {location}") self.conn = sqlite3.connect(location, check_same_thread=False) - self.lock = threading.Lock() + self.lock = threading.RLock() self.conn.row_factory = sqlite3.Row if self._config.log_sql: diff --git a/invokeai/app/util/controlnet_utils.py b/invokeai/app/util/controlnet_utils.py index e6f34a4c44..51ceec2edd 100644 --- a/invokeai/app/util/controlnet_utils.py +++ b/invokeai/app/util/controlnet_utils.py @@ -265,7 +265,7 @@ def np_img_resize(np_img: np.ndarray, resize_mode: str, h: int, w: int, device: def prepare_control_image( - image: Image, + image: Image.Image, width: int, height: int, num_channels: int = 3, diff --git a/invokeai/app/util/misc.py b/invokeai/app/util/misc.py index 6d56652ed4..910b05d8dd 100644 --- a/invokeai/app/util/misc.py +++ b/invokeai/app/util/misc.py @@ -1,4 +1,5 @@ import datetime +import typing import uuid import numpy as np @@ -27,3 +28,8 @@ def get_random_seed(): def uuid_string(): res = uuid.uuid4() return str(res) + + +def is_optional(value: typing.Any): + """Checks if a value is typed as Optional. Note that Optional is sugar for Union[x, None].""" + return typing.get_origin(value) is typing.Union and type(None) in typing.get_args(value) diff --git a/invokeai/app/util/model_exclude_null.py b/invokeai/app/util/model_exclude_null.py index b75f127ec7..6da41039b4 100644 --- a/invokeai/app/util/model_exclude_null.py +++ b/invokeai/app/util/model_exclude_null.py @@ -13,11 +13,11 @@ From https://github.com/tiangolo/fastapi/discussions/8882#discussioncomment-5154 class BaseModelExcludeNull(BaseModel): - def dict(self, *args, **kwargs) -> dict[str, Any]: + def model_dump(self, *args, **kwargs) -> dict[str, Any]: """ Override the default dict method to exclude None values in the response """ kwargs.pop("exclude_none", None) - return super().dict(*args, exclude_none=True, **kwargs) + return super().model_dump(*args, exclude_none=True, **kwargs) pass diff --git a/invokeai/assets/__init__.py b/invokeai/assets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/invokeai/backend/image_util/txt2mask.py b/invokeai/backend/image_util/txt2mask.py index 12db54b0db..de0c6a1652 100644 --- a/invokeai/backend/image_util/txt2mask.py +++ b/invokeai/backend/image_util/txt2mask.py @@ -41,18 +41,18 @@ config = InvokeAIAppConfig.get_config() class SegmentedGrayscale(object): - def __init__(self, image: Image, heatmap: torch.Tensor): + def __init__(self, image: Image.Image, heatmap: torch.Tensor): self.heatmap = heatmap self.image = image - def to_grayscale(self, invert: bool = False) -> Image: + def to_grayscale(self, invert: bool = False) -> Image.Image: return self._rescale(Image.fromarray(np.uint8(255 - self.heatmap * 255 if invert else self.heatmap * 255))) - def to_mask(self, threshold: float = 0.5) -> Image: + def to_mask(self, threshold: float = 0.5) -> Image.Image: discrete_heatmap = self.heatmap.lt(threshold).int() return self._rescale(Image.fromarray(np.uint8(discrete_heatmap * 255), mode="L")) - def to_transparent(self, invert: bool = False) -> Image: + def to_transparent(self, invert: bool = False) -> Image.Image: transparent_image = self.image.copy() # For img2img, we want the selected regions to be transparent, # but to_grayscale() returns the opposite. Thus invert. @@ -61,7 +61,7 @@ class SegmentedGrayscale(object): return transparent_image # unscales and uncrops the 352x352 heatmap so that it matches the image again - def _rescale(self, heatmap: Image) -> Image: + def _rescale(self, heatmap: Image.Image) -> Image.Image: size = self.image.width if (self.image.width > self.image.height) else self.image.height resized_image = heatmap.resize((size, size), resample=Image.Resampling.LANCZOS) return resized_image.crop((0, 0, self.image.width, self.image.height)) @@ -82,7 +82,7 @@ class Txt2Mask(object): self.model = CLIPSegForImageSegmentation.from_pretrained(CLIPSEG_MODEL, cache_dir=config.cache_dir) @torch.no_grad() - def segment(self, image, prompt: str) -> SegmentedGrayscale: + def segment(self, image: Image.Image, prompt: str) -> SegmentedGrayscale: """ Given a prompt string such as "a bagel", tries to identify the object in the provided image and returns a SegmentedGrayscale object in which the brighter @@ -99,7 +99,7 @@ class Txt2Mask(object): heatmap = torch.sigmoid(outputs.logits) return SegmentedGrayscale(image, heatmap) - def _scale_and_crop(self, image: Image) -> Image: + def _scale_and_crop(self, image: Image.Image) -> Image.Image: scaled_image = Image.new("RGB", (CLIPSEG_SIZE, CLIPSEG_SIZE)) if image.width > image.height: # width is constraint scale = CLIPSEG_SIZE / image.width diff --git a/invokeai/backend/image_util/util.py b/invokeai/backend/image_util/util.py index bc7fa01e3b..7eceb9be82 100644 --- a/invokeai/backend/image_util/util.py +++ b/invokeai/backend/image_util/util.py @@ -9,7 +9,7 @@ class InitImageResizer: def __init__(self, Image): self.image = Image - def resize(self, width=None, height=None) -> Image: + def resize(self, width=None, height=None) -> Image.Image: """ Return a copy of the image resized to fit within a box width x height. The aspect ratio is diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index d4bcea64d0..59cf1260ba 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -793,7 +793,11 @@ def migrate_init_file(legacy_format: Path): old = legacy_parser.parse_args([f"@{str(legacy_format)}"]) new = InvokeAIAppConfig.get_config() - fields = [x for x, y in InvokeAIAppConfig.__fields__.items() if y.field_info.extra.get("category") != "DEPRECATED"] + fields = [ + x + for x, y in InvokeAIAppConfig.model_fields.items() + if (y.json_schema_extra.get("category", None) if y.json_schema_extra else None) != "DEPRECATED" + ] for attr in fields: if hasattr(old, attr): try: diff --git a/invokeai/backend/install/model_install_backend.py b/invokeai/backend/install/model_install_backend.py index 1481300c77..9224f5c8b2 100644 --- a/invokeai/backend/install/model_install_backend.py +++ b/invokeai/backend/install/model_install_backend.py @@ -236,9 +236,16 @@ class ModelInstall(object): if not models_installed: models_installed = dict() + model_path_id_or_url = str(model_path_id_or_url).strip("\"' ") + # A little hack to allow nested routines to retrieve info on the requested ID self.current_id = model_path_id_or_url path = Path(model_path_id_or_url) + + # fix relative paths + if path.exists() and not path.is_absolute(): + path = path.absolute() # make relative to current WD + # checkpoint file, or similar if path.is_file(): models_installed.update({str(path): self._install_path(path)}) diff --git a/invokeai/backend/model_management/memory_snapshot.py b/invokeai/backend/model_management/memory_snapshot.py index 4f43affcf7..01f1328114 100644 --- a/invokeai/backend/model_management/memory_snapshot.py +++ b/invokeai/backend/model_management/memory_snapshot.py @@ -55,8 +55,10 @@ class MemorySnapshot: try: malloc_info = LibcUtil().mallinfo2() - except OSError: - # This is expected in environments that do not have the 'libc.so.6' shared library. + except (OSError, AttributeError): + # OSError: This is expected in environments that do not have the 'libc.so.6' shared library. + # AttributeError: This is expected in environments that have `libc.so.6` but do not have the `mallinfo2` (e.g. glibc < 2.33) + # TODO: Does `mallinfo` work? malloc_info = None return cls(process_ram, vram, malloc_info) diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index 7bb188cb4e..38a7361c85 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -236,13 +236,13 @@ import types from dataclasses import dataclass from pathlib import Path from shutil import move, rmtree -from typing import Callable, Dict, List, Literal, Optional, Set, Tuple, Union +from typing import Callable, Dict, List, Literal, Optional, Set, Tuple, Union, cast import torch import yaml from omegaconf import OmegaConf from omegaconf.dictconfig import DictConfig -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field import invokeai.backend.util.logging as logger from invokeai.app.services.config import InvokeAIAppConfig @@ -294,6 +294,8 @@ class AddModelResult(BaseModel): base_model: BaseModelType = Field(description="The base model") config: ModelConfigBase = Field(description="The configuration of the model") + model_config = ConfigDict(protected_namespaces=()) + MAX_CACHE_SIZE = 6.0 # GB @@ -576,7 +578,7 @@ class ModelManager(object): """ model_key = self.create_key(model_name, base_model, model_type) if model_key in self.models: - return self.models[model_key].dict(exclude_defaults=True) + return self.models[model_key].model_dump(exclude_defaults=True) else: return None # TODO: None or empty dict on not found @@ -632,7 +634,7 @@ class ModelManager(object): continue model_dict = dict( - **model_config.dict(exclude_defaults=True), + **model_config.model_dump(exclude_defaults=True), # OpenAPIModelInfoBase model_name=cur_model_name, base_model=cur_base_model, @@ -900,14 +902,16 @@ class ModelManager(object): Write current configuration out to the indicated file. """ data_to_save = dict() - data_to_save["__metadata__"] = self.config_meta.dict() + data_to_save["__metadata__"] = self.config_meta.model_dump() for model_key, model_config in self.models.items(): model_name, base_model, model_type = self.parse_key(model_key) model_class = self._get_implementation(base_model, model_type) if model_class.save_to_config: # TODO: or exclude_unset better fits here? - data_to_save[model_key] = model_config.dict(exclude_defaults=True, exclude={"error"}) + data_to_save[model_key] = cast(BaseModel, model_config).model_dump( + exclude_defaults=True, exclude={"error"}, mode="json" + ) # alias for config file data_to_save[model_key]["format"] = data_to_save[model_key].pop("model_format") @@ -986,6 +990,8 @@ class ModelManager(object): for model_path in models_dir.iterdir(): if model_path not in loaded_files: # TODO: check + if model_path.name.startswith("."): + continue model_name = model_path.name if model_path.is_dir() else model_path.stem model_key = self.create_key(model_name, cur_base_model, cur_model_type) diff --git a/invokeai/backend/model_management/models/__init__.py b/invokeai/backend/model_management/models/__init__.py index bf4b208395..0afd731032 100644 --- a/invokeai/backend/model_management/models/__init__.py +++ b/invokeai/backend/model_management/models/__init__.py @@ -2,7 +2,7 @@ import inspect from enum import Enum from typing import Literal, get_origin -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict, create_model from .base import ( # noqa: F401 BaseModelType, @@ -106,6 +106,8 @@ class OpenAPIModelInfoBase(BaseModel): base_model: BaseModelType model_type: ModelType + model_config = ConfigDict(protected_namespaces=()) + for base_model, models in MODEL_CLASSES.items(): for model_type, model_class in models.items(): @@ -121,17 +123,11 @@ for base_model, models in MODEL_CLASSES.items(): if openapi_cfg_name in vars(): continue - api_wrapper = type( + api_wrapper = create_model( openapi_cfg_name, - (cfg, OpenAPIModelInfoBase), - dict( - __annotations__=dict( - model_type=Literal[model_type.value], - ), - ), + __base__=(cfg, OpenAPIModelInfoBase), + model_type=(Literal[model_type], model_type), # type: ignore ) - - # globals()[openapi_cfg_name] = api_wrapper vars()[openapi_cfg_name] = api_wrapper OPENAPI_MODEL_CONFIGS.append(api_wrapper) diff --git a/invokeai/backend/model_management/models/base.py b/invokeai/backend/model_management/models/base.py index 6e507735d4..f735e37189 100644 --- a/invokeai/backend/model_management/models/base.py +++ b/invokeai/backend/model_management/models/base.py @@ -19,7 +19,7 @@ from diffusers import logging as diffusers_logging from onnx import numpy_helper from onnxruntime import InferenceSession, SessionOptions, get_available_providers from picklescan.scanner import scan_file_path -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from transformers import logging as transformers_logging @@ -86,14 +86,21 @@ class ModelError(str, Enum): NotFound = "not_found" +def model_config_json_schema_extra(schema: dict[str, Any]) -> None: + if "required" not in schema: + schema["required"] = [] + schema["required"].append("model_type") + + class ModelConfigBase(BaseModel): path: str # or Path description: Optional[str] = Field(None) model_format: Optional[str] = Field(None) error: Optional[ModelError] = Field(None) - class Config: - use_enum_values = True + model_config = ConfigDict( + use_enum_values=True, protected_namespaces=(), json_schema_extra=model_config_json_schema_extra + ) class EmptyConfigLoader(ConfigMixin): diff --git a/invokeai/backend/model_management/models/ip_adapter.py b/invokeai/backend/model_management/models/ip_adapter.py index 63694af0c8..c60edd0abe 100644 --- a/invokeai/backend/model_management/models/ip_adapter.py +++ b/invokeai/backend/model_management/models/ip_adapter.py @@ -58,14 +58,16 @@ class IPAdapterModel(ModelBase): def get_model( self, - torch_dtype: Optional[torch.dtype], + torch_dtype: torch.dtype, child_type: Optional[SubModelType] = None, ) -> typing.Union[IPAdapter, IPAdapterPlus]: if child_type is not None: raise ValueError("There are no child models in an IP-Adapter model.") model = build_ip_adapter( - ip_adapter_ckpt_path=os.path.join(self.model_path, "ip_adapter.bin"), device="cpu", dtype=torch_dtype + ip_adapter_ckpt_path=os.path.join(self.model_path, "ip_adapter.bin"), + device=torch.device("cpu"), + dtype=torch_dtype, ) self.model_size = model.calc_size() diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 7138f2e123..bfdf9e0c53 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -96,7 +96,7 @@ def set_seamless(model: Union[UNet2DConditionModel, AutoencoderKL], seamless_axe finally: for module, orig_conv_forward in to_restore: module._conv_forward = orig_conv_forward - if hasattr(m, "asymmetric_padding_mode"): - del m.asymmetric_padding_mode - if hasattr(m, "asymmetric_padding"): - del m.asymmetric_padding + if hasattr(module, "asymmetric_padding_mode"): + del module.asymmetric_padding_mode + if hasattr(module, "asymmetric_padding"): + del module.asymmetric_padding diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 0943b78bf8..1b65326f6e 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: - # 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: + 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: + 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 diff --git a/invokeai/backend/stable_diffusion/diffusion/cross_attention_map_saving.py b/invokeai/backend/stable_diffusion/diffusion/cross_attention_map_saving.py index abef979b1c..b5ea40185a 100644 --- a/invokeai/backend/stable_diffusion/diffusion/cross_attention_map_saving.py +++ b/invokeai/backend/stable_diffusion/diffusion/cross_attention_map_saving.py @@ -1,7 +1,8 @@ import math +from typing import Optional -import PIL import torch +from PIL import Image from torchvision.transforms.functional import InterpolationMode from torchvision.transforms.functional import resize as tv_resize @@ -11,7 +12,7 @@ class AttentionMapSaver: self.token_ids = token_ids self.latents_shape = latents_shape # self.collated_maps = #torch.zeros([len(token_ids), latents_shape[0], latents_shape[1]]) - self.collated_maps = {} + self.collated_maps: dict[str, torch.Tensor] = {} def clear_maps(self): self.collated_maps = {} @@ -38,9 +39,10 @@ class AttentionMapSaver: def write_maps_to_disk(self, path: str): pil_image = self.get_stacked_maps_image() - pil_image.save(path, "PNG") + if pil_image is not None: + pil_image.save(path, "PNG") - def get_stacked_maps_image(self) -> PIL.Image: + def get_stacked_maps_image(self) -> Optional[Image.Image]: """ Scale all collected attention maps to the same size, blend them together and return as an image. :return: An image containing a vertical stack of blended attention maps, one for each requested token. @@ -95,4 +97,4 @@ class AttentionMapSaver: return None merged_bytes = merged.mul(0xFF).byte() - return PIL.Image.fromarray(merged_bytes.numpy(), mode="L") + return Image.fromarray(merged_bytes.numpy(), mode="L") diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index c12c86ed92..d2af522496 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,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: @@ -437,6 +445,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 +474,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 +499,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 +536,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 +556,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, ) diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index e5f1513c89..59e672544a 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -54,42 +54,42 @@ ] }, "dependencies": { - "@chakra-ui/anatomy": "^2.2.0", - "@chakra-ui/icons": "^2.1.0", - "@chakra-ui/react": "^2.8.0", + "@chakra-ui/anatomy": "^2.2.1", + "@chakra-ui/icons": "^2.1.1", + "@chakra-ui/react": "^2.8.1", "@chakra-ui/styled-system": "^2.9.1", - "@chakra-ui/theme-tools": "^2.1.0", + "@chakra-ui/theme-tools": "^2.1.1", "@dagrejs/graphlib": "^2.1.13", "@dnd-kit/core": "^6.0.8", "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/utilities": "^3.2.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@floating-ui/react-dom": "^2.0.1", - "@fontsource-variable/inter": "^5.0.8", - "@fontsource/inter": "^5.0.8", + "@floating-ui/react-dom": "^2.0.2", + "@fontsource-variable/inter": "^5.0.13", + "@fontsource/inter": "^5.0.13", "@mantine/core": "^6.0.19", "@mantine/form": "^6.0.19", "@mantine/hooks": "^6.0.19", "@nanostores/react": "^0.7.1", - "@reduxjs/toolkit": "^1.9.5", - "@roarr/browser-log-writer": "^1.1.5", + "@reduxjs/toolkit": "^1.9.7", + "@roarr/browser-log-writer": "^1.3.0", "@stevebel/png": "^1.5.1", "compare-versions": "^6.1.0", "dateformat": "^5.0.3", - "formik": "^2.4.3", - "framer-motion": "^10.16.1", + "formik": "^2.4.5", + "framer-motion": "^10.16.4", "fuse.js": "^6.6.2", - "i18next": "^23.4.4", + "i18next": "^23.5.1", "i18next-browser-languagedetector": "^7.0.2", - "i18next-http-backend": "^2.2.1", - "konva": "^9.2.0", + "i18next-http-backend": "^2.2.2", + "konva": "^9.2.2", "lodash-es": "^4.17.21", "nanostores": "^0.9.2", "new-github-issue-url": "^1.0.0", - "openapi-fetch": "^0.7.4", - "overlayscrollbars": "^2.2.0", - "overlayscrollbars-react": "^0.5.0", + "openapi-fetch": "^0.7.10", + "overlayscrollbars": "^2.3.2", + "overlayscrollbars-react": "^0.5.2", "patch-package": "^8.0.0", "query-string": "^8.1.0", "react": "^18.2.0", @@ -98,25 +98,25 @@ "react-dropzone": "^14.2.3", "react-error-boundary": "^4.0.11", "react-hotkeys-hook": "4.4.1", - "react-i18next": "^13.1.2", - "react-icons": "^4.10.1", + "react-i18next": "^13.3.0", + "react-icons": "^4.11.0", "react-konva": "^18.2.10", - "react-redux": "^8.1.2", + "react-redux": "^8.1.3", "react-resizable-panels": "^0.0.55", "react-use": "^17.4.0", - "react-virtuoso": "^4.5.0", - "react-zoom-pan-pinch": "^3.0.8", - "reactflow": "^11.8.3", + "react-virtuoso": "^4.6.1", + "react-zoom-pan-pinch": "^3.2.0", + "reactflow": "^11.9.3", "redux-dynamic-middlewares": "^2.2.0", - "redux-remember": "^4.0.1", + "redux-remember": "^4.0.4", "roarr": "^7.15.1", - "serialize-error": "^11.0.1", + "serialize-error": "^11.0.2", "socket.io-client": "^4.7.2", - "type-fest": "^4.2.0", + "type-fest": "^4.4.0", "use-debounce": "^9.0.4", "use-image": "^1.1.1", - "uuid": "^9.0.0", - "zod": "^3.22.2", + "uuid": "^9.0.1", + "zod": "^3.22.4", "zod-validation-error": "^1.5.0" }, "peerDependencies": { @@ -129,40 +129,40 @@ "devDependencies": { "@chakra-ui/cli": "^2.4.1", "@types/dateformat": "^5.0.0", - "@types/lodash-es": "^4.14.194", - "@types/node": "^20.5.1", - "@types/react": "^18.2.20", - "@types/react-dom": "^18.2.6", - "@types/react-redux": "^7.1.25", - "@types/react-transition-group": "^4.4.6", - "@types/uuid": "^9.0.2", - "@typescript-eslint/eslint-plugin": "^6.4.1", - "@typescript-eslint/parser": "^6.4.1", - "@vitejs/plugin-react-swc": "^3.3.2", - "axios": "^1.4.0", + "@types/lodash-es": "^4.17.9", + "@types/node": "^20.8.6", + "@types/react": "^18.2.28", + "@types/react-dom": "^18.2.13", + "@types/react-redux": "^7.1.27", + "@types/react-transition-group": "^4.4.7", + "@types/uuid": "^9.0.5", + "@typescript-eslint/eslint-plugin": "^6.7.5", + "@typescript-eslint/parser": "^6.7.5", + "@vitejs/plugin-react-swc": "^3.4.0", + "axios": "^1.5.1", "babel-plugin-transform-imports": "^2.0.0", - "concurrently": "^8.2.0", - "eslint": "^8.47.0", + "concurrently": "^8.2.1", + "eslint": "^8.51.0", "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "form-data": "^4.0.0", "husky": "^8.0.3", - "lint-staged": "^14.0.1", + "lint-staged": "^15.0.1", "madge": "^6.1.0", "openapi-types": "^12.1.3", - "openapi-typescript": "^6.5.2", + "openapi-typescript": "^6.7.0", "postinstall-postinstall": "^2.1.0", - "prettier": "^3.0.2", + "prettier": "^3.0.3", "rollup-plugin-visualizer": "^5.9.2", "ts-toolbelt": "^9.6.0", "typescript": "^5.2.2", - "vite": "^4.4.9", + "vite": "^4.4.11", "vite-plugin-css-injected-by-js": "^3.3.0", - "vite-plugin-dts": "^3.5.2", + "vite-plugin-dts": "^3.6.0", "vite-plugin-eslint": "^1.8.1", - "vite-tsconfig-paths": "^4.2.0", + "vite-tsconfig-paths": "^4.2.1", "yarn": "^1.22.19" } } diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index e0baefcf9e..818f9f4fa9 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -137,9 +137,9 @@ "controlnet": { "controlAdapter_one": "Control Adapter", "controlAdapter_other": "Control Adapters", - "controlnet": "$t(controlnet.controlAdapter) #{{number}} ($t(common.controlNet))", - "ip_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.ipAdapter))", - "t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.t2iAdapter))", + "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))", + "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))", + "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))", "addControlNet": "Add $t(common.controlNet)", "addIPAdapter": "Add $t(common.ipAdapter)", "addT2IAdapter": "Add $t(common.t2iAdapter)", @@ -559,8 +559,10 @@ "negativePrompt": "Negative Prompt", "noImageDetails": "No image details found", "noMetaData": "No metadata found", + "noRecallParameters": "No parameters to recall found", "perlin": "Perlin Noise", "positivePrompt": "Positive Prompt", + "recallParameters": "Recall Parameters", "scheduler": "Scheduler", "seamless": "Seamless", "seed": "Seed", @@ -1113,6 +1115,7 @@ "showProgressInViewer": "Show Progress Images in Viewer", "ui": "User Interface", "useSlidersForAll": "Use Sliders For All Options", + "clearIntermediatesDisabled": "Queue must be empty to clear intermediates", "clearIntermediatesDesc1": "Clearing intermediates will reset your Canvas and ControlNet state.", "clearIntermediatesDesc2": "Intermediate images are byproducts of generation, different from the result images in the gallery. Clearing intermediates will free disk space.", "clearIntermediatesDesc3": "Your gallery images will not be deleted.", diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index 42836e4d0f..c69879cfcf 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.json @@ -87,7 +87,9 @@ "learnMore": "Per saperne di piĆ¹", "ipAdapter": "Adattatore IP", "t2iAdapter": "Adattatore T2I", - "controlAdapter": "Adattatore di Controllo" + "controlAdapter": "Adattatore di Controllo", + "controlNet": "ControlNet", + "auto": "Automatico" }, "gallery": { "generations": "Generazioni", @@ -115,7 +117,10 @@ "currentlyInUse": "Questa immagine ĆØ attualmente utilizzata nelle seguenti funzionalitĆ :", "copy": "Copia", "download": "Scarica", - "setCurrentImage": "Imposta come immagine corrente" + "setCurrentImage": "Imposta come immagine corrente", + "preparingDownload": "Preparazione del download", + "preparingDownloadFailed": "Problema durante la preparazione del download", + "downloadSelection": "Scarica gli elementi selezionati" }, "hotkeys": { "keyboardShortcuts": "Tasti rapidi", @@ -468,7 +473,8 @@ "useCustomConfig": "Utilizza configurazione personalizzata", "closeAdvanced": "Chiudi Avanzate", "modelType": "Tipo di modello", - "customConfigFileLocation": "Posizione del file di configurazione personalizzato" + "customConfigFileLocation": "Posizione del file di configurazione personalizzato", + "vaePrecision": "Precisione VAE" }, "parameters": { "images": "Immagini", @@ -570,9 +576,12 @@ "systemBusy": "Sistema occupato", "unableToInvoke": "Impossibile invocare", "systemDisconnected": "Sistema disconnesso", - "noControlImageForControlAdapter": "L'adattatore di controllo {{number}} non ha un'immagine di controllo", - "noModelForControlAdapter": "Nessun modello selezionato per l'adattatore di controllo {{number}}.", - "incompatibleBaseModelForControlAdapter": "Il modello dell'adattatore di controllo {{number}} non ĆØ compatibile con il modello principale." + "noControlImageForControlAdapter": "L'adattatore di controllo #{{number}} non ha un'immagine di controllo", + "noModelForControlAdapter": "Nessun modello selezionato per l'adattatore di controllo #{{number}}.", + "incompatibleBaseModelForControlAdapter": "Il modello dell'adattatore di controllo #{{number}} non ĆØ compatibile con il modello principale.", + "missingNodeTemplate": "Modello di nodo mancante", + "missingInputForField": "{{nodeLabel}} -> {{fieldLabel}} ingresso mancante", + "missingFieldTemplate": "Modello di campo mancante" }, "enableNoiseSettings": "Abilita le impostazioni del rumore", "cpuNoise": "Rumore CPU", @@ -583,7 +592,7 @@ "iterations": "Iterazioni", "iterationsWithCount_one": "{{count}} Iterazione", "iterationsWithCount_many": "{{count}} Iterazioni", - "iterationsWithCount_other": "", + "iterationsWithCount_other": "{{count}} Iterazioni", "seamlessX&Y": "Senza cuciture X & Y", "isAllowedToUpscale": { "useX2Model": "L'immagine ĆØ troppo grande per l'ampliamento con il modello x4, utilizza il modello x2", @@ -591,7 +600,8 @@ }, "seamlessX": "Senza cuciture X", "seamlessY": "Senza cuciture Y", - "imageActions": "Azioni Immagine" + "imageActions": "Azioni Immagine", + "aspectRatioFree": "Libere" }, "settings": { "models": "Modelli", @@ -620,7 +630,19 @@ "beta": "Beta", "enableNodesEditor": "Abilita l'editor dei nodi", "experimental": "Sperimentale", - "autoChangeDimensions": "Aggiorna L/A alle impostazioni predefinite del modello in caso di modifica" + "autoChangeDimensions": "Aggiorna L/A alle impostazioni predefinite del modello in caso di modifica", + "clearIntermediates": "Cancella le immagini intermedie", + "clearIntermediatesDesc3": "Le immagini della galleria non verranno eliminate.", + "clearIntermediatesDesc2": "Le immagini intermedie sono sottoprodotti della generazione, diversi dalle immagini risultanti nella galleria. La cancellazione degli intermedi libererĆ  spazio su disco.", + "intermediatesCleared_one": "Cancellata {{count}} immagine intermedia", + "intermediatesCleared_many": "Cancellate {{count}} immagini intermedie", + "intermediatesCleared_other": "Cancellate {{count}} immagini intermedie", + "clearIntermediatesDesc1": "La cancellazione delle immagini intermedie ripristinerĆ  lo stato di Tela Unificata e ControlNet.", + "intermediatesClearedFailed": "Problema con la cancellazione delle immagini intermedie", + "clearIntermediatesWithCount_one": "Cancella {{count}} immagine intermedia", + "clearIntermediatesWithCount_many": "Cancella {{count}} immagini intermedie", + "clearIntermediatesWithCount_other": "Cancella {{count}} immagini intermedie", + "clearIntermediatesDisabled": "La coda deve essere vuota per cancellare le immagini intermedie" }, "toast": { "tempFoldersEmptied": "Cartella temporanea svuotata", @@ -670,9 +692,9 @@ "nodesUnrecognizedTypes": "Impossibile caricare. Il grafico ha tipi di dati non riconosciuti", "nodesNotValidJSON": "JSON non valido", "nodesBrokenConnections": "Impossibile caricare. Alcune connessioni sono interrotte.", - "baseModelChangedCleared_one": "Il modello base ĆØ stato modificato, cancellato o disabilitato {{number}} sotto-modello incompatibile", - "baseModelChangedCleared_many": "", - "baseModelChangedCleared_other": "", + "baseModelChangedCleared_one": "Il modello base ĆØ stato modificato, cancellato o disabilitato {{count}} sotto-modello incompatibile", + "baseModelChangedCleared_many": "Il modello base ĆØ stato modificato, cancellato o disabilitato {{count}} sotto-modelli incompatibili", + "baseModelChangedCleared_other": "Il modello base ĆØ stato modificato, cancellato o disabilitato {{count}} sotto-modelli incompatibili", "imageSavingFailed": "Salvataggio dell'immagine non riuscito", "canvasSentControlnetAssets": "Tela inviata a ControlNet & Risorse", "problemCopyingCanvasDesc": "Impossibile copiare la tela", @@ -866,7 +888,144 @@ "workflowValidation": "Errore di convalida del flusso di lavoro", "workflowAuthor": "Autore", "workflowName": "Nome", - "workflowNotes": "Note" + "workflowNotes": "Note", + "unhandledInputProperty": "ProprietĆ  di input non gestita", + "versionUnknown": " Versione sconosciuta", + "unableToValidateWorkflow": "Impossibile convalidare il flusso di lavoro", + "updateApp": "Aggiorna App", + "problemReadingWorkflow": "Problema durante la lettura del flusso di lavoro dall'immagine", + "unableToLoadWorkflow": "Impossibile caricare il flusso di lavoro", + "updateNode": "Aggiorna nodo", + "version": "Versione", + "notes": "Note", + "problemSettingTitle": "Problema nell'impostazione del titolo", + "unkownInvocation": "Tipo di invocazione sconosciuta", + "unknownTemplate": "Modello sconosciuto", + "nodeType": "Tipo di nodo", + "vaeField": "VAE", + "unhandledOutputProperty": "ProprietĆ  di output non gestita", + "notesDescription": "Aggiunge note sul tuo flusso di lavoro", + "unknownField": "Campo sconosciuto", + "unknownNode": "Nodo sconosciuto", + "vaeFieldDescription": "Sotto modello VAE.", + "booleanPolymorphicDescription": "Una raccolta di booleani.", + "missingTemplate": "Modello mancante", + "outputSchemaNotFound": "Schema di output non trovato", + "colorFieldDescription": "Un colore RGBA.", + "maybeIncompatible": "Potrebbe essere incompatibile con quello installato", + "noNodeSelected": "Nessun nodo selezionato", + "colorPolymorphic": "Colore polimorfico", + "booleanCollectionDescription": "Una raccolta di booleani.", + "colorField": "Colore", + "nodeTemplate": "Modello di nodo", + "nodeOpacity": "OpacitĆ  del nodo", + "pickOne": "Sceglierne uno", + "outputField": "Campo di output", + "nodeSearch": "Cerca nodi", + "nodeOutputs": "Uscite del nodo", + "collectionItem": "Oggetto della raccolta", + "noConnectionInProgress": "Nessuna connessione in corso", + "noConnectionData": "Nessun dato di connessione", + "outputFields": "Campi di output", + "cannotDuplicateConnection": "Impossibile creare connessioni duplicate", + "booleanPolymorphic": "Polimorfico booleano", + "colorPolymorphicDescription": "Una collezione di colori polimorfici.", + "missingCanvaInitImage": "Immagine iniziale della tela mancante", + "clipFieldDescription": "Sottomodelli di tokenizzatore e codificatore di testo.", + "noImageFoundState": "Nessuna immagine iniziale trovata nello stato", + "clipField": "CLIP", + "noMatchingNodes": "Nessun nodo corrispondente", + "noFieldType": "Nessun tipo di campo", + "colorCollection": "Una collezione di colori.", + "noOutputSchemaName": "Nessun nome dello schema di output trovato nell'oggetto di riferimento", + "boolean": "Booleani", + "missingCanvaInitMaskImages": "Immagini di inizializzazione e maschera della tela mancanti", + "oNNXModelField": "Modello ONNX", + "node": "Nodo", + "booleanDescription": "I booleani sono veri o falsi.", + "collection": "Raccolta", + "cannotConnectInputToInput": "Impossibile collegare Input a Input", + "cannotConnectOutputToOutput": "Impossibile collegare Output ad Output", + "booleanCollection": "Raccolta booleana", + "cannotConnectToSelf": "Impossibile connettersi a se stesso", + "mismatchedVersion": "Ha una versione non corrispondente", + "outputNode": "Nodo di Output", + "loadingNodes": "Caricamento nodi...", + "oNNXModelFieldDescription": "Campo del modello ONNX.", + "denoiseMaskFieldDescription": "La maschera di riduzione del rumore puĆ² essere passata tra i nodi", + "floatCollectionDescription": "Una raccolta di numeri virgola mobile.", + "enum": "Enumeratore", + "float": "In virgola mobile", + "doesNotExist": "non esiste", + "currentImageDescription": "Visualizza l'immagine corrente nell'editor dei nodi", + "fieldTypesMustMatch": "I tipi di campo devono corrispondere", + "edge": "Bordo", + "enumDescription": "Gli enumeratori sono valori che possono essere una delle diverse opzioni.", + "denoiseMaskField": "Maschera riduzione rumore", + "currentImage": "Immagine corrente", + "floatCollection": "Raccolta in virgola mobile", + "inputField": "Campo di Input", + "controlFieldDescription": "Informazioni di controllo passate tra i nodi.", + "skippingUnknownOutputType": "Tipo di campo di output sconosciuto saltato", + "latentsFieldDescription": "Le immagini latenti possono essere passate tra i nodi.", + "ipAdapterPolymorphicDescription": "Una raccolta di adattatori IP.", + "latentsPolymorphicDescription": "Le immagini latenti possono essere passate tra i nodi.", + "ipAdapterCollection": "Raccolta Adattatori IP", + "conditioningCollection": "Raccolta condizionamenti", + "ipAdapterPolymorphic": "Adattatore IP Polimorfico", + "integerPolymorphicDescription": "Una raccolta di numeri interi.", + "conditioningCollectionDescription": "Il condizionamento puĆ² essere passato tra i nodi.", + "skippingReservedFieldType": "Tipo di campo riservato saltato", + "conditioningPolymorphic": "Condizionamento Polimorfico", + "integer": "Numero Intero", + "latentsCollection": "Raccolta Latenti", + "sourceNode": "Nodo di origine", + "integerDescription": "Gli interi sono numeri senza punto decimale.", + "stringPolymorphic": "Stringa polimorfica", + "conditioningPolymorphicDescription": "Il condizionamento puĆ² essere passato tra i nodi.", + "skipped": "Saltato", + "imagePolymorphic": "Immagine Polimorfica", + "imagePolymorphicDescription": "Una raccolta di immagini.", + "floatPolymorphic": "Numeri in virgola mobile Polimorfici", + "ipAdapterCollectionDescription": "Una raccolta di adattatori IP.", + "stringCollectionDescription": "Una raccolta di stringhe.", + "unableToParseNode": "Impossibile analizzare il nodo", + "controlCollection": "Raccolta di Controllo", + "stringCollection": "Raccolta di stringhe", + "inputMayOnlyHaveOneConnection": "L'ingresso puĆ² avere solo una connessione", + "ipAdapter": "Adattatore IP", + "integerCollection": "Raccolta di numeri interi", + "controlCollectionDescription": "Informazioni di controllo passate tra i nodi.", + "skippedReservedInput": "Campo di input riservato saltato", + "inputNode": "Nodo di Input", + "imageField": "Immagine", + "skippedReservedOutput": "Campo di output riservato saltato", + "integerCollectionDescription": "Una raccolta di numeri interi.", + "conditioningFieldDescription": "Il condizionamento puĆ² essere passato tra i nodi.", + "stringDescription": "Le stringhe sono testo.", + "integerPolymorphic": "Numero intero Polimorfico", + "ipAdapterModel": "Modello Adattatore IP", + "latentsPolymorphic": "Latenti polimorfici", + "skippingInputNoTemplate": "Campo di input senza modello saltato", + "ipAdapterDescription": "Un adattatore di prompt di immagini (Adattatore IP).", + "stringPolymorphicDescription": "Una raccolta di stringhe.", + "skippingUnknownInputType": "Tipo di campo di input sconosciuto saltato", + "controlField": "Controllo", + "ipAdapterModelDescription": "Campo Modello adattatore IP", + "invalidOutputSchema": "Schema di output non valido", + "floatDescription": "I numeri in virgola mobile sono numeri con un punto decimale.", + "floatPolymorphicDescription": "Una raccolta di numeri in virgola mobile.", + "conditioningField": "Condizionamento", + "string": "Stringa", + "latentsField": "Latenti", + "connectionWouldCreateCycle": "La connessione creerebbe un ciclo", + "inputFields": "Campi di Input", + "uNetFieldDescription": "Sub-modello UNet.", + "imageCollectionDescription": "Una raccolta di immagini.", + "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" }, "boards": { "autoAddBoard": "Aggiungi automaticamente bacheca", @@ -883,7 +1042,8 @@ "searchBoard": "Cerca bacheche ...", "noMatching": "Nessuna bacheca corrispondente", "selectBoard": "Seleziona una Bacheca", - "uncategorized": "Non categorizzato" + "uncategorized": "Non categorizzato", + "downloadBoard": "Scarica la bacheca" }, "controlnet": { "contentShuffleDescription": "Rimescola il contenuto di un'immagine", @@ -951,8 +1111,12 @@ "addControlNet": "Aggiungi $t(common.controlNet)", "controlNetT2IMutexDesc": "$t(common.controlNet) e $t(common.t2iAdapter) contemporaneamente non sono attualmente supportati.", "addIPAdapter": "Aggiungi $t(common.ipAdapter)", - "controlAdapter": "Adattatore di Controllo", - "megaControl": "Mega ControlNet" + "controlAdapter_one": "Adattatore di Controllo", + "controlAdapter_many": "Adattatori di Controllo", + "controlAdapter_other": "Adattatori di Controllo", + "megaControl": "Mega ControlNet", + "minConfidence": "Confidenza minima", + "scribble": "Scribble" }, "queue": { "queueFront": "Aggiungi all'inizio della coda", @@ -979,7 +1143,9 @@ "pause": "Sospendi", "pruneTooltip": "Rimuovi {{item_count}} elementi completati", "cancelSucceeded": "Elemento annullato", - "batchQueuedDesc": "Aggiunte {{item_count}} sessioni a {{direction}} della coda", + "batchQueuedDesc_one": "Aggiunta {{count}} sessione a {{direction}} della coda", + "batchQueuedDesc_many": "Aggiunte {{count}} sessioni a {{direction}} della coda", + "batchQueuedDesc_other": "Aggiunte {{count}} sessioni a {{direction}} della coda", "graphQueued": "Grafico in coda", "batch": "Lotto", "clearQueueAlertDialog": "Lo svuotamento della coda annulla immediatamente tutti gli elementi in elaborazione e cancella completamente la coda.", @@ -1056,7 +1222,7 @@ "maxPrompts": "Numero massimo di prompt", "promptsWithCount_one": "{{count}} Prompt", "promptsWithCount_many": "{{count}} Prompt", - "promptsWithCount_other": "", + "promptsWithCount_other": "{{count}} Prompt", "dynamicPrompts": "Prompt dinamici" }, "popovers": { @@ -1268,7 +1434,8 @@ "controlNet": { "paragraphs": [ "ControlNet fornisce una guida al processo di generazione, aiutando a creare immagini con composizione, struttura o stile controllati, a seconda del modello selezionato." - ] + ], + "heading": "ControlNet" } }, "sdxl": { @@ -1313,6 +1480,8 @@ "createdBy": "Creato da", "workflow": "Flusso di lavoro", "steps": "Passi", - "scheduler": "Campionatore" + "scheduler": "Campionatore", + "recallParameters": "Richiama i parametri", + "noRecallParameters": "Nessun parametro da richiamare trovato" } } diff --git a/invokeai/frontend/web/public/locales/nl.json b/invokeai/frontend/web/public/locales/nl.json index f682886dae..5c08f65d21 100644 --- a/invokeai/frontend/web/public/locales/nl.json +++ b/invokeai/frontend/web/public/locales/nl.json @@ -79,7 +79,18 @@ "modelManager": "Modelbeheer", "darkMode": "Donkere modus", "lightMode": "Lichte modus", - "communityLabel": "Gemeenschap" + "communityLabel": "Gemeenschap", + "t2iAdapter": "T2I-adapter", + "on": "Aan", + "nodeEditor": "Knooppunteditor", + "ipAdapter": "IP-adapter", + "controlAdapter": "Control-adapter", + "auto": "Autom.", + "controlNet": "ControlNet", + "statusProcessing": "Bezig met verwerken", + "imageFailedToLoad": "Kan afbeelding niet laden", + "learnMore": "Meer informatie", + "advanced": "Uitgebreid" }, "gallery": { "generations": "Gegenereerde afbeeldingen", @@ -100,7 +111,17 @@ "deleteImagePermanent": "Gewiste afbeeldingen kunnen niet worden hersteld.", "assets": "Eigen onderdelen", "images": "Afbeeldingen", - "autoAssignBoardOnClick": "Ken automatisch bord toe bij klikken" + "autoAssignBoardOnClick": "Ken automatisch bord toe bij klikken", + "featuresWillReset": "Als je deze afbeelding verwijdert, dan worden deze functies onmiddellijk teruggezet.", + "loading": "Bezig met laden", + "unableToLoad": "Kan galerij niet laden", + "preparingDownload": "Bezig met voorbereiden van download", + "preparingDownloadFailed": "Fout bij voorbereiden van download", + "downloadSelection": "Download selectie", + "currentlyInUse": "Deze afbeelding is momenteel in gebruik door de volgende functies:", + "copy": "Kopieer", + "download": "Download", + "setCurrentImage": "Stel in als huidige afbeelding" }, "hotkeys": { "keyboardShortcuts": "Sneltoetsen", @@ -332,7 +353,7 @@ "config": "Configuratie", "configValidationMsg": "Pad naar het configuratiebestand van je model.", "modelLocation": "Locatie model", - "modelLocationValidationMsg": "Pad naar waar je model zich bevindt.", + "modelLocationValidationMsg": "Geef het pad naar een lokale map waar je Diffusers-model wordt bewaard", "vaeLocation": "Locatie VAE", "vaeLocationValidationMsg": "Pad naar waar je VAE zich bevindt.", "width": "Breedte", @@ -444,7 +465,17 @@ "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.", "loraModels": "LoRA's", "onnxModels": "Onnx", - "oliveModels": "Olives" + "oliveModels": "Olives", + "noModels": "Geen modellen gevonden", + "predictionType": "Soort voorspelling (voor Stable Diffusion 2.x-modellen en incidentele Stable Diffusion 1.x-modellen)", + "quickAdd": "Voeg snel toe", + "simpleModelDesc": "Geef een pad naar een lokaal Diffusers-model, lokale-checkpoint- / safetensors-model, een HuggingFace-repo-ID of een url naar een checkpoint- / Diffusers-model.", + "advanced": "Uitgebreid", + "useCustomConfig": "Gebruik eigen configuratie", + "closeAdvanced": "Sluit uitgebreid", + "modelType": "Soort model", + "customConfigFileLocation": "Locatie eigen configuratiebestand", + "vaePrecision": "Nauwkeurigheid VAE" }, "parameters": { "images": "Afbeeldingen", @@ -465,7 +496,7 @@ "type": "Soort", "strength": "Sterkte", "upscaling": "Opschalen", - "upscale": "Schaal op", + "upscale": "Vergroot (Shift + U)", "upscaleImage": "Schaal afbeelding op", "scale": "Schaal", "otherOptions": "Andere opties", @@ -496,7 +527,7 @@ "useInitImg": "Gebruik initiĆ«le afbeelding", "info": "Info", "initialImage": "InitiĆ«le afbeelding", - "showOptionsPanel": "Toon deelscherm Opties", + "showOptionsPanel": "Toon deelscherm Opties (O of T)", "symmetry": "Symmetrie", "hSymmetryStep": "Stap horiz. symmetrie", "vSymmetryStep": "Stap vert. symmetrie", @@ -504,7 +535,8 @@ "immediate": "Annuleer direct", "isScheduled": "Annuleren", "setType": "Stel annuleervorm in", - "schedule": "Annuleer na huidige iteratie" + "schedule": "Annuleer na huidige iteratie", + "cancel": "Annuleer" }, "general": "Algemeen", "copyImage": "Kopieer afbeelding", @@ -520,7 +552,7 @@ "boundingBoxWidth": "Tekenvak breedte", "boundingBoxHeight": "Tekenvak hoogte", "clipSkip": "Overslaan CLIP", - "aspectRatio": "Verhouding", + "aspectRatio": "Beeldverhouding", "negativePromptPlaceholder": "Negatieve prompt", "controlNetControlMode": "Aansturingsmodus", "positivePromptPlaceholder": "Positieve prompt", @@ -532,7 +564,46 @@ "coherenceSteps": "Stappen", "coherenceStrength": "Sterkte", "seamHighThreshold": "Hoog", - "seamLowThreshold": "Laag" + "seamLowThreshold": "Laag", + "invoke": { + "noNodesInGraph": "Geen knooppunten in graaf", + "noModelSelected": "Geen model ingesteld", + "invoke": "Start", + "noPrompts": "Geen prompts gegenereerd", + "systemBusy": "Systeem is bezig", + "noInitialImageSelected": "Geen initiĆ«le afbeelding gekozen", + "missingInputForField": "{{nodeLabel}} -> {{fieldLabel}} invoer ontbreekt", + "noControlImageForControlAdapter": "Controle-adapter #{{number}} heeft geen controle-afbeelding", + "noModelForControlAdapter": "Control-adapter #{{number}} heeft geen model ingesteld staan.", + "unableToInvoke": "Kan niet starten", + "incompatibleBaseModelForControlAdapter": "Model van controle-adapter #{{number}} is ongeldig in combinatie met het hoofdmodel.", + "systemDisconnected": "Systeem is niet verbonden", + "missingNodeTemplate": "Knooppuntsjabloon ontbreekt", + "readyToInvoke": "Klaar om te starten", + "missingFieldTemplate": "Veldsjabloon ontbreekt", + "addingImagesTo": "Bezig met toevoegen van afbeeldingen aan" + }, + "seamlessX&Y": "Naadloos X en Y", + "isAllowedToUpscale": { + "useX2Model": "Afbeelding is te groot om te vergroten met het x4-model. Gebruik hiervoor het x2-model", + "tooLarge": "Afbeelding is te groot om te vergoten. Kies een kleinere afbeelding" + }, + "aspectRatioFree": "Vrij", + "cpuNoise": "CPU-ruis", + "patchmatchDownScaleSize": "Verklein", + "gpuNoise": "GPU-ruis", + "seamlessX": "Naadloos X", + "useCpuNoise": "Gebruik CPU-ruis", + "clipSkipWithLayerCount": "Overslaan CLIP {{layerCount}}", + "seamlessY": "Naadloos Y", + "manualSeed": "Handmatige seedwaarde", + "imageActions": "Afbeeldingshandeling", + "randomSeed": "Willekeurige seedwaarde", + "iterations": "Iteraties", + "iterationsWithCount_one": "{{count}} iteratie", + "iterationsWithCount_other": "{{count}} iteraties", + "enableNoiseSettings": "Schakel ruisinstellingen in", + "coherenceMode": "Modus" }, "settings": { "models": "Modellen", @@ -561,7 +632,16 @@ "experimental": "Experimenteel", "alternateCanvasLayout": "Omwisselen Canvas Layout", "enableNodesEditor": "Knopen Editor Inschakelen", - "autoChangeDimensions": "Werk bij wijziging afmetingen bij naar modelstandaard" + "autoChangeDimensions": "Werk bij wijziging afmetingen bij naar modelstandaard", + "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.", + "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.", + "intermediatesClearedFailed": "Fout bij wissen van tussentijdse afbeeldingen" }, "toast": { "tempFoldersEmptied": "Tijdelijke map geleegd", @@ -610,7 +690,42 @@ "nodesCorruptedGraph": "Kan niet laden. Graph lijkt corrupt.", "nodesUnrecognizedTypes": "Laden mislukt. Graph heeft onherkenbare types", "nodesBrokenConnections": "Laden mislukt. Sommige verbindingen zijn verbroken.", - "nodesNotValidGraph": "Geen geldige knooppunten graph" + "nodesNotValidGraph": "Geen geldige knooppunten graph", + "baseModelChangedCleared_one": "Basismodel is gewijzigd: {{count}} niet-compatibel submodel weggehaald of uitgeschakeld", + "baseModelChangedCleared_other": "Basismodel is gewijzigd: {{count}} niet-compatibele submodellen weggehaald of uitgeschakeld", + "imageSavingFailed": "Fout bij bewaren afbeelding", + "canvasSentControlnetAssets": "Canvas gestuurd naar ControlNet en Assets", + "problemCopyingCanvasDesc": "Kan basislaag niet exporteren", + "loadedWithWarnings": "Werkstroom geladen met waarschuwingen", + "setInitialImage": "Ingesteld als initiĆ«le afbeelding", + "canvasCopiedClipboard": "Canvas gekopieerd naar klembord", + "setControlImage": "Ingesteld als controle-afbeelding", + "setNodeField": "Ingesteld als knooppuntveld", + "problemSavingMask": "Fout bij bewaren masker", + "problemSavingCanvasDesc": "Kan basislaag niet exporteren", + "maskSavedAssets": "Masker bewaard in Assets", + "modelAddFailed": "Fout bij toevoegen model", + "problemDownloadingCanvas": "Fout bij downloaden van canvas", + "problemMergingCanvas": "Fout bij samenvoegen canvas", + "setCanvasInitialImage": "Ingesteld als initiĆ«le canvasafbeelding", + "imageUploaded": "Afbeelding geĆ¼pload", + "addedToBoard": "Toegevoegd aan bord", + "workflowLoaded": "Werkstroom geladen", + "modelAddedSimple": "Model toegevoegd", + "problemImportingMaskDesc": "Kan masker niet exporteren", + "problemCopyingCanvas": "Fout bij kopiĆ«ren canvas", + "problemSavingCanvas": "Fout bij bewaren canvas", + "canvasDownloaded": "Canvas gedownload", + "setIPAdapterImage": "Ingesteld als IP-adapterafbeelding", + "problemMergingCanvasDesc": "Kan basislaag niet exporteren", + "problemDownloadingCanvasDesc": "Kan basislaag niet exporteren", + "problemSavingMaskDesc": "Kan masker niet exporteren", + "imageSaved": "Afbeelding bewaard", + "maskSentControlnetAssets": "Masker gestuurd naar ControlNet en Assets", + "canvasSavedGallery": "Canvas bewaard in galerij", + "imageUploadFailed": "Fout bij uploaden afbeelding", + "modelAdded": "Model toegevoegd: {{modelName}}", + "problemImportingMask": "Fout bij importeren masker" }, "tooltip": { "feature": { @@ -685,7 +800,9 @@ "betaDarkenOutside": "Verduister buiten tekenvak", "betaLimitToBox": "Beperk tot tekenvak", "betaPreserveMasked": "Behoud masker", - "antialiasing": "Anti-aliasing" + "antialiasing": "Anti-aliasing", + "showResultsOn": "Toon resultaten (aan)", + "showResultsOff": "Toon resultaten (uit)" }, "accessibility": { "exitViewer": "Stop viewer", @@ -707,7 +824,9 @@ "toggleAutoscroll": "Autom. scrollen aan/uit", "toggleLogViewer": "Logboekviewer aan/uit", "showOptionsPanel": "Toon zijscherm", - "menu": "Menu" + "menu": "Menu", + "showGalleryPanel": "Toon deelscherm Galerij", + "loadMore": "Laad meer" }, "ui": { "showProgressImages": "Toon voortgangsafbeeldingen", @@ -730,6 +849,661 @@ "resetWorkflow": "Herstel werkstroom", "resetWorkflowDesc": "Weet je zeker dat je deze werkstroom wilt herstellen?", "resetWorkflowDesc2": "Herstel van een werkstroom haalt alle knooppunten, randen en werkstroomdetails weg.", - "downloadWorkflow": "Download JSON van werkstroom" + "downloadWorkflow": "Download JSON van werkstroom", + "booleanPolymorphicDescription": "Een verzameling Booleanse waarden.", + "scheduler": "Planner", + "inputField": "Invoerveld", + "controlFieldDescription": "Controlegegevens doorgegeven tussen knooppunten.", + "skippingUnknownOutputType": "Overslaan van onbekend soort uitvoerveld", + "latentsFieldDescription": "Latents kunnen worden doorgegeven tussen knooppunten.", + "denoiseMaskFieldDescription": "Ontruisingsmasker kan worden doorgegeven tussen knooppunten", + "floatCollectionDescription": "Een verzameling zwevende-kommagetallen.", + "missingTemplate": "Ontbrekende sjabloon", + "outputSchemaNotFound": "Uitvoerschema niet gevonden", + "ipAdapterPolymorphicDescription": "Een verzameling IP-adapters.", + "workflowDescription": "Korte beschrijving", + "latentsPolymorphicDescription": "Latents kunnen worden doorgegeven tussen knooppunten.", + "colorFieldDescription": "Een RGBA-kleur.", + "mainModelField": "Model", + "unhandledInputProperty": "Onverwerkt invoerkenmerk", + "versionUnknown": " Versie onbekend", + "ipAdapterCollection": "Verzameling IP-adapters", + "conditioningCollection": "Verzameling conditionering", + "maybeIncompatible": "Is mogelijk niet compatibel met geĆÆnstalleerde knooppunten", + "ipAdapterPolymorphic": "Polymorfisme IP-adapter", + "noNodeSelected": "Geen knooppunt gekozen", + "addNode": "Voeg knooppunt toe", + "unableToValidateWorkflow": "Kan werkstroom niet valideren", + "enum": "Enumeratie", + "integerPolymorphicDescription": "Een verzameling gehele getallen.", + "noOutputRecorded": "Geen uitvoer opgenomen", + "updateApp": "Werk app bij", + "conditioningCollectionDescription": "Conditionering kan worden doorgegeven tussen knooppunten.", + "colorPolymorphic": "Polymorfisme kleur", + "colorCodeEdgesHelp": "Kleurgecodeerde randen op basis van hun verbonden velden", + "collectionDescription": "Beschrijving", + "float": "Zwevende-kommagetal", + "workflowContact": "Contactpersoon", + "skippingReservedFieldType": "Overslaan van gereserveerd veldsoort", + "animatedEdges": "Geanimeerde randen", + "booleanCollectionDescription": "Een verzameling van Booleanse waarden.", + "sDXLMainModelFieldDescription": "SDXL-modelveld.", + "conditioningPolymorphic": "Polymorfisme conditionering", + "integer": "Geheel getal", + "colorField": "Kleur", + "boardField": "Bord", + "nodeTemplate": "Sjabloon knooppunt", + "latentsCollection": "Verzameling latents", + "problemReadingWorkflow": "Fout bij lezen van werkstroom uit afbeelding", + "sourceNode": "Bronknooppunt", + "nodeOpacity": "Dekking knooppunt", + "pickOne": "Kies er een", + "collectionItemDescription": "Beschrijving", + "integerDescription": "Gehele getallen zijn getallen zonder een decimaalteken.", + "outputField": "Uitvoerveld", + "unableToLoadWorkflow": "Kan werkstroom niet valideren", + "snapToGrid": "Lijn uit op raster", + "stringPolymorphic": "Polymorfisme tekenreeks", + "conditioningPolymorphicDescription": "Conditionering kan worden doorgegeven tussen knooppunten.", + "noFieldsLinearview": "Geen velden toegevoegd aan lineaire weergave", + "skipped": "Overgeslagen", + "imagePolymorphic": "Polymorfisme afbeelding", + "nodeSearch": "Zoek naar knooppunten", + "updateNode": "Werk knooppunt bij", + "sDXLRefinerModelFieldDescription": "Beschrijving", + "imagePolymorphicDescription": "Een verzameling afbeeldingen.", + "floatPolymorphic": "Polymorfisme zwevende-kommagetal", + "version": "Versie", + "doesNotExist": "bestaat niet", + "ipAdapterCollectionDescription": "Een verzameling van IP-adapters.", + "stringCollectionDescription": "Een verzameling tekenreeksen.", + "unableToParseNode": "Kan knooppunt niet inlezen", + "controlCollection": "Controle-verzameling", + "validateConnections": "Valideer verbindingen en graaf", + "stringCollection": "Verzameling tekenreeksen", + "inputMayOnlyHaveOneConnection": "Invoer mag slechts een enkele verbinding hebben", + "notes": "Opmerkingen", + "uNetField": "UNet", + "nodeOutputs": "Uitvoer knooppunt", + "currentImageDescription": "Toont de huidige afbeelding in de knooppunteditor", + "validateConnectionsHelp": "Voorkom dat er ongeldige verbindingen worden gelegd en dat er ongeldige grafen worden aangeroepen", + "problemSettingTitle": "Fout bij instellen titel", + "ipAdapter": "IP-adapter", + "integerCollection": "Verzameling gehele getallen", + "collectionItem": "Verzamelingsonderdeel", + "noConnectionInProgress": "Geen verbinding bezig te maken", + "vaeModelField": "VAE", + "controlCollectionDescription": "Controlegegevens doorgegeven tussen knooppunten.", + "skippedReservedInput": "Overgeslagen gereserveerd invoerveld", + "workflowVersion": "Versie", + "noConnectionData": "Geen verbindingsgegevens", + "outputFields": "Uitvoervelden", + "fieldTypesMustMatch": "Veldsoorten moeten overeenkomen", + "workflow": "Werkstroom", + "edge": "Rand", + "inputNode": "Invoerknooppunt", + "enumDescription": "Enumeraties zijn waarden die uit een aantal opties moeten worden gekozen.", + "unkownInvocation": "Onbekende aanroepsoort", + "loRAModelFieldDescription": "Beschrijving", + "imageField": "Afbeelding", + "skippedReservedOutput": "Overgeslagen gereserveerd uitvoerveld", + "animatedEdgesHelp": "Animeer gekozen randen en randen verbonden met de gekozen knooppunten", + "cannotDuplicateConnection": "Kan geen dubbele verbindingen maken", + "booleanPolymorphic": "Polymorfisme Booleaanse waarden", + "unknownTemplate": "Onbekend sjabloon", + "noWorkflow": "Geen werkstroom", + "removeLinearView": "Verwijder uit lineaire weergave", + "colorCollectionDescription": "Beschrijving", + "integerCollectionDescription": "Een verzameling gehele getallen.", + "colorPolymorphicDescription": "Een verzameling kleuren.", + "sDXLMainModelField": "SDXL-model", + "workflowTags": "Labels", + "denoiseMaskField": "Ontruisingsmasker", + "schedulerDescription": "Beschrijving", + "missingCanvaInitImage": "Ontbrekende initialisatie-afbeelding voor canvas", + "conditioningFieldDescription": "Conditionering kan worden doorgegeven tussen knooppunten.", + "clipFieldDescription": "Submodellen voor tokenizer en text_encoder.", + "fullyContainNodesHelp": "Knooppunten moeten zich volledig binnen het keuzevak bevinden om te worden gekozen", + "noImageFoundState": "Geen initiĆ«le afbeelding gevonden in de staat", + "workflowValidation": "Validatiefout werkstroom", + "clipField": "Clip", + "stringDescription": "Tekenreeksen zijn tekst.", + "nodeType": "Soort knooppunt", + "noMatchingNodes": "Geen overeenkomende knooppunten", + "fullyContainNodes": "Omvat knooppunten volledig om ze te kiezen", + "integerPolymorphic": "Polymorfisme geheel getal", + "executionStateInProgress": "Bezig", + "noFieldType": "Geen soort veld", + "colorCollection": "Een verzameling kleuren.", + "executionStateError": "Fout", + "noOutputSchemaName": "Geen naam voor uitvoerschema gevonden in referentieobject", + "ipAdapterModel": "Model IP-adapter", + "latentsPolymorphic": "Polymorfisme latents", + "vaeModelFieldDescription": "Beschrijving", + "skippingInputNoTemplate": "Overslaan van invoerveld zonder sjabloon", + "ipAdapterDescription": "Een Afbeeldingsprompt-adapter (IP-adapter).", + "boolean": "Booleaanse waarden", + "missingCanvaInitMaskImages": "Ontbrekende initialisatie- en maskerafbeeldingen voor canvas", + "problemReadingMetadata": "Fout bij lezen van metagegevens uit afbeelding", + "stringPolymorphicDescription": "Een verzameling tekenreeksen.", + "oNNXModelField": "ONNX-model", + "executionStateCompleted": "Voltooid", + "node": "Knooppunt", + "skippingUnknownInputType": "Overslaan van onbekend soort invoerveld", + "workflowAuthor": "Auteur", + "currentImage": "Huidige afbeelding", + "controlField": "Controle", + "workflowName": "Naam", + "booleanDescription": "Booleanse waarden zijn waar en onwaar.", + "collection": "Verzameling", + "ipAdapterModelDescription": "Modelveld IP-adapter", + "cannotConnectInputToInput": "Kan invoer niet aan invoer verbinden", + "invalidOutputSchema": "Ongeldig uitvoerschema", + "boardFieldDescription": "Een galerijbord", + "floatDescription": "Zwevende-kommagetallen zijn getallen met een decimaalteken.", + "floatPolymorphicDescription": "Een verzameling zwevende-kommagetallen.", + "vaeField": "Vae", + "conditioningField": "Conditionering", + "unhandledOutputProperty": "Onverwerkt uitvoerkenmerk", + "workflowNotes": "Opmerkingen", + "string": "Tekenreeks", + "floatCollection": "Verzameling zwevende-kommagetallen", + "latentsField": "Latents", + "cannotConnectOutputToOutput": "Kan uitvoer niet aan uitvoer verbinden", + "booleanCollection": "Verzameling Booleaanse waarden", + "connectionWouldCreateCycle": "Verbinding zou cyclisch worden", + "cannotConnectToSelf": "Kan niet aan zichzelf verbinden", + "notesDescription": "Voeg opmerkingen toe aan je werkstroom", + "unknownField": "Onbekend veld", + "inputFields": "Invoervelden", + "colorCodeEdges": "Kleurgecodeerde randen", + "uNetFieldDescription": "UNet-submodel.", + "unknownNode": "Onbekend knooppunt", + "imageCollectionDescription": "Een verzameling afbeeldingen.", + "mismatchedVersion": "Heeft niet-overeenkomende versie", + "vaeFieldDescription": "Vae-submodel.", + "imageFieldDescription": "Afbeeldingen kunnen worden doorgegeven tussen knooppunten.", + "outputNode": "Uitvoerknooppunt", + "addNodeToolTip": "Voeg knooppunt toe (Shift+A, spatie)", + "loadingNodes": "Bezig met laden van knooppunten...", + "snapToGridHelp": "Lijn knooppunten uit op raster bij verplaatsing", + "workflowSettings": "Instellingen werkstroomeditor", + "mainModelFieldDescription": "Beschrijving", + "sDXLRefinerModelField": "Verfijningsmodel", + "loRAModelField": "LoRA", + "unableToParseEdge": "Kan rand niet inlezen", + "latentsCollectionDescription": "Latents kunnen worden doorgegeven tussen knooppunten.", + "oNNXModelFieldDescription": "ONNX-modelveld.", + "imageCollection": "Afbeeldingsverzameling" + }, + "controlnet": { + "amult": "a_mult", + "resize": "Schaal", + "showAdvanced": "Toon uitgebreid", + "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", + "normalBae": "Normale BAE", + "importMaskFromCanvas": "Importeer masker uit canvas", + "hed": "HED", + "hideAdvanced": "Verberg uitgebreid", + "contentShuffle": "Verschuif materiaal", + "controlNetEnabledT2IDisabled": "$t(common.controlNet) ingeschakeld, $t(common.t2iAdapter)s uitgeschakeld", + "ipAdapterModel": "Adaptermodel", + "resetControlImage": "Zet controle-afbeelding terug", + "beginEndStepPercent": "Percentage begin-/eindstap", + "mlsdDescription": "Minimalistische herkenning lijnsegmenten", + "duplicate": "Maak kopie", + "balanced": "Gebalanceerd", + "f": "F", + "h": "H", + "prompt": "Prompt", + "depthMidasDescription": "Generatie van diepteblad via Midas", + "controlnet": "$t(controlnet.controlAdapter) #{{number}} ($t(common.controlNet))", + "openPoseDescription": "Menselijke pose-benadering via Openpose", + "control": "Controle", + "resizeMode": "Modus schaling", + "t2iEnabledControlNetDisabled": "$t(common.t2iAdapter) ingeschakeld, $t(common.controlNet)s uitgeschakeld", + "coarse": "Grof", + "weight": "Gewicht", + "selectModel": "Kies een model", + "crop": "Snij bij", + "depthMidas": "Diepte (Midas)", + "w": "B", + "processor": "Verwerker", + "addControlNet": "Voeg $t(common.controlNet) toe", + "none": "Geen", + "incompatibleBaseModel": "Niet-compatibel basismodel:", + "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))", + "pidiDescription": "PIDI-afbeeldingsverwerking", + "mediapipeFace": "Mediapipe - Gezicht", + "mlsd": "M-LSD", + "controlMode": "Controlemodus", + "fill": "Vul", + "cannyDescription": "Herkenning Canny-rand", + "addIPAdapter": "Voeg $t(common.ipAdapter) toe", + "lineart": "Lineart", + "colorMapDescription": "Genereert een kleurenblad van de afbeelding", + "lineartAnimeDescription": "Lineartverwerking in anime-stijl", + "t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.t2iAdapter))", + "minConfidence": "Min. vertrouwensniveau", + "imageResolution": "Resolutie afbeelding", + "megaControl": "Zeer veel controle", + "depthZoe": "Diepte (Zoe)", + "colorMap": "Kleur", + "lowThreshold": "Lage drempelwaarde", + "autoConfigure": "Configureer verwerker automatisch", + "highThreshold": "Hoge drempelwaarde", + "normalBaeDescription": "Normale BAE-verwerking", + "noneDescription": "Geen verwerking toegepast", + "saveControlImage": "Bewaar controle-afbeelding", + "openPose": "Openpose", + "toggleControlNet": "Zet deze ControlNet aan/uit", + "delete": "Verwijder", + "controlAdapter_one": "Control-adapter", + "controlAdapter_other": "Control-adapters", + "safe": "Veilig", + "colorMapTileSize": "Grootte tegel", + "lineartAnime": "Lineart-anime", + "ipAdapterImageFallback": "Geen IP-adapterafbeelding gekozen", + "mediapipeFaceDescription": "Gezichtsherkenning met Mediapipe", + "canny": "Canny", + "depthZoeDescription": "Generatie van 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", + "handAndFace": "Hand en gezicht", + "enableIPAdapter": "Schakel IP-adapter in", + "maxFaces": "Max. gezichten" + }, + "dynamicPrompts": { + "seedBehaviour": { + "perPromptDesc": "Gebruik een verschillende seedwaarde per afbeelding", + "perIterationLabel": "Seedwaarde per iteratie", + "perIterationDesc": "Gebruik een verschillende seedwaarde per iteratie", + "perPromptLabel": "Seedwaarde per afbeelding", + "label": "Gedrag seedwaarde" + }, + "enableDynamicPrompts": "Schakel dynamische prompts in", + "combinatorial": "Combinatorische generatie", + "maxPrompts": "Max. prompts", + "promptsWithCount_one": "{{count}} prompt", + "promptsWithCount_other": "{{count}} prompts", + "dynamicPrompts": "Dynamische prompts" + }, + "popovers": { + "noiseUseCPU": { + "paragraphs": [ + "Bestuurt 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." + ], + "heading": "Gebruik CPU-ruis" + }, + "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." + ], + "heading": "Planner" + }, + "scaleBeforeProcessing": { + "paragraphs": [ + "Schaalt het gekozen gebied naar de grootte die het meest geschikt is voor het model, vooraf aan het proces van het afbeeldingen genereren." + ], + "heading": "Schaal vooraf aan verwerking" + }, + "compositingMaskAdjustments": { + "heading": "Aanpassingen masker", + "paragraphs": [ + "Pas het masker aan." + ] + }, + "paramRatio": { + "heading": "Beeldverhouding", + "paragraphs": [ + "De beeldverhouding van de afmetingen van de afbeelding die wordt gegenereerd.", + "Een afbeeldingsgrootte (in aantal pixels) equivalent aan 512x512 wordt aanbevolen voor SD1.5-modellen. Een grootte-equivalent van 1024x1024 wordt aanbevolen voor SDXL-modellen." + ] + }, + "compositingCoherenceSteps": { + "heading": "Stappen", + "paragraphs": [ + "Het aantal te gebruiken ontruisingsstappen in de coherentiefase.", + "Gelijk aan de hoofdparameter Stappen." + ] + }, + "dynamicPrompts": { + "paragraphs": [ + "Dynamische prompts vormt een enkele prompt om in vele.", + "De basissyntax is \"a {red|green|blue} ball\". Dit zal de volgende drie prompts geven: \"a red ball\", \"a green ball\" en \"a blue ball\".", + "Gebruik de syntax zo vaak als je wilt in een enkele prompt, maar zorg ervoor dat het aantal gegenereerde prompts in lijn ligt met de instelling Max. prompts." + ], + "heading": "Dynamische prompts" + }, + "paramVAE": { + "paragraphs": [ + "Het model gebruikt voor het vertalen van AI-uitvoer naar de uiteindelijke afbeelding." + ], + "heading": "VAE" + }, + "compositingBlur": { + "heading": "Vervaging", + "paragraphs": [ + "De vervagingsstraal van het masker." + ] + }, + "paramIterations": { + "paragraphs": [ + "Het aantal te genereren afbeeldingen.", + "Als dynamische prompts is ingeschakeld, dan zal elke prompt dit aantal keer gegenereerd worden." + ], + "heading": "Iteraties" + }, + "paramVAEPrecision": { + "heading": "Nauwkeurigheid VAE", + "paragraphs": [ + "De nauwkeurigheid gebruikt tijdens de VAE-codering en -decodering. FP16/halve nauwkeurig is efficiĆ«nter, ten koste van kleine afbeeldingsvariaties." + ] + }, + "compositingCoherenceMode": { + "heading": "Modus", + "paragraphs": [ + "De modus van de coherentiefase." + ] + }, + "paramSeed": { + "paragraphs": [ + "Bestuurt de startruis die gebruikt wordt bij het genereren.", + "Schakel \"Willekeurige seedwaarde\" uit om identieke resultaten te krijgen met dezelfde generatie-instellingen." + ], + "heading": "Seedwaarde" + }, + "controlNetResizeMode": { + "heading": "Schaalmodus", + "paragraphs": [ + "Hoe de ControlNet-afbeelding zal worden geschaald aan de uitvoergrootte van de afbeelding." + ] + }, + "controlNetBeginEnd": { + "paragraphs": [ + "Op welke stappen van het ontruisingsproces ControlNet worden toegepast.", + "ControlNets die worden toegepast aan het begin begeleiden het compositieproces. ControlNets die worden toegepast aan het eind zorgen voor details." + ], + "heading": "Percentage begin- / eindstap" + }, + "dynamicPromptsSeedBehaviour": { + "paragraphs": [ + "Bestuurt 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." + ], + "heading": "Gedrag seedwaarde" + }, + "clipSkip": { + "paragraphs": [ + "Kies hoeveel CLIP-modellagen je wilt overslaan.", + "Bepaalde modellen werken beter met bepaalde Overslaan CLIP-instellingen.", + "Een hogere waarde geeft meestal een minder gedetailleerde afbeelding." + ], + "heading": "Overslaan CLIP" + }, + "paramModel": { + "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." + ] + }, + "compositingCoherencePass": { + "heading": "Coherentiefase", + "paragraphs": [ + "Een tweede ronde ontruising helpt bij het samenstellen van de erin- of eruitgetekende afbeelding." + ] + }, + "paramDenoisingStrength": { + "paragraphs": [ + "Hoeveel ruis wordt toegevoegd aan de invoerafbeelding.", + "0 geeft een identieke afbeelding, waarbij 1 een volledig nieuwe afbeelding geeft." + ], + "heading": "Ontruisingssterkte" + }, + "compositingStrength": { + "heading": "Sterkte", + "paragraphs": [ + "Ontruisingssterkte voor de coherentiefase.", + "Gelijk aan de parameter Ontruisingssterkte Afbeelding naar afbeelding." + ] + }, + "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.", + "Ondersteunt Compel-syntax en -embeddingen." + ], + "heading": "Negatieve prompt" + }, + "compositingBlurMethod": { + "heading": "Vervagingsmethode", + "paragraphs": [ + "De methode van de vervaging die wordt toegepast op het gemaskeerd gebied." + ] + }, + "dynamicPromptsMaxPrompts": { + "heading": "Max. prompts", + "paragraphs": [ + "Beperkt het aantal prompts die kunnen worden gegenereerd door dynamische prompts." + ] + }, + "infillMethod": { + "paragraphs": [ + "Methode om een gekozen gebied in te vullen." + ], + "heading": "Invulmethode" + }, + "controlNetWeight": { + "heading": "Gewicht", + "paragraphs": [ + "Hoe sterk ControlNet effect heeft op de gegeneerde afbeelding." + ] + }, + "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." + ] + }, + "paramCFGScale": { + "heading": "CFG-schaal", + "paragraphs": [ + "Bestuurt hoeveel je prompt invloed heeft op het generatieproces." + ] + }, + "controlNetControlMode": { + "paragraphs": [ + "Geeft meer gewicht aan ofwel de prompt danwel ControlNet." + ], + "heading": "Controlemodus" + }, + "paramSteps": { + "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." + ] + }, + "paramPositiveConditioning": { + "heading": "Positieve prompt", + "paragraphs": [ + "Begeleidt het generartieproces. Gebruik een woord of frase naar keuze.", + "Syntaxes en embeddings voor Compel en dynamische prompts." + ] + }, + "lora": { + "heading": "Gewicht LoRA", + "paragraphs": [ + "Een hogere LoRA-gewicht zal leiden tot een groter effect op de uiteindelijke afbeelding." + ] + } + }, + "metadata": { + "seamless": "Naadloos", + "positivePrompt": "Positieve prompt", + "negativePrompt": "Negatieve prompt", + "generationMode": "Generatiemodus", + "Threshold": "Drempelwaarde ruis", + "metadata": "Metagegevens", + "strength": "Sterkte Afbeelding naar afbeelding", + "seed": "Seedwaarde", + "imageDetails": "Afbeeldingsdetails", + "perlin": "Perlin-ruis", + "model": "Model", + "noImageDetails": "Geen afbeeldingsdetails gevonden", + "hiresFix": "Optimalisatie voor hoge resolutie", + "cfgScale": "CFG-schaal", + "fit": "Schaal aanpassen in Afbeelding naar afbeelding", + "initImage": "InitiĆ«le afbeelding", + "recallParameters": "Opnieuw aan te roepen parameters", + "height": "Hoogte", + "variations": "Paren seedwaarde-gewicht", + "noMetaData": "Geen metagegevens gevonden", + "width": "Breedte", + "createdBy": "Gemaakt door", + "workflow": "Werkstroom", + "steps": "Stappen", + "scheduler": "Planner", + "noRecallParameters": "Geen opnieuw uit te voeren parameters gevonden" + }, + "queue": { + "status": "Status", + "pruneSucceeded": "{{item_count}} voltooide onderdelen uit wachtrij gesnoeid", + "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", + "batchFailedToQueue": "Fout bij reeks in wachtrij plaatsen", + "completed": "Voltooid", + "queueBack": "Voeg toe aan wachtrij", + "batchValues": "Reekswaarden", + "cancelFailed": "Fout bij annuleren onderdeel", + "queueCountPrediction": "Voeg {{predicted}} toe aan wachtrij", + "batchQueued": "Reeks in wachtrij geplaatst", + "pauseFailed": "Fout bij onderbreken verwerker", + "clearFailed": "Fout bij wissen van wachtrij", + "queuedCount": "{{pending}} wachtend", + "front": "begin", + "clearSucceeded": "Wachtrij gewist", + "pause": "Onderbreek", + "pruneTooltip": "Snoei {{item_count}} voltooide onderdelen", + "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.", + "pending": "Wachtend", + "completedIn": "Voltooid na", + "resumeFailed": "Fout bij hervatten verwerker", + "clear": "Wis", + "prune": "Snoei", + "total": "Totaal", + "canceled": "Geannuleerd", + "pruneFailed": "Fout bij snoeien van wachtrij", + "cancelBatchSucceeded": "Reeks geannuleerd", + "clearTooltip": "Annuleer en wis alle onderdelen", + "current": "Huidig", + "pauseTooltip": "Onderbreek verwerker", + "failed": "Mislukt", + "cancelItem": "Annuleer onderdeel", + "next": "Volgende", + "cancelBatch": "Annuleer reeks", + "back": "eind", + "cancel": "Annuleer", + "session": "Sessie", + "queueTotal": "Totaal {{total}}", + "resumeSucceeded": "Verwerker hervat", + "enqueueing": "Toevoegen van reeks aan wachtrij", + "resumeTooltip": "Hervat verwerker", + "queueMaxExceeded": "Max. aantal van {{max_queue_size}} overschreden, {{skip}} worden overgeslagen", + "resume": "Hervat", + "cancelBatchFailed": "Fout bij annuleren van reeks", + "clearQueueAlertDialog2": "Weet je zeker dat je de wachtrij wilt wissen?", + "item": "Onderdeel", + "graphFailedToQueue": "Fout bij toevoegen graaf aan wachtrij" + }, + "sdxl": { + "refinerStart": "Startwaarde verfijner", + "selectAModel": "Kies een model", + "scheduler": "Planner", + "cfgScale": "CFG-schaal", + "negStylePrompt": "Negatieve-stijlprompt", + "noModelsAvailable": "Geen modellen beschikbaar", + "refiner": "Verfijner", + "negAestheticScore": "Negatieve aantrekkelijkheidsscore", + "useRefiner": "Gebruik verfijner", + "denoisingStrength": "Sterkte ontruising", + "refinermodel": "Verfijnermodel", + "posAestheticScore": "Positieve aantrekkelijkheidsscore", + "concatPromptStyle": "Plak prompt- en stijltekst aan elkaar", + "loading": "Bezig met laden...", + "steps": "Stappen", + "posStylePrompt": "Positieve-stijlprompt" + }, + "models": { + "noMatchingModels": "Geen overeenkomend modellen", + "loading": "bezig met laden", + "noMatchingLoRAs": "Geen overeenkomende LoRA's", + "noLoRAsAvailable": "Geen LoRA's beschikbaar", + "noModelsAvailable": "Geen modellen beschikbaar", + "selectModel": "Kies een model", + "selectLoRA": "Kies een LoRA" + }, + "boards": { + "autoAddBoard": "Voeg automatisch bord toe", + "topMessage": "Dit bord bevat afbeeldingen die in gebruik zijn door de volgende functies:", + "move": "Verplaats", + "menuItemAutoAdd": "Voeg dit automatisch toe aan bord", + "myBoard": "Mijn bord", + "searchBoard": "Zoek borden...", + "noMatching": "Geen overeenkomende borden", + "selectBoard": "Kies een bord", + "cancel": "Annuleer", + "addBoard": "Voeg bord toe", + "bottomMessage": "Als je dit bord en alle afbeeldingen erop verwijdert, dan worden alle functies teruggezet die ervan gebruik maken.", + "uncategorized": "Zonder categorie", + "downloadBoard": "Download bord", + "changeBoard": "Wijzig bord", + "loading": "Bezig met laden...", + "clearSearch": "Maak zoekopdracht leeg" + }, + "invocationCache": { + "disable": "Schakel uit", + "misses": "Mislukt cacheverzoek", + "enableFailed": "Fout bij inschakelen aanroepcache", + "invocationCache": "Aanroepcache", + "clearSucceeded": "Aanroepcache gewist", + "enableSucceeded": "Aanroepcache ingeschakeld", + "clearFailed": "Fout bij wissen aanroepcache", + "hits": "Gelukt cacheverzoek", + "disableSucceeded": "Aanroepcache uitgeschakeld", + "disableFailed": "Fout bij uitschakelen aanroepcache", + "enable": "Schakel in", + "clear": "Wis", + "maxCacheSize": "Max. grootte cache", + "cacheSize": "Grootte cache" + }, + "embedding": { + "noMatchingEmbedding": "Geen overeenkomende embeddings", + "addEmbedding": "Voeg embedding toe", + "incompatibleModel": "Niet-compatibel basismodel:" } } diff --git a/invokeai/frontend/web/public/locales/zh_CN.json b/invokeai/frontend/web/public/locales/zh_CN.json index d91bf0b4bb..3f896076d4 100644 --- a/invokeai/frontend/web/public/locales/zh_CN.json +++ b/invokeai/frontend/web/public/locales/zh_CN.json @@ -88,7 +88,9 @@ "t2iAdapter": "T2I Adapter", "ipAdapter": "IP Adapter", "controlAdapter": "Control Adapter", - "controlNet": "ControlNet" + "controlNet": "ControlNet", + "on": "开", + "auto": "č‡ŖåŠØ" }, "gallery": { "generations": "ē”Ÿęˆēš„图像", @@ -472,7 +474,8 @@ "vae": "VAE", "oliveModels": "Olive", "loraModels": "LoRA", - "alpha": "Alpha" + "alpha": "Alpha", + "vaePrecision": "VAE ē²¾åŗ¦" }, "parameters": { "images": "图像", @@ -595,7 +598,11 @@ "useX2Model": "图像å¤Ŗ大ļ¼Œę— ę³•ä½æē”Ø x4 ęؔ型ļ¼Œä½æē”Ø x2 ęؔ型作äøŗę›æ代", "tooLarge": "图像å¤Ŗå¤§ę— ę³•čæ›č”Œę”¾å¤§ļ¼ŒčÆ·é€‰ę‹©ę›“å°ēš„图像" }, - "iterationsWithCount_other": "{{count}} ꬔčæ­ä»£ē”Ÿęˆ" + "iterationsWithCount_other": "{{count}} ꬔčæ­ä»£ē”Ÿęˆ", + "seamlessX&Y": "ꗠē¼ X & Y", + "aspectRatioFree": "č‡Ŗē”±", + "seamlessX": "ꗠē¼ X", + "seamlessY": "ꗠē¼ Y" }, "settings": { "models": "ęؔ型", @@ -628,10 +635,11 @@ "clearIntermediates": "ęø…除äø­é—“äŗ§ē‰©", "clearIntermediatesDesc3": "ę‚Ø图åŗ“äø­ēš„图像äøä¼šč¢«åˆ é™¤ć€‚", "clearIntermediatesDesc2": "äø­é—“äŗ§ē‰©å›¾åƒę˜Æē”Ÿęˆčæ‡ē؋äø­äŗ§ē”Ÿēš„å‰Æäŗ§å“ļ¼ŒäøŽå›¾åŗ“äø­ēš„ē»“ęžœå›¾åƒäøåŒć€‚ęø…除äø­é—“äŗ§ē‰©åÆé‡Šę”¾ē£ē›˜ē©ŗ闓怂", - "intermediatesCleared_other": "å·²ęø…除 {{number}} äøŖäø­é—“äŗ§ē‰©", + "intermediatesCleared_other": "å·²ęø…除 {{count}} äøŖäø­é—“äŗ§ē‰©", "clearIntermediatesDesc1": "ęø…除äø­é—“äŗ§ē‰©ä¼šé‡ē½®ę‚Øēš„ē”»åøƒå’Œ ControlNet ēŠ¶ę€ć€‚", "intermediatesClearedFailed": "ęø…除äø­é—“äŗ§ē‰©ę—¶å‡ŗēŽ°é—®é¢˜", - "noIntermediates": "ę²”ęœ‰åÆęø…除ēš„äø­é—“äŗ§ē‰©" + "clearIntermediatesWithCount_other": "ęø…除 {{count}} äøŖäø­é—“äŗ§ē‰©", + "clearIntermediatesDisabled": "队列äøŗē©ŗę‰čƒ½ęø…ē†äø­é—“äŗ§ē‰©" }, "toast": { "tempFoldersEmptied": "äø“ę—¶ę–‡ä»¶å¤¹å·²ęø…ē©ŗ", @@ -714,7 +722,7 @@ "canvasSavedGallery": "ē”»åøƒå·²äæå­˜åˆ°å›¾åŗ“", "imageUploadFailed": "图像äøŠä¼ å¤±č“„", "problemImportingMask": "åƼ兄遮ē½©ę—¶å‡ŗēŽ°é—®é¢˜", - "baseModelChangedCleared_other": "åŸŗē”€ęØ”åž‹å·²ę›“ę”¹, å·²ęø…é™¤ęˆ–ē¦ē”Ø {{number}} äøŖäøå…¼å®¹ēš„子ęؔ型" + "baseModelChangedCleared_other": "åŸŗē”€ęØ”åž‹å·²ę›“ę”¹, å·²ęø…é™¤ęˆ–ē¦ē”Ø {{count}} äøŖäøå…¼å®¹ēš„子ęؔ型" }, "unifiedCanvas": { "layer": "图层", @@ -1003,7 +1011,27 @@ "booleanCollection": "åøƒå°”值合集", "imageCollectionDescription": "äø€äøŖå›¾åƒåˆé›†ć€‚", "loRAModelField": "LoRA", - "imageCollection": "图像合集" + "imageCollection": "图像合集", + "ipAdapterPolymorphicDescription": "äø€äøŖ IP-Adapters Collection åˆé›†ć€‚", + "ipAdapterCollection": "IP-Adapters 合集", + "conditioningCollection": "ę”ä»¶åˆé›†", + "ipAdapterPolymorphic": "IP-Adapters å¤šę€", + "conditioningCollectionDescription": "ę”ä»¶åÆ仄åœØ节ē‚¹é—“ä¼ é€’ć€‚", + "colorPolymorphic": "é¢œč‰²å¤šę€", + "conditioningPolymorphic": "ę”ä»¶å¤šę€", + "latentsCollection": "Latents 合集", + "stringPolymorphic": "字ē¬¦å¤šę€", + "conditioningPolymorphicDescription": "ę”ä»¶åÆ仄åœØ节ē‚¹é—“ä¼ é€’ć€‚", + "imagePolymorphic": "å›¾åƒå¤šę€", + "floatPolymorphic": "ęµ®ē‚¹å¤šę€", + "ipAdapterCollectionDescription": "äø€äøŖ IP-Adapters Collection åˆé›†ć€‚", + "ipAdapter": "IP-Adapter", + "booleanPolymorphic": "åøƒå°”å¤šę€", + "conditioningFieldDescription": "ę”ä»¶åÆ仄åœØ节ē‚¹é—“ä¼ é€’ć€‚", + "integerPolymorphic": "ę•“ę•°å¤šę€", + "latentsPolymorphic": "Latents å¤šę€", + "conditioningField": "ę”ä»¶", + "latentsField": "Latents" }, "controlnet": { "resize": "ē›“ꎄē¼©ę”¾", @@ -1073,21 +1101,21 @@ "contentShuffle": "Content Shuffle", "f": "F", "h": "H", - "controlnet": "$t(controlnet.controlAdapter) #{{number}} ($t(common.controlNet))", + "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))", "control": "Control (ę™®é€šęŽ§åˆ¶)", "coarse": "Coarse", "depthMidas": "Depth (Midas)", "w": "W", - "ip_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.ipAdapter))", + "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))", "mediapipeFace": "Mediapipe Face", "mlsd": "M-LSD", "lineart": "Lineart", - "t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.t2iAdapter))", + "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))", "megaControl": "Mega Control (超ēŗ§ęŽ§åˆ¶)", "depthZoe": "Depth (Zoe)", "colorMap": "Color", "openPose": "Openpose", - "controlAdapter": "Control Adapter", + "controlAdapter_other": "Control Adapters", "lineartAnime": "Lineart Anime", "canny": "Canny" }, @@ -1141,7 +1169,7 @@ "queuedCount": "{{pending}} 待处ē†", "front": "前", "pruneTooltip": "äæ®å‰Ŗ {{item_count}} äøŖå·²å®Œęˆēš„锹ē›®", - "batchQueuedDesc": "åœØ队列ēš„ {{direction}} äø­ę·»åŠ äŗ† {{item_count}} äøŖ会čƝ", + "batchQueuedDesc_other": "åœØ队列ēš„ {{direction}} äø­ę·»åŠ äŗ† {{count}} äøŖ会čƝ", "graphQueued": "节ē‚¹å›¾å·²åŠ å…„队列", "back": "后", "session": "会čƝ", @@ -1192,7 +1220,9 @@ "steps": "ę­„ę•°", "scheduler": "调åŗ¦å™Ø", "seamless": "ꗠē¼", - "fit": "图ē”Ÿå›¾é€‚åŗ”" + "fit": "图ē”Ÿå›¾åŒ¹é…", + "recallParameters": "å¬å›žå‚ę•°", + "noRecallParameters": "ęœŖę‰¾åˆ°č¦å¬å›žēš„å‚ę•°" }, "models": { "noMatchingModels": "ꗠē›ø匹配ēš„ęؔ型", 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/canvasMerged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts index 62f7b60036..35c1affb97 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts @@ -44,7 +44,7 @@ export const addCanvasMergedListener = () => { } const baseLayerRect = canvasBaseLayer.getClientRect({ - relativeTo: canvasBaseLayer.getParent(), + relativeTo: canvasBaseLayer.getParent() ?? undefined, }); const imageDTO = await dispatch( 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/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts index 79a09c628f..bd5422841f 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts @@ -151,7 +151,9 @@ export const addRequestedSingleImageDeletionListener = () => { if (wasImageDeleted) { dispatch( - api.util.invalidateTags([{ type: 'Board', id: imageDTO.board_id }]) + api.util.invalidateTags([ + { type: 'Board', id: imageDTO.board_id ?? 'none' }, + ]) ); } }, diff --git a/invokeai/frontend/web/src/app/types/invokeai.ts b/invokeai/frontend/web/src/app/types/invokeai.ts index 8331e9c979..39e4ffd27a 100644 --- a/invokeai/frontend/web/src/app/types/invokeai.ts +++ b/invokeai/frontend/web/src/app/types/invokeai.ts @@ -39,7 +39,8 @@ export type SDFeature = | 'hires' | 'lora' | 'embedding' - | 'vae'; + | 'vae' + | 'hrf'; /** * Configuration options for the InvokeAI UI. @@ -110,6 +111,14 @@ export type AppConfig = { fineStep: number; coarseStep: number; }; + hrfStrength: { + initial: number; + min: number; + sliderMax: number; + inputMax: number; + fineStep: number; + coarseStep: number; + }; dynamicPrompts: { maxPrompts: { initial: number; diff --git a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts index f2398483bf..197f5f4068 100644 --- a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts +++ b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts @@ -2,6 +2,7 @@ import { PopoverProps } from '@chakra-ui/react'; export type Feature = | 'clipSkip' + | 'hrf' | 'paramNegativeConditioning' | 'paramPositiveConditioning' | 'paramScheduler' diff --git a/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx b/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx index 7c85b3557e..5ea17f788c 100644 --- a/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx +++ b/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx @@ -6,7 +6,7 @@ import { useMantineMultiSelectStyles } from 'mantine-theme/hooks/useMantineMulti import { KeyboardEvent, RefObject, memo, useCallback } from 'react'; type IAIMultiSelectProps = Omit & { - tooltip?: string; + tooltip?: string | null; inputRef?: RefObject; label?: string; }; diff --git a/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx b/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx index 39fe7ead3c..675314b421 100644 --- a/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx +++ b/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx @@ -12,7 +12,7 @@ export type IAISelectDataType = { }; type IAISelectProps = Omit & { - tooltip?: string; + tooltip?: string | null; label?: string; inputRef?: RefObject; }; diff --git a/invokeai/frontend/web/src/common/components/IAIMantineSelect.tsx b/invokeai/frontend/web/src/common/components/IAIMantineSelect.tsx index 8cc08d2304..9541015b65 100644 --- a/invokeai/frontend/web/src/common/components/IAIMantineSelect.tsx +++ b/invokeai/frontend/web/src/common/components/IAIMantineSelect.tsx @@ -10,7 +10,7 @@ export type IAISelectDataType = { }; export type IAISelectProps = Omit & { - tooltip?: string; + tooltip?: string | null; inputRef?: RefObject; label?: string; }; diff --git a/invokeai/frontend/web/src/common/hooks/useImage.ts b/invokeai/frontend/web/src/common/hooks/useImage.ts new file mode 100644 index 0000000000..60c973ce59 --- /dev/null +++ b/invokeai/frontend/web/src/common/hooks/useImage.ts @@ -0,0 +1,102 @@ +import { useLayoutEffect, useRef, useState } from 'react'; + +// Adapted from https://github.com/konvajs/use-image + +type CrossOrigin = 'anonymous' | 'use-credentials'; +type ReferrerPolicy = + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url'; +type ImageStatus = 'loaded' | 'loading' | 'failed'; + +export const useImage = ( + url: string, + crossOrigin?: CrossOrigin, + referrerpolicy?: ReferrerPolicy +): [undefined | HTMLImageElement, ImageStatus, Blob | null] => { + // lets use refs for image and status + // so we can update them during render + // to have instant update in status/image when new data comes in + const statusRef = useRef('loading'); + const imageRef = useRef(); + const blobRef = useRef(null); + + // we are not going to use token + // but we need to just to trigger state update + const [_, setStateToken] = useState(0); + + // keep track of old props to trigger changes + const oldUrl = useRef(); + const oldCrossOrigin = useRef(); + const oldReferrerPolicy = useRef(); + + if ( + oldUrl.current !== url || + oldCrossOrigin.current !== crossOrigin || + oldReferrerPolicy.current !== referrerpolicy + ) { + statusRef.current = 'loading'; + imageRef.current = undefined; + oldUrl.current = url; + oldCrossOrigin.current = crossOrigin; + oldReferrerPolicy.current = referrerpolicy; + } + + useLayoutEffect( + function () { + if (!url) { + return; + } + const img = document.createElement('img'); + + function onload() { + statusRef.current = 'loaded'; + imageRef.current = img; + const canvas = document.createElement('canvas'); + canvas.width = img.clientWidth; + canvas.height = img.clientHeight; + + const context = canvas.getContext('2d'); + if (context) { + context.drawImage(img, 0, 0); + canvas.toBlob(function (blob) { + blobRef.current = blob; + }, 'image/png'); + } + setStateToken(Math.random()); + } + + function onerror() { + statusRef.current = 'failed'; + imageRef.current = undefined; + setStateToken(Math.random()); + } + + img.addEventListener('load', onload); + img.addEventListener('error', onerror); + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + if (referrerpolicy) { + img.referrerPolicy = referrerpolicy; + } + img.src = url; + + return function cleanup() { + img.removeEventListener('load', onload); + img.removeEventListener('error', onerror); + }; + }, + [url, crossOrigin, referrerpolicy] + ); + + // return array because it is better to use in case of several useImage hooks + // const [background, backgroundStatus] = useImage(url1); + // const [patter] = useImage(url2); + return [imageRef.current, statusRef.current, blobRef.current]; +}; diff --git a/invokeai/frontend/web/src/common/hooks/useImageUrlToBlob.ts b/invokeai/frontend/web/src/common/hooks/useImageUrlToBlob.ts new file mode 100644 index 0000000000..77538a929d --- /dev/null +++ b/invokeai/frontend/web/src/common/hooks/useImageUrlToBlob.ts @@ -0,0 +1,40 @@ +import { useCallback } from 'react'; +import { $authToken } from 'services/api/client'; + +/** + * Converts an image URL to a Blob by creating an element, drawing it to canvas + * and then converting the canvas to a Blob. + * + * @returns A function that takes a URL and returns a Promise that resolves with a Blob + */ +export const useImageUrlToBlob = () => { + const imageUrlToBlob = useCallback( + async (url: string) => + new Promise((resolve) => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + + const context = canvas.getContext('2d'); + if (!context) { + return; + } + context.drawImage(img, 0, 0); + resolve( + new Promise((resolve) => { + canvas.toBlob(function (blob) { + resolve(blob); + }, 'image/png'); + }) + ); + }; + img.crossOrigin = $authToken.get() ? 'use-credentials' : 'anonymous'; + img.src = url; + }), + [] + ); + + return imageUrlToBlob; +}; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index 77fae4e0a1..a5520322be 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -30,6 +30,7 @@ import { isCanvasMaskLine, } from './canvasTypes'; import { appSocketQueueItemStatusChanged } from 'services/events/actions'; +import { queueApi } from 'services/api/endpoints/queue'; export const initialLayerState: CanvasLayerState = { objects: [], @@ -812,6 +813,20 @@ export const canvasSlice = createSlice({ ); } }); + builder.addMatcher( + queueApi.endpoints.clearQueue.matchFulfilled, + (state) => { + state.batchIds = []; + } + ); + builder.addMatcher( + queueApi.endpoints.cancelByBatchIds.matchFulfilled, + (state, action) => { + state.batchIds = state.batchIds.filter( + (id) => !action.meta.arg.originalArgs.batch_ids.includes(id) + ); + } + ); }, }); diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdaptersCollapse.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdaptersCollapse.tsx index d1c3f6f0b9..2cad007a03 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdaptersCollapse.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdaptersCollapse.tsx @@ -90,9 +90,7 @@ const ControlAdaptersCollapse = () => { return ( 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/features/dynamicPrompts/store/dynamicPromptsSlice.ts b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts index 32e24845ea..4c2cd31eca 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts @@ -39,7 +39,10 @@ export const dynamicPromptsSlice = createSlice({ promptsChanged: (state, action: PayloadAction) => { state.prompts = action.payload; }, - parsingErrorChanged: (state, action: PayloadAction) => { + parsingErrorChanged: ( + state, + action: PayloadAction + ) => { state.parsingError = action.payload; }, isErrorChanged: (state, action: PayloadAction) => { 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 8c7e69b2b1..e9cb3ffcaf 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx @@ -18,6 +18,7 @@ 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; @@ -65,19 +66,32 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => { - - + {t('metadata.recallParameters')} {t('metadata.metadata')} {t('metadata.imageDetails')} {t('metadata.workflow')} + + {metadata ? ( + + + + ) : ( + + )} + {metadata ? ( diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index f7ef848211..87c716bb81 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -10,7 +10,7 @@ import { } from 'features/parameters/types/parameterSchemas'; import i18n from 'i18next'; import { has, keyBy } from 'lodash-es'; -import { OpenAPIV3 } from 'openapi-types'; +import { OpenAPIV3_1 } from 'openapi-types'; import { RgbaColor } from 'react-colorful'; import { Node } from 'reactflow'; import { Graph, _InputField, _OutputField } from 'services/api/types'; @@ -791,9 +791,9 @@ export type IntegerInputFieldTemplate = InputFieldTemplateBase & { default: number; multipleOf?: number; maximum?: number; - exclusiveMaximum?: boolean; + exclusiveMaximum?: number; minimum?: number; - exclusiveMinimum?: boolean; + exclusiveMinimum?: number; }; export type IntegerCollectionInputFieldTemplate = InputFieldTemplateBase & { @@ -814,9 +814,9 @@ export type FloatInputFieldTemplate = InputFieldTemplateBase & { default: number; multipleOf?: number; maximum?: number; - exclusiveMaximum?: boolean; + exclusiveMaximum?: number; minimum?: number; - exclusiveMinimum?: boolean; + exclusiveMinimum?: number; }; export type FloatCollectionInputFieldTemplate = InputFieldTemplateBase & { @@ -1163,20 +1163,20 @@ export type TypeHints = { }; export type InvocationSchemaExtra = { - output: OpenAPIV3.ReferenceObject; // the output of the invocation + output: OpenAPIV3_1.ReferenceObject; // the output of the invocation title: string; category?: string; tags?: string[]; version?: string; properties: Omit< - NonNullable & + NonNullable & (_InputField | _OutputField), 'type' > & { - type: Omit & { + type: Omit & { default: AnyInvocationType; }; - use_cache: Omit & { + use_cache: Omit & { default: boolean; }; }; @@ -1187,17 +1187,17 @@ export type InvocationSchemaType = { }; export type InvocationBaseSchemaObject = Omit< - OpenAPIV3.BaseSchemaObject, + OpenAPIV3_1.BaseSchemaObject, 'title' | 'type' | 'properties' > & InvocationSchemaExtra; export type InvocationOutputSchemaObject = Omit< - OpenAPIV3.SchemaObject, + OpenAPIV3_1.SchemaObject, 'properties' > & { - properties: OpenAPIV3.SchemaObject['properties'] & { - type: Omit & { + properties: OpenAPIV3_1.SchemaObject['properties'] & { + type: Omit & { default: string; }; } & { @@ -1205,14 +1205,18 @@ export type InvocationOutputSchemaObject = Omit< }; }; -export type InvocationFieldSchema = OpenAPIV3.SchemaObject & _InputField; +export type InvocationFieldSchema = OpenAPIV3_1.SchemaObject & _InputField; + +export type OpenAPIV3_1SchemaOrRef = + | OpenAPIV3_1.ReferenceObject + | OpenAPIV3_1.SchemaObject; export interface ArraySchemaObject extends InvocationBaseSchemaObject { - type: OpenAPIV3.ArraySchemaObjectType; - items: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject; + type: OpenAPIV3_1.ArraySchemaObjectType; + items: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject; } export interface NonArraySchemaObject extends InvocationBaseSchemaObject { - type?: OpenAPIV3.NonArraySchemaObjectType; + type?: OpenAPIV3_1.NonArraySchemaObjectType; } export type InvocationSchemaObject = ( @@ -1221,41 +1225,41 @@ export type InvocationSchemaObject = ( ) & { class: 'invocation' }; export const isSchemaObject = ( - obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined -): obj is OpenAPIV3.SchemaObject => Boolean(obj && !('$ref' in obj)); + obj: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | undefined +): obj is OpenAPIV3_1.SchemaObject => Boolean(obj && !('$ref' in obj)); export const isArraySchemaObject = ( - obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined -): obj is OpenAPIV3.ArraySchemaObject => + obj: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | undefined +): obj is OpenAPIV3_1.ArraySchemaObject => Boolean(obj && !('$ref' in obj) && obj.type === 'array'); export const isNonArraySchemaObject = ( - obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined -): obj is OpenAPIV3.NonArraySchemaObject => + obj: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | undefined +): obj is OpenAPIV3_1.NonArraySchemaObject => Boolean(obj && !('$ref' in obj) && obj.type !== 'array'); export const isRefObject = ( - obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined -): obj is OpenAPIV3.ReferenceObject => Boolean(obj && '$ref' in obj); + obj: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | undefined +): obj is OpenAPIV3_1.ReferenceObject => Boolean(obj && '$ref' in obj); export const isInvocationSchemaObject = ( obj: - | OpenAPIV3.ReferenceObject - | OpenAPIV3.SchemaObject + | OpenAPIV3_1.ReferenceObject + | OpenAPIV3_1.SchemaObject | InvocationSchemaObject ): obj is InvocationSchemaObject => 'class' in obj && obj.class === 'invocation'; export const isInvocationOutputSchemaObject = ( obj: - | OpenAPIV3.ReferenceObject - | OpenAPIV3.SchemaObject + | OpenAPIV3_1.ReferenceObject + | OpenAPIV3_1.SchemaObject | InvocationOutputSchemaObject ): obj is InvocationOutputSchemaObject => 'class' in obj && obj.class === 'output'; export const isInvocationFieldSchema = ( - obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject + obj: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject ): obj is InvocationFieldSchema => !('$ref' in obj); export type InvocationEdgeExtra = { type: 'default' | 'collapsed' }; diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index 1f7fe81620..3fd44207c0 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -1,5 +1,12 @@ -import { isBoolean, isInteger, isNumber, isString } from 'lodash-es'; -import { OpenAPIV3 } from 'openapi-types'; +import { + isArray, + isBoolean, + isInteger, + isNumber, + isString, + startCase, +} from 'lodash-es'; +import { OpenAPIV3_1 } from 'openapi-types'; import { COLLECTION_MAP, POLYMORPHIC_TYPES, @@ -72,6 +79,7 @@ import { T2IAdapterCollectionInputFieldTemplate, BoardInputFieldTemplate, InputFieldTemplate, + OpenAPIV3_1SchemaOrRef, } from '../types/types'; import { ControlField } from 'services/api/types'; @@ -90,7 +98,7 @@ export type BuildInputFieldArg = { * @example * refObjectToFieldType({ "$ref": "#/components/schemas/ImageField" }) --> 'ImageField' */ -export const refObjectToSchemaName = (refObject: OpenAPIV3.ReferenceObject) => +export const refObjectToSchemaName = (refObject: OpenAPIV3_1.ReferenceObject) => refObject.$ref.split('/').slice(-1)[0]; const buildIntegerInputFieldTemplate = ({ @@ -111,7 +119,10 @@ const buildIntegerInputFieldTemplate = ({ template.maximum = schemaObject.maximum; } - if (schemaObject.exclusiveMaximum !== undefined) { + if ( + schemaObject.exclusiveMaximum !== undefined && + isNumber(schemaObject.exclusiveMaximum) + ) { template.exclusiveMaximum = schemaObject.exclusiveMaximum; } @@ -119,7 +130,10 @@ const buildIntegerInputFieldTemplate = ({ template.minimum = schemaObject.minimum; } - if (schemaObject.exclusiveMinimum !== undefined) { + if ( + schemaObject.exclusiveMinimum !== undefined && + isNumber(schemaObject.exclusiveMinimum) + ) { template.exclusiveMinimum = schemaObject.exclusiveMinimum; } @@ -144,7 +158,10 @@ const buildIntegerPolymorphicInputFieldTemplate = ({ template.maximum = schemaObject.maximum; } - if (schemaObject.exclusiveMaximum !== undefined) { + if ( + schemaObject.exclusiveMaximum !== undefined && + isNumber(schemaObject.exclusiveMaximum) + ) { template.exclusiveMaximum = schemaObject.exclusiveMaximum; } @@ -152,7 +169,10 @@ const buildIntegerPolymorphicInputFieldTemplate = ({ template.minimum = schemaObject.minimum; } - if (schemaObject.exclusiveMinimum !== undefined) { + if ( + schemaObject.exclusiveMinimum !== undefined && + isNumber(schemaObject.exclusiveMinimum) + ) { template.exclusiveMinimum = schemaObject.exclusiveMinimum; } @@ -195,7 +215,10 @@ const buildFloatInputFieldTemplate = ({ template.maximum = schemaObject.maximum; } - if (schemaObject.exclusiveMaximum !== undefined) { + if ( + schemaObject.exclusiveMaximum !== undefined && + isNumber(schemaObject.exclusiveMaximum) + ) { template.exclusiveMaximum = schemaObject.exclusiveMaximum; } @@ -203,7 +226,10 @@ const buildFloatInputFieldTemplate = ({ template.minimum = schemaObject.minimum; } - if (schemaObject.exclusiveMinimum !== undefined) { + if ( + schemaObject.exclusiveMinimum !== undefined && + isNumber(schemaObject.exclusiveMinimum) + ) { template.exclusiveMinimum = schemaObject.exclusiveMinimum; } @@ -227,7 +253,10 @@ const buildFloatPolymorphicInputFieldTemplate = ({ template.maximum = schemaObject.maximum; } - if (schemaObject.exclusiveMaximum !== undefined) { + if ( + schemaObject.exclusiveMaximum !== undefined && + isNumber(schemaObject.exclusiveMaximum) + ) { template.exclusiveMaximum = schemaObject.exclusiveMaximum; } @@ -235,7 +264,10 @@ const buildFloatPolymorphicInputFieldTemplate = ({ template.minimum = schemaObject.minimum; } - if (schemaObject.exclusiveMinimum !== undefined) { + if ( + schemaObject.exclusiveMinimum !== undefined && + isNumber(schemaObject.exclusiveMinimum) + ) { template.exclusiveMinimum = schemaObject.exclusiveMinimum; } return template; @@ -872,84 +904,106 @@ const buildSchedulerInputFieldTemplate = ({ }; export const getFieldType = ( - schemaObject: InvocationFieldSchema + schemaObject: OpenAPIV3_1SchemaOrRef ): string | undefined => { - if (schemaObject?.ui_type) { - return schemaObject.ui_type; - } else if (!schemaObject.type) { - // if schemaObject has no type, then it should have one of allOf, anyOf, oneOf + if (isSchemaObject(schemaObject)) { + if (!schemaObject.type) { + // if schemaObject has no type, then it should have one of allOf, anyOf, oneOf - if (schemaObject.allOf) { - const allOf = schemaObject.allOf; - if (allOf && allOf[0] && isRefObject(allOf[0])) { - return refObjectToSchemaName(allOf[0]); - } - } else if (schemaObject.anyOf) { - const anyOf = schemaObject.anyOf; - /** - * Handle Polymorphic inputs, eg string | string[]. In OpenAPI, this is: - * - an `anyOf` with two items - * - one is an `ArraySchemaObject` with a single `SchemaObject or ReferenceObject` of type T in its `items` - * - the other is a `SchemaObject` or `ReferenceObject` of type T - * - * Any other cases we ignore. - */ - - let firstType: string | undefined; - let secondType: string | undefined; - - if (isArraySchemaObject(anyOf[0])) { - // first is array, second is not - const first = anyOf[0].items; - const second = anyOf[1]; - if (isRefObject(first) && isRefObject(second)) { - firstType = refObjectToSchemaName(first); - secondType = refObjectToSchemaName(second); - } else if ( - isNonArraySchemaObject(first) && - isNonArraySchemaObject(second) - ) { - firstType = first.type; - secondType = second.type; + if (schemaObject.allOf) { + const allOf = schemaObject.allOf; + if (allOf && allOf[0] && isRefObject(allOf[0])) { + return refObjectToSchemaName(allOf[0]); } - } else if (isArraySchemaObject(anyOf[1])) { - // first is not array, second is - const first = anyOf[0]; - const second = anyOf[1].items; - if (isRefObject(first) && isRefObject(second)) { - firstType = refObjectToSchemaName(first); - secondType = refObjectToSchemaName(second); - } else if ( - isNonArraySchemaObject(first) && - isNonArraySchemaObject(second) - ) { - firstType = first.type; - secondType = second.type; + } else if (schemaObject.anyOf) { + // ignore null types + const anyOf = schemaObject.anyOf.filter((i) => { + if (isSchemaObject(i)) { + if (i.type === 'null') { + return false; + } + } + return true; + }); + if (anyOf.length === 1) { + if (isRefObject(anyOf[0])) { + return refObjectToSchemaName(anyOf[0]); + } else if (isSchemaObject(anyOf[0])) { + return getFieldType(anyOf[0]); + } + } + /** + * Handle Polymorphic inputs, eg string | string[]. In OpenAPI, this is: + * - an `anyOf` with two items + * - one is an `ArraySchemaObject` with a single `SchemaObject or ReferenceObject` of type T in its `items` + * - the other is a `SchemaObject` or `ReferenceObject` of type T + * + * Any other cases we ignore. + */ + + let firstType: string | undefined; + let secondType: string | undefined; + + if (isArraySchemaObject(anyOf[0])) { + // first is array, second is not + const first = anyOf[0].items; + const second = anyOf[1]; + if (isRefObject(first) && isRefObject(second)) { + firstType = refObjectToSchemaName(first); + secondType = refObjectToSchemaName(second); + } else if ( + isNonArraySchemaObject(first) && + isNonArraySchemaObject(second) + ) { + firstType = first.type; + secondType = second.type; + } + } else if (isArraySchemaObject(anyOf[1])) { + // first is not array, second is + const first = anyOf[0]; + const second = anyOf[1].items; + if (isRefObject(first) && isRefObject(second)) { + firstType = refObjectToSchemaName(first); + secondType = refObjectToSchemaName(second); + } else if ( + isNonArraySchemaObject(first) && + isNonArraySchemaObject(second) + ) { + firstType = first.type; + secondType = second.type; + } + } + if (firstType === secondType && isPolymorphicItemType(firstType)) { + return SINGLE_TO_POLYMORPHIC_MAP[firstType]; } } - if (firstType === secondType && isPolymorphicItemType(firstType)) { - return SINGLE_TO_POLYMORPHIC_MAP[firstType]; + } else if (schemaObject.enum) { + return 'enum'; + } else if (schemaObject.type) { + if (schemaObject.type === 'number') { + // floats are "number" in OpenAPI, while ints are "integer" - we need to distinguish them + return 'float'; + } else if (schemaObject.type === 'array') { + const itemType = isSchemaObject(schemaObject.items) + ? schemaObject.items.type + : refObjectToSchemaName(schemaObject.items); + + if (isArray(itemType)) { + // This is a nested array, which we don't support + return; + } + + if (isCollectionItemType(itemType)) { + return COLLECTION_MAP[itemType]; + } + + return; + } else if (!isArray(schemaObject.type)) { + return schemaObject.type; } } - } else if (schemaObject.enum) { - return 'enum'; - } else if (schemaObject.type) { - if (schemaObject.type === 'number') { - // floats are "number" in OpenAPI, while ints are "integer" - we need to distinguish them - return 'float'; - } else if (schemaObject.type === 'array') { - const itemType = isSchemaObject(schemaObject.items) - ? schemaObject.items.type - : refObjectToSchemaName(schemaObject.items); - - if (isCollectionItemType(itemType)) { - return COLLECTION_MAP[itemType]; - } - - return; - } else { - return schemaObject.type; - } + } else if (isRefObject(schemaObject)) { + return refObjectToSchemaName(schemaObject); } return; }; @@ -1025,7 +1079,15 @@ export const buildInputFieldTemplate = ( name: string, fieldType: FieldType ) => { - const { input, ui_hidden, ui_component, ui_type, ui_order } = fieldSchema; + const { + input, + ui_hidden, + ui_component, + ui_type, + ui_order, + ui_choice_labels, + item_default, + } = fieldSchema; const extra = { // TODO: Can we support polymorphic inputs in the UI? @@ -1035,11 +1097,13 @@ export const buildInputFieldTemplate = ( ui_type, required: nodeSchema.required?.includes(name) ?? false, ui_order, + ui_choice_labels, + item_default, }; const baseField = { name, - title: fieldSchema.title ?? '', + title: fieldSchema.title ?? (name ? startCase(name) : ''), description: fieldSchema.description ?? '', fieldKind: 'input' as const, ...extra, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts new file mode 100644 index 0000000000..4b4a8a8a03 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addHrfToGraph.ts @@ -0,0 +1,247 @@ +import { RootState } from 'app/store/store'; +import { NonNullableGraph } from 'features/nodes/types/types'; +import { + DenoiseLatentsInvocation, + ResizeLatentsInvocation, + NoiseInvocation, + LatentsToImageInvocation, + Edge, +} 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, + NOISE_HRF, + VAE_LOADER, +} from './constants'; +import { logger } from 'app/logging/logger'; + +// Copy certain connections from previous DENOISE_LATENTS to new DENOISE_LATENTS_HRF. +function copyConnectionsToDenoiseLatentsHrf(graph: NonNullableGraph): void { + const destinationFields = [ + 'vae', + 'control', + 'ip_adapter', + 'metadata', + 'unet', + 'positive_conditioning', + 'negative_conditioning', + ]; + const newEdges: Edge[] = []; + + // Loop through the existing edges connected to DENOISE_LATENTS + graph.edges.forEach((edge: Edge) => { + if ( + edge.destination.node_id === DENOISE_LATENTS && + destinationFields.includes(edge.destination.field) + ) { + // Add a similar connection to DENOISE_LATENTS_HRF + newEdges.push({ + source: { + node_id: edge.source.node_id, + field: edge.source.field, + }, + destination: { + node_id: DENOISE_LATENTS_HRF, + field: edge.destination.field, + }, + }); + } + }); + graph.edges = graph.edges.concat(newEdges); +} + +// Adds the high-res fix feature to the given graph. +export const addHrfToGraph = ( + state: RootState, + graph: NonNullableGraph +): void => { + // Double check hrf is enabled. + if ( + !state.generation.hrfEnabled || + state.config.disabledSDFeatures.includes('hrf') || + state.generation.model?.model_type === 'onnx' // TODO: ONNX support + ) { + return; + } + const log = logger('txt2img'); + + const { vae } = 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 + | DenoiseLatentsInvocation + | undefined; + const originalNoiseNode = graph.nodes[NOISE] as NoiseInvocation | undefined; + // Original latents to image should pick this up. + const originalLatentsToImageNode = graph.nodes[LATENTS_TO_IMAGE] as + | LatentsToImageInvocation + | undefined; + // Check if originalDenoiseLatentsNode is undefined and log an error + if (!originalDenoiseLatentsNode) { + log.error('originalDenoiseLatentsNode is undefined'); + return; + } + // Check if originalNoiseNode is undefined and log an error + if (!originalNoiseNode) { + log.error('originalNoiseNode is undefined'); + return; + } + + // Check if originalLatentsToImageNode is undefined and log an error + if (!originalLatentsToImageNode) { + log.error('originalLatentsToImageNode is undefined'); + return; + } + // Change height and width of original noise node to initial resolution. + if (originalNoiseNode) { + originalNoiseNode.width = hrfWidth; + originalNoiseNode.height = hrfHeight; + } + + // Define new nodes. + // Denoise latents node to be run on upscaled latents. + const denoiseLatentsHrfNode: DenoiseLatentsInvocation = { + type: 'denoise_latents', + id: DENOISE_LATENTS_HRF, + is_intermediate: originalDenoiseLatentsNode?.is_intermediate, + cfg_scale: originalDenoiseLatentsNode?.cfg_scale, + scheduler: originalDenoiseLatentsNode?.scheduler, + steps: originalDenoiseLatentsNode?.steps, + denoising_start: 1 - state.generation.hrfStrength, + denoising_end: 1, + }; + + // New base resolution noise node. + const hrfNoiseNode: NoiseInvocation = { + type: 'noise', + id: NOISE_HRF, + seed: originalNoiseNode?.seed, + use_cpu: originalNoiseNode?.use_cpu, + is_intermediate: originalNoiseNode?.is_intermediate, + }; + + const rescaleLatentsNode: ResizeLatentsInvocation = { + id: RESCALE_LATENTS, + type: 'lresize', + width: state.generation.width, + height: state.generation.height, + }; + + // New node to convert latents to image. + const latentsToImageHrfNode: LatentsToImageInvocation | undefined = + originalLatentsToImageNode + ? { + type: 'l2i', + id: LATENTS_TO_IMAGE_HRF, + fp32: originalLatentsToImageNode?.fp32, + is_intermediate: originalLatentsToImageNode?.is_intermediate, + } + : undefined; + + // Add new nodes to graph. + graph.nodes[LATENTS_TO_IMAGE_HRF] = + latentsToImageHrfNode as LatentsToImageInvocation; + graph.nodes[DENOISE_LATENTS_HRF] = + denoiseLatentsHrfNode as DenoiseLatentsInvocation; + graph.nodes[NOISE_HRF] = hrfNoiseNode as NoiseInvocation; + graph.nodes[RESCALE_LATENTS] = rescaleLatentsNode as ResizeLatentsInvocation; + + // Connect nodes. + graph.edges.push( + { + // Set up rescale latents. + source: { + node_id: DENOISE_LATENTS, + field: 'latents', + }, + destination: { + node_id: RESCALE_LATENTS, + field: 'latents', + }, + }, + // Set up new noise node + { + source: { + node_id: RESCALE_LATENTS, + field: 'height', + }, + destination: { + node_id: NOISE_HRF, + field: 'height', + }, + }, + { + source: { + node_id: RESCALE_LATENTS, + field: 'width', + }, + destination: { + node_id: NOISE_HRF, + field: 'width', + }, + }, + // Set up new denoise node. + { + source: { + node_id: RESCALE_LATENTS, + field: 'latents', + }, + destination: { + node_id: DENOISE_LATENTS_HRF, + field: 'latents', + }, + }, + { + source: { + node_id: NOISE_HRF, + field: 'noise', + }, + destination: { + node_id: DENOISE_LATENTS_HRF, + field: 'noise', + }, + }, + // Set up new latents to image node. + { + source: { + node_id: DENOISE_LATENTS_HRF, + field: 'latents', + }, + destination: { + node_id: LATENTS_TO_IMAGE_HRF, + 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, + field: 'vae', + }, + destination: { + node_id: LATENTS_TO_IMAGE_HRF, + field: 'vae', + }, + } + ); + + copyConnectionsToDenoiseLatentsHrf(graph); +}; 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 738c69faff..d5a6addf8a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSaveImageNode.ts @@ -2,6 +2,7 @@ import { NonNullableGraph } from 'features/nodes/types/types'; import { CANVAS_OUTPUT, LATENTS_TO_IMAGE, + LATENTS_TO_IMAGE_HRF, METADATA_ACCUMULATOR, NSFW_CHECKER, SAVE_IMAGE, @@ -82,6 +83,14 @@ export const addSaveImageNode = ( }, destination, }); + } else if (LATENTS_TO_IMAGE_HRF in graph.nodes) { + graph.edges.push({ + source: { + node_id: LATENTS_TO_IMAGE_HRF, + field: 'image', + }, + destination, + }); } else if (LATENTS_TO_IMAGE in graph.nodes) { graph.edges.push({ source: { 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 f07edcb220..16dc5bbc71 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addT2IAdapterToLinearGraph.ts @@ -86,7 +86,7 @@ export const addT2IAdaptersToLinearGraph = ( graph.nodes[t2iAdapterNode.id] = t2iAdapterNode as T2IAdapterInvocation; - if (metadataAccumulator?.ipAdapters) { + 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, [ 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 c3c7fcdf1b..e692e12fa4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -6,6 +6,7 @@ import { ONNXTextToLatentsInvocation, } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; +import { addHrfToGraph } from './addHrfToGraph'; import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; @@ -47,6 +48,10 @@ export const buildLinearTextToImageGraph = ( seamlessXAxis, seamlessYAxis, seed, + hrfWidth, + hrfHeight, + hrfStrength, + hrfEnabled: hrfEnabled, } = state.generation; const use_cpu = shouldUseCpuNoise; @@ -254,6 +259,9 @@ export const buildLinearTextToImageGraph = ( 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({ @@ -287,6 +295,12 @@ export const buildLinearTextToImageGraph = ( addT2IAdaptersToLinearGraph(state, graph, DENOISE_LATENTS); + // High resolution fix. + // NOTE: Not supported for onnx models. + if (state.generation.hrfEnabled && !isUsingOnnxModel) { + addHrfToGraph(state, graph); + } + // NSFW & watermark - must be last thing added to graph if (state.system.shouldUseNSFWChecker) { // must add before watermarker! 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 e538094731..7d547d09e6 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts @@ -2,11 +2,14 @@ export const POSITIVE_CONDITIONING = 'positive_conditioning'; export const NEGATIVE_CONDITIONING = 'negative_conditioning'; export const DENOISE_LATENTS = 'denoise_latents'; +export const DENOISE_LATENTS_HRF = 'denoise_latents_hrf'; export const LATENTS_TO_IMAGE = 'latents_to_image'; +export const LATENTS_TO_IMAGE_HRF = 'latents_to_image_hrf'; export const SAVE_IMAGE = 'save_image'; export const NSFW_CHECKER = 'nsfw_checker'; export const WATERMARKER = 'invisible_watermark'; export const NOISE = 'noise'; +export const NOISE_HRF = 'noise_hrf'; export const RANDOM_INT = 'rand_int'; export const RANGE_OF_SIZE = 'range_of_size'; export const ITERATE = 'iterate'; @@ -18,6 +21,7 @@ export const CLIP_SKIP = 'clip_skip'; export const IMAGE_TO_LATENTS = 'image_to_latents'; export const LATENTS_TO_LATENTS = 'latents_to_latents'; export const RESIZE = 'resize_image'; +export const RESCALE_LATENTS = 'rescale_latents'; export const IMG2IMG_RESIZE = 'img2img_resize'; export const CANVAS_OUTPUT = 'canvas_output'; export const INPAINT_IMAGE = 'inpaint_image'; diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index 69d8d9dd4c..93cd75dd75 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -1,7 +1,7 @@ import { logger } from 'app/logging/logger'; import { parseify } from 'common/util/serialize'; -import { reduce } from 'lodash-es'; -import { OpenAPIV3 } from 'openapi-types'; +import { reduce, startCase } from 'lodash-es'; +import { OpenAPIV3_1 } from 'openapi-types'; import { AnyInvocationType } from 'services/events/types'; import { FieldType, @@ -60,7 +60,7 @@ const isNotInDenylist = (schema: InvocationSchemaObject) => !invocationDenylist.includes(schema.properties.type.default); export const parseSchema = ( - openAPI: OpenAPIV3.Document, + openAPI: OpenAPIV3_1.Document, nodesAllowlistExtra: string[] | undefined = undefined, nodesDenylistExtra: string[] | undefined = undefined ): Record => { @@ -110,7 +110,7 @@ export const parseSchema = ( return inputsAccumulator; } - const fieldType = getFieldType(property); + const fieldType = property.ui_type ?? getFieldType(property); if (!isFieldType(fieldType)) { logger('nodes').warn( @@ -209,7 +209,7 @@ export const parseSchema = ( return outputsAccumulator; } - const fieldType = getFieldType(property); + const fieldType = property.ui_type ?? getFieldType(property); if (!isFieldType(fieldType)) { logger('nodes').warn( @@ -222,7 +222,8 @@ export const parseSchema = ( outputsAccumulator[propertyName] = { fieldKind: 'output', name: propertyName, - title: property.title ?? '', + title: + property.title ?? (propertyName ? startCase(propertyName) : ''), description: property.description ?? '', type: fieldType, ui_hidden: property.ui_hidden ?? false, 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 new file mode 100644 index 0000000000..ef0db1af6d --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfCollapse.tsx @@ -0,0 +1,65 @@ +import { Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +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 { useMemo } from 'react'; +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, + (state: RootState) => { + const { hrfEnabled } = state.generation; + + return { hrfEnabled }; + }, + defaultSelectorOptions +); + +export default function ParamHrfCollapse() { + const isHRFFeatureEnabled = useFeatureStatus('hrf').isFeatureEnabled; + const { hrfEnabled } = useAppSelector(selector); + const activeLabel = useMemo(() => { + if (hrfEnabled) { + return 'On'; + } else { + return 'Off'; + } + }, [hrfEnabled]); + + if (!isHRFFeatureEnabled) { + return null; + } + + return ( + + + + {hrfEnabled && ( + + + + + )} + {hrfEnabled && } + + + ); +} diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfHeight.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfHeight.tsx new file mode 100644 index 0000000000..053da11a5a --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfHeight.tsx @@ -0,0 +1,87 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider'; +import { roundToMultiple } from 'common/util/roundDownToMultiple'; +import { + setHrfHeight, + setHrfWidth, +} from 'features/parameters/store/generationSlice'; +import { memo, useCallback } from 'react'; + +function findPrevMultipleOfEight(n: number): number { + return Math.floor((n - 1) / 8) * 8; +} + +const selector = createSelector( + [stateSelector], + ({ generation, hotkeys, config }) => { + const { min, fineStep, coarseStep } = config.sd.height; + const { model, height, hrfHeight, aspectRatio, hrfEnabled } = generation; + + const step = hotkeys.shift ? fineStep : coarseStep; + + return { + model, + height, + hrfHeight, + min, + step, + aspectRatio, + hrfEnabled, + }; + }, + defaultSelectorOptions +); + +type ParamHeightProps = Omit< + IAIFullSliderProps, + 'label' | 'value' | 'onChange' +>; + +const ParamHrfHeight = (props: ParamHeightProps) => { + const { height, hrfHeight, min, step, aspectRatio, hrfEnabled } = + useAppSelector(selector); + const dispatch = useAppDispatch(); + const maxHrfHeight = Math.max(findPrevMultipleOfEight(height), min); + + const handleChange = useCallback( + (v: number) => { + dispatch(setHrfHeight(v)); + if (aspectRatio) { + const newWidth = roundToMultiple(v * aspectRatio, 8); + dispatch(setHrfWidth(newWidth)); + } + }, + [dispatch, aspectRatio] + ); + + const handleReset = useCallback(() => { + dispatch(setHrfHeight(maxHrfHeight)); + if (aspectRatio) { + const newWidth = roundToMultiple(maxHrfHeight * aspectRatio, 8); + dispatch(setHrfWidth(newWidth)); + } + }, [dispatch, maxHrfHeight, aspectRatio]); + + return ( + + ); +}; + +export default memo(ParamHrfHeight); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfStrength.tsx new file mode 100644 index 0000000000..ba17bc2f36 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfStrength.tsx @@ -0,0 +1,64 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector, useAppDispatch } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { memo, useCallback } from 'react'; +import { stateSelector } from 'app/store/store'; +import { setHrfStrength } from 'features/parameters/store/generationSlice'; +import IAISlider from 'common/components/IAISlider'; + +const selector = createSelector( + [stateSelector], + ({ generation, hotkeys, config }) => { + const { initial, min, sliderMax, inputMax, fineStep, coarseStep } = + config.sd.hrfStrength; + const { hrfStrength, hrfEnabled } = generation; + const step = hotkeys.shift ? fineStep : coarseStep; + + return { + hrfStrength, + initial, + min, + sliderMax, + inputMax, + step, + hrfEnabled, + }; + }, + defaultSelectorOptions +); + +const ParamHrfStrength = () => { + const { hrfStrength, initial, min, sliderMax, step, hrfEnabled } = + useAppSelector(selector); + const dispatch = useAppDispatch(); + + const handleHrfStrengthReset = useCallback(() => { + dispatch(setHrfStrength(initial)); + }, [dispatch, initial]); + + const handleHrfStrengthChange = useCallback( + (v: number) => { + dispatch(setHrfStrength(v)); + }, + [dispatch] + ); + + return ( + + ); +}; + +export default memo(ParamHrfStrength); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfToggle.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfToggle.tsx new file mode 100644 index 0000000000..8a68ead652 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfToggle.tsx @@ -0,0 +1,27 @@ +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAISwitch from 'common/components/IAISwitch'; +import { setHrfEnabled } from 'features/parameters/store/generationSlice'; +import { ChangeEvent, useCallback } from 'react'; + +export default function ParamHrfToggle() { + const dispatch = useAppDispatch(); + + const hrfEnabled = useAppSelector( + (state: RootState) => state.generation.hrfEnabled + ); + + const handleHrfEnabled = useCallback( + (e: ChangeEvent) => + dispatch(setHrfEnabled(e.target.checked)), + [dispatch] + ); + + return ( + + ); +} diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfWidth.tsx new file mode 100644 index 0000000000..09615d5154 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/HighResFix/ParamHrfWidth.tsx @@ -0,0 +1,84 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider'; +import { roundToMultiple } from 'common/util/roundDownToMultiple'; +import { + setHrfHeight, + setHrfWidth, +} from 'features/parameters/store/generationSlice'; +import { memo, useCallback } from 'react'; + +function findPrevMultipleOfEight(n: number): number { + return Math.floor((n - 1) / 8) * 8; +} + +const selector = createSelector( + [stateSelector], + ({ generation, hotkeys, config }) => { + const { min, fineStep, coarseStep } = config.sd.width; + const { model, width, hrfWidth, aspectRatio, hrfEnabled } = generation; + + const step = hotkeys.shift ? fineStep : coarseStep; + + return { + model, + width, + hrfWidth, + min, + step, + aspectRatio, + hrfEnabled, + }; + }, + defaultSelectorOptions +); + +type ParamWidthProps = Omit; + +const ParamHrfWidth = (props: ParamWidthProps) => { + const { width, hrfWidth, min, step, aspectRatio, hrfEnabled } = + useAppSelector(selector); + const dispatch = useAppDispatch(); + const maxHrfWidth = Math.max(findPrevMultipleOfEight(width), min); + + const handleChange = useCallback( + (v: number) => { + dispatch(setHrfWidth(v)); + if (aspectRatio) { + const newHeight = roundToMultiple(v / aspectRatio, 8); + dispatch(setHrfHeight(newHeight)); + } + }, + [dispatch, aspectRatio] + ); + + const handleReset = useCallback(() => { + dispatch(setHrfWidth(maxHrfWidth)); + if (aspectRatio) { + const newHeight = roundToMultiple(maxHrfWidth / aspectRatio, 8); + dispatch(setHrfHeight(newHeight)); + } + }, [dispatch, maxHrfWidth, aspectRatio]); + + return ( + + ); +}; + +export default memo(ParamHrfWidth); diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 84d26b6476..63d545662a 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -27,6 +27,10 @@ import { } from '../types/parameterSchemas'; export interface GenerationState { + hrfHeight: HeightParam; + hrfWidth: WidthParam; + hrfEnabled: boolean; + hrfStrength: StrengthParam; cfgScale: CfgScaleParam; height: HeightParam; img2imgStrength: StrengthParam; @@ -69,6 +73,10 @@ export interface GenerationState { } export const initialGenerationState: GenerationState = { + hrfHeight: 64, + hrfWidth: 64, + hrfStrength: 0.75, + hrfEnabled: false, cfgScale: 7.5, height: 512, img2imgStrength: 0.75, @@ -271,6 +279,18 @@ export const generationSlice = createSlice({ setClipSkip: (state, action: PayloadAction) => { state.clipSkip = action.payload; }, + setHrfHeight: (state, action: PayloadAction) => { + state.hrfHeight = action.payload; + }, + setHrfWidth: (state, action: PayloadAction) => { + state.hrfWidth = action.payload; + }, + setHrfStrength: (state, action: PayloadAction) => { + state.hrfStrength = action.payload; + }, + setHrfEnabled: (state, action: PayloadAction) => { + state.hrfEnabled = action.payload; + }, shouldUseCpuNoiseChanged: (state, action: PayloadAction) => { state.shouldUseCpuNoise = action.payload; }, @@ -355,6 +375,10 @@ export const { setSeamlessXAxis, setSeamlessYAxis, setClipSkip, + setHrfHeight, + setHrfWidth, + setHrfStrength, + setHrfEnabled, shouldUseCpuNoiseChanged, setAspectRatio, setShouldLockAspectRatio, diff --git a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts index e548b9aeaf..7a6b6b8a5c 100644 --- a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts +++ b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts @@ -210,6 +210,15 @@ export type HeightParam = z.infer; export const isValidHeight = (val: unknown): val is HeightParam => zHeight.safeParse(val).success; +/** + * Zod schema for resolution parameter + */ +export const zResolution = z.tuple([zWidth, zHeight]); +/** + * Type alias for resolution parameter, inferred from its zod schema + */ +export type ResolutionParam = z.infer; + export const zBaseModel = z.enum([ 'any', 'sd-1', diff --git a/invokeai/frontend/web/src/features/queue/components/common/QueueItemCard.tsx b/invokeai/frontend/web/src/features/queue/components/common/QueueItemCard.tsx index 9cc991335e..d441be4ecb 100644 --- a/invokeai/frontend/web/src/features/queue/components/common/QueueItemCard.tsx +++ b/invokeai/frontend/web/src/features/queue/components/common/QueueItemCard.tsx @@ -7,7 +7,7 @@ const QueueItemCard = ({ session_queue_item, label, }: { - session_queue_item?: components['schemas']['SessionQueueItem']; + session_queue_item?: components['schemas']['SessionQueueItem'] | null; label: string; }) => { return ( 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 423ce41bcd..fbe5692431 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsClearIntermediates.tsx @@ -3,6 +3,7 @@ import { useAppDispatch } from 'app/store/storeHooks'; import { controlAdaptersReset } from 'features/controlAdapters/store/controlAdaptersSlice'; import { useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { useGetQueueStatusQuery } from 'services/api/endpoints/queue'; import IAIButton from '../../../../common/components/IAIButton'; import { useClearIntermediatesMutation, @@ -22,7 +23,16 @@ export default function SettingsClearIntermediates() { const [clearIntermediates, { isLoading: isLoadingClearIntermediates }] = useClearIntermediatesMutation(); + const { data: queueStatus } = useGetQueueStatusQuery(); + const hasPendingItems = + queueStatus && + (queueStatus.queue.in_progress > 0 || queueStatus.queue.pending > 0); + const handleClickClearIntermediates = useCallback(() => { + if (hasPendingItems) { + return; + } + clearIntermediates() .unwrap() .then((clearedCount) => { @@ -43,7 +53,7 @@ export default function SettingsClearIntermediates() { }) ); }); - }, [t, clearIntermediates, dispatch]); + }, [t, clearIntermediates, dispatch, hasPendingItems]); useEffect(() => { // update the count on mount @@ -54,10 +64,13 @@ export default function SettingsClearIntermediates() { {t('settings.clearIntermediates')} {t('settings.clearIntermediatesWithCount', { count: intermediatesCount ?? 0, diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts index 30eebab5d5..78d540203b 100644 --- a/invokeai/frontend/web/src/features/system/store/configSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts @@ -69,6 +69,14 @@ export const initialConfigState: AppConfig = { fineStep: 0.01, coarseStep: 0.05, }, + hrfStrength: { + initial: 0.7, + min: 0, + sliderMax: 1, + inputMax: 1, + fineStep: 0.01, + coarseStep: 0.05, + }, dynamicPrompts: { maxPrompts: { initial: 100, diff --git a/invokeai/frontend/web/src/features/system/util/copyBlobToClipboard.ts b/invokeai/frontend/web/src/features/system/util/copyBlobToClipboard.ts index cf59f2a687..b5e896f3bf 100644 --- a/invokeai/frontend/web/src/features/system/util/copyBlobToClipboard.ts +++ b/invokeai/frontend/web/src/features/system/util/copyBlobToClipboard.ts @@ -2,7 +2,7 @@ * Copies a blob to the clipboard by calling navigator.clipboard.write(). */ export const copyBlobToClipboard = ( - blob: Promise, + blob: Promise | Blob, type = 'image/png' ) => { navigator.clipboard.write([ diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/MergeModelsPanel.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/MergeModelsPanel.tsx index 6837a2e853..e5c68ba6cf 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/MergeModelsPanel.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/MergeModelsPanel.tsx @@ -112,7 +112,7 @@ export default function MergeModelsPanel() { } }); - const mergeModelsInfo: MergeModelConfig = { + const mergeModelsInfo: MergeModelConfig['body'] = { model_names: models_names, merged_model_name: mergedModelName !== '' ? mergedModelName : models_names.join('-'), @@ -125,7 +125,7 @@ export default function MergeModelsPanel() { mergeModels({ base_model: baseModel, - body: mergeModelsInfo, + body: { body: mergeModelsInfo }, }) .unwrap() .then((_) => { diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx index 0c153fd7eb..8ec8c9caed 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx @@ -3,6 +3,7 @@ import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse'; import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse'; import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; +import ParamHrfCollapse from 'features/parameters/components/Parameters/HighResFix/ParamHrfCollapse'; import { memo } from 'react'; import ParamPromptArea from '../../../../parameters/components/Parameters/Prompt/ParamPromptArea'; import TextToImageTabCoreParameters from './TextToImageTabCoreParameters'; @@ -16,6 +17,7 @@ const TextToImageTabParameters = () => { + ); diff --git a/invokeai/frontend/web/src/features/ui/hooks/useCopyImageToClipboard.ts b/invokeai/frontend/web/src/features/ui/hooks/useCopyImageToClipboard.ts index 4b42a45e93..ef9db44a9d 100644 --- a/invokeai/frontend/web/src/features/ui/hooks/useCopyImageToClipboard.ts +++ b/invokeai/frontend/web/src/features/ui/hooks/useCopyImageToClipboard.ts @@ -1,11 +1,13 @@ import { useAppToaster } from 'app/components/Toaster'; +import { useImageUrlToBlob } from 'common/hooks/useImageUrlToBlob'; +import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard'; export const useCopyImageToClipboard = () => { const toaster = useAppToaster(); const { t } = useTranslation(); + const imageUrlToBlob = useImageUrlToBlob(); const isClipboardAPIAvailable = useMemo(() => { return Boolean(navigator.clipboard) && Boolean(window.ClipboardItem); @@ -23,15 +25,13 @@ export const useCopyImageToClipboard = () => { }); } try { - const getImageBlob = async () => { - const response = await fetch(image_url); - if (!response.ok) { - throw new Error(`Problem retrieving image data`); - } - return await response.blob(); - }; + const blob = await imageUrlToBlob(image_url); - copyBlobToClipboard(getImageBlob()); + if (!blob) { + throw new Error('Unable to create Blob'); + } + + copyBlobToClipboard(blob); toaster({ title: t('toast.imageCopied'), @@ -49,7 +49,7 @@ export const useCopyImageToClipboard = () => { }); } }, - [isClipboardAPIAvailable, t, toaster] + [imageUrlToBlob, isClipboardAPIAvailable, t, toaster] ); return { isClipboardAPIAvailable, copyImageToClipboard }; diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index 3fa606d4b6..99a5fc5f50 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -520,7 +520,7 @@ export const imagesApi = api.injectEndpoints({ // assume all images are on the same board/category if (images[0]) { const categories = getCategories(images[0]); - const boardId = images[0].board_id; + const boardId = images[0].board_id ?? undefined; return [ { @@ -637,7 +637,7 @@ export const imagesApi = api.injectEndpoints({ // assume all images are on the same board/category if (images[0]) { const categories = getCategories(images[0]); - const boardId = images[0].board_id; + const boardId = images[0].board_id ?? undefined; return [ { type: 'ImageList', diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 6da1fa5154..e0da45c4c9 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -5,80 +5,13 @@ export type paths = { - "/api/v1/sessions/": { - /** - * List Sessions - * @deprecated - * @description Gets a list of sessions, optionally searching - */ - get: operations["list_sessions"]; - /** - * Create Session - * @deprecated - * @description Creates a new session, optionally initializing it with an invocation graph - */ - post: operations["create_session"]; - }; "/api/v1/sessions/{session_id}": { /** * Get Session - * @deprecated * @description Gets a session */ get: operations["get_session"]; }; - "/api/v1/sessions/{session_id}/nodes": { - /** - * Add Node - * @deprecated - * @description Adds a node to the graph - */ - post: operations["add_node"]; - }; - "/api/v1/sessions/{session_id}/nodes/{node_path}": { - /** - * Update Node - * @deprecated - * @description Updates a node in the graph and removes all linked edges - */ - put: operations["update_node"]; - /** - * Delete Node - * @deprecated - * @description Deletes a node in the graph and removes all linked edges - */ - delete: operations["delete_node"]; - }; - "/api/v1/sessions/{session_id}/edges": { - /** - * Add Edge - * @deprecated - * @description Adds an edge to the graph - */ - post: operations["add_edge"]; - }; - "/api/v1/sessions/{session_id}/edges/{from_node_id}/{from_field}/{to_node_id}/{to_field}": { - /** - * Delete Edge - * @deprecated - * @description Deletes an edge from the graph - */ - delete: operations["delete_edge"]; - }; - "/api/v1/sessions/{session_id}/invoke": { - /** - * Invoke Session - * @deprecated - * @description Invokes a session - */ - put: operations["invoke_session"]; - /** - * Cancel Session Invoke - * @deprecated - * @description Invokes a session - */ - delete: operations["cancel_session_invoke"]; - }; "/api/v1/utilities/dynamicprompts": { /** * Parse Dynamicprompts @@ -481,18 +414,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * A * @description The first number @@ -506,9 +439,9 @@ export type components = { */ b?: number; /** - * Type + * type * @default add - * @enum {string} + * @constant */ type: "add"; }; @@ -551,7 +484,6 @@ export type components = { }; /** * BaseModelType - * @description An enumeration. * @enum {string} */ BaseModelType: "any" | "sd-1" | "sd-2" | "sdxl" | "sdxl-refiner"; @@ -566,11 +498,8 @@ export type components = { * Data * @description The batch data collection. */ - data?: components["schemas"]["BatchDatum"][][]; - /** - * Graph - * @description The graph to initialize the session with - */ + data?: components["schemas"]["BatchDatum"][][] | null; + /** @description The graph to initialize the session with */ graph: components["schemas"]["Graph"]; /** * Runs @@ -655,18 +584,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Width * @description The width of the image @@ -687,20 +616,19 @@ export type components = { */ mode?: "RGB" | "RGBA"; /** - * Color * @description The color of the image * @default { - * "r": 0, - * "g": 0, + * "a": 255, * "b": 0, - * "a": 255 + * "g": 0, + * "r": 0 * } */ color?: components["schemas"]["ColorField"]; /** - * Type + * type * @default blank_image - * @enum {string} + * @constant */ type: "blank_image"; }; @@ -719,27 +647,21 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Latents A - * @description Latents tensor - */ + use_cache?: boolean | null; + /** @description Latents tensor */ latents_a?: components["schemas"]["LatentsField"]; - /** - * Latents B - * @description Latents tensor - */ + /** @description Latents tensor */ latents_b?: components["schemas"]["LatentsField"]; /** * Alpha @@ -748,9 +670,9 @@ export type components = { */ alpha?: number; /** - * Type + * type * @default lblend - * @enum {string} + * @constant */ type: "lblend"; }; @@ -760,12 +682,12 @@ export type components = { * Board Name * @description The board's new name. */ - board_name?: string; + board_name?: string | null; /** * Cover Image Name * @description The name of the board's new cover image. */ - cover_image_name?: string; + cover_image_name?: string | null; }; /** * BoardDTO @@ -796,12 +718,12 @@ export type components = { * Deleted At * @description The deleted timestamp of the board. */ - deleted_at?: string; + deleted_at?: string | null; /** * Cover Image Name * @description The name of the board's cover image. */ - cover_image_name?: string; + cover_image_name: string | null; /** * Image Count * @description The number of images in the board. @@ -872,14 +794,11 @@ export type components = { * Board Id * @description The board from which image should be downloaded from */ - board_id?: string; + board_id?: string | null; }; /** Body_enqueue_batch */ Body_enqueue_batch: { - /** - * Batch - * @description Batch to process - */ + /** @description Batch to process */ batch: components["schemas"]["Batch"]; /** * Prepend @@ -890,10 +809,7 @@ export type components = { }; /** Body_enqueue_graph */ Body_enqueue_graph: { - /** - * Graph - * @description The graph to enqueue - */ + /** @description The graph to enqueue */ graph: components["schemas"]["Graph"]; /** * Prepend @@ -912,41 +828,13 @@ export type components = { /** * Prediction Type * @description Prediction type for SDv2 checkpoints and rare SDv1 checkpoints - * @enum {string} */ - prediction_type?: "v_prediction" | "epsilon" | "sample"; + prediction_type?: ("v_prediction" | "epsilon" | "sample") | null; }; /** Body_merge_models */ Body_merge_models: { - /** - * Model Names - * @description model name - */ - model_names: string[]; - /** - * Merged Model Name - * @description Name of destination model - */ - merged_model_name: string; - /** - * Alpha - * @description Alpha weighting strength to apply to 2d and 3d models - * @default 0.5 - */ - alpha?: number; - /** @description Interpolation method */ - interp: components["schemas"]["MergeInterpolationMethod"]; - /** - * Force - * @description Force merging of models created with different versions of diffusers - * @default false - */ - force?: boolean; - /** - * Merge Dest Directory - * @description Save the merged model to the designated directory (with 'merged_model_name' appended) - */ - merge_dest_directory?: string; + /** @description Model configuration */ + body: components["schemas"]["MergeModelsBody"]; }; /** Body_parse_dynamicprompts */ Body_parse_dynamicprompts: { @@ -1023,27 +911,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of boolean values */ collection?: boolean[]; /** - * Type + * type * @default boolean_collection - * @enum {string} + * @constant */ type: "boolean_collection"; }; @@ -1058,9 +946,9 @@ export type components = { */ collection: boolean[]; /** - * Type + * type * @default boolean_collection_output - * @enum {string} + * @constant */ type: "boolean_collection_output"; }; @@ -1079,18 +967,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The boolean value @@ -1098,9 +986,9 @@ export type components = { */ value?: boolean; /** - * Type + * type * @default boolean - * @enum {string} + * @constant */ type: "boolean"; }; @@ -1115,9 +1003,9 @@ export type components = { */ value: boolean; /** - * Type + * type * @default boolean_output - * @enum {string} + * @constant */ type: "boolean_output"; }; @@ -1128,19 +1016,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default clip_vision + * @constant */ model_type: "clip_vision"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** CLIPVisionModelField */ CLIPVisionModelField: { @@ -1167,27 +1056,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to infill - */ + use_cache?: boolean | null; + /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default infill_cv2 - * @enum {string} + * @constant */ type: "infill_cv2"; }; @@ -1217,29 +1103,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default canny_image_processor - * @enum {string} - */ - type: "canny_image_processor"; /** * Low Threshold * @description The low threshold of the Canny pixel gradient (0-255) @@ -1252,6 +1129,12 @@ export type components = { * @default 200 */ high_threshold?: number; + /** + * type + * @default canny_image_processor + * @constant + */ + type: "canny_image_processor"; }; /** * ClearResult @@ -1266,15 +1149,9 @@ export type components = { }; /** ClipField */ ClipField: { - /** - * Tokenizer - * @description Info to load tokenizer submodel - */ + /** @description Info to load tokenizer submodel */ tokenizer: components["schemas"]["ModelInfo"]; - /** - * Text Encoder - * @description Info to load text_encoder submodel - */ + /** @description Info to load text_encoder submodel */ text_encoder: components["schemas"]["ModelInfo"]; /** * Skipped Layers @@ -1302,18 +1179,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count @@ -1326,9 +1203,9 @@ export type components = { */ skipped_layers?: number; /** - * Type + * type * @default clip_skip - * @enum {string} + * @constant */ type: "clip_skip"; }; @@ -1341,11 +1218,11 @@ export type components = { * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip?: components["schemas"]["ClipField"]; + clip?: components["schemas"]["ClipField"] | null; /** - * Type + * type * @default clip_skip_output - * @enum {string} + * @constant */ type: "clip_skip_output"; }; @@ -1364,18 +1241,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection Item * @description The item to collect (all inputs must be of the same type) @@ -1387,18 +1264,13 @@ export type components = { */ collection?: unknown[]; /** - * Type + * type * @default collect - * @enum {string} + * @constant */ type: "collect"; }; - /** - * CollectInvocationOutput - * @description Base class for all invocation outputs. - * - * All invocation outputs must use the `@invocation_output` decorator to provide their unique type. - */ + /** CollectInvocationOutput */ CollectInvocationOutput: { /** * Collection @@ -1406,9 +1278,9 @@ export type components = { */ collection: unknown[]; /** - * Type + * type * @default collect_output - * @enum {string} + * @constant */ type: "collect_output"; }; @@ -1423,9 +1295,9 @@ export type components = { */ collection: components["schemas"]["ColorField"][]; /** - * Type + * type * @default color_collection_output - * @enum {string} + * @constant */ type: "color_collection_output"; }; @@ -1445,33 +1317,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to color-correct - */ + use_cache?: boolean | null; + /** @description The image to color-correct */ image?: components["schemas"]["ImageField"]; - /** - * Reference - * @description Reference image for color-correction - */ + /** @description Reference image for color-correction */ reference?: components["schemas"]["ImageField"]; - /** - * Mask - * @description Mask to use when applying color-correction - */ - mask?: components["schemas"]["ImageField"]; + /** @description Mask to use when applying color-correction */ + mask?: components["schemas"]["ImageField"] | null; /** * Mask Blur Radius * @description Mask blur radius @@ -1479,9 +1342,9 @@ export type components = { */ mask_blur_radius?: number; /** - * Type + * type * @default color_correct - * @enum {string} + * @constant */ type: "color_correct"; }; @@ -1526,33 +1389,32 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** - * Color * @description The color value * @default { - * "r": 0, - * "g": 0, + * "a": 255, * "b": 0, - * "a": 255 + * "g": 0, + * "r": 0 * } */ color?: components["schemas"]["ColorField"]; /** - * Type + * type * @default color - * @enum {string} + * @constant */ type: "color"; }; @@ -1571,50 +1433,44 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default color_map_image_processor - * @enum {string} - */ - type: "color_map_image_processor"; /** * Color Map Tile Size * @description Tile size * @default 64 */ color_map_tile_size?: number; + /** + * type + * @default color_map_image_processor + * @constant + */ + type: "color_map_image_processor"; }; /** * ColorOutput * @description Base class for nodes that output a single color */ ColorOutput: { - /** - * Color - * @description The output color - */ + /** @description The output color */ color: components["schemas"]["ColorField"]; /** - * Type + * type * @default color_output - * @enum {string} + * @constant */ type: "color_output"; }; @@ -1633,35 +1489,35 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Prompt * @description Prompt to be parsed by Compel to create a conditioning tensor * @default */ prompt?: string; - /** - * Type - * @default compel - * @enum {string} - */ - type: "compel"; /** * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; + /** + * type + * @default compel + * @constant + */ + type: "compel"; }; /** * Conditioning Collection Primitive @@ -1678,27 +1534,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of conditioning tensors */ collection?: components["schemas"]["ConditioningField"][]; /** - * Type + * type * @default conditioning_collection - * @enum {string} + * @constant */ type: "conditioning_collection"; }; @@ -1713,9 +1569,9 @@ export type components = { */ collection: components["schemas"]["ConditioningField"][]; /** - * Type + * type * @default conditioning_collection_output - * @enum {string} + * @constant */ type: "conditioning_collection_output"; }; @@ -1745,27 +1601,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Conditioning - * @description Conditioning tensor - */ + use_cache?: boolean | null; + /** @description Conditioning tensor */ conditioning?: components["schemas"]["ConditioningField"]; /** - * Type + * type * @default conditioning - * @enum {string} + * @constant */ type: "conditioning"; }; @@ -1774,15 +1627,12 @@ export type components = { * @description Base class for nodes that output a single conditioning tensor */ ConditioningOutput: { - /** - * Conditioning - * @description Conditioning tensor - */ + /** @description Conditioning tensor */ conditioning: components["schemas"]["ConditioningField"]; /** - * Type + * type * @default conditioning_output - * @enum {string} + * @constant */ type: "conditioning_output"; }; @@ -1801,29 +1651,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default content_shuffle_image_processor - * @enum {string} - */ - type: "content_shuffle_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -1854,18 +1695,18 @@ export type components = { * @default 256 */ f?: number; + /** + * type + * @default content_shuffle_image_processor + * @constant + */ + type: "content_shuffle_image_processor"; }; /** ControlField */ ControlField: { - /** - * Image - * @description The control image - */ + /** @description The control image */ image: components["schemas"]["ImageField"]; - /** - * Control Model - * @description The ControlNet model to use - */ + /** @description The ControlNet model to use */ control_model: components["schemas"]["ControlNetModelField"]; /** * Control Weight @@ -1915,27 +1756,21 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The control image - */ + use_cache?: boolean | null; + /** @description The control image */ image?: components["schemas"]["ImageField"]; - /** - * Control Model - * @description ControlNet model to load - */ + /** @description ControlNet model to load */ control_model: components["schemas"]["ControlNetModelField"]; /** * Control Weight @@ -1970,9 +1805,9 @@ export type components = { */ resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple"; /** - * Type + * type * @default controlnet - * @enum {string} + * @constant */ type: "controlnet"; }; @@ -1983,19 +1818,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default controlnet + * @constant */ model_type: "controlnet"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "checkpoint"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Config */ config: string; }; @@ -2006,19 +1842,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default controlnet + * @constant */ model_type: "controlnet"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** * ControlNetModelField @@ -2038,15 +1875,12 @@ export type components = { * @description node output for ControlNet info */ ControlOutput: { - /** - * Control - * @description ControlNet(s) to apply - */ + /** @description ControlNet(s) to apply */ control: components["schemas"]["ControlField"]; /** - * Type + * type * @default control_output - * @enum {string} + * @constant */ type: "control_output"; }; @@ -2058,154 +1892,145 @@ export type components = { /** * App Version * @description The version of InvokeAI used to generate this image - * @default 3.2.0 + * @default 3.3.0 */ app_version?: string; /** * Generation Mode * @description The generation mode that output this image */ - generation_mode: string; + generation_mode?: string | null; /** * Created By * @description The name of the creator of the image */ - created_by?: string; + created_by?: string | null; /** * Positive Prompt * @description The positive prompt parameter */ - positive_prompt: string; + positive_prompt?: string | null; /** * Negative Prompt * @description The negative prompt parameter */ - negative_prompt: string; + negative_prompt?: string | null; /** * Width * @description The width parameter */ - width: number; + width?: number | null; /** * Height * @description The height parameter */ - height: number; + height?: number | null; /** * Seed * @description The seed used for noise generation */ - seed: number; + seed?: number | null; /** * Rand Device * @description The device used for random number generation */ - rand_device: string; + rand_device?: string | null; /** * Cfg Scale * @description The classifier-free guidance scale parameter */ - cfg_scale: number; + cfg_scale?: number | null; /** * Steps * @description The number of steps used for inference */ - steps: number; + steps?: number | null; /** * Scheduler * @description The scheduler used for inference */ - scheduler: string; + scheduler?: string | null; /** * Clip Skip * @description The number of skipped CLIP layers */ - clip_skip?: number; - /** - * Model - * @description The main model used for inference - */ - model: components["schemas"]["MainModelField"]; + 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"][]; + controlnets?: components["schemas"]["ControlField"][] | null; /** * Ipadapters * @description The IP Adapters used for inference */ - ipAdapters: components["schemas"]["IPAdapterMetadataField"][]; + ipAdapters?: components["schemas"]["IPAdapterMetadataField"][] | null; /** * T2Iadapters * @description The IP Adapters used for inference */ - t2iAdapters: components["schemas"]["T2IAdapterField"][]; + t2iAdapters?: components["schemas"]["T2IAdapterField"][] | null; /** * Loras * @description The LoRAs used for inference */ - loras: components["schemas"]["LoRAMetadataField"][]; - /** - * Vae - * @description The VAE used for decoding, if the main model's default was not used - */ - vae?: components["schemas"]["VAEModelField"]; + 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 */ - strength?: number; + strength?: number | null; /** * Init Image * @description The name of the initial image */ - init_image?: string; + init_image?: string | null; /** * Positive Style Prompt * @description The positive style prompt parameter */ - positive_style_prompt?: string; + positive_style_prompt?: string | null; /** * Negative Style Prompt * @description The negative style prompt parameter */ - negative_style_prompt?: string; - /** - * Refiner Model - * @description The SDXL Refiner model used - */ - refiner_model?: components["schemas"]["MainModelField"]; + 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; + refiner_cfg_scale?: number | null; /** * Refiner Steps * @description The number of steps used for the refiner */ - refiner_steps?: number; + refiner_steps?: number | null; /** * Refiner Scheduler * @description The scheduler used for the refiner */ - refiner_scheduler?: string; + refiner_scheduler?: string | null; /** * Refiner Positive Aesthetic Score * @description The aesthetic score used for the refiner */ - refiner_positive_aesthetic_score?: number; + refiner_positive_aesthetic_score?: number | null; /** * Refiner Negative Aesthetic Score * @description The aesthetic score used for the refiner */ - refiner_negative_aesthetic_score?: number; + refiner_negative_aesthetic_score?: number | null; /** * Refiner Start * @description The start value used for refiner denoising */ - refiner_start?: number; + refiner_start?: number | null; }; /** * Create Denoise Mask @@ -2222,32 +2047,23 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Vae - * @description VAE - */ + use_cache?: boolean | null; + /** @description VAE */ vae?: components["schemas"]["VaeField"]; - /** - * Image - * @description Image which will be masked - */ - image?: components["schemas"]["ImageField"]; - /** - * Mask - * @description The mask to use when pasting - */ + /** @description Image which will be masked */ + image?: components["schemas"]["ImageField"] | null; + /** @description The mask to use when pasting */ mask?: components["schemas"]["ImageField"]; /** * Tiled @@ -2262,17 +2078,13 @@ export type components = { */ fp32?: boolean; /** - * Type + * type * @default create_denoise_mask - * @enum {string} + * @constant */ type: "create_denoise_mask"; }; - /** - * CursorPaginatedResults[SessionQueueItemDTO] - * @description Cursor-paginated results - * Generic must be a Pydantic model - */ + /** CursorPaginatedResults[SessionQueueItemDTO] */ CursorPaginatedResults_SessionQueueItemDTO_: { /** * Limit @@ -2305,32 +2117,26 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to inpaint - */ + use_cache?: boolean | null; + /** @description The image to inpaint */ image?: components["schemas"]["ImageField"]; - /** - * Mask - * @description The mask to use when inpainting - */ + /** @description The mask to use when inpainting */ mask?: components["schemas"]["ImageField"]; /** - * Type + * type * @default cv_inpaint - * @enum {string} + * @constant */ type: "cv_inpaint"; }; @@ -2372,23 +2178,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Noise - * @description Noise tensor - */ - noise?: components["schemas"]["LatentsField"]; + use_cache?: boolean | null; + /** @description Positive conditioning tensor */ + positive_conditioning?: components["schemas"]["ConditioningField"]; + /** @description Negative conditioning tensor */ + negative_conditioning?: components["schemas"]["ConditioningField"]; + /** @description Noise tensor */ + noise?: components["schemas"]["LatentsField"] | null; /** * Steps * @description Number of steps to run @@ -2420,49 +2227,33 @@ export type components = { * @enum {string} */ scheduler?: "ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc"; - /** Control */ - control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][]; - /** - * IP-Adapter - * @description IP-Adapter to apply - */ - ip_adapter?: components["schemas"]["IPAdapterField"] | components["schemas"]["IPAdapterField"][]; - /** - * T2I-Adapter - * @description T2I-Adapter(s) to apply - */ - t2i_adapter?: components["schemas"]["T2IAdapterField"] | components["schemas"]["T2IAdapterField"][]; - /** - * Latents - * @description Latents tensor - */ - latents?: components["schemas"]["LatentsField"]; - /** - * Denoise Mask - * @description The mask to use for the operation - */ - denoise_mask?: components["schemas"]["DenoiseMaskField"]; - /** - * Type - * @default denoise_latents - * @enum {string} - */ - type: "denoise_latents"; - /** - * Positive Conditioning - * @description Positive conditioning tensor - */ - positive_conditioning?: components["schemas"]["ConditioningField"]; - /** - * Negative Conditioning - * @description Negative conditioning tensor - */ - negative_conditioning?: components["schemas"]["ConditioningField"]; /** * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; + /** Control */ + control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][] | null; + /** + * IP-Adapter + * @description IP-Adapter to apply + */ + ip_adapter?: components["schemas"]["IPAdapterField"] | components["schemas"]["IPAdapterField"][] | null; + /** + * T2I-Adapter + * @description T2I-Adapter(s) to apply + */ + t2i_adapter?: components["schemas"]["T2IAdapterField"] | components["schemas"]["T2IAdapterField"][] | null; + /** @description Latents tensor */ + latents?: components["schemas"]["LatentsField"] | null; + /** @description The mask to use for the operation */ + denoise_mask?: components["schemas"]["DenoiseMaskField"] | null; + /** + * type + * @default denoise_latents + * @constant + */ + type: "denoise_latents"; }; /** * DenoiseMaskField @@ -2478,22 +2269,19 @@ export type components = { * Masked Latents Name * @description The name of the masked image latents */ - masked_latents_name?: string; + masked_latents_name: string | null; }; /** * DenoiseMaskOutput * @description Base class for nodes that output a single image */ DenoiseMaskOutput: { - /** - * Denoise Mask - * @description Mask for denoise model run - */ + /** @description Mask for denoise model run */ denoise_mask: components["schemas"]["DenoiseMaskField"]; /** - * Type + * type * @default denoise_mask_output - * @enum {string} + * @constant */ type: "denoise_mask_output"; }; @@ -2512,18 +2300,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * A * @description The first number @@ -2537,9 +2325,9 @@ export type components = { */ b?: number; /** - * Type + * type * @default div - * @enum {string} + * @constant */ type: "div"; }; @@ -2558,18 +2346,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default false */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Prompt * @description The prompt to parse with dynamicprompts @@ -2588,9 +2376,9 @@ export type components = { */ combinatorial?: boolean; /** - * Type + * type * @default dynamic_prompt - * @enum {string} + * @constant */ type: "dynamic_prompt"; }; @@ -2599,7 +2387,7 @@ export type components = { /** Prompts */ prompts: string[]; /** Error */ - error?: string; + error?: string | null; }; /** * Upscale (RealESRGAN) @@ -2616,22 +2404,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The input image - */ + use_cache?: boolean | null; + /** @description The input image */ image?: components["schemas"]["ImageField"]; /** * Model Name @@ -2647,23 +2432,17 @@ export type components = { */ tile_size?: number; /** - * Type + * type * @default esrgan - * @enum {string} + * @constant */ type: "esrgan"; }; /** Edge */ Edge: { - /** - * Source - * @description The connection for the edge's from node and field - */ + /** @description The connection for the edge's from node and field */ source: components["schemas"]["EdgeConnection"]; - /** - * Destination - * @description The connection for the edge's to node and field - */ + /** @description The connection for the edge's to node and field */ destination: components["schemas"]["EdgeConnection"]; }; /** EdgeConnection */ @@ -2696,10 +2475,7 @@ export type components = { * @description The total number of queue items requested to be enqueued */ requested: number; - /** - * Batch - * @description The batch that was enqueued - */ + /** @description The batch that was enqueued */ batch: components["schemas"]["Batch"]; /** * Priority @@ -2719,20 +2495,14 @@ export type components = { * @description The total number of queue items requested to be enqueued */ requested: number; - /** - * Batch - * @description The batch that was enqueued - */ + /** @description The batch that was enqueued */ batch: components["schemas"]["Batch"]; /** * Priority * @description The priority of the enqueued batch */ priority: number; - /** - * Queue Item - * @description The queue item that was enqueued - */ + /** @description The queue item that was enqueued */ queue_item: components["schemas"]["SessionQueueItemDTO"]; }; /** @@ -2750,22 +2520,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description Image to face detect - */ + use_cache?: boolean | null; + /** @description Image to face detect */ image?: components["schemas"]["ImageField"]; /** * Minimum Confidence @@ -2780,9 +2547,9 @@ export type components = { */ chunk?: boolean; /** - * Type + * type * @default face_identifier - * @enum {string} + * @constant */ type: "face_identifier"; }; @@ -2801,22 +2568,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description Image to face detect - */ + use_cache?: boolean | null; + /** @description Image to face detect */ image?: components["schemas"]["ImageField"]; /** * Face Ids @@ -2855,9 +2619,9 @@ export type components = { */ invert_mask?: boolean; /** - * Type + * type * @default face_mask_detection - * @enum {string} + * @constant */ type: "face_mask_detection"; }; @@ -2866,10 +2630,7 @@ export type components = { * @description Base class for FaceMask output */ FaceMaskOutput: { - /** - * Image - * @description The output image - */ + /** @description The output image */ image: components["schemas"]["ImageField"]; /** * Width @@ -2882,15 +2643,12 @@ export type components = { */ height: number; /** - * Type + * type * @default face_mask_output - * @enum {string} + * @constant */ type: "face_mask_output"; - /** - * Mask - * @description The output mask - */ + /** @description The output mask */ mask: components["schemas"]["ImageField"]; }; /** @@ -2908,22 +2666,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description Image for face detection - */ + use_cache?: boolean | null; + /** @description Image for face detection */ image?: components["schemas"]["ImageField"]; /** * Face Id @@ -2962,9 +2717,9 @@ export type components = { */ chunk?: boolean; /** - * Type + * type * @default face_off - * @enum {string} + * @constant */ type: "face_off"; }; @@ -2973,10 +2728,7 @@ export type components = { * @description Base class for FaceOff Output */ FaceOffOutput: { - /** - * Image - * @description The output image - */ + /** @description The output image */ image: components["schemas"]["ImageField"]; /** * Width @@ -2989,15 +2741,12 @@ export type components = { */ height: number; /** - * Type + * type * @default face_off_output - * @enum {string} + * @constant */ type: "face_off_output"; - /** - * Mask - * @description The output mask - */ + /** @description The output mask */ mask: components["schemas"]["ImageField"]; /** * X @@ -3025,27 +2774,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of float values */ collection?: number[]; /** - * Type + * type * @default float_collection - * @enum {string} + * @constant */ type: "float_collection"; }; @@ -3060,9 +2809,9 @@ export type components = { */ collection: number[]; /** - * Type + * type * @default float_collection_output - * @enum {string} + * @constant */ type: "float_collection_output"; }; @@ -3081,18 +2830,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The float value @@ -3100,9 +2849,9 @@ export type components = { */ value?: number; /** - * Type + * type * @default float - * @enum {string} + * @constant */ type: "float"; }; @@ -3121,18 +2870,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Start * @description The first value of the range @@ -3152,9 +2901,9 @@ export type components = { */ steps?: number; /** - * Type + * type * @default float_range - * @enum {string} + * @constant */ type: "float_range"; }; @@ -3173,18 +2922,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Operation * @description The operation to perform @@ -3205,9 +2954,9 @@ export type components = { */ b?: number; /** - * Type + * type * @default float_math - * @enum {string} + * @constant */ type: "float_math"; }; @@ -3222,9 +2971,9 @@ export type components = { */ value: number; /** - * Type + * type * @default float_output - * @enum {string} + * @constant */ type: "float_output"; }; @@ -3243,18 +2992,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The value to round @@ -3275,9 +3024,9 @@ export type components = { */ method?: "Nearest" | "Floor" | "Ceiling" | "Truncate"; /** - * Type + * type * @default float_to_int - * @enum {string} + * @constant */ type: "float_to_int"; }; @@ -3293,7 +3042,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"]; + [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 @@ -3311,15 +3060,9 @@ export type components = { * @description The id of the execution state */ id: string; - /** - * Graph - * @description The graph being executed - */ + /** @description The graph being executed */ graph: components["schemas"]["Graph"]; - /** - * Execution Graph - * @description The expanded graph of activated and executed nodes - */ + /** @description The expanded graph of activated and executed nodes */ execution_graph: components["schemas"]["Graph"]; /** * Executed @@ -3336,7 +3079,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["BooleanOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["String2Output"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"]; + [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 @@ -3375,41 +3118,33 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Graph - * @description The graph to run - */ + use_cache?: boolean | null; + /** @description The graph to run */ graph?: components["schemas"]["Graph"]; /** - * Type + * type * @default graph - * @enum {string} + * @constant */ type: "graph"; }; - /** - * GraphInvocationOutput - * @description Base class for all invocation outputs. - * - * All invocation outputs must use the `@invocation_output` decorator to provide their unique type. - */ + /** GraphInvocationOutput */ GraphInvocationOutput: { /** - * Type + * type * @default graph_output - * @enum {string} + * @constant */ type: "graph_output"; }; @@ -3433,29 +3168,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default hed_image_processor - * @enum {string} - */ - type: "hed_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -3474,23 +3200,20 @@ export type components = { * @default false */ scribble?: boolean; + /** + * type + * @default hed_image_processor + * @constant + */ + type: "hed_image_processor"; }; /** IPAdapterField */ IPAdapterField: { - /** - * Image - * @description The IP-Adapter image prompt. - */ + /** @description The IP-Adapter image prompt. */ image: components["schemas"]["ImageField"]; - /** - * Ip Adapter Model - * @description The IP-Adapter model to use. - */ + /** @description The IP-Adapter model to use. */ ip_adapter_model: components["schemas"]["IPAdapterModelField"]; - /** - * Image Encoder Model - * @description The name of the CLIP image encoder model. - */ + /** @description The name of the CLIP image encoder model. */ image_encoder_model: components["schemas"]["CLIPVisionModelField"]; /** * Weight @@ -3526,22 +3249,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The IP-Adapter image prompt. - */ + use_cache?: boolean | null; + /** @description The IP-Adapter image prompt. */ image?: components["schemas"]["ImageField"]; /** * IP-Adapter Model @@ -3567,23 +3287,17 @@ export type components = { */ end_step_percent?: number; /** - * Type + * type * @default ip_adapter - * @enum {string} + * @constant */ type: "ip_adapter"; }; /** IPAdapterMetadataField */ IPAdapterMetadataField: { - /** - * Image - * @description The IP-Adapter image prompt. - */ + /** @description The IP-Adapter image prompt. */ image: components["schemas"]["ImageField"]; - /** - * Ip Adapter Model - * @description The IP-Adapter model to use. - */ + /** @description The IP-Adapter model to use. */ ip_adapter_model: components["schemas"]["IPAdapterModelField"]; /** * Weight @@ -3620,26 +3334,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default ip_adapter + * @constant */ model_type: "ip_adapter"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "invokeai"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; - /** - * IPAdapterOutput - * @description Base class for all invocation outputs. - * - * All invocation outputs must use the `@invocation_output` decorator to provide their unique type. - */ + /** IPAdapterOutput */ IPAdapterOutput: { /** * IP-Adapter @@ -3647,9 +3357,9 @@ export type components = { */ ip_adapter: components["schemas"]["IPAdapterField"]; /** - * Type + * type * @default ip_adapter_output - * @enum {string} + * @constant */ type: "ip_adapter_output"; }; @@ -3668,22 +3378,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to blur - */ + use_cache?: boolean | null; + /** @description The image to blur */ image?: components["schemas"]["ImageField"]; /** * Radius @@ -3699,9 +3406,9 @@ export type components = { */ blur_type?: "gaussian" | "box"; /** - * Type + * type * @default img_blur - * @enum {string} + * @constant */ type: "img_blur"; }; @@ -3732,22 +3439,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to get the channel from - */ + use_cache?: boolean | null; + /** @description The image to get the channel from */ image?: components["schemas"]["ImageField"]; /** * Channel @@ -3757,9 +3461,9 @@ export type components = { */ channel?: "A" | "R" | "G" | "B"; /** - * Type + * type * @default img_chan - * @enum {string} + * @constant */ type: "img_chan"; }; @@ -3778,22 +3482,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to adjust - */ + use_cache?: boolean | null; + /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** * Channel @@ -3814,9 +3515,9 @@ export type components = { */ invert_channel?: boolean; /** - * Type + * type * @default img_channel_multiply - * @enum {string} + * @constant */ type: "img_channel_multiply"; }; @@ -3835,22 +3536,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to adjust - */ + use_cache?: boolean | null; + /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** * Channel @@ -3865,9 +3563,9 @@ export type components = { */ offset?: number; /** - * Type + * type * @default img_channel_offset - * @enum {string} + * @constant */ type: "img_channel_offset"; }; @@ -3886,27 +3584,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of image values */ collection?: components["schemas"]["ImageField"][]; /** - * Type + * type * @default image_collection - * @enum {string} + * @constant */ type: "image_collection"; }; @@ -3921,9 +3619,9 @@ export type components = { */ collection: components["schemas"]["ImageField"][]; /** - * Type + * type * @default image_collection_output - * @enum {string} + * @constant */ type: "image_collection_output"; }; @@ -3942,22 +3640,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to convert - */ + use_cache?: boolean | null; + /** @description The image to convert */ image?: components["schemas"]["ImageField"]; /** * Mode @@ -3967,9 +3662,9 @@ export type components = { */ mode?: "L" | "RGB" | "RGBA" | "CMYK" | "YCbCr" | "LAB" | "HSV" | "I" | "F"; /** - * Type + * type * @default img_conv - * @enum {string} + * @constant */ type: "img_conv"; }; @@ -3988,22 +3683,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to crop - */ + use_cache?: boolean | null; + /** @description The image to crop */ image?: components["schemas"]["ImageField"]; /** * X @@ -4030,9 +3722,9 @@ export type components = { */ height?: number; /** - * Type + * type * @default img_crop - * @enum {string} + * @constant */ type: "img_crop"; }; @@ -4084,7 +3776,7 @@ export type components = { * Deleted At * @description The deleted timestamp of the image. */ - deleted_at?: string; + deleted_at?: string | null; /** * Is Intermediate * @description Whether this is an intermediate image. @@ -4094,12 +3786,12 @@ export type components = { * Session Id * @description The session ID that generated this image, if it is a generated image. */ - session_id?: string; + session_id?: string | null; /** * Node Id * @description The node ID that generated this image, if it is a generated image. */ - node_id?: string; + node_id?: string | null; /** * Starred * @description Whether this image is starred. @@ -4109,7 +3801,7 @@ export type components = { * Board Id * @description The id of the board the image belongs to, if one exists. */ - board_id?: string; + board_id?: string | null; }; /** * ImageField @@ -4137,22 +3829,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to adjust - */ + use_cache?: boolean | null; + /** @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** * Hue @@ -4161,9 +3850,9 @@ export type components = { */ hue?: number; /** - * Type + * type * @default img_hue_adjust - * @enum {string} + * @constant */ type: "img_hue_adjust"; }; @@ -4182,22 +3871,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to lerp - */ + use_cache?: boolean | null; + /** @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** * Min @@ -4212,9 +3898,9 @@ export type components = { */ max?: number; /** - * Type + * type * @default img_ilerp - * @enum {string} + * @constant */ type: "img_ilerp"; }; @@ -4233,27 +3919,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to load - */ + use_cache?: boolean | null; + /** @description The image to load */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default image - * @enum {string} + * @constant */ type: "image"; }; @@ -4272,22 +3955,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to lerp - */ + use_cache?: boolean | null; + /** @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** * Min @@ -4302,9 +3982,9 @@ export type components = { */ max?: number; /** - * Type + * type * @default img_lerp - * @enum {string} + * @constant */ type: "img_lerp"; }; @@ -4317,12 +3997,12 @@ export type components = { * Metadata * @description The image's core metadata, if it was created in the Linear or Canvas UI */ - metadata?: Record; + metadata?: Record | null; /** * Graph * @description The graph that created the image */ - graph?: Record; + graph?: Record | null; }; /** * Multiply Images @@ -4339,32 +4019,26 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image1 - * @description The first image to multiply - */ + use_cache?: boolean | null; + /** @description The first image to multiply */ image1?: components["schemas"]["ImageField"]; - /** - * Image2 - * @description The second image to multiply - */ + /** @description The second image to multiply */ image2?: components["schemas"]["ImageField"]; /** - * Type + * type * @default img_mul - * @enum {string} + * @constant */ type: "img_mul"; }; @@ -4383,44 +4057,35 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; + /** @description The image to check */ + image?: components["schemas"]["ImageField"]; + /** @description Optional core metadata to be written to image */ + metadata?: components["schemas"]["CoreMetadata"] | null; /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default img_nsfw - * @enum {string} + * @constant */ type: "img_nsfw"; - /** - * Image - * @description The image to check - */ - image?: components["schemas"]["ImageField"]; }; /** * ImageOutput * @description Base class for nodes that output a single image */ ImageOutput: { - /** - * Image - * @description The output image - */ + /** @description The output image */ image: components["schemas"]["ImageField"]; /** * Width @@ -4433,9 +4098,9 @@ export type components = { */ height: number; /** - * Type + * type * @default image_output - * @enum {string} + * @constant */ type: "image_output"; }; @@ -4454,33 +4119,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Base Image - * @description The base image - */ + use_cache?: boolean | null; + /** @description The base image */ base_image?: components["schemas"]["ImageField"]; - /** - * Image - * @description The image to paste - */ + /** @description The image to paste */ image?: components["schemas"]["ImageField"]; - /** - * Mask - * @description The mask to use when pasting - */ - mask?: components["schemas"]["ImageField"]; + /** @description The mask to use when pasting */ + mask?: components["schemas"]["ImageField"] | null; /** * X * @description The left x coordinate at which to paste the image @@ -4500,51 +4156,12 @@ export type components = { */ crop?: boolean; /** - * Type + * type * @default img_paste - * @enum {string} + * @constant */ type: "img_paste"; }; - /** - * Base Image Processor - * @description Base class for invocations that preprocess images for ControlNet - */ - ImageProcessorInvocation: { - /** - * 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; - /** - * Workflow - * @description The workflow to save with the image - */ - workflow?: string; - /** - * Use Cache - * @description Whether or not to use the cache - * @default true - */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ - image?: components["schemas"]["ImageField"]; - /** - * Type - * @default image_processor - * @enum {string} - */ - type: "image_processor"; - }; /** * ImageRecordChanges * @description A set of changes to apply to an image record. @@ -4557,22 +4174,23 @@ export type components = { */ ImageRecordChanges: { /** @description The image's new category. */ - image_category?: components["schemas"]["ImageCategory"]; + image_category?: components["schemas"]["ImageCategory"] | null; /** * Session Id * @description The image's new session ID. */ - session_id?: string; + session_id?: string | null; /** * Is Intermediate * @description The image's new `is_intermediate` flag. */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Starred * @description The image's new `starred` state */ - starred?: boolean; + starred?: boolean | null; + [key: string]: unknown; }; /** * Resize Image @@ -4589,22 +4207,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to resize - */ + use_cache?: boolean | null; + /** @description The image to resize */ image?: components["schemas"]["ImageField"]; /** * Width @@ -4625,15 +4240,12 @@ 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; /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default img_resize - * @enum {string} + * @constant */ type: "img_resize"; }; @@ -4652,22 +4264,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to scale - */ + use_cache?: boolean | null; + /** @description The image to scale */ image?: components["schemas"]["ImageField"]; /** * Scale Factor @@ -4683,9 +4292,9 @@ export type components = { */ resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos"; /** - * Type + * type * @default img_scale - * @enum {string} + * @constant */ type: "img_scale"; }; @@ -4704,27 +4313,21 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to encode - */ + use_cache?: boolean | null; + /** @description The image to encode */ image?: components["schemas"]["ImageField"]; - /** - * Vae - * @description VAE - */ + /** @description VAE */ vae?: components["schemas"]["VaeField"]; /** * Tiled @@ -4739,9 +4342,9 @@ export type components = { */ fp32?: boolean; /** - * Type + * type * @default i2l - * @enum {string} + * @constant */ type: "i2l"; }; @@ -4781,22 +4384,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to check - */ + use_cache?: boolean | null; + /** @description The image to check */ image?: components["schemas"]["ImageField"]; /** * Text @@ -4804,15 +4404,12 @@ export type components = { * @default InvokeAI */ text?: string; + /** @description Optional core metadata to be written to image */ + metadata?: components["schemas"]["CoreMetadata"] | null; /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default img_watermark - * @enum {string} + * @constant */ type: "img_watermark"; }; @@ -4822,7 +4419,7 @@ export type components = { * Response * @description If defined, the message to display to the user when images begin downloading */ - response?: string; + response: string | null; }; /** ImagesUpdatedFromListResult */ ImagesUpdatedFromListResult: { @@ -4847,38 +4444,34 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to infill - */ + use_cache?: boolean | null; + /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** - * Color * @description The color to use to infill * @default { - * "r": 127, - * "g": 127, + * "a": 255, * "b": 127, - * "a": 255 + * "g": 127, + * "r": 127 * } */ color?: components["schemas"]["ColorField"]; /** - * Type + * type * @default infill_rgba - * @enum {string} + * @constant */ type: "infill_rgba"; }; @@ -4897,22 +4490,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to infill - */ + use_cache?: boolean | null; + /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** * Downscale @@ -4928,9 +4518,9 @@ export type components = { */ resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos"; /** - * Type + * type * @default infill_patchmatch - * @enum {string} + * @constant */ type: "infill_patchmatch"; }; @@ -4949,22 +4539,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to infill - */ + use_cache?: boolean | null; + /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** * Tile Size @@ -4978,9 +4565,9 @@ export type components = { */ seed?: number; /** - * Type + * type * @default infill_tile - * @enum {string} + * @constant */ type: "infill_tile"; }; @@ -4999,27 +4586,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of integer values */ collection?: number[]; /** - * Type + * type * @default integer_collection - * @enum {string} + * @constant */ type: "integer_collection"; }; @@ -5034,9 +4621,9 @@ export type components = { */ collection: number[]; /** - * Type + * type * @default integer_collection_output - * @enum {string} + * @constant */ type: "integer_collection_output"; }; @@ -5055,18 +4642,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The integer value @@ -5074,9 +4661,9 @@ export type components = { */ value?: number; /** - * Type + * type * @default integer - * @enum {string} + * @constant */ type: "integer"; }; @@ -5095,18 +4682,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Operation * @description The operation to perform @@ -5127,9 +4714,9 @@ export type components = { */ b?: number; /** - * Type + * type * @default integer_math - * @enum {string} + * @constant */ type: "integer_math"; }; @@ -5144,9 +4731,9 @@ export type components = { */ value: number; /** - * Type + * type * @default integer_output - * @enum {string} + * @constant */ type: "integer_output"; }; @@ -5193,18 +4780,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The list of items to iterate over @@ -5217,9 +4804,9 @@ export type components = { */ index?: number; /** - * Type + * type * @default iterate - * @enum {string} + * @constant */ type: "iterate"; }; @@ -5232,11 +4819,11 @@ export type components = { * Collection Item * @description The item being iterated over */ - item?: unknown; + item: unknown; /** - * Type + * type * @default iterate_output - * @enum {string} + * @constant */ type: "iterate_output"; }; @@ -5255,27 +4842,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to infill - */ + use_cache?: boolean | null; + /** @description The image to infill */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default infill_lama - * @enum {string} + * @constant */ type: "infill_lama"; }; @@ -5294,27 +4878,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of latents tensors */ collection?: components["schemas"]["LatentsField"][]; /** - * Type + * type * @default latents_collection - * @enum {string} + * @constant */ type: "latents_collection"; }; @@ -5329,9 +4913,9 @@ export type components = { */ collection: components["schemas"]["LatentsField"][]; /** - * Type + * type * @default latents_collection_output - * @enum {string} + * @constant */ type: "latents_collection_output"; }; @@ -5349,7 +4933,7 @@ export type components = { * Seed * @description Seed used to generate this latents */ - seed?: number; + seed?: number | null; }; /** * Latents Primitive @@ -5366,27 +4950,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Latents - * @description The latents tensor - */ + use_cache?: boolean | null; + /** @description The latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Type + * type * @default latents - * @enum {string} + * @constant */ type: "latents"; }; @@ -5395,10 +4976,7 @@ export type components = { * @description Base class for nodes that output a single latents tensor */ LatentsOutput: { - /** - * Latents - * @description Latents tensor - */ + /** @description Latents tensor */ latents: components["schemas"]["LatentsField"]; /** * Width @@ -5411,9 +4989,9 @@ export type components = { */ height: number; /** - * Type + * type * @default latents_output - * @enum {string} + * @constant */ type: "latents_output"; }; @@ -5432,18 +5010,22 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; + /** @description Latents tensor */ + latents?: components["schemas"]["LatentsField"]; + /** @description VAE */ + vae?: components["schemas"]["VaeField"]; /** * Tiled * @description Processing using overlapping tiles (reduce memory consumption) @@ -5456,27 +5038,14 @@ export type components = { * @default false */ fp32?: boolean; + /** @description Optional core metadata to be written to image */ + metadata?: components["schemas"]["CoreMetadata"] | null; /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default l2i - * @enum {string} + * @constant */ type: "l2i"; - /** - * Latents - * @description Latents tensor - */ - latents?: components["schemas"]["LatentsField"]; - /** - * Vae - * @description VAE - */ - vae?: components["schemas"]["VaeField"]; }; /** * Leres (Depth) Processor @@ -5493,29 +5062,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default leres_image_processor - * @enum {string} - */ - type: "leres_image_processor"; /** * Thr A * @description Leres parameter `thr_a` @@ -5546,6 +5106,12 @@ export type components = { * @default 512 */ image_resolution?: number; + /** + * type + * @default leres_image_processor + * @constant + */ + type: "leres_image_processor"; }; /** * Lineart Anime Processor @@ -5562,29 +5128,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default lineart_anime_image_processor - * @enum {string} - */ - type: "lineart_anime_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -5597,6 +5154,12 @@ export type components = { * @default 512 */ image_resolution?: number; + /** + * type + * @default lineart_anime_image_processor + * @constant + */ + type: "lineart_anime_image_processor"; }; /** * Lineart Processor @@ -5613,29 +5176,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default lineart_image_processor - * @enum {string} - */ - type: "lineart_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -5654,16 +5208,19 @@ export type components = { * @default false */ coarse?: boolean; + /** + * type + * @default lineart_image_processor + * @constant + */ + type: "lineart_image_processor"; }; /** * LoRAMetadataField * @description LoRA metadata for an image generated in InvokeAI. */ LoRAMetadataField: { - /** - * Lora - * @description The LoRA model - */ + /** @description The LoRA model */ lora: components["schemas"]["LoRAModelField"]; /** * Weight @@ -5678,15 +5235,16 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default lora + * @constant */ model_type: "lora"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; model_format: components["schemas"]["LoRAModelFormat"]; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** * LoRAModelField @@ -5703,13 +5261,11 @@ export type components = { }; /** * LoRAModelFormat - * @description An enumeration. * @enum {string} */ LoRAModelFormat: "lycoris" | "diffusers"; /** * LogLevel - * @description An enumeration. * @enum {integer} */ LogLevel: 0 | 10 | 20 | 30 | 40 | 50; @@ -5725,7 +5281,7 @@ export type components = { /** @description Info to load submodel */ model_type: components["schemas"]["ModelType"]; /** @description Info to load submodel */ - submodel?: components["schemas"]["SubModelType"]; + submodel?: components["schemas"]["SubModelType"] | null; /** * Weight * @description Lora's weight which to use when apply to model @@ -5747,18 +5303,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * LoRA * @description LoRA model to load @@ -5774,16 +5330,16 @@ export type components = { * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip?: components["schemas"]["ClipField"]; + clip?: components["schemas"]["ClipField"] | null; /** - * Type + * type * @default lora_loader - * @enum {string} + * @constant */ type: "lora_loader"; }; @@ -5796,16 +5352,16 @@ export type components = { * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip?: components["schemas"]["ClipField"]; + clip?: components["schemas"]["ClipField"] | null; /** - * Type + * type * @default lora_loader_output - * @enum {string} + * @constant */ type: "lora_loader_output"; }; @@ -5839,27 +5395,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Model - * @description Main model (UNet, VAE, CLIP) to load - */ + use_cache?: boolean | null; + /** @description Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["MainModelField"]; /** - * Type + * type * @default main_model_loader - * @enum {string} + * @constant */ type: "main_model_loader"; }; @@ -5878,32 +5431,26 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Mask1 - * @description The first mask to combine - */ + use_cache?: boolean | null; + /** @description The first mask to combine */ mask1?: components["schemas"]["ImageField"]; - /** - * Mask2 - * @description The second image to combine - */ + /** @description The second image to combine */ mask2?: components["schemas"]["ImageField"]; /** - * Type + * type * @default mask_combine - * @enum {string} + * @constant */ type: "mask_combine"; }; @@ -5922,22 +5469,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to apply the mask to - */ + use_cache?: boolean | null; + /** @description The image to apply the mask to */ image?: components["schemas"]["ImageField"]; /** * Edge Size @@ -5960,9 +5504,9 @@ export type components = { */ high_threshold?: number; /** - * Type + * type * @default mask_edge - * @enum {string} + * @constant */ type: "mask_edge"; }; @@ -5981,22 +5525,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to create the mask from - */ + use_cache?: boolean | null; + /** @description The image to create the mask from */ image?: components["schemas"]["ImageField"]; /** * Invert @@ -6005,9 +5546,9 @@ export type components = { */ invert?: boolean; /** - * Type + * type * @default tomask - * @enum {string} + * @constant */ type: "tomask"; }; @@ -6026,29 +5567,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default mediapipe_face_processor - * @enum {string} - */ - type: "mediapipe_face_processor"; /** * Max Faces * @description Maximum number of faces to detect @@ -6061,13 +5593,50 @@ export type components = { * @default 0.5 */ min_confidence?: number; + /** + * type + * @default mediapipe_face_processor + * @constant + */ + type: "mediapipe_face_processor"; }; /** * MergeInterpolationMethod - * @description An enumeration. * @enum {string} */ MergeInterpolationMethod: "weighted_sum" | "sigmoid" | "inv_sigmoid" | "add_difference"; + /** MergeModelsBody */ + MergeModelsBody: { + /** + * Model Names + * @description model name + */ + model_names: string[]; + /** + * Merged Model Name + * @description Name of destination model + */ + merged_model_name: string | null; + /** + * Alpha + * @description Alpha weighting strength to apply to 2d and 3d models + * @default 0.5 + */ + alpha?: number | null; + /** @description Interpolation method */ + interp: components["schemas"]["MergeInterpolationMethod"] | null; + /** + * Force + * @description Force merging of models created with different versions of diffusers + * @default false + */ + force?: boolean | null; + /** + * Merge Dest Directory + * @description Save the merged model to the designated directory (with 'merged_model_name' appended) + */ + merge_dest_directory?: string | null; + }; /** * Metadata Accumulator * @description Outputs a Core Metadata Object @@ -6083,162 +5652,168 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Generation Mode * @description The generation mode that output this image */ - generation_mode?: string; + generation_mode?: string | null; /** * Positive Prompt * @description The positive prompt parameter */ - positive_prompt?: string; + positive_prompt?: string | null; /** * Negative Prompt * @description The negative prompt parameter */ - negative_prompt?: string; + negative_prompt?: string | null; /** * Width * @description The width parameter */ - width?: number; + width?: number | null; /** * Height * @description The height parameter */ - height?: number; + height?: number | null; /** * Seed * @description The seed used for noise generation */ - seed?: number; + seed?: number | null; /** * Rand Device * @description The device used for random number generation */ - rand_device?: string; + rand_device?: string | null; /** * Cfg Scale * @description The classifier-free guidance scale parameter */ - cfg_scale?: number; + cfg_scale?: number | null; /** * Steps * @description The number of steps used for inference */ - steps?: number; + steps?: number | null; /** * Scheduler * @description The scheduler used for inference */ - scheduler?: string; + scheduler?: string | null; /** * Clip Skip * @description The number of skipped CLIP layers */ - clip_skip?: number; - /** - * Model - * @description The main model used for inference - */ - model?: components["schemas"]["MainModelField"]; + 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"][]; + controlnets?: components["schemas"]["ControlField"][] | null; /** * Ipadapters * @description The IP Adapters used for inference */ - ipAdapters?: components["schemas"]["IPAdapterMetadataField"][]; + ipAdapters?: components["schemas"]["IPAdapterMetadataField"][] | null; /** * T2Iadapters * @description The IP Adapters used for inference */ - t2iAdapters: components["schemas"]["T2IAdapterField"][]; + t2iAdapters?: components["schemas"]["T2IAdapterField"][] | null; /** * Loras * @description The LoRAs used for inference */ - loras?: components["schemas"]["LoRAMetadataField"][]; + loras?: components["schemas"]["LoRAMetadataField"][] | null; /** * Strength * @description The strength used for latents-to-latents */ - strength?: number; + strength?: number | null; /** * Init Image * @description The name of the initial image */ - init_image?: string; + init_image?: string | null; + /** @description The VAE used for decoding, if the main model's default was not used */ + vae?: components["schemas"]["VAEModelField"] | null; /** - * Vae - * @description The VAE used for decoding, if the main model's default was not used + * Hrf Width + * @description The high resolution fix height and width multipler. */ - vae?: components["schemas"]["VAEModelField"]; + 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; + positive_style_prompt?: string | null; /** * Negative Style Prompt * @description The negative style prompt parameter */ - negative_style_prompt?: string; - /** - * Refiner Model - * @description The SDXL Refiner model used - */ - refiner_model?: components["schemas"]["MainModelField"]; + 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; + refiner_cfg_scale?: number | null; /** * Refiner Steps * @description The number of steps used for the refiner */ - refiner_steps?: number; + refiner_steps?: number | null; /** * Refiner Scheduler * @description The scheduler used for the refiner */ - refiner_scheduler?: string; + refiner_scheduler?: string | null; /** * Refiner Positive Aesthetic Score * @description The aesthetic score used for the refiner */ - refiner_positive_aesthetic_score?: number; + refiner_positive_aesthetic_score?: number | null; /** * Refiner Negative Aesthetic Score * @description The aesthetic score used for the refiner */ - refiner_negative_aesthetic_score?: number; + refiner_negative_aesthetic_score?: number | null; /** * Refiner Start * @description The start value used for refiner denoising */ - refiner_start?: number; + refiner_start?: number | null; /** - * Type + * type * @default metadata_accumulator - * @enum {string} + * @constant */ type: "metadata_accumulator"; }; @@ -6247,15 +5822,12 @@ export type components = { * @description The output of the MetadataAccumulator node */ MetadataAccumulatorOutput: { - /** - * Metadata - * @description The core metadata for the image - */ + /** @description The core metadata for the image */ metadata: components["schemas"]["CoreMetadata"]; /** - * Type + * type * @default metadata_accumulator_output - * @enum {string} + * @constant */ type: "metadata_accumulator_output"; }; @@ -6274,29 +5846,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default midas_depth_image_processor - * @enum {string} - */ - type: "midas_depth_image_processor"; /** * A Mult * @description Midas parameter `a_mult` (a = a_mult * PI) @@ -6309,6 +5872,12 @@ export type components = { * @default 0.1 */ bg_th?: number; + /** + * type + * @default midas_depth_image_processor + * @constant + */ + type: "midas_depth_image_processor"; }; /** * MLSD Processor @@ -6325,29 +5894,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default mlsd_image_processor - * @enum {string} - */ - type: "mlsd_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -6372,11 +5932,16 @@ export type components = { * @default 0.1 */ thr_d?: number; + /** + * type + * @default mlsd_image_processor + * @constant + */ + type: "mlsd_image_processor"; }; /** * ModelError - * @description An enumeration. - * @enum {string} + * @constant */ ModelError: "not_found"; /** ModelInfo */ @@ -6391,7 +5956,7 @@ export type components = { /** @description Info to load submodel */ model_type: components["schemas"]["ModelType"]; /** @description Info to load submodel */ - submodel?: components["schemas"]["SubModelType"]; + submodel?: components["schemas"]["SubModelType"] | null; }; /** * ModelLoaderOutput @@ -6414,21 +5979,19 @@ export type components = { */ vae: components["schemas"]["VaeField"]; /** - * Type + * type * @default model_loader_output - * @enum {string} + * @constant */ type: "model_loader_output"; }; /** * ModelType - * @description An enumeration. * @enum {string} */ ModelType: "onnx" | "main" | "vae" | "lora" | "controlnet" | "embedding" | "ip_adapter" | "clip_vision" | "t2i_adapter"; /** * ModelVariantType - * @description An enumeration. * @enum {string} */ ModelVariantType: "normal" | "inpaint" | "depth"; @@ -6452,18 +6015,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * A * @description The first number @@ -6477,9 +6040,9 @@ export type components = { */ b?: number; /** - * Type + * type * @default mul - * @enum {string} + * @constant */ type: "mul"; }; @@ -6516,18 +6079,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Seed * @description Seed for random number generation @@ -6552,9 +6115,9 @@ export type components = { */ use_cpu?: boolean; /** - * Type + * type * @default noise - * @enum {string} + * @constant */ type: "noise"; }; @@ -6563,11 +6126,8 @@ export type components = { * @description Invocation noise output */ NoiseOutput: { - /** - * Noise - * @description Noise tensor - */ - noise?: components["schemas"]["LatentsField"]; + /** @description Noise tensor */ + noise: components["schemas"]["LatentsField"]; /** * Width * @description Width of output (px) @@ -6579,9 +6139,9 @@ export type components = { */ height: number; /** - * Type + * type * @default noise_output - * @enum {string} + * @constant */ type: "noise_output"; }; @@ -6600,29 +6160,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default normalbae_image_processor - * @enum {string} - */ - type: "normalbae_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -6635,6 +6186,12 @@ export type components = { * @default 512 */ image_resolution?: number; + /** + * type + * @default normalbae_image_processor + * @constant + */ + type: "normalbae_image_processor"; }; /** * ONNX Latents to Image @@ -6651,37 +6208,28 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Latents - * @description Denoised latents tensor - */ + use_cache?: boolean | null; + /** @description Denoised latents tensor */ latents?: components["schemas"]["LatentsField"]; - /** - * Vae - * @description VAE - */ + /** @description VAE */ vae?: components["schemas"]["VaeField"]; + /** @description Optional core metadata to be written to image */ + metadata?: components["schemas"]["CoreMetadata"] | null; /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default l2i_onnx - * @enum {string} + * @constant */ type: "l2i_onnx"; }; @@ -6711,19 +6259,13 @@ export type components = { */ vae_encoder?: components["schemas"]["VaeField"]; /** - * Type + * type * @default model_loader_output_onnx - * @enum {string} + * @constant */ type: "model_loader_output_onnx"; }; - /** - * ONNX Prompt (Raw) - * @description 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. - */ + /** ONNX Prompt (Raw) */ ONNXPromptInvocation: { /** * Id @@ -6735,33 +6277,30 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Prompt * @description Raw prompt text (no parsing) * @default */ prompt?: string; - /** - * Clip - * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count - */ + /** @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; /** - * Type + * type * @default prompt_onnx - * @enum {string} + * @constant */ type: "prompt_onnx"; }; @@ -6772,19 +6311,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default onnx + * @constant */ model_type: "onnx"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "onnx"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; variant: components["schemas"]["ModelVariantType"]; }; /** ONNXStableDiffusion2ModelConfig */ @@ -6794,19 +6334,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default onnx + * @constant */ model_type: "onnx"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "onnx"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; variant: components["schemas"]["ModelVariantType"]; prediction_type: components["schemas"]["SchedulerPredictionType"]; /** Upcast Attention */ @@ -6827,32 +6368,23 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Positive Conditioning - * @description Positive conditioning tensor - */ + use_cache?: boolean | null; + /** @description Positive conditioning tensor */ positive_conditioning?: components["schemas"]["ConditioningField"]; - /** - * Negative Conditioning - * @description Negative conditioning tensor - */ + /** @description Negative conditioning tensor */ negative_conditioning?: components["schemas"]["ConditioningField"]; - /** - * Noise - * @description Noise tensor - */ + /** @description Noise tensor */ noise?: components["schemas"]["LatentsField"]; /** * Steps @@ -6880,10 +6412,7 @@ export type components = { * @enum {string} */ precision?: "tensor(bool)" | "tensor(int8)" | "tensor(uint8)" | "tensor(int16)" | "tensor(uint16)" | "tensor(int32)" | "tensor(uint32)" | "tensor(int64)" | "tensor(uint64)" | "tensor(float16)" | "tensor(float)" | "tensor(double)"; - /** - * Unet - * @description UNet (scheduler, LoRAs) - */ + /** @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** * Control @@ -6891,17 +6420,13 @@ export type components = { */ control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][]; /** - * Type + * type * @default t2l_onnx - * @enum {string} + * @constant */ type: "t2l_onnx"; }; - /** - * OffsetPaginatedResults[BoardDTO] - * @description Offset-paginated results - * Generic must be a Pydantic model - */ + /** OffsetPaginatedResults[BoardDTO] */ OffsetPaginatedResults_BoardDTO_: { /** * Limit @@ -6924,11 +6449,7 @@ export type components = { */ items: components["schemas"]["BoardDTO"][]; }; - /** - * OffsetPaginatedResults[ImageDTO] - * @description Offset-paginated results - * Generic must be a Pydantic model - */ + /** OffsetPaginatedResults[ImageDTO] */ OffsetPaginatedResults_ImageDTO_: { /** * Limit @@ -6981,27 +6502,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Model - * @description ONNX Main model (UNet, VAE, CLIP) to load - */ + use_cache?: boolean | null; + /** @description ONNX Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["OnnxModelField"]; /** - * Type + * type * @default onnx_model_loader - * @enum {string} + * @constant */ type: "onnx_model_loader"; }; @@ -7020,29 +6538,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default openpose_image_processor - * @enum {string} - */ - type: "openpose_image_processor"; /** * Hand And Face * @description Whether to use hands and face mode @@ -7061,38 +6570,12 @@ export type components = { * @default 512 */ image_resolution?: number; - }; - /** - * PaginatedResults[GraphExecutionState] - * @description Paginated results - * Generic must be a Pydantic model - */ - PaginatedResults_GraphExecutionState_: { /** - * Page - * @description Current Page + * type + * @default openpose_image_processor + * @constant */ - page: number; - /** - * Pages - * @description Total number of pages - */ - pages: number; - /** - * Per Page - * @description Number of items per page - */ - per_page: number; - /** - * Total - * @description Total number of items in result - */ - total: number; - /** - * Items - * @description Items - */ - items: components["schemas"]["GraphExecutionState"][]; + type: "openpose_image_processor"; }; /** * PIDI Processor @@ -7109,29 +6592,20 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default pidi_image_processor - * @enum {string} - */ - type: "pidi_image_processor"; /** * Detect Resolution * @description Pixel resolution for detection @@ -7156,6 +6630,12 @@ export type components = { * @default false */ scribble?: boolean; + /** + * type + * @default pidi_image_processor + * @constant + */ + type: "pidi_image_processor"; }; /** * Prompts from File @@ -7172,18 +6652,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * File Path * @description Path to prompt text file @@ -7193,12 +6673,12 @@ export type components = { * Pre Prompt * @description String to prepend to each prompt */ - pre_prompt?: string; + pre_prompt?: string | null; /** * Post Prompt * @description String to append to each prompt */ - post_prompt?: string; + post_prompt?: string | null; /** * Start Line * @description Line in the file to start start from @@ -7212,9 +6692,9 @@ export type components = { */ max_prompts?: number; /** - * Type + * type * @default prompt_from_file - * @enum {string} + * @constant */ type: "prompt_from_file"; }; @@ -7244,18 +6724,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache - * @default true + * @default false */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Low * @description The inclusive low value @@ -7275,9 +6755,9 @@ export type components = { */ decimals?: number; /** - * Type + * type * @default rand_float - * @enum {string} + * @constant */ type: "rand_float"; }; @@ -7296,18 +6776,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default false */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Low * @description The inclusive low value @@ -7321,9 +6801,9 @@ export type components = { */ high?: number; /** - * Type + * type * @default rand_int - * @enum {string} + * @constant */ type: "rand_int"; }; @@ -7342,18 +6822,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default false */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Low * @description The inclusive low value @@ -7378,9 +6858,9 @@ export type components = { */ seed?: number; /** - * Type + * type * @default random_range - * @enum {string} + * @constant */ type: "random_range"; }; @@ -7399,18 +6879,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Start * @description The start of the range @@ -7430,9 +6910,9 @@ export type components = { */ step?: number; /** - * Type + * type * @default range - * @enum {string} + * @constant */ type: "range"; }; @@ -7451,18 +6931,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Start * @description The start of the range @@ -7482,9 +6962,9 @@ export type components = { */ step?: number; /** - * Type + * type * @default range_of_size - * @enum {string} + * @constant */ type: "range_of_size"; }; @@ -7511,22 +6991,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Latents - * @description Latents tensor - */ + use_cache?: boolean | null; + /** @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** * Width @@ -7552,9 +7029,9 @@ export type components = { */ antialias?: boolean; /** - * Type + * type * @default lresize - * @enum {string} + * @constant */ type: "lresize"; }; @@ -7583,18 +7060,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The float value @@ -7608,9 +7085,9 @@ export type components = { */ decimals?: number; /** - * Type + * type * @default round_float - * @enum {string} + * @constant */ type: "round_float"; }; @@ -7629,18 +7106,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Prompt * @description Prompt to be parsed by Compel to create a conditioning tensor @@ -7694,9 +7171,9 @@ export type components = { */ clip2?: components["schemas"]["ClipField"]; /** - * Type + * type * @default sdxl_compel_prompt - * @enum {string} + * @constant */ type: "sdxl_compel_prompt"; }; @@ -7715,18 +7192,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * LoRA * @description LoRA model to load @@ -7742,21 +7219,21 @@ export type components = { * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * CLIP 1 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip?: components["schemas"]["ClipField"]; + clip?: components["schemas"]["ClipField"] | null; /** * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip2?: components["schemas"]["ClipField"]; + clip2?: components["schemas"]["ClipField"] | null; /** - * Type + * type * @default sdxl_lora_loader - * @enum {string} + * @constant */ type: "sdxl_lora_loader"; }; @@ -7769,21 +7246,21 @@ export type components = { * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * CLIP 1 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip?: components["schemas"]["ClipField"]; + clip?: components["schemas"]["ClipField"] | null; /** * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ - clip2?: components["schemas"]["ClipField"]; + clip2?: components["schemas"]["ClipField"] | null; /** - * Type + * type * @default sdxl_lora_loader_output - * @enum {string} + * @constant */ type: "sdxl_lora_loader_output"; }; @@ -7802,27 +7279,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Model - * @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load - */ + use_cache?: boolean | null; + /** @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load */ model: components["schemas"]["MainModelField"]; /** - * Type + * type * @default sdxl_model_loader - * @enum {string} + * @constant */ type: "sdxl_model_loader"; }; @@ -7852,9 +7326,9 @@ export type components = { */ vae: components["schemas"]["VaeField"]; /** - * Type + * type * @default sdxl_model_loader_output - * @enum {string} + * @constant */ type: "sdxl_model_loader_output"; }; @@ -7873,18 +7347,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Style * @description Prompt to be parsed by Compel to create a conditioning tensor @@ -7917,15 +7391,12 @@ export type components = { * @default 6 */ aesthetic_score?: number; - /** - * Clip2 - * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count - */ + /** @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2?: components["schemas"]["ClipField"]; /** - * Type + * type * @default sdxl_refiner_compel_prompt - * @enum {string} + * @constant */ type: "sdxl_refiner_compel_prompt"; }; @@ -7944,27 +7415,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Model - * @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load - */ + use_cache?: boolean | null; + /** @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load */ model: components["schemas"]["MainModelField"]; /** - * Type + * type * @default sdxl_refiner_model_loader - * @enum {string} + * @constant */ type: "sdxl_refiner_model_loader"; }; @@ -7989,9 +7457,9 @@ export type components = { */ vae: components["schemas"]["VaeField"]; /** - * Type + * type * @default sdxl_refiner_model_loader_output - * @enum {string} + * @constant */ type: "sdxl_refiner_model_loader_output"; }; @@ -8010,37 +7478,28 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default false */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @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 - * @description The board to save the image to - */ - board?: components["schemas"]["BoardField"]; - /** - * Metadata - * @description Optional core metadata to be written to image - */ - metadata?: components["schemas"]["CoreMetadata"]; - /** - * Type + * type * @default save_image - * @enum {string} + * @constant */ type: "save_image"; }; @@ -8059,22 +7518,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Latents - * @description Latents tensor - */ + use_cache?: boolean | null; + /** @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** * Scale Factor @@ -8095,9 +7551,9 @@ export type components = { */ antialias?: boolean; /** - * Type + * type * @default lscale - * @enum {string} + * @constant */ type: "lscale"; }; @@ -8116,18 +7572,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Scheduler * @description Scheduler to use during inference @@ -8136,18 +7592,13 @@ export type components = { */ scheduler?: "ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc"; /** - * Type + * type * @default scheduler - * @enum {string} + * @constant */ type: "scheduler"; }; - /** - * SchedulerOutput - * @description Base class for all invocation outputs. - * - * All invocation outputs must use the `@invocation_output` decorator to provide their unique type. - */ + /** SchedulerOutput */ SchedulerOutput: { /** * Scheduler @@ -8156,15 +7607,14 @@ export type components = { */ scheduler: "ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc"; /** - * Type + * type * @default scheduler_output - * @enum {string} + * @constant */ type: "scheduler_output"; }; /** * SchedulerPredictionType - * @description An enumeration. * @enum {string} */ SchedulerPredictionType: "epsilon" | "v_prediction" | "sample"; @@ -8183,28 +7633,28 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * VAE * @description VAE model to load */ - vae?: components["schemas"]["VaeField"]; + vae?: components["schemas"]["VaeField"] | null; /** * Seamless Y * @description Specify whether Y axis is seamless @@ -8218,9 +7668,9 @@ export type components = { */ seamless_x?: boolean; /** - * Type + * type * @default seamless - * @enum {string} + * @constant */ type: "seamless"; }; @@ -8233,16 +7683,16 @@ export type components = { * UNet * @description UNet (scheduler, LoRAs) */ - unet?: components["schemas"]["UNetField"]; + unet?: components["schemas"]["UNetField"] | null; /** * VAE * @description VAE */ - vae?: components["schemas"]["VaeField"]; + vae?: components["schemas"]["VaeField"] | null; /** - * Type + * type * @default seamless_output - * @enum {string} + * @constant */ type: "seamless_output"; }; @@ -8261,27 +7711,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default segment_anything_processor - * @enum {string} + * @constant */ type: "segment_anything_processor"; }; @@ -8306,10 +7753,7 @@ export type components = { queue: components["schemas"]["SessionQueueStatus"]; processor: components["schemas"]["SessionProcessorStatus"]; }; - /** - * SessionQueueItem - * @description Session queue item without the full graph. Used for serialization. - */ + /** SessionQueueItem */ SessionQueueItem: { /** * Item Id @@ -8343,7 +7787,7 @@ export type components = { * Error * @description The error message if this queue item errored */ - error?: string; + error?: string | null; /** * Created At * @description When this queue item was created @@ -8358,12 +7802,12 @@ export type components = { * Started At * @description When this queue item was started */ - started_at?: string; + started_at?: string | null; /** * Completed At * @description When this queue item was completed */ - completed_at?: string; + completed_at?: string | null; /** * Queue Id * @description The id of the queue with which this item is associated @@ -8373,17 +7817,11 @@ export type components = { * Field Values * @description The field values that were used for this queue item */ - field_values?: components["schemas"]["NodeFieldValue"][]; - /** - * Session - * @description The fully-populated session to be executed - */ + field_values?: components["schemas"]["NodeFieldValue"][] | null; + /** @description The fully-populated session to be executed */ session: components["schemas"]["GraphExecutionState"]; }; - /** - * SessionQueueItemDTO - * @description Session queue item without the full graph. Used for serialization. - */ + /** SessionQueueItemDTO */ SessionQueueItemDTO: { /** * Item Id @@ -8417,7 +7855,7 @@ export type components = { * Error * @description The error message if this queue item errored */ - error?: string; + error?: string | null; /** * Created At * @description When this queue item was created @@ -8432,12 +7870,12 @@ export type components = { * Started At * @description When this queue item was started */ - started_at?: string; + started_at?: string | null; /** * Completed At * @description When this queue item was completed */ - completed_at?: string; + completed_at?: string | null; /** * Queue Id * @description The id of the queue with which this item is associated @@ -8447,7 +7885,7 @@ export type components = { * Field Values * @description The field values that were used for this queue item */ - field_values?: components["schemas"]["NodeFieldValue"][]; + field_values?: components["schemas"]["NodeFieldValue"][] | null; }; /** SessionQueueStatus */ SessionQueueStatus: { @@ -8460,17 +7898,17 @@ export type components = { * Item Id * @description The current queue item id */ - item_id?: number; + item_id: number | null; /** * Batch Id * @description The current queue item's batch id */ - batch_id?: string; + batch_id: string | null; /** * Session Id * @description The current queue item's session id */ - session_id?: string; + session_id: string | null; /** * Pending * @description Number of queue items with status 'pending' @@ -8517,27 +7955,24 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to show - */ + use_cache?: boolean | null; + /** @description The image to show */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default show_image - * @enum {string} + * @constant */ type: "show_image"; }; @@ -8548,21 +7983,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "checkpoint"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; /** Config */ config: string; variant: components["schemas"]["ModelVariantType"]; @@ -8574,21 +8010,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; variant: components["schemas"]["ModelVariantType"]; }; /** StableDiffusion2ModelCheckpointConfig */ @@ -8598,21 +8035,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "checkpoint"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; /** Config */ config: string; variant: components["schemas"]["ModelVariantType"]; @@ -8624,21 +8062,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; variant: components["schemas"]["ModelVariantType"]; }; /** StableDiffusionXLModelCheckpointConfig */ @@ -8648,21 +8087,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "checkpoint"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; /** Config */ config: string; variant: components["schemas"]["ModelVariantType"]; @@ -8674,21 +8114,22 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default main + * @constant */ model_type: "main"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; /** Vae */ - vae?: string; + vae?: string | null; variant: components["schemas"]["ModelVariantType"]; }; /** @@ -8706,18 +8147,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Easing * @description The easing function to use @@ -8759,12 +8200,12 @@ export type components = { * Pre Start Value * @description value before easing start */ - pre_start_value?: number; + pre_start_value?: number | null; /** * Post End Value * @description value after easing end */ - post_end_value?: number; + post_end_value?: number | null; /** * Mirror * @description include mirror of easing function @@ -8778,9 +8219,9 @@ export type components = { */ show_easing_plot?: boolean; /** - * Type + * type * @default step_param_easing - * @enum {string} + * @constant */ type: "step_param_easing"; }; @@ -8800,9 +8241,9 @@ export type components = { */ string_2: string; /** - * Type + * type * @default string_2_output - * @enum {string} + * @constant */ type: "string_2_output"; }; @@ -8821,27 +8262,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Collection * @description The collection of string values */ collection?: string[]; /** - * Type + * type * @default string_collection - * @enum {string} + * @constant */ type: "string_collection"; }; @@ -8856,9 +8297,9 @@ export type components = { */ collection: string[]; /** - * Type + * type * @default string_collection_output - * @enum {string} + * @constant */ type: "string_collection_output"; }; @@ -8877,18 +8318,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * Value * @description The string value @@ -8896,9 +8337,9 @@ export type components = { */ value?: string; /** - * Type + * type * @default string - * @enum {string} + * @constant */ type: "string"; }; @@ -8917,18 +8358,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * String Left * @description String Left @@ -8942,9 +8383,9 @@ export type components = { */ string_right?: string; /** - * Type + * type * @default string_join - * @enum {string} + * @constant */ type: "string_join"; }; @@ -8963,18 +8404,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * String Left * @description String Left @@ -8994,9 +8435,9 @@ export type components = { */ string_right?: string; /** - * Type + * type * @default string_join_three - * @enum {string} + * @constant */ type: "string_join_three"; }; @@ -9011,9 +8452,9 @@ export type components = { */ value: string; /** - * Type + * type * @default string_output - * @enum {string} + * @constant */ type: "string_output"; }; @@ -9033,9 +8474,9 @@ export type components = { */ negative_string: string; /** - * Type + * type * @default string_pos_neg_output - * @enum {string} + * @constant */ type: "string_pos_neg_output"; }; @@ -9054,18 +8495,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * String * @description String to work on @@ -9091,9 +8532,9 @@ export type components = { */ use_regex?: boolean; /** - * Type + * type * @default string_replace - * @enum {string} + * @constant */ type: "string_replace"; }; @@ -9112,18 +8553,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * String * @description String to split @@ -9137,9 +8578,9 @@ export type components = { */ delimiter?: string; /** - * Type + * type * @default string_split - * @enum {string} + * @constant */ type: "string_split"; }; @@ -9158,18 +8599,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * String * @description String to split @@ -9177,15 +8618,14 @@ export type components = { */ string?: string; /** - * Type + * type * @default string_split_neg - * @enum {string} + * @constant */ type: "string_split_neg"; }; /** * SubModelType - * @description An enumeration. * @enum {string} */ SubModelType: "unet" | "text_encoder" | "text_encoder_2" | "tokenizer" | "tokenizer_2" | "vae" | "vae_decoder" | "vae_encoder" | "scheduler" | "safety_checker"; @@ -9204,18 +8644,18 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * A * @description The first number @@ -9229,23 +8669,17 @@ export type components = { */ b?: number; /** - * Type + * type * @default sub - * @enum {string} + * @constant */ type: "sub"; }; /** T2IAdapterField */ T2IAdapterField: { - /** - * Image - * @description The T2I-Adapter image prompt. - */ + /** @description The T2I-Adapter image prompt. */ image: components["schemas"]["ImageField"]; - /** - * T2I Adapter Model - * @description The T2I-Adapter model to use. - */ + /** @description The T2I-Adapter model to use. */ t2i_adapter_model: components["schemas"]["T2IAdapterModelField"]; /** * Weight @@ -9288,22 +8722,19 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The IP-Adapter image prompt. - */ + use_cache?: boolean | null; + /** @description The IP-Adapter image prompt. */ image?: components["schemas"]["ImageField"]; /** * T2I-Adapter Model @@ -9336,9 +8767,9 @@ export type components = { */ resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple"; /** - * Type + * type * @default t2i_adapter - * @enum {string} + * @constant */ type: "t2i_adapter"; }; @@ -9349,19 +8780,20 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default t2i_adapter + * @constant */ model_type: "t2i_adapter"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** * Model Format - * @enum {string} + * @constant */ model_format: "diffusers"; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** T2IAdapterModelField */ T2IAdapterModelField: { @@ -9373,12 +8805,7 @@ export type components = { /** @description Base model */ base_model: components["schemas"]["BaseModelType"]; }; - /** - * T2IAdapterOutput - * @description Base class for all invocation outputs. - * - * All invocation outputs must use the `@invocation_output` decorator to provide their unique type. - */ + /** T2IAdapterOutput */ T2IAdapterOutput: { /** * T2I Adapter @@ -9386,9 +8813,9 @@ export type components = { */ t2i_adapter: components["schemas"]["T2IAdapterField"]; /** - * Type + * type * @default t2i_adapter_output - * @enum {string} + * @constant */ type: "t2i_adapter_output"; }; @@ -9399,16 +8826,17 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default embedding + * @constant */ model_type: "embedding"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; /** Model Format */ model_format: null; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** * Tile Resample Processor @@ -9425,47 +8853,38 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; - /** - * Type - * @default tile_image_processor - * @enum {string} - */ - type: "tile_image_processor"; /** * Down Sampling Rate * @description Down sampling rate * @default 1 */ down_sampling_rate?: number; + /** + * type + * @default tile_image_processor + * @constant + */ + type: "tile_image_processor"; }; /** UNetField */ UNetField: { - /** - * Unet - * @description Info to load unet submodel - */ + /** @description Info to load unet submodel */ unet: components["schemas"]["ModelInfo"]; - /** - * Scheduler - * @description Info to load scheduler submodel - */ + /** @description Info to load scheduler submodel */ scheduler: components["schemas"]["ModelInfo"]; /** * Loras @@ -9506,10 +8925,7 @@ export type components = { }; /** VaeField */ VaeField: { - /** - * Vae - * @description Info to load vae submodel - */ + /** @description Info to load vae submodel */ vae: components["schemas"]["ModelInfo"]; /** * Seamless Axes @@ -9532,27 +8948,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; + use_cache?: boolean | null; /** * VAE * @description VAE model to load */ vae_model: components["schemas"]["VAEModelField"]; /** - * Type + * type * @default vae_loader - * @enum {string} + * @constant */ type: "vae_loader"; }; @@ -9567,9 +8983,9 @@ export type components = { */ vae: components["schemas"]["VaeField"]; /** - * Type + * type * @default vae_loader_output - * @enum {string} + * @constant */ type: "vae_loader_output"; }; @@ -9580,19 +8996,19 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; /** * Model Type - * @enum {string} + * @default vae + * @constant */ model_type: "vae"; /** Path */ path: string; /** Description */ - description?: string; + description?: string | null; model_format: components["schemas"]["VaeModelFormat"]; - error?: components["schemas"]["ModelError"]; + error?: components["schemas"]["ModelError"] | null; }; /** * VaeModelFormat - * @description An enumeration. * @enum {string} */ VaeModelFormat: "checkpoint" | "diffusers"; @@ -9620,57 +9036,27 @@ export type components = { * @description Whether or not this is an intermediate invocation. * @default false */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** * Workflow * @description The workflow to save with the image */ - workflow?: string; + workflow?: string | null; /** * Use Cache * @description Whether or not to use the cache * @default true */ - use_cache?: boolean; - /** - * Image - * @description The image to process - */ + use_cache?: boolean | null; + /** @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Type + * type * @default zoe_depth_image_processor - * @enum {string} + * @constant */ type: "zoe_depth_image_processor"; }; - /** - * UIConfigBase - * @description Provides additional node configuration to the UI. - * This is used internally by the @invocation decorator logic. Do not use this directly. - */ - UIConfigBase: { - /** - * Tags - * @description The node's tags - */ - tags?: string[]; - /** - * Title - * @description The node's display name - */ - title?: string; - /** - * Category - * @description The node's category - */ - category?: string; - /** - * Version - * @description The node's version. Should be a valid semver string e.g. "1.0.0" or "3.8.13". - */ - version?: string; - }; /** * Input * @description The type of input a field accepts. @@ -9680,6 +9066,42 @@ export type components = { * @enum {string} */ Input: "connection" | "direct" | "any"; + /** + * UIComponent + * @description The type of UI component to use for a field, used to override the default components, which are inferred from the field type. + * @enum {string} + */ + UIComponent: "none" | "textarea" | "slider"; + /** + * UIConfigBase + * @description Provides additional node configuration to the UI. + * This is used internally by the @invocation decorator logic. Do not use this directly. + */ + UIConfigBase: { + /** + * Tags + * @description The node's tags + */ + tags: string[] | null; + /** + * Title + * @description The node's display name + * @default null + */ + title: string | null; + /** + * Category + * @description The node's category + * @default null + */ + category: string | null; + /** + * Version + * @description The node's version. Should be a valid semver string e.g. "1.0.0" or "3.8.13". + * @default null + */ + version: string | null; + }; /** * UIType * @description Type hints for the UI. @@ -9687,12 +9109,6 @@ export type components = { * @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"; - /** - * UIComponent - * @description The type of UI component to use for a field, used to override the default components, which are inferred from the field type. - * @enum {string} - */ - UIComponent: "none" | "textarea" | "slider"; /** * _InputField * @description *DO NOT USE* @@ -9704,16 +9120,16 @@ export type components = { input: components["schemas"]["Input"]; /** Ui Hidden */ ui_hidden: boolean; - ui_type?: components["schemas"]["UIType"]; - ui_component?: components["schemas"]["UIComponent"]; + ui_type: components["schemas"]["UIType"] | null; + ui_component: components["schemas"]["UIComponent"] | null; /** Ui Order */ - ui_order?: number; + ui_order: number | null; /** Ui Choice Labels */ - ui_choice_labels?: { + ui_choice_labels: { [key: string]: string; - }; + } | null; /** Item Default */ - item_default?: unknown; + item_default: unknown; }; /** * _OutputField @@ -9725,46 +9141,28 @@ export type components = { _OutputField: { /** Ui Hidden */ ui_hidden: boolean; - ui_type?: components["schemas"]["UIType"]; + ui_type: components["schemas"]["UIType"] | null; /** Ui Order */ - ui_order?: number; + ui_order: number | null; }; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "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"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusion2ModelFormat * @description An enumeration. * @enum {string} */ StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * CLIPVisionModelFormat * @description An enumeration. @@ -9777,6 +9175,24 @@ export type components = { * @enum {string} */ StableDiffusionOnnxModelFormat: "olive" | "onnx"; + /** + * StableDiffusionXLModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * T2IAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + T2IAdapterModelFormat: "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -9791,76 +9207,8 @@ export type external = Record; export type operations = { - /** - * List Sessions - * @deprecated - * @description Gets a list of sessions, optionally searching - */ - list_sessions: { - parameters: { - query?: { - /** @description The page of results to get */ - page?: number; - /** @description The number of results per page */ - per_page?: number; - /** @description The query string to search for */ - query?: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["PaginatedResults_GraphExecutionState_"]; - }; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Create Session - * @deprecated - * @description Creates a new session, optionally initializing it with an invocation graph - */ - create_session: { - parameters: { - query?: { - /** @description The id of the queue to associate the session with */ - queue_id?: string; - }; - }; - requestBody?: { - content: { - "application/json": components["schemas"]["Graph"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Invalid json */ - 400: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; /** * Get Session - * @deprecated * @description Gets a session */ get_session: { @@ -9889,284 +9237,6 @@ export type operations = { }; }; }; - /** - * Add Node - * @deprecated - * @description Adds a node to the graph - */ - add_node: { - parameters: { - path: { - /** @description The id of the session */ - session_id: string; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": string; - }; - }; - /** @description Invalid node or link */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Update Node - * @deprecated - * @description Updates a node in the graph and removes all linked edges - */ - update_node: { - parameters: { - path: { - /** @description The id of the session */ - session_id: string; - /** @description The path to the node in the graph */ - node_path: string; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Invalid node or link */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Delete Node - * @deprecated - * @description Deletes a node in the graph and removes all linked edges - */ - delete_node: { - parameters: { - path: { - /** @description The id of the session */ - session_id: string; - /** @description The path to the node to delete */ - node_path: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Invalid node or link */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Add Edge - * @deprecated - * @description Adds an edge to the graph - */ - add_edge: { - parameters: { - path: { - /** @description The id of the session */ - session_id: string; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["Edge"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Invalid node or link */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Delete Edge - * @deprecated - * @description Deletes an edge from the graph - */ - delete_edge: { - parameters: { - path: { - /** @description The id of the session */ - session_id: string; - /** @description The id of the node the edge is coming from */ - from_node_id: string; - /** @description The field of the node the edge is coming from */ - from_field: string; - /** @description The id of the node the edge is going to */ - to_node_id: string; - /** @description The field of the node the edge is going to */ - to_field: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GraphExecutionState"]; - }; - }; - /** @description Invalid node or link */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Invoke Session - * @deprecated - * @description Invokes a session - */ - invoke_session: { - parameters: { - query: { - /** @description The id of the queue to associate the session with */ - queue_id: string; - /** @description Whether or not to invoke all remaining invocations */ - all?: boolean; - }; - path: { - /** @description The id of the session to invoke */ - session_id: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": unknown; - }; - }; - /** @description The invocation is queued */ - 202: { - content: never; - }; - /** @description The session has no invocations ready to invoke */ - 400: { - content: never; - }; - /** @description Session not found */ - 404: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - /** - * Cancel Session Invoke - * @deprecated - * @description Invokes a session - */ - cancel_session_invoke: { - parameters: { - path: { - /** @description The id of the session to cancel */ - session_id: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": unknown; - }; - }; - /** @description The invocation is canceled */ - 202: { - content: never; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; /** * Parse Dynamicprompts * @description Creates a batch process @@ -10200,9 +9270,9 @@ export type operations = { parameters: { query?: { /** @description Base models to include */ - base_models?: components["schemas"]["BaseModelType"][]; + base_models?: components["schemas"]["BaseModelType"][] | null; /** @description The type of model to get */ - model_type?: components["schemas"]["ModelType"]; + model_type?: components["schemas"]["ModelType"] | null; }; }; responses: { @@ -10385,7 +9455,7 @@ export type operations = { parameters: { query?: { /** @description Save the converted model to the designated directory */ - convert_dest_directory?: string; + convert_dest_directory?: string | null; }; path: { /** @description Base model */ @@ -10526,11 +9596,11 @@ export type operations = { /** @description Whether this is an intermediate image */ is_intermediate: boolean; /** @description The board to add this image to, if any */ - board_id?: string; + board_id?: string | null; /** @description The session ID associated with this upload, if any */ - session_id?: string; + session_id?: string | null; /** @description Whether to crop the image */ - crop_visible?: boolean; + crop_visible?: boolean | null; }; }; requestBody: { @@ -10649,7 +9719,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": unknown; + "application/json": number; }; }; }; @@ -10774,13 +9844,13 @@ export type operations = { parameters: { query?: { /** @description The origin of images to list. */ - image_origin?: components["schemas"]["ResourceOrigin"]; + image_origin?: components["schemas"]["ResourceOrigin"] | null; /** @description The categories of image to include. */ - categories?: components["schemas"]["ImageCategory"][]; + categories?: components["schemas"]["ImageCategory"][] | null; /** @description Whether to list intermediate images. */ - is_intermediate?: boolean; + is_intermediate?: boolean | null; /** @description The board id to filter by. Use 'none' to find images without a board. */ - board_id?: string; + board_id?: string | null; /** @description The page offset */ offset?: number; /** @description The number of images per page */ @@ -10898,11 +9968,11 @@ export type operations = { parameters: { query?: { /** @description Whether to list all boards */ - all?: boolean; + all?: boolean | null; /** @description The page offset */ - offset?: number; + offset?: number | null; /** @description The number of boards per page */ - limit?: number; + limit?: number | null; }; }; responses: { @@ -10980,7 +10050,7 @@ export type operations = { parameters: { query?: { /** @description Permanently delete all images on the board */ - include_images?: boolean; + include_images?: boolean | null; }; path: { /** @description The id of board to delete */ @@ -11296,7 +10366,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": unknown; + "application/json": components["schemas"]["EnqueueGraphResult"]; }; }; /** @description Created */ @@ -11333,7 +10403,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": unknown; + "application/json": components["schemas"]["EnqueueBatchResult"]; }; }; /** @description Created */ @@ -11360,9 +10430,9 @@ export type operations = { /** @description The number of items to fetch */ limit?: number; /** @description The status of items to fetch */ - status?: "pending" | "in_progress" | "completed" | "failed" | "canceled"; + status?: ("pending" | "in_progress" | "completed" | "failed" | "canceled") | null; /** @description The pagination cursor */ - cursor?: number; + cursor?: number | null; /** @description The pagination cursor priority */ priority?: number; }; @@ -11536,7 +10606,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["SessionQueueItem"]; + "application/json": components["schemas"]["SessionQueueItem"] | null; }; }; /** @description Validation Error */ @@ -11562,7 +10632,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["SessionQueueItem"]; + "application/json": components["schemas"]["SessionQueueItem"] | null; }; }; /** @description Validation Error */ diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index da56d2782f..6fda849b89 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -137,6 +137,7 @@ export type CompelInvocation = s['CompelInvocation']; export type DynamicPromptInvocation = s['DynamicPromptInvocation']; export type NoiseInvocation = s['NoiseInvocation']; export type DenoiseLatentsInvocation = s['DenoiseLatentsInvocation']; +export type ResizeLatentsInvocation = s['ResizeLatentsInvocation']; export type ONNXTextToLatentsInvocation = s['ONNXTextToLatentsInvocation']; export type SDXLLoraLoaderInvocation = s['SDXLLoraLoaderInvocation']; export type ImageToLatentsInvocation = s['ImageToLatentsInvocation']; diff --git a/invokeai/frontend/web/yarn.lock b/invokeai/frontend/web/yarn.lock index 2a531175d4..cc257115da 100644 --- a/invokeai/frontend/web/yarn.lock +++ b/invokeai/frontend/web/yarn.lock @@ -50,13 +50,20 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.9.2": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.10.2", "@babel/runtime@^7.13.10": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" + integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/types@^7.22.5", "@babel/types@^7.4": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" @@ -66,33 +73,33 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@chakra-ui/accordion@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.3.0.tgz#2c85fd2d2734b176f019f8db9f4e075007b4e1fb" - integrity sha512-A4TkRw3Jnt+Fam6dSSJ62rskdrvjF3JGctYcfXlojfFIpHPuIw4pDwfZgNAxlaxWkcj0e7JJKlQ88dnZW+QfFg== +"@chakra-ui/accordion@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.3.1.tgz#a326509e286a5c4e8478de9bc2b4b05017039e6b" + integrity sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag== dependencies: "@chakra-ui/descendant" "3.1.0" - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-use-controllable-state" "2.1.0" "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/transition" "2.1.0" -"@chakra-ui/alert@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.2.0.tgz#b59eadca4f083674dfcd43651b6c47b953c2c984" - integrity sha512-De+BT88iYOu3Con7MxQeICb1SwgAdVdgpHIYjTh3qvGlNXAQjs81rhG0fONXvwW1FIYletvr9DY2Tlg8xJe7tQ== +"@chakra-ui/alert@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.2.1.tgz#69f4fae19e4f8204ae1db906784139d416063d04" + integrity sha512-GduIqqWCkvID8hxRlKw29Jp3w93r/E9S30J2F8By3ODon9Bhk1o/KVolcPiSiQvRwKNBJCd/rBTpPpLkB+s7pw== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/spinner" "2.1.0" -"@chakra-ui/anatomy@2.2.0", "@chakra-ui/anatomy@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-2.2.0.tgz#788229829f853dcd03314cd7ddd4f19f056ec24e" - integrity sha512-cD8Ms5C8+dFda0LrORMdxiFhAZwOIY1BSlCadz6/mHUIgNdQy13AHPrXiq6qWdMslqVHq10k5zH7xMPLt6kjFg== +"@chakra-ui/anatomy@2.2.1", "@chakra-ui/anatomy@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-2.2.1.tgz#f7ef088dcb8be4f1d075f37101830199fb93f763" + integrity sha512-bbmyWTGwQo+aHYDMtLIj7k7hcWvwE7GFVDViLFArrrPhfUTDdQTNqhiDp1N7eh2HLyjNhc2MKXV8s2KTQqkmTg== "@chakra-ui/avatar@2.3.0": version "2.3.0" @@ -137,12 +144,12 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/checkbox@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.3.0.tgz#6a103555100008fcde0b25a4f3f87267dd6ea073" - integrity sha512-fX7M5sQK27aFWoj7vqnPkf1Q3AHmML/5dIRYfm7HEIsZXYH2C1CkM6+dijeSWIk6a0mp0r3el6SNDUti2ehH8g== +"@chakra-ui/checkbox@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.3.1.tgz#bde33a655a8f033656378e3e95ae0dc4c8e73864" + integrity sha512-e6qL9ntVI/Ui6g0+iljUV2chX86YMsXafldpTHBNYDEoNLjGo1lqLFzq3y6zs3iuB3DHI0X7eAG3REmMVs0A0w== dependencies: - "@chakra-ui/form-control" "2.1.0" + "@chakra-ui/form-control" "2.1.1" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.1.0" @@ -151,8 +158,8 @@ "@chakra-ui/react-use-safe-layout-effect" "2.1.0" "@chakra-ui/react-use-update-effect" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/visually-hidden" "2.1.0" - "@zag-js/focus-visible" "0.10.5" + "@chakra-ui/visually-hidden" "2.2.0" + "@zag-js/focus-visible" "0.16.0" "@chakra-ui/cli@^2.4.1": version "2.4.1" @@ -175,12 +182,12 @@ "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/close-button@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/close-button/-/close-button-2.1.0.tgz#5af435a62919793dc713be321eaff1f61749b6d5" - integrity sha512-KfJcz6UAaR2dDWSIv6UrCGkZQS54Fjl+DEEVOUTJ7gf4KOP4FQZCkv8hqsAB9FeCtnwU43adq2oaw3aZH/Uzew== +"@chakra-ui/close-button@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/close-button/-/close-button-2.1.1.tgz#995b245c56eb41465a71d8667840c238618a7b66" + integrity sha512-gnpENKOanKexswSVpVz7ojZEALl2x5qjLYNqSQGbxz+aP9sOXPfUS56ebyBrre7T7exuWGiFeRwnM0oVeGPaiw== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/color-mode@2.2.0": version "2.2.0" @@ -203,10 +210,10 @@ "@chakra-ui/react-use-callback-ref" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/css-reset@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.2.0.tgz#7bd8da563941709cd68e2d1cf1e71279bec038ea" - integrity sha512-nn7hjquIrPwCzwI4d/Y4wzM5A5xAeswREOfT8gT0Yd+U+Qnw3pPT8NPLbNJ3DvuOfJaCV6/N5ld/6RRTgYF/sQ== +"@chakra-ui/css-reset@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.3.0.tgz#83e3160a9c2a12431cad0ee27ebfbf3aedc5c9c7" + integrity sha512-cQwwBy5O0jzvl0K7PLTLgp8ijqLPKyuEMiDXwYzl95seD3AoeuoCLyzZcJtVqaUZ573PiBdAbY/IlZcwDOItWg== "@chakra-ui/descendant@3.1.0": version "3.1.0" @@ -249,40 +256,40 @@ "@chakra-ui/dom-utils" "2.1.0" react-focus-lock "^2.9.4" -"@chakra-ui/form-control@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.1.0.tgz#a48ad454428c03daaaf71671925becd02a2c3f66" - integrity sha512-3QmWG9v6Rx+JOwJP3Wt89+AWZxK0F1NkVAgXP3WVfE9VDXOKFRV/faLT0GEe2V+l7WZHF5PLdEBvKG8Cgw2mkA== +"@chakra-ui/form-control@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.1.1.tgz#05b06a52432642ddc7ed795bfe127108d160927d" + integrity sha512-LJPDzA1ITc3lhd/iDiINqGeca5bJD09PZAjePGEmmZyLPZZi8nPh/iii0RMxvKyJArsTBwXymCh+dEqK9aDzGQ== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/hooks@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.2.0.tgz#f779bf85542dacd607abe7e67f4571cf8a1102fa" - integrity sha512-GZE64mcr20w+3KbCUPqQJHHmiFnX5Rcp8jS3YntGA4D5X2qU85jka7QkjfBwv/iduZ5Ei0YpCMYGCpi91dhD1Q== +"@chakra-ui/hooks@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.2.1.tgz#b86ce5eeaaab877ddcb11a50842d1227306ace28" + integrity sha512-RQbTnzl6b1tBjbDPf9zGRo9rf/pQMholsOudTxjy4i9GfTfz6kgp5ValGjQm2z7ng6Z31N1cnjZ1AlSzQ//ZfQ== dependencies: "@chakra-ui/react-utils" "2.0.12" "@chakra-ui/utils" "2.0.15" - compute-scroll-into-view "1.0.20" + compute-scroll-into-view "3.0.3" copy-to-clipboard "3.3.3" -"@chakra-ui/icon@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.1.0.tgz#48312c071b3a0ed20ce807c8bd24d5f3e9cfdb7f" - integrity sha512-t6v0lGCXRbwUJycN8A/nDTuLktMP+LRjKbYJnd2oL6Pm2vOl99XwEQ5cAEyEa4XoseYNEgXiLR+2TfvgfNFvcw== +"@chakra-ui/icon@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.2.0.tgz#92b9454aa0d561b4994bcd6a1b3bb1fdd5c67bef" + integrity sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ== dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/icons@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.1.0.tgz#52677939e02f9d6b902bd2c2931e5f18d3c8b523" - integrity sha512-pGFxFfQ/P5VnSRnTzK8zGAJxoxkxpHo/Br9ohRZdOpuhnIHSW7va0P53UoycEO5/vNJ/7BN0oDY0k9qurChcew== +"@chakra-ui/icons@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.1.1.tgz#58ff0f9e703f2f4f89debd600ce4e438f43f9c9a" + integrity sha512-3p30hdo4LlRZTT5CwoAJq3G9fHI0wDc0pBaMHj4SUn0yomO+RcDRlzhdXqdr5cVnzax44sqXJVnf3oQG0eI+4g== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/image@2.1.0": version "2.1.0" @@ -292,24 +299,24 @@ "@chakra-ui/react-use-safe-layout-effect" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/input@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.1.0.tgz#45a2e2ccdd65dc9f6dee11b6e3043438864bf806" - integrity sha512-HItI2vq6vupCuixdzof4sIanGdLlszhDtlR5be5z8Nrda1RkXVqI+9CTJPbNsx2nIKEfwPt01pnT9mozoOSMMw== +"@chakra-ui/input@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.1.1.tgz#c9666bd1efd7763458bec713fb87cc3f365ec15d" + integrity sha512-RQYzQ/qcak3eCuCfvSqc1kEFx0sCcnIeiSi7i0r70CeBnAUK/CP1/4Uz849FpKz81K4z2SikC9MkHPQd8ZpOwg== dependencies: - "@chakra-ui/form-control" "2.1.0" + "@chakra-ui/form-control" "2.1.1" "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-children-utils" "2.0.6" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/layout@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.3.0.tgz#c53219235db737202006b8b0881b82fedcf3b225" - integrity sha512-tp1/Bn+cHn0Q4HWKY62HtOwzhpH1GUA3i5fvs23HEhOEryTps05hyuQVeJ71fLqSs6f1QEIdm+9It+5WCj64vQ== +"@chakra-ui/layout@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.3.1.tgz#0601c5eb91555d24a7015a7c9d4e01fed2698557" + integrity sha512-nXuZ6WRbq0WdgnRgLw+QuxWAHuhDtVX8ElWqcTK+cSMFg/52eVP47czYBE5F35YhnoW2XBwfNoNgZ7+e8Z01Rg== dependencies: "@chakra-ui/breakpoint-utils" "2.0.8" - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-children-utils" "2.0.6" "@chakra-ui/react-context" "2.1.0" @@ -334,10 +341,10 @@ "@chakra-ui/react-env" "3.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/menu@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.2.0.tgz#ba74b538a3fa3dc46313368ed2878f92b479e6d7" - integrity sha512-l7HQjriW4JGeCyxDdguAzekwwB+kHGDLxACi0DJNp37sil51SRaN1S1OrneISbOHVpHuQB+KVNgU0rqhoglVew== +"@chakra-ui/menu@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.2.1.tgz#7d9810d435f6b40fa72ed867a33b88a1ef75073f" + integrity sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g== dependencies: "@chakra-ui/clickable" "2.1.0" "@chakra-ui/descendant" "3.1.0" @@ -355,12 +362,12 @@ "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/transition" "2.1.0" -"@chakra-ui/modal@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.3.0.tgz#f7c35bb457c3c4be391c9366f892a5a779af810a" - integrity sha512-S1sITrIeLSf21LJ0Vz8xZhj5fWEud5z5Dl2dmvOEv1ezypgOrCCBdOEnnqCkoEKZDbKvzZWZXWR5791ikLP6+g== +"@chakra-ui/modal@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.3.1.tgz#524dc32b6b4f545b54ae531dbf6c74e1052ee794" + integrity sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ== dependencies: - "@chakra-ui/close-button" "2.1.0" + "@chakra-ui/close-button" "2.1.1" "@chakra-ui/focus-lock" "2.1.0" "@chakra-ui/portal" "2.1.0" "@chakra-ui/react-context" "2.1.0" @@ -368,17 +375,17 @@ "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/transition" "2.1.0" - aria-hidden "^1.2.2" - react-remove-scroll "^2.5.5" + aria-hidden "^1.2.3" + react-remove-scroll "^2.5.6" -"@chakra-ui/number-input@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.1.0.tgz#7812a6602edbed26829a8f7defe8c4f9f175421a" - integrity sha512-/gEAzQHhrMA+1rzyCMaN8OkKtUPuER6iA+nloYEYBoT7dH/EoNlRtBkiIQhDp+E4VpgZJ0SK3OVrm9/eBbtHHg== +"@chakra-ui/number-input@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.1.1.tgz#5308a30e972cd45a017f613996d7d5c1f32bd89f" + integrity sha512-B4xwUPyr0NmjGN/dBhOmCD2xjX6OY1pr9GmGH3GQRozMsLAClD3TibwiZetwlyCp02qQqiFwEcZmUxaX88794Q== dependencies: "@chakra-ui/counter" "2.1.0" - "@chakra-ui/form-control" "2.1.0" - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/form-control" "2.1.1" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.1.0" @@ -411,12 +418,12 @@ "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/popover@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.2.0.tgz#470c4814447010a1b7db6839fcc3e8983cbabb60" - integrity sha512-cTqXdgkU0vgK82AR1nWcC2MJYhEL/y6uTeprvO2+j4o2D0yPrzVMuIZZRl0abrQwiravQyVGEMgA5y0ZLYwbiQ== +"@chakra-ui/popover@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.2.1.tgz#89cfd29817abcd204da570073c0f2b4d8072c3a3" + integrity sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg== dependencies: - "@chakra-ui/close-button" "2.1.0" + "@chakra-ui/close-button" "2.1.1" "@chakra-ui/lazy-utils" "2.0.5" "@chakra-ui/popper" "3.1.0" "@chakra-ui/react-context" "2.1.0" @@ -452,28 +459,28 @@ dependencies: "@chakra-ui/react-context" "2.1.0" -"@chakra-ui/provider@2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.4.0.tgz#1649e607b7dddd8dd160e624946769a29f67d9a3" - integrity sha512-KJ/TNczpY+EStQXa2Y5PZ+senlBHrY7P+RpBgJLBZLGkQUCS3APw5KvCwgpA0COb2M4AZXCjw+rm+Ko7ontlgA== +"@chakra-ui/provider@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.4.1.tgz#0c6c1bab2b50fdf9dfbcbb363df8982988c54d65" + integrity sha512-u4g02V9tJ9vVYfkLz5jBn/bKlAyjLdg4Sh3f7uckmYVAZpOL/uUlrStyADrynu3tZhI+BE8XdmXC4zs/SYD7ow== dependencies: - "@chakra-ui/css-reset" "2.2.0" + "@chakra-ui/css-reset" "2.3.0" "@chakra-ui/portal" "2.1.0" "@chakra-ui/react-env" "3.1.0" - "@chakra-ui/system" "2.6.0" + "@chakra-ui/system" "2.6.1" "@chakra-ui/utils" "2.0.15" -"@chakra-ui/radio@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.1.0.tgz#68b2cb4193570369568052cb1254163224a1479c" - integrity sha512-WiRlSCqKWgy4m9106w4g77kcLYqBxqGhFRO1pTTJp99rxpM6jNadOeK+moEjqj64N9mSz3njEecMJftKKcOYdg== +"@chakra-ui/radio@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.1.1.tgz#399983ce8a1bbc81e7cddfbaf091f54a1645fb7e" + integrity sha512-5JXDVvMWsF/Cprh6BKfcTLbLtRcgD6Wl2zwbNU30nmKIE8+WUfqD7JQETV08oWEzhi3Ea4e5EHvyll2sGx8H3w== dependencies: - "@chakra-ui/form-control" "2.1.0" + "@chakra-ui/form-control" "2.1.1" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" - "@zag-js/focus-visible" "0.10.5" + "@zag-js/focus-visible" "0.16.0" "@chakra-ui/react-children-utils@2.0.6": version "2.0.6" @@ -617,71 +624,71 @@ dependencies: "@chakra-ui/utils" "2.0.15" -"@chakra-ui/react@^2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.8.0.tgz#cc76a2448f9bc85f1645a1afb90d5756a5313ac3" - integrity sha512-tV82DaqE4fMbLIWq58BYh4Ol3gAlNEn+qYOzx8bPrZudboEDnboq8aVfSBwWOY++MLWz2Nn7CkT69YRm91e5sg== +"@chakra-ui/react@^2.8.1": + version "2.8.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.8.1.tgz#fd80632b0ef34434443d8999d03d297f130aabcf" + integrity sha512-UL9Rtj4DovP3+oVbI06gsdfyJJb+wmS2RYnGNXjW9tsjCyXxjlBw9TAUj0jyOfWe0+zd/4juL8+J+QCwmdhptg== dependencies: - "@chakra-ui/accordion" "2.3.0" - "@chakra-ui/alert" "2.2.0" + "@chakra-ui/accordion" "2.3.1" + "@chakra-ui/alert" "2.2.1" "@chakra-ui/avatar" "2.3.0" "@chakra-ui/breadcrumb" "2.2.0" "@chakra-ui/button" "2.1.0" "@chakra-ui/card" "2.2.0" - "@chakra-ui/checkbox" "2.3.0" - "@chakra-ui/close-button" "2.1.0" + "@chakra-ui/checkbox" "2.3.1" + "@chakra-ui/close-button" "2.1.1" "@chakra-ui/control-box" "2.1.0" "@chakra-ui/counter" "2.1.0" - "@chakra-ui/css-reset" "2.2.0" + "@chakra-ui/css-reset" "2.3.0" "@chakra-ui/editable" "3.1.0" "@chakra-ui/focus-lock" "2.1.0" - "@chakra-ui/form-control" "2.1.0" - "@chakra-ui/hooks" "2.2.0" - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/form-control" "2.1.1" + "@chakra-ui/hooks" "2.2.1" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/image" "2.1.0" - "@chakra-ui/input" "2.1.0" - "@chakra-ui/layout" "2.3.0" + "@chakra-ui/input" "2.1.1" + "@chakra-ui/layout" "2.3.1" "@chakra-ui/live-region" "2.1.0" "@chakra-ui/media-query" "3.3.0" - "@chakra-ui/menu" "2.2.0" - "@chakra-ui/modal" "2.3.0" - "@chakra-ui/number-input" "2.1.0" + "@chakra-ui/menu" "2.2.1" + "@chakra-ui/modal" "2.3.1" + "@chakra-ui/number-input" "2.1.1" "@chakra-ui/pin-input" "2.1.0" - "@chakra-ui/popover" "2.2.0" + "@chakra-ui/popover" "2.2.1" "@chakra-ui/popper" "3.1.0" "@chakra-ui/portal" "2.1.0" "@chakra-ui/progress" "2.2.0" - "@chakra-ui/provider" "2.4.0" - "@chakra-ui/radio" "2.1.0" + "@chakra-ui/provider" "2.4.1" + "@chakra-ui/radio" "2.1.1" "@chakra-ui/react-env" "3.1.0" - "@chakra-ui/select" "2.1.0" + "@chakra-ui/select" "2.1.1" "@chakra-ui/skeleton" "2.1.0" "@chakra-ui/skip-nav" "2.1.0" "@chakra-ui/slider" "2.1.0" "@chakra-ui/spinner" "2.1.0" - "@chakra-ui/stat" "2.1.0" - "@chakra-ui/stepper" "2.3.0" + "@chakra-ui/stat" "2.1.1" + "@chakra-ui/stepper" "2.3.1" "@chakra-ui/styled-system" "2.9.1" - "@chakra-ui/switch" "2.1.0" - "@chakra-ui/system" "2.6.0" + "@chakra-ui/switch" "2.1.1" + "@chakra-ui/system" "2.6.1" "@chakra-ui/table" "2.1.0" - "@chakra-ui/tabs" "2.2.0" - "@chakra-ui/tag" "3.1.0" - "@chakra-ui/textarea" "2.1.0" - "@chakra-ui/theme" "3.2.0" - "@chakra-ui/theme-utils" "2.0.19" - "@chakra-ui/toast" "7.0.0" + "@chakra-ui/tabs" "3.0.0" + "@chakra-ui/tag" "3.1.1" + "@chakra-ui/textarea" "2.1.1" + "@chakra-ui/theme" "3.3.0" + "@chakra-ui/theme-utils" "2.0.20" + "@chakra-ui/toast" "7.0.1" "@chakra-ui/tooltip" "2.3.0" "@chakra-ui/transition" "2.1.0" "@chakra-ui/utils" "2.0.15" - "@chakra-ui/visually-hidden" "2.1.0" + "@chakra-ui/visually-hidden" "2.2.0" -"@chakra-ui/select@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.1.0.tgz#4c9a6e881281e77ed35ba7a2e343f235b7e0b2fd" - integrity sha512-6GEjCJNOm1pS9E7XRvodoVOuSFl82Jio3MGWgmcQrLznjJAhIZVMq85vCQqzGpjjfbHys/UctfdJY75Ctas/Jg== +"@chakra-ui/select@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.1.1.tgz#0792eeebdb82b1710c4527e7e8e2e07c686c714d" + integrity sha512-CERDATncv5w05Zo5/LrFtf1yKp1deyMUyDGv6eZvQG/etyukH4TstsuIHt/0GfNXrCF3CJLZ8lINzpv5wayVjQ== dependencies: - "@chakra-ui/form-control" "2.1.0" + "@chakra-ui/form-control" "2.1.1" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/shared-utils@2.0.5": @@ -726,21 +733,21 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/stat@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.1.0.tgz#6643b507358e9cacf008387b3f12b75899497369" - integrity sha512-sqx0/AdFFZ80dsiM5owmhtQyYl+zON1r+IY0m70I/ABRVy+I3br06xdUhoaxh3tcP7c0O/BQgb+VCfXa9Y34CA== +"@chakra-ui/stat@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.1.1.tgz#a204ba915795345996a16c79794d84826d7dcc2d" + integrity sha512-LDn0d/LXQNbAn2KaR3F1zivsZCewY4Jsy1qShmfBMKwn6rI8yVlbvu6SiA3OpHS0FhxbsZxQI6HefEoIgtqY6Q== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/stepper@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/stepper/-/stepper-2.3.0.tgz#5714df429936839145a62b5c197cff26b872b660" - integrity sha512-q80QX/NLrjJQIlBP1N+Q8GVJb7/HiOpMoK1PlP4denB/KxkU2K8GEjss8U2vklR1XsWJy1fwfj03+66Q78Uk/Q== +"@chakra-ui/stepper@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/stepper/-/stepper-2.3.1.tgz#a0a0b73e147f202ab4e51cae55dad45489cc89fd" + integrity sha512-ky77lZbW60zYkSXhYz7kbItUpAQfEdycT0Q4bkHLxfqbuiGMf8OmgZOQkOB9uM4v0zPwy2HXhe0vq4Dd0xa55Q== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" @@ -753,26 +760,26 @@ csstype "^3.0.11" lodash.mergewith "4.6.2" -"@chakra-ui/switch@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.1.0.tgz#750474ef7f0a9854062e692cbbe9f3ed0cfbc4d8" - integrity sha512-uWHOaIDQdGh+mszxeppj5aYVepbkSK445KZlJJkfr9Bnr6sythTwM63HSufnVDiTEE4uRqegv9jEjZK2JKA+9A== +"@chakra-ui/switch@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.1.1.tgz#8049963e6421cdd5eaaac1d20d9febae8d731b62" + integrity sha512-cOHIhW5AlLZSFENxFEBYTBniqiduOowa1WdzslP1Fd0usBFaD5iAgOY1Fvr7xKhE8nmzzeMCkPB3XBvUSWnawQ== dependencies: - "@chakra-ui/checkbox" "2.3.0" + "@chakra-ui/checkbox" "2.3.1" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/system@2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.6.0.tgz#29f65bb0887ee0816bbb7b4b098ca5aa4918c409" - integrity sha512-MgAFRz9V1pW0dplwWsB99hx49LCC+LsrkMala7KXcP0OvWdrkjw+iu+voBksO3626+glzgIwlZW113Eja+7JEQ== +"@chakra-ui/system@2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.6.1.tgz#22ee50ddc9e1f56b974a0dd42d86108391a2f372" + integrity sha512-P5Q/XRWy3f1pXJ7IxDkV+Z6AT7GJeR2JlBnQl109xewVQcBLWWMIp702fFMFw8KZ2ALB/aYKtWm5EmQMddC/tg== dependencies: "@chakra-ui/color-mode" "2.2.0" "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-utils" "2.0.12" "@chakra-ui/styled-system" "2.9.1" - "@chakra-ui/theme-utils" "2.0.19" + "@chakra-ui/theme-utils" "2.0.20" "@chakra-ui/utils" "2.0.15" - react-fast-compare "3.2.1" + react-fast-compare "3.2.2" "@chakra-ui/table@2.1.0": version "2.1.0" @@ -782,10 +789,10 @@ "@chakra-ui/react-context" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/tabs@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-2.2.0.tgz#72b6bf8bff3d3da3effb115991bf24e2157e29d2" - integrity sha512-ulN7McHZ322qlbJXg8S+IwdN8Axh8q0HzYBOHzSdcnVphEytfv9TsfJhN0Hx5yjkpekAzG5fewn33ZdIpIpKyQ== +"@chakra-ui/tabs@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-3.0.0.tgz#854c06880af26158d7c72881c4b5e0453f6c485d" + integrity sha512-6Mlclp8L9lqXmsGWF5q5gmemZXOiOYuh0SGT/7PgJVNPz3LXREXlXg2an4MBUD8W5oTkduCX+3KTMCwRrVrDYw== dependencies: "@chakra-ui/clickable" "2.1.0" "@chakra-ui/descendant" "3.1.0" @@ -797,64 +804,64 @@ "@chakra-ui/react-use-safe-layout-effect" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/tag@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-3.1.0.tgz#b2c06254e1d5aaaf77ff41e5d2e6548b404cabd7" - integrity sha512-Mn2u828z5HvqEBEG+tUJWe3al5tzN87bK2U0QfThx3+zqWbBCWBSCVfnWRtkNh80m+5a1TekexDAPZqu5G8zdw== +"@chakra-ui/tag@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-3.1.1.tgz#d05284b6549a84d3a08e57eec57df3ad0eebd882" + integrity sha512-Bdel79Dv86Hnge2PKOU+t8H28nm/7Y3cKd4Kfk9k3lOpUh4+nkSGe58dhRzht59lEqa4N9waCgQiBdkydjvBXQ== dependencies: - "@chakra-ui/icon" "3.1.0" + "@chakra-ui/icon" "3.2.0" "@chakra-ui/react-context" "2.1.0" -"@chakra-ui/textarea@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.1.0.tgz#d0f157c9a09aea87c372409eead4292bd26999a0" - integrity sha512-4F7X/lPRsY+sPxYrWGrhh1pBtdnFvVllIOapzAwnjYwsflm+vf6c+9ZgoDWobXsNezJ9fcqN0FTPwaBnDvDQRQ== +"@chakra-ui/textarea@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.1.1.tgz#3e33404ff8470140e877840a5702a406996a3834" + integrity sha512-28bpwgmXg3BzSpg8i1Ao9h7pHaE1j2mBBFJpWaqPgMhS0IHm0BQsqqyWU6PsxxJDvrC4HN6MTzrIL4C1RA1I0A== dependencies: - "@chakra-ui/form-control" "2.1.0" + "@chakra-ui/form-control" "2.1.1" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/theme-tools@2.1.0", "@chakra-ui/theme-tools@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-tools/-/theme-tools-2.1.0.tgz#ad34f2fdda61305ac96f69ad9ce38ad12f8bfdbf" - integrity sha512-TKv4trAY8q8+DWdZrpSabTd3SZtZrnzFDwUdzhbWBhFEDEVR3fAkRTPpnPDtf1X9w1YErWn3QAcMACVFz4+vkw== +"@chakra-ui/theme-tools@2.1.1", "@chakra-ui/theme-tools@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-tools/-/theme-tools-2.1.1.tgz#c7f3072ab533d7abc6a3831666be3c172f992554" + integrity sha512-n14L5L3ej3Zy+Xm/kDKO1G6/DkmieT7Li1C7NzMRcUj5C9YybQpyo7IZZ0BBUh3u+OVnKVhNC3d4P2NYDGRXmA== dependencies: - "@chakra-ui/anatomy" "2.2.0" + "@chakra-ui/anatomy" "2.2.1" "@chakra-ui/shared-utils" "2.0.5" - color2k "^2.0.0" + color2k "^2.0.2" -"@chakra-ui/theme-utils@2.0.19": - version "2.0.19" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.19.tgz#47e6af43f8ef22403686b779ca1a869ab1b7a5ec" - integrity sha512-UQ+KvozTN86+0oA80rdQd1a++4rm4ulo+DEabkgwNpkK3yaWsucOxkDQpi2sMIMvw5X0oaWvNBZJuVyK7HdOXg== +"@chakra-ui/theme-utils@2.0.20": + version "2.0.20" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.20.tgz#fdc4947ac4b95c16ff5885707c9a931c43b80cf6" + integrity sha512-IkAzSmwBlRIZ3dN2InDz0tf9SldbckVkgwylCobSFmYP8lnMjykL8Lex1BBo9U8UQjZxEDVZ+Qw6SeayKRntOQ== dependencies: "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/styled-system" "2.9.1" - "@chakra-ui/theme" "3.2.0" + "@chakra-ui/theme" "3.3.0" lodash.mergewith "4.6.2" -"@chakra-ui/theme@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-3.2.0.tgz#b8232d770e542895cf82535942a74ad803bb7133" - integrity sha512-q9mppdkhmaBnvOT8REr/lVNNBX/prwm50EzObJ+r+ErVhNQDc55gCFmtr+It3xlcCqmOteG6XUdwRCJz8qzOqg== +"@chakra-ui/theme@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-3.3.0.tgz#7fe364322e75c7bdfa45b96dd3db6dac7eb8f7ef" + integrity sha512-VHY2ax5Wqgfm83U/zYBk0GS0TGD8m41s/rxQgnEq8tU+ug1YZjvOZmtOq/VjfKP/bQraFhCt05zchcxXmDpEYg== dependencies: - "@chakra-ui/anatomy" "2.2.0" + "@chakra-ui/anatomy" "2.2.1" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/theme-tools" "2.1.0" + "@chakra-ui/theme-tools" "2.1.1" -"@chakra-ui/toast@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-7.0.0.tgz#6c6f1b7b8dc458ed0827b2edc47eb7d4075c95dc" - integrity sha512-XQgSnn4DYRgfOBzBvh8GI/AZ7SfrO8wlVSmChfp92Nfmqm7tRDUT9x8ws/iNKAvMRHkhl7fmRjJ39ipeXYrMvA== +"@chakra-ui/toast@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-7.0.1.tgz#11113b9185409ed1dc7a062f0498673f0840a013" + integrity sha512-V5JUhw6RZxbGRTijvd5k4iEMLCfbzTLNWbZLZhRZk10YvFfAP5OYfRCm68zpE/t3orN/f+4ZLL3P+Wb4E7oSmw== dependencies: - "@chakra-ui/alert" "2.2.0" - "@chakra-ui/close-button" "2.1.0" + "@chakra-ui/alert" "2.2.1" + "@chakra-ui/close-button" "2.1.1" "@chakra-ui/portal" "2.1.0" "@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-use-timeout" "2.1.0" "@chakra-ui/react-use-update-effect" "2.1.0" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/styled-system" "2.9.1" - "@chakra-ui/theme" "3.2.0" + "@chakra-ui/theme" "3.3.0" "@chakra-ui/tooltip@2.3.0": version "2.3.0" @@ -887,10 +894,10 @@ framesync "6.1.2" lodash.mergewith "4.6.2" -"@chakra-ui/visually-hidden@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.1.0.tgz#9ec573964e5a07f8682574a060140d78e9f91c32" - integrity sha512-3OHKqTz78PX7V4qto+a5Y6VvH6TbU3Pg6Z0Z2KnDkOBP3Po8fiz0kk+/OSPzIwdcSsQKiocLi0c1pnnUPdMZPg== +"@chakra-ui/visually-hidden@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz#9b0ecef8f01263ab808ba3bda7b36a0d91b4d5c1" + integrity sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ== "@dagrejs/graphlib@^2.1.13": version "2.1.13" @@ -1302,27 +1309,30 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@^8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d" - integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og== +"@eslint/js@8.51.0": + version "8.51.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" + integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== "@fastify/deepmerge@^1.0.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@fastify/deepmerge/-/deepmerge-1.3.0.tgz#8116858108f0c7d9fd460d05a7d637a13fe3239a" integrity sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A== -"@floating-ui/core@^1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.3.1.tgz#4d795b649cc3b1cbb760d191c80dcb4353c9a366" - integrity sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g== - -"@floating-ui/dom@^1.2.1", "@floating-ui/dom@^1.3.0": - version "1.4.5" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.4.5.tgz#336dfb9870c98b471ff5802002982e489b8bd1c5" - integrity sha512-96KnRWkRnuBSSFbj0sFGwwOUd8EkiecINVl0O9wiZlZ64EkpyAOG3Xc2vKKNJmru0Z7RqWNymA+6b8OZqjgyyw== +"@floating-ui/core@^1.4.2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.0.tgz#5c05c60d5ae2d05101c3021c1a2a350ddc027f8c" + integrity sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg== dependencies: - "@floating-ui/core" "^1.3.1" + "@floating-ui/utils" "^0.1.3" + +"@floating-ui/dom@^1.2.1", "@floating-ui/dom@^1.5.1": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa" + integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA== + dependencies: + "@floating-ui/core" "^1.4.2" + "@floating-ui/utils" "^0.1.3" "@floating-ui/react-dom@^1.3.0": version "1.3.0" @@ -1331,12 +1341,12 @@ dependencies: "@floating-ui/dom" "^1.2.1" -"@floating-ui/react-dom@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.1.tgz#7972a4fc488a8c746cded3cfe603b6057c308a91" - integrity sha512-rZtAmSht4Lry6gdhAJDrCp/6rKN7++JnL1/Anbr/DdeyYXQPxvg/ivrbYvJulbRf4vL8b212suwMM2lxbv+RQA== +"@floating-ui/react-dom@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.2.tgz#fab244d64db08e6bed7be4b5fcce65315ef44d20" + integrity sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ== dependencies: - "@floating-ui/dom" "^1.3.0" + "@floating-ui/dom" "^1.5.1" "@floating-ui/react@^0.19.1": version "0.19.2" @@ -1347,20 +1357,25 @@ aria-hidden "^1.1.3" tabbable "^6.0.1" -"@fontsource-variable/inter@^5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@fontsource-variable/inter/-/inter-5.0.8.tgz#bd6d61ece1019c59b0ac330a138d48a34dfa6d8c" - integrity sha512-WkYfFNccmEIeL2fNg0mYeLWqOoB7xD8MFxFRc4IwbSP2o8ZaBt36v5aW4by4MyrgGRMNk7uNi5LbvYKq6clPjw== +"@floating-ui/utils@^0.1.3": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" + integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== -"@fontsource/inter@^5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.8.tgz#61b50cb0eb72b14ae1938d47c4a9a91546d2a50c" - integrity sha512-28knWH1BfOiRalfLs90U4sge5mpQ8ZH6FS0PTT+IZMKrZ7wNHDHRuKa1kQJg+uHcc6axBppnxll+HXM4c7zo/Q== +"@fontsource-variable/inter@^5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fontsource-variable/inter/-/inter-5.0.13.tgz#ddffb8cdc888c00bc232e30698fb872b775ee115" + integrity sha512-mb2WyZ2rHeqIG8aqGJIvLBOmo4sg2x7SHlsE6PUhwxbOicVzO59EZwSGtzNO3FmchuDPFVAxzcXYcR5B6jE6Qw== -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@fontsource/inter@^5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.13.tgz#b106fdc43b8eea8d6f5c0ce55941b1ae577c49e5" + integrity sha512-FVIBhP9X/x02blF2VQl2Pji/c3jUjkWEQ9bom4vIrGwO1MlHRDXhXx9iA1hhjpcCIfH3oX68ihIBdYcFnOXhsg== + +"@humanwhocodes/config-array@^0.11.11": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -1377,63 +1392,63 @@ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@mantine/core@^6.0.19": - version "6.0.19" - resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.19.tgz#612413f0e8eb117e6a39068a625c6ccf2ae2ccdd" - integrity sha512-SvMZCOgCc315SIg6hkuLM0ZnBaAac4VFDHZ0BM5LIE4MPJUpe4QOLsg/5RGxOa5s7JRCtu/dawH3/9frvfDrhw== + version "6.0.21" + resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.21.tgz#6e3a1b8d0f6869518a644d5f5e3d55a5db7e1e51" + integrity sha512-Kx4RrRfv0I+cOCIcsq/UA2aWcYLyXgW3aluAuW870OdXnbII6qg7RW28D+r9D76SHPxWFKwIKwmcucAG08Divg== dependencies: "@floating-ui/react" "^0.19.1" - "@mantine/styles" "6.0.19" - "@mantine/utils" "6.0.19" + "@mantine/styles" "6.0.21" + "@mantine/utils" "6.0.21" "@radix-ui/react-scroll-area" "1.0.2" react-remove-scroll "^2.5.5" react-textarea-autosize "8.3.4" "@mantine/form@^6.0.19": - version "6.0.19" - resolved "https://registry.yarnpkg.com/@mantine/form/-/form-6.0.19.tgz#3d97f08a45b1a8bc8840dbf77defd267abb20e39" - integrity sha512-5SFLZEzaBH7yKIDSDt1r9UiN4y7RkFvu+7J7CFPIQM+nTdXeGnugVFM8rASuZI7/FSYty/XoPY+Yymq3xDX+MQ== + version "6.0.21" + resolved "https://registry.yarnpkg.com/@mantine/form/-/form-6.0.21.tgz#0d717631aa90b9cce834a479f4c8d7e9c0e1969b" + integrity sha512-d4tlxyZic7MSDnaPx/WliCX1sRFDkUd2nxx4MxxO2T4OSek0YDqTlSBCxeoveu60P+vrQQN5rbbsVsaOJBe4SQ== dependencies: fast-deep-equal "^3.1.3" klona "^2.0.5" "@mantine/hooks@^6.0.19": - version "6.0.19" - resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.19.tgz#39f61434304f687d3ba7bf0040c5adf380c7c4b3" - integrity sha512-YkmuB6kmoenU1PVuE8tLBA+6RJIY9hIsGyIQG1yuPAy6SLWNFT8g2T9YvI/psqsUbVIYGaNEXg8zq42xbxnD8Q== + version "6.0.21" + resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.21.tgz#bc009d8380ad18455b90f3ddaf484de16a13da95" + integrity sha512-sYwt5wai25W6VnqHbS5eamey30/HD5dNXaZuaVEAJ2i2bBv8C0cCiczygMDpAFiSYdXoSMRr/SZ2CrrPTzeNew== -"@mantine/styles@6.0.19": - version "6.0.19" - resolved "https://registry.yarnpkg.com/@mantine/styles/-/styles-6.0.19.tgz#7d9a6f2c2a9b345dfd9d12f8fd66af3976d67ab2" - integrity sha512-0tg3Dvv/kxCc1mbQVFhZaIhlSbSbV1F/3xG0NRlP2DF23mw9088o5KaIXGKM6XkXU6OEt/f99nDCUHBk2ixtUg== +"@mantine/styles@6.0.21": + version "6.0.21" + resolved "https://registry.yarnpkg.com/@mantine/styles/-/styles-6.0.21.tgz#8ea097fc76cbb3ed55f5cfd719d2f910aff5031b" + integrity sha512-PVtL7XHUiD/B5/kZ/QvZOZZQQOj12QcRs3Q6nPoqaoPcOX5+S7bMZLMH0iLtcGq5OODYk0uxlvuJkOZGoPj8Mg== dependencies: clsx "1.1.1" csstype "3.0.9" -"@mantine/utils@6.0.19": - version "6.0.19" - resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.19.tgz#0197fccc5649259787d5468228139f8815909803" - integrity sha512-duvtnaW1gDR2gnvUqnWhl6DMW7sN0HEWqS8Z/BbwaMi75U+Xp17Q72R9JtiIrxQbzsq+KvH9L9B/pxMVwbLirg== +"@mantine/utils@6.0.21": + version "6.0.21" + resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.21.tgz#6185506e91cba3e308aaa8ea9ababc8e767995d6" + integrity sha512-33RVDRop5jiWFao3HKd3Yp7A9mEq4HAJxJPTuYm1NkdqX6aTKOQK7wT8v8itVodBp+sb4cJK6ZVdD1UurK/txQ== -"@microsoft/api-extractor-model@7.27.6": - version "7.27.6" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.27.6.tgz#308e44cd595d2fb446c6357759ee0675ec37d26e" - integrity sha512-eiCnlayyum1f7fS2nA9pfIod5VCNR1G+Tq84V/ijDrKrOFVa598BLw145nCsGDMoFenV6ajNi2PR5WCwpAxW6Q== +"@microsoft/api-extractor-model@7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.28.2.tgz#91c66dd820ccc70e0c163e06b392d8363f1b9269" + integrity sha512-vkojrM2fo3q4n4oPh4uUZdjJ2DxQ2+RnDQL/xhTWSRUNPF6P4QyrvY357HBxbnltKcYu+nNNolVqc6TIGQ73Ig== dependencies: "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.59.7" + "@rushstack/node-core-library" "3.61.0" -"@microsoft/api-extractor@^7.36.3": - version "7.36.4" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.36.4.tgz#3bb9fbbbeacaa48eea49150351905a2677a506d9" - integrity sha512-21UECq8C/8CpHT23yiqTBQ10egKUacIpxkPyYR7hdswo/M5yTWdBvbq+77YC9uPKQJOUfOD1FImBQ1DzpsdeQQ== +"@microsoft/api-extractor@^7.36.4": + version "7.38.0" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.38.0.tgz#e72546d6766b3866578a462b040f71b17779e1c5" + integrity sha512-e1LhZYnfw+JEebuY2bzhw0imDCl1nwjSThTrQqBXl40hrVo6xm3j/1EpUr89QyzgjqmAwek2ZkIVZbrhaR+cqg== dependencies: - "@microsoft/api-extractor-model" "7.27.6" + "@microsoft/api-extractor-model" "7.28.2" "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.59.7" - "@rushstack/rig-package" "0.4.1" - "@rushstack/ts-command-line" "4.15.2" + "@rushstack/node-core-library" "3.61.0" + "@rushstack/rig-package" "0.5.1" + "@rushstack/ts-command-line" "4.16.1" colors "~1.2.1" lodash "~4.17.15" resolve "~1.22.1" @@ -1589,28 +1604,28 @@ dependencies: "@babel/runtime" "^7.13.10" -"@reactflow/background@11.2.8": - version "11.2.8" - resolved "https://registry.yarnpkg.com/@reactflow/background/-/background-11.2.8.tgz#aa83f87b7d65442b52732f0a04d9da981f978265" - integrity sha512-5o41N2LygiNC2/Pk8Ak2rIJjXbKHfQ23/Y9LFsnAlufqwdzFqKA8txExpsMoPVHHlbAdA/xpQaMuoChGPqmyDw== +"@reactflow/background@11.3.3": + version "11.3.3" + resolved "https://registry.yarnpkg.com/@reactflow/background/-/background-11.3.3.tgz#c2662ca22acf49cce5084daf21aa4a3ca9f241f2" + integrity sha512-m3MR25ufbrDkZI2Yi7pHX5uewVpiaaVM5px35pk2v3qdG68adqHOgJjncUOpGiJpc3rDwt4mqmW1V7RjBqNv6Q== dependencies: - "@reactflow/core" "11.8.3" + "@reactflow/core" "11.9.3" classcat "^5.0.3" zustand "^4.4.1" -"@reactflow/controls@11.1.19": - version "11.1.19" - resolved "https://registry.yarnpkg.com/@reactflow/controls/-/controls-11.1.19.tgz#a8bc4b4eafc10d5d230db5286753e867bcf35e5b" - integrity sha512-Vo0LFfAYjiSRMLEII/aeBo+1MT2a0Yc7iLVnkuRTLzChC0EX+A2Fa+JlzeOEYKxXlN4qcDxckRNGR7092v1HOQ== +"@reactflow/controls@11.2.3": + version "11.2.3" + resolved "https://registry.yarnpkg.com/@reactflow/controls/-/controls-11.2.3.tgz#d965399772f912b504f1e96d00ddf950aa822153" + integrity sha512-UTsfHE+PhgWrCZN4GUOTRU/3l8dGSyR2KslmgqV7mVNsh6EuS2cxboRczjpcIc8lF0EH+7QxLGeXSH42GWCcOQ== dependencies: - "@reactflow/core" "11.8.3" + "@reactflow/core" "11.9.3" classcat "^5.0.3" zustand "^4.4.1" -"@reactflow/core@11.8.3": - version "11.8.3" - resolved "https://registry.yarnpkg.com/@reactflow/core/-/core-11.8.3.tgz#03ffeb06fbc141b8f786cb4ac8169f8a51a5f00e" - integrity sha512-y6DN8Wy4V4KQBGHFqlj9zWRjLJU6CgdnVwWaEA/PdDg/YUkFBMpZnXqTs60czinoA2rAcvsz50syLTPsj5e+Wg== +"@reactflow/core@11.9.3": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@reactflow/core/-/core-11.9.3.tgz#5212092e5f1ad741e9bd36b4e1a785a7611fd9da" + integrity sha512-45o8X1sjF48wSWALHybbLoWF6yo9SARgJpMKm96J8ZL8mrNhqSjll77sLRJg6zQ+VKdDwotEN30jp5eY6i28tw== dependencies: "@types/d3" "^7.4.0" "@types/d3-drag" "^3.0.1" @@ -1622,12 +1637,12 @@ d3-zoom "^3.0.0" zustand "^4.4.1" -"@reactflow/minimap@11.6.3": - version "11.6.3" - resolved "https://registry.yarnpkg.com/@reactflow/minimap/-/minimap-11.6.3.tgz#1cfddd87e9afd23ad704167988c66bd683ffc5d2" - integrity sha512-PSA28dk09RnBHOA1zb45fjQXz3UozSJZmsIpgq49O3trfVFlSgRapxNdGsughWLs7/emg2M5jmi6Vc+ejcfjvQ== +"@reactflow/minimap@11.7.3": + version "11.7.3" + resolved "https://registry.yarnpkg.com/@reactflow/minimap/-/minimap-11.7.3.tgz#d6ed45d48080e2d8bbd0af255dec958aca523574" + integrity sha512-u620uYwjmA5tJ/4p+F/0kyjNojvV0axTMSw87d/CCDij96m+2/drwqMW+BE8XHEqjG0c1HyplrkXQ3WhGu6ZaA== dependencies: - "@reactflow/core" "11.8.3" + "@reactflow/core" "11.9.3" "@types/d3-selection" "^3.0.3" "@types/d3-zoom" "^3.0.1" classcat "^5.0.3" @@ -1635,40 +1650,40 @@ d3-zoom "^3.0.0" zustand "^4.4.1" -"@reactflow/node-resizer@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@reactflow/node-resizer/-/node-resizer-2.1.5.tgz#f4033946ccc9cc8f47a94ed93f10a32befd546f1" - integrity sha512-z/hJlsptd2vTx13wKouqvN/Kln08qbkA+YTJLohc2aJ6rx3oGn9yX4E4IqNxhA7zNqYEdrnc1JTEA//ifh9z3w== +"@reactflow/node-resizer@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@reactflow/node-resizer/-/node-resizer-2.2.3.tgz#94665174cbf0524a3733bac836f5428f851b50e3" + integrity sha512-x1TXN4YZhBI1LxNegVsE51emUg1rf4rBgvNL8Tzj0xsKkD/av4DOzRizQ3xAGgk0joPrsOTiGiP511m/PWjsew== dependencies: - "@reactflow/core" "11.8.3" + "@reactflow/core" "11.9.3" classcat "^5.0.4" d3-drag "^3.0.0" d3-selection "^3.0.0" zustand "^4.4.1" -"@reactflow/node-toolbar@1.2.7": - version "1.2.7" - resolved "https://registry.yarnpkg.com/@reactflow/node-toolbar/-/node-toolbar-1.2.7.tgz#cf6639945dc42b42416f293d6132e1187bca3424" - integrity sha512-vs+Wg1tjy3SuD7eoeTqEtscBfE9RY+APqC28urVvftkrtsN7KlnoQjqDG6aE45jWP4z+8bvFizRWjAhxysNLkg== +"@reactflow/node-toolbar@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@reactflow/node-toolbar/-/node-toolbar-1.3.3.tgz#ccedd3522a43426438e69c204c281f2bb6609f40" + integrity sha512-juNFBLZgC+KOYpVaQFTkSQTDf4hYK7WAagiQQ4Dw0IUcLaMY3TA31OLP6X6gMG73YGKFmkgrDwi0ZDB0jpMqdA== dependencies: - "@reactflow/core" "11.8.3" + "@reactflow/core" "11.9.3" classcat "^5.0.3" zustand "^4.4.1" -"@reduxjs/toolkit@^1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" - integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== +"@reduxjs/toolkit@^1.9.7": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.7.tgz#7fc07c0b0ebec52043f8cb43510cf346405f78a6" + integrity sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ== dependencies: immer "^9.0.21" redux "^4.2.1" redux-thunk "^2.4.2" reselect "^4.1.8" -"@roarr/browser-log-writer@^1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@roarr/browser-log-writer/-/browser-log-writer-1.1.5.tgz#755ff62ddaa297bb3488067408a7085db382352b" - integrity sha512-yLn//DRjh1/rUgZpZkwmT/5RqHYfkdOwGXWXnKBR3l/HE04DIhSVeYin3sc8aWHBa7s7WglQpYX/uw/WI6POpw== +"@roarr/browser-log-writer@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@roarr/browser-log-writer/-/browser-log-writer-1.3.0.tgz#64aeb65ac88050f0e8c133876e548bec05cfa4af" + integrity sha512-RTzjxrm0CpTSoESmsO6104VymAksDS/yJEkaZrL/OLfbM6q+J+jLRBLtJxhJHSY03pBWOEE3wRh+pVwfKtBPqg== dependencies: boolean "^3.1.4" globalthis "^1.0.2" @@ -1691,10 +1706,10 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rushstack/node-core-library@3.59.7": - version "3.59.7" - resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz#9dcd62b79263e8a5b68465d4bf9124ec86e14b6c" - integrity sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw== +"@rushstack/node-core-library@3.61.0": + version "3.61.0" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.61.0.tgz#7441a0d2ae5268b758a7a49588a78cd55af57e66" + integrity sha512-tdOjdErme+/YOu4gPed3sFS72GhtWCgNV9oDsHDnoLY5oDfwjKUc9Z+JOZZ37uAxcm/OCahDHfuu2ugqrfWAVQ== dependencies: colors "~1.2.1" fs-extra "~7.0.1" @@ -1704,18 +1719,18 @@ semver "~7.5.4" z-schema "~5.0.2" -"@rushstack/rig-package@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.4.1.tgz#ff11bf67dad46f9b4f09db91cf45739ab411ee9f" - integrity sha512-AGRwpqlXNSp9LhUSz4HKI9xCluqQDt/obsQFdv/NYIekF3pTTPzc+HbQsIsjVjYnJ3DcmxOREVMhvrMEjpiq6g== +"@rushstack/rig-package@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.5.1.tgz#6c9c283cc96b5bb1eae9875946d974ac5429bb21" + integrity sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA== dependencies: resolve "~1.22.1" strip-json-comments "~3.1.1" -"@rushstack/ts-command-line@4.15.2": - version "4.15.2" - resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.15.2.tgz#7920e3fa2ab6af129d995ce4424c600da0bf8a93" - integrity sha512-5+C2uoJY8b+odcZD6coEe2XNC4ZjGB4vCMESbqW/8DHRWC/qIHfANdmN9F1wz/lAgxz72i7xRoVtPY2j7e4gpQ== +"@rushstack/ts-command-line@4.16.1": + version "4.16.1" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.16.1.tgz#3537bbc323f77c8646646465c579b992d39feb16" + integrity sha512-+OCsD553GYVLEmz12yiFjMOzuPeCiZ3f8wTiFHL30ZVXexTyPmgjwXEhg2K2P0a2lVf+8YBy7WtPoflB2Fp8/A== dependencies: "@types/argparse" "1.0.38" argparse "~1.0.9" @@ -1734,71 +1749,84 @@ dependencies: pako "^2.1.0" -"@swc/core-darwin-arm64@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.70.tgz#056ac6899e22cb7f7be21388d4d938ca5123a72b" - integrity sha512-31+mcl0dgdRHvZRjhLOK9V6B+qJ7nxDZYINr9pBlqGWxknz37Vld5KK19Kpr79r0dXUZvaaelLjCnJk9dA2PcQ== +"@swc/core-darwin-arm64@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.93.tgz#aefd94625451988286bebccb1c072bae0a36bcdb" + integrity sha512-gEKgk7FVIgltnIfDO6GntyuQBBlAYg5imHpRgLxB1zSI27ijVVkksc6QwISzFZAhKYaBWIsFSVeL9AYSziAF7A== -"@swc/core-darwin-x64@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.70.tgz#3945814de6fadbee5b46cb2a3422353acb420c5c" - integrity sha512-GMFJ65E18zQC80t0os+TZvI+8lbRuitncWVge/RXmXbVLPRcdykP4EJ87cqzcG5Ah0z18/E0T+ixD6jHRisrYQ== +"@swc/core-darwin-x64@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.93.tgz#18409c6effdf508ddf1ebccfa77d35aaa6cd72f0" + integrity sha512-ZQPxm/fXdDQtn3yrYSL/gFfA8OfZ5jTi33yFQq6vcg/Y8talpZ+MgdSlYM0FkLrZdMTYYTNFiuBQuuvkA+av+Q== -"@swc/core-linux-arm-gnueabihf@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.70.tgz#7960e54ede1af75a7ef99ee53febf37fea6269a8" - integrity sha512-wjhCwS8LCiAq2VedF1b4Bryyw68xZnfMED4pLRazAl8BaUlDFANfRBORNunxlfHQj4V3x39IaiLgCZRHMdzXBg== +"@swc/core-linux-arm-gnueabihf@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.93.tgz#23a97bc94a8b2f23fb6cc4bc9d8936899e5eeff5" + integrity sha512-OYFMMI2yV+aNe3wMgYhODxHdqUB/jrK0SEMHHS44GZpk8MuBXEF+Mcz4qjkY5Q1EH7KVQqXb/gVWwdgTHpjM2A== -"@swc/core-linux-arm64-gnu@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.70.tgz#df9654e5040bbeb1619739756a7f50100e38ace8" - integrity sha512-9D/Rx67cAOnMiexvCqARxvhj7coRajTp5HlJHuf+rfwMqI2hLhpO9/pBMQxBUAWxODO/ksQ/OF+GJRjmtWw/2A== +"@swc/core-linux-arm64-gnu@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.93.tgz#7a17406a7cf76a959a617626d5ee2634ae9afa26" + integrity sha512-BT4dT78odKnJMNiq5HdjBsv29CiIdcCcImAPxeFqAeFw1LL6gh9nzI8E96oWc+0lVT5lfhoesCk4Qm7J6bty8w== -"@swc/core-linux-arm64-musl@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.70.tgz#2c2aab5a136c7eb409ddc9cdc4f947a68fd74493" - integrity sha512-gkjxBio7XD+1GlQVVyPP/qeFkLu83VhRHXaUrkNYpr5UZG9zZurBERT9nkS6Y+ouYh+Q9xmw57aIyd2KvD2zqQ== +"@swc/core-linux-arm64-musl@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.93.tgz#a30be7780090afefd3b8706398418cbe1d23db49" + integrity sha512-yH5fWEl1bktouC0mhh0Chuxp7HEO4uCtS/ly1Vmf18gs6wZ8DOOkgAEVv2dNKIryy+Na++ljx4Ym7C8tSJTrLw== -"@swc/core-linux-x64-gnu@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.70.tgz#774351532b154ed36a5c6d14b647e7a8ab510028" - integrity sha512-/nCly+V4xfMVwfEUoLLAukxUSot/RcSzsf6GdsGTjFcrp5sZIntAjokYRytm3VT1c2TK321AfBorsi9R5w8Y7Q== +"@swc/core-linux-x64-gnu@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.93.tgz#41e903fd82e059952d16051b442cbe65ee5b8cb3" + integrity sha512-OFUdx64qvrGJhXKEyxosHxgoUVgba2ztYh7BnMiU5hP8lbI8G13W40J0SN3CmFQwPP30+3oEbW7LWzhKEaYjlg== -"@swc/core-linux-x64-musl@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.70.tgz#c0b1b4ad5f4ef187eaa093589a4933ecb6836546" - integrity sha512-HoOsPJbt361KGKaivAK0qIiYARkhzlxeAfvF5NlnKxkIMOZpQ46Lwj3tR0VWohKbrhS+cYKFlVuDi5XnDkx0XA== +"@swc/core-linux-x64-musl@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.93.tgz#0866807545c44eac9b3254b374310ad5e1c573f9" + integrity sha512-4B8lSRwEq1XYm6xhxHhvHmKAS7pUp1Q7E33NQ2TlmFhfKvCOh86qvThcjAOo57x8DRwmpvEVrqvpXtYagMN6Ig== -"@swc/core-win32-arm64-msvc@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.70.tgz#8640267ce3959db0e7e682103677a5e0500b5ea7" - integrity sha512-hm4IBK/IaRil+aj1cWU6f0GyAdHpw/Jr5nyFYLM2c/tt7w2t5hgb8NjzM2iM84lOClrig1fG6edj2vCF1dFzNQ== +"@swc/core-win32-arm64-msvc@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.93.tgz#c72411dea2fd4f62a832f71a6e15424d849e7610" + integrity sha512-BHShlxtkven8ZjjvZ5QR6sC5fZCJ9bMujEkiha6W4cBUTY7ce7qGFyHmQd+iPC85d9kD/0cCiX/Xez8u0BhO7w== -"@swc/core-win32-ia32-msvc@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.70.tgz#f95d5656622f5a963bc0125da9fda84cf40faa8d" - integrity sha512-5cgKUKIT/9Fp5fCA+zIjYCQ4dSvjFYOeWGZR3QiTXGkC4bGa1Ji9SEPyeIAX0iruUnKjYaZB9RvHK2tNn7RLrQ== +"@swc/core-win32-ia32-msvc@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.93.tgz#05c2b031b976af4ef81f5073ee114254678a5d5d" + integrity sha512-nEwNWnz4JzYAK6asVvb92yeylfxMYih7eMQOnT7ZVlZN5ba9WF29xJ6kcQKs9HRH6MvWhz9+wRgv3FcjlU6HYA== -"@swc/core-win32-x64-msvc@1.3.70": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.70.tgz#5b3acddb96fdf60df089b837061915cb4be94eaa" - integrity sha512-LE8lW46+TQBzVkn2mHBlk8DIElPIZ2dO5P8AbJiARNBAnlqQWu67l9gWM89UiZ2l33J2cI37pHzON3tKnT8f9g== +"@swc/core-win32-x64-msvc@1.3.93": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.93.tgz#f8748b3fd1879f13084b1b0814edf328c662935c" + integrity sha512-jibQ0zUr4kwJaQVwgmH+svS04bYTPnPw/ZkNInzxS+wFAtzINBYcU8s2PMWbDb2NGYiRSEeoSGyAvS9H+24JFA== -"@swc/core@^1.3.61": - version "1.3.70" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.70.tgz#f5ddc6fe6add7a99f5b94d2214ad0d8527d11479" - integrity sha512-LWVWlEDLlOD25PvA2NEz41UzdwXnlDyBiZbe69s3zM0DfCPwZXLUm79uSqH9ItsOjTrXSL5/1+XUL6C/BZwChA== +"@swc/core@^1.3.85": + version "1.3.93" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.93.tgz#be4282aa44deffb0e5081a2613bac00335600630" + integrity sha512-690GRr1wUGmGYZHk7fUduX/JUwViMF2o74mnZYIWEcJaCcd9MQfkhsxPBtjeg6tF+h266/Cf3RPYhsFBzzxXcA== + dependencies: + "@swc/counter" "^0.1.1" + "@swc/types" "^0.1.5" optionalDependencies: - "@swc/core-darwin-arm64" "1.3.70" - "@swc/core-darwin-x64" "1.3.70" - "@swc/core-linux-arm-gnueabihf" "1.3.70" - "@swc/core-linux-arm64-gnu" "1.3.70" - "@swc/core-linux-arm64-musl" "1.3.70" - "@swc/core-linux-x64-gnu" "1.3.70" - "@swc/core-linux-x64-musl" "1.3.70" - "@swc/core-win32-arm64-msvc" "1.3.70" - "@swc/core-win32-ia32-msvc" "1.3.70" - "@swc/core-win32-x64-msvc" "1.3.70" + "@swc/core-darwin-arm64" "1.3.93" + "@swc/core-darwin-x64" "1.3.93" + "@swc/core-linux-arm-gnueabihf" "1.3.93" + "@swc/core-linux-arm64-gnu" "1.3.93" + "@swc/core-linux-arm64-musl" "1.3.93" + "@swc/core-linux-x64-gnu" "1.3.93" + "@swc/core-linux-x64-musl" "1.3.93" + "@swc/core-win32-arm64-msvc" "1.3.93" + "@swc/core-win32-ia32-msvc" "1.3.93" + "@swc/core-win32-x64-msvc" "1.3.93" + +"@swc/counter@^0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.2.tgz#bf06d0770e47c6f1102270b744e17b934586985e" + integrity sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw== + +"@swc/types@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" + integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== "@types/argparse@1.0.38": version "1.0.38" @@ -2061,10 +2089,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash-es@^4.14.194": - version "4.17.8" - resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.8.tgz#cfffd0969507830c22da18dbb20d2ca126fdaa8b" - integrity sha512-euY3XQcZmIzSy7YH5+Unb3b2X12Wtk54YWINBvvGQ5SmMvwb11JQskGsfkH/5HXK77Kr8GF0wkVDIxzAisWtog== +"@types/lodash-es@^4.17.9": + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.9.tgz#49dbe5112e23c54f2b387d860b7d03028ce170c2" + integrity sha512-ZTcmhiI3NNU7dEvWLZJkzG6ao49zOIjEgIE0RgV7wbPxU0f2xT3VSAHw2gmst8swH6V0YkLRGp4qPlX/6I90MQ== dependencies: "@types/lodash" "*" @@ -2080,10 +2108,12 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== -"@types/node@^20.5.1": - version "20.5.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.1.tgz#178d58ee7e4834152b0e8b4d30cbfab578b9bb30" - integrity sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg== +"@types/node@^20.8.6": + version "20.8.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.6.tgz#0dbd4ebcc82ad0128df05d0e6f57e05359ee47fa" + integrity sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ== + dependencies: + undici-types "~5.25.1" "@types/parse-json@^4.0.0": version "4.0.0" @@ -2095,10 +2125,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/react-dom@^18.2.6": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" - integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== +"@types/react-dom@^18.2.13": + version "18.2.13" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.13.tgz#89cd7f9ec8b28c8b6f0392b9591671fb4a9e96b7" + integrity sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw== dependencies: "@types/react" "*" @@ -2109,20 +2139,20 @@ dependencies: "@types/react" "*" -"@types/react-redux@^7.1.25": - version "7.1.25" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88" - integrity sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg== +"@types/react-redux@^7.1.27": + version "7.1.27" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.27.tgz#1afb31f7354bf787e162c10ff3fa19bafa9e6b57" + integrity sha512-xj7d9z32p1K/eBmO+OEy+qfaWXtcPlN8f1Xk3Ne0p/ZRQ867RI5bQ/bpBtxbqU1AHNhKJSgGvld/P2myU2uYkg== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-transition-group@^4.4.6": - version "4.4.6" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e" - integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== +"@types/react-transition-group@^4.4.7": + version "4.4.7" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.7.tgz#bf69f269d74aa78b99097673ca6dd6824a68ef1c" + integrity sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg== dependencies: "@types/react" "*" @@ -2135,10 +2165,10 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^18.2.20": - version "18.2.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" - integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== +"@types/react@^18.2.28": + version "18.2.28" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.28.tgz#86877465c0fcf751659a36c769ecedfcfacee332" + integrity sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2159,21 +2189,21 @@ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== -"@types/uuid@^9.0.2": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b" - integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ== +"@types/uuid@^9.0.5": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.5.tgz#25a71eb73eba95ac0e559ff3dd018fc08294acf6" + integrity sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ== -"@typescript-eslint/eslint-plugin@^6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.1.tgz#bc0c6f000134b53c304ad0bec4ee4753cd3e89d2" - integrity sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw== +"@typescript-eslint/eslint-plugin@^6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz#f4024b9f63593d0c2b5bd6e4ca027e6f30934d4f" + integrity sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.4.1" - "@typescript-eslint/type-utils" "6.4.1" - "@typescript-eslint/utils" "6.4.1" - "@typescript-eslint/visitor-keys" "6.4.1" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/type-utils" "6.7.5" + "@typescript-eslint/utils" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -2181,32 +2211,32 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.4.1.tgz#85ad550bf4ac4aa227504f1becb828f8e46c44e3" - integrity sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg== +"@typescript-eslint/parser@^6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.5.tgz#8d7ca3d1fbd9d5a58cc4d30b2aa797a760137886" + integrity sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw== dependencies: - "@typescript-eslint/scope-manager" "6.4.1" - "@typescript-eslint/types" "6.4.1" - "@typescript-eslint/typescript-estree" "6.4.1" - "@typescript-eslint/visitor-keys" "6.4.1" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/typescript-estree" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz#4b073a30be2dbe603e44e9ae0cff7e1d3ed19278" - integrity sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A== +"@typescript-eslint/scope-manager@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz#1cf33b991043886cd67f4f3600b8e122fc14e711" + integrity sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A== dependencies: - "@typescript-eslint/types" "6.4.1" - "@typescript-eslint/visitor-keys" "6.4.1" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" -"@typescript-eslint/type-utils@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.4.1.tgz#fa21cb13016c8d6f352fe9b2d6c9ab6edc2d1857" - integrity sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA== +"@typescript-eslint/type-utils@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz#0a65949ec16588d8956f6d967f7d9c84ddb2d72a" + integrity sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g== dependencies: - "@typescript-eslint/typescript-estree" "6.4.1" - "@typescript-eslint/utils" "6.4.1" + "@typescript-eslint/typescript-estree" "6.7.5" + "@typescript-eslint/utils" "6.7.5" debug "^4.3.4" ts-api-utils "^1.0.1" @@ -2220,18 +2250,18 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.4.1.tgz#b2c61159f46dda210fed9f117f5d027f65bb5c3b" - integrity sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg== +"@typescript-eslint/types@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.5.tgz#4571320fb9cf669de9a95d9849f922c3af809790" + integrity sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ== -"@typescript-eslint/typescript-estree@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz#91ff88101c710adb0f70a317f2f65efa9441da45" - integrity sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg== +"@typescript-eslint/typescript-estree@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz#4578de1a26e9f24950f029a4f00d1bfe41f15a39" + integrity sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg== dependencies: - "@typescript-eslint/types" "6.4.1" - "@typescript-eslint/visitor-keys" "6.4.1" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -2264,17 +2294,17 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.4.1.tgz#81bf62ff0c3119a26c19fab683582e29450717bc" - integrity sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw== +"@typescript-eslint/utils@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.5.tgz#ab847b53d6b65e029314b8247c2336843dba81ab" + integrity sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.4.1" - "@typescript-eslint/types" "6.4.1" - "@typescript-eslint/typescript-estree" "6.4.1" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/typescript-estree" "6.7.5" semver "^7.5.4" "@typescript-eslint/visitor-keys@4.33.0": @@ -2293,20 +2323,20 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz#e3ccf7b8d42e625946ac5094ed92a405fb4115e0" - integrity sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ== +"@typescript-eslint/visitor-keys@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz#84c68d6ceb5b12d5246b918b84f2b79affd6c2f1" + integrity sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg== dependencies: - "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/types" "6.7.5" eslint-visitor-keys "^3.4.1" -"@vitejs/plugin-react-swc@^3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz#34a82c1728066f48a86dfecb2f15df60f89207fb" - integrity sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA== +"@vitejs/plugin-react-swc@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.4.0.tgz#53ca6a07423abadec92f967e188d5ba49b350830" + integrity sha512-m7UaA4Uvz82N/0EOVpZL4XsFIakRqrFKeSNxa1FBLSXGvWrWRBwmZb4qxk+ZIVAZcW3c3dn5YosomDgx62XWcQ== dependencies: - "@swc/core" "^1.3.61" + "@swc/core" "^1.3.85" "@volar/language-core@1.10.1", "@volar/language-core@~1.10.0": version "1.10.1" @@ -2391,22 +2421,22 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zag-js/dom-query@0.10.5": - version "0.10.5" - resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-0.10.5.tgz#9fc02a51383989667694d8747925e6d20294af9e" - integrity sha512-zm6wA5+kqU48it6afNjaUhjVSixKZruTKB23z0V1xBqKbuiLOMMOZ5oK26cTPSXtZ5CPhDNZ2Qk4pliS5n9SVw== +"@zag-js/dom-query@0.16.0": + version "0.16.0" + resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-0.16.0.tgz#bca46bcd78f78c900064478646d95f9781ed098e" + integrity sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ== "@zag-js/element-size@0.10.5": version "0.10.5" resolved "https://registry.yarnpkg.com/@zag-js/element-size/-/element-size-0.10.5.tgz#a24bad2eeb7e2c8709e32be5336e158e1a1a174f" integrity sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w== -"@zag-js/focus-visible@0.10.5": - version "0.10.5" - resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.10.5.tgz#643e196ea768bea5ce54771102fae22f5e9ba3c7" - integrity sha512-EhDHKLutMtvLFCjBjyIY6h1JoJJNXG3KJz7Dj1sh4tj4LWAqo/TqLvgHyUTB29XMHwoslFHDJHKVWmLGMi+ULQ== +"@zag-js/focus-visible@0.16.0": + version "0.16.0" + resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.16.0.tgz#c9e53e3dbab0f2649d04a489bb379f5800f4f069" + integrity sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA== dependencies: - "@zag-js/dom-query" "0.10.5" + "@zag-js/dom-query" "0.16.0" acorn-jsx@^5.3.2: version "5.3.2" @@ -2516,7 +2546,7 @@ argparse@~1.0.9: dependencies: sprintf-js "~1.0.2" -aria-hidden@^1.1.3, aria-hidden@^1.2.2: +aria-hidden@^1.1.3, aria-hidden@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== @@ -2632,10 +2662,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axios@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" - integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== +axios@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" + integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -2918,7 +2948,7 @@ color-name@^1.1.4, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color2k@^2.0.0: +color2k@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.2.tgz#ac2b4aea11c822a6bcb70c768b5a289f4fffcebb" integrity sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w== @@ -2940,10 +2970,10 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" - integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== +commander@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== commander@^10.0.0: version "10.0.1" @@ -2975,20 +3005,20 @@ compare-versions@^6.1.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== -compute-scroll-into-view@1.0.20: - version "1.0.20" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43" - integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg== +compute-scroll-into-view@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz#c418900a5c56e2b04b885b54995df164535962b1" + integrity sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A== concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.0.tgz#cdc9f621a4d913366600355d68254df2c5e782f3" - integrity sha512-nnLMxO2LU492mTUj9qX/az/lESonSZu81UznYDoXtz1IQf996ixVqPAgHXwvHiHCAef/7S8HIK+fTFK7Ifk8YA== +concurrently@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.1.tgz#bcab9cacc38c23c503839583151e0fa96fd5b584" + integrity sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ== dependencies: chalk "^4.1.2" date-fns "^2.30.0" @@ -3642,10 +3672,10 @@ eslint-config-prettier@^9.0.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== -eslint-plugin-prettier@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz#6887780ed95f7708340ec79acfdf60c35b9be57a" - integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w== +eslint-plugin-prettier@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515" + integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg== dependencies: prettier-linter-helpers "^1.0.0" synckit "^0.8.5" @@ -3700,16 +3730,16 @@ eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.47.0: - version "8.47.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806" - integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q== +eslint@^8.51.0: + version "8.51.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" + integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "^8.47.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint/js" "8.51.0" + "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" ajv "^6.12.4" @@ -3791,19 +3821,19 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -execa@7.2.0, execa@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== +execa@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== dependencies: cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" + get-stream "^8.0.1" + human-signals "^5.0.0" is-stream "^3.0.0" merge-stream "^2.0.0" npm-run-path "^5.1.0" onetime "^6.0.0" - signal-exit "^3.0.7" + signal-exit "^4.1.0" strip-final-newline "^3.0.0" execa@^5.0.0: @@ -3821,6 +3851,21 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -4020,11 +4065,12 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formik@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.3.tgz#6020e85eb3e3e8415b3b19d6f4f65793ab754b24" - integrity sha512-2Dy79Szw3zlXmZiokUdKsn+n1ow4G8hRrC/n92cOWHNTWXCRpQXlyvz6HcjW7aSQZrldytvDOavYjhfmDnUq8Q== +formik@^2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.5.tgz#f899b5b7a6f103a8fabb679823e8fafc7e0ee1b4" + integrity sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ== dependencies: + "@types/hoist-non-react-statics" "^3.3.1" deepmerge "^2.1.1" hoist-non-react-statics "^3.3.0" lodash "^4.17.21" @@ -4033,10 +4079,10 @@ formik@^2.4.3: tiny-warning "^1.0.2" tslib "^2.0.0" -framer-motion@^10.16.1: - version "10.16.1" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.16.1.tgz#0ff5de554bbb35ee6605357d80f92b27d0271a94" - integrity sha512-K6TXr5mZtitC/dxQCBdg7xzdN0d5IAIrlaqCPKtIQVdzVPGC0qBuJKXggHX1vjnP5gPOFwB1KbCCTWcnFc3kWg== +framer-motion@^10.16.4: + version "10.16.4" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.16.4.tgz#30279ef5499b8d85db3a298ee25c83429933e9f8" + integrity sha512-p9V9nGomS3m6/CALXqv6nFGMuFOxbWsmaOrdmhyQimMIlLl3LC7h7l86wge/Js/8cRu5ktutS/zlzgR7eBOtFA== dependencies: tslib "^2.4.0" optionalDependencies: @@ -4149,6 +4195,11 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -4313,6 +4364,11 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + husky@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" @@ -4330,17 +4386,17 @@ i18next-browser-languagedetector@^7.0.2: dependencies: "@babel/runtime" "^7.19.4" -i18next-http-backend@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.2.1.tgz#cdb7efbafa46ce8f237d9db443f62514664a3bdf" - integrity sha512-ZXIdn/8NJIBJ0X4hzXfc3STYxKrCKh1fYjji9HPyIpEJfvTvy8/ZlTl8RuTizzCPj2ZcWrfaecyOMKs6bQ7u5A== +i18next-http-backend@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.2.2.tgz#3ee16dfe5fe33524ec8925d4f0bf1508ebbbfadf" + integrity sha512-mJu4ZqzDtBiU3O4GV9AbK5ekEqoDMdMnCl3pkdXmb5b8yoIH//u8FsmIe6C5qXb3teZu+j6VMi20tjUgzeABiw== dependencies: cross-fetch "3.1.6" -i18next@^23.4.4: - version "23.4.4" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.4.4.tgz#ec8fb2b5f3c5d8e3bf3f8ab1b19e743be91300e0" - integrity sha512-+c9B0txp/x1m5zn+QlwHaCS9vyFtmIAEXbVSFzwCX7vupm5V7va8F9cJGNJZ46X9ZtoGzhIiRC7eTIIh93TxPA== +i18next@^23.5.1: + version "23.5.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.5.1.tgz#7f7c35ffaa907618d9489f106d5006b09fbca3d3" + integrity sha512-JelYzcaCoFDaa+Ysbfz2JsGAKkrHiMG6S61+HLBUEIPaF40WMwW9hCPymlQGrP+wWawKxKPuSuD71WZscCsWHg== dependencies: "@babel/runtime" "^7.22.5" @@ -4837,10 +4893,10 @@ kolorist@^1.8.0: resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== -konva@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/konva/-/konva-9.2.0.tgz#3739e539724b0e6b76d697a322efdaa01baa1508" - integrity sha512-+woI76Sk+VFVl9z7zPkuTnN2zFpEYg27YWz8BCdQXpt5IS3pdnSPAPQVPPMidcbDi9/G5b/IOIp35/KqMGiYPA== +konva@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/konva/-/konva-9.2.2.tgz#972105ec79a89c60296d5e36d1f7cef9b84a42d4" + integrity sha512-Gyn5hQa/5+8pJvTn/IVyZWgum2otWXszuVCG/cevkAyKUFcmFv4tGbQhHFGtJPLQkGO+W6xfgRzyYIkNgKnPxA== levn@^0.4.1: version "0.4.1" @@ -4860,21 +4916,21 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-14.0.1.tgz#57dfa3013a3d60762d9af5d9c83bdb51291a6232" - integrity sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw== +lint-staged@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.0.1.tgz#1db47c315c79bafe993aa33a0b50cbfeef50d906" + integrity sha512-2IU5OWmCaxch0X0+IBF4/v7sutpB+F3qoXbro43pYjQTOo5wumckjxoxn47pQBqqBsCWrD5HnI2uG/zJA7isew== dependencies: chalk "5.3.0" - commander "11.0.0" + commander "11.1.0" debug "4.3.4" - execa "7.2.0" + execa "8.0.1" lilconfig "2.1.0" - listr2 "6.6.1" + listr2 "7.0.1" micromatch "4.0.5" pidtree "0.6.0" string-argv "0.3.2" - yaml "2.3.1" + yaml "2.3.2" liqe@^3.6.0: version "3.6.1" @@ -4884,10 +4940,10 @@ liqe@^3.6.0: nearley "^2.20.1" ts-error "^1.0.6" -listr2@6.6.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d" - integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== +listr2@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-7.0.1.tgz#18e7a655b189cd7a8a76575a26f4d494b6ffc2c2" + integrity sha512-nz+7hwgbDp8eWNoDgzdl4hA/xDSLrNRzPu1TLgOYs6l5Y+Ma6zVWWy9Oyt9TQFONwKoSPoka3H50D3vD5EuNwg== dependencies: cli-truncate "^3.1.0" colorette "^2.0.20" @@ -5299,27 +5355,27 @@ open@^9.1.0: is-inside-container "^1.0.0" is-wsl "^2.2.0" -openapi-fetch@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.7.4.tgz#3676e0c44433bfa6701cd408853fec75599a9f0d" - integrity sha512-ACoSikOuFO3sMROtqritJAsGd694gRNXFnWpYAqi+tQzowLOkcQ6SbeAvS+T6qNS92y/OLiiYcNrb/Rh/MrEVw== +openapi-fetch@^0.7.10: + version "0.7.10" + resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.7.10.tgz#624c928a646b53561ff2703f00d5617fa88a72df" + integrity sha512-lDZkHjSxBuSTPXkJuJ9kSpkLxY9jgsVHbKkhS7rukoKi5et5QUlWCEzO/E6PaSHTQkJDPOjXdBJeDOSj2e8QwQ== dependencies: - openapi-typescript-helpers "^0.0.1" + openapi-typescript-helpers "^0.0.4" openapi-types@^12.1.3: version "12.1.3" resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== -openapi-typescript-helpers@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.1.tgz#865c9b66f18db89e41cd0d770170719610f68d2d" - integrity sha512-WDmxej0eHSZtLgCuyPEn2NXRV7tcvUnBBNP/0c/U66mOlxs6Yn0/dHuWlkVKdHGNahSUwG57A1tyutHWRpWqFg== +openapi-typescript-helpers@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.4.tgz#ffe7c4868f094fcc8502dbdcddc6c32ce8011aee" + integrity sha512-Q0MTapapFAG993+dx8lNw33X6P/6EbFr31yNymJHq56fNc6dODyRm8tWyRnGxuC74lyl1iCRMV6nQCGQsfVNKg== -openapi-typescript@^6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.5.2.tgz#622e54e6de25bd65c65a1f129be42193160e6e42" - integrity sha512-Zz41utYZ3BAyr32QhOATSnN9zcWMsJeA4Jdq7xQjfYOdZbQfI8Fvsvx41Doe9Wvoho1aj5cP9b5Z7kHtG6mYvg== +openapi-typescript@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.7.0.tgz#6d1a4dfc0db60b61573a3ea3c52984a79c638c67" + integrity sha512-eoUfJwhnMEug7euZ1dATG7iRiDVsEROwdPkhLUDiaFjcClV4lzft9F0Ii0fYjULCPNIiWiFi0BqMpSxipuvAgQ== dependencies: ansi-colors "^4.1.3" fast-glob "^3.3.1" @@ -5360,15 +5416,15 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -overlayscrollbars-react@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.1.tgz#b5dde9803bae0115f0f214db0c60cdf98213eedb" - integrity sha512-0xw9J1CT/cQ+ELYy3hudG6nY1H5dgJ1DdVW3d8aZwqx6wyHNZV4nsBQXUxoHmPo3dmlJ5MvOLzpKWA4X6nL4QA== +overlayscrollbars-react@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.2.tgz#b8a6294279a1d0984392586b56a03df78d6c1e34" + integrity sha512-y3xIPY3to7hneF30MQ/tK9nI6UOcflgenAYktgyfi0GuwnsYEuAqgLfs2qDGiNhFA30Xcz3gaMxvqD7+hTvFRA== -overlayscrollbars@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.2.1.tgz#2a6d43ebba5188a394a8b99611f39e22aad6e0c0" - integrity sha512-5oMxq4UCiEVLiOSvovbX8p+P2NtPosjHC0KkIcaobnYuxGwMyTOwBCtBdqO1tXrrA02VVrNzuIjGMLisO2mIwg== +overlayscrollbars@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.3.2.tgz#1f31daa0b808f5d4710a59c73eb579397745dd72" + integrity sha512-K3Sau7NpFruKfXBauvchAQshAW+un1qD8EYNcozrPAB2kbif8C2rqa+1EWvMMWPKl88wgf2rX2QDMLgAfR0hHA== p-limit@^3.0.2: version "3.1.0" @@ -5577,10 +5633,10 @@ prettier@^2.0.5, prettier@^2.8.8: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.2.tgz#78fcecd6d870551aa5547437cdae39d4701dca5b" - integrity sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ== +prettier@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== pretty-ms@^7.0.1: version "7.0.1" @@ -5686,10 +5742,10 @@ react-error-boundary@^4.0.11: dependencies: "@babel/runtime" "^7.12.5" -react-fast-compare@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.1.tgz#53933d9e14f364281d6cba24bfed7a4afb808b5f" - integrity sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg== +react-fast-compare@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== react-fast-compare@^2.0.1: version "2.0.4" @@ -5713,18 +5769,18 @@ react-hotkeys-hook@4.4.1: resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz#1f7a7a1c9c21d4fa3280bf340fcca8fd77d81994" integrity sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw== -react-i18next@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.1.2.tgz#dbb1b18c364295af2a9072333ee4e0b43cbc2da8" - integrity sha512-D/OJ/8ZQYscabsvbCAiOgvJq8W3feQF/VIV0to1w7V7UvrUE1IZ3hcalOckUYvKBd7BP3b8EPm+hop3J8sS+Mw== +react-i18next@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.3.0.tgz#8e39c0101f654db7eb971f159bb55067a78925c3" + integrity sha512-FlR9xjYHSPIJfQspEmkN0yOlxgRyNuiJKJ8gCaZH08UJ7SZHG+VrptEPcpEMEchjNoCOZdKcvJ3PnmHEZhkeXg== dependencies: "@babel/runtime" "^7.22.5" html-parse-stringify "^3.0.1" -react-icons@^4.10.1: - version "4.10.1" - resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.10.1.tgz#3f3b5eec1f63c1796f6a26174a1091ca6437a500" - integrity sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw== +react-icons@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65" + integrity sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA== react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" @@ -5754,10 +5810,10 @@ react-reconciler@~0.29.0: loose-envify "^1.1.0" scheduler "^0.23.0" -react-redux@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188" - integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw== +react-redux@^8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.3.tgz#4fdc0462d0acb59af29a13c27ffef6f49ab4df46" + integrity sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw== dependencies: "@babel/runtime" "^7.12.1" "@types/hoist-non-react-statics" "^3.3.1" @@ -5774,10 +5830,10 @@ react-remove-scroll-bar@^2.3.4: react-style-singleton "^2.2.1" tslib "^2.0.0" -react-remove-scroll@^2.5.5: - version "2.5.6" - resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.6.tgz#7510b8079e9c7eebe00e65a33daaa3aa29a10336" - integrity sha512-bO856ad1uDYLefgArk559IzUNeQ6SWH4QnrevIUjH+GczV56giDfl3h0Idptf2oIKxQmd1p9BN25jleKodTALg== +react-remove-scroll@^2.5.5, react-remove-scroll@^2.5.6: + version "2.5.7" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb" + integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA== dependencies: react-remove-scroll-bar "^2.3.4" react-style-singleton "^2.2.1" @@ -5833,15 +5889,15 @@ react-use@^17.4.0: ts-easing "^0.2.0" tslib "^2.1.0" -react-virtuoso@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.5.0.tgz#0bc043b4e3e928e7891aa541dd7e55d5b46db8c8" - integrity sha512-OMP6XrzJMMos1vbJZC16RxGW7utAxUMP7i5PNPi6epBNVH7nz+CF/DlmecNBep5wyjLud51dQ5epjb2A0w9W/Q== +react-virtuoso@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.6.1.tgz#b08465be4222d9820a22fbe2fefec29e91d0b048" + integrity sha512-dQq0yOdRjdWIYaiTvUbudqmTodGSdWGt5lVYz3mM07TTEV91yv7eL5Fn3FPEJOA36whScxPWg0GiYBIOZYEIEA== -react-zoom-pan-pinch@^3.0.8: - version "3.1.0" - resolved "https://registry.yarnpkg.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.1.0.tgz#d87a66fd22a97f5dd56b54076411a9dce1f448cd" - integrity sha512-a3LlP8QPgTikvteCNkZ3X6wIWC0lrg1geP5WkUJyx2MXXAhHQek3r17N1nT/esOiWGuPIECnsd9AGoK8jOeGcg== +react-zoom-pan-pinch@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.2.0.tgz#6ce7d014a8dc4aa62ce83ca57f85e76cf2e934b8" + integrity sha512-7MS0wYWoXjr6PrmpgHOVpVyNQr9gj7LEr4xIvq6lBy62nuNwjdI1r+XxahQ0SDHhWrLuSF11e2PTL/YLengYyg== react@^18.2.0: version "18.2.0" @@ -5850,17 +5906,17 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" -reactflow@^11.8.3: - version "11.8.3" - resolved "https://registry.yarnpkg.com/reactflow/-/reactflow-11.8.3.tgz#ad5cdf22408298956c92ab652929ff92206af9dc" - integrity sha512-wuVxJOFqi1vhA4WAEJLK0JWx2TsTiWpxTXTRp/wvpqKInQgQcB49I2QNyNYsKJCQ6jjXektS7H+LXoaVK/pG4A== +reactflow@^11.9.3: + version "11.9.3" + resolved "https://registry.yarnpkg.com/reactflow/-/reactflow-11.9.3.tgz#4723774370ff87403c574bdec43c93e809165854" + integrity sha512-GiIo20Vgy1U4h1NlLyQChWYgsl2OQkEgKHjokyQsdmm1nidywTr0n94O6w97ixLljKzJynTMjDdWP0p8xkq6NQ== dependencies: - "@reactflow/background" "11.2.8" - "@reactflow/controls" "11.1.19" - "@reactflow/core" "11.8.3" - "@reactflow/minimap" "11.6.3" - "@reactflow/node-resizer" "2.1.5" - "@reactflow/node-toolbar" "1.2.7" + "@reactflow/background" "11.3.3" + "@reactflow/controls" "11.2.3" + "@reactflow/core" "11.9.3" + "@reactflow/minimap" "11.7.3" + "@reactflow/node-resizer" "2.2.3" + "@reactflow/node-toolbar" "1.3.3" readable-stream@^3.4.0: version "3.6.2" @@ -5883,10 +5939,10 @@ redux-dynamic-middlewares@^2.2.0: resolved "https://registry.yarnpkg.com/redux-dynamic-middlewares/-/redux-dynamic-middlewares-2.2.0.tgz#6835dd6d4f2fd975266376b45dcae0141320ae97" integrity sha512-GHESQC+Y0PV98ZBoaC6br6cDOsNiM1Cu4UleGMqMWCXX03jIr3BoozYVrRkLVVAl4sC216chakMnZOu6SwNdGA== -redux-remember@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/redux-remember/-/redux-remember-4.0.1.tgz#fae416d140a9dccdf84285b957e7062934a337fb" - integrity sha512-mP/EWdBVKg0bJfe3srzofp5sNSmWBLjKX+JzJC7J+DBjbLaxTCsLXVq1fnE4rcHXb9Sz/4u5qZ040I/ZhKzjLw== +redux-remember@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/redux-remember/-/redux-remember-4.0.4.tgz#ca0b583088fdb1ff6d917c88ae80bb83001627de" + integrity sha512-a1T+UMYTa08Uq0YtCp0j5Z7v5yydbePPgfu4iAZ21Uk4ozcFfT/PoB9PwETFhHRxBW4Ij0yWPfPJw3mIE/CXlw== redux-thunk@^2.4.2: version "2.4.2" @@ -5917,6 +5973,11 @@ regenerator-runtime@^0.13.11: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" @@ -6169,10 +6230,10 @@ semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semve dependencies: lru-cache "^6.0.0" -serialize-error@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.1.tgz#7cfa2b54f7aca3e4cbfc0137259d94d93793f813" - integrity sha512-B5yw3/Lg+Daspbs0f+iO3Qim0+lALnaLS8aZUAy8Y0tO92tkOoMEuwtKo4jpZ5XO16CTwMi4tYN8cZQI3QF2Qw== +serialize-error@^11.0.2: + version "11.0.2" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.2.tgz#8c1a44f0ab872ee2c3ca6736ca5c750003bc1d04" + integrity sha512-o43i0jLcA0LXA5Uu+gI1Vj+lF66KR9IAcy0ThbGq1bAMPN+k5IgSHsulfnqf/ddKAz6dWf+k8PD5hAr9oCSHEQ== dependencies: type-fest "^2.12.2" @@ -6212,6 +6273,11 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -6629,20 +6695,20 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" - integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== tslib@^2.0.3: version "2.6.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== -tslib@^2.5.0, tslib@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.4.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== tsutils@^3.21.0: version "3.21.0" @@ -6673,10 +6739,10 @@ type-fest@^2.12.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-fest@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.2.0.tgz#e259430307710e77721ecf6f545840acad72195f" - integrity sha512-5zknd7Dss75pMSED270A1RQS3KloqRJA9XbXLe0eCxyw7xXFb3rd+9B0UQ/0E+LQT6lnrLviEolYORlRWamn4w== +type-fest@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.4.0.tgz#061cd10ff55664bb7174218cdf78c28c48f71c69" + integrity sha512-HT3RRs7sTfY22KuPQJkD/XjbTbxgP2Je5HPt6H6JEGvcjHd5Lqru75EbrP3tb4FYjNJ+DjLp+MNQTFQU0mhXNw== typed-array-buffer@^1.0.0: version "1.0.0" @@ -6747,6 +6813,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~5.25.1: + version "5.25.3" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" + integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== + undici@^5.23.0: version "5.23.0" resolved "https://registry.yarnpkg.com/undici/-/undici-5.23.0.tgz#e7bdb0ed42cebe7b7aca87ced53e6eaafb8f8ca0" @@ -6833,10 +6904,10 @@ util-deprecate@^1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== validator@^13.7.0: version "13.9.0" @@ -6848,12 +6919,12 @@ vite-plugin-css-injected-by-js@^3.3.0: resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.0.tgz#c19480a9e42a95c5bced976a9dde1446f9bd91ff" integrity sha512-xG+jyHNCmUqi/TXp6q88wTJGeAOrNLSyUUTp4qEQ9QZLGcHWQQsCsSSKa59rPMQr8sOzfzmWDd8enGqfH/dBew== -vite-plugin-dts@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.5.2.tgz#429612f727f1bf4eff1f22e29c04b52a75d398b8" - integrity sha512-iKc851+jdHEoN1ifbOEsoMs+/Zg26PE1EyO2Jc+4apOWRoaeK2zRJnaStgUuJaVaEcAjTqWzpNgCAMq7iO6DWA== +vite-plugin-dts@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.6.0.tgz#8d1052e93ae4efef1b0860e44411570a58c77517" + integrity sha512-doxhDRFJCZD2sGjIp4V800nm8Y19GvmwckjG5vYPuiqJ7OBjc9NlW1Vp9Gkyh2aXlUs1jTDRH/lxWfcsPLOQHg== dependencies: - "@microsoft/api-extractor" "^7.36.3" + "@microsoft/api-extractor" "^7.36.4" "@rollup/pluginutils" "^5.0.2" "@vue/language-core" "^1.8.8" debug "^4.3.4" @@ -6869,19 +6940,19 @@ vite-plugin-eslint@^1.8.1: "@types/eslint" "^8.4.5" rollup "^2.77.2" -vite-tsconfig-paths@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.0.tgz#bd2647d3eadafb65a10fc98a2ca565211f2eaf63" - integrity sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw== +vite-tsconfig-paths@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.1.tgz#e53b89096b91d31a6d1e26f75999ea8c336a89ed" + integrity sha512-GNUI6ZgPqT3oervkvzU+qtys83+75N/OuDaQl7HmOqFTb0pjZsuARrRipsyJhJ3enqV8beI1xhGbToR4o78nSQ== dependencies: debug "^4.1.1" globrex "^0.1.2" tsconfck "^2.1.0" -vite@^4.4.9: - version "4.4.9" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" - integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== +vite@^4.4.11: + version "4.4.11" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.11.tgz#babdb055b08c69cfc4c468072a2e6c9ca62102b0" + integrity sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A== dependencies: esbuild "^0.18.10" postcss "^8.4.27" @@ -7036,16 +7107,21 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@2.3.1, yaml@^2.2.2: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== +yaml@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" + integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" @@ -7090,10 +7166,10 @@ zod-validation-error@^1.5.0: resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-1.5.0.tgz#2b355007a1c3b7fb04fa476bfad4e7b3fd5491e3" integrity sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw== -zod@^3.22.2: - version "3.22.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.2.tgz#3add8c682b7077c05ac6f979fea6998b573e157b" - integrity sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg== +zod@^3.22.4: + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== zustand@^4.4.1: version "4.4.1" diff --git a/pyproject.toml b/pyproject.toml index bab87172c2..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"] @@ -35,10 +35,10 @@ dependencies = [ "accelerate~=0.23.0", "albumentations", "click", - "clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip", + "clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip", "compel~=2.0.2", "controlnet-aux>=0.0.6", - "timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26 + "timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26 "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 @@ -48,19 +48,20 @@ dependencies = [ "easing-functions", "einops", "facexlib", - "fastapi==0.88.0", - "fastapi-events==0.8.0", + "fastapi~=0.103.2", + "fastapi-events~=0.9.1", "huggingface-hub~=0.16.4", - "invisible-watermark~=0.2.0", # needed to install SDXL base and refiner using their repo_ids - "matplotlib", # needed for plotting of Penner easing functions - "mediapipe", # needed for "mediapipeface" controlnet model + "invisible-watermark~=0.2.0", # needed to install SDXL base and refiner using their repo_ids + "matplotlib", # needed for plotting of Penner easing functions + "mediapipe", # needed for "mediapipeface" controlnet model "numpy", "npyscreen", "omegaconf", "onnx", "onnxruntime", "opencv-python", - "pydantic==1.*", + "pydantic~=2.4.2", + "pydantic-settings~=2.0.3", "picklescan", "pillow", "prompt-toolkit", @@ -69,7 +70,7 @@ dependencies = [ 'pyperclip', "pyreadline3", "python-multipart", - "python-socketio", + "python-socketio~=5.10.0", "pytorch-lightning", "realesrgan", "requests~=2.28.2", @@ -95,33 +96,25 @@ dependencies = [ "mkdocs-git-revision-date-localized-plugin", "mkdocs-redirects==1.2.0", ] -"dev" = [ - "jurigged", - "pudb", -] +"dev" = ["jurigged", "pudb"] "test" = [ "black", "flake8", "Flake8-pyproject", "isort", + "mypy", "pre-commit", "pytest>6.0.0", "pytest-cov", "pytest-datadir", ] "xformers" = [ - "xformers~=0.0.19; sys_platform!='darwin'", - "triton; sys_platform=='linux'", -] -"onnx" = [ - "onnxruntime", -] -"onnx-cuda" = [ - "onnxruntime-gpu", -] -"onnx-directml" = [ - "onnxruntime-directml", + "xformers~=0.0.19; sys_platform!='darwin'", + "triton; sys_platform=='linux'", ] +"onnx" = ["onnxruntime"] +"onnx-cuda" = ["onnxruntime-gpu"] +"onnx-directml" = ["onnxruntime-directml"] [project.scripts] @@ -163,12 +156,15 @@ version = { attr = "invokeai.version.__version__" } [tool.setuptools.packages.find] "where" = ["."] "include" = [ - "invokeai.assets.fonts*","invokeai.version*", - "invokeai.generator*","invokeai.backend*", - "invokeai.frontend*", "invokeai.frontend.web.dist*", - "invokeai.frontend.web.static*", - "invokeai.configs*", - "invokeai.app*", + "invokeai.assets.fonts*", + "invokeai.version*", + "invokeai.generator*", + "invokeai.backend*", + "invokeai.frontend*", + "invokeai.frontend.web.dist*", + "invokeai.frontend.web.static*", + "invokeai.configs*", + "invokeai.app*", ] [tool.setuptools.package-data] @@ -182,7 +178,7 @@ version = { attr = "invokeai.version.__version__" } [tool.pytest.ini_options] addopts = "--cov-report term --cov-report html --cov-report xml --strict-markers -m \"not slow\"" markers = [ - "slow: Marks tests as slow. Disabled by default. To run all tests, use -m \"\". To run only slow tests, use -m \"slow\"." + "slow: Marks tests as slow. Disabled by default. To run all tests, use -m \"\". To run only slow tests, use -m \"slow\".", ] [tool.coverage.run] branch = true @@ -190,7 +186,7 @@ source = ["invokeai"] omit = ["*tests*", "*migrations*", ".venv/*", "*.env"] [tool.coverage.report] show_missing = true -fail_under = 85 # let's set something sensible on Day 1 ... +fail_under = 85 # let's set something sensible on Day 1 ... [tool.coverage.json] output = "coverage/coverage.json" pretty_print = true @@ -209,7 +205,7 @@ exclude = [ "__pycache__", "build", "dist", - "invokeai/frontend/web/node_modules/" + "invokeai/frontend/web/node_modules/", ] [tool.black] @@ -218,3 +214,53 @@ line-length = 120 [tool.isort] profile = "black" line_length = 120 + +[tool.mypy] +ignore_missing_imports = true # ignores missing types in third-party libraries + +[[tool.mypy.overrides]] +follow_imports = "skip" +module = [ + "invokeai.app.api.routers.models", + "invokeai.app.invocations.compel", + "invokeai.app.invocations.latent", + "invokeai.app.services.config.config_base", + "invokeai.app.services.config.config_default", + "invokeai.app.services.invocation_stats.invocation_stats_default", + "invokeai.app.services.model_manager.model_manager_base", + "invokeai.app.services.model_manager.model_manager_default", + "invokeai.app.util.controlnet_utils", + "invokeai.backend.image_util.txt2mask", + "invokeai.backend.image_util.safety_checker", + "invokeai.backend.image_util.patchmatch", + "invokeai.backend.image_util.invisible_watermark", + "invokeai.backend.install.model_install_backend", + "invokeai.backend.ip_adapter.ip_adapter", + "invokeai.backend.ip_adapter.resampler", + "invokeai.backend.ip_adapter.unet_patcher", + "invokeai.backend.model_management.convert_ckpt_to_diffusers", + "invokeai.backend.model_management.lora", + "invokeai.backend.model_management.model_cache", + "invokeai.backend.model_management.model_manager", + "invokeai.backend.model_management.model_merge", + "invokeai.backend.model_management.model_probe", + "invokeai.backend.model_management.model_search", + "invokeai.backend.model_management.models.*", # this is needed to ignore the module's `__init__.py` + "invokeai.backend.model_management.models.base", + "invokeai.backend.model_management.models.controlnet", + "invokeai.backend.model_management.models.ip_adapter", + "invokeai.backend.model_management.models.lora", + "invokeai.backend.model_management.models.sdxl", + "invokeai.backend.model_management.models.stable_diffusion", + "invokeai.backend.model_management.models.vae", + "invokeai.backend.model_management.seamless", + "invokeai.backend.model_management.util", + "invokeai.backend.stable_diffusion.diffusers_pipeline", + "invokeai.backend.stable_diffusion.diffusion.cross_attention_control", + "invokeai.backend.stable_diffusion.diffusion.shared_invokeai_diffusion", + "invokeai.backend.util.hotfixes", + "invokeai.backend.util.logging", + "invokeai.backend.util.mps_fixes", + "invokeai.backend.util.util", + "invokeai.frontend.install.model_install", +] diff --git a/tests/backend/model_management/test_libc_util.py b/tests/backend/model_management/test_libc_util.py index a517db4c90..e13a2fd3a2 100644 --- a/tests/backend/model_management/test_libc_util.py +++ b/tests/backend/model_management/test_libc_util.py @@ -11,7 +11,10 @@ def test_libc_util_mallinfo2(): # TODO: Set the expected result preemptively based on the system properties. pytest.xfail("libc shared library is not available on this system.") - info = libc.mallinfo2() + try: + info = libc.mallinfo2() + except AttributeError: + pytest.xfail("`mallinfo2` is not available on this system, likely due to glibc < 2.33.") assert info.arena > 0 diff --git a/tests/nodes/test_node_graph.py b/tests/nodes/test_node_graph.py index 822ffc1588..3c965895f9 100644 --- a/tests/nodes/test_node_graph.py +++ b/tests/nodes/test_node_graph.py @@ -1,4 +1,5 @@ import pytest +from pydantic import TypeAdapter from invokeai.app.invocations.baseinvocation import ( BaseInvocation, @@ -593,20 +594,21 @@ def test_graph_can_serialize(): g.add_edge(e) # Not throwing on this line is sufficient - _ = g.json() + _ = g.model_dump_json() def test_graph_can_deserialize(): g = Graph() n1 = TextToImageTestInvocation(id="1", prompt="Banana sushi") - n2 = ESRGANInvocation(id="2") + n2 = ImageToImageTestInvocation(id="2") g.add_node(n1) g.add_node(n2) e = create_edge(n1.id, "image", n2.id, "image") g.add_edge(e) - json = g.json() - g2 = Graph.parse_raw(json) + json = g.model_dump_json() + adapter_graph = TypeAdapter(Graph) + g2 = adapter_graph.validate_json(json) assert g2 is not None assert g2.nodes["1"] is not None @@ -619,7 +621,7 @@ def test_graph_can_deserialize(): def test_invocation_decorator(): - invocation_type = "test_invocation" + invocation_type = "test_invocation_decorator" title = "Test Invocation" tags = ["first", "second", "third"] category = "category" @@ -630,7 +632,7 @@ def test_invocation_decorator(): def invoke(self): pass - schema = TestInvocation.schema() + schema = TestInvocation.model_json_schema() assert schema.get("title") == title assert schema.get("tags") == tags @@ -640,18 +642,17 @@ def test_invocation_decorator(): def test_invocation_version_must_be_semver(): - invocation_type = "test_invocation" valid_version = "1.0.0" invalid_version = "not_semver" - @invocation(invocation_type, version=valid_version) + @invocation("test_invocation_version_valid", version=valid_version) class ValidVersionInvocation(BaseInvocation): def invoke(self): pass with pytest.raises(InvalidVersionError): - @invocation(invocation_type, version=invalid_version) + @invocation("test_invocation_version_invalid", version=invalid_version) class InvalidVersionInvocation(BaseInvocation): def invoke(self): pass @@ -694,4 +695,4 @@ def test_ints_do_not_accept_floats(): 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 - _ = Graph.schema_json(indent=2) + _ = Graph.model_json_schema() diff --git a/tests/nodes/test_session_queue.py b/tests/nodes/test_session_queue.py index 6dd7c4845a..731316068c 100644 --- a/tests/nodes/test_session_queue.py +++ b/tests/nodes/test_session_queue.py @@ -1,5 +1,5 @@ import pytest -from pydantic import ValidationError, parse_raw_as +from pydantic import TypeAdapter, ValidationError from invokeai.app.services.session_queue.session_queue_common import ( Batch, @@ -150,8 +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) # graph should be serialized - ges = parse_raw_as(GraphExecutionState, values[0].session) + ges = session_adapter.validate_json(values[0].session) # graph values should be populated assert ges.graph.get_node("1").prompt == "Banana sushi" @@ -160,15 +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] == [parse_raw_as(GraphExecutionState, v.session).id for v in values] + assert [v.session_id for v in values] == [session_adapter.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]) # should have 3 node field values assert type(values[0].field_values) is str - assert len(parse_raw_as(list[NodeFieldValue], values[0].field_values)) == 3 + assert len(nfv_list_adapter.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) diff --git a/tests/nodes/test_sqlite.py b/tests/nodes/test_sqlite.py index 6e4da8b36e..818f9d048f 100644 --- a/tests/nodes/test_sqlite.py +++ b/tests/nodes/test_sqlite.py @@ -15,7 +15,8 @@ class TestModel(BaseModel): @pytest.fixture def db() -> SqliteItemStorage[TestModel]: sqlite_db = SqliteDatabase(InvokeAIAppConfig(use_memory_db=True), InvokeAILogger.get_logger()) - return SqliteItemStorage[TestModel](db=sqlite_db, table_name="test", id_field="id") + sqlite_item_storage = SqliteItemStorage[TestModel](db=sqlite_db, table_name="test", id_field="id") + return sqlite_item_storage def test_sqlite_service_can_create_and_get(db: SqliteItemStorage[TestModel]):