diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 13b90f8f80..5e1bcd2057 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,7 +2,7 @@ /.github/workflows/ @lstein @blessedcoolant # documentation -/docs/ @lstein @blessedcoolant @hipsterusername +/docs/ @lstein @blessedcoolant @hipsterusername @Millu /mkdocs.yml @lstein @blessedcoolant # nodes @@ -22,7 +22,7 @@ /invokeai/backend @blessedcoolant @psychedelicious @lstein @maryhipp # generation, model management, postprocessing -/invokeai/backend @damian0815 @lstein @blessedcoolant @gregghelt2 @StAlKeR7779 @brandonrising +/invokeai/backend @damian0815 @lstein @blessedcoolant @gregghelt2 @StAlKeR7779 @brandonrising @ryanjdick # front ends /invokeai/frontend/CLI @lstein diff --git a/README.md b/README.md index f10c372545..c40b9ef418 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Web Interface, interactive Command Line Interface, and also serves as the foundation for multiple commercial products. **Quick links**: [[How to - Install](https://invoke-ai.github.io/InvokeAI/#installation)] [Discord Server] [Documentation and Tutorials] [ + --> + diff --git a/docs/contributing/LOCAL_DEVELOPMENT.md b/docs/contributing/LOCAL_DEVELOPMENT.md index b2a5cd581d..f93ec56e96 100644 --- a/docs/contributing/LOCAL_DEVELOPMENT.md +++ b/docs/contributing/LOCAL_DEVELOPMENT.md @@ -35,18 +35,17 @@ access. ## Backend -The backend is contained within the `./invokeai/backend` folder structure. To -get started however please install the development dependencies. +The backend is contained within the `./invokeai/backend` and `./invokeai/app` directories. +To get started please install the development dependencies. From the root of the repository run the following command. Note the use of `"`. ```zsh -pip install ".[test]" +pip install ".[dev,test]" ``` -This in an optional group of packages which is defined within the -`pyproject.toml` and will be required for testing the changes you make the the -code. +These are optional groups of packages which are defined within the `pyproject.toml` +and will be required for testing the changes you make to the code. ### Running Tests @@ -76,6 +75,20 @@ pytest --cov; open ./coverage/html/index.html ![html-detail](../assets/contributing/html-detail.png) +### Reloading Changes + +Experimenting with changes to the Python source code is a drag if you have to re-start the server — +and re-load those multi-gigabyte models — +after every change. + +For a faster development workflow, add the `--dev_reload` flag when starting the server. +The server will watch for changes to all the Python files in the `invokeai` directory and apply those changes to the +running server on the fly. + +This will allow you to avoid restarting the server (and reloading models) in most cases, but there are some caveats; see +the [jurigged documentation](https://github.com/breuleux/jurigged#caveats) for details. + + ## Front End diff --git a/docs/features/CONFIGURATION.md b/docs/features/CONFIGURATION.md index 09e6143e95..6920d3d97f 100644 --- a/docs/features/CONFIGURATION.md +++ b/docs/features/CONFIGURATION.md @@ -175,22 +175,27 @@ These configuration settings allow you to enable and disable various InvokeAI fe | `internet_available` | `true` | When a resource is not available locally, try to fetch it via the internet | | `log_tokenization` | `false` | Before each text2image generation, print a color-coded representation of the prompt to the console; this can help understand why a prompt is not working as expected | | `patchmatch` | `true` | Activate the "patchmatch" algorithm for improved inpainting | -| `restore` | `true` | Activate the facial restoration features (DEPRECATED; restoration features will be removed in 3.0.0) | -### Memory/Performance +### Generation These options tune InvokeAI's memory and performance characteristics. -| Setting | Default Value | Description | -|----------|----------------|--------------| -| `always_use_cpu` | `false` | Use the CPU to generate images, even if a GPU is available | -| `free_gpu_mem` | `false` | Aggressively free up GPU memory after each operation; this will allow you to run in low-VRAM environments with some performance penalties | -| `max_cache_size` | `6` | Amount of CPU RAM (in GB) to reserve for caching models in memory; more cache allows you to keep models in memory and switch among them quickly | -| `max_vram_cache_size` | `2.75` | Amount of GPU VRAM (in GB) to reserve for caching models in VRAM; more cache speeds up generation but reduces the size of the images that can be generated. This can be set to zero to maximize the amount of memory available for generation. | -| `precision` | `auto` | Floating point precision. One of `auto`, `float16` or `float32`. `float16` will consume half the memory of `float32` but produce slightly lower-quality images. The `auto` setting will guess the proper precision based on your video card and operating system | -| `sequential_guidance` | `false` | Calculate guidance in serial rather than in parallel, lowering memory requirements at the cost of some performance loss | -| `xformers_enabled` | `true` | If the x-formers memory-efficient attention module is installed, activate it for better memory usage and generation speed| -| `tiled_decode` | `false` | If true, then during the VAE decoding phase the image will be decoded a section at a time, reducing memory consumption at the cost of a performance hit | +| Setting | Default Value | Description | +|-----------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `sequential_guidance` | `false` | Calculate guidance in serial rather than in parallel, lowering memory requirements at the cost of some performance loss | +| `attention_type` | `auto` | Select the type of attention to use. One of `auto`,`normal`,`xformers`,`sliced`, or `torch-sdp` | +| `attention_slice_size` | `auto` | When "sliced" attention is selected, set the slice size. One of `auto`, `balanced`, `max` or the integers 1-8| +| `force_tiled_decode` | `false` | Force the VAE step to decode in tiles, reducing memory consumption at the cost of performance | + +### Device + +These options configure the generation execution device. + +| Setting | Default Value | Description | +|-----------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `device` | `auto` | Preferred execution device. One of `auto`, `cpu`, `cuda`, `cuda:1`, `mps`. `auto` will choose the device depending on the hardware platform and the installed torch capabilities. | +| `precision` | `auto` | Floating point precision. One of `auto`, `float16` or `float32`. `float16` will consume half the memory of `float32` but produce slightly lower-quality images. The `auto` setting will guess the proper precision based on your video card and operating system | + ### Paths diff --git a/docs/features/NODES.md b/docs/features/NODES.md deleted file mode 100644 index eef71eb974..0000000000 --- a/docs/features/NODES.md +++ /dev/null @@ -1,208 +0,0 @@ -# Nodes Editor (Experimental) - -🚨 -*The node editor is experimental. We've made it accessible because we use it to develop the application, but we have not addressed the many known rough edges. It's very easy to shoot yourself in the foot, and we cannot offer support for it until it sees full release (ETA v3.1). Everything is subject to change without warning.* -🚨 - -The nodes editor is a blank canvas allowing for the use of individual functions and image transformations to control the image generation workflow. The node processing flow is usually done from left (inputs) to right (outputs), though linearity can become abstracted the more complex the node graph becomes. Nodes inputs and outputs are connected by dragging connectors from node to node. - -To better understand how nodes are used, think of how an electric power bar works. It takes in one input (electricity from a wall outlet) and passes it to multiple devices through multiple outputs. Similarly, a node could have multiple inputs and outputs functioning at the same (or different) time, but all node outputs pass information onward like a power bar passes electricity. Not all outputs are compatible with all inputs, however - Each node has different constraints on how it is expecting to input/output information. In general, node outputs are colour-coded to match compatible inputs of other nodes. - -## Anatomy of a Node - -Individual nodes are made up of the following: - -- Inputs: Edge points on the left side of the node window where you connect outputs from other nodes. -- Outputs: Edge points on the right side of the node window where you connect to inputs on other nodes. -- Options: Various options which are either manually configured, or overridden by connecting an output from another node to the input. - -## Diffusion Overview - -Taking the time to understand the diffusion process will help you to understand how to set up your nodes in the nodes editor. - -There are two main spaces Stable Diffusion works in: image space and latent space. - -Image space represents images in pixel form that you look at. Latent space represents compressed inputs. It’s in latent space that Stable Diffusion processes images. A VAE (Variational Auto Encoder) is responsible for compressing and encoding inputs into latent space, as well as decoding outputs back into image space. - -When you generate an image using text-to-image, multiple steps occur in latent space: -1. Random noise is generated at the chosen height and width. The noise’s characteristics are dictated by the chosen (or not chosen) seed. This noise tensor is passed into latent space. We’ll call this noise A. -1. Using a model’s U-Net, a noise predictor examines noise A, and the words tokenized by CLIP from your prompt (conditioning). It generates its own noise tensor to predict what the final image might look like in latent space. We’ll call this noise B. -1. Noise B is subtracted from noise A in an attempt to create a final latent image indicative of the inputs. This step is repeated for the number of sampler steps chosen. -1. The VAE decodes the final latent image from latent space into image space. - -image-to-image is a similar process, with only step 1 being different: -1. The input image is decoded from image space into latent space by the VAE. Noise is then added to the input latent image. Denoising Strength dictates how much noise is added, 0 being none, and 1 being all-encompassing. We’ll call this noise A. The process is then the same as steps 2-4 in the text-to-image explanation above. - -Furthermore, a model provides the CLIP prompt tokenizer, the VAE, and a U-Net (where noise prediction occurs given a prompt and initial noise tensor). - -A noise scheduler (eg. DPM++ 2M Karras) schedules the subtraction of noise from the latent image across the sampler steps chosen (step 3 above). Less noise is usually subtracted at higher sampler steps. - -## Node Types (Base Nodes) - -| Node | Function | -| ---------------------------------- | --------------------------------------------------------------------------------------| -| Add | Adds two numbers | -| CannyImageProcessor | Canny edge detection for ControlNet | -| ClipSkip | Skip layers in clip text_encoder model | -| Collect | Collects values into a collection | -| Prompt (Compel) | Parse prompt using compel package to conditioning | -| ContentShuffleImageProcessor | Applies content shuffle processing to image | -| ControlNet | Collects ControlNet info to pass to other nodes | -| CvInpaint | Simple inpaint using opencv | -| Divide | Divides two numbers | -| DynamicPrompt | Parses a prompt using adieyal/dynamic prompt's random or combinatorial generator | -| FloatLinearRange | Creates a range | -| HedImageProcessor | Applies HED edge detection to image | -| ImageBlur | Blurs an image | -| ImageChannel | Gets a channel from an image | -| ImageCollection | Load a collection of images and provide it as output | -| ImageConvert | Converts an image to a different mode | -| ImageCrop | Crops an image to a specified box. The box can be outside of the image. | -| ImageInverseLerp | Inverse linear interpolation of all pixels of an image | -| ImageLerp | Linear interpolation of all pixels of an image | -| ImageMultiply | Multiplies two images together using `PIL.ImageChops.Multiply()` | -| ImageNSFWBlurInvocation | Detects and blurs images that may contain sexually explicit content | -| ImagePaste | Pastes an image into another image | -| ImageProcessor | Base class for invocations that reprocess images for ControlNet | -| ImageResize | Resizes an image to specific dimensions | -| ImageScale | Scales an image by a factor | -| ImageToLatents | Scales latents by a given factor | -| ImageWatermarkInvocation | Adds an invisible watermark to images | -| InfillColor | Infills transparent areas of an image with a solid color | -| InfillPatchMatch | Infills transparent areas of an image using the PatchMatch algorithm | -| InfillTile | Infills transparent areas of an image with tiles of the image | -| Inpaint | Generates an image using inpaint | -| Iterate | Iterates over a list of items | -| LatentsToImage | Generates an image from latents | -| LatentsToLatents | Generates latents using latents as base image | -| LeresImageProcessor | Applies leres processing to image | -| LineartAnimeImageProcessor | Applies line art anime processing to image | -| LineartImageProcessor | Applies line art processing to image | -| LoadImage | Load an image and provide it as output | -| Lora Loader | Apply selected lora to unet and text_encoder | -| Model Loader | Loads a main model, outputting its submodels | -| MaskFromAlpha | Extracts the alpha channel of an image as a mask | -| MediapipeFaceProcessor | Applies mediapipe face processing to image | -| MidasDepthImageProcessor | Applies Midas depth processing to image | -| MlsdImageProcessor | Applied MLSD processing to image | -| Multiply | Multiplies two numbers | -| Noise | Generates latent noise | -| NormalbaeImageProcessor | Applies NormalBAE processing to image | -| OpenposeImageProcessor | Applies Openpose processing to image | -| ParamFloat | A float parameter | -| ParamInt | An integer parameter | -| PidiImageProcessor | Applies PIDI processing to an image | -| Progress Image | Displays the progress image in the Node Editor | -| RandomInit | Outputs a single random integer | -| RandomRange | Creates a collection of random numbers | -| Range | Creates a range of numbers from start to stop with step | -| RangeOfSize | Creates a range from start to start + size with step | -| ResizeLatents | Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8. | -| RestoreFace | Restores faces in the image | -| ScaleLatents | Scales latents by a given factor | -| SegmentAnythingProcessor | Applies segment anything processing to image | -| ShowImage | Displays a provided image, and passes it forward in the pipeline | -| StepParamEasing | Experimental per-step parameter for easing for denoising steps | -| Subtract | Subtracts two numbers | -| TextToLatents | Generates latents from conditionings | -| TileResampleProcessor | Bass class for invocations that preprocess images for ControlNet | -| Upscale | Upscales an image | -| VAE Loader | Loads a VAE model, outputting a VaeLoaderOutput | -| ZoeDepthImageProcessor | Applies Zoe depth processing to image | - -## Node Grouping Concepts - -There are several node grouping concepts that can be examined with a narrow focus. These (and other) groupings can be pieced together to make up functional graph setups, and are important to understanding how groups of nodes work together as part of a whole. Note that the screenshots below aren't examples of complete functioning node graphs (see Examples). - -### Noise - -As described, an initial noise tensor is necessary for the latent diffusion process. As a result, all non-image *ToLatents nodes require a noise node input. - -![groupsnoise](../assets/nodes/groupsnoise.png) - -### Conditioning - -As described, conditioning is necessary for the latent diffusion process, whether empty or not. As a result, all non-image *ToLatents nodes require positive and negative conditioning inputs. Conditioning is reliant on a CLIP tokenizer provided by the Model Loader node. - -![groupsconditioning](../assets/nodes/groupsconditioning.png) - -### Image Space & VAE - -The ImageToLatents node doesn't require a noise node input, but requires a VAE input to convert the image from image space into latent space. In reverse, the LatentsToImage node requires a VAE input to convert from latent space back into image space. - -![groupsimgvae](../assets/nodes/groupsimgvae.png) - -### Defined & Random Seeds - -It is common to want to use both the same seed (for continuity) and random seeds (for variance). To define a seed, simply enter it into the 'Seed' field on a noise node. Conversely, the RandomInt node generates a random integer between 'Low' and 'High', and can be used as input to the 'Seed' edge point on a noise node to randomize your seed. - -![groupsrandseed](../assets/nodes/groupsrandseed.png) - -### Control - -Control means to guide the diffusion process to adhere to a defined input or structure. Control can be provided as input to non-image *ToLatents nodes from ControlNet nodes. ControlNet nodes usually require an image processor which converts an input image for use with ControlNet. - -![groupscontrol](../assets/nodes/groupscontrol.png) - -### LoRA - -The Lora Loader node lets you load a LoRA (say that ten times fast) and pass it as output to both the Prompt (Compel) and non-image *ToLatents nodes. A model's CLIP tokenizer is passed through the LoRA into Prompt (Compel), where it affects conditioning. A model's U-Net is also passed through the LoRA into a non-image *ToLatents node, where it affects noise prediction. - -![groupslora](../assets/nodes/groupslora.png) - -### Scaling - -Use the ImageScale, ScaleLatents, and Upscale nodes to upscale images and/or latent images. The chosen method differs across contexts. However, be aware that latents are already noisy and compressed at their original resolution; scaling an image could produce more detailed results. - -![groupsallscale](../assets/nodes/groupsallscale.png) - -### Iteration + Multiple Images as Input - -Iteration is a common concept in any processing, and means to repeat a process with given input. In nodes, you're able to use the Iterate node to iterate through collections usually gathered by the Collect node. The Iterate node has many potential uses, from processing a collection of images one after another, to varying seeds across multiple image generations and more. This screenshot demonstrates how to collect several images and pass them out one at a time. - -![groupsiterate](../assets/nodes/groupsiterate.png) - -### Multiple Image Generation + Random Seeds - -Multiple image generation in the node editor is done using the RandomRange node. In this case, the 'Size' field represents the number of images to generate. As RandomRange produces a collection of integers, we need to add the Iterate node to iterate through the collection. - -To control seeds across generations takes some care. The first row in the screenshot will generate multiple images with different seeds, but using the same RandomRange parameters across invocations will result in the same group of random seeds being used across the images, producing repeatable results. In the second row, adding the RandomInt node as input to RandomRange's 'Seed' edge point will ensure that seeds are varied across all images across invocations, producing varied results. - -![groupsmultigenseeding](../assets/nodes/groupsmultigenseeding.png) - -## Examples - -With our knowledge of node grouping and the diffusion process, let’s break down some basic graphs in the nodes editor. Note that a node's options can be overridden by inputs from other nodes. These examples aren't strict rules to follow and only demonstrate some basic configurations. - -### Basic text-to-image Node Graph - -![nodest2i](../assets/nodes/nodest2i.png) - -- Model Loader: A necessity to generating images (as we’ve read above). We choose our model from the dropdown. It outputs a U-Net, CLIP tokenizer, and VAE. -- Prompt (Compel): Another necessity. Two prompt nodes are created. One will output positive conditioning (what you want, ‘dog’), one will output negative (what you don’t want, ‘cat’). They both input the CLIP tokenizer that the Model Loader node outputs. -- Noise: Consider this noise A from step one of the text-to-image explanation above. Choose a seed number, width, and height. -- TextToLatents: This node takes many inputs for converting and processing text & noise from image space into latent space, hence the name TextTo**Latents**. In this setup, it inputs positive and negative conditioning from the prompt nodes for processing (step 2 above). It inputs noise from the noise node for processing (steps 2 & 3 above). Lastly, it inputs a U-Net from the Model Loader node for processing (step 2 above). It outputs latents for use in the next LatentsToImage node. Choose number of sampler steps, CFG scale, and scheduler. -- LatentsToImage: This node takes in processed latents from the TextToLatents node, and the model’s VAE from the Model Loader node which is responsible for decoding latents back into the image space, hence the name LatentsTo**Image**. This node is the last stop, and once the image is decoded, it is saved to the gallery. - -### Basic image-to-image Node Graph - -![nodesi2i](../assets/nodes/nodesi2i.png) - -- Model Loader: Choose a model from the dropdown. -- Prompt (Compel): Two prompt nodes. One positive (dog), one negative (dog). Same CLIP inputs from the Model Loader node as before. -- ImageToLatents: Upload a source image directly in the node window, via drag'n'drop from the gallery, or passed in as input. The ImageToLatents node inputs the VAE from the Model Loader node to decode the chosen image from image space into latent space, hence the name ImageTo**Latents**. It outputs latents for use in the next LatentsToLatents node. It also outputs the source image's width and height for use in the next Noise node if the final image is to be the same dimensions as the source image. -- Noise: A noise tensor is created with the width and height of the source image, and connected to the next LatentsToLatents node. Notice the width and height fields are overridden by the input from the ImageToLatents width and height outputs. -- LatentsToLatents: The inputs and options are nearly identical to TextToLatents, except that LatentsToLatents also takes latents as an input. Considering our source image is already converted to latents in the last ImageToLatents node, and text + noise are no longer the only inputs to process, we use the LatentsToLatents node. -- LatentsToImage: Like previously, the LatentsToImage node will use the VAE from the Model Loader as input to decode the latents from LatentsToLatents into image space, and save it to the gallery. - -### Basic ControlNet Node Graph - -![nodescontrol](../assets/nodes/nodescontrol.png) - -- Model Loader -- Prompt (Compel) -- Noise: Width and height of the CannyImageProcessor ControlNet image is passed in to set the dimensions of the noise passed to TextToLatents. -- CannyImageProcessor: The CannyImageProcessor node is used to process the source image being used as a ControlNet. Each ControlNet processor node applies control in different ways, and has some different options to configure. Width and height are passed to noise, as mentioned. The processed ControlNet image is output to the ControlNet node. -- ControlNet: Select the type of control model. In this case, canny is chosen as the CannyImageProcessor was used to generate the ControlNet image. Configure the control node options, and pass the control output to TextToLatents. -- TextToLatents: Similar to the basic text-to-image example, except ControlNet is passed to the control input edge point. -- LatentsToImage diff --git a/docs/features/PROMPTS.md b/docs/features/PROMPTS.md index 1fd4550493..66af903072 100644 --- a/docs/features/PROMPTS.md +++ b/docs/features/PROMPTS.md @@ -4,80 +4,6 @@ title: Prompting-Features # :octicons-command-palette-24: Prompting-Features -## **Negative and Unconditioned Prompts** - -Any words between a pair of square brackets will instruct Stable -Diffusion to attempt to ban the concept from the generated image. The -same effect is achieved by placing words in the "Negative Prompts" -textbox in the Web UI. - -```text -this is a test prompt [not really] to make you understand [cool] how this works. -``` - -In the above statement, the words 'not really cool` will be ignored by Stable -Diffusion. - -Here's a prompt that depicts what it does. - -original prompt: - -`#!bash "A fantastical translucent pony made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve"` - -`#!bash parameters: steps=20, dimensions=512x768, CFG=7.5, Scheduler=k_euler_a, seed=1654590180` - -
- -![step1](../assets/negative_prompt_walkthru/step1.png) - -
- -That image has a woman, so if we want the horse without a rider, we can -influence the image not to have a woman by putting [woman] in the prompt, like -this: - -`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman]"` -(same parameters as above) - -
- -![step2](../assets/negative_prompt_walkthru/step2.png) - -
- -That's nice - but say we also don't want the image to be quite so blue. We can -add "blue" to the list of negative prompts, so it's now [woman blue]: - -`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman blue]"` -(same parameters as above) - -
- -![step3](../assets/negative_prompt_walkthru/step3.png) - -
- -Getting close - but there's no sense in having a saddle when our horse doesn't -have a rider, so we'll add one more negative prompt: [woman blue saddle]. - -`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman blue saddle]"` -(same parameters as above) - -
- -![step4](../assets/negative_prompt_walkthru/step4.png) - -
- -!!! notes "Notes about this feature:" - - * The only requirement for words to be ignored is that they are in between a pair of square brackets. - * You can provide multiple words within the same bracket. - * You can provide multiple brackets with multiple words in different places of your prompt. That works just fine. - * To improve typical anatomy problems, you can add negative prompts like `[bad anatomy, extra legs, extra arms, extra fingers, poorly drawn hands, poorly drawn feet, disfigured, out of frame, tiling, bad art, deformed, mutated]`. - ---- - ## **Prompt Syntax Features** The InvokeAI prompting language has the following features: @@ -102,9 +28,6 @@ The following syntax is recognised: `a tall thin man (picking (apricots)1.3)1.1`. (`+` is equivalent to 1.1, `++` is pow(1.1,2), `+++` is pow(1.1,3), etc; `-` means 0.9, `--` means pow(0.9,2), etc.) -- attention also applies to `[unconditioning]` so - `a tall thin man picking apricots [(ladder)0.01]` will _very gently_ nudge SD - away from trying to draw the man on a ladder You can use this to increase or decrease the amount of something. Starting from this prompt of `a man picking apricots from a tree`, let's see what happens if @@ -150,7 +73,7 @@ Or, alternatively, with more man: | ---------------------------------------------- | ---------------------------------------------- | ---------------------------------------------- | ---------------------------------------------- | | ![](../assets/prompt_syntax/mountain-man1.png) | ![](../assets/prompt_syntax/mountain-man2.png) | ![](../assets/prompt_syntax/mountain-man3.png) | ![](../assets/prompt_syntax/mountain-man4.png) | -### Blending between prompts +### Prompt Blending - `("a tall thin man picking apricots", "a tall thin man picking pears").blend(1,1)` - The existing prompt blending using `:` will continue to be supported - @@ -168,6 +91,24 @@ Or, alternatively, with more man: See the section below on "Prompt Blending" for more information about how this works. +### Prompt Conjunction +Join multiple clauses together to create a conjoined prompt. Each clause will be passed to CLIP separately. + +For example, the prompt: + +```bash +"A mystical valley surround by towering granite cliffs, watercolor, warm" +``` + +Can be used with .and(): +```bash +("A mystical valley", "surround by towering granite cliffs", "watercolor", "warm").and() +``` + +Each will give you different results - try them out and see what you prefer! + + + ### Cross-Attention Control ('prompt2prompt') Sometimes an image you generate is almost right, and you just want to change one @@ -190,7 +131,7 @@ For example, consider the prompt `a cat.swap(dog) playing with a ball in the for - For multiple word swaps, use parentheses: `a (fluffy cat).swap(barking dog) playing with a ball in the forest`. - To swap a comma, use quotes: `a ("fluffy, grey cat").swap("big, barking dog") playing with a ball in the forest`. -- Supports options `t_start` and `t_end` (each 0-1) loosely corresponding to bloc97's `prompt_edit_tokens_start/_end` but with the math swapped to make it easier to +- Supports options `t_start` and `t_end` (each 0-1) loosely corresponding to (bloc97's)[(https://github.com/bloc97/CrossAttentionControl)] `prompt_edit_tokens_start/_end` but with the math swapped to make it easier to intuitively understand. `t_start` and `t_end` are used to control on which steps cross-attention control should run. With the default values `t_start=0` and `t_end=1`, cross-attention control is active on every step of image generation. Other values can be used to turn cross-attention control off for part of the image generation process. - For example, if doing a diffusion with 10 steps for the prompt is `a cat.swap(dog, t_start=0.3, t_end=1.0) playing with a ball in the forest`, the first 3 steps will be run as `a cat playing with a ball in the forest`, while the last 7 steps will run as `a dog playing with a ball in the forest`, but the pixels that represent `dog` will be locked to the pixels that would have represented `cat` if the `cat` prompt had been used instead. - Conversely, for `a cat.swap(dog, t_start=0, t_end=0.7) playing with a ball in the forest`, the first 7 steps will run as `a dog playing with a ball in the forest` with the pixels that represent `dog` locked to the same pixels that would have represented `cat` if the `cat` prompt was being used instead. The final 3 steps will just run `a cat playing with a ball in the forest`. @@ -201,7 +142,7 @@ Prompt2prompt `.swap()` is not compatible with xformers, which will be temporari The `prompt2prompt` code is based off [bloc97's colab](https://github.com/bloc97/CrossAttentionControl). -### Escaping parantheses () and speech marks "" +### Escaping parentheses () and speech marks "" If the model you are using has parentheses () or speech marks "" as part of its syntax, you will need to "escape" these using a backslash, so that`(my_keyword)` @@ -212,23 +153,16 @@ the parentheses as part of the prompt syntax and it will get confused. ## **Prompt Blending** -You may blend together different sections of the prompt to explore the AI's +You may blend together prompts to explore the AI's latent semantic space and generate interesting (and often surprising!) variations. The syntax is: ```bash -blue sphere:0.25 red cube:0.75 hybrid +("prompt #1", "prompt #2").blend(0.25, 0.75) ``` -This will tell the sampler to blend 25% of the concept of a blue sphere with 75% -of the concept of a red cube. The blend weights can use any combination of -integers and floating point numbers, and they do not need to add up to 1. -Everything to the left of the `:XX` up to the previous `:XX` is used for -merging, so the overall effect is: - -```bash -0.25 * "blue sphere" + 0.75 * "white duck" + hybrid -``` +This will tell the sampler to blend 25% of the concept of prompt #1 with 75% +of the concept of prompt #2. It is recommended to keep the sum of the weights to around 1.0, but interesting things might happen if you go outside of this range. Because you are exploring the "mind" of the AI, the AI's way of mixing two concepts may not match yours, leading to surprising effects. To illustrate, here @@ -236,13 +170,14 @@ are three images generated using various combinations of blend weights. As usual, unless you fix the seed, the prompts will give you different results each time you run them. -
+Let's examine how this affects image generation results: -### "blue sphere, red cube, hybrid" -
+```bash +"blue sphere, red cube, hybrid" +``` -This example doesn't use melding at all and represents the default way of mixing +This example doesn't use blending at all and represents the default way of mixing concepts.
@@ -251,55 +186,47 @@ concepts.
-It's interesting to see how the AI expressed the concept of "cube" as the four -quadrants of the enclosing frame. If you look closely, there is depth there, so -the enclosing frame is actually a cube. +It's interesting to see how the AI expressed the concept of "cube" within the sphere. If you look closely, there is depth there, so the enclosing frame is actually a cube.
-### "blue sphere:0.25 red cube:0.75 hybrid" +```bash +("blue sphere", "red cube").blend(0.25, 0.75) +``` ![blue-sphere-25-red-cube-75](../assets/prompt-blending/blue-sphere-0.25-red-cube-0.75-hybrid.png)
-Now that's interesting. We get neither a blue sphere nor a red cube, but a red -sphere embedded in a brick wall, which represents a melding of concepts within -the AI's "latent space" of semantic representations. Where is Ludwig -Wittgenstein when you need him? +Now that's interesting. We get an image with a resemblance of a red cube, with a hint of blue shadows which represents a melding of concepts within the AI's "latent space" of semantic representations.
-### "blue sphere:0.75 red cube:0.25 hybrid" +```bash +("blue sphere", "red cube").blend(0.75, 0.25) +``` ![blue-sphere-75-red-cube-25](../assets/prompt-blending/blue-sphere-0.75-red-cube-0.25-hybrid.png)
-Definitely more blue-spherey. The cube is gone entirely, but it's really cool -abstract art. +Definitely more blue-spherey.
-### "blue sphere:0.5 red cube:0.5 hybrid" +```bash +("blue sphere", "red cube").blend(0.5, 0.5) +``` +
+
![blue-sphere-5-red-cube-5-hybrid](../assets/prompt-blending/blue-sphere-0.5-red-cube-0.5-hybrid.png) -
-Whoa...! I see blue and red, but no spheres or cubes. Is the word "hybrid" -summoning up the concept of some sort of scifi creature? Let's find out. -
+Whoa...! I see blue and red, and if I squint, spheres and cubes. -### "blue sphere:0.5 red cube:0.5" -![blue-sphere-5-red-cube-5](../assets/prompt-blending/blue-sphere-0.5-red-cube-0.5.png) - -
- -Indeed, removing the word "hybrid" produces an image that is more like what we'd -expect. ## Dynamic Prompts diff --git a/docs/features/index.md b/docs/features/index.md index e55917af5b..490da5e31f 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -30,10 +30,6 @@ image output. ### * [Image-to-Image Guide](IMG2IMG.md) Use a seed image to build new creations in the CLI. -### * [Generating Variations](VARIATIONS.md) -Have an image you like and want to generate many more like it? Variations -are the ticket. - ## Model Management ### * [Model Installation](../installation/050_INSTALLING_MODELS.md) diff --git a/docs/help/diffusion.md b/docs/help/diffusion.md new file mode 100644 index 0000000000..0dbb09f304 --- /dev/null +++ b/docs/help/diffusion.md @@ -0,0 +1,27 @@ +Taking the time to understand the diffusion process will help you to understand how to more effectively use InvokeAI. + +There are two main ways Stable Diffusion works - with images, and latents. + +Image space represents images in pixel form that you look at. Latent space represents compressed inputs. It’s in latent space that Stable Diffusion processes images. A VAE (Variational Auto Encoder) is responsible for compressing and encoding inputs into latent space, as well as decoding outputs back into image space. + +To fully understand the diffusion process, we need to understand a few more terms: UNet, CLIP, and conditioning. + +A U-Net is a model trained on a large number of latent images with with known amounts of random noise added. This means that the U-Net can be given a slightly noisy image and it will predict the pattern of noise needed to subtract from the image in order to recover the original. + +CLIP is a model that tokenizes and encodes text into conditioning. This conditioning guides the model during the denoising steps to produce a new image. + +The U-Net and CLIP work together during the image generation process at each denoising step, with the U-Net removing noise in such a way that the result is similar to images in the U-Net’s training set, while CLIP guides the U-Net towards creating images that are most similar to the prompt. + + +When you generate an image using text-to-image, multiple steps occur in latent space: +1. Random noise is generated at the chosen height and width. The noise’s characteristics are dictated by seed. This noise tensor is passed into latent space. We’ll call this noise A. +2. Using a model’s U-Net, a noise predictor examines noise A, and the words tokenized by CLIP from your prompt (conditioning). It generates its own noise tensor to predict what the final image might look like in latent space. We’ll call this noise B. +3. Noise B is subtracted from noise A in an attempt to create a latent image consistent with the prompt. This step is repeated for the number of sampler steps chosen. +4. The VAE decodes the final latent image from latent space into image space. + +Image-to-image is a similar process, with only step 1 being different: +1. The input image is encoded from image space into latent space by the VAE. Noise is then added to the input latent image. Denoising Strength dictates how may noise steps are added, and the amount of noise added at each step. A Denoising Strength of 0 means there are 0 steps and no noise added, resulting in an unchanged image, while a Denoising Strength of 1 results in the image being completely replaced with noise and a full set of denoising steps are performance. The process is then the same as steps 2-4 in the text-to-image process. + +Furthermore, a model provides the CLIP prompt tokenizer, the VAE, and a U-Net (where noise prediction occurs given a prompt and initial noise tensor). + +A noise scheduler (eg. DPM++ 2M Karras) schedules the subtraction of noise from the latent image across the sampler steps chosen (step 3 above). Less noise is usually subtracted at higher sampler steps. diff --git a/docs/index.md b/docs/index.md index 099e66908e..a317f4590e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -49,9 +49,9 @@ title: Home [![github stars badge]][github stars link] [![github forks badge]][github forks link] -[![CI checks on main badge]][ci checks on main link] + +[![latest commit to dev badge]][latest commit to dev link] --> [![github open issues badge]][github open issues link] [![github open prs badge]][github open prs link] diff --git a/docs/installation/020_INSTALL_MANUAL.md b/docs/installation/020_INSTALL_MANUAL.md index a68e5b1414..fd0fbe35ed 100644 --- a/docs/installation/020_INSTALL_MANUAL.md +++ b/docs/installation/020_INSTALL_MANUAL.md @@ -8,9 +8,9 @@ title: Installing Manually -!!! warning "This is for advanced Users" +!!! warning "This is for Advanced Users" - **python experience is mandatory** + **Python experience is mandatory** ## Introduction diff --git a/docs/installation/040_INSTALL_DOCKER.md b/docs/installation/040_INSTALL_DOCKER.md index 07e7f55e93..fd75067cf1 100644 --- a/docs/installation/040_INSTALL_DOCKER.md +++ b/docs/installation/040_INSTALL_DOCKER.md @@ -4,9 +4,9 @@ title: Installing with Docker # :fontawesome-brands-docker: Docker -!!! warning "For end users" +!!! warning "For most users" - We highly recommend to Install InvokeAI locally using [these instructions](index.md) + We highly recommend to Install InvokeAI locally using [these instructions](INSTALLATION.md) !!! tip "For developers" diff --git a/docs/javascripts/tablesort.js b/docs/javascripts/tablesort.js new file mode 100644 index 0000000000..ceb1f94acd --- /dev/null +++ b/docs/javascripts/tablesort.js @@ -0,0 +1,7 @@ +document$.subscribe(function() { + var tables = document.querySelectorAll("article table:not([class])") + tables.forEach(function(table) { + new Tablesort(table) + }) + }) + \ No newline at end of file diff --git a/docs/nodes/NODES.md b/docs/nodes/NODES.md new file mode 100644 index 0000000000..9455e6bdcf --- /dev/null +++ b/docs/nodes/NODES.md @@ -0,0 +1,68 @@ +# Using the Node Editor + +The nodes editor is a blank canvas allowing for the use of individual functions and image transformations to control the image generation workflow. Nodes take in inputs on the left side of the node, and return an output on the right side of the node. A node graph is composed of multiple nodes that are connected together to create a workflow. Nodes' inputs and outputs are connected by dragging connectors from node to node. Inputs and outputs are color coded for ease of use. + +To better understand how nodes are used, think of how an electric power bar works. It takes in one input (electricity from a wall outlet) and passes it to multiple devices through multiple outputs. Similarly, a node could have multiple inputs and outputs functioning at the same (or different) time, but all node outputs pass information onward like a power bar passes electricity. Not all outputs are compatible with all inputs, however - Each node has different constraints on how it is expecting to input/output information. In general, node outputs are colour-coded to match compatible inputs of other nodes. + + +If you're not familiar with Diffusion, take a look at our [Diffusion Overview.](../help/diffusion.md) Understanding how diffusion works will enable you to more easily use the Nodes Editor and build workflows to suit your needs. + +## Important Concepts + +There are several node grouping concepts that can be examined with a narrow focus. These (and other) groupings can be pieced together to make up functional graph setups, and are important to understanding how groups of nodes work together as part of a whole. Note that the screenshots below aren't examples of complete functioning node graphs (see Examples). + +### Noise + +An initial noise tensor is necessary for the latent diffusion process. As a result, the Denoising node requires a noise node input. + +![groupsnoise](../assets/nodes/groupsnoise.png) + +### Text Prompt Conditioning + +Conditioning is necessary for the latent diffusion process, whether empty or not. As a result, the Denoising node requires positive and negative conditioning inputs. Conditioning is reliant on a CLIP text encoder provided by the Model Loader node. + +![groupsconditioning](../assets/nodes/groupsconditioning.png) + +### Image to Latents & VAE + +The ImageToLatents node takes in a pixel image and a VAE and outputs a latents. The LatentsToImage node does the opposite, taking in a latents and a VAE and outpus a pixel image. + +![groupsimgvae](../assets/nodes/groupsimgvae.png) + +### Defined & Random Seeds + +It is common to want to use both the same seed (for continuity) and random seeds (for variety). To define a seed, simply enter it into the 'Seed' field on a noise node. Conversely, the RandomInt node generates a random integer between 'Low' and 'High', and can be used as input to the 'Seed' edge point on a noise node to randomize your seed. + +![groupsrandseed](../assets/nodes/groupsrandseed.png) + +### ControlNet + +The ControlNet node outputs a Control, which can be provided as input to non-image *ToLatents nodes. Depending on the type of ControlNet desired, ControlNet nodes usually require an image processor node, such as a Canny Processor or Depth Processor, which prepares an input image for use with ControlNet. + +![groupscontrol](../assets/nodes/groupscontrol.png) + +### LoRA + +The Lora Loader node lets you load a LoRA and pass it as output.A LoRA provides fine-tunes to the UNet and text encoder weights that augment the base model’s image and text vocabularies. + +![groupslora](../assets/nodes/groupslora.png) + +### Scaling + +Use the ImageScale, ScaleLatents, and Upscale nodes to upscale images and/or latent images. Upscaling is the process of enlarging an image and adding more detail. The chosen method differs across contexts. However, be aware that latents are already noisy and compressed at their original resolution; scaling an image could produce more detailed results. + +![groupsallscale](../assets/nodes/groupsallscale.png) + +### Iteration + Multiple Images as Input + +Iteration is a common concept in any processing, and means to repeat a process with given input. In nodes, you're able to use the Iterate node to iterate through collections usually gathered by the Collect node. The Iterate node has many potential uses, from processing a collection of images one after another, to varying seeds across multiple image generations and more. This screenshot demonstrates how to collect several images and use them in an image generation workflow. + +![groupsiterate](../assets/nodes/groupsiterate.png) + +### Multiple Image Generation + Random Seeds + +Multiple image generation in the node editor is done using the RandomRange node. In this case, the 'Size' field represents the number of images to generate. As RandomRange produces a collection of integers, we need to add the Iterate node to iterate through the collection. + +To control seeds across generations takes some care. The first row in the screenshot will generate multiple images with different seeds, but using the same RandomRange parameters across invocations will result in the same group of random seeds being used across the images, producing repeatable results. In the second row, adding the RandomInt node as input to RandomRange's 'Seed' edge point will ensure that seeds are varied across all images across invocations, producing varied results. + +![groupsmultigenseeding](../assets/nodes/groupsmultigenseeding.png) diff --git a/docs/nodes/comfyToInvoke.md b/docs/nodes/comfyToInvoke.md new file mode 100644 index 0000000000..2d894dc74c --- /dev/null +++ b/docs/nodes/comfyToInvoke.md @@ -0,0 +1,80 @@ +# ComfyUI to InvokeAI + +If you're coming to InvokeAI from ComfyUI, welcome! You'll find things are similar but different - the good news is that you already know how things should work, and it's just a matter of wiring them up! + +Some things to note: + +- InvokeAI's nodes tend to be more granular than default nodes in Comfy. This means each node in Invoke will do a specific task and you might need to use multiple nodes to achieve the same result. The added granularity improves the control you have have over your workflows. +- InvokeAI's backend and ComfyUI's backend are very different which means Comfy workflows are not able to be imported into InvokeAI. However, we have created a [list of popular workflows](exampleWorkflows.md) for you to get started with Nodes in InvokeAI! + +## Node Equivalents: + +| Comfy UI Category | ComfyUI Node | Invoke Equivalent | +|:---------------------------------- |:---------------------------------- | :----------------------------------| +| Sampling |KSampler |Denoise Latents| +| Sampling |Ksampler Advanced|Denoise Latents | +| Loaders |Load Checkpoint | Main Model Loader _or_ SDXL Main Model Loader| +| Loaders |Load VAE | VAE Loader | +| Loaders |Load Lora | LoRA Loader _or_ SDXL Lora Loader| +| Loaders |Load ControlNet Model | ControlNet| +| Loaders |Load ControlNet Model (diff) | ControlNet| +| Loaders |Load Style Model | Reference Only ControlNet will be coming in a future version of InvokeAI| +| Loaders |unCLIPCheckpointLoader | N/A | +| Loaders |GLIGENLoader | N/A | +| Loaders |Hypernetwork Loader | N/A | +| Loaders |Load Upscale Model | Occurs within "Upscale (RealESRGAN)"| +|Conditioning |CLIP Text Encode (Prompt) | Compel (Prompt) or SDXL Compel (Prompt) | +|Conditioning |CLIP Set Last Layer | CLIP Skip| +|Conditioning |Conditioning (Average) | Use the .blend() feature of prompts | +|Conditioning |Conditioning (Combine) | N/A | +|Conditioning |Conditioning (Concat) | See the Prompt Tools Community Node| +|Conditioning |Conditioning (Set Area) | N/A | +|Conditioning |Conditioning (Set Mask) | Mask Edge | +|Conditioning |CLIP Vision Encode | N/A | +|Conditioning |unCLIPConditioning | N/A | +|Conditioning |Apply ControlNet | ControlNet | +|Conditioning |Apply ControlNet (Advanced) | ControlNet | +|Latent |VAE Decode | Latents to Image| +|Latent |VAE Encode | Image to Latents | +|Latent |Empty Latent Image | Noise | +|Latent |Upscale Latent |Resize Latents | +|Latent |Upscale Latent By |Scale Latents | +|Latent |Latent Composite | Blend Latents | +|Latent |LatentCompositeMasked | N/A | +|Image |Save Image | Image | +|Image |Preview Image |Current | +|Image |Load Image | Image| +|Image |Empty Image| Blank Image | +|Image |Invert Image | Invert Lerp Image | +|Image |Batch Images | Link "Image" nodes into an "Image Collection" node | +|Image |Pad Image for Outpainting | Outpainting is easily accomplished in the Unified Canvas | +|Image |ImageCompositeMasked | Paste Image | +|Image | Upscale Image | Resize Image | +|Image | Upscale Image By | Upscale Image | +|Image | Upscale Image (using Model) | Upscale Image | +|Image | ImageBlur | Blur Image | +|Image | ImageQuantize | N/A | +|Image | ImageSharpen | N/A | +|Image | Canny | Canny Processor | +|Mask |Load Image (as Mask) | Image | +|Mask |Convert Mask to Image | Image| +|Mask |Convert Image to Mask | Image | +|Mask |SolidMask | N/A | +|Mask |InvertMask |Invert Lerp Image | +|Mask |CropMask | Crop Image | +|Mask |MaskComposite | Combine Mask | +|Mask |FeatherMask | Blur Image | +|Advanced | Load CLIP | Main Model Loader _or_ SDXL Main Model Loader| +|Advanced | UNETLoader | Main Model Loader _or_ SDXL Main Model Loader| +|Advanced | DualCLIPLoader | Main Model Loader _or_ SDXL Main Model Loader| +|Advanced | Load Checkpoint | Main Model Loader _or_ SDXL Main Model Loader | +|Advanced | ConditioningZeroOut | N/A | +|Advanced | ConditioningSetTimestepRange | N/A | +|Advanced | CLIPTextEncodeSDXLRefiner | Compel (Prompt) or SDXL Compel (Prompt) | +|Advanced | CLIPTextEncodeSDXL |Compel (Prompt) or SDXL Compel (Prompt) | +|Advanced | ModelMergeSimple | Model Merging is available in the Model Manager | +|Advanced | ModelMergeBlocks | Model Merging is available in the Model Manager| +|Advanced | CheckpointSave | Model saving is available in the Model Manager| +|Advanced | CLIPMergeSimple | N/A | + + diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index 2e04018b45..65aa55ee15 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -2,17 +2,13 @@ These are nodes that have been developed by the community, for the community. If you're not sure what a node is, you can learn more about nodes [here](overview.md). -If you'd like to submit a node for the community, please refer to the [node creation overview](./overview.md#contributing-nodes). +If you'd like to submit a node for the community, please refer to the [node creation overview](contributingNodes.md). -To download a node, simply download the `.py` node file from the link and add it to the `invokeai/app/invocations/` folder in your Invoke AI install location. Along with the node, an example node graph should be provided to help you get started with the node. +To download a node, simply download the `.py` node file from the link and add it to the `invokeai/app/invocations` folder in your Invoke AI install location. Along with the node, an example node graph should be provided to help you get started with the node. To use a community node graph, download the the `.json` node graph file and load it into Invoke AI via the **Load Nodes** button on the Node Editor. -## Disclaimer - -The nodes linked below have been developed and contributed by members of the Invoke AI community. While we strive to ensure the quality and safety of these contributions, we do not guarantee the reliability or security of the nodes. If you have issues or concerns with any of the nodes below, please raise it on GitHub or in the Discord. - -## List of Nodes +## Community Nodes ### FaceTools @@ -26,15 +22,81 @@ The nodes linked below have been developed and contributed by members of the Inv ![b920b710-1882-49a0-8d02-82dff2cca907](https://github.com/invoke-ai/InvokeAI/assets/25252829/7660c1ed-bf7d-4d0a-947f-1fc1679557ba) ![71a91805-fda5-481c-b380-264665703133](https://github.com/invoke-ai/InvokeAI/assets/25252829/f8f6a2ee-2b68-4482-87da-b90221d5c3e2) -
- ### 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 + -------------------------------- +### 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) + +-------------------------------- +### GPT2RandomPromptMaker + +**Description:** A node for InvokeAI utilizes the GPT-2 language model to generate random prompts based on a provided seed and context. + +**Node Link:** https://github.com/mickr777/GPT2RandomPromptMaker + +**Output Examples** + +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 + +**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:** +======= +![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) + +-------------------------------- + +### 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." + +![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. + +-------------------------------- + ### Example Node Template **Description:** This node allows you to do super cool things with InvokeAI. @@ -47,7 +109,12 @@ The nodes linked below have been developed and contributed by members of the Inv ![Example Image](https://invoke-ai.github.io/InvokeAI/assets/invoke_ai_banner.png){: style="height:115px;width:240px"} + +## Disclaimer + +The nodes linked have been developed and contributed by members of the Invoke AI community. While we strive to ensure the quality and safety of these contributions, we do not guarantee the reliability or security of the nodes. If you have issues or concerns with any of the nodes below, please raise it on GitHub or in the Discord. + + ## Help If you run into any issues with a node, please post in the [InvokeAI Discord](https://discord.gg/ZmtBAhwWhy). - diff --git a/docs/nodes/contributingNodes.md b/docs/nodes/contributingNodes.md new file mode 100644 index 0000000000..a34d429cd8 --- /dev/null +++ b/docs/nodes/contributingNodes.md @@ -0,0 +1,27 @@ +# Contributing Nodes + +To learn about the specifics of creating a new node, please visit our [Node creation documentation](../contributing/INVOCATIONS.md). + +Once you’ve created a node and confirmed that it behaves as expected locally, follow these steps: + +- Make sure the node is contained in a new Python (.py) file +- Submit a pull request with a link to your node in GitHub against the `nodes` branch to add the node to the [Community Nodes](Community Nodes) list + - Make sure you are following the template below and have provided all relevant details about the node and what it does. +- A maintainer will review the pull request and node. If the node is aligned with the direction of the project, you might be asked for permission to include it in the core project. + +### Community Node Template + +```markdown +-------------------------------- +### Super Cool Node Template + +**Description:** This node allows you to do super cool things with InvokeAI. + +**Node Link:** https://github.com/invoke-ai/InvokeAI/fake_node.py + +**Example Node Graph:** https://github.com/invoke-ai/InvokeAI/fake_node_graph.json + +**Output Examples** + +![InvokeAI](https://invoke-ai.github.io/InvokeAI/assets/invoke_ai_banner.png) +``` diff --git a/docs/nodes/defaultNodes.md b/docs/nodes/defaultNodes.md new file mode 100644 index 0000000000..7748f635cb --- /dev/null +++ b/docs/nodes/defaultNodes.md @@ -0,0 +1,97 @@ +# List of Default Nodes + +The table below contains a list of the default nodes shipped with InvokeAI and their descriptions. + +| Node | Function | +|: ---------------------------------- | :--------------------------------------------------------------------------------------| +|Add Integers | Adds two numbers| +|Boolean Primitive Collection | A collection of boolean primitive values| +|Boolean Primitive | A boolean primitive value| +|Canny Processor | Canny edge detection for ControlNet| +|CLIP Skip | Skip layers in clip text_encoder model.| +|Collect | Collects values into a collection| +|Color Correct | Shifts the colors of a target image to match the reference image, optionally using a mask to only color-correct certain regions of the target image.| +|Color Primitive | A color primitive value| +|Compel Prompt | Parse prompt using compel package to conditioning.| +|Conditioning Primitive Collection | A collection of conditioning tensor primitive values| +|Conditioning Primitive | A conditioning tensor primitive value| +|Content Shuffle Processor | Applies content shuffle processing to image| +|ControlNet | Collects ControlNet info to pass to other nodes| +|OpenCV Inpaint | Simple inpaint using opencv.| +|Denoise Latents | Denoises noisy latents to decodable images| +|Divide Integers | Divides two numbers| +|Dynamic Prompt | Parses a prompt using adieyal/dynamicprompts' random or combinatorial generator| +|Upscale (RealESRGAN) | Upscales an image using RealESRGAN.| +|Float Primitive Collection | A collection of float primitive values| +|Float Primitive | A float primitive value| +|Float Range | Creates a range| +|HED (softedge) Processor | Applies HED edge detection to image| +|Blur Image | Blurs an image| +|Extract Image Channel | Gets a channel from an image.| +|Image Primitive Collection | A collection of image primitive values| +|Convert Image Mode | Converts an image to a different mode.| +|Crop Image | Crops an image to a specified box. The box can be outside of the image.| +|Image Hue Adjustment | Adjusts the Hue of an image.| +|Inverse Lerp Image | Inverse linear interpolation of all pixels of an image| +|Image Primitive | An image primitive value| +|Lerp Image | Linear interpolation of all pixels of an image| +|Image Luminosity Adjustment | Adjusts the Luminosity (Value) of an image.| +|Multiply Images | Multiplies two images together using `PIL.ImageChops.multiply()`.| +|Blur NSFW Image | Add blur to NSFW-flagged images| +|Paste Image | Pastes an image into another image.| +|ImageProcessor | Base class for invocations that preprocess images for ControlNet| +|Resize Image | Resizes an image to specific dimensions| +|Image Saturation Adjustment | Adjusts the Saturation of an image.| +|Scale Image | Scales an image by a factor| +|Image to Latents | Encodes an image into latents.| +|Add Invisible Watermark | Add an invisible watermark to an image| +|Solid Color Infill | Infills transparent areas of an image with a solid color| +|PatchMatch Infill | Infills transparent areas of an image using the PatchMatch algorithm| +|Tile Infill | Infills transparent areas of an image with tiles of the image| +|Integer Primitive Collection | A collection of integer primitive values| +|Integer Primitive | An integer primitive value| +|Iterate | Iterates over a list of items| +|Latents Primitive Collection | A collection of latents tensor primitive values| +|Latents Primitive | A latents tensor primitive value| +|Latents to Image | Generates an image from latents.| +|Leres (Depth) Processor | Applies leres processing to image| +|Lineart Anime Processor | Applies line art anime processing to image| +|Lineart Processor | Applies line art processing to image| +|LoRA Loader | Apply selected lora to unet and text_encoder.| +|Main Model Loader | Loads a main model, outputting its submodels.| +|Combine Mask | Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`.| +|Mask Edge | Applies an edge mask to an image| +|Mask from Alpha | Extracts the alpha channel of an image as a mask.| +|Mediapipe Face Processor | Applies mediapipe face processing to image| +|Midas (Depth) Processor | Applies Midas depth processing to image| +|MLSD Processor | Applies MLSD processing to image| +|Multiply Integers | Multiplies two numbers| +|Noise | Generates latent noise.| +|Normal BAE Processor | Applies NormalBae processing to image| +|ONNX Latents to Image | Generates an image from latents.| +|ONNX Prompt (Raw) | A node to process inputs and produce outputs. May use dependency injection in __init__ to receive providers.| +|ONNX Text to Latents | Generates latents from conditionings.| +|ONNX Model Loader | Loads a main model, outputting its submodels.| +|Openpose Processor | Applies Openpose processing to image| +|PIDI Processor | Applies PIDI processing to image| +|Prompts from File | Loads prompts from a text file| +|Random Integer | Outputs a single random integer.| +|Random Range | Creates a collection of random numbers| +|Integer Range | Creates a range of numbers from start to stop with step| +|Integer Range of Size | Creates a range from start to start + size with step| +|Resize Latents | Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8.| +|SDXL Compel Prompt | Parse prompt using compel package to conditioning.| +|SDXL LoRA Loader | Apply selected lora to unet and text_encoder.| +|SDXL Main Model Loader | Loads an sdxl base model, outputting its submodels.| +|SDXL Refiner Compel Prompt | Parse prompt using compel package to conditioning.| +|SDXL Refiner Model Loader | Loads an sdxl refiner model, outputting its submodels.| +|Scale Latents | Scales latents by a given factor.| +|Segment Anything Processor | Applies segment anything processing to image| +|Show Image | Displays a provided image, and passes it forward in the pipeline.| +|Step Param Easing | Experimental per-step parameter easing for denoising steps| +|String Primitive Collection | A collection of string primitive values| +|String Primitive | A string primitive value| +|Subtract Integers | Subtracts two numbers| +|Tile Resample Processor | Tile resampler processor| +|VAE Loader | Loads a VAE model, outputting a VaeLoaderOutput| +|Zoe (Depth) Processor | Applies Zoe depth processing to image| \ No newline at end of file diff --git a/docs/nodes/exampleWorkflows.md b/docs/nodes/exampleWorkflows.md new file mode 100644 index 0000000000..5f8dabb67c --- /dev/null +++ b/docs/nodes/exampleWorkflows.md @@ -0,0 +1,15 @@ +# Example Workflows + +TODO: Will update once uploading workflows is available. + +## Text2Image + +## Image2Image + +## ControlNet + +## Upscaling + +## Inpainting / Outpainting + +## LoRAs diff --git a/docs/nodes/overview.md b/docs/nodes/overview.md index e959ad9d7b..71e316c856 100644 --- a/docs/nodes/overview.md +++ b/docs/nodes/overview.md @@ -1,42 +1,26 @@ # Nodes ## What are Nodes? -An Node is simply a single operation that takes in some inputs and gives -out some outputs. We can then chain multiple nodes together to create more +An Node is simply a single operation that takes in inputs and returns +out outputs. Multiple nodes can be linked together to create more complex functionality. All InvokeAI features are added through nodes. -This means nodes can be used to easily extend the image generation capabilities of InvokeAI, and allow you build workflows to suit your needs. +### Anatomy of a Node -You can read more about nodes and the node editor [here](../features/NODES.md). +Individual nodes are made up of the following: + +- Inputs: Edge points on the left side of the node window where you connect outputs from other nodes. +- Outputs: Edge points on the right side of the node window where you connect to inputs on other nodes. +- Options: Various options which are either manually configured, or overridden by connecting an output from another node to the input. -## Downloading Nodes -To download a new node, visit our list of [Community Nodes](communityNodes.md). These are nodes that have been created by the community, for the community. +With nodes, you can can easily extend the image generation capabilities of InvokeAI, and allow you build workflows that suit your needs. + +You can read more about nodes and the node editor [here](../nodes/NODES.md). + +To get started with nodes, take a look at some of our examples for [common workflows](../nodes/exampleWorkflows.md) + +## Downloading New Nodes +To download a new node, visit our list of [Community Nodes](../nodes/communityNodes.md). These are nodes that have been created by the community, for the community. -## Contributing Nodes - -To learn about creating a new node, please visit our [Node creation documenation](../contributing/INVOCATIONS.md). - -Once you’ve created a node and confirmed that it behaves as expected locally, follow these steps: -* Make sure the node is contained in a new Python (.py) file -* Submit a pull request with a link to your node in GitHub against the `nodes` branch to add the node to the [Community Nodes](Community Nodes) list - * Make sure you are following the template below and have provided all relevant details about the node and what it does. -* A maintainer will review the pull request and node. If the node is aligned with the direction of the project, you might be asked for permission to include it in the core project. - -### Community Node Template - -```markdown --------------------------------- -### Super Cool Node Template - -**Description:** This node allows you to do super cool things with InvokeAI. - -**Node Link:** https://github.com/invoke-ai/InvokeAI/fake_node.py - -**Example Node Graph:** https://github.com/invoke-ai/InvokeAI/fake_node_graph.json - -**Output Examples** - -![InvokeAI](https://invoke-ai.github.io/InvokeAI/assets/invoke_ai_banner.png) -``` diff --git a/invokeai/app/api/routers/app_info.py b/invokeai/app/api/routers/app_info.py index 9d9e47d2ef..b69a0b9a03 100644 --- a/invokeai/app/api/routers/app_info.py +++ b/invokeai/app/api/routers/app_info.py @@ -55,7 +55,7 @@ async def get_version() -> AppVersion: @app_router.get("/config", operation_id="get_config", status_code=200, response_model=AppConfig) async def get_config() -> AppConfig: - infill_methods = ["tile"] + infill_methods = ["tile", "lama"] if PatchMatch.patchmatch_available(): infill_methods.append("patchmatch") diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index b34000dc04..902af0c02c 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -1,11 +1,11 @@ # Copyright (c) 2022-2023 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team import asyncio -from inspect import signature - import logging -import uvicorn import socket +from inspect import signature +from pathlib import Path +import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html @@ -13,7 +13,6 @@ from fastapi.openapi.utils import get_openapi from fastapi.staticfiles import StaticFiles from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware -from pathlib import Path from pydantic.schema import schema from .services.config import InvokeAIAppConfig @@ -30,9 +29,12 @@ from .api.sockets import SocketIO from .invocations.baseinvocation import BaseInvocation, _InputField, _OutputField, UIConfigBase import torch + +# noinspection PyUnresolvedReferences import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) if torch.backends.mps.is_available(): + # noinspection PyUnresolvedReferences import invokeai.backend.util.mps_fixes # noqa: F401 (monkeypatching on import) @@ -40,7 +42,6 @@ app_config = InvokeAIAppConfig.get_config() app_config.parse_args() logger = InvokeAILogger.getLogger(config=app_config) - # fix for windows mimetypes registry entries being borked # see https://github.com/invoke-ai/InvokeAI/discussions/3684#discussioncomment-6391352 mimetypes.add_type("application/javascript", ".js") @@ -208,6 +209,17 @@ def invoke_api(): check_invokeai_root(app_config) # note, may exit with an exception if root not set up + if app_config.dev_reload: + try: + import jurigged + except ImportError as e: + logger.error( + 'Can\'t start `--dev_reload` because jurigged is not found; `pip install -e ".[dev]"` to include development dependencies.', + exc_info=e, + ) + else: + jurigged.watch(logger=InvokeAILogger.getLogger(name="jurigged").info) + port = find_port(app_config.port) if port != app_config.port: logger.warn(f"Port {app_config.port} in use, using port {port}") diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index d9bdcc988b..cbf5d1bfae 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -170,6 +170,7 @@ class _InputField(BaseModel): ui_hidden: bool ui_type: Optional[UIType] ui_component: Optional[UIComponent] + ui_order: Optional[int] class _OutputField(BaseModel): @@ -182,6 +183,7 @@ class _OutputField(BaseModel): ui_hidden: bool ui_type: Optional[UIType] + ui_order: Optional[int] def InputField( @@ -215,6 +217,7 @@ def InputField( ui_type: Optional[UIType] = None, ui_component: Optional[UIComponent] = None, ui_hidden: bool = False, + ui_order: Optional[int] = None, **kwargs: Any, ) -> Any: """ @@ -273,6 +276,7 @@ def InputField( ui_type=ui_type, ui_component=ui_component, ui_hidden=ui_hidden, + ui_order=ui_order, **kwargs, ) @@ -306,6 +310,7 @@ def OutputField( repr: bool = True, ui_type: Optional[UIType] = None, ui_hidden: bool = False, + ui_order: Optional[int] = None, **kwargs: Any, ) -> Any: """ @@ -352,6 +357,7 @@ def OutputField( repr=repr, ui_type=ui_type, ui_hidden=ui_hidden, + ui_order=ui_order, **kwargs, ) @@ -380,7 +386,7 @@ class BaseInvocationOutput(BaseModel): """Base class for all invocation outputs""" # All outputs must include a type name like this: - # type: Literal['your_output_name'] + # type: Literal['your_output_name'] # noqa f821 @classmethod def get_all_subclasses_tuple(cls): @@ -421,7 +427,7 @@ class BaseInvocation(ABC, BaseModel): """ # All invocations must include a type name like this: - # type: Literal['your_output_name'] + # type: Literal['your_output_name'] # noqa f821 @classmethod def get_all_subclasses(cls): @@ -499,7 +505,7 @@ class BaseInvocation(ABC, BaseModel): raise MissingInputException(self.__fields__["type"].default, field_name) return self.invoke(context) - id: str = InputField(description="The id of this node. Must be unique among all nodes.") + id: str = Field(description="The id of this node. Must be unique among all nodes.") is_intermediate: bool = InputField( default=False, description="Whether or not this node is an intermediate node.", input=Input.Direct ) diff --git a/invokeai/app/invocations/image.py b/invokeai/app/invocations/image.py index f4a1648196..36157e195a 100644 --- a/invokeai/app/invocations/image.py +++ b/invokeai/app/invocations/image.py @@ -8,7 +8,7 @@ import numpy from PIL import Image, ImageChops, ImageFilter, ImageOps from invokeai.app.invocations.metadata import CoreMetadata -from invokeai.app.invocations.primitives import ImageField, ImageOutput +from invokeai.app.invocations.primitives import ColorField, ImageField, ImageOutput from invokeai.backend.image_util.invisible_watermark import InvisibleWatermark from invokeai.backend.image_util.safety_checker import SafetyChecker @@ -41,6 +41,39 @@ class ShowImageInvocation(BaseInvocation): ) +@title("Blank Image") +@tags("image") +class BlankImageInvocation(BaseInvocation): + """Creates a blank image and forwards it to the pipeline""" + + # Metadata + type: Literal["blank_image"] = "blank_image" + + # Inputs + width: int = InputField(default=512, description="The width of the image") + height: int = InputField(default=512, description="The height of the image") + mode: Literal["RGB", "RGBA"] = InputField(default="RGB", description="The mode of the image") + color: ColorField = InputField(default=ColorField(r=0, g=0, b=0, a=255), description="The color of the image") + + def invoke(self, context: InvocationContext) -> ImageOutput: + image = Image.new(mode=self.mode, size=(self.width, self.height), color=self.color.tuple()) + + image_dto = context.services.images.create( + image=image, + image_origin=ResourceOrigin.INTERNAL, + image_category=ImageCategory.GENERAL, + node_id=self.id, + session_id=context.graph_execution_state_id, + is_intermediate=self.is_intermediate, + ) + + return ImageOutput( + image=ImageField(image_name=image_dto.image_name), + width=image_dto.width, + height=image_dto.height, + ) + + @title("Crop Image") @tags("image", "crop") class ImageCropInvocation(BaseInvocation): diff --git a/invokeai/app/invocations/infill.py b/invokeai/app/invocations/infill.py index fea418567b..78b641b210 100644 --- a/invokeai/app/invocations/infill.py +++ b/invokeai/app/invocations/infill.py @@ -1,23 +1,25 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team +import math from typing import Literal, Optional, get_args import numpy as np -import math from PIL import Image, ImageOps -from invokeai.app.invocations.primitives import ImageField, ImageOutput, ColorField +from invokeai.app.invocations.primitives import ColorField, ImageField, ImageOutput from invokeai.app.util.misc import SEED_MAX, get_random_seed +from invokeai.backend.image_util.lama import LaMA from invokeai.backend.image_util.patchmatch import PatchMatch from ..models.image import ImageCategory, ResourceOrigin -from .baseinvocation import BaseInvocation, InputField, InvocationContext, title, tags +from .baseinvocation import BaseInvocation, InputField, InvocationContext, tags, title def infill_methods() -> list[str]: methods = [ "tile", "solid", + "lama", ] if PatchMatch.patchmatch_available(): methods.insert(0, "patchmatch") @@ -28,6 +30,11 @@ INFILL_METHODS = Literal[tuple(infill_methods())] DEFAULT_INFILL_METHOD = "patchmatch" if "patchmatch" in get_args(INFILL_METHODS) else "tile" +def infill_lama(im: Image.Image) -> Image.Image: + lama = LaMA() + return lama(im) + + def infill_patchmatch(im: Image.Image) -> Image.Image: if im.mode != "RGBA": return im @@ -90,7 +97,7 @@ def tile_fill_missing(im: Image.Image, tile_size: int = 16, seed: Optional[int] return im # Find all invalid tiles and replace with a random valid tile - replace_count = (tiles_mask is False).sum() + replace_count = (tiles_mask == False).sum() # noqa: E712 rng = np.random.default_rng(seed=seed) tiles_all[np.logical_not(tiles_mask)] = filtered_tiles[rng.choice(filtered_tiles.shape[0], replace_count), :, :, :] @@ -218,3 +225,34 @@ class InfillPatchMatchInvocation(BaseInvocation): width=image_dto.width, height=image_dto.height, ) + + +@title("LaMa Infill") +@tags("image", "inpaint") +class LaMaInfillInvocation(BaseInvocation): + """Infills transparent areas of an image using the LaMa model""" + + type: Literal["infill_lama"] = "infill_lama" + + # Inputs + image: ImageField = InputField(description="The image to infill") + + def invoke(self, context: InvocationContext) -> ImageOutput: + image = context.services.images.get_pil_image(self.image.image_name) + + infilled = infill_lama(image.copy()) + + image_dto = context.services.images.create( + image=infilled, + image_origin=ResourceOrigin.INTERNAL, + image_category=ImageCategory.GENERAL, + node_id=self.id, + session_id=context.graph_execution_state_id, + is_intermediate=self.is_intermediate, + ) + + return ImageOutput( + image=ImageField(image_name=image_dto.image_name), + width=image_dto.width, + height=image_dto.height, + ) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index ba7f9e754f..314301663b 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -107,12 +107,12 @@ class DenoiseLatentsInvocation(BaseInvocation): # Inputs positive_conditioning: ConditioningField = InputField( - description=FieldDescriptions.positive_cond, input=Input.Connection + description=FieldDescriptions.positive_cond, input=Input.Connection, ui_order=0 ) negative_conditioning: ConditioningField = InputField( - description=FieldDescriptions.negative_cond, input=Input.Connection + description=FieldDescriptions.negative_cond, input=Input.Connection, ui_order=1 ) - noise: Optional[LatentsField] = InputField(description=FieldDescriptions.noise, input=Input.Connection) + noise: Optional[LatentsField] = InputField(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, ui_type=UIType.Float, title="CFG Scale" @@ -122,11 +122,13 @@ class DenoiseLatentsInvocation(BaseInvocation): scheduler: SAMPLER_NAME_VALUES = InputField( default="euler", description=FieldDescriptions.scheduler, ui_type=UIType.Scheduler ) - unet: UNetField = InputField(description=FieldDescriptions.unet, input=Input.Connection, title="UNet") + unet: UNetField = InputField(description=FieldDescriptions.unet, input=Input.Connection, title="UNet", ui_order=2) control: Union[ControlField, list[ControlField]] = InputField( - default=None, description=FieldDescriptions.control, input=Input.Connection + default=None, description=FieldDescriptions.control, input=Input.Connection, ui_order=5 + ) + latents: Optional[LatentsField] = InputField( + description=FieldDescriptions.latents, input=Input.Connection, ui_order=4 ) - latents: Optional[LatentsField] = InputField(description=FieldDescriptions.latents, input=Input.Connection) mask: Optional[ImageField] = InputField( default=None, description=FieldDescriptions.mask, diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 679c610750..a2e34109df 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -32,6 +32,7 @@ class CoreMetadata(BaseModelExcludeNull): generation_mode: str = Field( 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") diff --git a/invokeai/app/services/config/__init__.py b/invokeai/app/services/config/__init__.py new file mode 100644 index 0000000000..6a42f9e08c --- /dev/null +++ b/invokeai/app/services/config/__init__.py @@ -0,0 +1,8 @@ +""" +Init file for InvokeAI configure package +""" + +from .invokeai_config import ( # noqa F401 + InvokeAIAppConfig, + get_invokeai_config, +) diff --git a/invokeai/app/services/config/base.py b/invokeai/app/services/config/base.py new file mode 100644 index 0000000000..b83621c708 --- /dev/null +++ b/invokeai/app/services/config/base.py @@ -0,0 +1,239 @@ +# Copyright (c) 2023 Lincoln Stein (https://github.com/lstein) and the InvokeAI Development Team + +""" +Base class for the InvokeAI configuration system. +It defines a type of pydantic BaseSettings object that +is able to read and write from an omegaconf-based config file, +with overriding of settings from environment variables and/or +the command line. +""" + +from __future__ import annotations +import argparse +import os +import pydoc +import sys +from argparse import ArgumentParser +from omegaconf import OmegaConf, DictConfig, ListConfig +from pathlib import Path +from pydantic import BaseSettings +from typing import ClassVar, Dict, List, Literal, Union, get_origin, get_type_hints, get_args + + +class PagingArgumentParser(argparse.ArgumentParser): + """ + A custom ArgumentParser that uses pydoc to page its output. + It also supports reading defaults from an init file. + """ + + def print_help(self, file=None): + text = self.format_help() + pydoc.pager(text) + + +class InvokeAISettings(BaseSettings): + """ + Runtime configuration settings in which default values are + read from an omegaconf .yaml file. + """ + + initconf: ClassVar[DictConfig] = None + argparse_groups: ClassVar[Dict] = {} + + def parse_args(self, argv: list = sys.argv[1:]): + parser = self.get_parser() + opt = parser.parse_args(argv) + for name in self.__fields__: + if name not in self._excluded(): + value = getattr(opt, name) + if isinstance(value, ListConfig): + value = list(value) + elif isinstance(value, DictConfig): + value = dict(value) + setattr(self, name, value) + + def to_yaml(self) -> str: + """ + Return a YAML string representing our settings. This can be used + as the contents of `invokeai.yaml` to restore settings later. + """ + cls = self.__class__ + type = get_args(get_type_hints(cls)["type"])[0] + field_dict = dict({type: dict()}) + for name, field in self.__fields__.items(): + if name in cls._excluded_from_yaml(): + continue + category = field.field_info.extra.get("category") or "Uncategorized" + value = getattr(self, name) + if category not in field_dict[type]: + field_dict[type][category] = dict() + # keep paths as strings to make it easier to read + field_dict[type][category][name] = str(value) if isinstance(value, Path) else value + conf = OmegaConf.create(field_dict) + return OmegaConf.to_yaml(conf) + + @classmethod + def add_parser_arguments(cls, parser): + if "type" in get_type_hints(cls): + settings_stanza = get_args(get_type_hints(cls)["type"])[0] + else: + settings_stanza = "Uncategorized" + + env_prefix = cls.Config.env_prefix if hasattr(cls.Config, "env_prefix") else settings_stanza.upper() + + initconf = ( + cls.initconf.get(settings_stanza) + if cls.initconf and settings_stanza in cls.initconf + else OmegaConf.create() + ) + + # create an upcase version of the environment in + # order to achieve case-insensitive environment + # variables (the way Windows does) + upcase_environ = dict() + for key, value in os.environ.items(): + upcase_environ[key.upper()] = value + + fields = cls.__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") + env_name = env_prefix + "_" + name + if category in initconf and name in initconf.get(category): + field.default = initconf.get(category).get(name) + if env_name.upper() in upcase_environ: + field.default = upcase_environ[env_name.upper()] + cls.add_field_argument(parser, name, field) + + field.default = current_default + + @classmethod + def cmd_name(self, command_field: str = "type") -> str: + hints = get_type_hints(self) + if command_field in hints: + return get_args(hints[command_field])[0] + else: + return "Uncategorized" + + @classmethod + def get_parser(cls) -> ArgumentParser: + parser = PagingArgumentParser( + prog=cls.cmd_name(), + description=cls.__doc__, + ) + cls.add_parser_arguments(parser) + return parser + + @classmethod + def add_subparser(cls, parser: argparse.ArgumentParser): + parser.add_parser(cls.cmd_name(), help=cls.__doc__) + + @classmethod + def _excluded(self) -> List[str]: + # internal fields that shouldn't be exposed as command line options + return ["type", "initconf"] + + @classmethod + def _excluded_from_yaml(self) -> List[str]: + # combination of deprecated parameters and internal ones that shouldn't be exposed as invokeai.yaml options + return [ + "type", + "initconf", + "version", + "from_file", + "model", + "root", + "max_cache_size", + "max_vram_cache_size", + "always_use_cpu", + "free_gpu_mem", + "xformers_enabled", + "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) + default = ( + default_override + if default_override is not None + else field.default + if field.default_factory is None + else field.default_factory() + ) + if category := field.field_info.extra.get("category"): + if category not in cls.argparse_groups: + cls.argparse_groups[category] = command_parser.add_argument_group(category) + argparse_group = cls.argparse_groups[category] + else: + argparse_group = command_parser + + if get_origin(field_type) == Literal: + allowed_values = get_args(field.type_) + allowed_types = set() + for val in allowed_values: + allowed_types.add(type(val)) + allowed_types_list = list(allowed_types) + field_type = allowed_types_list[0] if len(allowed_types) == 1 else int_or_float_or_str + + argparse_group.add_argument( + f"--{name}", + dest=name, + type=field_type, + default=default, + choices=allowed_values, + help=field.field_info.description, + ) + + elif get_origin(field_type) == Union: + argparse_group.add_argument( + f"--{name}", + dest=name, + type=int_or_float_or_str, + default=default, + help=field.field_info.description, + ) + + elif get_origin(field_type) == list: + argparse_group.add_argument( + f"--{name}", + dest=name, + nargs="*", + type=field.type_, + default=default, + action=argparse.BooleanOptionalAction if field.type_ == bool else "store", + help=field.field_info.description, + ) + else: + argparse_group.add_argument( + f"--{name}", + dest=name, + type=field.type_, + default=default, + action=argparse.BooleanOptionalAction if field.type_ == bool else "store", + help=field.field_info.description, + ) + + +def int_or_float_or_str(value: str) -> Union[int, float, str]: + """ + Workaround for argparse type checking. + """ + try: + return int(value) + except Exception as e: # noqa F841 + pass + try: + return float(value) + except Exception as e: # noqa F841 + pass + return str(value) diff --git a/invokeai/app/services/config.py b/invokeai/app/services/config/invokeai_config.py similarity index 63% rename from invokeai/app/services/config.py rename to invokeai/app/services/config/invokeai_config.py index a9e5bbee98..1a2c22c89a 100644 --- a/invokeai/app/services/config.py +++ b/invokeai/app/services/config/invokeai_config.py @@ -10,37 +10,49 @@ categories returned by `invokeai --help`. The file looks like this: [file: invokeai.yaml] InvokeAI: - Paths: - root: /home/lstein/invokeai-main - conf_path: configs/models.yaml - legacy_conf_dir: configs/stable-diffusion - outdir: outputs - autoimport_dir: null - Models: - model: stable-diffusion-1.5 - embeddings: true - Memory/Performance: - xformers_enabled: false - sequential_guidance: false - precision: float16 - max_cache_size: 6 - max_vram_cache_size: 0.5 - always_use_cpu: false - free_gpu_mem: false - Features: - esrgan: true - patchmatch: true - internet_available: true - log_tokenization: false Web Server: host: 127.0.0.1 - port: 8081 + port: 9090 allow_origins: [] allow_credentials: true allow_methods: - '*' allow_headers: - '*' + Features: + esrgan: true + internet_available: true + log_tokenization: false + patchmatch: true + ignore_missing_core_models: false + Paths: + autoimport_dir: autoimport + lora_dir: null + embedding_dir: null + controlnet_dir: null + conf_path: configs/models.yaml + models_dir: models + legacy_conf_dir: configs/stable-diffusion + db_dir: databases + outdir: /home/lstein/invokeai-main/outputs + use_memory_db: false + Logging: + log_handlers: + - console + log_format: plain + log_level: info + Model Cache: + ram: 13.5 + vram: 0.25 + lazy_offload: true + Device: + device: auto + precision: auto + Generation: + sequential_guidance: false + attention_type: xformers + attention_slice_size: auto + force_tiled_decode: false The default name of the configuration file is `invokeai.yaml`, located in INVOKEAI_ROOT. You can replace supersede this by providing any @@ -54,24 +66,23 @@ InvokeAIAppConfig.parse_args() will parse the contents of `sys.argv` at initialization time. You may pass a list of strings in the optional `argv` argument to use instead of the system argv: - conf.parse_args(argv=['--xformers_enabled']) + conf.parse_args(argv=['--log_tokenization']) It is also possible to set a value at initialization time. However, if you call parse_args() it may be overwritten. - conf = InvokeAIAppConfig(xformers_enabled=True) - conf.parse_args(argv=['--no-xformers']) - conf.xformers_enabled + conf = InvokeAIAppConfig(log_tokenization=True) + conf.parse_args(argv=['--no-log_tokenization']) + conf.log_tokenization # False - To avoid this, use `get_config()` to retrieve the application-wide configuration object. This will retain any properties set at object creation time: - conf = InvokeAIAppConfig.get_config(xformers_enabled=True) - conf.parse_args(argv=['--no-xformers']) - conf.xformers_enabled + conf = InvokeAIAppConfig.get_config(log_tokenization=True) + conf.parse_args(argv=['--no-log_tokenization']) + conf.log_tokenization # True Any setting can be overwritten by setting an environment variable of @@ -93,7 +104,7 @@ Typical usage at the top level file: # get global configuration and print its cache size conf = InvokeAIAppConfig.get_config() conf.parse_args() - print(conf.max_cache_size) + print(conf.ram_cache_size) Typical usage in a backend module: @@ -101,8 +112,7 @@ Typical usage in a backend module: # get global configuration and print its cache size value conf = InvokeAIAppConfig.get_config() - print(conf.max_cache_size) - + print(conf.ram_cache_size) Computed properties: @@ -159,15 +169,15 @@ two configs are kept in separate sections of the config file: """ from __future__ import annotations -import argparse -import pydoc + import os -import sys -from argparse import ArgumentParser -from omegaconf import OmegaConf, DictConfig, ListConfig from pathlib import Path -from pydantic import BaseSettings, Field, parse_obj_as -from typing import ClassVar, Dict, List, Literal, Union, get_origin, get_type_hints, get_args +from typing import ClassVar, Dict, List, Literal, Union, get_type_hints, Optional + +from omegaconf import OmegaConf, DictConfig +from pydantic import Field, parse_obj_as + +from .base import InvokeAISettings INIT_FILE = Path("invokeai.yaml") DB_FILE = Path("invokeai.db") @@ -175,195 +185,6 @@ LEGACY_INIT_FILE = Path("invokeai.init") DEFAULT_MAX_VRAM = 0.5 -class InvokeAISettings(BaseSettings): - """ - Runtime configuration settings in which default values are - read from an omegaconf .yaml file. - """ - - initconf: ClassVar[DictConfig] = None - argparse_groups: ClassVar[Dict] = {} - - def parse_args(self, argv: list = sys.argv[1:]): - parser = self.get_parser() - opt = parser.parse_args(argv) - for name in self.__fields__: - if name not in self._excluded(): - value = getattr(opt, name) - if isinstance(value, ListConfig): - value = list(value) - elif isinstance(value, DictConfig): - value = dict(value) - setattr(self, name, value) - - def to_yaml(self) -> str: - """ - Return a YAML string representing our settings. This can be used - as the contents of `invokeai.yaml` to restore settings later. - """ - cls = self.__class__ - type = get_args(get_type_hints(cls)["type"])[0] - field_dict = dict({type: dict()}) - for name, field in self.__fields__.items(): - if name in cls._excluded_from_yaml(): - continue - category = field.field_info.extra.get("category") or "Uncategorized" - value = getattr(self, name) - if category not in field_dict[type]: - field_dict[type][category] = dict() - # keep paths as strings to make it easier to read - field_dict[type][category][name] = str(value) if isinstance(value, Path) else value - conf = OmegaConf.create(field_dict) - return OmegaConf.to_yaml(conf) - - @classmethod - def add_parser_arguments(cls, parser): - if "type" in get_type_hints(cls): - settings_stanza = get_args(get_type_hints(cls)["type"])[0] - else: - settings_stanza = "Uncategorized" - - env_prefix = cls.Config.env_prefix if hasattr(cls.Config, "env_prefix") else settings_stanza.upper() - - initconf = ( - cls.initconf.get(settings_stanza) - if cls.initconf and settings_stanza in cls.initconf - else OmegaConf.create() - ) - - # create an upcase version of the environment in - # order to achieve case-insensitive environment - # variables (the way Windows does) - upcase_environ = dict() - for key, value in os.environ.items(): - upcase_environ[key.upper()] = value - - fields = cls.__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") - env_name = env_prefix + "_" + name - if category in initconf and name in initconf.get(category): - field.default = initconf.get(category).get(name) - if env_name.upper() in upcase_environ: - field.default = upcase_environ[env_name.upper()] - cls.add_field_argument(parser, name, field) - - field.default = current_default - - @classmethod - def cmd_name(self, command_field: str = "type") -> str: - hints = get_type_hints(self) - if command_field in hints: - return get_args(hints[command_field])[0] - else: - return "Uncategorized" - - @classmethod - def get_parser(cls) -> ArgumentParser: - parser = PagingArgumentParser( - prog=cls.cmd_name(), - description=cls.__doc__, - ) - cls.add_parser_arguments(parser) - return parser - - @classmethod - def add_subparser(cls, parser: argparse.ArgumentParser): - parser.add_parser(cls.cmd_name(), help=cls.__doc__) - - @classmethod - def _excluded(self) -> List[str]: - # internal fields that shouldn't be exposed as command line options - return ["type", "initconf"] - - @classmethod - def _excluded_from_yaml(self) -> List[str]: - # combination of deprecated parameters and internal ones that shouldn't be exposed as invokeai.yaml options - return [ - "type", - "initconf", - "version", - "from_file", - "model", - "root", - ] - - 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) - default = ( - default_override - if default_override is not None - else field.default - if field.default_factory is None - else field.default_factory() - ) - if category := field.field_info.extra.get("category"): - if category not in cls.argparse_groups: - cls.argparse_groups[category] = command_parser.add_argument_group(category) - argparse_group = cls.argparse_groups[category] - else: - argparse_group = command_parser - - if get_origin(field_type) == Literal: - allowed_values = get_args(field.type_) - allowed_types = set() - for val in allowed_values: - allowed_types.add(type(val)) - allowed_types_list = list(allowed_types) - field_type = allowed_types_list[0] if len(allowed_types) == 1 else Union[allowed_types_list] # type: ignore - - argparse_group.add_argument( - f"--{name}", - dest=name, - type=field_type, - default=default, - choices=allowed_values, - help=field.field_info.description, - ) - - elif get_origin(field_type) == list: - argparse_group.add_argument( - f"--{name}", - dest=name, - nargs="*", - type=field.type_, - default=default, - action=argparse.BooleanOptionalAction if field.type_ == bool else "store", - help=field.field_info.description, - ) - else: - argparse_group.add_argument( - f"--{name}", - dest=name, - type=field.type_, - default=default, - action=argparse.BooleanOptionalAction if field.type_ == bool else "store", - help=field.field_info.description, - ) - - -def _find_root() -> Path: - venv = Path(os.environ.get("VIRTUAL_ENV") or ".") - if os.environ.get("INVOKEAI_ROOT"): - root = Path(os.environ["INVOKEAI_ROOT"]) - elif any([(venv.parent / x).exists() for x in [INIT_FILE, LEGACY_INIT_FILE]]): - root = (venv.parent).resolve() - else: - root = Path("~/invokeai").expanduser().resolve() - return root - - class InvokeAIAppConfig(InvokeAISettings): """ Generate images using Stable Diffusion. Use "invokeai" to launch @@ -378,6 +199,8 @@ class InvokeAIAppConfig(InvokeAISettings): # fmt: off 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') @@ -385,20 +208,14 @@ class InvokeAIAppConfig(InvokeAISettings): 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') + # 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') - 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 : bool = Field(default=False, description="If true, purge model from GPU after each generation.", category='Memory/Performance') - max_cache_size : float = Field(default=6.0, gt=0, description="Maximum memory amount used by model cache for rapid switching", category='Memory/Performance') - max_vram_cache_size : float = Field(default=2.75, ge=0, description="Amount of VRAM reserved for model storage", category='Memory/Performance') - precision : Literal['auto', 'float16', 'float32', 'autocast'] = Field(default='auto', description='Floating point precision', category='Memory/Performance') - sequential_guidance : bool = Field(default=False, description="Whether to calculate guidance in serial instead of in parallel, lowering memory requirements", 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') - + # 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') @@ -409,16 +226,43 @@ class InvokeAIAppConfig(InvokeAISettings): 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') - from_file : Path = Field(default=None, description='Take command input from the indicated file (command-line client only)', category='Paths') use_memory_db : bool = Field(default=False, description='Use in-memory database for storing image metadata', category='Paths') - ignore_missing_core_models : bool = Field(default=False, description='Ignore missing models in models/core/convert', category='Features') + from_file : Path = Field(default=None, description='Take command input from the indicated file (command-line client only)', category='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") # 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") + dev_reload : bool = Field(default=False, description="Automatically reload when Python sources are changed.", category="Development") + version : bool = Field(default=False, description="Show InvokeAI version and exit", category="Other") + + # CACHE + ram : Union[float, Literal["auto"]] = Field(default=6.0, gt=0, description="Maximum memory amount used by model cache for rapid switching (floating point number or 'auto')", category="Model Cache", ) + vram : Union[float, Literal["auto"]] = Field(default=0.25, ge=0, description="Amount of VRAM reserved for model storage (floating point number or 'auto')", category="Model Cache", ) + lazy_offload : bool = Field(default=True, description="Keep models in VRAM until their space is needed", category="Model Cache", ) + + # DEVICE + device : Literal[tuple(["auto", "cpu", "cuda", "cuda:1", "mps"])] = Field(default="auto", description="Generation device", category="Device", ) + precision: Literal[tuple(["auto", "float16", "float32", "autocast"])] = Field(default="auto", description="Floating point precision", category="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[tuple(["auto", "normal", "xformers", "sliced", "torch-sdp"])] = Field(default="auto", description="Attention type", category="Generation", ) + attention_slice_size: Literal[tuple(["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",) + + # 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') + + # See InvokeAIAppConfig subclass below for CACHE and DEVICE categories # fmt: on class Config: @@ -541,11 +385,6 @@ class InvokeAIAppConfig(InvokeAISettings): """Return true if precision set to float32""" return self.precision == "float32" - @property - def disable_xformers(self) -> bool: - """Return true if xformers_enabled is false""" - return not self.xformers_enabled - @property def try_patchmatch(self) -> bool: """Return true if patchmatch true""" @@ -561,6 +400,27 @@ class InvokeAIAppConfig(InvokeAISettings): """invisible watermark node is always active and disabled from Web UIe""" return True + @property + def ram_cache_size(self) -> float: + return self.max_cache_size or self.ram + + @property + def vram_cache_size(self) -> float: + return self.max_vram_cache_size or self.vram + + @property + def use_cpu(self) -> bool: + return self.always_use_cpu or self.device == "cpu" + + @property + def disable_xformers(self) -> bool: + """ + Return true if enable_xformers is false (reversed logic) + and attention type is not set to xformers. + """ + disabled_in_config = not self.xformers_enabled + return disabled_in_config and self.attention_type != "xformers" + @staticmethod def find_root() -> Path: """ @@ -570,19 +430,19 @@ class InvokeAIAppConfig(InvokeAISettings): return _find_root() -class PagingArgumentParser(argparse.ArgumentParser): - """ - A custom ArgumentParser that uses pydoc to page its output. - It also supports reading defaults from an init file. - """ - - def print_help(self, file=None): - text = self.format_help() - pydoc.pager(text) - - def get_invokeai_config(**kwargs) -> InvokeAIAppConfig: """ Legacy function which returns InvokeAIAppConfig.get_config() """ return InvokeAIAppConfig.get_config(**kwargs) + + +def _find_root() -> Path: + venv = Path(os.environ.get("VIRTUAL_ENV") or ".") + if os.environ.get("INVOKEAI_ROOT"): + root = Path(os.environ["INVOKEAI_ROOT"]) + elif any([(venv.parent / x).exists() for x in [INIT_FILE, LEGACY_INIT_FILE]]): + root = (venv.parent).resolve() + else: + root = Path("~/invokeai").expanduser().resolve() + return root diff --git a/invokeai/app/services/model_manager_service.py b/invokeai/app/services/model_manager_service.py index 675bc71257..11ebab7938 100644 --- a/invokeai/app/services/model_manager_service.py +++ b/invokeai/app/services/model_manager_service.py @@ -330,8 +330,8 @@ class ModelManagerService(ModelManagerServiceBase): # configuration value. If present, then the # cache size is set to 2.5 GB times # the number of max_loaded_models. Otherwise - # use new `max_cache_size` config setting - max_cache_size = config.max_cache_size if hasattr(config, "max_cache_size") else config.max_loaded_models * 2.5 + # use new `ram_cache_size` config setting + max_cache_size = config.ram_cache_size logger.debug(f"Maximum RAM cache size: {max_cache_size} GiB") diff --git a/invokeai/backend/image_util/lama.py b/invokeai/backend/image_util/lama.py new file mode 100644 index 0000000000..2ea22b6fa3 --- /dev/null +++ b/invokeai/backend/image_util/lama.py @@ -0,0 +1,56 @@ +import gc +from typing import Any + +import numpy as np +import torch +from PIL import Image + +from invokeai.app.services.config import get_invokeai_config +from invokeai.backend.util.devices import choose_torch_device + + +def norm_img(np_img): + if len(np_img.shape) == 2: + np_img = np_img[:, :, np.newaxis] + np_img = np.transpose(np_img, (2, 0, 1)) + np_img = np_img.astype("float32") / 255 + return np_img + + +def load_jit_model(url_or_path, device): + model_path = url_or_path + print(f"Loading model from: {model_path}") + model = torch.jit.load(model_path, map_location="cpu").to(device) + model.eval() + return model + + +class LaMA: + def __call__(self, input_image: Image.Image, *args: Any, **kwds: Any) -> Any: + device = choose_torch_device() + model_location = get_invokeai_config().models_path / "core/misc/lama/lama.pt" + model = load_jit_model(model_location, device) + + image = np.asarray(input_image.convert("RGB")) + image = norm_img(image) + + mask = input_image.split()[-1] + mask = np.asarray(mask) + mask = np.invert(mask) + mask = norm_img(mask) + + mask = (mask > 0) * 1 + image = torch.from_numpy(image).unsqueeze(0).to(device) + mask = torch.from_numpy(mask).unsqueeze(0).to(device) + + with torch.inference_mode(): + infilled_image = model(image, mask) + + infilled_image = infilled_image[0].permute(1, 2, 0).detach().cpu().numpy() + infilled_image = np.clip(infilled_image * 255, 0, 255).astype("uint8") + infilled_image = Image.fromarray(infilled_image) + + del model + gc.collect() + + return infilled_image diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index d7ecb41e9b..90298ce076 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -21,6 +21,7 @@ from argparse import Namespace from enum import Enum from pathlib import Path from shutil import get_terminal_size +from typing import get_type_hints, get_args, Any from urllib import request import npyscreen @@ -49,7 +50,8 @@ from invokeai.frontend.install.model_install import addModelsForm, process_and_e # TO DO - Move all the frontend code into invokeai.frontend.install from invokeai.frontend.install.widgets import ( - SingleSelectColumns, + SingleSelectColumnsSimple, + MultiSelectColumns, CenteredButtonPress, FileBox, set_min_terminal_size, @@ -71,6 +73,10 @@ warnings.filterwarnings("ignore") transformers.logging.set_verbosity_error() +def get_literal_fields(field) -> list[Any]: + return get_args(get_type_hints(InvokeAIAppConfig).get(field)) + + # --------------------------globals----------------------- config = InvokeAIAppConfig.get_config() @@ -80,7 +86,11 @@ Model_dir = "models" Default_config_file = config.model_conf_path SD_Configs = config.legacy_conf_path -PRECISION_CHOICES = ["auto", "float16", "float32"] +PRECISION_CHOICES = get_literal_fields("precision") +DEVICE_CHOICES = get_literal_fields("device") +ATTENTION_CHOICES = get_literal_fields("attention_type") +ATTENTION_SLICE_CHOICES = get_literal_fields("attention_slice_size") +GENERATION_OPT_CHOICES = ["sequential_guidance", "force_tiled_decode", "lazy_offload"] GB = 1073741824 # GB in bytes HAS_CUDA = torch.cuda.is_available() _, MAX_VRAM = torch.cuda.mem_get_info() if HAS_CUDA else (0, 0) @@ -311,6 +321,7 @@ class editOptsForm(CyclingForm, npyscreen.FormMultiPage): Use ctrl-N and ctrl-P to move to the ext and

revious fields. Use cursor arrows to make a checkbox selection, and space to toggle. """ + self.nextrely -= 1 for i in textwrap.wrap(label, width=window_width - 6): self.add_widget_intelligent( npyscreen.FixedText, @@ -337,76 +348,127 @@ Use cursor arrows to make a checkbox selection, and space to toggle. use_two_lines=False, scroll_exit=True, ) - self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.TitleFixedText, - name="GPU Management", - begin_entry_at=0, - editable=False, - color="CONTROL", - scroll_exit=True, - ) - self.nextrely -= 1 - self.free_gpu_mem = self.add_widget_intelligent( - npyscreen.Checkbox, - name="Free GPU memory after each generation", - value=old_opts.free_gpu_mem, - max_width=45, - relx=5, - scroll_exit=True, - ) - self.nextrely -= 1 - self.xformers_enabled = self.add_widget_intelligent( - npyscreen.Checkbox, - name="Enable xformers support", - value=old_opts.xformers_enabled, - max_width=30, - relx=50, - scroll_exit=True, - ) - self.nextrely -= 1 - self.always_use_cpu = self.add_widget_intelligent( - npyscreen.Checkbox, - name="Force CPU to be used on GPU systems", - value=old_opts.always_use_cpu, - relx=80, - scroll_exit=True, - ) + + # old settings for defaults precision = old_opts.precision or ("float32" if program_opts.full_precision else "auto") + device = old_opts.device + attention_type = old_opts.attention_type + attention_slice_size = old_opts.attention_slice_size self.nextrely += 1 self.add_widget_intelligent( npyscreen.TitleFixedText, - name="Floating Point Precision", + name="Image Generation Options:", + editable=False, + color="CONTROL", + scroll_exit=True, + ) + self.nextrely -= 2 + self.generation_options = self.add_widget_intelligent( + MultiSelectColumns, + columns=3, + values=GENERATION_OPT_CHOICES, + value=[GENERATION_OPT_CHOICES.index(x) for x in GENERATION_OPT_CHOICES if getattr(old_opts, x)], + relx=30, + max_height=2, + max_width=80, + scroll_exit=True, + ) + + self.add_widget_intelligent( + npyscreen.TitleFixedText, + name="Floating Point Precision:", begin_entry_at=0, editable=False, color="CONTROL", scroll_exit=True, ) - self.nextrely -= 1 + self.nextrely -= 2 self.precision = self.add_widget_intelligent( - SingleSelectColumns, - columns=3, + SingleSelectColumnsSimple, + columns=len(PRECISION_CHOICES), name="Precision", values=PRECISION_CHOICES, value=PRECISION_CHOICES.index(precision), begin_entry_at=3, max_height=2, + relx=30, + max_width=56, + scroll_exit=True, + ) + self.add_widget_intelligent( + npyscreen.TitleFixedText, + name="Generation Device:", + begin_entry_at=0, + editable=False, + color="CONTROL", + scroll_exit=True, + ) + self.nextrely -= 2 + self.device = self.add_widget_intelligent( + SingleSelectColumnsSimple, + columns=len(DEVICE_CHOICES), + values=DEVICE_CHOICES, + value=[DEVICE_CHOICES.index(device)], + begin_entry_at=3, + relx=30, + max_height=2, + max_width=60, + scroll_exit=True, + ) + self.add_widget_intelligent( + npyscreen.TitleFixedText, + name="Attention Type:", + begin_entry_at=0, + editable=False, + color="CONTROL", + scroll_exit=True, + ) + self.nextrely -= 2 + self.attention_type = self.add_widget_intelligent( + SingleSelectColumnsSimple, + columns=len(ATTENTION_CHOICES), + values=ATTENTION_CHOICES, + value=[ATTENTION_CHOICES.index(attention_type)], + begin_entry_at=3, + max_height=2, + relx=30, max_width=80, scroll_exit=True, ) - self.nextrely += 1 + self.attention_type.on_changed = self.show_hide_slice_sizes + self.attention_slice_label = self.add_widget_intelligent( + npyscreen.TitleFixedText, + name="Attention Slice Size:", + relx=5, + editable=False, + hidden=attention_type != "sliced", + color="CONTROL", + scroll_exit=True, + ) + self.nextrely -= 2 + self.attention_slice_size = self.add_widget_intelligent( + SingleSelectColumnsSimple, + columns=len(ATTENTION_SLICE_CHOICES), + values=ATTENTION_SLICE_CHOICES, + value=[ATTENTION_SLICE_CHOICES.index(attention_slice_size)], + relx=30, + hidden=attention_type != "sliced", + max_height=2, + max_width=110, + scroll_exit=True, + ) self.add_widget_intelligent( npyscreen.TitleFixedText, - name="RAM cache size (GB). Make this at least large enough to hold a single full model.", + name="Model RAM cache size (GB). Make this at least large enough to hold a single full model.", begin_entry_at=0, editable=False, color="CONTROL", scroll_exit=True, ) self.nextrely -= 1 - self.max_cache_size = self.add_widget_intelligent( + self.ram = self.add_widget_intelligent( npyscreen.Slider, - value=clip(old_opts.max_cache_size, range=(3.0, MAX_RAM), step=0.5), + value=clip(old_opts.ram_cache_size, range=(3.0, MAX_RAM), step=0.5), out_of=round(MAX_RAM), lowest=0.0, step=0.5, @@ -417,16 +479,16 @@ Use cursor arrows to make a checkbox selection, and space to toggle. self.nextrely += 1 self.add_widget_intelligent( npyscreen.TitleFixedText, - name="VRAM cache size (GB). Reserving a small amount of VRAM will modestly speed up the start of image generation.", + name="Model VRAM cache size (GB). Reserving a small amount of VRAM will modestly speed up the start of image generation.", begin_entry_at=0, editable=False, color="CONTROL", scroll_exit=True, ) self.nextrely -= 1 - self.max_vram_cache_size = self.add_widget_intelligent( + self.vram = self.add_widget_intelligent( npyscreen.Slider, - value=clip(old_opts.max_vram_cache_size, range=(0, MAX_VRAM), step=0.25), + value=clip(old_opts.vram_cache_size, range=(0, MAX_VRAM), step=0.25), out_of=round(MAX_VRAM * 2) / 2, lowest=0.0, relx=8, @@ -434,7 +496,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle. scroll_exit=True, ) else: - self.max_vram_cache_size = DummyWidgetValue.zero + self.vram_cache_size = DummyWidgetValue.zero self.nextrely += 1 self.outdir = self.add_widget_intelligent( FileBox, @@ -490,6 +552,11 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS when_pressed_function=self.on_ok, ) + def show_hide_slice_sizes(self, value): + show = ATTENTION_CHOICES[value[0]] == "sliced" + self.attention_slice_label.hidden = not show + self.attention_slice_size.hidden = not show + def on_ok(self): options = self.marshall_arguments() if self.validate_field_values(options): @@ -523,12 +590,9 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS new_opts = Namespace() for attr in [ + "ram", + "vram", "outdir", - "free_gpu_mem", - "max_cache_size", - "max_vram_cache_size", - "xformers_enabled", - "always_use_cpu", ]: setattr(new_opts, attr, getattr(self, attr).value) @@ -541,6 +605,12 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS new_opts.hf_token = self.hf_token.value new_opts.license_acceptance = self.license_acceptance.value new_opts.precision = PRECISION_CHOICES[self.precision.value[0]] + new_opts.device = DEVICE_CHOICES[self.device.value[0]] + new_opts.attention_type = ATTENTION_CHOICES[self.attention_type.value[0]] + new_opts.attention_slice_size = ATTENTION_SLICE_CHOICES[self.attention_slice_size.value[0]] + generation_options = [GENERATION_OPT_CHOICES[x] for x in self.generation_options.value] + for v in GENERATION_OPT_CHOICES: + setattr(new_opts, v, v in generation_options) return new_opts @@ -635,8 +705,6 @@ def initialize_rootdir(root: Path, yes_to_all: bool = False): path = dest / "core" path.mkdir(parents=True, exist_ok=True) - maybe_create_models_yaml(root) - def maybe_create_models_yaml(root: Path): models_yaml = root / "configs" / "models.yaml" diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index 1b10554e69..d87bc03fb7 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -341,7 +341,8 @@ class ModelManager(object): self.logger = logger self.cache = ModelCache( max_cache_size=max_cache_size, - max_vram_cache_size=self.app_config.max_vram_cache_size, + max_vram_cache_size=self.app_config.vram_cache_size, + lazy_offloading=self.app_config.lazy_offload, execution_device=device_type, precision=precision, sequential_offload=sequential_offload, diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py index 0180830b76..63b0c78b51 100644 --- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py +++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py @@ -33,7 +33,7 @@ from .diffusion import ( PostprocessingSettings, BasicConditioningInfo, ) -from ..util import normalize_device +from ..util import normalize_device, auto_detect_slice_size @dataclass @@ -291,6 +291,24 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline): if xformers is available, use it, otherwise use sliced attention. """ config = InvokeAIAppConfig.get_config() + if config.attention_type == "xformers": + self.enable_xformers_memory_efficient_attention() + return + elif config.attention_type == "sliced": + slice_size = config.attention_slice_size + if slice_size == "auto": + slice_size = auto_detect_slice_size(latents) + elif slice_size == "balanced": + slice_size = "auto" + self.enable_attention_slicing(slice_size=slice_size) + return + elif config.attention_type == "normal": + self.disable_attention_slicing() + return + elif config.attention_type == "torch-sdp": + raise Exception("torch-sdp attention slicing not yet implemented") + + # the remainder if this code is called when attention_type=='auto' if self.unet.device.type == "cuda": if is_xformers_available() and not config.disable_xformers: self.enable_xformers_memory_efficient_attention() diff --git a/invokeai/backend/util/__init__.py b/invokeai/backend/util/__init__.py index 30bb0efc15..b4e1c6e3a3 100644 --- a/invokeai/backend/util/__init__.py +++ b/invokeai/backend/util/__init__.py @@ -11,4 +11,11 @@ from .devices import ( # noqa: F401 torch_dtype, ) from .log import write_log # noqa: F401 -from .util import ask_user, download_with_resume, instantiate_from_config, url_attachment_name, Chdir # noqa: F401 +from .util import ( # noqa: F401 + ask_user, + download_with_resume, + instantiate_from_config, + url_attachment_name, + Chdir, +) +from .attention import auto_detect_slice_size # noqa: F401 diff --git a/invokeai/backend/util/attention.py b/invokeai/backend/util/attention.py new file mode 100644 index 0000000000..a821464394 --- /dev/null +++ b/invokeai/backend/util/attention.py @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Lincoln Stein and the InvokeAI Team +""" +Utility routine used for autodetection of optimal slice size +for attention mechanism. +""" +import torch +import psutil + + +def auto_detect_slice_size(latents: torch.Tensor) -> str: + bytes_per_element_needed_for_baddbmm_duplication = latents.element_size() + 4 + max_size_required_for_baddbmm = ( + 16 + * latents.size(dim=2) + * latents.size(dim=3) + * latents.size(dim=2) + * latents.size(dim=3) + * bytes_per_element_needed_for_baddbmm_duplication + ) + if latents.device.type in {"cpu", "mps"}: + mem_free = psutil.virtual_memory().free + elif latents.device.type == "cuda": + mem_free, _ = torch.cuda.mem_get_info(latents.device) + else: + raise ValueError(f"unrecognized device {latents.device}") + + if max_size_required_for_baddbmm > (mem_free * 3.0 / 4.0): + return "max" + elif torch.backends.mps.is_available(): + return "max" + else: + return "balanced" diff --git a/invokeai/backend/util/devices.py b/invokeai/backend/util/devices.py index 1827f295e4..bdaf3244f3 100644 --- a/invokeai/backend/util/devices.py +++ b/invokeai/backend/util/devices.py @@ -17,13 +17,17 @@ config = InvokeAIAppConfig.get_config() def choose_torch_device() -> torch.device: """Convenience routine for guessing which GPU device to run model on""" - if config.always_use_cpu: + if config.use_cpu: # legacy setting - force CPU return CPU_DEVICE - if torch.cuda.is_available(): - return torch.device("cuda") - if hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): - return torch.device("mps") - return CPU_DEVICE + elif config.device == "auto": + if torch.cuda.is_available(): + return torch.device("cuda") + if hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): + return torch.device("mps") + else: + return CPU_DEVICE + else: + return torch.device(config.device) def choose_precision(device: torch.device) -> str: diff --git a/invokeai/frontend/install/widgets.py b/invokeai/frontend/install/widgets.py index 79b6280990..9eefd93e09 100644 --- a/invokeai/frontend/install/widgets.py +++ b/invokeai/frontend/install/widgets.py @@ -17,8 +17,8 @@ from shutil import get_terminal_size from curses import BUTTON2_CLICKED, BUTTON3_CLICKED # minimum size for UIs -MIN_COLS = 130 -MIN_LINES = 38 +MIN_COLS = 150 +MIN_LINES = 40 class WindowTooSmallException(Exception): @@ -177,6 +177,8 @@ class FloatTitleSlider(npyscreen.TitleText): class SelectColumnBase: + """Base class for selection widget arranged in columns.""" + def make_contained_widgets(self): self._my_widgets = [] column_width = self.width // self.columns @@ -253,6 +255,7 @@ class MultiSelectColumns(SelectColumnBase, npyscreen.MultiSelect): class SingleSelectWithChanged(npyscreen.SelectOne): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.on_changed = None def h_select(self, ch): super().h_select(ch) @@ -260,7 +263,9 @@ class SingleSelectWithChanged(npyscreen.SelectOne): self.on_changed(self.value) -class SingleSelectColumns(SelectColumnBase, SingleSelectWithChanged): +class SingleSelectColumnsSimple(SelectColumnBase, SingleSelectWithChanged): + """Row of radio buttons. Spacebar to select.""" + def __init__(self, screen, columns: int = 1, values: list = [], **keywords): self.columns = columns self.value_cnt = len(values) @@ -268,15 +273,19 @@ class SingleSelectColumns(SelectColumnBase, SingleSelectWithChanged): self.on_changed = None super().__init__(screen, values=values, **keywords) - def when_value_edited(self): - self.h_select(self.cursor_line) + def h_cursor_line_right(self, ch): + self.h_exit_down("bye bye") + + def h_cursor_line_left(self, ch): + self.h_exit_up("bye bye") + + +class SingleSelectColumns(SingleSelectColumnsSimple): + """Row of radio buttons. When tabbing over a selection, it is auto selected.""" def when_cursor_moved(self): self.h_select(self.cursor_line) - def h_cursor_line_right(self, ch): - self.h_exit_down("bye bye") - class TextBoxInner(npyscreen.MultiLineEdit): def __init__(self, *args, **kwargs): @@ -324,55 +333,6 @@ class TextBoxInner(npyscreen.MultiLineEdit): if bstate & (BUTTON2_CLICKED | BUTTON3_CLICKED): self.h_paste() - # def update(self, clear=True): - # if clear: - # self.clear() - - # HEIGHT = self.height - # WIDTH = self.width - # # draw box. - # self.parent.curses_pad.hline(self.rely, self.relx, curses.ACS_HLINE, WIDTH) - # self.parent.curses_pad.hline( - # self.rely + HEIGHT, self.relx, curses.ACS_HLINE, WIDTH - # ) - # self.parent.curses_pad.vline( - # self.rely, self.relx, curses.ACS_VLINE, self.height - # ) - # self.parent.curses_pad.vline( - # self.rely, self.relx + WIDTH, curses.ACS_VLINE, HEIGHT - # ) - - # # draw corners - # self.parent.curses_pad.addch( - # self.rely, - # self.relx, - # curses.ACS_ULCORNER, - # ) - # self.parent.curses_pad.addch( - # self.rely, - # self.relx + WIDTH, - # curses.ACS_URCORNER, - # ) - # self.parent.curses_pad.addch( - # self.rely + HEIGHT, - # self.relx, - # curses.ACS_LLCORNER, - # ) - # self.parent.curses_pad.addch( - # self.rely + HEIGHT, - # self.relx + WIDTH, - # curses.ACS_LRCORNER, - # ) - - # # fool our superclass into thinking drawing area is smaller - this is really hacky but it seems to work - # (relx, rely, height, width) = (self.relx, self.rely, self.height, self.width) - # self.relx += 1 - # self.rely += 1 - # self.height -= 1 - # self.width -= 1 - # super().update(clear=False) - # (self.relx, self.rely, self.height, self.width) = (relx, rely, height, width) - class TextBox(npyscreen.BoxTitle): _contained_widget = TextBoxInner diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js index 7e4d5ead2b..c2b1433a9a 100644 --- a/invokeai/frontend/web/.eslintrc.js +++ b/invokeai/frontend/web/.eslintrc.js @@ -9,8 +9,8 @@ module.exports = { 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', - 'plugin:prettier/recommended', 'plugin:react/jsx-runtime', + 'prettier', ], parser: '@typescript-eslint/parser', parserOptions: { @@ -39,7 +39,6 @@ module.exports = { 'warn', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, ], - 'prettier/prettier': ['error', { endOfLine: 'auto' }], '@typescript-eslint/ban-ts-comment': 'warn', '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-empty-interface': [ diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index 2f60245768..e3f6dc48d7 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -29,12 +29,13 @@ "lint:eslint": "eslint --max-warnings=0 .", "lint:prettier": "prettier --check .", "lint:tsc": "tsc --noEmit", - "lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:tsc && yarn run lint:madge", + "lint": "concurrently -g -n eslint,prettier,tsc,madge -c cyan,green,magenta,yellow \"yarn run lint:eslint\" \"yarn run lint:prettier\" \"yarn run lint:tsc\" \"yarn run lint:madge\"", "fix": "eslint --fix . && prettier --loglevel warn --write . && tsc --noEmit", "lint-staged": "lint-staged", "postinstall": "patch-package && yarn run theme", "theme": "chakra-cli tokens src/theme/theme.ts", - "theme:watch": "chakra-cli tokens src/theme/theme.ts --watch" + "theme:watch": "chakra-cli tokens src/theme/theme.ts --watch", + "up": "yarn upgrade-interactive --latest" }, "madge": { "detectiveOptions": { @@ -54,7 +55,7 @@ }, "dependencies": { "@chakra-ui/anatomy": "^2.2.0", - "@chakra-ui/icons": "^2.0.19", + "@chakra-ui/icons": "^2.1.0", "@chakra-ui/react": "^2.8.0", "@chakra-ui/styled-system": "^2.9.1", "@chakra-ui/theme-tools": "^2.1.0", @@ -65,56 +66,55 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@floating-ui/react-dom": "^2.0.1", - "@fontsource-variable/inter": "^5.0.3", - "@fontsource/inter": "^5.0.3", - "@mantine/core": "^6.0.14", - "@mantine/form": "^6.0.15", - "@mantine/hooks": "^6.0.14", + "@fontsource-variable/inter": "^5.0.8", + "@fontsource/inter": "^5.0.8", + "@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", "dateformat": "^5.0.3", - "downshift": "^7.6.0", - "formik": "^2.4.2", - "framer-motion": "^10.12.17", + "formik": "^2.4.3", + "framer-motion": "^10.16.1", "fuse.js": "^6.6.2", - "i18next": "^23.2.3", + "i18next": "^23.4.4", "i18next-browser-languagedetector": "^7.0.2", "i18next-http-backend": "^2.2.1", "konva": "^9.2.0", "lodash-es": "^4.17.21", "nanostores": "^0.9.2", "new-github-issue-url": "^1.0.0", - "openapi-fetch": "^0.6.1", + "openapi-fetch": "^0.7.4", "overlayscrollbars": "^2.2.0", "overlayscrollbars-react": "^0.5.0", - "patch-package": "^7.0.0", + "patch-package": "^8.0.0", "query-string": "^8.1.0", - "re-resizable": "^6.9.9", "react": "^18.2.0", "react-colorful": "^5.6.1", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", "react-error-boundary": "^4.0.11", - "react-hotkeys-hook": "4.4.0", - "react-i18next": "^13.0.1", + "react-hotkeys-hook": "4.4.1", + "react-i18next": "^13.1.2", "react-icons": "^4.10.1", "react-konva": "^18.2.10", - "react-redux": "^8.1.1", - "react-resizable-panels": "^0.0.52", + "react-redux": "^8.1.2", + "react-resizable-panels": "^0.0.55", "react-use": "^17.4.0", - "react-virtuoso": "^4.3.11", + "react-virtuoso": "^4.5.0", "react-zoom-pan-pinch": "^3.0.8", - "reactflow": "^11.7.4", + "reactflow": "^11.8.3", "redux-dynamic-middlewares": "^2.2.0", - "redux-remember": "^3.3.1", - "roarr": "^7.15.0", - "serialize-error": "^11.0.0", - "socket.io-client": "^4.7.0", + "redux-remember": "^4.0.1", + "roarr": "^7.15.1", + "serialize-error": "^11.0.1", + "socket.io-client": "^4.7.2", "use-debounce": "^9.0.4", "use-image": "^1.1.1", "uuid": "^9.0.0", - "zod": "^3.21.4" + "zod": "^3.22.2", + "zod-validation-error": "^1.5.0" }, "peerDependencies": { "@chakra-ui/cli": "^2.4.0", @@ -127,38 +127,36 @@ "@chakra-ui/cli": "^2.4.1", "@types/dateformat": "^5.0.0", "@types/lodash-es": "^4.14.194", - "@types/node": "^20.3.1", - "@types/react": "^18.2.14", + "@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": "^5.60.0", - "@typescript-eslint/parser": "^5.60.0", + "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/parser": "^6.4.1", "@vitejs/plugin-react-swc": "^3.3.2", "axios": "^1.4.0", "babel-plugin-transform-imports": "^2.0.0", "concurrently": "^8.2.0", - "eslint": "^8.43.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.32.2", + "eslint": "^8.47.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "form-data": "^4.0.0", "husky": "^8.0.3", - "lint-staged": "^13.2.2", + "lint-staged": "^14.0.1", "madge": "^6.1.0", "openapi-types": "^12.1.3", - "openapi-typescript": "^6.2.8", - "openapi-typescript-codegen": "^0.24.0", + "openapi-typescript": "^6.5.2", "postinstall-postinstall": "^2.1.0", - "prettier": "^2.8.8", + "prettier": "^3.0.2", "rollup-plugin-visualizer": "^5.9.2", - "terser": "^5.18.1", "ts-toolbelt": "^9.6.0", - "vite": "^4.3.9", - "vite-plugin-css-injected-by-js": "^3.1.1", - "vite-plugin-dts": "^2.3.0", + "vite": "^4.4.9", + "vite-plugin-css-injected-by-js": "^3.3.0", + "vite-plugin-dts": "^3.5.2", "vite-plugin-eslint": "^1.8.1", "vite-tsconfig-paths": "^4.2.0", "yarn": "^1.22.19" diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index fca2a1a153..e39f438146 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -19,7 +19,7 @@ "toggleAutoscroll": "Toggle autoscroll", "toggleLogViewer": "Toggle Log Viewer", "showGallery": "Show Gallery", - "showOptionsPanel": "Show Options Panel", + "showOptionsPanel": "Show Side Panel", "menu": "Menu" }, "common": { @@ -95,7 +95,6 @@ "statusModelConverted": "Model Converted", "statusMergingModels": "Merging Models", "statusMergedModels": "Models Merged", - "pinOptionsPanel": "Pin Options Panel", "loading": "Loading", "loadingInvokeAI": "Loading Invoke AI", "random": "Random", @@ -116,7 +115,6 @@ "maintainAspectRatio": "Maintain Aspect Ratio", "autoSwitchNewImages": "Auto-Switch to New Images", "singleColumnLayout": "Single Column Layout", - "pinGallery": "Pin Gallery", "allImagesLoaded": "All Images Loaded", "loadMore": "Load More", "noImagesInGallery": "No Images to Display", @@ -511,12 +509,9 @@ "maskAdjustmentsHeader": "Mask Adjustments", "maskBlur": "Mask Blur", "maskBlurMethod": "Mask Blur Method", - "seamPaintingHeader": "Seam Painting", - "seamSize": "Seam Size", - "seamBlur": "Seam Blur", - "seamSteps": "Seam Steps", - "seamStrength": "Seam Strength", - "seamThreshold": "Seam Threshold", + "coherencePassHeader": "Coherence Pass", + "coherenceSteps": "Coherence Pass Steps", + "coherenceStrength": "Coherence Pass Strength", "seamLowThreshold": "Low", "seamHighThreshold": "High", "scaleBeforeProcessing": "Scale Before Processing", @@ -577,7 +572,7 @@ "resetWebUI": "Reset Web UI", "resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.", "resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.", - "resetComplete": "Web UI has been reset. Refresh the page to reload.", + "resetComplete": "Web UI has been reset.", "consoleLogLevel": "Log Level", "shouldLogToConsole": "Console Logging", "developer": "Developer", @@ -720,11 +715,12 @@ "swapSizes": "Swap Sizes" }, "nodes": { - "reloadSchema": "Reload Schema", - "saveGraph": "Save Graph", - "loadGraph": "Load Graph (saved from Node Editor) (Do not copy-paste metadata)", - "clearGraph": "Clear Graph", - "clearGraphDesc": "Are you sure you want to clear all nodes?", + "reloadNodeTemplates": "Reload Node Templates", + "saveWorkflow": "Save Workflow", + "loadWorkflow": "Load Workflow", + "resetWorkflow": "Reset Workflow", + "resetWorkflowDesc": "Are you sure you want to reset this workflow?", + "resetWorkflowDesc2": "Resetting the workflow will clear all nodes, edges and workflow details.", "zoomInNodes": "Zoom In", "zoomOutNodes": "Zoom Out", "fitViewportNodes": "Fit View", diff --git a/invokeai/frontend/web/scripts/typegen.js b/invokeai/frontend/web/scripts/typegen.js index 80302a9c99..485cf6cbc3 100644 --- a/invokeai/frontend/web/scripts/typegen.js +++ b/invokeai/frontend/web/scripts/typegen.js @@ -27,21 +27,10 @@ async function main() { * field accepts connection input. If it does, we can make the field optional. */ - // Check if we are generating types for an invocation - const isInvocationPath = metadata.path.match( - /^#\/components\/schemas\/\w*Invocation$/ - ); - - const hasInvocationProperties = - schemaObject.properties && - ['id', 'is_intermediate', 'type'].every( - (prop) => prop in schemaObject.properties - ); - - if (isInvocationPath && hasInvocationProperties) { + if ('class' in schemaObject && schemaObject.class === 'invocation') { // We only want to make fields optional if they are required if (!Array.isArray(schemaObject?.required)) { - schemaObject.required = ['id', 'type']; + schemaObject.required = []; } schemaObject.required.forEach((prop) => { @@ -60,32 +49,12 @@ async function main() { ); } }); - - schemaObject.required = [ - ...new Set(schemaObject.required.concat(['id', 'type'])), - ]; - return; } // Check if we are generating types for an invocation output - const isInvocationOutputPath = metadata.path.match( - /^#\/components\/schemas\/\w*Output$/ - ); - - const hasOutputProperties = - schemaObject.properties && 'type' in schemaObject.properties; - - if (isInvocationOutputPath && hasOutputProperties) { - if (!Array.isArray(schemaObject?.required)) { - schemaObject.required = ['type']; - } - schemaObject.required = [ - ...new Set(schemaObject.required.concat(['type'])), - ]; - console.log( - `Making output's "type" required: ${COLORS.fg.yellow}${schemaObject.title}${COLORS.reset}` - ); + if ('class' in schemaObject && schemaObject.class === 'output') { + // modify output types } }, }); diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index 8c7ce65ece..c2cc4645b8 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -1,4 +1,4 @@ -import { Flex, Grid, Portal } from '@chakra-ui/react'; +import { Flex, Grid } from '@chakra-ui/react'; import { useLogger } from 'app/logging/useLogger'; import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; @@ -6,21 +6,17 @@ import { PartialAppConfig } from 'app/types/invokeai'; import ImageUploader from 'common/components/ImageUploader'; import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal'; import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal'; -import GalleryDrawer from 'features/gallery/components/GalleryPanel'; import SiteHeader from 'features/system/components/SiteHeader'; import { configChanged } from 'features/system/store/configSlice'; import { languageSelector } from 'features/system/store/systemSelectors'; -import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton'; -import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons'; import InvokeTabs from 'features/ui/components/InvokeTabs'; -import ParametersDrawer from 'features/ui/components/ParametersDrawer'; import i18n from 'i18n'; import { size } from 'lodash-es'; import { ReactNode, memo, useCallback, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; +import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; import GlobalHotkeys from './GlobalHotkeys'; import Toaster from './Toaster'; -import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; const DEFAULT_CONFIG = {}; @@ -32,7 +28,7 @@ interface Props { const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => { const language = useAppSelector(languageSelector); - const logger = useLogger(); + const logger = useLogger('system'); const dispatch = useAppDispatch(); const handleReset = useCallback(() => { localStorage.clear(); @@ -46,7 +42,7 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => { useEffect(() => { if (size(config)) { - logger.info({ namespace: 'App', config }, 'Received config'); + logger.info({ config }, 'Received config'); dispatch(configChanged(config)); } }, [dispatch, config, logger]); @@ -83,15 +79,6 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => { - - - - - - - - - diff --git a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts index bbe77dc698..ac48fcc7b1 100644 --- a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts +++ b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts @@ -1,30 +1,21 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { ctrlKeyPressed, metaKeyPressed, shiftKeyPressed, } from 'features/ui/store/hotkeysSlice'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { - setActiveTab, - toggleGalleryPanel, - toggleParametersPanel, - togglePinGalleryPanel, - togglePinParametersPanel, -} from 'features/ui/store/uiSlice'; +import { setActiveTab } from 'features/ui/store/uiSlice'; import { isEqual } from 'lodash-es'; import React, { memo } from 'react'; import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook'; const globalHotkeysSelector = createSelector( [stateSelector], - ({ hotkeys, ui }) => { + ({ hotkeys }) => { const { shift, ctrl, meta } = hotkeys; - const { shouldPinParametersPanel, shouldPinGallery } = ui; - return { shift, ctrl, meta, shouldPinGallery, shouldPinParametersPanel }; + return { shift, ctrl, meta }; }, { memoizeOptions: { @@ -41,9 +32,7 @@ const globalHotkeysSelector = createSelector( */ const GlobalHotkeys: React.FC = () => { const dispatch = useAppDispatch(); - const { shift, ctrl, meta, shouldPinParametersPanel, shouldPinGallery } = - useAppSelector(globalHotkeysSelector); - const activeTabName = useAppSelector(activeTabNameSelector); + const { shift, ctrl, meta } = useAppSelector(globalHotkeysSelector); useHotkeys( '*', @@ -68,34 +57,6 @@ const GlobalHotkeys: React.FC = () => { [shift, ctrl, meta] ); - useHotkeys('o', () => { - dispatch(toggleParametersPanel()); - if (activeTabName === 'unifiedCanvas' && shouldPinParametersPanel) { - dispatch(requestCanvasRescale()); - } - }); - - useHotkeys(['shift+o'], () => { - dispatch(togglePinParametersPanel()); - if (activeTabName === 'unifiedCanvas') { - dispatch(requestCanvasRescale()); - } - }); - - useHotkeys('g', () => { - dispatch(toggleGalleryPanel()); - if (activeTabName === 'unifiedCanvas' && shouldPinGallery) { - dispatch(requestCanvasRescale()); - } - }); - - useHotkeys(['shift+g'], () => { - dispatch(togglePinGalleryPanel()); - if (activeTabName === 'unifiedCanvas') { - dispatch(requestCanvasRescale()); - } - }); - useHotkeys('1', () => { dispatch(setActiveTab('txt2img')); }); @@ -112,6 +73,10 @@ const GlobalHotkeys: React.FC = () => { dispatch(setActiveTab('nodes')); }); + useHotkeys('5', () => { + dispatch(setActiveTab('modelManager')); + }); + return null; }; diff --git a/invokeai/frontend/web/src/app/logging/logger.ts b/invokeai/frontend/web/src/app/logging/logger.ts index 7797b8dc92..2d7b8a7744 100644 --- a/invokeai/frontend/web/src/app/logging/logger.ts +++ b/invokeai/frontend/web/src/app/logging/logger.ts @@ -9,7 +9,7 @@ export const log = Roarr.child(BASE_CONTEXT); export const $logger = atom(Roarr.child(BASE_CONTEXT)); -type LoggerNamespace = +export type LoggerNamespace = | 'images' | 'models' | 'config' diff --git a/invokeai/frontend/web/src/app/logging/useLogger.ts b/invokeai/frontend/web/src/app/logging/useLogger.ts index 6c60bd4fd0..d31bcc2660 100644 --- a/invokeai/frontend/web/src/app/logging/useLogger.ts +++ b/invokeai/frontend/web/src/app/logging/useLogger.ts @@ -1,12 +1,17 @@ -import { useStore } from '@nanostores/react'; import { createSelector } from '@reduxjs/toolkit'; import { createLogWriter } from '@roarr/browser-log-writer'; import { useAppSelector } from 'app/store/storeHooks'; import { systemSelector } from 'features/system/store/systemSelectors'; import { isEqual } from 'lodash-es'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { ROARR, Roarr } from 'roarr'; -import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP } from './logger'; +import { + $logger, + BASE_CONTEXT, + LOG_LEVEL_MAP, + LoggerNamespace, + logger, +} from './logger'; const selector = createSelector( systemSelector, @@ -25,7 +30,7 @@ const selector = createSelector( } ); -export const useLogger = () => { +export const useLogger = (namespace: LoggerNamespace) => { const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector); // The provided Roarr browser log writer uses localStorage to config logging to console @@ -57,7 +62,7 @@ export const useLogger = () => { $logger.set(Roarr.child(newContext)); }, []); - const logger = useStore($logger); + const log = useMemo(() => logger(namespace), [namespace]); - return logger; + return log; }; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts index 32a6cce203..739bbd7110 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts @@ -5,6 +5,7 @@ import { modelsApi } from 'services/api/endpoints/models'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { appSocketConnected, socketConnected } from 'services/events/actions'; import { startAppListening } from '../..'; +import { size } from 'lodash-es'; export const addSocketConnectedEventListener = () => { startAppListening({ @@ -18,7 +19,7 @@ export const addSocketConnectedEventListener = () => { const { disabledTabs } = config; - if (!nodes.schema && !disabledTabs.includes('nodes')) { + if (!size(nodes.nodeTemplates) && !disabledTabs.includes('nodes')) { dispatch(receivedOpenAPISchema()); } diff --git a/invokeai/frontend/web/src/common/components/IAICollapse.tsx b/invokeai/frontend/web/src/common/components/IAICollapse.tsx index 0ce767ed9d..a5e08e6ddc 100644 --- a/invokeai/frontend/web/src/common/components/IAICollapse.tsx +++ b/invokeai/frontend/web/src/common/components/IAICollapse.tsx @@ -34,14 +34,10 @@ const IAICollapse = (props: IAIToggleCollapseProps) => { gap: 2, borderTopRadius: 'base', borderBottomRadius: isOpen ? 0 : 'base', - bg: isOpen - ? mode('base.200', 'base.750')(colorMode) - : mode('base.150', 'base.800')(colorMode), + bg: mode('base.250', 'base.750')(colorMode), color: mode('base.900', 'base.100')(colorMode), _hover: { - bg: isOpen - ? mode('base.250', 'base.700')(colorMode) - : mode('base.200', 'base.750')(colorMode), + bg: mode('base.300', 'base.700')(colorMode), }, fontSize: 'sm', fontWeight: 600, @@ -90,9 +86,10 @@ const IAICollapse = (props: IAIToggleCollapseProps) => { { ? {} : { cursor: 'pointer', - bg: mode('base.200', 'base.800')(colorMode), + bg: mode('base.200', 'base.700')(colorMode), _hover: { bg: mode('base.300', 'base.650')(colorMode), color: mode('base.500', 'base.300')(colorMode), diff --git a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts index ac770e3787..e06a1106c1 100644 --- a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts +++ b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts @@ -32,6 +32,10 @@ const selector = createSelector( } if (activeTabName === 'nodes' && nodes.shouldValidateGraph) { + if (!nodes.nodes.length) { + reasons.push('No nodes in graph'); + } + nodes.nodes.forEach((node) => { if (!isInvocationNode(node)) { return; diff --git a/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts b/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts new file mode 100644 index 0000000000..e29005186f --- /dev/null +++ b/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts @@ -0,0 +1,2 @@ +export const colorTokenToCssVar = (colorToken: string) => + `var(--invokeai-colors-${colorToken.split('.').join('-')}`; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx index 82d49625fa..4f9e47282d 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx @@ -1,6 +1,6 @@ import { Box, chakra, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/store/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { canvasSelector, @@ -9,7 +9,7 @@ import { import Konva from 'konva'; import { KonvaEventObject } from 'konva/lib/Node'; import { Vector2d } from 'konva/lib/types'; -import { memo, useCallback, useRef } from 'react'; +import { memo, useCallback, useEffect, useRef } from 'react'; import { Layer, Stage } from 'react-konva'; import useCanvasDragMove from '../hooks/useCanvasDragMove'; import useCanvasHotkeys from '../hooks/useCanvasHotkeys'; @@ -18,6 +18,7 @@ import useCanvasMouseMove from '../hooks/useCanvasMouseMove'; import useCanvasMouseOut from '../hooks/useCanvasMouseOut'; import useCanvasMouseUp from '../hooks/useCanvasMouseUp'; import useCanvasWheel from '../hooks/useCanvasZoom'; +import { canvasResized } from '../store/canvasSlice'; import { setCanvasBaseLayer, setCanvasStage, @@ -106,7 +107,8 @@ const IAICanvas = () => { shouldAntialias, } = useAppSelector(selector); useCanvasHotkeys(); - + const dispatch = useAppDispatch(); + const containerRef = useRef(null); const stageRef = useRef(null); const canvasBaseLayerRef = useRef(null); @@ -137,8 +139,30 @@ const IAICanvas = () => { const { handleDragStart, handleDragMove, handleDragEnd } = useCanvasDragMove(); + useEffect(() => { + if (!containerRef.current) { + return; + } + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + if (entry.contentBoxSize) { + const { width, height } = entry.contentRect; + dispatch(canvasResized({ width, height })); + } + } + }); + + resizeObserver.observe(containerRef.current); + + return () => { + resizeObserver.disconnect(); + }; + }, [dispatch]); + return ( { borderRadius: 'base', }} > - + { /> - - + + ); }; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx deleted file mode 100644 index e0d8776d8c..0000000000 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Flex, Spinner } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { - canvasSelector, - initialCanvasImageSelector, -} from 'features/canvas/store/canvasSelectors'; -import { - resizeAndScaleCanvas, - resizeCanvas, - setCanvasContainerDimensions, - setDoesCanvasNeedScaling, -} from 'features/canvas/store/canvasSlice'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { memo, useLayoutEffect, useRef } from 'react'; - -const canvasResizerSelector = createSelector( - canvasSelector, - initialCanvasImageSelector, - activeTabNameSelector, - (canvas, initialCanvasImage, activeTabName) => { - const { doesCanvasNeedScaling, isCanvasInitialized } = canvas; - return { - doesCanvasNeedScaling, - activeTabName, - initialCanvasImage, - isCanvasInitialized, - }; - } -); - -const IAICanvasResizer = () => { - const dispatch = useAppDispatch(); - const { - doesCanvasNeedScaling, - activeTabName, - initialCanvasImage, - isCanvasInitialized, - } = useAppSelector(canvasResizerSelector); - - const ref = useRef(null); - - useLayoutEffect(() => { - window.setTimeout(() => { - if (!ref.current) { - return; - } - - const { clientWidth, clientHeight } = ref.current; - - dispatch( - setCanvasContainerDimensions({ - width: clientWidth, - height: clientHeight, - }) - ); - - if (!isCanvasInitialized) { - dispatch(resizeAndScaleCanvas()); - } else { - dispatch(resizeCanvas()); - } - - dispatch(setDoesCanvasNeedScaling(false)); - }, 0); - }, [ - dispatch, - initialCanvasImage, - doesCanvasNeedScaling, - activeTabName, - isCanvasInitialized, - ]); - - return ( - - - - ); -}; - -export default memo(IAICanvasResizer); diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx index 2065e16668..cc15141d38 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx @@ -140,11 +140,10 @@ const IAICanvasStagingAreaToolbar = () => { w="100%" align="center" justify="center" - filter="drop-shadow(0 0.5rem 1rem rgba(0,0,0))" onMouseOver={handleMouseOver} onMouseOut={handleMouseOut} > - + { const handleResetCanvas = () => { dispatch(resetCanvas()); - dispatch(resizeAndScaleCanvas()); }; const handleMergeVisible = () => { diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts index dc0df55ad0..1990f28516 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts @@ -3,8 +3,4 @@ import { CanvasState } from './canvasTypes'; /** * Canvas slice persist denylist */ -export const canvasPersistDenylist: (keyof CanvasState)[] = [ - 'cursorPosition', - 'isCanvasInitialized', - 'doesCanvasNeedScaling', -]; +export const canvasPersistDenylist: (keyof CanvasState)[] = ['cursorPosition']; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index 83341d017e..ca26a0567f 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -5,10 +5,6 @@ import { roundToMultiple, } from 'common/util/roundDownToMultiple'; import { setAspectRatio } from 'features/parameters/store/generationSlice'; -import { - setActiveTab, - setShouldUseCanvasBetaLayout, -} from 'features/ui/store/uiSlice'; import { IRect, Vector2d } from 'konva/lib/types'; import { clamp, cloneDeep } from 'lodash-es'; import { RgbaColor } from 'react-colorful'; @@ -50,12 +46,9 @@ export const initialCanvasState: CanvasState = { boundingBoxScaleMethod: 'none', brushColor: { r: 90, g: 90, b: 255, a: 1 }, brushSize: 50, - canvasContainerDimensions: { width: 0, height: 0 }, colorPickerColor: { r: 90, g: 90, b: 255, a: 1 }, cursorPosition: null, - doesCanvasNeedScaling: false, futureLayerStates: [], - isCanvasInitialized: false, isDrawing: false, isMaskEnabled: true, isMouseOverBoundingBox: false, @@ -208,7 +201,6 @@ export const canvasSlice = createSlice({ }; state.futureLayerStates = []; - state.isCanvasInitialized = false; const newScale = calculateScale( stageDimensions.width, stageDimensions.height, @@ -228,7 +220,6 @@ export const canvasSlice = createSlice({ ); state.stageScale = newScale; state.stageCoordinates = newCoordinates; - state.doesCanvasNeedScaling = true; }, setBoundingBoxDimensions: (state, action: PayloadAction) => { const newDimensions = roundDimensionsTo64(action.payload); @@ -258,9 +249,6 @@ export const canvasSlice = createSlice({ setBoundingBoxPreviewFill: (state, action: PayloadAction) => { state.boundingBoxPreviewFill = action.payload; }, - setDoesCanvasNeedScaling: (state, action: PayloadAction) => { - state.doesCanvasNeedScaling = action.payload; - }, setStageScale: (state, action: PayloadAction) => { state.stageScale = action.payload; }, @@ -493,97 +481,14 @@ export const canvasSlice = createSlice({ state.layerState = initialLayerState; state.futureLayerStates = []; }, - setCanvasContainerDimensions: ( + canvasResized: ( state, - action: PayloadAction + action: PayloadAction<{ width: number; height: number }> ) => { - state.canvasContainerDimensions = action.payload; - }, - resizeAndScaleCanvas: (state) => { - const { width: containerWidth, height: containerHeight } = - state.canvasContainerDimensions; - - const initialCanvasImage = - state.layerState.objects.find(isCanvasBaseImage); - + const { width, height } = action.payload; const newStageDimensions = { - width: Math.floor(containerWidth), - height: Math.floor(containerHeight), - }; - - if (!initialCanvasImage) { - const newScale = calculateScale( - newStageDimensions.width, - newStageDimensions.height, - 512, - 512, - STAGE_PADDING_PERCENTAGE - ); - - const newCoordinates = calculateCoordinates( - newStageDimensions.width, - newStageDimensions.height, - 0, - 0, - 512, - 512, - newScale - ); - - const newBoundingBoxDimensions = { width: 512, height: 512 }; - - state.stageScale = newScale; - state.stageCoordinates = newCoordinates; - state.stageDimensions = newStageDimensions; - state.boundingBoxCoordinates = { x: 0, y: 0 }; - state.boundingBoxDimensions = newBoundingBoxDimensions; - - if (state.boundingBoxScaleMethod === 'auto') { - const scaledDimensions = getScaledBoundingBoxDimensions( - newBoundingBoxDimensions - ); - state.scaledBoundingBoxDimensions = scaledDimensions; - } - - return; - } - - const { width: imageWidth, height: imageHeight } = initialCanvasImage; - - const padding = 0.95; - - const newScale = calculateScale( - containerWidth, - containerHeight, - imageWidth, - imageHeight, - padding - ); - - const newCoordinates = calculateCoordinates( - newStageDimensions.width, - newStageDimensions.height, - 0, - 0, - imageWidth, - imageHeight, - newScale - ); - - state.minimumStageScale = newScale; - state.stageScale = newScale; - state.stageCoordinates = floorCoordinates(newCoordinates); - state.stageDimensions = newStageDimensions; - - state.isCanvasInitialized = true; - }, - resizeCanvas: (state) => { - const { width: containerWidth, height: containerHeight } = - state.canvasContainerDimensions; - - const newStageDimensions = { - width: Math.floor(containerWidth), - height: Math.floor(containerHeight), + width: Math.floor(width), + height: Math.floor(height), }; state.stageDimensions = newStageDimensions; @@ -876,14 +781,6 @@ export const canvasSlice = createSlice({ state.layerState.stagingArea = initialLayerState.stagingArea; } }); - - builder.addCase(setShouldUseCanvasBetaLayout, (state) => { - state.doesCanvasNeedScaling = true; - }); - - builder.addCase(setActiveTab, (state) => { - state.doesCanvasNeedScaling = true; - }); builder.addCase(setAspectRatio, (state, action) => { const ratio = action.payload; if (ratio) { @@ -915,8 +812,6 @@ export const { resetCanvas, resetCanvasInteractionState, resetCanvasView, - resizeAndScaleCanvas, - resizeCanvas, setBoundingBoxCoordinates, setBoundingBoxDimensions, setBoundingBoxPreviewFill, @@ -924,10 +819,8 @@ export const { flipBoundingBoxAxes, setBrushColor, setBrushSize, - setCanvasContainerDimensions, setColorPickerColor, setCursorPosition, - setDoesCanvasNeedScaling, setInitialCanvasImage, setIsDrawing, setIsMaskEnabled, @@ -966,6 +859,7 @@ export const { stagingAreaInitialized, canvasSessionIdChanged, setShouldAntialias, + canvasResized, } = canvasSlice.actions; export default canvasSlice.reducer; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts index f2ba90b050..1b4eca329d 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts @@ -126,12 +126,9 @@ export interface CanvasState { boundingBoxScaleMethod: BoundingBoxScale; brushColor: RgbaColor; brushSize: number; - canvasContainerDimensions: Dimensions; colorPickerColor: RgbaColor; cursorPosition: Vector2d | null; - doesCanvasNeedScaling: boolean; futureLayerStates: CanvasLayerState[]; - isCanvasInitialized: boolean; isDrawing: boolean; isMaskEnabled: boolean; isMouseOverBoundingBox: boolean; diff --git a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts b/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts deleted file mode 100644 index f16c92651a..0000000000 --- a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AppDispatch, AppGetState } from 'app/store/store'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { debounce } from 'lodash-es'; -import { setDoesCanvasNeedScaling } from '../canvasSlice'; - -const debouncedCanvasScale = debounce((dispatch: AppDispatch) => { - dispatch(setDoesCanvasNeedScaling(true)); -}, 300); - -export const requestCanvasRescale = - () => (dispatch: AppDispatch, getState: AppGetState) => { - const activeTabName = activeTabNameSelector(getState()); - if (activeTabName === 'unifiedCanvas') { - debouncedCanvasScale(dispatch); - } - }; diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx index 6a49fd9727..de9995c577 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx @@ -80,12 +80,12 @@ const ControlNet = (props: ControlNetProps) => { sx={{ flexDir: 'column', gap: 3, - p: 3, + p: 2, borderRadius: 'base', position: 'relative', - bg: 'base.200', + bg: 'base.250', _dark: { - bg: 'base.850', + bg: 'base.750', }, }} > @@ -194,7 +194,7 @@ const ControlNet = (props: ControlNetProps) => { aspectRatio: '1/1', }} > - + )} @@ -207,7 +207,7 @@ const ControlNet = (props: ControlNetProps) => { {isExpanded && ( <> - + diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx index 0683282811..3b92d9d0c6 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx @@ -1,14 +1,14 @@ -import { Box, Flex, Spinner, SystemStyleObject } from '@chakra-ui/react'; +import { Box, Flex, Spinner } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { skipToken } from '@reduxjs/toolkit/dist/query'; -import { - TypesafeDraggableData, - TypesafeDroppableData, -} from 'features/dnd/types'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAIDndImage from 'common/components/IAIDndImage'; +import { + TypesafeDraggableData, + TypesafeDroppableData, +} from 'features/dnd/types'; import { memo, useCallback, useMemo, useState } from 'react'; import { FaUndo } from 'react-icons/fa'; import { useGetImageDTOQuery } from 'services/api/endpoints/images'; @@ -21,7 +21,7 @@ import { type Props = { controlNet: ControlNetConfig; - height: SystemStyleObject['h']; + isSmall?: boolean; }; const selector = createSelector( @@ -36,15 +36,14 @@ const selector = createSelector( defaultSelectorOptions ); -const ControlNetImagePreview = (props: Props) => { - const { height } = props; +const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => { const { controlImage: controlImageName, processedControlImage: processedControlImageName, processorType, isEnabled, controlNetId, - } = props.controlNet; + } = controlNet; const dispatch = useAppDispatch(); @@ -109,7 +108,7 @@ const ControlNetImagePreview = (props: Props) => { sx={{ position: 'relative', w: 'full', - h: height, + h: isSmall ? 28 : 366, // magic no touch alignItems: 'center', justifyContent: 'center', pointerEvents: isEnabled ? 'auto' : 'none', diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx deleted file mode 100644 index 1bbec03f3e..0000000000 --- a/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { gallerySelector } from 'features/gallery/store/gallerySelectors'; -import { setGalleryImageMinimumWidth } from 'features/gallery/store/gallerySlice'; - -import { clamp, isEqual } from 'lodash-es'; -import { useHotkeys } from 'react-hotkeys-hook'; - -import { createSelector } from '@reduxjs/toolkit'; -import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; -import ResizableDrawer from 'features/ui/components/common/ResizableDrawer/ResizableDrawer'; -import { - activeTabNameSelector, - uiSelector, -} from 'features/ui/store/uiSelectors'; -import { setShouldShowGallery } from 'features/ui/store/uiSlice'; -import { memo } from 'react'; -import ImageGalleryContent from './ImageGalleryContent'; - -const selector = createSelector( - [activeTabNameSelector, uiSelector, gallerySelector, isStagingSelector], - (activeTabName, ui, gallery, isStaging) => { - const { shouldPinGallery, shouldShowGallery } = ui; - const { galleryImageMinimumWidth } = gallery; - - return { - activeTabName, - isStaging, - shouldPinGallery, - shouldShowGallery, - galleryImageMinimumWidth, - isResizable: activeTabName !== 'unifiedCanvas', - }; - }, - { - memoizeOptions: { - resultEqualityCheck: isEqual, - }, - } -); - -const GalleryDrawer = () => { - const dispatch = useAppDispatch(); - const { - shouldPinGallery, - shouldShowGallery, - galleryImageMinimumWidth, - // activeTabName, - // isStaging, - // isResizable, - } = useAppSelector(selector); - - const handleCloseGallery = () => { - dispatch(setShouldShowGallery(false)); - shouldPinGallery && dispatch(requestCanvasRescale()); - }; - - useHotkeys( - 'esc', - () => { - dispatch(setShouldShowGallery(false)); - }, - { - enabled: () => !shouldPinGallery, - preventDefault: true, - }, - [shouldPinGallery] - ); - - const IMAGE_SIZE_STEP = 32; - - useHotkeys( - 'shift+up', - () => { - if (galleryImageMinimumWidth < 256) { - const newMinWidth = clamp( - galleryImageMinimumWidth + IMAGE_SIZE_STEP, - 32, - 256 - ); - dispatch(setGalleryImageMinimumWidth(newMinWidth)); - } - }, - [galleryImageMinimumWidth] - ); - - useHotkeys( - 'shift+down', - () => { - if (galleryImageMinimumWidth > 32) { - const newMinWidth = clamp( - galleryImageMinimumWidth - IMAGE_SIZE_STEP, - 32, - 256 - ); - dispatch(setGalleryImageMinimumWidth(newMinWidth)); - } - }, - [galleryImageMinimumWidth] - ); - - if (shouldPinGallery) { - return null; - } - - return ( - - - - ); -}; - -export default memo(GalleryDrawer); diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx deleted file mode 100644 index f1895c4d6f..0000000000 --- a/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx +++ /dev/null @@ -1,45 +0,0 @@ -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 IAIIconButton from 'common/components/IAIIconButton'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; -import { togglePinGalleryPanel } from 'features/ui/store/uiSlice'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; - -const selector = createSelector( - [stateSelector], - (state) => { - const { shouldPinGallery } = state.ui; - - return { - shouldPinGallery, - }; - }, - defaultSelectorOptions -); - -const GalleryPinButton = () => { - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - - const { shouldPinGallery } = useAppSelector(selector); - - const handleSetShouldPinGallery = () => { - dispatch(togglePinGalleryPanel()); - dispatch(requestCanvasRescale()); - }; - return ( - : } - /> - ); -}; - -export default memo(GalleryPinButton); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 3a793d2775..76eee18d72 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -1,11 +1,8 @@ -import { MenuItem } from '@chakra-ui/react'; +import { Flex, MenuItem, Text } from '@chakra-ui/react'; import { skipToken } from '@reduxjs/toolkit/dist/query'; import { useAppToaster } from 'app/components/Toaster'; import { useAppDispatch } from 'app/store/storeHooks'; -import { - resizeAndScaleCanvas, - setInitialCanvasImage, -} from 'features/canvas/store/canvasSlice'; +import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { imagesToChangeSelected, isModalOpenChanged, @@ -29,6 +26,7 @@ import { FaShare, FaTrash, } from 'react-icons/fa'; +import { MdStar, MdStarBorder } from 'react-icons/md'; import { useGetImageMetadataQuery, useStarImagesMutation, @@ -37,7 +35,6 @@ import { import { ImageDTO } from 'services/api/types'; import { useDebounce } from 'use-debounce'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; -import { MdStar, MdStarBorder } from 'react-icons/md'; type SingleSelectionMenuItemsProps = { imageDTO: ImageDTO; @@ -110,7 +107,6 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const handleSendToCanvas = useCallback(() => { dispatch(sentImageToCanvas()); dispatch(setInitialCanvasImage(imageDTO)); - dispatch(resizeAndScaleCanvas()); dispatch(setActiveTab('unifiedCanvas')); toaster({ @@ -232,6 +228,18 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { > {t('gallery.deleteImage')} + {metadata?.created_by && ( + + + Created by {metadata?.created_by} + + + )} ); }; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx index 804df49b8e..6c34029490 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx @@ -18,7 +18,6 @@ import { FaImages, FaServer } from 'react-icons/fa'; import { galleryViewChanged } from '../store/gallerySlice'; import BoardsList from './Boards/BoardsList/BoardsList'; import GalleryBoardName from './GalleryBoardName'; -import GalleryPinButton from './GalleryPinButton'; import GallerySettingsPopover from './GallerySettingsPopover'; import GalleryImageGrid from './ImageGrid/GalleryImageGrid'; @@ -75,7 +74,6 @@ const ImageGalleryContent = () => { onToggle={onToggleBoardList} /> - diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx index a98124bb89..87c0957354 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx @@ -8,10 +8,12 @@ type Props = { label: string; data: object | string; fileName?: string; + withDownload?: boolean; + withCopy?: boolean; }; const DataViewer = (props: Props) => { - const { label, data, fileName } = props; + const { label, data, fileName, withDownload = true, withCopy = true } = props; const dataString = useMemo( () => (isString(data) ? data : JSON.stringify(data, null, 2)), [data] @@ -70,24 +72,28 @@ const DataViewer = (props: Props) => { - - } - variant="ghost" - opacity={0.7} - onClick={handleSave} - /> - - - } - variant="ghost" - opacity={0.7} - onClick={handleCopy} - /> - + {withDownload && ( + + } + variant="ghost" + opacity={0.7} + onClick={handleSave} + /> + + )} + {withCopy && ( + + } + variant="ghost" + opacity={0.7} + onClick={handleCopy} + /> + + )} ); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx index ee5b342d4e..c3e5d763a4 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx @@ -69,6 +69,9 @@ const ImageMetadataActions = (props: Props) => { return ( <> + {metadata.created_by && ( + + )} {metadata.generation_mode && ( { - const [isPanelCollapsed, setIsPanelCollapsed] = useState(false); const isReady = useAppSelector((state) => state.nodes.isReady); return ( - - - - - - - - - {isReady && ( - - - - - )} - - - {!isReady && ( - - - - - - )} - - - - + + {isReady && ( + + + + + + + + + + )} + + + {!isReady && ( + + + + + + )} + + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx index 05aa60c1ba..83f7482177 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx @@ -140,7 +140,7 @@ const AddNodePopover = () => { onClose(); }, [onClose]); - useHotkeys(['space', '/'], handleHotkeyOpen); + useHotkeys(['shift+a', 'space'], handleHotkeyOpen); useHotkeys(['escape'], handleHotkeyClose); return ( diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx index 817ef4ff3d..e8fb66d074 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx @@ -1,5 +1,8 @@ import { useToken } from '@chakra-ui/react'; +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 { contextMenusClosed } from 'features/ui/store/uiSlice'; import { useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -39,11 +42,6 @@ import InvocationDefaultEdge from './edges/InvocationDefaultEdge'; import CurrentImageNode from './nodes/CurrentImage/CurrentImageNode'; import InvocationNodeWrapper from './nodes/Invocation/InvocationNodeWrapper'; import NotesNode from './nodes/Notes/NotesNode'; -import BottomLeftPanel from './panels/BottomLeftPanel/BottomLeftPanel'; -import MinimapPanel from './panels/MinimapPanel/MinimapPanel'; -import TopCenterPanel from './panels/TopCenterPanel/TopCenterPanel'; -import TopLeftPanel from './panels/TopLeftPanel/TopLeftPanel'; -import TopRightPanel from './panels/TopRightPanel/TopRightPanel'; const DELETE_KEYS = ['Delete', 'Backspace']; @@ -61,14 +59,24 @@ const nodeTypes = { // TODO: can we support reactflow? if not, we could style the attribution so it matches the app const proOptions: ProOptions = { hideAttribution: true }; +const selector = createSelector( + stateSelector, + ({ nodes }) => { + const { shouldSnapToGrid, selectionMode } = nodes; + return { + shouldSnapToGrid, + selectionMode, + }; + }, + defaultSelectorOptions +); + export const Flow = () => { const dispatch = useAppDispatch(); const nodes = useAppSelector((state) => state.nodes.nodes); const edges = useAppSelector((state) => state.nodes.edges); const viewport = useAppSelector((state) => state.nodes.viewport); - const shouldSnapToGrid = useAppSelector( - (state) => state.nodes.shouldSnapToGrid - ); + const { shouldSnapToGrid, selectionMode } = useAppSelector(selector); const isValidConnection = useIsValidConnection(); @@ -181,12 +189,8 @@ export const Flow = () => { style={{ borderRadius }} onPaneClick={handlePaneClick} deleteKeyCode={DELETE_KEYS} + selectionMode={selectionMode} > - - - - - ); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx index ad8ba3dc62..a379be7ee2 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx @@ -1,9 +1,10 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppSelector } from 'app/store/storeHooks'; -import { ConnectionLineComponentProps, getBezierPath } from 'reactflow'; -import { FIELDS, colorTokenToCssVar } from '../../../types/constants'; +import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar'; +import { FIELDS } from 'features/nodes/types/constants'; import { memo } from 'react'; +import { ConnectionLineComponentProps, getBezierPath } from 'reactflow'; const selector = createSelector(stateSelector, ({ nodes }) => { const { shouldAnimateEdges, currentConnectionFieldType, shouldColorEdges } = diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts index ed692042c6..b5dc484eae 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts +++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts @@ -1,7 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; -import { FIELDS, colorTokenToCssVar } from 'features/nodes/types/constants'; +import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar'; +import { FIELDS } from 'features/nodes/types/constants'; import { isInvocationNode } from 'features/nodes/types/types'; export const makeEdgeSelector = ( diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx index 624578003e..8f6a2531a0 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx @@ -1,12 +1,14 @@ -import { Flex } from '@chakra-ui/react'; +import { Flex, Grid, GridItem } from '@chakra-ui/react'; import { memo } from 'react'; import InvocationNodeFooter from './InvocationNodeFooter'; import InvocationNodeHeader from './InvocationNodeHeader'; import NodeWrapper from '../common/NodeWrapper'; import OutputField from './fields/OutputField'; import InputField from './fields/InputField'; -import { useFieldNames } from 'features/nodes/hooks/useFieldNames'; +import { useOutputFieldNames } from 'features/nodes/hooks/useOutputFieldNames'; import { useWithFooter } from 'features/nodes/hooks/useWithFooter'; +import { useConnectionInputFieldNames } from 'features/nodes/hooks/useConnectionInputFieldNames'; +import { useAnyOrDirectInputFieldNames } from 'features/nodes/hooks/useAnyOrDirectInputFieldNames'; type Props = { nodeId: string; @@ -17,8 +19,9 @@ type Props = { }; const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => { - const inputFieldNames = useFieldNames(nodeId, 'input'); - const outputFieldNames = useFieldNames(nodeId, 'output'); + const inputConnectionFieldNames = useConnectionInputFieldNames(nodeId); + const inputAnyOrDirectFieldNames = useAnyOrDirectInputFieldNames(nodeId); + const outputFieldNames = useOutputFieldNames(nodeId); const withFooter = useWithFooter(nodeId); return ( @@ -44,14 +47,27 @@ const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => { }} > - {outputFieldNames.map((fieldName) => ( - - ))} - {inputFieldNames.map((fieldName) => ( + + {inputConnectionFieldNames.map((fieldName, i) => ( + + + + ))} + {outputFieldNames.map((fieldName, i) => ( + + + + ))} + + {inputAnyOrDirectFieldNames.map((fieldName) => ( { const handleSubmit = useCallback( async (newTitle: string) => { - if (newTitle === label || newTitle === fieldTemplateTitle) { + if (newTitle && (newTitle === label || newTitle === fieldTemplateTitle)) { return; } setLocalTitle(newTitle || fieldTemplateTitle || 'Unknown Field'); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx index 7c88318fa1..e717423f65 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx @@ -1,10 +1,4 @@ -import { - Flex, - FormControl, - FormLabel, - Spacer, - Tooltip, -} from '@chakra-ui/react'; +import { Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react'; import { useConnectionState } from 'features/nodes/hooks/useConnectionState'; import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate'; import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants'; @@ -42,7 +36,6 @@ const OutputField = ({ nodeId, fieldName }: Props) => { return ( - {children} diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/common/NodeWrapper.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/common/NodeWrapper.tsx index 327c01a806..e3dacdbf97 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/common/NodeWrapper.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/common/NodeWrapper.tsx @@ -4,13 +4,16 @@ import { useColorModeValue, useToken, } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { DRAG_HANDLE_CLASSNAME, NODE_WIDTH, } from 'features/nodes/types/constants'; +import { NodeStatus } from 'features/nodes/types/types'; import { contextMenusClosed } from 'features/ui/store/uiSlice'; -import { PropsWithChildren, memo, useCallback } from 'react'; +import { PropsWithChildren, memo, useCallback, useMemo } from 'react'; type NodeWrapperProps = PropsWithChildren & { nodeId: string; @@ -19,25 +22,42 @@ type NodeWrapperProps = PropsWithChildren & { }; const NodeWrapper = (props: NodeWrapperProps) => { - const { width, children, selected } = props; + const { nodeId, width, children, selected } = props; + + const selectIsInProgress = useMemo( + () => + createSelector( + stateSelector, + ({ nodes }) => + nodes.nodeExecutionStates[nodeId]?.status === NodeStatus.IN_PROGRESS + ), + [nodeId] + ); + + const isInProgress = useAppSelector(selectIsInProgress); const [ - nodeSelectedOutlineLight, - nodeSelectedOutlineDark, + nodeSelectedLight, + nodeSelectedDark, + nodeInProgressLight, + nodeInProgressDark, shadowsXl, shadowsBase, ] = useToken('shadows', [ - 'nodeSelectedOutline.light', - 'nodeSelectedOutline.dark', + 'nodeSelected.light', + 'nodeSelected.dark', + 'nodeInProgress.light', + 'nodeInProgress.dark', 'shadows.xl', 'shadows.base', ]); const dispatch = useAppDispatch(); - const shadow = useColorModeValue( - nodeSelectedOutlineLight, - nodeSelectedOutlineDark + const selectedShadow = useColorModeValue(nodeSelectedLight, nodeSelectedDark); + const inProgressShadow = useColorModeValue( + nodeInProgressLight, + nodeInProgressDark ); const opacity = useAppSelector((state) => state.nodes.nodeOpacity); @@ -57,7 +77,11 @@ const NodeWrapper = (props: NodeWrapperProps) => { w: width ?? NODE_WIDTH, transitionProperty: 'common', transitionDuration: '0.1s', - shadow: selected ? shadow : undefined, + shadow: selected + ? isInProgress + ? undefined + : selectedShadow + : undefined, cursor: 'grab', opacity, }} @@ -75,6 +99,22 @@ const NodeWrapper = (props: NodeWrapperProps) => { zIndex: -1, }} /> + {children} ); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx index eccc4409af..c59557f1a0 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx @@ -1,16 +1,13 @@ -import { memo } from 'react'; -import { Panel } from 'reactflow'; -import ViewportControls from './ViewportControls'; -import NodeOpacitySlider from './NodeOpacitySlider'; import { Flex } from '@chakra-ui/react'; +import { memo } from 'react'; +import NodeOpacitySlider from './NodeOpacitySlider'; +import ViewportControls from './ViewportControls'; const BottomLeftPanel = () => ( - - - - - - + + + + ); export default memo(BottomLeftPanel); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx index 260655723e..15d8d58d7b 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx @@ -1,20 +1,19 @@ -import { ButtonGroup, Tooltip } from '@chakra-ui/react'; +import { ButtonGroup } from '@chakra-ui/react'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; +import { + // shouldShowFieldTypeLegendChanged, + shouldShowMinimapPanelChanged, +} from 'features/nodes/store/nodesSlice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { FaExpand, // FaInfo, FaMapMarkerAlt, - FaMinus, - FaPlus, } from 'react-icons/fa'; +import { FaMagnifyingGlassMinus, FaMagnifyingGlassPlus } from 'react-icons/fa6'; import { useReactFlow } from 'reactflow'; -import { - // shouldShowFieldTypeLegendChanged, - shouldShowMinimapPanelChanged, -} from 'features/nodes/store/nodesSlice'; const ViewportControls = () => { const { t } = useTranslation(); @@ -49,27 +48,24 @@ const ViewportControls = () => { return ( - - } - /> - - - } - /> - - - } - /> - + } + /> + } + /> + } + /> {/* { icon={} /> */} - - } - /> - + aria-label={ + shouldShowMinimapPanel + ? t('nodes.hideMinimapnodes') + : t('nodes.showMinimapnodes') + } + isChecked={shouldShowMinimapPanel} + onClick={handleClickedToggleMiniMapPanel} + icon={} + /> ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx index 8b7fb942a6..9d7289c273 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx @@ -1,19 +1,12 @@ +import { Flex, chakra, useColorModeValue } from '@chakra-ui/react'; import { RootState } from 'app/store/store'; import { useAppSelector } from 'app/store/storeHooks'; -import { useColorModeValue } from '@chakra-ui/react'; import { memo } from 'react'; import { MiniMap } from 'reactflow'; -const MinimapPanel = () => { - const miniMapStyle = useColorModeValue( - { - background: 'var(--invokeai-colors-base-200)', - }, - { - background: 'var(--invokeai-colors-base-500)', - } - ); +const ChakraMiniMap = chakra(MiniMap); +const MinimapPanel = () => { const shouldShowMinimapPanel = useAppSelector( (state: RootState) => state.nodes.shouldShowMinimapPanel ); @@ -29,18 +22,28 @@ const MinimapPanel = () => { ); return ( - <> + {shouldShowMinimapPanel && ( - )} - + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx new file mode 100644 index 0000000000..8454f5539f --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx @@ -0,0 +1,30 @@ +import { FileButton } from '@mantine/core'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { useLoadWorkflowFromFile } from 'features/nodes/hooks/useLoadWorkflowFromFile'; +import { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { FaUpload } from 'react-icons/fa'; + +const LoadWorkflowButton = () => { + const { t } = useTranslation(); + const resetRef = useRef<() => void>(null); + const loadWorkflowFromFile = useLoadWorkflowFromFile(); + return ( + + {(props) => ( + } + tooltip={t('nodes.loadWorkflow')} + aria-label={t('nodes.loadWorkflow')} + {...props} + /> + )} + + ); +}; + +export default memo(LoadWorkflowButton); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeInvokeButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeInvokeButton.tsx deleted file mode 100644 index decaea19e8..0000000000 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeInvokeButton.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Box } from '@chakra-ui/react'; -import { userInvoked } from 'app/store/actions'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIButton, { IAIButtonProps } from 'common/components/IAIButton'; -import { IAIIconButtonProps } from 'common/components/IAIIconButton'; -import { useIsReadyToInvoke } from 'common/hooks/useIsReadyToInvoke'; -import { InvokeButtonTooltipContent } from 'features/parameters/components/ProcessButtons/InvokeButton'; -import ProgressBar from 'features/system/components/ProgressBar'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { memo, useCallback } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { useTranslation } from 'react-i18next'; -import { FaPlay } from 'react-icons/fa'; - -interface InvokeButton - extends Omit {} - -const NodeInvokeButton = (props: InvokeButton) => { - const { ...rest } = props; - const dispatch = useAppDispatch(); - const activeTabName = useAppSelector(activeTabNameSelector); - const { isReady, isProcessing } = useIsReadyToInvoke(); - const handleInvoke = useCallback(() => { - dispatch(userInvoked('nodes')); - }, [dispatch]); - - const { t } = useTranslation(); - - useHotkeys( - ['ctrl+enter', 'meta+enter'], - handleInvoke, - { - enabled: () => isReady, - preventDefault: true, - enableOnFormTags: ['input', 'textarea', 'select'], - }, - [isReady, activeTabName] - ); - - return ( - - - {!isReady && ( - - - - )} - } - aria-label={t('parameters.invoke')} - type="submit" - isDisabled={!isReady} - onClick={handleInvoke} - flexGrow={1} - w="100%" - colorScheme="accent" - id="invoke-button" - leftIcon={isProcessing ? undefined : } - fontWeight={700} - isLoading={isProcessing} - loadingText={t('parameters.invoke')} - {...rest} - > - Invoke - - - - ); -}; - -export default memo(NodeInvokeButton); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx index cbb0ea58ee..905b0b74a2 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx @@ -1,11 +1,11 @@ import { useAppDispatch } from 'app/store/storeHooks'; -import IAIIconButton from 'common/components/IAIIconButton'; +import IAIButton from 'common/components/IAIButton'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { FaSyncAlt } from 'react-icons/fa'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; -const ReloadSchemaButton = () => { +const ReloadNodeTemplatesButton = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); @@ -14,13 +14,15 @@ const ReloadSchemaButton = () => { }, [dispatch]); return ( - } - tooltip={t('nodes.reloadSchema')} - aria-label={t('nodes.reloadSchema')} + } + tooltip={t('nodes.reloadNodeTemplates')} + aria-label={t('nodes.reloadNodeTemplates')} onClick={handleReloadSchema} - /> + > + {t('nodes.reloadNodeTemplates')} + ); }; -export default memo(ReloadSchemaButton); +export default memo(ReloadNodeTemplatesButton); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ClearGraphButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx similarity index 78% rename from invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ClearGraphButton.tsx rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx index 1501d0270b..129b7f72c9 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ClearGraphButton.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx @@ -6,6 +6,7 @@ import { AlertDialogHeader, AlertDialogOverlay, Button, + Flex, Text, useDisclosure, } from '@chakra-ui/react'; @@ -19,7 +20,7 @@ import { memo, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { FaTrash } from 'react-icons/fa'; -const ClearGraphButton = () => { +const ResetWorkflowButton = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const { isOpen, onOpen, onClose } = useDisclosure(); @@ -48,10 +49,11 @@ const ClearGraphButton = () => { <> } - tooltip={t('nodes.clearGraph')} - aria-label={t('nodes.clearGraph')} + tooltip={t('nodes.resetWorkflow')} + aria-label={t('nodes.resetWorkflow')} onClick={onOpen} isDisabled={!nodesCount} + colorScheme="error" /> { - {t('nodes.clearGraph')} + {t('nodes.resetWorkflow')} - - {t('nodes.clearGraphDesc')} + + + {t('nodes.resetWorkflowDesc')} + {t('nodes.resetWorkflowDesc2')} + - @@ -85,4 +90,4 @@ const ClearGraphButton = () => { ); }; -export default memo(ClearGraphButton); +export default memo(ResetWorkflowButton); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx new file mode 100644 index 0000000000..45764307a3 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx @@ -0,0 +1,29 @@ +import IAIIconButton from 'common/components/IAIIconButton'; +import { useWorkflow } from 'features/nodes/hooks/useWorkflow'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { FaSave } from 'react-icons/fa'; + +const SaveWorkflowButton = () => { + const { t } = useTranslation(); + const workflow = useWorkflow(); + const handleSave = useCallback(() => { + const blob = new Blob([JSON.stringify(workflow, null, 2)]); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = `${workflow.name || 'My Workflow'}.json`; + document.body.appendChild(a); + a.click(); + a.remove(); + }, [workflow]); + return ( + } + tooltip={t('nodes.saveWorkflow')} + aria-label={t('nodes.saveWorkflow')} + onClick={handleSave} + /> + ); +}; + +export default memo(SaveWorkflowButton); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx index 675a69325a..3a2ac7ad89 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx @@ -1,23 +1,24 @@ -import { HStack } from '@chakra-ui/react'; -import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton'; +import { Flex } from '@chakra-ui/layout'; import { memo } from 'react'; -import { Panel } from 'reactflow'; -import NodeEditorSettings from './NodeEditorSettings'; -import ClearGraphButton from './ClearGraphButton'; -import NodeInvokeButton from './NodeInvokeButton'; -import ReloadSchemaButton from './ReloadSchemaButton'; +import LoadWorkflowButton from './LoadWorkflowButton'; +import ResetWorkflowButton from './ResetWorkflowButton'; +import SaveWorkflowButton from './SaveWorkflowButton'; const TopCenterPanel = () => { return ( - - - - - - - - - + + + + + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx new file mode 100644 index 0000000000..3a72f52b0c --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx @@ -0,0 +1,15 @@ +import { Flex } from '@chakra-ui/react'; +import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton'; +import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton'; +import { memo } from 'react'; + +const WorkflowEditorControls = () => { + return ( + + + + + ); +}; + +export default memo(WorkflowEditorControls); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx index a5f1539b64..73296ef52d 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx @@ -1,9 +1,9 @@ +import { Flex } from '@chakra-ui/layout'; import { useAppDispatch } from 'app/store/storeHooks'; -import IAIButton from 'common/components/IAIButton'; +import IAIIconButton from 'common/components/IAIIconButton'; import { addNodePopoverOpened } from 'features/nodes/store/nodesSlice'; import { memo, useCallback } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { Panel } from 'reactflow'; +import { FaPlus } from 'react-icons/fa'; const TopLeftPanel = () => { const dispatch = useAppDispatch(); @@ -12,16 +12,15 @@ const TopLeftPanel = () => { dispatch(addNodePopoverOpened()); }, [dispatch]); - useHotkeys(['shift+a'], () => { - handleOpenAddNodePopover(); - }); - return ( - - - Add Node - - + + } + onClick={handleOpenAddNodePopover} + /> + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx index 903502811d..db8f544c2e 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx @@ -1,7 +1,8 @@ +import { Flex } from '@chakra-ui/layout'; import { useAppSelector } from 'app/store/storeHooks'; import { memo } from 'react'; -import { Panel } from 'reactflow'; import FieldTypeLegend from './FieldTypeLegend'; +import WorkflowEditorSettings from './WorkflowEditorSettings'; const TopRightPanel = () => { const shouldShowFieldTypeLegend = useAppSelector( @@ -9,9 +10,10 @@ const TopRightPanel = () => { ); return ( - + + {shouldShowFieldTypeLegend && } - + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeEditorSettings.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx similarity index 73% rename from invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeEditorSettings.tsx rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx index e62f1bac89..c423750cd8 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/NodeEditorSettings.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx @@ -1,6 +1,7 @@ import { Divider, Flex, + FormLabelProps, Heading, Modal, ModalBody, @@ -8,22 +9,30 @@ import { ModalContent, ModalHeader, ModalOverlay, + forwardRef, useDisclosure, } from '@chakra-ui/react'; 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 IAIIconButton from 'common/components/IAIIconButton'; import IAISwitch from 'common/components/IAISwitch'; -import { ChangeEvent, memo, useCallback } from 'react'; -import { FaCog } from 'react-icons/fa'; import { + selectionModeChanged, shouldAnimateEdgesChanged, shouldColorEdgesChanged, shouldSnapToGridChanged, shouldValidateGraphChanged, } from 'features/nodes/store/nodesSlice'; -import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { ChangeEvent, memo, useCallback } from 'react'; +import { FaCog } from 'react-icons/fa'; +import { SelectionMode } from 'reactflow'; +import ReloadNodeTemplatesButton from '../TopCenterPanel/ReloadSchemaButton'; + +const formLabelProps: FormLabelProps = { + fontWeight: 600, +}; const selector = createSelector( stateSelector, @@ -33,18 +42,20 @@ const selector = createSelector( shouldValidateGraph, shouldSnapToGrid, shouldColorEdges, + selectionMode, } = nodes; return { shouldAnimateEdges, shouldValidateGraph, shouldSnapToGrid, shouldColorEdges, + selectionModeIsChecked: selectionMode === SelectionMode.Full, }; }, defaultSelectorOptions ); -const NodeEditorSettings = () => { +const WorkflowEditorSettings = forwardRef((_, ref) => { const { isOpen, onOpen, onClose } = useDisclosure(); const dispatch = useAppDispatch(); const { @@ -52,6 +63,7 @@ const NodeEditorSettings = () => { shouldValidateGraph, shouldSnapToGrid, shouldColorEdges, + selectionModeIsChecked, } = useAppSelector(selector); const handleChangeShouldValidate = useCallback( @@ -82,10 +94,19 @@ const NodeEditorSettings = () => { [dispatch] ); + const handleChangeSelectionMode = useCallback( + (e: ChangeEvent) => { + dispatch(selectionModeChanged(e.target.checked)); + }, + [dispatch] + ); + return ( <> } onClick={onOpen} /> @@ -93,7 +114,7 @@ const NodeEditorSettings = () => { - Node Editor Settings + Workflow Editor Settings { > General { /> { /> + Advanced + ); -}; +}); -export default memo(NodeEditorSettings); +export default memo(WorkflowEditorSettings); diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx index 909dca2ced..f40d5ddd80 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx @@ -1,48 +1,68 @@ +import { Flex } from '@chakra-ui/react'; +import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import ResizeHandle from 'features/ui/components/tabs/ResizeHandle'; -import { memo, useState } from 'react'; -import { Panel, PanelGroup } from 'react-resizable-panels'; +import { usePanelStorage } from 'features/ui/hooks/usePanelStorage'; +import { memo, useCallback, useRef, useState } from 'react'; +import { + ImperativePanelGroupHandle, + Panel, + PanelGroup, +} from 'react-resizable-panels'; import 'reactflow/dist/style.css'; -import WorkflowPanel from './workflow/WorkflowPanel'; import InspectorPanel from './inspector/InspectorPanel'; +import WorkflowPanel from './workflow/WorkflowPanel'; const NodeEditorPanelGroup = () => { const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false); const [isBottomPanelCollapsed, setIsBottomPanelCollapsed] = useState(false); + const panelGroupRef = useRef(null); + const panelStorage = usePanelStorage(); + const handleDoubleClickHandle = useCallback(() => { + if (!panelGroupRef.current) { + return; + } + panelGroupRef.current.setLayout([50, 50]); + }, []); return ( - - - - - + + - - - - + + + + + + + + + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx index 12970a0e66..22f3ad6bb5 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx @@ -20,7 +20,7 @@ const InspectorPanel = () => { w: 'full', h: 'full', borderRadius: 'base', - p: 4, + p: 2, gap: 2, }} > diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx index 21c75a42da..aa3b1ad1be 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx @@ -1,26 +1,10 @@ import { Flex } from '@chakra-ui/react'; -import { RootState } from 'app/store/store'; -import { useAppSelector } from 'app/store/storeHooks'; import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer'; -import { buildWorkflow } from 'features/nodes/util/buildWorkflow'; -import { memo, useMemo } from 'react'; -import { useDebounce } from 'use-debounce'; - -const useWatchWorkflow = () => { - const nodes = useAppSelector((state: RootState) => state.nodes); - const [debouncedNodes] = useDebounce(nodes, 300); - const workflow = useMemo( - () => buildWorkflow(debouncedNodes), - [debouncedNodes] - ); - - return { - workflow, - }; -}; +import { useWorkflow } from 'features/nodes/hooks/useWorkflow'; +import { memo } from 'react'; const WorkflowJSONTab = () => { - const { workflow } = useWatchWorkflow(); + const workflow = useWorkflow(); return ( { h: 'full', }} > - + ); }; diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx index df1c0dcc69..4cf7b2e431 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx @@ -8,8 +8,8 @@ import { } from '@chakra-ui/react'; import { memo } from 'react'; import WorkflowGeneralTab from './WorkflowGeneralTab'; -import WorkflowLinearTab from './WorkflowLinearTab'; import WorkflowJSONTab from './WorkflowJSONTab'; +import WorkflowLinearTab from './WorkflowLinearTab'; const WorkflowPanel = () => { return ( @@ -20,7 +20,8 @@ const WorkflowPanel = () => { w: 'full', h: 'full', borderRadius: 'base', - p: 4, + p: 2, + gap: 2, }} > { + const selector = useMemo( + () => + createSelector( + stateSelector, + ({ nodes }) => { + const node = nodes.nodes.find((node) => node.id === nodeId); + if (!isInvocationNode(node)) { + return []; + } + const nodeTemplate = nodes.nodeTemplates[node.data.type]; + if (!nodeTemplate) { + return []; + } + return map(nodeTemplate.inputs) + .filter((field) => ['any', 'direct'].includes(field.input)) + .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) + .map((field) => field.name) + .filter((fieldName) => fieldName !== 'is_intermediate'); + }, + defaultSelectorOptions + ), + [nodeId] + ); + + const fieldNames = useAppSelector(selector); + return fieldNames; +}; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts new file mode 100644 index 0000000000..b7eef02e9d --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts @@ -0,0 +1,36 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { map } from 'lodash-es'; +import { useMemo } from 'react'; +import { isInvocationNode } from '../types/types'; + +export const useConnectionInputFieldNames = (nodeId: string) => { + const selector = useMemo( + () => + createSelector( + stateSelector, + ({ nodes }) => { + const node = nodes.nodes.find((node) => node.id === nodeId); + if (!isInvocationNode(node)) { + return []; + } + const nodeTemplate = nodes.nodeTemplates[node.data.type]; + if (!nodeTemplate) { + return []; + } + return map(nodeTemplate.inputs) + .filter((field) => field.input === 'connection') + .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) + .map((field) => field.name) + .filter((fieldName) => fieldName !== 'is_intermediate'); + }, + defaultSelectorOptions + ), + [nodeId] + ); + + const fieldNames = useAppSelector(selector); + return fieldNames; +}; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx b/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx new file mode 100644 index 0000000000..7e42bcea5f --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx @@ -0,0 +1,103 @@ +import { ListItem, Text, UnorderedList } from '@chakra-ui/react'; +import { useLogger } from 'app/logging/useLogger'; +import { useAppDispatch } from 'app/store/storeHooks'; +import { parseify } from 'common/util/serialize'; +import { workflowLoaded } from 'features/nodes/store/nodesSlice'; +import { zWorkflow } from 'features/nodes/types/types'; +import { addToast } from 'features/system/store/systemSlice'; +import { makeToast } from 'features/system/util/makeToast'; +import { memo, useCallback } from 'react'; +import { ZodError } from 'zod'; +import { fromZodError, fromZodIssue } from 'zod-validation-error'; + +export const useLoadWorkflowFromFile = () => { + const dispatch = useAppDispatch(); + const logger = useLogger('nodes'); + const loadWorkflowFromFile = useCallback( + (file: File | null) => { + if (!file) { + return; + } + const reader = new FileReader(); + reader.onload = async () => { + const rawJSON = reader.result; + + try { + const parsedJSON = JSON.parse(String(rawJSON)); + const result = zWorkflow.safeParse(parsedJSON); + + if (!result.success) { + const message = fromZodError(result.error, { + prefix: 'Workflow Validation Error', + }).toString(); + logger.error({ error: parseify(result.error) }, message); + + dispatch( + addToast( + makeToast({ + title: 'Unable to Validate Workflow', + description: ( + + ), + status: 'error', + duration: 5000, + }) + ) + ); + return; + } + + dispatch(workflowLoaded(result.data)); + + dispatch( + addToast( + makeToast({ + title: 'Workflow Loaded', + status: 'success', + }) + ) + ); + reader.abort(); + } catch (error) { + // file reader error + if (error) { + dispatch( + addToast( + makeToast({ + title: 'Unable to Load Workflow', + status: 'error', + }) + ) + ); + } + } + }; + + reader.readAsText(file); + }, + [dispatch, logger] + ); + + return loadWorkflowFromFile; +}; + +const WorkflowValidationErrorContent = memo((props: { error: ZodError }) => { + if (props.error.issues[0]) { + return ( + + {fromZodIssue(props.error.issues[0], { prefix: null }).toString()} + + ); + } + return ( + + {props.error.issues.map((issue, i) => ( + + {fromZodIssue(issue, { prefix: null }).toString()} + + ))} + + ); +}); + +WorkflowValidationErrorContent.displayName = 'WorkflowValidationErrorContent'; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts similarity index 63% rename from invokeai/frontend/web/src/features/nodes/hooks/useFieldNames.ts rename to invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts index e2c7126012..41d3a1ac91 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts @@ -4,10 +4,9 @@ import { useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { map } from 'lodash-es'; import { useMemo } from 'react'; -import { KIND_MAP } from '../types/constants'; import { isInvocationNode } from '../types/types'; -export const useFieldNames = (nodeId: string, kind: 'input' | 'output') => { +export const useOutputFieldNames = (nodeId: string) => { const selector = useMemo( () => createSelector( @@ -17,13 +16,18 @@ export const useFieldNames = (nodeId: string, kind: 'input' | 'output') => { if (!isInvocationNode(node)) { return []; } - return map(node.data[KIND_MAP[kind]], (field) => field.name).filter( - (fieldName) => fieldName !== 'is_intermediate' - ); + const nodeTemplate = nodes.nodeTemplates[node.data.type]; + if (!nodeTemplate) { + return []; + } + return map(nodeTemplate.outputs) + .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) + .map((field) => field.name) + .filter((fieldName) => fieldName !== 'is_intermediate'); }, defaultSelectorOptions ), - [kind, nodeId] + [nodeId] ); const fieldNames = useAppSelector(selector); diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts b/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts new file mode 100644 index 0000000000..f729aa1004 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts @@ -0,0 +1,16 @@ +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { buildWorkflow } from 'features/nodes/util/buildWorkflow'; +import { useMemo } from 'react'; +import { useDebounce } from 'use-debounce'; + +export const useWorkflow = () => { + const nodes = useAppSelector((state: RootState) => state.nodes); + const [debouncedNodes] = useDebounce(nodes, 300); + const workflow = useMemo( + () => buildWorkflow(debouncedNodes), + [debouncedNodes] + ); + + return workflow; +}; diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts b/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts index fe52b63bb2..acf9918a89 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts @@ -4,7 +4,6 @@ import { NodesState } from './types'; * Nodes slice persist denylist */ export const nodesPersistDenylist: (keyof NodesState)[] = [ - 'schema', 'nodeTemplates', 'connectionStartParams', 'currentConnectionFieldType', diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index 816a326ae0..dec0daabe9 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -14,6 +14,7 @@ import { Node, NodeChange, OnConnectStartParams, + SelectionMode, Viewport, } from 'reactflow'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; @@ -56,6 +57,8 @@ import { import { NodesState } from './types'; import { findUnoccupiedPosition } from './util/findUnoccupiedPosition'; +export const WORKFLOW_FORMAT_VERSION = '1.0.0'; + const initialNodeExecutionState: Omit = { status: NodeStatus.PENDING, error: null, @@ -64,10 +67,23 @@ const initialNodeExecutionState: Omit = { outputs: [], }; +export const initialWorkflow = { + meta: { + version: WORKFLOW_FORMAT_VERSION, + }, + name: '', + author: '', + description: '', + notes: '', + tags: '', + contact: '', + version: '', + exposedFields: [], +}; + export const initialNodesState: NodesState = { nodes: [], edges: [], - schema: null, nodeTemplates: {}, isReady: false, connectionStartParams: null, @@ -82,21 +98,13 @@ export const initialNodesState: NodesState = { nodeOpacity: 1, selectedNodes: [], selectedEdges: [], - workflow: { - name: '', - author: '', - description: '', - notes: '', - tags: '', - contact: '', - version: '', - exposedFields: [], - }, + workflow: initialWorkflow, nodeExecutionStates: {}, viewport: { x: 0, y: 0, zoom: 1 }, mouseOverField: null, nodesToCopy: [], edgesToCopy: [], + selectionMode: SelectionMode.Partial, }; type FieldValueAction = PayloadAction<{ @@ -570,15 +578,6 @@ const nodesSlice = createSlice({ nodeOpacityChanged: (state, action: PayloadAction) => { state.nodeOpacity = action.payload; }, - loadFileNodes: ( - state, - action: PayloadAction[]> - ) => { - state.nodes = action.payload; - }, - loadFileEdges: (state, action: PayloadAction) => { - state.edges = action.payload; - }, workflowNameChanged: (state, action: PayloadAction) => { state.workflow.name = action.payload; }, @@ -601,9 +600,9 @@ const nodesSlice = createSlice({ state.workflow.contact = action.payload; }, workflowLoaded: (state, action: PayloadAction) => { - // TODO: validation const { nodes, edges, ...workflow } = action.payload; state.workflow = workflow; + state.nodes = applyNodeChanges( nodes.map((node) => ({ item: { ...node, dragHandle: `.${DRAG_HANDLE_CLASSNAME}` }, @@ -615,6 +614,19 @@ const nodesSlice = createSlice({ edges.map((edge) => ({ item: edge, type: 'add' })), [] ); + + state.nodeExecutionStates = nodes.reduce< + Record + >((acc, node) => { + acc[node.id] = { + nodeId: node.id, + ...initialNodeExecutionState, + }; + return acc; + }, {}); + }, + workflowReset: (state) => { + state.workflow = cloneDeep(initialWorkflow); }, viewportChanged: (state, action: PayloadAction) => { state.viewport = action.payload; @@ -721,14 +733,16 @@ const nodesSlice = createSlice({ addNodePopoverToggled: (state) => { state.isAddNodePopoverOpen = !state.isAddNodePopoverOpen; }, + selectionModeChanged: (state, action: PayloadAction) => { + state.selectionMode = action.payload + ? SelectionMode.Full + : SelectionMode.Partial; + }, }, extraReducers: (builder) => { builder.addCase(receivedOpenAPISchema.pending, (state) => { state.isReady = false; }); - builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => { - state.schema = action.payload; - }); builder.addCase(appSocketInvocationStarted, (state, action) => { const { source_node_id } = action.payload.data; const node = state.nodeExecutionStates[source_node_id]; @@ -792,8 +806,6 @@ export const { nodeTemplatesBuilt, nodeEditorReset, imageCollectionFieldValueChanged, - loadFileNodes, - loadFileEdges, fieldStringValueChanged, fieldNumberValueChanged, fieldBooleanValueChanged, @@ -837,6 +849,7 @@ export const { addNodePopoverOpened, addNodePopoverClosed, addNodePopoverToggled, + selectionModeChanged, } = nodesSlice.actions; export default nodesSlice.reducer; diff --git a/invokeai/frontend/web/src/features/nodes/store/types.ts b/invokeai/frontend/web/src/features/nodes/store/types.ts index bcc878d69e..26eec9b2d5 100644 --- a/invokeai/frontend/web/src/features/nodes/store/types.ts +++ b/invokeai/frontend/web/src/features/nodes/store/types.ts @@ -1,5 +1,10 @@ -import { OpenAPIV3 } from 'openapi-types'; -import { Edge, Node, OnConnectStartParams, Viewport } from 'reactflow'; +import { + Edge, + Node, + OnConnectStartParams, + SelectionMode, + Viewport, +} from 'reactflow'; import { FieldIdentifier, FieldType, @@ -13,7 +18,6 @@ import { export type NodesState = { nodes: Node[]; edges: Edge[]; - schema: OpenAPIV3.Document | null; nodeTemplates: Record; connectionStartParams: OnConnectStartParams | null; currentConnectionFieldType: FieldType | null; @@ -34,4 +38,5 @@ export type NodesState = { nodesToCopy: Node[]; edgesToCopy: Edge[]; isAddNodePopoverOpen: boolean; + selectionMode: SelectionMode; }; diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 4fbb32fe7f..4e61e46d8a 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -23,9 +23,6 @@ export const COLLECTION_TYPES: FieldType[] = [ 'ImageCollection', ]; -export const colorTokenToCssVar = (colorToken: string) => - `var(--invokeai-colors-${colorToken.split('.').join('-')}`; - export const FIELDS: Record = { integer: { title: 'Integer', diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index 1b5d193aed..26aa19bd9d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -1,23 +1,13 @@ import { - ControlNetModelParam, - LoRAModelParam, - MainModelParam, - OnnxModelParam, SchedulerParam, - VaeModelParam, + zBaseModel, + zMainOrOnnxModel, + zScheduler, } from 'features/parameters/types/parameterSchemas'; import { OpenAPIV3 } from 'openapi-types'; import { RgbaColor } from 'react-colorful'; -import { Edge, Node } from 'reactflow'; -import { components } from 'services/api/schema'; -import { - Graph, - GraphExecutionState, - ImageDTO, - ImageField, - _InputField, - _OutputField, -} from 'services/api/types'; +import { Node } from 'reactflow'; +import { Graph, ImageDTO, _InputField, _OutputField } from 'services/api/types'; import { AnyInvocationType, AnyResult, @@ -53,6 +43,10 @@ export type InvocationTemplate = { * Array of the invocation outputs */ outputs: Record; + /** + * The type of this node's output + */ + outputType: string; // TODO: generate a union of output types }; export type FieldUIConfig = { @@ -114,40 +108,6 @@ export type FieldType = z.infer; export const isFieldType = (value: unknown): value is FieldType => zFieldType.safeParse(value).success; -/** - * An input field is persisted across reloads as part of the user's local state. - * - * An input field has three properties: - * - `id` a unique identifier - * - `name` the name of the field, which comes from the python dataclass - * - `value` the field's value - */ -export type InputFieldValue = - | IntegerInputFieldValue - | SeedInputFieldValue - | FloatInputFieldValue - | StringInputFieldValue - | BooleanInputFieldValue - | ImageInputFieldValue - | LatentsInputFieldValue - | ConditioningInputFieldValue - | UNetInputFieldValue - | ClipInputFieldValue - | VaeInputFieldValue - | ControlInputFieldValue - | EnumInputFieldValue - | MainModelInputFieldValue - | SDXLMainModelInputFieldValue - | SDXLRefinerModelInputFieldValue - | VaeModelInputFieldValue - | LoRAModelInputFieldValue - | ControlNetModelInputFieldValue - | CollectionInputFieldValue - | CollectionItemInputFieldValue - | ColorInputFieldValue - | ImageCollectionInputFieldValue - | SchedulerInputFieldValue; - /** * An input field template is generated on each page load from the OpenAPI schema. * @@ -179,6 +139,19 @@ export type InputFieldTemplate = | ImageCollectionInputFieldTemplate | SchedulerInputFieldTemplate; +/** + * Indicates the kind of input(s) this field may have. + */ +export const zInputKind = z.enum(['connection', 'direct', 'any']); +export type InputKind = z.infer; + +export const zFieldValueBase = z.object({ + id: z.string().trim().min(1), + name: z.string().trim().min(1), + type: zFieldType, +}); +export type FieldValueBase = z.infer; + /** * An output field is persisted across as part of the user's local state. * @@ -186,7 +159,11 @@ export type InputFieldTemplate = * - `id` a unique identifier * - `name` the name of the field, which comes from the python dataclass */ -export type OutputFieldValue = FieldValueBase & { fieldKind: 'output' }; + +export const zOutputFieldValue = zFieldValueBase.extend({ + fieldKind: z.literal('output'), +}); +export type OutputFieldValue = z.infer; /** * An output field template is generated on each page load from the OpenAPI schema. @@ -199,143 +176,309 @@ export type OutputFieldTemplate = { type: FieldType; title: string; description: string; -}; +} & _OutputField; -/** - * Indicates the kind of input(s) this field may have. - */ -export type InputKind = 'connection' | 'direct' | 'any'; +export const zInputFieldValueBase = zFieldValueBase.extend({ + fieldKind: z.literal('input'), + label: z.string(), +}); +export type InputFieldValueBase = z.infer; -export type FieldValueBase = { - id: string; - name: string; - type: FieldType; -}; +export const zModelIdentifier = z.object({ + model_name: z.string().trim().min(1), + base_model: zBaseModel, +}); -export type InputFieldValueBase = FieldValueBase & { - fieldKind: 'input'; - label: string; -}; +export const zImageField = z.object({ + image_name: z.string().trim().min(1), +}); +export type ImageField = z.infer; -export type IntegerInputFieldValue = InputFieldValueBase & { - type: 'integer'; - value?: number; -}; +export const zLatentsField = z.object({ + latents_name: z.string().trim().min(1), + seed: z.number().int().optional(), +}); +export type LatentsField = z.infer; -export type FloatInputFieldValue = InputFieldValueBase & { - type: 'float'; - value?: number; -}; +export const zConditioningField = z.object({ + conditioning_name: z.string().trim().min(1), +}); +export type ConditioningField = z.infer; -export type SeedInputFieldValue = InputFieldValueBase & { - type: 'Seed'; - value?: number; -}; +export const zIntegerInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('integer'), + value: z.number().optional(), +}); +export type IntegerInputFieldValue = z.infer; -export type StringInputFieldValue = InputFieldValueBase & { - type: 'string'; - value?: string; -}; +export const zFloatInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('float'), + value: z.number().optional(), +}); +export type FloatInputFieldValue = z.infer; -export type BooleanInputFieldValue = InputFieldValueBase & { - type: 'boolean'; - value?: boolean; -}; +export const zStringInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('string'), + value: z.string().optional(), +}); +export type StringInputFieldValue = z.infer; -export type EnumInputFieldValue = InputFieldValueBase & { - type: 'enum'; - value?: number | string; -}; +export const zBooleanInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('boolean'), + value: z.boolean().optional(), +}); +export type BooleanInputFieldValue = z.infer; -export type LatentsInputFieldValue = InputFieldValueBase & { - type: 'LatentsField'; - value?: undefined; -}; +export const zEnumInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('enum'), + value: z.union([z.string(), z.number()]).optional(), +}); +export type EnumInputFieldValue = z.infer; -export type ConditioningInputFieldValue = InputFieldValueBase & { - type: 'ConditioningField'; - value?: string; -}; +export const zLatentsInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('LatentsField'), + value: zLatentsField.optional(), +}); +export type LatentsInputFieldValue = z.infer; -export type ControlInputFieldValue = InputFieldValueBase & { - type: 'ControlField'; - value?: undefined; -}; +export const zConditioningInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ConditioningField'), + value: zConditioningField.optional(), +}); +export type ConditioningInputFieldValue = z.infer< + typeof zConditioningInputFieldValue +>; -export type UNetInputFieldValue = InputFieldValueBase & { - type: 'UNetField'; - value?: undefined; -}; +export const zControlNetModel = zModelIdentifier; +export type ControlNetModel = z.infer; -export type ClipInputFieldValue = InputFieldValueBase & { - type: 'ClipField'; - value?: undefined; -}; +export const zControlField = zInputFieldValueBase.extend({ + image: zImageField, + control_model: zControlNetModel, + control_weight: z.union([z.number(), z.array(z.number())]).optional(), + begin_step_percent: z.number().optional(), + end_step_percent: z.number().optional(), + control_mode: z + .enum(['balanced', 'more_prompt', 'more_control', 'unbalanced']) + .optional(), + resize_mode: z + .enum(['just_resize', 'crop_resize', 'fill_resize', 'just_resize_simple']) + .optional(), +}); +export type ControlField = z.infer; -export type VaeInputFieldValue = InputFieldValueBase & { - type: 'VaeField'; - value?: undefined; -}; +export const zControlInputFieldTemplate = zInputFieldValueBase.extend({ + type: z.literal('ControlField'), + value: zControlField.optional(), +}); +export type ControlInputFieldValue = z.infer; -export type ImageInputFieldValue = InputFieldValueBase & { - type: 'ImageField'; - value?: ImageField; -}; +export const zModelType = z.enum([ + 'onnx', + 'main', + 'vae', + 'lora', + 'controlnet', + 'embedding', +]); +export type ModelType = z.infer; -export type ImageCollectionInputFieldValue = InputFieldValueBase & { - type: 'ImageCollection'; - value?: ImageField[]; -}; +export const zSubModelType = z.enum([ + 'unet', + 'text_encoder', + 'text_encoder_2', + 'tokenizer', + 'tokenizer_2', + 'vae', + 'vae_decoder', + 'vae_encoder', + 'scheduler', + 'safety_checker', +]); +export type SubModelType = z.infer; -export type MainModelInputFieldValue = InputFieldValueBase & { - type: 'MainModelField'; - value?: MainModelParam | OnnxModelParam; -}; +export const zModelInfo = zModelIdentifier.extend({ + model_type: zModelType, + submodel: zSubModelType.optional(), +}); +export type ModelInfo = z.infer; -export type SDXLMainModelInputFieldValue = InputFieldValueBase & { - type: 'SDXLMainModelField'; - value?: MainModelParam | OnnxModelParam; -}; +export const zLoraInfo = zModelInfo.extend({ + weight: z.number().optional(), +}); +export type LoraInfo = z.infer; -export type SDXLRefinerModelInputFieldValue = InputFieldValueBase & { - type: 'SDXLRefinerModelField'; - value?: MainModelParam | OnnxModelParam; -}; +export const zUNetField = z.object({ + unet: zModelInfo, + scheduler: zModelInfo, + loras: z.array(zLoraInfo), +}); +export type UNetField = z.infer; -export type VaeModelInputFieldValue = InputFieldValueBase & { - type: 'VaeModelField'; - value?: VaeModelParam; -}; +export const zUNetInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('UNetField'), + value: zUNetField.optional(), +}); +export type UNetInputFieldValue = z.infer; -export type LoRAModelInputFieldValue = InputFieldValueBase & { - type: 'LoRAModelField'; - value?: LoRAModelParam; -}; +export const zClipField = z.object({ + tokenizer: zModelInfo, + text_encoder: zModelInfo, + skipped_layers: z.number(), + loras: z.array(zLoraInfo), +}); +export type ClipField = z.infer; -export type ControlNetModelInputFieldValue = InputFieldValueBase & { - type: 'ControlNetModelField'; - value?: ControlNetModelParam; -}; +export const zClipInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ClipField'), + value: zClipField.optional(), +}); +export type ClipInputFieldValue = z.infer; -export type CollectionInputFieldValue = InputFieldValueBase & { - type: 'Collection'; - value?: (string | number)[]; -}; +export const zVaeField = z.object({ + vae: zModelInfo, +}); +export type VaeField = z.infer; -export type CollectionItemInputFieldValue = InputFieldValueBase & { - type: 'CollectionItem'; - value?: undefined; -}; +export const zVaeInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('VaeField'), + value: zVaeField.optional(), +}); +export type VaeInputFieldValue = z.infer; -export type ColorInputFieldValue = InputFieldValueBase & { - type: 'ColorField'; - value?: RgbaColor; -}; +export const zImageInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ImageField'), + value: zImageField.optional(), +}); +export type ImageInputFieldValue = z.infer; -export type SchedulerInputFieldValue = InputFieldValueBase & { - type: 'Scheduler'; - value?: SchedulerParam; -}; +export const zImageCollectionInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ImageCollection'), + value: z.array(zImageField).optional(), +}); +export type ImageCollectionInputFieldValue = z.infer< + typeof zImageCollectionInputFieldValue +>; + +export const zMainModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('MainModelField'), + value: zMainOrOnnxModel.optional(), +}); +export type MainModelInputFieldValue = z.infer< + typeof zMainModelInputFieldValue +>; + +export const zSDXLMainModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('SDXLMainModelField'), + value: zMainOrOnnxModel.optional(), +}); +export type SDXLMainModelInputFieldValue = z.infer< + typeof zSDXLMainModelInputFieldValue +>; + +export const zSDXLRefinerModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('SDXLRefinerModelField'), + value: zMainOrOnnxModel.optional(), // TODO: should narrow this down to a refiner model +}); +export type SDXLRefinerModelInputFieldValue = z.infer< + typeof zSDXLRefinerModelInputFieldValue +>; + +export const zVaeModelField = zModelIdentifier; + +export const zVaeModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('VaeModelField'), + value: zVaeModelField.optional(), +}); +export type VaeModelInputFieldValue = z.infer; + +export const zLoRAModelField = zModelIdentifier; +export type LoRAModelField = z.infer; + +export const zLoRAModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('LoRAModelField'), + value: zLoRAModelField.optional(), +}); +export type LoRAModelInputFieldValue = z.infer< + typeof zLoRAModelInputFieldValue +>; + +export const zControlNetModelField = zModelIdentifier; +export type ControlNetModelField = z.infer; + +export const zControlNetModelInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ControlNetModelField'), + value: zControlNetModelField.optional(), +}); +export type ControlNetModelInputFieldValue = z.infer< + typeof zControlNetModelInputFieldValue +>; + +export const zCollectionInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('Collection'), + value: z.array(z.any()).optional(), // TODO: should this field ever have a value? +}); +export type CollectionInputFieldValue = z.infer< + typeof zCollectionInputFieldValue +>; + +export const zCollectionItemInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('CollectionItem'), + value: z.any().optional(), // TODO: should this field ever have a value? +}); +export type CollectionItemInputFieldValue = z.infer< + typeof zCollectionItemInputFieldValue +>; + +export const zColorField = z.object({ + r: z.number().int().min(0).max(255), + g: z.number().int().min(0).max(255), + b: z.number().int().min(0).max(255), + a: z.number().int().min(0).max(255), +}); +export type ColorField = z.infer; + +export const zColorInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('ColorField'), + value: zColorField.optional(), +}); +export type ColorInputFieldValue = z.infer; + +export const zSchedulerInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('Scheduler'), + value: zScheduler.optional(), +}); +export type SchedulerInputFieldValue = z.infer< + typeof zSchedulerInputFieldValue +>; + +export const zInputFieldValue = z.discriminatedUnion('type', [ + zIntegerInputFieldValue, + zFloatInputFieldValue, + zStringInputFieldValue, + zBooleanInputFieldValue, + zImageInputFieldValue, + zLatentsInputFieldValue, + zConditioningInputFieldValue, + zUNetInputFieldValue, + zClipInputFieldValue, + zVaeInputFieldValue, + zControlInputFieldTemplate, + zEnumInputFieldValue, + zMainModelInputFieldValue, + zSDXLMainModelInputFieldValue, + zSDXLRefinerModelInputFieldValue, + zVaeModelInputFieldValue, + zLoRAModelInputFieldValue, + zControlNetModelInputFieldValue, + zCollectionInputFieldValue, + zCollectionItemInputFieldValue, + zColorInputFieldValue, + zImageCollectionInputFieldValue, + zSchedulerInputFieldValue, +]); + +export type InputFieldValue = z.infer; export type InputFieldTemplateBase = { name: string; @@ -521,14 +664,15 @@ export type InvocationBaseSchemaObject = Omit< export type InvocationOutputSchemaObject = Omit< OpenAPIV3.SchemaObject, 'properties' -> & - OpenAPIV3.SchemaObject['properties'] & { +> & { + properties: OpenAPIV3.SchemaObject['properties'] & { type: Omit & { - default: AnyInvocationType; + default: string; }; } & { class: 'output'; }; +}; export type InvocationFieldSchema = OpenAPIV3.SchemaObject & _InputField; @@ -571,24 +715,26 @@ export const isInvocationFieldSchema = ( export type InvocationEdgeExtra = { type: 'default' | 'collapsed' }; -export const zInputFieldValue = z.object({ - id: z.string().trim().min(1), - name: z.string().trim().min(1), - type: zFieldType, - label: z.string(), - isExposed: z.boolean(), -}); - export const zInvocationNodeData = z.object({ id: z.string().trim().min(1), + // no easy way to build this dynamically, and we don't want to anyways, because this will be used + // to validate incoming workflows, and we want to allow community nodes. type: z.string().trim().min(1), - inputs: z.record(z.any()), - outputs: z.record(z.any()), + inputs: z.record(zInputFieldValue), + outputs: z.record(zOutputFieldValue), label: z.string(), isOpen: z.boolean(), notes: z.string(), }); +// Massage this to get better type safety while developing +export type InvocationNodeData = Omit< + z.infer, + 'type' +> & { + type: AnyInvocationType; +}; + export const zNotesNodeData = z.object({ id: z.string().trim().min(1), type: z.literal('notes'), @@ -597,75 +743,83 @@ export const zNotesNodeData = z.object({ notes: z.string(), }); +export type NotesNodeData = z.infer; + +export const zWorkflowInvocationNode = z.object({ + id: z.string().trim().min(1), + type: z.literal('invocation'), + data: zInvocationNodeData, + width: z.number().gt(0), + height: z.number().gt(0), + position: z.object({ + x: z.number(), + y: z.number(), + }), +}); + +export const zWorkflowNotesNode = z.object({ + id: z.string().trim().min(1), + type: z.literal('notes'), + data: zNotesNodeData, + width: z.number().gt(0), + height: z.number().gt(0), + position: z.object({ + x: z.number(), + y: z.number(), + }), +}); + +export const zWorkflowNode = z.discriminatedUnion('type', [ + zWorkflowInvocationNode, + zWorkflowNotesNode, +]); + +export type WorkflowNode = z.infer; + +export const zWorkflowEdge = z.object({ + source: z.string().trim().min(1), + sourceHandle: z.string().trim().min(1), + target: z.string().trim().min(1), + targetHandle: z.string().trim().min(1), + id: z.string().trim().min(1), + type: z.enum(['default', 'collapsed']), +}); + +export const zFieldIdentifier = z.object({ + nodeId: z.string().trim().min(1), + fieldName: z.string().trim().min(1), +}); + +export type FieldIdentifier = z.infer; + +export const zSemVer = z.string().refine((val) => { + const [major, minor, patch] = val.split('.'); + return ( + major !== undefined && + minor !== undefined && + patch !== undefined && + Number.isInteger(Number(major)) && + Number.isInteger(Number(minor)) && + Number.isInteger(Number(patch)) + ); +}); + +export type SemVer = z.infer; + export const zWorkflow = z.object({ - name: z.string().trim().min(1), + name: z.string(), author: z.string(), description: z.string(), version: z.string(), contact: z.string(), tags: z.string(), notes: z.string(), - nodes: z.array( - z.object({ - id: z.string().trim().min(1), - type: z.string().trim().min(1), - data: z.union([zInvocationNodeData, zNotesNodeData]), - width: z.number().gt(0), - height: z.number().gt(0), - position: z.object({ - x: z.number(), - y: z.number(), - }), - }) - ), - edges: z.array( - z.object({ - source: z.string().trim().min(1), - sourceHandle: z.string().trim().min(1), - target: z.string().trim().min(1), - targetHandle: z.string().trim().min(1), - id: z.string().trim().min(1), - type: z.string().trim().min(1), - }) - ), + nodes: z.array(zWorkflowNode), + edges: z.array(zWorkflowEdge), + exposedFields: z.array(zFieldIdentifier), }); -export type Workflow = { - name: string; - author: string; - description: string; - version: string; - contact: string; - tags: string; - notes: string; - nodes: Pick< - Node, - 'id' | 'type' | 'data' | 'width' | 'height' | 'position' - >[]; - edges: Pick< - Edge, - 'source' | 'sourceHandle' | 'target' | 'targetHandle' | 'id' | 'type' - >[]; - exposedFields: FieldIdentifier[]; -}; - -export type InvocationNodeData = { - id: string; - type: AnyInvocationType; - inputs: Record; - outputs: Record; - label: string; - isOpen: boolean; - notes: string; -}; - -export type NotesNodeData = { - id: string; - type: 'notes'; - label: string; - notes: string; - isOpen: boolean; -}; +export type Workflow = z.infer; export type CurrentImageNodeData = { id: string; @@ -705,25 +859,6 @@ export enum NodeStatus { FAILED, } -type SavedOutput = - | components['schemas']['StringOutput'] - | components['schemas']['IntegerOutput'] - | components['schemas']['FloatOutput'] - | components['schemas']['ImageOutput']; - -export const isSavedOutput = ( - output: GraphExecutionState['results'][string] -): output is SavedOutput => - Boolean( - output && - [ - 'string_output', - 'integer_output', - 'float_output', - 'image_output', - ].includes(output?.type) - ); - export type NodeExecutionState = { nodeId: string; status: NodeStatus; @@ -733,14 +868,9 @@ export type NodeExecutionState = { outputs: AnyResult[]; }; -export type FieldIdentifier = { - nodeId: string; - fieldName: string; -}; - export type FieldComponentProps< V extends InputFieldValue, - T extends InputFieldTemplate + T extends InputFieldTemplate, > = { nodeId: string; field: V; diff --git a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts index da3aff7e1c..cb0d0b942b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts @@ -1,8 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; -import { pick } from 'lodash-es'; import { NodesState } from '../store/types'; -import { Workflow, isInvocationNode, isNotesNode } from '../types/types'; +import { Workflow, zWorkflowEdge, zWorkflowNode } from '../types/types'; export const buildWorkflow = (nodesState: NodesState): Workflow => { const { workflow: workflowMeta, nodes, edges } = nodesState; @@ -13,25 +12,19 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => { }; nodes.forEach((node) => { - if (!isInvocationNode(node) && !isNotesNode(node)) { + const result = zWorkflowNode.safeParse(node); + if (!result.success) { return; } - workflow.nodes.push( - pick(node, ['id', 'type', 'position', 'width', 'height', 'data']) - ); + workflow.nodes.push(result.data); }); edges.forEach((edge) => { - workflow.edges.push( - pick(edge, [ - 'source', - 'sourceHandle', - 'target', - 'targetHandle', - 'id', - 'type', - ]) - ); + const result = zWorkflowEdge.safeParse(edge); + if (!result.success) { + return; + } + workflow.edges.push(result.data); }); return workflow; diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index ef96b8b485..ca7674a021 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -467,7 +467,7 @@ export const buildInputFieldTemplate = ( const fieldType = getFieldType(fieldSchema); // console.log('input fieldType', fieldType); - const { input, ui_hidden, ui_component, ui_type } = fieldSchema; + const { input, ui_hidden, ui_component, ui_type, ui_order } = fieldSchema; const extra = { input, @@ -475,6 +475,7 @@ export const buildInputFieldTemplate = ( ui_component, ui_type, required: nodeSchema.required?.includes(name) ?? false, + ui_order, }; const baseField = { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts index 01158d1cf0..e199a78a20 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts @@ -6,6 +6,9 @@ import { MetadataAccumulatorInvocation, } from 'services/api/types'; import { + CANVAS_INPAINT_GRAPH, + CANVAS_OUTPAINT_GRAPH, + CANVAS_COHERENCE_DENOISE_LATENTS, CLIP_SKIP, LORA_LOADER, MAIN_MODEL_LOADER, @@ -136,6 +139,22 @@ export const addLoRAsToGraph = ( }, }); + if ( + graph.id && + [CANVAS_INPAINT_GRAPH, CANVAS_OUTPAINT_GRAPH].includes(graph.id) + ) { + graph.edges.push({ + source: { + node_id: currentLoraNodeId, + field: 'unet', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'unet', + }, + }); + } + graph.edges.push({ source: { node_id: currentLoraNodeId, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts index 190816f21f..a52264ca8e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts @@ -6,10 +6,13 @@ import { SDXLLoraLoaderInvocation, } from 'services/api/types'; import { + CANVAS_COHERENCE_DENOISE_LATENTS, LORA_LOADER, METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, POSITIVE_CONDITIONING, + SDXL_CANVAS_INPAINT_GRAPH, + SDXL_CANVAS_OUTPAINT_GRAPH, SDXL_MODEL_LOADER, } from './constants'; @@ -163,6 +166,24 @@ export const addSDXLLoRAsToGraph = ( }, }); + if ( + graph.id && + [SDXL_CANVAS_INPAINT_GRAPH, SDXL_CANVAS_OUTPAINT_GRAPH].includes( + graph.id + ) + ) { + graph.edges.push({ + source: { + node_id: currentLoraNodeId, + field: 'unet', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'unet', + }, + }); + } + graph.edges.push({ source: { node_id: currentLoraNodeId, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index 4f83868d67..4b017340cb 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -17,8 +17,10 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { CANVAS_INPAINT_GRAPH, CANVAS_OUTPUT, + CANVAS_COHERENCE_DENOISE_LATENTS, + CANVAS_COHERENCE_NOISE, + CANVAS_COHERENCE_NOISE_INCREMENT, CLIP_SKIP, - COLOR_CORRECT, DENOISE_LATENTS, INPAINT_IMAGE, INPAINT_IMAGE_RESIZE_DOWN, @@ -61,6 +63,8 @@ export const buildCanvasInpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, + canvasCoherenceSteps, + canvasCoherenceStrength, clipSkip, } = state.generation; @@ -139,23 +143,39 @@ export const buildCanvasInpaintGraph = ( denoising_start: 1 - strength, denoising_end: 1, }, + [CANVAS_COHERENCE_NOISE]: { + type: 'noise', + id: NOISE, + use_cpu, + is_intermediate: true, + }, + [CANVAS_COHERENCE_NOISE_INCREMENT]: { + type: 'add', + id: CANVAS_COHERENCE_NOISE_INCREMENT, + b: 1, + is_intermediate: true, + }, + [CANVAS_COHERENCE_DENOISE_LATENTS]: { + type: 'denoise_latents', + id: DENOISE_LATENTS, + is_intermediate: true, + steps: canvasCoherenceSteps, + cfg_scale: cfg_scale, + scheduler: scheduler, + denoising_start: 1 - canvasCoherenceStrength, + denoising_end: 1, + }, [LATENTS_TO_IMAGE]: { type: 'l2i', id: LATENTS_TO_IMAGE, is_intermediate: true, fp32: vaePrecision === 'fp32' ? true : false, }, - [COLOR_CORRECT]: { - type: 'color_correct', - id: COLOR_CORRECT, - is_intermediate: true, - reference: canvasInitImage, - }, [CANVAS_OUTPUT]: { - type: 'img_paste', + type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate: !shouldAutoSave, - base_image: canvasInitImage, + reference: canvasInitImage, }, [RANGE_OF_SIZE]: { type: 'range_of_size', @@ -287,12 +307,83 @@ export const buildCanvasInpaintGraph = ( field: 'seed', }, }, - // Decode Inpainted Latents To Image + // Canvas Refine + { + source: { + node_id: ITERATE, + field: 'item', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'a', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'value', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'seed', + }, + }, + { + source: { + node_id: MAIN_MODEL_LOADER, + field: 'unet', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'unet', + }, + }, + { + source: { + node_id: POSITIVE_CONDITIONING, + field: 'conditioning', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'positive_conditioning', + }, + }, + { + source: { + node_id: NEGATIVE_CONDITIONING, + field: 'conditioning', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'negative_conditioning', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'noise', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'noise', + }, + }, { source: { node_id: DENOISE_LATENTS, field: 'latents', }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'latents', + }, + }, + // Decode Inpainted Latents To Image + { + source: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'latents', + }, destination: { node_id: LATENTS_TO_IMAGE, field: 'latents', @@ -338,11 +429,12 @@ export const buildCanvasInpaintGraph = ( height: height, }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: scaledWidth, - height: scaledHeight, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth; + (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = + scaledWidth; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = + scaledHeight; // Connect Nodes graph.edges.push( @@ -384,7 +476,7 @@ export const buildCanvasInpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'image', }, }, @@ -398,27 +490,6 @@ export const buildCanvasInpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: MASK_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Back Onto Original Image - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'image', - }, - }, { source: { node_id: MASK_RESIZE_DOWN, @@ -432,11 +503,11 @@ export const buildCanvasInpaintGraph = ( ); } else { // Add Images To Nodes - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: width, - height: height, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = width; + (graph.nodes[NOISE] as NoiseInvocation).height = height; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height; + graph.nodes[INPAINT_IMAGE] = { ...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation), image: canvasInitImage, @@ -453,27 +524,6 @@ export const buildCanvasInpaintGraph = ( node_id: LATENTS_TO_IMAGE, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: MASK_BLUR, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Back Onto Original Image - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 379f864549..9f424d3dcf 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -19,8 +19,10 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { CANVAS_OUTPAINT_GRAPH, CANVAS_OUTPUT, + CANVAS_COHERENCE_DENOISE_LATENTS, + CANVAS_COHERENCE_NOISE, + CANVAS_COHERENCE_NOISE_INCREMENT, CLIP_SKIP, - COLOR_CORRECT, DENOISE_LATENTS, INPAINT_IMAGE, INPAINT_IMAGE_RESIZE_DOWN, @@ -32,7 +34,6 @@ import { MAIN_MODEL_LOADER, MASK_BLUR, MASK_COMBINE, - MASK_EDGE, MASK_FROM_ALPHA, MASK_RESIZE_DOWN, MASK_RESIZE_UP, @@ -41,10 +42,6 @@ import { POSITIVE_CONDITIONING, RANDOM_INT, RANGE_OF_SIZE, - SEAM_FIX_DENOISE_LATENTS, - SEAM_MASK_COMBINE, - SEAM_MASK_RESIZE_DOWN, - SEAM_MASK_RESIZE_UP, } from './constants'; /** @@ -72,12 +69,8 @@ export const buildCanvasOutpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, - seamSize, - seamBlur, - seamSteps, - seamStrength, - seamLowThreshold, - seamHighThreshold, + canvasCoherenceSteps, + canvasCoherenceStrength, tileSize, infillMethod, clipSkip, @@ -141,11 +134,6 @@ export const buildCanvasOutpaintGraph = ( is_intermediate: true, mask2: canvasMaskImage, }, - [SEAM_MASK_COMBINE]: { - type: 'mask_combine', - id: MASK_COMBINE, - is_intermediate: true, - }, [MASK_BLUR]: { type: 'img_blur', id: MASK_BLUR, @@ -153,12 +141,6 @@ export const buildCanvasOutpaintGraph = ( radius: maskBlur, blur_type: maskBlurMethod, }, - [INPAINT_INFILL]: { - type: 'infill_tile', - id: INPAINT_INFILL, - is_intermediate: true, - tile_size: tileSize, - }, [INPAINT_IMAGE]: { type: 'i2l', id: INPAINT_IMAGE, @@ -181,23 +163,26 @@ export const buildCanvasOutpaintGraph = ( denoising_start: 1 - strength, denoising_end: 1, }, - [MASK_EDGE]: { - type: 'mask_edge', - id: MASK_EDGE, + [CANVAS_COHERENCE_NOISE]: { + type: 'noise', + id: NOISE, + use_cpu, is_intermediate: true, - edge_size: seamSize, - edge_blur: seamBlur, - low_threshold: seamLowThreshold, - high_threshold: seamHighThreshold, }, - [SEAM_FIX_DENOISE_LATENTS]: { - type: 'denoise_latents', - id: SEAM_FIX_DENOISE_LATENTS, + [CANVAS_COHERENCE_NOISE_INCREMENT]: { + type: 'add', + id: CANVAS_COHERENCE_NOISE_INCREMENT, + b: 1, is_intermediate: true, - steps: seamSteps, + }, + [CANVAS_COHERENCE_DENOISE_LATENTS]: { + type: 'denoise_latents', + id: CANVAS_COHERENCE_DENOISE_LATENTS, + is_intermediate: true, + steps: canvasCoherenceSteps, cfg_scale: cfg_scale, scheduler: scheduler, - denoising_start: 1 - seamStrength, + denoising_start: 1 - canvasCoherenceStrength, denoising_end: 1, }, [LATENTS_TO_IMAGE]: { @@ -206,13 +191,8 @@ export const buildCanvasOutpaintGraph = ( is_intermediate: true, fp32: vaePrecision === 'fp32' ? true : false, }, - [COLOR_CORRECT]: { - type: 'color_correct', - id: COLOR_CORRECT, - is_intermediate: true, - }, [CANVAS_OUTPUT]: { - type: 'img_paste', + type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate: !shouldAutoSave, }, @@ -368,14 +348,34 @@ export const buildCanvasOutpaintGraph = ( field: 'seed', }, }, - // Seam Paint + // Canvas Refine + { + source: { + node_id: ITERATE, + field: 'item', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'a', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'value', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'seed', + }, + }, { source: { node_id: MAIN_MODEL_LOADER, field: 'unet', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'unet', }, }, @@ -385,7 +385,7 @@ export const buildCanvasOutpaintGraph = ( field: 'conditioning', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'positive_conditioning', }, }, @@ -395,17 +395,17 @@ export const buildCanvasOutpaintGraph = ( field: 'conditioning', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'negative_conditioning', }, }, { source: { - node_id: NOISE, + node_id: CANVAS_COHERENCE_NOISE, field: 'noise', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'noise', }, }, @@ -415,14 +415,14 @@ export const buildCanvasOutpaintGraph = ( field: 'latents', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'latents', }, }, // Decode the result from Inpaint { source: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'latents', }, destination: { @@ -442,6 +442,23 @@ export const buildCanvasOutpaintGraph = ( }; } + if (infillMethod === 'lama') { + graph.nodes[INPAINT_INFILL] = { + type: 'infill_lama', + id: INPAINT_INFILL, + is_intermediate: true, + }; + } + + if (infillMethod === 'tile') { + graph.nodes[INPAINT_INFILL] = { + type: 'infill_tile', + id: INPAINT_INFILL, + is_intermediate: true, + tile_size: tileSize, + }; + } + // Handle Scale Before Processing if (['auto', 'manual'].includes(boundingBoxScaleMethod)) { const scaledWidth: number = scaledBoundingBoxDimensions.width; @@ -463,13 +480,6 @@ export const buildCanvasOutpaintGraph = ( width: scaledWidth, height: scaledHeight, }; - graph.nodes[SEAM_MASK_RESIZE_UP] = { - type: 'img_resize', - id: SEAM_MASK_RESIZE_UP, - is_intermediate: true, - width: scaledWidth, - height: scaledHeight, - }; graph.nodes[INPAINT_IMAGE_RESIZE_DOWN] = { type: 'img_resize', id: INPAINT_IMAGE_RESIZE_DOWN, @@ -491,19 +501,13 @@ export const buildCanvasOutpaintGraph = ( width: width, height: height, }; - graph.nodes[SEAM_MASK_RESIZE_DOWN] = { - type: 'img_resize', - id: SEAM_MASK_RESIZE_DOWN, - is_intermediate: true, - width: width, - height: height, - }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: scaledWidth, - height: scaledHeight, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth; + (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = + scaledWidth; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = + scaledHeight; // Connect Nodes graph.edges.push( @@ -539,57 +543,6 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, }, - // Seam Paint Mask - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, - field: 'mask', - }, - }, - { - source: { - node_id: MASK_BLUR, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask1', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask2', - }, - }, // Resize Results Down { source: { @@ -611,16 +564,6 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: SEAM_MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_RESIZE_DOWN, - field: 'image', - }, - }, { source: { node_id: INPAINT_INFILL, @@ -638,7 +581,7 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'reference', }, }, @@ -647,37 +590,6 @@ export const buildCanvasOutpaintGraph = ( node_id: INPAINT_IMAGE_RESIZE_DOWN, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Everything Back - { - source: { - node_id: INPAINT_INFILL_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'base_image', - }, - }, - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', @@ -685,7 +597,7 @@ export const buildCanvasOutpaintGraph = ( }, { source: { - node_id: SEAM_MASK_RESIZE_DOWN, + node_id: MASK_RESIZE_DOWN, field: 'image', }, destination: { @@ -702,11 +614,12 @@ export const buildCanvasOutpaintGraph = ( | InfillPatchMatchInvocation), image: canvasInitImage, }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: width, - height: height, - }; + + (graph.nodes[NOISE] as NoiseInvocation).width = width; + (graph.nodes[NOISE] as NoiseInvocation).height = height; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height; + graph.nodes[INPAINT_IMAGE] = { ...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation), image: canvasInitImage, @@ -727,47 +640,6 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, }, - // Seam Paint Mask - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, - field: 'mask', - }, - }, - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask1', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask2', - }, - }, // Color Correct The Inpainted Result { source: { @@ -775,7 +647,7 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'reference', }, }, @@ -784,37 +656,6 @@ export const buildCanvasOutpaintGraph = ( node_id: LATENTS_TO_IMAGE, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Everything Back - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'base_image', - }, - }, - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', @@ -822,7 +663,7 @@ export const buildCanvasOutpaintGraph = ( }, { source: { - node_id: SEAM_MASK_COMBINE, + node_id: MASK_BLUR, field: 'image', }, destination: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index 12ae969f76..f60c710c64 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -17,7 +17,9 @@ import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { CANVAS_OUTPUT, - COLOR_CORRECT, + CANVAS_COHERENCE_DENOISE_LATENTS, + CANVAS_COHERENCE_NOISE, + CANVAS_COHERENCE_NOISE_INCREMENT, INPAINT_IMAGE, INPAINT_IMAGE_RESIZE_DOWN, INPAINT_IMAGE_RESIZE_UP, @@ -61,6 +63,8 @@ export const buildCanvasSDXLInpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, + canvasCoherenceSteps, + canvasCoherenceStrength, } = state.generation; const { @@ -144,23 +148,39 @@ export const buildCanvasSDXLInpaintGraph = ( : 1 - strength, denoising_end: shouldUseSDXLRefiner ? refinerStart : 1, }, + [CANVAS_COHERENCE_NOISE]: { + type: 'noise', + id: NOISE, + use_cpu, + is_intermediate: true, + }, + [CANVAS_COHERENCE_NOISE_INCREMENT]: { + type: 'add', + id: CANVAS_COHERENCE_NOISE_INCREMENT, + b: 1, + is_intermediate: true, + }, + [CANVAS_COHERENCE_DENOISE_LATENTS]: { + type: 'denoise_latents', + id: SDXL_DENOISE_LATENTS, + is_intermediate: true, + steps: canvasCoherenceSteps, + cfg_scale: cfg_scale, + scheduler: scheduler, + denoising_start: 1 - canvasCoherenceStrength, + denoising_end: 1, + }, [LATENTS_TO_IMAGE]: { type: 'l2i', id: LATENTS_TO_IMAGE, is_intermediate: true, fp32: vaePrecision === 'fp32' ? true : false, }, - [COLOR_CORRECT]: { - type: 'color_correct', - id: COLOR_CORRECT, - is_intermediate: true, - reference: canvasInitImage, - }, [CANVAS_OUTPUT]: { - type: 'img_paste', + type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate: !shouldAutoSave, - base_image: canvasInitImage, + reference: canvasInitImage, }, [RANGE_OF_SIZE]: { type: 'range_of_size', @@ -301,12 +321,83 @@ export const buildCanvasSDXLInpaintGraph = ( field: 'seed', }, }, - // Decode inpainted latents to image + // Canvas Refine + { + source: { + node_id: ITERATE, + field: 'item', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'a', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'value', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'seed', + }, + }, + { + source: { + node_id: SDXL_MODEL_LOADER, + field: 'unet', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'unet', + }, + }, + { + source: { + node_id: POSITIVE_CONDITIONING, + field: 'conditioning', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'positive_conditioning', + }, + }, + { + source: { + node_id: NEGATIVE_CONDITIONING, + field: 'conditioning', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'negative_conditioning', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'noise', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'noise', + }, + }, { source: { node_id: SDXL_DENOISE_LATENTS, field: 'latents', }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'latents', + }, + }, + // Decode Inpainted Latents To Image + { + source: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'latents', + }, destination: { node_id: LATENTS_TO_IMAGE, field: 'latents', @@ -352,11 +443,12 @@ export const buildCanvasSDXLInpaintGraph = ( height: height, }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: scaledWidth, - height: scaledHeight, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth; + (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = + scaledWidth; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = + scaledHeight; // Connect Nodes graph.edges.push( @@ -398,7 +490,7 @@ export const buildCanvasSDXLInpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'image', }, }, @@ -412,27 +504,6 @@ export const buildCanvasSDXLInpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: MASK_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Back Onto Original Image - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'image', - }, - }, { source: { node_id: MASK_RESIZE_DOWN, @@ -446,11 +517,11 @@ export const buildCanvasSDXLInpaintGraph = ( ); } else { // Add Images To Nodes - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: width, - height: height, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = width; + (graph.nodes[NOISE] as NoiseInvocation).height = height; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height; + graph.nodes[INPAINT_IMAGE] = { ...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation), image: canvasInitImage, @@ -467,27 +538,6 @@ export const buildCanvasSDXLInpaintGraph = ( node_id: LATENTS_TO_IMAGE, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: MASK_BLUR, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Back Onto Original Image - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', @@ -528,7 +578,7 @@ export const buildCanvasSDXLInpaintGraph = ( // Add Refiner if enabled if (shouldUseSDXLRefiner) { - addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS); + addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS); } // optionally add custom VAE diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index 5dc0093f79..7e98c37233 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -19,7 +19,9 @@ import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { CANVAS_OUTPUT, - COLOR_CORRECT, + CANVAS_COHERENCE_DENOISE_LATENTS, + CANVAS_COHERENCE_NOISE, + CANVAS_COHERENCE_NOISE_INCREMENT, INPAINT_IMAGE, INPAINT_IMAGE_RESIZE_DOWN, INPAINT_IMAGE_RESIZE_UP, @@ -29,7 +31,6 @@ import { LATENTS_TO_IMAGE, MASK_BLUR, MASK_COMBINE, - MASK_EDGE, MASK_FROM_ALPHA, MASK_RESIZE_DOWN, MASK_RESIZE_UP, @@ -41,10 +42,6 @@ import { SDXL_CANVAS_OUTPAINT_GRAPH, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, - SEAM_FIX_DENOISE_LATENTS, - SEAM_MASK_COMBINE, - SEAM_MASK_RESIZE_DOWN, - SEAM_MASK_RESIZE_UP, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -72,12 +69,8 @@ export const buildCanvasSDXLOutpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, - seamSize, - seamBlur, - seamSteps, - seamStrength, - seamLowThreshold, - seamHighThreshold, + canvasCoherenceSteps, + canvasCoherenceStrength, tileSize, infillMethod, } = state.generation; @@ -144,11 +137,6 @@ export const buildCanvasSDXLOutpaintGraph = ( is_intermediate: true, mask2: canvasMaskImage, }, - [SEAM_MASK_COMBINE]: { - type: 'mask_combine', - id: MASK_COMBINE, - is_intermediate: true, - }, [MASK_BLUR]: { type: 'img_blur', id: MASK_BLUR, @@ -156,12 +144,6 @@ export const buildCanvasSDXLOutpaintGraph = ( radius: maskBlur, blur_type: maskBlurMethod, }, - [INPAINT_INFILL]: { - type: 'infill_tile', - id: INPAINT_INFILL, - is_intermediate: true, - tile_size: tileSize, - }, [INPAINT_IMAGE]: { type: 'i2l', id: INPAINT_IMAGE, @@ -186,23 +168,26 @@ export const buildCanvasSDXLOutpaintGraph = ( : 1 - strength, denoising_end: shouldUseSDXLRefiner ? refinerStart : 1, }, - [MASK_EDGE]: { - type: 'mask_edge', - id: MASK_EDGE, + [CANVAS_COHERENCE_NOISE]: { + type: 'noise', + id: NOISE, + use_cpu, is_intermediate: true, - edge_size: seamSize, - edge_blur: seamBlur, - low_threshold: seamLowThreshold, - high_threshold: seamHighThreshold, }, - [SEAM_FIX_DENOISE_LATENTS]: { - type: 'denoise_latents', - id: SEAM_FIX_DENOISE_LATENTS, + [CANVAS_COHERENCE_NOISE_INCREMENT]: { + type: 'add', + id: CANVAS_COHERENCE_NOISE_INCREMENT, + b: 1, is_intermediate: true, - steps: seamSteps, + }, + [CANVAS_COHERENCE_DENOISE_LATENTS]: { + type: 'denoise_latents', + id: CANVAS_COHERENCE_DENOISE_LATENTS, + is_intermediate: true, + steps: canvasCoherenceSteps, cfg_scale: cfg_scale, scheduler: scheduler, - denoising_start: 1 - seamStrength, + denoising_start: 1 - canvasCoherenceStrength, denoising_end: 1, }, [LATENTS_TO_IMAGE]: { @@ -211,13 +196,8 @@ export const buildCanvasSDXLOutpaintGraph = ( is_intermediate: true, fp32: vaePrecision === 'fp32' ? true : false, }, - [COLOR_CORRECT]: { - type: 'color_correct', - id: COLOR_CORRECT, - is_intermediate: true, - }, [CANVAS_OUTPUT]: { - type: 'img_paste', + type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate: !shouldAutoSave, }, @@ -382,14 +362,34 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'seed', }, }, - // Seam Paint + // Canvas Refine + { + source: { + node_id: ITERATE, + field: 'item', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'a', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_NOISE_INCREMENT, + field: 'value', + }, + destination: { + node_id: CANVAS_COHERENCE_NOISE, + field: 'seed', + }, + }, { source: { node_id: SDXL_MODEL_LOADER, field: 'unet', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'unet', }, }, @@ -399,7 +399,7 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'conditioning', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'positive_conditioning', }, }, @@ -409,17 +409,17 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'conditioning', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'negative_conditioning', }, }, { source: { - node_id: NOISE, + node_id: CANVAS_COHERENCE_NOISE, field: 'noise', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'noise', }, }, @@ -429,14 +429,14 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'latents', }, destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'latents', }, }, // Decode inpainted latents to image { source: { - node_id: SEAM_FIX_DENOISE_LATENTS, + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, field: 'latents', }, destination: { @@ -457,6 +457,23 @@ export const buildCanvasSDXLOutpaintGraph = ( }; } + if (infillMethod === 'lama') { + graph.nodes[INPAINT_INFILL] = { + type: 'infill_lama', + id: INPAINT_INFILL, + is_intermediate: true, + }; + } + + if (infillMethod === 'tile') { + graph.nodes[INPAINT_INFILL] = { + type: 'infill_tile', + id: INPAINT_INFILL, + is_intermediate: true, + tile_size: tileSize, + }; + } + // Handle Scale Before Processing if (['auto', 'manual'].includes(boundingBoxScaleMethod)) { const scaledWidth: number = scaledBoundingBoxDimensions.width; @@ -478,13 +495,6 @@ export const buildCanvasSDXLOutpaintGraph = ( width: scaledWidth, height: scaledHeight, }; - graph.nodes[SEAM_MASK_RESIZE_UP] = { - type: 'img_resize', - id: SEAM_MASK_RESIZE_UP, - is_intermediate: true, - width: scaledWidth, - height: scaledHeight, - }; graph.nodes[INPAINT_IMAGE_RESIZE_DOWN] = { type: 'img_resize', id: INPAINT_IMAGE_RESIZE_DOWN, @@ -506,19 +516,13 @@ export const buildCanvasSDXLOutpaintGraph = ( width: width, height: height, }; - graph.nodes[SEAM_MASK_RESIZE_DOWN] = { - type: 'img_resize', - id: SEAM_MASK_RESIZE_DOWN, - is_intermediate: true, - width: width, - height: height, - }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: scaledWidth, - height: scaledHeight, - }; + (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth; + (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = + scaledWidth; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = + scaledHeight; // Connect Nodes graph.edges.push( @@ -554,57 +558,6 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, }, - // Seam Paint Mask - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, - field: 'mask', - }, - }, - { - source: { - node_id: MASK_BLUR, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask1', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask2', - }, - }, // Resize Results Down { source: { @@ -626,16 +579,6 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: SEAM_MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_RESIZE_DOWN, - field: 'image', - }, - }, { source: { node_id: INPAINT_INFILL, @@ -653,7 +596,7 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'reference', }, }, @@ -662,37 +605,6 @@ export const buildCanvasSDXLOutpaintGraph = ( node_id: INPAINT_IMAGE_RESIZE_DOWN, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Everything Back - { - source: { - node_id: INPAINT_INFILL_RESIZE_DOWN, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'base_image', - }, - }, - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', @@ -700,7 +612,7 @@ export const buildCanvasSDXLOutpaintGraph = ( }, { source: { - node_id: SEAM_MASK_RESIZE_DOWN, + node_id: MASK_RESIZE_DOWN, field: 'image', }, destination: { @@ -717,11 +629,12 @@ export const buildCanvasSDXLOutpaintGraph = ( | InfillPatchMatchInvocation), image: canvasInitImage, }; - graph.nodes[NOISE] = { - ...(graph.nodes[NOISE] as NoiseInvocation), - width: width, - height: height, - }; + + (graph.nodes[NOISE] as NoiseInvocation).width = width; + (graph.nodes[NOISE] as NoiseInvocation).height = height; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width; + (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height; + graph.nodes[INPAINT_IMAGE] = { ...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation), image: canvasInitImage, @@ -742,47 +655,6 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, }, - // Seam Paint Mask - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_FIX_DENOISE_LATENTS, - field: 'mask', - }, - }, - { - source: { - node_id: MASK_FROM_ALPHA, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask1', - }, - }, - { - source: { - node_id: MASK_EDGE, - field: 'image', - }, - destination: { - node_id: SEAM_MASK_COMBINE, - field: 'mask2', - }, - }, // Color Correct The Inpainted Result { source: { @@ -790,7 +662,7 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, destination: { - node_id: COLOR_CORRECT, + node_id: CANVAS_OUTPUT, field: 'reference', }, }, @@ -799,37 +671,6 @@ export const buildCanvasSDXLOutpaintGraph = ( node_id: LATENTS_TO_IMAGE, field: 'image', }, - destination: { - node_id: COLOR_CORRECT, - field: 'image', - }, - }, - { - source: { - node_id: SEAM_MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: COLOR_CORRECT, - field: 'mask', - }, - }, - // Paste Everything Back - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_OUTPUT, - field: 'base_image', - }, - }, - { - source: { - node_id: COLOR_CORRECT, - field: 'image', - }, destination: { node_id: CANVAS_OUTPUT, field: 'image', @@ -837,7 +678,7 @@ export const buildCanvasSDXLOutpaintGraph = ( }, { source: { - node_id: SEAM_MASK_COMBINE, + node_id: MASK_BLUR, field: 'image', }, destination: { @@ -870,7 +711,7 @@ export const buildCanvasSDXLOutpaintGraph = ( // Add Refiner if enabled if (shouldUseSDXLRefiner) { - addSDXLRefinerToGraph(state, graph, SEAM_FIX_DENOISE_LATENTS); + addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS); } // optionally add custom VAE 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 1f6acd4e26..6547d4a092 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts @@ -25,14 +25,15 @@ export const INPAINT_IMAGE_RESIZE_DOWN = 'inpaint_image_resize_down'; export const INPAINT_INFILL = 'inpaint_infill'; export const INPAINT_INFILL_RESIZE_DOWN = 'inpaint_infill_resize_down'; export const INPAINT_FINAL_IMAGE = 'inpaint_final_image'; -export const SEAM_FIX_DENOISE_LATENTS = 'seam_fix_denoise_latents'; +export const CANVAS_COHERENCE_DENOISE_LATENTS = + 'canvas_coherence_denoise_latents'; +export const CANVAS_COHERENCE_NOISE = 'canvas_coherence_noise'; +export const CANVAS_COHERENCE_NOISE_INCREMENT = + 'canvas_coherence_noise_increment'; export const MASK_FROM_ALPHA = 'tomask'; export const MASK_EDGE = 'mask_edge'; export const MASK_BLUR = 'mask_blur'; export const MASK_COMBINE = 'mask_combine'; -export const SEAM_MASK_COMBINE = 'seam_mask_combine'; -export const SEAM_MASK_RESIZE_UP = 'seam_mask_resize_up'; -export const SEAM_MASK_RESIZE_DOWN = 'seam_mask_resize_down'; export const MASK_RESIZE_UP = 'mask_resize_up'; export const MASK_RESIZE_DOWN = 'mask_resize_down'; export const COLOR_CORRECT = 'color_correct'; diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index e237ecbfe4..4bbb754d58 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -14,13 +14,34 @@ import { } from '../types/types'; import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders'; -const RESERVED_FIELD_NAMES = ['id', 'type', 'metadata']; +const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata']; +const RESERVED_OUTPUT_FIELD_NAMES = ['type']; const invocationDenylist: AnyInvocationType[] = [ 'graph', 'metadata_accumulator', ]; +const isAllowedInputField = (nodeType: string, fieldName: string) => { + if (RESERVED_INPUT_FIELD_NAMES.includes(fieldName)) { + return false; + } + if (nodeType === 'collect' && fieldName === 'collection') { + return false; + } + if (nodeType === 'iterate' && fieldName === 'index') { + return false; + } + return true; +}; + +const isAllowedOutputField = (nodeType: string, fieldName: string) => { + if (RESERVED_OUTPUT_FIELD_NAMES.includes(fieldName)) { + return false; + } + return true; +}; + const isNotInDenylist = (schema: InvocationSchemaObject) => !invocationDenylist.includes(schema.properties.type.default); @@ -42,17 +63,28 @@ export const parseSchema = ( const inputs = reduce( schema.properties, (inputsAccumulator, property, propertyName) => { - if ( - !RESERVED_FIELD_NAMES.includes(propertyName) && - isInvocationFieldSchema(property) && - !property.ui_hidden - ) { - const field = buildInputFieldTemplate(schema, property, propertyName); - - if (field) { - inputsAccumulator[propertyName] = field; - } + if (!isAllowedInputField(type, propertyName)) { + logger('nodes').trace( + { type, propertyName, property: parseify(property) }, + 'Skipped reserved input field' + ); + return inputsAccumulator; } + + if (!isInvocationFieldSchema(property)) { + logger('nodes').warn( + { type, propertyName, property: parseify(property) }, + 'Unhandled input property' + ); + return inputsAccumulator; + } + + const field = buildInputFieldTemplate(schema, property, propertyName); + + if (field) { + inputsAccumulator[propertyName] = field; + } + return inputsAccumulator; }, {} as Record @@ -82,26 +114,39 @@ export const parseSchema = ( throw 'Invalid output schema'; } + const outputType = outputSchema.properties.type.default; + const outputs = reduce( - outputSchema.properties as OpenAPIV3.SchemaObject, + outputSchema.properties, (outputsAccumulator, property, propertyName) => { - if ( - !['type', 'id'].includes(propertyName) && - !['object'].includes(property.type) && // TODO: handle objects? - isInvocationFieldSchema(property) - ) { - const fieldType = getFieldType(property); - outputsAccumulator[propertyName] = { - fieldKind: 'output', - name: propertyName, - title: property.title ?? '', - description: property.description ?? '', - type: fieldType, - }; - } else { - logger('nodes').warn({ property }, 'Unhandled output property'); + if (!isAllowedOutputField(type, propertyName)) { + logger('nodes').trace( + { type, propertyName, property: parseify(property) }, + 'Skipped reserved output field' + ); + return outputsAccumulator; } + if (!isInvocationFieldSchema(property)) { + logger('nodes').warn( + { type, propertyName, property: parseify(property) }, + 'Unhandled output property' + ); + return outputsAccumulator; + } + + const fieldType = getFieldType(property); + outputsAccumulator[propertyName] = { + fieldKind: 'output', + name: propertyName, + title: property.title ?? '', + description: property.description ?? '', + type: fieldType, + ui_hidden: property.ui_hidden ?? false, + ui_type: property.ui_type, + ui_order: property.ui_order, + }; + return outputsAccumulator; }, {} as Record @@ -114,6 +159,7 @@ export const parseSchema = ( description, inputs, outputs, + outputType, }; Object.assign(acc, { [type]: invocation }); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx index 9ac0e3588f..2a8f1ece69 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx @@ -27,7 +27,9 @@ const ParamInfillMethod = () => { const { data: appConfigData, isLoading } = useGetAppConfigQuery(); - const infill_methods = appConfigData?.infill_methods; + const infill_methods = appConfigData?.infill_methods.filter( + (method) => method !== 'lama' + ); const { t } = useTranslation(); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx new file mode 100644 index 0000000000..b454c4ccec --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx @@ -0,0 +1,21 @@ +import { Flex } from '@chakra-ui/react'; +import IAICollapse from 'common/components/IAICollapse'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import ParamCanvasCoherenceSteps from './ParamCanvasCoherenceSteps'; +import ParamCanvasCoherenceStrength from './ParamCanvasCoherenceStrength'; + +const ParamCanvasCoherencePassCollapse = () => { + const { t } = useTranslation(); + + return ( + + + + + + + ); +}; + +export default memo(ParamCanvasCoherencePassCollapse); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx similarity index 54% rename from invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx rename to invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx index e69339dbfe..5482a7e1d9 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx @@ -1,36 +1,36 @@ import type { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; -import { setSeamSteps } from 'features/parameters/store/generationSlice'; +import { setCanvasCoherenceSteps } from 'features/parameters/store/generationSlice'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -const ParamSeamSteps = () => { +const ParamCanvasCoherenceSteps = () => { const dispatch = useAppDispatch(); - const seamSteps = useAppSelector( - (state: RootState) => state.generation.seamSteps + const canvasCoherenceSteps = useAppSelector( + (state: RootState) => state.generation.canvasCoherenceSteps ); const { t } = useTranslation(); return ( { - dispatch(setSeamSteps(v)); + dispatch(setCanvasCoherenceSteps(v)); }} withInput withSliderMarks withReset handleReset={() => { - dispatch(setSeamSteps(20)); + dispatch(setCanvasCoherenceSteps(20)); }} /> ); }; -export default memo(ParamSeamSteps); +export default memo(ParamCanvasCoherenceSteps); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx similarity index 54% rename from invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx rename to invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx index 3f0fa01fcb..f478bd70fe 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx @@ -1,36 +1,36 @@ import type { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; -import { setSeamStrength } from 'features/parameters/store/generationSlice'; +import { setCanvasCoherenceStrength } from 'features/parameters/store/generationSlice'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -const ParamSeamStrength = () => { +const ParamCanvasCoherenceStrength = () => { const dispatch = useAppDispatch(); - const seamStrength = useAppSelector( - (state: RootState) => state.generation.seamStrength + const canvasCoherenceStrength = useAppSelector( + (state: RootState) => state.generation.canvasCoherenceStrength ); const { t } = useTranslation(); return ( { - dispatch(setSeamStrength(v)); + dispatch(setCanvasCoherenceStrength(v)); }} withInput withSliderMarks withReset handleReset={() => { - dispatch(setSeamStrength(0.7)); + dispatch(setCanvasCoherenceStrength(0.3)); }} /> ); }; -export default memo(ParamSeamStrength); +export default memo(ParamCanvasCoherenceStrength); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx deleted file mode 100644 index 2ab048ce72..0000000000 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { RootState } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAISlider from 'common/components/IAISlider'; -import { setSeamBlur } from 'features/parameters/store/generationSlice'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; - -const ParamSeamBlur = () => { - const dispatch = useAppDispatch(); - const seamBlur = useAppSelector( - (state: RootState) => state.generation.seamBlur - ); - const { t } = useTranslation(); - - return ( - { - dispatch(setSeamBlur(v)); - }} - withInput - withSliderMarks - withReset - handleReset={() => { - dispatch(setSeamBlur(8)); - }} - /> - ); -}; - -export default memo(ParamSeamBlur); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx deleted file mode 100644 index 23e06797e5..0000000000 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Flex } from '@chakra-ui/react'; -import IAICollapse from 'common/components/IAICollapse'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import ParamSeamBlur from './ParamSeamBlur'; -import ParamSeamSize from './ParamSeamSize'; -import ParamSeamSteps from './ParamSeamSteps'; -import ParamSeamStrength from './ParamSeamStrength'; -import ParamSeamThreshold from './ParamSeamThreshold'; - -const ParamSeamPaintingCollapse = () => { - const { t } = useTranslation(); - - return ( - - - - - - - - - - ); -}; - -export default memo(ParamSeamPaintingCollapse); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx deleted file mode 100644 index 841e9555fd..0000000000 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { RootState } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAISlider from 'common/components/IAISlider'; -import { setSeamSize } from 'features/parameters/store/generationSlice'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; - -const ParamSeamSize = () => { - const dispatch = useAppDispatch(); - const seamSize = useAppSelector( - (state: RootState) => state.generation.seamSize - ); - const { t } = useTranslation(); - - return ( - { - dispatch(setSeamSize(v)); - }} - withInput - withSliderMarks - withReset - handleReset={() => { - dispatch(setSeamSize(16)); - }} - /> - ); -}; - -export default memo(ParamSeamSize); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx deleted file mode 100644 index f40491db98..0000000000 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { - FormControl, - FormLabel, - HStack, - RangeSlider, - RangeSliderFilledTrack, - RangeSliderMark, - RangeSliderThumb, - RangeSliderTrack, - Tooltip, -} from '@chakra-ui/react'; -import type { RootState } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIIconButton from 'common/components/IAIIconButton'; -import { - setSeamHighThreshold, - setSeamLowThreshold, -} from 'features/parameters/store/generationSlice'; -import { memo, useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { BiReset } from 'react-icons/bi'; - -const ParamSeamThreshold = () => { - const dispatch = useAppDispatch(); - const seamLowThreshold = useAppSelector( - (state: RootState) => state.generation.seamLowThreshold - ); - - const seamHighThreshold = useAppSelector( - (state: RootState) => state.generation.seamHighThreshold - ); - const { t } = useTranslation(); - - const handleSeamThresholdChange = useCallback( - (v: number[]) => { - dispatch(setSeamLowThreshold(v[0] as number)); - dispatch(setSeamHighThreshold(v[1] as number)); - }, - [dispatch] - ); - - const handleSeamThresholdReset = () => { - dispatch(setSeamLowThreshold(100)); - dispatch(setSeamHighThreshold(200)); - }; - - return ( - - {t('parameters.seamThreshold')} - - - - - - - - - - - - - 0 - - - 100 - - - 200 - - - 255 - - - } - onClick={handleSeamThresholdReset} - /> - - - ); -}; - -export default memo(ParamSeamThreshold); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx index c4d2d35f8f..9732e34c84 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx @@ -69,31 +69,29 @@ const ParamControlNetCollapse = () => { return ( - - - - - + + + } isDisabled={!firstModel} flexGrow={1} - size="md" + size="sm" onClick={handleClickedAddControlNet} /> diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx index 923ba1546d..ca45da121f 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx @@ -23,9 +23,8 @@ import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus'; const promptInputSelector = createSelector( [stateSelector, activeTabNameSelector], - ({ generation, ui }, activeTabName) => { + ({ generation }, activeTabName) => { return { - shouldPinParametersPanel: ui.shouldPinParametersPanel, prompt: generation.positivePrompt, activeTabName, }; @@ -42,8 +41,7 @@ const promptInputSelector = createSelector( */ const ParamPositiveConditioning = () => { const dispatch = useAppDispatch(); - const { prompt, shouldPinParametersPanel, activeTabName } = - useAppSelector(promptInputSelector); + const { prompt, activeTabName } = useAppSelector(promptInputSelector); const isReady = useIsReadyToInvoke(); const promptRef = useRef(null); const { isOpen, onClose, onOpen } = useDisclosure(); @@ -148,7 +146,7 @@ const ParamPositiveConditioning = () => { diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx index 960b4cd773..ee08d4ca99 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx @@ -49,7 +49,7 @@ const InitialImageDisplay = () => { alignItems: 'center', justifyContent: 'center', borderRadius: 'base', - p: 4, + p: 2, gap: 4, }} > @@ -64,6 +64,7 @@ const InitialImageDisplay = () => { > & { btnGroupWidth?: string | number; -} + asIconButton?: boolean; +}; -const CancelButton = ( - props: CancelButtonProps & Omit -) => { +const CancelButton = (props: Props) => { const dispatch = useAppDispatch(); - const { btnGroupWidth = 'auto', ...rest } = props; + const { btnGroupWidth = 'auto', asIconButton = false, ...rest } = props; const { isProcessing, isConnected, @@ -124,16 +124,31 @@ const CancelButton = ( return ( - + {asIconButton ? ( + + ) : ( + + Cancel + + )}

{ - const { autoAddBoardId } = gallery; - - return { - isBusy, - autoAddBoardId, - activeTabName, - }; - }, - defaultSelectorOptions -); - interface InvokeButton extends Omit { - iconButton?: boolean; + asIconButton?: boolean; } export default function InvokeButton(props: InvokeButton) { - const { iconButton = false, ...rest } = props; + const { asIconButton = false, sx, ...rest } = props; const dispatch = useAppDispatch(); const { isReady, isProcessing } = useIsReadyToInvoke(); - const { activeTabName } = useAppSelector(selector); + const activeTabName = useAppSelector(activeTabNameSelector); const handleInvoke = useCallback(() => { dispatch(clampSymmetrySteps()); @@ -87,21 +59,22 @@ export default function InvokeButton(props: InvokeButton) { {!isReady && ( )} - {iconButton ? ( + {asIconButton ? ( ) : ( } aria-label={t('parameters.invoke')} type="submit" + data-progress={isProcessing} isDisabled={!isReady} onClick={handleInvoke} colorScheme="accent" @@ -131,13 +106,13 @@ export default function InvokeButton(props: InvokeButton) { leftIcon={isProcessing ? undefined : } isLoading={isProcessing} loadingText={t('parameters.invoke')} - {...rest} sx={{ w: 'full', flexGrow: 1, fontWeight: 700, - ...(isProcessing ? IN_PROGRESS_STYLES : {}), + ...sx, }} + {...rest} > Invoke @@ -147,9 +122,21 @@ export default function InvokeButton(props: InvokeButton) { ); } +const tooltipSelector = createSelector( + [stateSelector], + ({ gallery }) => { + const { autoAddBoardId } = gallery; + + return { + autoAddBoardId, + }; + }, + defaultSelectorOptions +); + export const InvokeButtonTooltipContent = memo(() => { const { isReady, reasons } = useIsReadyToInvoke(); - const { autoAddBoardId } = useAppSelector(selector); + const { autoAddBoardId } = useAppSelector(tooltipSelector); const autoAddBoardName = useBoardName(autoAddBoardId); return ( @@ -166,7 +153,11 @@ export const InvokeButtonTooltipContent = memo(() => { ))} )} - + Adding images to{' '} diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx index ebd60b14bd..41f1f3c918 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx @@ -1,14 +1,14 @@ import { Flex } from '@chakra-ui/react'; +import { memo } from 'react'; import CancelButton from './CancelButton'; import InvokeButton from './InvokeButton'; -import { memo } from 'react'; /** * Buttons to start and cancel image generation. */ const ProcessButtons = () => { return ( - + diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index c7ab83cc00..8a4b9a7963 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -37,12 +37,8 @@ export interface GenerationState { scheduler: SchedulerParam; maskBlur: number; maskBlurMethod: MaskBlurMethodParam; - seamSize: number; - seamBlur: number; - seamSteps: number; - seamStrength: StrengthParam; - seamLowThreshold: number; - seamHighThreshold: number; + canvasCoherenceSteps: number; + canvasCoherenceStrength: StrengthParam; seed: SeedParam; seedWeights: string; shouldFitToWidthHeight: boolean; @@ -80,12 +76,8 @@ export const initialGenerationState: GenerationState = { scheduler: 'euler', maskBlur: 16, maskBlurMethod: 'box', - seamSize: 16, - seamBlur: 8, - seamSteps: 20, - seamStrength: 0.7, - seamLowThreshold: 100, - seamHighThreshold: 200, + canvasCoherenceSteps: 20, + canvasCoherenceStrength: 0.3, seed: 0, seedWeights: '', shouldFitToWidthHeight: true, @@ -212,23 +204,11 @@ export const generationSlice = createSlice({ setMaskBlurMethod: (state, action: PayloadAction) => { state.maskBlurMethod = action.payload; }, - setSeamSize: (state, action: PayloadAction) => { - state.seamSize = action.payload; + setCanvasCoherenceSteps: (state, action: PayloadAction) => { + state.canvasCoherenceSteps = action.payload; }, - setSeamBlur: (state, action: PayloadAction) => { - state.seamBlur = action.payload; - }, - setSeamSteps: (state, action: PayloadAction) => { - state.seamSteps = action.payload; - }, - setSeamStrength: (state, action: PayloadAction) => { - state.seamStrength = action.payload; - }, - setSeamLowThreshold: (state, action: PayloadAction) => { - state.seamLowThreshold = action.payload; - }, - setSeamHighThreshold: (state, action: PayloadAction) => { - state.seamHighThreshold = action.payload; + setCanvasCoherenceStrength: (state, action: PayloadAction) => { + state.canvasCoherenceStrength = action.payload; }, setTileSize: (state, action: PayloadAction) => { state.tileSize = action.payload; @@ -338,12 +318,8 @@ export const { setScheduler, setMaskBlur, setMaskBlurMethod, - setSeamSize, - setSeamBlur, - setSeamSteps, - setSeamStrength, - setSeamLowThreshold, - setSeamHighThreshold, + setCanvasCoherenceSteps, + setCanvasCoherenceStrength, setSeed, setSeedWeights, setShouldFitToWidthHeight, diff --git a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts index 25905e1e14..e210efc414 100644 --- a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts +++ b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts @@ -210,7 +210,7 @@ export type HeightParam = z.infer; export const isValidHeight = (val: unknown): val is HeightParam => zHeight.safeParse(val).success; -const zBaseModel = z.enum(['sd-1', 'sd-2', 'sdxl', 'sdxl-refiner']); +export const zBaseModel = z.enum(['sd-1', 'sd-2', 'sdxl', 'sdxl-refiner']); export type BaseModelParam = z.infer; diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx index 7d51c6dea7..057ee6fe78 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx @@ -9,10 +9,6 @@ export default function ParamSDXLConcatButton() { (state: RootState) => state.sdxl.shouldConcatSDXLStylePrompt ); - const shouldPinParametersPanel = useAppSelector( - (state: RootState) => state.ui.shouldPinParametersPanel - ); - const dispatch = useAppDispatch(); const handleShouldConcatPromptChange = () => { @@ -31,7 +27,7 @@ export default function ParamSDXLConcatButton() { sx={{ position: 'absolute', insetInlineEnd: 1, - top: shouldPinParametersPanel ? 12 : 20, + top: 6, border: 'none', color: shouldConcatSDXLStylePrompt ? 'accent.500' : 'base.500', _hover: { diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx index 5c2df5c1bb..4667ca63c0 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx @@ -2,17 +2,15 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; +import { memo } from 'react'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse'; import SDXLImageToImageTabCoreParameters from './SDXLImageToImageTabCoreParameters'; -import { memo } from 'react'; const SDXLImageToImageTabParameters = () => { return ( <> - diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx index 46d8ad3558..084c12af61 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx @@ -2,17 +2,15 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters'; +import { memo } from 'react'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse'; -import { memo } from 'react'; const SDXLTextToImageTabParameters = () => { return ( <> - diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx index 74833ebd70..00432bcec8 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx @@ -2,10 +2,9 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse'; import ParamMaskAdjustmentCollapse from 'features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskAdjustmentCollapse'; -import ParamSeamPaintingCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse'; +import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse'; import SDXLUnifiedCanvasTabCoreParameters from './SDXLUnifiedCanvasTabCoreParameters'; @@ -14,7 +13,6 @@ export default function SDXLUnifiedCanvasTabParameters() { return ( <> - @@ -23,7 +21,7 @@ export default function SDXLUnifiedCanvasTabParameters() { - + ); } diff --git a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx index 12c25dcb6b..029444b776 100644 --- a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx @@ -60,11 +60,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: t('hotkeys.toggleOptions.desc'), hotkey: 'O', }, - { - title: t('hotkeys.pinOptions.title'), - desc: t('hotkeys.pinOptions.desc'), - hotkey: 'Shift+O', - }, { title: t('hotkeys.toggleGallery.title'), desc: t('hotkeys.toggleGallery.desc'), @@ -136,11 +131,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: t('hotkeys.nextImage.desc'), hotkey: 'Arrow Right', }, - { - title: t('hotkeys.toggleGalleryPin.title'), - desc: t('hotkeys.toggleGalleryPin.desc'), - hotkey: 'Shift+G', - }, { title: t('hotkeys.increaseGalleryThumbSize.title'), desc: t('hotkeys.increaseGalleryThumbSize.desc'), @@ -290,7 +280,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { { title: t('hotkeys.addNodes.title'), desc: t('hotkeys.addNodes.desc'), - hotkey: 'Shift + A', + hotkey: 'Shift + A / Space', }, ]; diff --git a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx index a81d898975..10349afd52 100644 --- a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx +++ b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx @@ -15,7 +15,7 @@ const InvokeAILogoComponent = ({ showVersion = true }: Props) => { const isHovered = useHoverDirty(ref); return ( - + invoke-ai-logo void; +}; + +const ResetWebUIButton = ({ onSettingsModalClose }: Props) => { + const { t } = useTranslation(); + const [countdown, setCountdown] = useState(5); + + const { + isOpen: isRefreshModalOpen, + onOpen: onRefreshModalOpen, + onClose: onRefreshModalClose, + } = useDisclosure(); + + const handleClickResetWebUI = useCallback(() => { + // Only remove our keys + Object.keys(window.localStorage).forEach((key) => { + if ( + LOCALSTORAGE_KEYS.includes(key) || + key.startsWith(LOCALSTORAGE_PREFIX) + ) { + localStorage.removeItem(key); + } + }); + onSettingsModalClose(); + onRefreshModalOpen(); + setInterval(() => setCountdown((prev) => prev - 1), 1000); + }, [onSettingsModalClose, onRefreshModalOpen]); + + useEffect(() => { + if (countdown <= 0) { + window.location.reload(); + } + }, [countdown]); + + return ( + <> + + {t('settings.resetWebUI')} + + + + + + + + + {t('settings.resetComplete')} + Reloading in {countdown}... + + + + + + + + ); +}; + +export default memo(ResetWebUIButton); diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx index 0026604203..9f9f9fc58a 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx @@ -31,7 +31,6 @@ import { } from 'features/system/store/systemSlice'; import { setShouldShowProgressInViewer, - setShouldUseCanvasBetaLayout, setShouldUseSliders, } from 'features/ui/store/uiSlice'; import { isEqual } from 'lodash-es'; @@ -42,6 +41,7 @@ import { memo, useCallback, useEffect, + useState, } from 'react'; import { useTranslation } from 'react-i18next'; import { LogLevelName } from 'roarr'; @@ -68,18 +68,13 @@ const selector = createSelector( shouldUseWatermarker, } = system; - const { - shouldUseCanvasBetaLayout, - shouldUseSliders, - shouldShowProgressInViewer, - } = ui; + const { shouldUseSliders, shouldShowProgressInViewer } = ui; const { shouldShowAdvancedOptions } = generation; return { shouldConfirmOnDelete, enableImageDebugging, - shouldUseCanvasBetaLayout, shouldUseSliders, shouldShowProgressInViewer, consoleLogLevel, @@ -98,7 +93,6 @@ const selector = createSelector( type ConfigOptions = { shouldShowDeveloperSettings: boolean; shouldShowResetWebUiText: boolean; - shouldShowBetaLayout: boolean; shouldShowAdvancedOptionsSettings: boolean; shouldShowClearIntermediates: boolean; shouldShowLocalizationToggle: boolean; @@ -113,8 +107,8 @@ type SettingsModalProps = { const SettingsModal = ({ children, config }: SettingsModalProps) => { const dispatch = useAppDispatch(); const { t } = useTranslation(); + const [countdown, setCountdown] = useState(3); - const shouldShowBetaLayout = config?.shouldShowBetaLayout ?? true; const shouldShowDeveloperSettings = config?.shouldShowDeveloperSettings ?? true; const shouldShowResetWebUiText = config?.shouldShowResetWebUiText ?? true; @@ -156,7 +150,6 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { const { shouldConfirmOnDelete, enableImageDebugging, - shouldUseCanvasBetaLayout, shouldUseSliders, shouldShowProgressInViewer, consoleLogLevel, @@ -179,8 +172,15 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { }); onSettingsModalClose(); onRefreshModalOpen(); + setInterval(() => setCountdown((prev) => prev - 1), 1000); }, [onSettingsModalClose, onRefreshModalOpen]); + useEffect(() => { + if (countdown <= 0) { + window.location.reload(); + } + }, [countdown]); + const handleLogLevelChanged = useCallback( (v: string) => { dispatch(consoleLogLevelChanged(v as LogLevelName)); @@ -297,17 +297,6 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { ) } /> - {shouldShowBetaLayout && ( - ) => - dispatch(setShouldUseCanvasBetaLayout(e.target.checked)) - } - /> - )} {shouldShowLocalizationToggle && ( { isOpen={isRefreshModalOpen} onClose={onRefreshModalClose} isCentered + closeOnEsc={false} > @@ -388,7 +378,9 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { - {t('settings.resetComplete')} + + {t('settings.resetComplete')} Reloading in {countdown}... + diff --git a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts b/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts deleted file mode 100644 index 8ba5731a5b..0000000000 --- a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/store/storeHooks'; -import { useMemo } from 'react'; -import { configSelector } from '../store/configSelectors'; -import { systemSelector } from '../store/systemSelectors'; - -const isApplicationReadySelector = createSelector( - [systemSelector, configSelector], - (system, config) => { - const { wasSchemaParsed } = system; - - const { disabledTabs } = config; - - return { - disabledTabs, - wasSchemaParsed, - }; - } -); - -/** - * Checks if the application is ready to be used, i.e. if the initial startup process is finished. - */ -export const useIsApplicationReady = () => { - const { disabledTabs, wasSchemaParsed } = useAppSelector( - isApplicationReadySelector - ); - - const isApplicationReady = useMemo(() => { - if (!disabledTabs.includes('nodes') && !wasSchemaParsed) { - return false; - } - - return true; - }, [disabledTabs, wasSchemaParsed]); - - return isApplicationReady; -}; diff --git a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts index bba279c4bc..b5376afc4f 100644 --- a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts @@ -16,7 +16,6 @@ export const systemPersistDenylist: (keyof SystemState)[] = [ 'isCancelScheduled', 'progressImage', 'wereModelsReceived', - 'wasSchemaParsed', 'isPersisted', 'isUploading', ]; diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index d789df49a4..bf8036ba98 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -2,9 +2,8 @@ import { UseToastOptions } from '@chakra-ui/react'; import { PayloadAction, createSlice, isAnyOf } from '@reduxjs/toolkit'; import { InvokeLogLevel } from 'app/logging/logger'; import { userInvoked } from 'app/store/actions'; -import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; import { t } from 'i18next'; -import { startCase, upperFirst } from 'lodash-es'; +import { get, startCase, upperFirst } from 'lodash-es'; import { LogLevelName } from 'roarr'; import { isAnySessionRejected, @@ -68,10 +67,6 @@ export interface SystemState { * Whether or not the available models were received */ wereModelsReceived: boolean; - /** - * Whether or not the OpenAPI schema was received and parsed - */ - wasSchemaParsed: boolean; /** * The console output logging level */ @@ -112,7 +107,6 @@ export const initialSystemState: SystemState = { isCancelScheduled: false, subscribedNodeIds: [], wereModelsReceived: false, - wasSchemaParsed: false, consoleLogLevel: 'debug', shouldLogToConsole: true, statusTranslationKey: 'common.statusDisconnected', @@ -339,13 +333,6 @@ export const systemSlice = createSlice({ ); }); - /** - * OpenAPI schema was parsed - */ - builder.addCase(nodeTemplatesBuilt, (state) => { - state.wasSchemaParsed = true; - }); - // *** Matchers - must be after all cases *** /** @@ -381,14 +368,14 @@ export const systemSlice = createSlice({ return; } } else if (action.payload?.error) { - errorDescription = action.payload?.error as string; + errorDescription = action.payload?.error; } state.toastQueue.push( makeToast({ title: t('toast.serverError'), status: 'error', - description: errorDescription, + description: get(errorDescription, 'detail', 'Unknown Error'), duration, }) ); diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx index af3eb72d8d..7af1a4d674 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx @@ -1,65 +1,57 @@ -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { Flex } from '@chakra-ui/layout'; +import { Portal } from '@chakra-ui/portal'; import IAIIconButton from 'common/components/IAIIconButton'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; -import { setShouldShowGallery } from 'features/ui/store/uiSlice'; -import { isEqual } from 'lodash-es'; -import { memo } from 'react'; +import { RefObject, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { MdPhotoLibrary } from 'react-icons/md'; -import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; -import { NO_GALLERY_TABS } from './InvokeTabs'; +import { ImperativePanelHandle } from 'react-resizable-panels'; -const floatingGalleryButtonSelector = createSelector( - [activeTabNameSelector, uiSelector], - (activeTabName, ui) => { - const { shouldPinGallery, shouldShowGallery } = ui; +type Props = { + isGalleryCollapsed: boolean; + galleryPanelRef: RefObject; +}; - return { - shouldPinGallery, - shouldShowGalleryButton: NO_GALLERY_TABS.includes(activeTabName) - ? false - : !shouldShowGallery, - }; - }, - { memoizeOptions: { resultEqualityCheck: isEqual } } -); - -const FloatingGalleryButton = () => { +const FloatingGalleryButton = ({ + isGalleryCollapsed, + galleryPanelRef, +}: Props) => { const { t } = useTranslation(); - const { shouldPinGallery, shouldShowGalleryButton } = useAppSelector( - floatingGalleryButtonSelector - ); - const dispatch = useAppDispatch(); const handleShowGallery = () => { - dispatch(setShouldShowGallery(true)); - shouldPinGallery && dispatch(requestCanvasRescale()); + galleryPanelRef.current?.expand(); }; - return shouldShowGalleryButton ? ( - - - - ) : null; + if (!isGalleryCollapsed) { + return null; + } + + return ( + + + } + sx={{ + p: 0, + px: 3, + h: 48, + borderStartEndRadius: 0, + borderEndEndRadius: 0, + shadow: '2xl', + }} + /> + + + ); }; export default memo(FloatingGalleryButton); diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx index 0969426339..aa24896591 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx @@ -1,20 +1,12 @@ -import { ChakraProps, Flex } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { ChakraProps, Flex, Portal } from '@chakra-ui/react'; import IAIIconButton from 'common/components/IAIIconButton'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton'; import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton'; -import { - activeTabNameSelector, - uiSelector, -} from 'features/ui/store/uiSelectors'; -import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice'; -import { isEqual } from 'lodash-es'; -import { memo } from 'react'; +import { RefObject, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { FaSlidersH } from 'react-icons/fa'; +import { ImperativePanelHandle } from 'react-resizable-panels'; const floatingButtonStyles: ChakraProps['sx'] = { borderStartStartRadius: 0, @@ -22,81 +14,48 @@ const floatingButtonStyles: ChakraProps['sx'] = { shadow: '2xl', }; -export const floatingParametersPanelButtonSelector = createSelector( - [uiSelector, activeTabNameSelector], - (ui, activeTabName) => { - const { - shouldPinParametersPanel, - shouldUseCanvasBetaLayout, - shouldShowParametersPanel, - } = ui; +type Props = { + isSidePanelCollapsed: boolean; + sidePanelRef: RefObject; +}; - const canvasBetaLayoutCheck = - shouldUseCanvasBetaLayout && activeTabName === 'unifiedCanvas'; - - const shouldShowProcessButtons = - !canvasBetaLayoutCheck && - (!shouldPinParametersPanel || !shouldShowParametersPanel); - - const shouldShowParametersPanelButton = - !canvasBetaLayoutCheck && - !shouldShowParametersPanel && - ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName); - - return { - shouldPinParametersPanel, - shouldShowParametersPanelButton, - shouldShowProcessButtons, - }; - }, - { memoizeOptions: { resultEqualityCheck: isEqual } } -); - -const FloatingParametersPanelButtons = () => { - const dispatch = useAppDispatch(); +const FloatingSidePanelButtons = ({ + isSidePanelCollapsed, + sidePanelRef, +}: Props) => { const { t } = useTranslation(); - const { - shouldShowProcessButtons, - shouldShowParametersPanelButton, - shouldPinParametersPanel, - } = useAppSelector(floatingParametersPanelButtonSelector); - const handleShowOptionsPanel = () => { - dispatch(setShouldShowParametersPanel(true)); - shouldPinParametersPanel && dispatch(requestCanvasRescale()); + const handleShowSidePanel = () => { + sidePanelRef.current?.expand(); }; - if (!shouldShowParametersPanelButton) { + if (!isSidePanelCollapsed) { return null; } return ( - - + - - - {shouldShowProcessButtons && ( - <> - - - - )} - + } + /> + + + + ); }; -export default memo(FloatingParametersPanelButtons); +export default memo(FloatingSidePanelButtons); diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx index 2dd9220288..0f5a8d92ff 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx @@ -11,12 +11,12 @@ import { } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import AuxiliaryProgressIndicator from 'app/components/AuxiliaryProgressIndicator'; -import { RootState, stateSelector } from 'app/store/store'; +import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; +import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup'; import { InvokeTabName, tabMap } from 'features/ui/store/tabMap'; -import { setActiveTab, togglePanels } from 'features/ui/store/uiSlice'; +import { setActiveTab } from 'features/ui/store/uiSlice'; import { ResourceKey } from 'i18next'; import { isEqual } from 'lodash-es'; import { MouseEvent, ReactNode, memo, useCallback, useMemo } from 'react'; @@ -25,11 +25,15 @@ import { useTranslation } from 'react-i18next'; import { FaCube, FaFont, FaImage } from 'react-icons/fa'; import { MdDeviceHub, MdGridOn } from 'react-icons/md'; import { Panel, PanelGroup } from 'react-resizable-panels'; -import { useMinimumPanelSize } from '../hooks/useMinimumPanelSize'; +import { usePanel } from '../hooks/usePanel'; +import { usePanelStorage } from '../hooks/usePanelStorage'; import { activeTabIndexSelector, activeTabNameSelector, } from '../store/uiSelectors'; +import FloatingGalleryButton from './FloatingGalleryButton'; +import FloatingSidePanelButtons from './FloatingParametersPanelButtons'; +import ParametersPanel from './ParametersPanel'; import ImageTab from './tabs/ImageToImage/ImageToImageTab'; import ModelManagerTab from './tabs/ModelManager/ModelManagerTab'; import NodesTab from './tabs/Nodes/NodesTab'; @@ -89,38 +93,20 @@ const enabledTabsSelector = createSelector( } ); -const MIN_GALLERY_WIDTH = 350; -const DEFAULT_GALLERY_PCT = 20; +const SIDE_PANEL_MIN_SIZE_PX = 448; +const MAIN_PANEL_MIN_SIZE_PX = 448; +const GALLERY_PANEL_MIN_SIZE_PX = 360; + export const NO_GALLERY_TABS: InvokeTabName[] = ['modelManager']; +export const NO_SIDE_PANEL_TABS: InvokeTabName[] = ['modelManager']; const InvokeTabs = () => { const activeTab = useAppSelector(activeTabIndexSelector); const activeTabName = useAppSelector(activeTabNameSelector); const enabledTabs = useAppSelector(enabledTabsSelector); - - const { shouldPinGallery, shouldPinParametersPanel, shouldShowGallery } = - useAppSelector((state: RootState) => state.ui); - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - useHotkeys( - 'f', - () => { - dispatch(togglePanels()); - (shouldPinGallery || shouldPinParametersPanel) && - dispatch(requestCanvasRescale()); - }, - [shouldPinGallery, shouldPinParametersPanel] - ); - - const handleResizeGallery = useCallback(() => { - if (activeTabName === 'unifiedCanvas') { - dispatch(requestCanvasRescale()); - } - }, [dispatch, activeTabName]); - const handleClickTab = useCallback((e: MouseEvent) => { if (e.target instanceof HTMLElement) { e.target.blur(); @@ -153,9 +139,6 @@ const InvokeTabs = () => { [enabledTabs] ); - const { ref: galleryPanelRef, minSizePct: galleryMinSizePct } = - useMinimumPanelSize(MIN_GALLERY_WIDTH, DEFAULT_GALLERY_PCT, 'app'); - const handleTabChange = useCallback( (index: number) => { const activeTabName = tabMap[index]; @@ -167,6 +150,60 @@ const InvokeTabs = () => { [dispatch] ); + const { + minSize: sidePanelMinSize, + isCollapsed: isSidePanelCollapsed, + setIsCollapsed: setIsSidePanelCollapsed, + ref: sidePanelRef, + reset: resetSidePanel, + expand: expandSidePanel, + collapse: collapseSidePanel, + toggle: toggleSidePanel, + } = usePanel(SIDE_PANEL_MIN_SIZE_PX, 'pixels'); + + const { + ref: galleryPanelRef, + minSize: galleryPanelMinSize, + isCollapsed: isGalleryPanelCollapsed, + setIsCollapsed: setIsGalleryPanelCollapsed, + reset: resetGalleryPanel, + expand: expandGalleryPanel, + collapse: collapseGalleryPanel, + toggle: toggleGalleryPanel, + } = usePanel(GALLERY_PANEL_MIN_SIZE_PX, 'pixels'); + + useHotkeys( + 'f', + () => { + if (isGalleryPanelCollapsed || isSidePanelCollapsed) { + expandGalleryPanel(); + expandSidePanel(); + } else { + collapseSidePanel(); + collapseGalleryPanel(); + } + }, + [dispatch, isGalleryPanelCollapsed, isSidePanelCollapsed] + ); + + useHotkeys( + ['t', 'o'], + () => { + toggleSidePanel(); + }, + [dispatch] + ); + + useHotkeys( + 'g', + () => { + toggleGalleryPanel(); + }, + [dispatch] + ); + + const panelStorage = usePanelStorage(); + return ( { autoSaveId="app" direction="horizontal" style={{ height: '100%', width: '100%' }} + storage={panelStorage} + units="pixels" > - + {!NO_SIDE_PANEL_TABS.includes(activeTabName) && ( + <> + + {activeTabName === 'nodes' ? ( + + ) : ( + + )} + + + + + )} + {tabPanels} - {shouldPinGallery && - shouldShowGallery && - !NO_GALLERY_TABS.includes(activeTabName) && ( - <> - - DEFAULT_GALLERY_PCT && - galleryMinSizePct < 100 // prevent this error https://github.com/bvaughn/react-resizable-panels/blob/main/packages/react-resizable-panels/src/Panel.ts#L96 - ? galleryMinSizePct - : DEFAULT_GALLERY_PCT - } - minSize={galleryMinSizePct} - maxSize={50} - > - - - - )} + {!NO_GALLERY_TABS.includes(activeTabName) && ( + <> + + + + + + + )} ); diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx deleted file mode 100644 index 393cb5bb34..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Flex } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; -import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters'; -import SDXLTextToImageTabParameters from 'features/sdxl/components/SDXLTextToImageTabParameters'; -import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; -import { - activeTabNameSelector, - uiSelector, -} from 'features/ui/store/uiSelectors'; -import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice'; -import { memo, useMemo } from 'react'; -import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants'; -import PinParametersPanelButton from './PinParametersPanelButton'; -import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer'; -import ImageToImageTabParameters from './tabs/ImageToImage/ImageToImageTabParameters'; -import TextToImageTabParameters from './tabs/TextToImage/TextToImageTabParameters'; -import UnifiedCanvasParameters from './tabs/UnifiedCanvas/UnifiedCanvasParameters'; - -const selector = createSelector( - [uiSelector, activeTabNameSelector], - (ui, activeTabName) => { - const { shouldPinParametersPanel, shouldShowParametersPanel } = ui; - - return { - activeTabName, - shouldPinParametersPanel, - shouldShowParametersPanel, - }; - }, - defaultSelectorOptions -); - -const ParametersDrawer = () => { - const dispatch = useAppDispatch(); - const { shouldPinParametersPanel, shouldShowParametersPanel, activeTabName } = - useAppSelector(selector); - - const handleClosePanel = () => { - dispatch(setShouldShowParametersPanel(false)); - }; - - const model = useAppSelector((state: RootState) => state.generation.model); - - const drawerContent = useMemo(() => { - if (activeTabName === 'txt2img') { - return model && model.base_model === 'sdxl' ? ( - - ) : ( - - ); - } - - if (activeTabName === 'img2img') { - return model && model.base_model === 'sdxl' ? ( - - ) : ( - - ); - } - - if (activeTabName === 'unifiedCanvas') { - return ; - } - - return null; - }, [activeTabName, model]); - - if (shouldPinParametersPanel) { - return null; - } - - return ( - - - - - - - - {drawerContent} - - - - ); -}; - -export default memo(ParametersDrawer); diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx new file mode 100644 index 0000000000..d3543db7bf --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx @@ -0,0 +1,130 @@ +import { Box, Flex } from '@chakra-ui/react'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; +import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters'; +import SDXLTextToImageTabParameters from 'features/sdxl/components/SDXLTextToImageTabParameters'; +import SDXLUnifiedCanvasTabParameters from 'features/sdxl/components/SDXLUnifiedCanvasTabParameters'; +import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; +import { PropsWithChildren, memo } from 'react'; +import { activeTabNameSelector } from '../store/uiSelectors'; +import ImageToImageTabParameters from './tabs/ImageToImage/ImageToImageTabParameters'; +import TextToImageTabParameters from './tabs/TextToImage/TextToImageTabParameters'; +import UnifiedCanvasParameters from './tabs/UnifiedCanvas/UnifiedCanvasParameters'; + +const ParametersPanel = () => { + const activeTabName = useAppSelector(activeTabNameSelector); + const model = useAppSelector((state: RootState) => state.generation.model); + + if (activeTabName === 'txt2img') { + return ( + + {model && model.base_model === 'sdxl' ? ( + + ) : ( + + )} + + ); + } + + if (activeTabName === 'img2img') { + return ( + + {model && model.base_model === 'sdxl' ? ( + + ) : ( + + )} + + ); + } + + if (activeTabName === 'unifiedCanvas') { + return ( + + {model && model.base_model === 'sdxl' ? ( + + ) : ( + + )} + + ); + } + + return null; +}; + +export default memo(ParametersPanel); + +const ParametersPanelWrapper = memo((props: PropsWithChildren) => { + return ( + + + + + + + + {props.children} + + + + + + + ); +}); + +ParametersPanelWrapper.displayName = 'ParametersPanelWrapper'; diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx deleted file mode 100644 index c7c1182d21..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Box, Flex } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/store/storeHooks'; -import { PropsWithChildren, memo } from 'react'; -import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants'; -import { uiSelector } from '../store/uiSelectors'; -import PinParametersPanelButton from './PinParametersPanelButton'; - -const selector = createSelector(uiSelector, (ui) => { - const { shouldPinParametersPanel, shouldShowParametersPanel } = ui; - - return { - shouldPinParametersPanel, - shouldShowParametersPanel, - }; -}); - -type ParametersPinnedWrapperProps = PropsWithChildren; - -const ParametersPinnedWrapper = (props: ParametersPinnedWrapperProps) => { - const { shouldPinParametersPanel, shouldShowParametersPanel } = - useAppSelector(selector); - - if (!(shouldPinParametersPanel && shouldShowParametersPanel)) { - return null; - } - - return ( - - - {props.children} - - - - - ); -}; - -export default memo(ParametersPinnedWrapper); diff --git a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx b/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx deleted file mode 100644 index dea179a704..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIIconButton, { - IAIIconButtonProps, -} from 'common/components/IAIIconButton'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; -import { useTranslation } from 'react-i18next'; -import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; -import { setShouldPinParametersPanel } from '../store/uiSlice'; -import { memo } from 'react'; - -type PinParametersPanelButtonProps = Omit; - -const PinParametersPanelButton = (props: PinParametersPanelButtonProps) => { - const { sx } = props; - const dispatch = useAppDispatch(); - const shouldPinParametersPanel = useAppSelector( - (state) => state.ui.shouldPinParametersPanel - ); - - const { t } = useTranslation(); - - const handleClickPinOptionsPanel = () => { - dispatch(setShouldPinParametersPanel(!shouldPinParametersPanel)); - dispatch(requestCanvasRescale()); - }; - - return ( - : } - variant="ghost" - size="sm" - sx={{ - color: 'base.500', - _hover: { - color: 'base.600', - }, - _active: { - color: 'base.700', - }, - _dark: { - color: 'base.500', - _hover: { - color: 'base.400', - }, - _active: { - color: 'base.300', - }, - }, - ...sx, - }} - /> - ); -}; - -export default memo(PinParametersPanelButton); diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx deleted file mode 100644 index 38e2c992dc..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx +++ /dev/null @@ -1,196 +0,0 @@ -import { - Box, - chakra, - ChakraProps, - Slide, - useOutsideClick, - useTheme, - SlideDirection, - useColorMode, -} from '@chakra-ui/react'; -import { - Resizable, - ResizableProps, - ResizeCallback, - ResizeStartCallback, -} from 're-resizable'; -import { ReactNode, memo, useEffect, useMemo, useRef, useState } from 'react'; -import { LangDirection } from './types'; -import { - getHandleEnables, - getMinMaxDimensions, - getSlideDirection, - getStyles, -} from './util'; -import { mode } from 'theme/util/mode'; - -type ResizableDrawerProps = ResizableProps & { - children: ReactNode; - isResizable: boolean; - isOpen: boolean; - onClose: () => void; - direction?: SlideDirection; - initialWidth?: number; - minWidth?: number; - maxWidth?: number; - initialHeight?: number; - minHeight?: number; - maxHeight?: number; - onResizeStart?: ResizeStartCallback; - onResizeStop?: ResizeCallback; - onResize?: ResizeCallback; - handleWidth?: string | number; - handleInteractWidth?: string | number; - sx?: ChakraProps['sx']; -}; - -const ChakraResizeable = chakra(Resizable, { - shouldForwardProp: (prop) => !['sx'].includes(prop), -}); - -const ResizableDrawer = ({ - direction = 'left', - isResizable, - isOpen, - onClose, - children, - initialWidth, - minWidth, - maxWidth, - initialHeight, - minHeight, - maxHeight, - onResizeStart, - onResizeStop, - onResize, - sx = {}, -}: ResizableDrawerProps) => { - const langDirection = useTheme().direction as LangDirection; - const { colorMode } = useColorMode(); - const outsideClickRef = useRef(null); - - const defaultWidth = useMemo( - () => - initialWidth ?? - minWidth ?? - (['left', 'right'].includes(direction) ? 'auto' : '100%'), - [initialWidth, minWidth, direction] - ); - - const defaultHeight = useMemo( - () => - initialHeight ?? - minHeight ?? - (['top', 'bottom'].includes(direction) ? 'auto' : '100%'), - [initialHeight, minHeight, direction] - ); - - const [width, setWidth] = useState(defaultWidth); - - const [height, setHeight] = useState(defaultHeight); - - useOutsideClick({ - ref: outsideClickRef, - handler: () => { - onClose(); - }, - enabled: isOpen, - }); - - const handleEnables = useMemo( - () => (isResizable ? getHandleEnables({ direction, langDirection }) : {}), - [isResizable, langDirection, direction] - ); - - const minMaxDimensions = useMemo( - () => - getMinMaxDimensions({ - direction, - minWidth, - maxWidth, - minHeight, - maxHeight, - }), - [minWidth, maxWidth, minHeight, maxHeight, direction] - ); - - const { containerStyles, handleStyles } = useMemo( - () => - getStyles({ - isResizable, - direction, - }), - [isResizable, direction] - ); - - const slideDirection = useMemo( - () => getSlideDirection(direction, langDirection), - [direction, langDirection] - ); - - useEffect(() => { - if (['left', 'right'].includes(direction)) { - setHeight('100vh'); - // setHeight(isPinned ? '100%' : '100vh'); - } - if (['top', 'bottom'].includes(direction)) { - setWidth('100vw'); - // setWidth(isPinned ? '100%' : '100vw'); - } - }, [direction]); - - return ( - - - { - onResizeStart && onResizeStart(event, direction, elementRef); - }} - onResize={(event, direction, elementRef, delta) => { - onResize && onResize(event, direction, elementRef, delta); - }} - onResizeStop={(event, direction, elementRef, delta) => { - if (['left', 'right'].includes(direction)) { - setWidth(Number(width) + delta.width); - } - if (['top', 'bottom'].includes(direction)) { - setHeight(Number(height) + delta.height); - } - onResizeStop && onResizeStop(event, direction, elementRef, delta); - }} - > - {children} - - - - ); -}; - -export default memo(ResizableDrawer); diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts deleted file mode 100644 index 5aa42ab7e5..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type Placement = 'top' | 'right' | 'bottom' | 'left'; -export type LangDirection = 'ltr' | 'rtl' | undefined; diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts deleted file mode 100644 index c9a660c297..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts +++ /dev/null @@ -1,283 +0,0 @@ -import { SlideDirection } from '@chakra-ui/react'; -import { AnimationProps } from 'framer-motion'; -import { HandleStyles } from 're-resizable'; -import { CSSProperties } from 'react'; -import { LangDirection } from './types'; - -export type GetHandleEnablesOptions = { - direction: SlideDirection; - langDirection: LangDirection; -}; - -/** - * Determine handles to enable. `re-resizable` doesn't handle RTL, so we have to do that here. - */ -export const getHandleEnables = ({ - direction, - langDirection, -}: GetHandleEnablesOptions) => { - const top = direction === 'bottom'; - - const right = - (langDirection !== 'rtl' && direction === 'left') || - (langDirection === 'rtl' && direction === 'right'); - - const bottom = direction === 'top'; - - const left = - (langDirection !== 'rtl' && direction === 'right') || - (langDirection === 'rtl' && direction === 'left'); - - return { - top, - right, - bottom, - left, - }; -}; - -export type GetDefaultSizeOptions = { - initialWidth?: string | number; - initialHeight?: string | number; - direction: SlideDirection; -}; - -// Get default sizes based on direction and initial values -export const getDefaultSize = ({ - initialWidth, - initialHeight, - direction, -}: GetDefaultSizeOptions) => { - const width = - initialWidth ?? (['left', 'right'].includes(direction) ? 500 : '100vw'); - - const height = - initialHeight ?? (['top', 'bottom'].includes(direction) ? 500 : '100vh'); - - return { width, height }; -}; - -export type GetMinMaxDimensionsOptions = { - direction: SlideDirection; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; -}; - -// Get the min/max width/height based on direction and provided values -export const getMinMaxDimensions = ({ - direction, - minWidth, - maxWidth, - minHeight, - maxHeight, -}: GetMinMaxDimensionsOptions) => { - const minW = - minWidth ?? (['left', 'right'].includes(direction) ? 10 : undefined); - - const maxW = - maxWidth ?? (['left', 'right'].includes(direction) ? '95vw' : undefined); - - const minH = - minHeight ?? (['top', 'bottom'].includes(direction) ? 10 : undefined); - - const maxH = - maxHeight ?? (['top', 'bottom'].includes(direction) ? '95vh' : undefined); - - return { - ...(minW ? { minWidth: minW } : {}), - ...(maxW ? { maxWidth: maxW } : {}), - ...(minH ? { minHeight: minH } : {}), - ...(maxH ? { maxHeight: maxH } : {}), - }; -}; - -export type GetAnimationsOptions = { - direction: SlideDirection; - langDirection: LangDirection; -}; - -// Get the framer-motion animation props, taking into account language direction -export const getAnimations = ({ - direction, - langDirection, -}: GetAnimationsOptions): AnimationProps => { - const baseAnimation = { - initial: { opacity: 0 }, - animate: { opacity: 1 }, - exit: { opacity: 0 }, - // chakra consumes the transition prop, which, for it, is a string. - // however we know the transition prop will make it to framer motion, - // which wants it as an object. cast as string to satisfy TS. - transition: { duration: 0.2, ease: 'easeInOut' }, - }; - - const langDirectionFactor = langDirection === 'rtl' ? -1 : 1; - - if (direction === 'top') { - return { - ...baseAnimation, - initial: { y: -999 }, - animate: { y: 0 }, - exit: { y: -999 }, - }; - } - - if (direction === 'right') { - return { - ...baseAnimation, - initial: { x: 999 * langDirectionFactor }, - animate: { x: 0 }, - exit: { x: 999 * langDirectionFactor }, - }; - } - - if (direction === 'bottom') { - return { - ...baseAnimation, - initial: { y: 999 }, - animate: { y: 0 }, - exit: { y: 999 }, - }; - } - - if (direction === 'left') { - return { - ...baseAnimation, - initial: { x: -999 * langDirectionFactor }, - animate: { x: 0 }, - exit: { x: -999 * langDirectionFactor }, - }; - } - - return {}; -}; - -export type GetResizableStylesProps = { - isResizable: boolean; - direction: SlideDirection; -}; - -// Expand the handle hitbox -const HANDLE_INTERACT_PADDING = '0.75rem'; - -// Visible padding around handle -const HANDLE_PADDING = '1rem'; -const HANDLE_WIDTH = '5px'; - -// Get the styles for the container and handle. Do not need to handle langDirection here bc we use direction-agnostic CSS -export const getStyles = ({ - isResizable, - direction, -}: GetResizableStylesProps): { - containerStyles: CSSProperties; // technically this could be ChakraProps['sx'], but we cannot use this for HandleStyles so leave it as CSSProperties to be consistent - handleStyles: HandleStyles; -} => { - // if (!isResizable) { - // return { containerStyles: {}, handleStyles: {} }; - // } - - // Calculate the positioning offset of the handle hitbox so it is centered over the handle - const handleOffset = `calc((2 * ${HANDLE_INTERACT_PADDING} + ${HANDLE_WIDTH}) / -2)`; - - if (direction === 'top') { - return { - containerStyles: { - borderBottomWidth: HANDLE_WIDTH, - paddingBottom: HANDLE_PADDING, - }, - handleStyles: isResizable - ? { - top: { - paddingTop: HANDLE_INTERACT_PADDING, - paddingBottom: HANDLE_INTERACT_PADDING, - bottom: handleOffset, - }, - } - : {}, - }; - } - - if (direction === 'left') { - return { - containerStyles: { - borderInlineEndWidth: HANDLE_WIDTH, - paddingInlineEnd: HANDLE_PADDING, - }, - handleStyles: isResizable - ? { - right: { - paddingInlineStart: HANDLE_INTERACT_PADDING, - paddingInlineEnd: HANDLE_INTERACT_PADDING, - insetInlineEnd: handleOffset, - }, - } - : {}, - }; - } - - if (direction === 'bottom') { - return { - containerStyles: { - borderTopWidth: HANDLE_WIDTH, - paddingTop: HANDLE_PADDING, - }, - handleStyles: isResizable - ? { - bottom: { - paddingTop: HANDLE_INTERACT_PADDING, - paddingBottom: HANDLE_INTERACT_PADDING, - top: handleOffset, - }, - } - : {}, - }; - } - - if (direction === 'right') { - return { - containerStyles: { - borderInlineStartWidth: HANDLE_WIDTH, - paddingInlineStart: HANDLE_PADDING, - }, - handleStyles: isResizable - ? { - left: { - paddingInlineStart: HANDLE_INTERACT_PADDING, - paddingInlineEnd: HANDLE_INTERACT_PADDING, - insetInlineStart: handleOffset, - }, - } - : {}, - }; - } - - return { containerStyles: {}, handleStyles: {} }; -}; - -// Chakra's Slide does not handle langDirection, so we need to do it here -export const getSlideDirection = ( - direction: SlideDirection, - langDirection: LangDirection -) => { - if (['top', 'bottom'].includes(direction)) { - return direction; - } - - if (direction === 'left') { - if (langDirection === 'rtl') { - return 'right'; - } - return 'left'; - } - - if (direction === 'right') { - if (langDirection === 'rtl') { - return 'left'; - } - return 'right'; - } - - return 'left'; -}; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx index d58630d1b9..8744fc2e0c 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx @@ -1,73 +1,57 @@ -import { Box, Flex } from '@chakra-ui/react'; -import { RootState } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; +import { Box } from '@chakra-ui/react'; import InitialImageDisplay from 'features/parameters/components/Parameters/ImageToImage/InitialImageDisplay'; -import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters'; +import { usePanelStorage } from 'features/ui/hooks/usePanelStorage'; import { memo, useCallback, useRef } from 'react'; import { ImperativePanelGroupHandle, Panel, PanelGroup, } from 'react-resizable-panels'; -import ParametersPinnedWrapper from '../../ParametersPinnedWrapper'; import ResizeHandle from '../ResizeHandle'; import TextToImageTabMain from '../TextToImage/TextToImageTabMain'; -import ImageToImageTabParameters from './ImageToImageTabParameters'; const ImageToImageTab = () => { - const dispatch = useAppDispatch(); const panelGroupRef = useRef(null); - const model = useAppSelector((state: RootState) => state.generation.model); const handleDoubleClickHandle = useCallback(() => { if (!panelGroupRef.current) { return; } - panelGroupRef.current.setLayout([50, 50]); }, []); + const panelStorage = usePanelStorage(); + return ( - - - {model && model.base_model === 'sdxl' ? ( - - ) : ( - - )} - - - + + - - - - - { - dispatch(requestCanvasRescale()); - }} - > - - - - - + + + + + + + + ); }; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabParameters.tsx index 49b4392362..47b509eb36 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabParameters.tsx @@ -3,24 +3,20 @@ import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; +import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea'; import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; -// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse'; -import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; -import ImageToImageTabCoreParameters from './ImageToImageTabCoreParameters'; import { memo } from 'react'; +import ImageToImageTabCoreParameters from './ImageToImageTabCoreParameters'; const ImageToImageTabParameters = () => { return ( <> - - {/* */} diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx index 9d7153e2db..a77d58d07f 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx @@ -238,7 +238,7 @@ const modelsFilter = < T extends | MainModelConfigEntity | LoRAModelConfigEntity - | OnnxModelConfigEntity + | OnnxModelConfigEntity, >( data: EntityState | undefined, model_type: ModelType, diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx index b8f99bfa29..b2defec39d 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx @@ -5,16 +5,27 @@ import { PanelResizeHandle } from 'react-resizable-panels'; type ResizeHandleProps = Omit & { direction?: 'horizontal' | 'vertical'; collapsedDirection?: 'top' | 'bottom' | 'left' | 'right'; + isCollapsed?: boolean; }; const ResizeHandle = (props: ResizeHandleProps) => { - const { direction = 'horizontal', collapsedDirection, ...rest } = props; + const { + direction = 'horizontal', + collapsedDirection, + isCollapsed = false, + ...rest + } = props; const bg = useColorModeValue('base.100', 'base.850'); const hoverBg = useColorModeValue('base.300', 'base.700'); if (direction === 'horizontal') { return ( - + { } return ( - + { - const model = useAppSelector((state: RootState) => state.generation.model); - return ( - - - {model && model.base_model === 'sdxl' ? ( - - ) : ( - - )} - - - - ); + return ; }; export default memo(TextToImageTab); diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabMain.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabMain.tsx index d1b70196c1..1e603b1ee6 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabMain.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabMain.tsx @@ -10,7 +10,7 @@ const TextToImageTabMain = () => { position: 'relative', width: '100%', height: '100%', - p: 4, + p: 2, borderRadius: 'base', }} > 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 d9b9e0bc39..559ef0849a 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 @@ -5,22 +5,18 @@ import ParamControlNetCollapse from 'features/parameters/components/Parameters/C import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; -// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; +import { memo } from 'react'; import ParamPromptArea from '../../../../parameters/components/Parameters/Prompt/ParamPromptArea'; import TextToImageTabCoreParameters from './TextToImageTabCoreParameters'; -import { memo } from 'react'; const TextToImageTabParameters = () => { return ( <> - - {/* */} diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx deleted file mode 100644 index ca2d2a1d0a..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Flex } from '@chakra-ui/layout'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIIconButton from 'common/components/IAIIconButton'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; -import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton'; -import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton'; -import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice'; -import { useTranslation } from 'react-i18next'; -import { FaSlidersH } from 'react-icons/fa'; - -export default function UnifiedCanvasProcessingButtons() { - const shouldPinParametersPanel = useAppSelector( - (state) => state.ui.shouldPinParametersPanel - ); - const shouldShowParametersPanel = useAppSelector( - (state) => state.ui.shouldShowParametersPanel - ); - - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - - const handleShowOptionsPanel = () => { - dispatch(setShouldShowParametersPanel(true)); - shouldPinParametersPanel && dispatch(requestCanvasRescale()); - }; - - return !shouldPinParametersPanel || !shouldShowParametersPanel ? ( - - - - - - - - - - - - ) : null; -} diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx index e8eeed7acc..85396c87be 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx @@ -1,10 +1,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; -import { - resetCanvas, - resizeAndScaleCanvas, -} from 'features/canvas/store/canvasSlice'; +import { resetCanvas } from 'features/canvas/store/canvasSlice'; import { useTranslation } from 'react-i18next'; import { FaTrash } from 'react-icons/fa'; @@ -15,7 +12,6 @@ export default function UnifiedCanvasResetCanvas() { const handleResetCanvas = () => { dispatch(resetCanvas()); - dispatch(resizeAndScaleCanvas()); }; return ( { return ( @@ -47,7 +46,6 @@ const UnifiedCanvasToolbarBeta = () => { - ); }; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx index 91bf4732c3..601493afe9 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx @@ -1,33 +1,11 @@ -import { Box, Flex } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { Flex } from '@chakra-ui/react'; import IAIDropOverlay from 'common/components/IAIDropOverlay'; import IAICanvas from 'features/canvas/components/IAICanvas'; -import IAICanvasResizer from 'features/canvas/components/IAICanvasResizer'; import IAICanvasToolbar from 'features/canvas/components/IAICanvasToolbar/IAICanvasToolbar'; -import { canvasSelector } from 'features/canvas/store/canvasSelectors'; -import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks'; import { CanvasInitialImageDropData } from 'features/dnd/types'; import { isValidDrop } from 'features/dnd/util/isValidDrop'; -import { uiSelector } from 'features/ui/store/uiSelectors'; -import { memo, useLayoutEffect } from 'react'; -import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta'; -import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta'; - -const selector = createSelector( - [canvasSelector, uiSelector], - (canvas, ui) => { - const { doesCanvasNeedScaling } = canvas; - const { shouldUseCanvasBetaLayout } = ui; - return { - doesCanvasNeedScaling, - shouldUseCanvasBetaLayout, - }; - }, - defaultSelectorOptions -); +import { memo } from 'react'; const droppableData: CanvasInitialImageDropData = { id: 'canvas-intial-image', @@ -35,11 +13,6 @@ const droppableData: CanvasInitialImageDropData = { }; const UnifiedCanvasContent = () => { - const dispatch = useAppDispatch(); - - const { doesCanvasNeedScaling, shouldUseCanvasBetaLayout } = - useAppSelector(selector); - const { isOver, setNodeRef: setDroppableRef, @@ -49,106 +22,27 @@ const UnifiedCanvasContent = () => { data: droppableData, }); - useLayoutEffect(() => { - const resizeCallback = () => { - dispatch(requestCanvasRescale()); - }; - - window.addEventListener('resize', resizeCallback); - - return () => window.removeEventListener('resize', resizeCallback); - }, [dispatch]); - - if (shouldUseCanvasBetaLayout) { - return ( - - - - - - - {doesCanvasNeedScaling ? : } - {isValidDrop(droppableData, active) && ( - - )} - - - - - ); - } - return ( - - - - - - {doesCanvasNeedScaling ? : } - {isValidDrop(droppableData, active) && ( - - )} - - - - + + + {isValidDrop(droppableData, active) && ( + + )} + ); }; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx index dcf3500239..1c3d3cd270 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx @@ -2,30 +2,26 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse'; import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse'; -import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; -import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; -// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse'; import ParamMaskAdjustmentCollapse from 'features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskAdjustmentCollapse'; -import ParamSeamPaintingCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse'; +import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse'; +import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea'; -import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; -import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters'; +import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; import { memo } from 'react'; +import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters'; const UnifiedCanvasParameters = () => { return ( <> - - {/* */} - + ); diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx index 0a5b872e4b..33af70e2bc 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx @@ -1,26 +1,8 @@ -import { Flex } from '@chakra-ui/react'; -import { RootState } from 'app/store/store'; -import { useAppSelector } from 'app/store/storeHooks'; -import SDXLUnifiedCanvasTabParameters from 'features/sdxl/components/SDXLUnifiedCanvasTabParameters'; import { memo } from 'react'; -import ParametersPinnedWrapper from '../../ParametersPinnedWrapper'; import UnifiedCanvasContent from './UnifiedCanvasContent'; -import UnifiedCanvasParameters from './UnifiedCanvasParameters'; const UnifiedCanvasTab = () => { - const model = useAppSelector((state: RootState) => state.generation.model); - return ( - - - {model && model.base_model === 'sdxl' ? ( - - ) : ( - - )} - - - - ); + return ; }; export default memo(UnifiedCanvasTab); diff --git a/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts b/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts deleted file mode 100644 index 3b2d9a068a..0000000000 --- a/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts +++ /dev/null @@ -1,75 +0,0 @@ -// adapted from https://github.com/bvaughn/react-resizable-panels/issues/141#issuecomment-1540048714 - -import { - RefObject, - useCallback, - useLayoutEffect, - useRef, - useState, -} from 'react'; -import { ImperativePanelHandle } from 'react-resizable-panels'; - -export const useMinimumPanelSize = ( - minSizePx: number, - defaultSizePct: number, - groupId: string, - orientation: 'horizontal' | 'vertical' = 'horizontal' -): { - ref: RefObject; - minSizePct: number; -} => { - const ref = useRef(null); - const [minSizePct, setMinSizePct] = useState(defaultSizePct); - - const handleWindowResize = useCallback(() => { - const size = ref.current?.getSize(); - - if (size !== undefined && size < minSizePct) { - ref.current?.resize(minSizePct); - } - }, [minSizePct]); - - useLayoutEffect(() => { - const panelGroup = document.querySelector( - `[data-panel-group-id="${groupId}"]` - ); - const resizeHandles = document.querySelectorAll( - orientation === 'horizontal' - ? '.resize-handle-horizontal' - : '.resize-handle-vertical' - ); - - if (!panelGroup) { - return; - } - const observer = new ResizeObserver(() => { - let dim = - orientation === 'horizontal' - ? panelGroup.getBoundingClientRect().width - : panelGroup.getBoundingClientRect().height; - - resizeHandles.forEach((resizeHandle) => { - dim -= - orientation === 'horizontal' - ? resizeHandle.getBoundingClientRect().width - : resizeHandle.getBoundingClientRect().height; - }); - - // Minimum size in pixels is a percentage of the PanelGroup's width/height - setMinSizePct((minSizePx / dim) * 100); - }); - observer.observe(panelGroup); - resizeHandles.forEach((resizeHandle) => { - observer.observe(resizeHandle); - }); - - window.addEventListener('resize', handleWindowResize); - - return () => { - observer.disconnect(); - window.removeEventListener('resize', handleWindowResize); - }; - }, [groupId, handleWindowResize, minSizePct, minSizePx, orientation]); - - return { ref, minSizePct }; -}; diff --git a/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts b/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts new file mode 100644 index 0000000000..f1deaa1c35 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts @@ -0,0 +1,52 @@ +import { useCallback, useRef, useState } from 'react'; +import { flushSync } from 'react-dom'; +import { ImperativePanelHandle, Units } from 'react-resizable-panels'; + +export const usePanel = (minSize: number, units: Units) => { + const ref = useRef(null); + + const [isCollapsed, setIsCollapsed] = useState(() => + Boolean(ref.current?.getCollapsed()) + ); + + const toggle = useCallback(() => { + if (ref.current?.getCollapsed()) { + flushSync(() => { + ref.current?.expand(); + }); + } else { + flushSync(() => { + ref.current?.collapse(); + }); + } + }, []); + + const expand = useCallback(() => { + flushSync(() => { + ref.current?.expand(); + }); + }, []); + + const collapse = useCallback(() => { + flushSync(() => { + ref.current?.collapse(); + }); + }, []); + + const reset = useCallback(() => { + flushSync(() => { + ref.current?.resize(minSize, units); + }); + }, [minSize, units]); + + return { + ref, + minSize, + isCollapsed, + setIsCollapsed, + reset, + toggle, + expand, + collapse, + }; +}; diff --git a/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts b/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts new file mode 100644 index 0000000000..a19125b92b --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts @@ -0,0 +1,17 @@ +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useCallback } from 'react'; +import { panelsChanged } from '../store/uiSlice'; + +export const usePanelStorage = () => { + const dispatch = useAppDispatch(); + const panels = useAppSelector((state) => state.ui.panels); + const getItem = useCallback((name: string) => panels[name] ?? '', [panels]); + const setItem = useCallback( + (name: string, value: string) => { + dispatch(panelsChanged({ name, value })); + }, + [dispatch] + ); + + return { getItem, setItem }; +}; diff --git a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts b/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts index 07fefd95e8..ec26c26d0c 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts @@ -6,4 +6,5 @@ import { UIState } from './uiTypes'; export const uiPersistDenylist: (keyof UIState)[] = [ 'shouldShowImageDetails', 'globalContextMenuCloseTrigger', + 'panels', ]; diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index ca35eab300..2e4227e8e6 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -8,19 +8,16 @@ import { UIState } from './uiTypes'; export const initialUIState: UIState = { activeTab: 0, - shouldPinParametersPanel: true, - shouldShowParametersPanel: true, shouldShowImageDetails: false, shouldUseCanvasBetaLayout: false, shouldShowExistingModelsInSearch: false, shouldUseSliders: false, - shouldPinGallery: true, - shouldShowGallery: true, shouldHidePreview: false, shouldShowProgressInViewer: true, shouldShowEmbeddingPicker: false, favoriteSchedulers: [], globalContextMenuCloseTrigger: 0, + panels: {}, }; export const uiSlice = createSlice({ @@ -30,13 +27,6 @@ export const uiSlice = createSlice({ setActiveTab: (state, action: PayloadAction) => { setActiveTabReducer(state, action.payload); }, - setShouldPinParametersPanel: (state, action: PayloadAction) => { - state.shouldPinParametersPanel = action.payload; - state.shouldShowParametersPanel = true; - }, - setShouldShowParametersPanel: (state, action: PayloadAction) => { - state.shouldShowParametersPanel = action.payload; - }, setShouldShowImageDetails: (state, action: PayloadAction) => { state.shouldShowImageDetails = action.payload; }, @@ -55,36 +45,6 @@ export const uiSlice = createSlice({ setShouldUseSliders: (state, action: PayloadAction) => { state.shouldUseSliders = action.payload; }, - setShouldShowGallery: (state, action: PayloadAction) => { - state.shouldShowGallery = action.payload; - }, - togglePinGalleryPanel: (state) => { - state.shouldPinGallery = !state.shouldPinGallery; - if (!state.shouldPinGallery) { - state.shouldShowGallery = true; - } - }, - togglePinParametersPanel: (state) => { - state.shouldPinParametersPanel = !state.shouldPinParametersPanel; - if (!state.shouldPinParametersPanel) { - state.shouldShowParametersPanel = true; - } - }, - toggleParametersPanel: (state) => { - state.shouldShowParametersPanel = !state.shouldShowParametersPanel; - }, - toggleGalleryPanel: (state) => { - state.shouldShowGallery = !state.shouldShowGallery; - }, - togglePanels: (state) => { - if (state.shouldShowGallery || state.shouldShowParametersPanel) { - state.shouldShowGallery = false; - state.shouldShowParametersPanel = false; - } else { - state.shouldShowGallery = true; - state.shouldShowParametersPanel = true; - } - }, setShouldShowProgressInViewer: (state, action: PayloadAction) => { state.shouldShowProgressInViewer = action.payload; }, @@ -100,6 +60,12 @@ export const uiSlice = createSlice({ contextMenusClosed: (state) => { state.globalContextMenuCloseTrigger += 1; }, + panelsChanged: ( + state, + action: PayloadAction<{ name: string; value: string }> + ) => { + state.panels[action.payload.name] = action.payload.value; + }, }, extraReducers(builder) { builder.addCase(initialImageChanged, (state) => { @@ -110,23 +76,16 @@ export const uiSlice = createSlice({ export const { setActiveTab, - setShouldPinParametersPanel, - setShouldShowParametersPanel, setShouldShowImageDetails, setShouldUseCanvasBetaLayout, setShouldShowExistingModelsInSearch, setShouldUseSliders, setShouldHidePreview, - setShouldShowGallery, - togglePanels, - togglePinGalleryPanel, - togglePinParametersPanel, - toggleParametersPanel, - toggleGalleryPanel, setShouldShowProgressInViewer, favoriteSchedulersChanged, toggleEmbeddingPicker, contextMenusClosed, + panelsChanged, } = uiSlice.actions; export default uiSlice.reducer; diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index 08c75a12f5..0f0ed64f97 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -14,17 +14,14 @@ export type Rect = Coordinates & Dimensions; export interface UIState { activeTab: number; - shouldPinParametersPanel: boolean; - shouldShowParametersPanel: boolean; shouldShowImageDetails: boolean; shouldUseCanvasBetaLayout: boolean; shouldShowExistingModelsInSearch: boolean; shouldUseSliders: boolean; shouldHidePreview: boolean; - shouldPinGallery: boolean; - shouldShowGallery: boolean; shouldShowProgressInViewer: boolean; shouldShowEmbeddingPicker: boolean; favoriteSchedulers: SchedulerParam[]; globalContextMenuCloseTrigger: number; + panels: Record; } diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 6dce8f0c2b..516ee49d48 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -7,104 +7,104 @@ export type paths = { "/api/v1/sessions/": { /** - * List Sessions + * List Sessions * @description Gets a list of sessions, optionally searching */ get: operations["list_sessions"]; /** - * Create Session + * Create Session * @description Creates a new session, optionally initializing it with an invocation graph */ post: operations["create_session"]; }; "/api/v1/sessions/{session_id}": { /** - * Get Session + * Get Session * @description Gets a session */ get: operations["get_session"]; }; "/api/v1/sessions/{session_id}/nodes": { /** - * Add Node + * Add Node * @description Adds a node to the graph */ post: operations["add_node"]; }; "/api/v1/sessions/{session_id}/nodes/{node_path}": { /** - * Update Node + * Update Node * @description Updates a node in the graph and removes all linked edges */ put: operations["update_node"]; /** - * Delete Node + * Delete Node * @description Deletes a node in the graph and removes all linked edges */ delete: operations["delete_node"]; }; "/api/v1/sessions/{session_id}/edges": { /** - * Add Edge + * Add Edge * @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 + * Delete Edge * @description Deletes an edge from the graph */ delete: operations["delete_edge"]; }; "/api/v1/sessions/{session_id}/invoke": { /** - * Invoke Session + * Invoke Session * @description Invokes a session */ put: operations["invoke_session"]; /** - * Cancel Session Invoke + * Cancel Session Invoke * @description Invokes a session */ delete: operations["cancel_session_invoke"]; }; "/api/v1/models/": { /** - * List Models + * List Models * @description Gets a list of models */ get: operations["list_models"]; }; "/api/v1/models/{base_model}/{model_type}/{model_name}": { /** - * Delete Model + * Delete Model * @description Delete Model */ delete: operations["del_model"]; /** - * Update Model + * Update Model * @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed. */ patch: operations["update_model"]; }; "/api/v1/models/import": { /** - * Import Model + * Import Model * @description Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically */ post: operations["import_model"]; }; "/api/v1/models/add": { /** - * Add Model + * Add Model * @description Add a model using the configuration information appropriate for its type. Only local models can be added by path */ post: operations["add_model"]; }; "/api/v1/models/convert/{base_model}/{model_type}/{model_name}": { /** - * Convert Model + * Convert Model * @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none. */ put: operations["convert_model"]; @@ -115,14 +115,14 @@ export type paths = { }; "/api/v1/models/ckpt_confs": { /** - * List Ckpt Configs + * List Ckpt Configs * @description Return a list of the legacy checkpoint configuration files stored in `ROOT/configs/stable-diffusion`, relative to ROOT. */ get: operations["list_ckpt_configs"]; }; "/api/v1/models/sync": { /** - * Sync To Config + * Sync To Config * @description Call after making changes to models.yaml, autoimport directories or models directory to synchronize * in-memory data structures with disk data structures. */ @@ -130,78 +130,78 @@ export type paths = { }; "/api/v1/models/merge/{base_model}": { /** - * Merge Models + * Merge Models * @description Convert a checkpoint model into a diffusers model */ put: operations["merge_models"]; }; "/api/v1/images/upload": { /** - * Upload Image + * Upload Image * @description Uploads an image */ post: operations["upload_image"]; }; "/api/v1/images/i/{image_name}": { /** - * Get Image Dto + * Get Image Dto * @description Gets an image's DTO */ get: operations["get_image_dto"]; /** - * Delete Image + * Delete Image * @description Deletes an image */ delete: operations["delete_image"]; /** - * Update Image + * Update Image * @description Updates an image */ patch: operations["update_image"]; }; "/api/v1/images/clear-intermediates": { /** - * Clear Intermediates + * Clear Intermediates * @description Clears all intermediates */ post: operations["clear_intermediates"]; }; "/api/v1/images/i/{image_name}/metadata": { /** - * Get Image Metadata + * Get Image Metadata * @description Gets an image's metadata */ get: operations["get_image_metadata"]; }; "/api/v1/images/i/{image_name}/full": { /** - * Get Image Full + * Get Image Full * @description Gets a full-resolution image file */ get: operations["get_image_full"]; /** - * Get Image Full + * Get Image Full * @description Gets a full-resolution image file */ head: operations["get_image_full"]; }; "/api/v1/images/i/{image_name}/thumbnail": { /** - * Get Image Thumbnail + * Get Image Thumbnail * @description Gets a thumbnail image file */ get: operations["get_image_thumbnail"]; }; "/api/v1/images/i/{image_name}/urls": { /** - * Get Image Urls + * Get Image Urls * @description Gets an image and thumbnail URL */ get: operations["get_image_urls"]; }; "/api/v1/images/": { /** - * List Image Dtos + * List Image Dtos * @description Gets a list of image DTOs */ get: operations["list_image_dtos"]; @@ -220,62 +220,62 @@ export type paths = { }; "/api/v1/boards/": { /** - * List Boards + * List Boards * @description Gets a list of boards */ get: operations["list_boards"]; /** - * Create Board + * Create Board * @description Creates a board */ post: operations["create_board"]; }; "/api/v1/boards/{board_id}": { /** - * Get Board + * Get Board * @description Gets a board */ get: operations["get_board"]; /** - * Delete Board + * Delete Board * @description Deletes a board */ delete: operations["delete_board"]; /** - * Update Board + * Update Board * @description Updates a board */ patch: operations["update_board"]; }; "/api/v1/boards/{board_id}/image_names": { /** - * List All Board Image Names + * List All Board Image Names * @description Gets a list of images for a board */ get: operations["list_all_board_image_names"]; }; "/api/v1/board_images/": { /** - * Add Image To Board + * Add Image To Board * @description Creates a board_image */ post: operations["add_image_to_board"]; /** - * Remove Image From Board + * Remove Image From Board * @description Removes an image from its board, if it had one */ delete: operations["remove_image_from_board"]; }; "/api/v1/board_images/batch": { /** - * Add Images To Board + * Add Images To Board * @description Adds a list of images to a board */ post: operations["add_images_to_board"]; }; "/api/v1/board_images/batch/delete": { /** - * Remove Images From Board + * Remove Images From Board * @description Removes a list of images from their board, if they had one */ post: operations["remove_images_from_board"]; @@ -290,12 +290,12 @@ export type paths = { }; "/api/v1/app/logging": { /** - * Get Log Level + * Get Log Level * @description Returns the log level */ get: operations["get_log_level"]; /** - * Set Log Level + * Set Log Level * @description Sets the log verbosity level */ post: operations["set_log_level"]; @@ -309,637 +309,138 @@ export type components = { /** AddImagesToBoardResult */ AddImagesToBoardResult: { /** - * Board Id + * Board Id * @description The id of the board the images were added to */ board_id: string; /** - * Added Image Names + * Added Image Names * @description The image names that were added to the board */ - added_image_names: (string)[]; + added_image_names: string[]; }; /** - * Add Integers + * Add Integers * @description Adds two numbers */ AddInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default add + * Type + * @default add * @enum {string} */ type: "add"; /** - * A - * @description The first number + * A + * @description The first number * @default 0 */ a?: number; /** - * B - * @description The second number + * B + * @description The second number * @default 0 */ b?: number; }; /** - * AppConfig + * AppConfig * @description App Config Response */ AppConfig: { /** - * Infill Methods + * Infill Methods * @description List of available infill methods */ - infill_methods: (string)[]; + infill_methods: string[]; /** - * Upscaling Methods + * Upscaling Methods * @description List of upscaling methods */ - upscaling_methods: (components["schemas"]["Upscaler"])[]; + upscaling_methods: components["schemas"]["Upscaler"][]; /** - * Nsfw Methods + * Nsfw Methods * @description List of NSFW checking methods */ - nsfw_methods: (string)[]; + nsfw_methods: string[]; /** - * Watermarking Methods + * Watermarking Methods * @description List of invisible watermark methods */ - watermarking_methods: (string)[]; + watermarking_methods: string[]; }; /** - * AppVersion + * AppVersion * @description App Version Response */ AppVersion: { /** - * Version + * Version * @description App version */ version: string; }; /** - * BaseModelType - * @description An enumeration. + * BaseModelType + * @description An enumeration. * @enum {string} */ BaseModelType: "sd-1" | "sd-2" | "sdxl" | "sdxl-refiner"; - /** BoardChanges */ - BoardChanges: { - /** - * Board Name - * @description The board's new name. - */ - board_name?: string; - /** - * Cover Image Name - * @description The name of the board's new cover image. - */ - cover_image_name?: string; - }; /** - * BoardDTO - * @description Deserialized board record with cover image URL and image count. + * Blank Image + * @description Creates a blank image and forwards it to the pipeline */ - BoardDTO: { + BlankImageInvocation: { /** - * Board Id - * @description The unique ID of the board. - */ - board_id: string; - /** - * Board Name - * @description The name of the board. - */ - board_name: string; - /** - * Created At - * @description The created timestamp of the board. - */ - created_at: string; - /** - * Updated At - * @description The updated timestamp of the board. - */ - updated_at: string; - /** - * Deleted At - * @description The deleted timestamp of the board. - */ - deleted_at?: string; - /** - * Cover Image Name - * @description The name of the board's cover image. - */ - cover_image_name?: string; - /** - * Image Count - * @description The number of images in the board. - */ - image_count: number; - }; - /** Body_add_image_to_board */ - Body_add_image_to_board: { - /** - * Board Id - * @description The id of the board to add to - */ - board_id: string; - /** - * Image Name - * @description The name of the image to add - */ - image_name: string; - }; - /** Body_add_images_to_board */ - Body_add_images_to_board: { - /** - * Board Id - * @description The id of the board to add to - */ - board_id: string; - /** - * Image Names - * @description The names of the images to add - */ - image_names: (string)[]; - }; - /** Body_delete_images_from_list */ - Body_delete_images_from_list: { - /** - * Image Names - * @description The list of names of images to delete - */ - image_names: (string)[]; - }; - /** Body_import_model */ - Body_import_model: { - /** - * Location - * @description A model path, repo_id or URL to import - */ - location: string; - /** - * Prediction Type - * @description Prediction type for SDv2 checkpoint files - * @default v_prediction - * @enum {string} - */ - prediction_type?: "v_prediction" | "epsilon" | "sample"; - }; - /** 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; - }; - /** Body_remove_image_from_board */ - Body_remove_image_from_board: { - /** - * Image Name - * @description The name of the image to remove - */ - image_name: string; - }; - /** Body_remove_images_from_board */ - Body_remove_images_from_board: { - /** - * Image Names - * @description The names of the images to remove - */ - image_names: (string)[]; - }; - /** Body_star_images_in_list */ - Body_star_images_in_list: { - /** - * Image Names - * @description The list of names of images to star - */ - image_names: (string)[]; - }; - /** Body_unstar_images_in_list */ - Body_unstar_images_in_list: { - /** - * Image Names - * @description The list of names of images to unstar - */ - image_names: (string)[]; - }; - /** Body_upload_image */ - Body_upload_image: { - /** - * File - * Format: binary - */ - file: Blob; - }; - /** - * Boolean Primitive Collection - * @description A collection of boolean primitive values - */ - BooleanCollectionInvocation: { - /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default boolean_collection + * Type + * @default blank_image * @enum {string} */ - type: "boolean_collection"; + type: "blank_image"; /** - * Collection - * @description The collection of boolean values + * Width + * @description The width of the image + * @default 512 */ - collection?: (boolean)[]; - }; - /** - * BooleanCollectionOutput - * @description Base class for nodes that output a collection of booleans - */ - BooleanCollectionOutput: { + width?: number; /** - * Type - * @default boolean_collection_output + * Height + * @description The height of the image + * @default 512 + */ + height?: number; + /** + * Mode + * @description The mode of the image + * @default RGB * @enum {string} */ - type: "boolean_collection_output"; + mode?: "RGB" | "RGBA"; /** - * Collection - * @description The output boolean collection - */ - collection: (boolean)[]; - }; - /** - * Boolean Primitive - * @description A boolean primitive value - */ - BooleanInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default boolean - * @enum {string} - */ - type: "boolean"; - /** - * Value - * @description The boolean value - * @default false - */ - value?: boolean; - }; - /** - * BooleanOutput - * @description Base class for nodes that output a single boolean - */ - BooleanOutput: { - /** - * Type - * @default boolean_output - * @enum {string} - */ - type: "boolean_output"; - /** - * Value - * @description The output boolean - */ - value: boolean; - }; - /** - * Canny Processor - * @description Canny edge detection for ControlNet - */ - CannyImageProcessorInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default canny_image_processor - * @enum {string} - */ - type: "canny_image_processor"; - /** - * Image - * @description The image to process - */ - image?: components["schemas"]["ImageField"]; - /** - * Low Threshold - * @description The low threshold of the Canny pixel gradient (0-255) - * @default 100 - */ - low_threshold?: number; - /** - * High Threshold - * @description The high threshold of the Canny pixel gradient (0-255) - * @default 200 - */ - high_threshold?: number; - }; - /** ClipField */ - ClipField: { - /** - * Tokenizer - * @description Info to load tokenizer submodel - */ - tokenizer: components["schemas"]["ModelInfo"]; - /** - * Text Encoder - * @description Info to load text_encoder submodel - */ - text_encoder: components["schemas"]["ModelInfo"]; - /** - * Skipped Layers - * @description Number of skipped layers in text_encoder - */ - skipped_layers: number; - /** - * Loras - * @description Loras to apply on model loading - */ - loras: (components["schemas"]["LoraInfo"])[]; - }; - /** - * CLIP Skip - * @description Skip layers in clip text_encoder model. - */ - ClipSkipInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default clip_skip - * @enum {string} - */ - type: "clip_skip"; - /** - * CLIP - * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count - */ - clip?: components["schemas"]["ClipField"]; - /** - * Skipped Layers - * @description Number of layers to skip in text encoder - * @default 0 - */ - skipped_layers?: number; - }; - /** - * ClipSkipInvocationOutput - * @description Clip skip node output - */ - ClipSkipInvocationOutput: { - /** - * Type - * @default clip_skip_output - * @enum {string} - */ - type: "clip_skip_output"; - /** - * CLIP - * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count - */ - clip?: components["schemas"]["ClipField"]; - }; - /** - * CollectInvocation - * @description Collects values into a collection - */ - CollectInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default collect - * @enum {string} - */ - type: "collect"; - /** - * Collection Item - * @description The item to collect (all inputs must be of the same type) - */ - item?: unknown; - /** - * Collection - * @description The collection, will be provided on execution - */ - collection?: (unknown)[]; - }; - /** - * CollectInvocationOutput - * @description Base class for all invocation outputs - */ - CollectInvocationOutput: { - /** - * Type - * @default collect_output - * @enum {string} - */ - type: "collect_output"; - /** - * Collection - * @description The collection of input items - */ - collection: (unknown)[]; - }; - /** - * ColorCollectionOutput - * @description Base class for nodes that output a collection of colors - */ - ColorCollectionOutput: { - /** - * Type - * @default color_collection_output - * @enum {string} - */ - type: "color_collection_output"; - /** - * Collection - * @description The output colors - */ - collection: (components["schemas"]["ColorField"])[]; - }; - /** - * Color Correct - * @description Shifts the colors of a target image to match the reference image, optionally - * using a mask to only color-correct certain regions of the target image. - */ - ColorCorrectInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default color_correct - * @enum {string} - */ - type: "color_correct"; - /** - * Image - * @description The image to color-correct - */ - image?: components["schemas"]["ImageField"]; - /** - * Reference - * @description Reference image for color-correction - */ - reference?: components["schemas"]["ImageField"]; - /** - * Mask - * @description Mask to use when applying color-correction - */ - mask?: components["schemas"]["ImageField"]; - /** - * Mask Blur Radius - * @description Mask blur radius - * @default 8 - */ - mask_blur_radius?: number; - }; - /** - * ColorField - * @description A color primitive field - */ - ColorField: { - /** - * R - * @description The red component - */ - r: number; - /** - * G - * @description The green component - */ - g: number; - /** - * B - * @description The blue component - */ - b: number; - /** - * A - * @description The alpha component - */ - a: number; - }; - /** - * Color Primitive - * @description A color primitive value - */ - ColorInvocation: { - /** - * Id - * @description The id of this node. Must be unique among all nodes. - */ - id: string; - /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. - * @default false - */ - is_intermediate?: boolean; - /** - * Type - * @default color - * @enum {string} - */ - type: "color"; - /** - * Color - * @description The color value + * Color + * @description The color of the image * @default { * "r": 0, * "g": 0, @@ -950,212 +451,803 @@ export type components = { color?: components["schemas"]["ColorField"]; }; /** - * ColorOutput - * @description Base class for nodes that output a single color + * Blend Latents + * @description Blend two latents using a given alpha. Latents must have same size. */ - ColorOutput: { + BlendLatentsInvocation: { /** - * Type - * @default color_output - * @enum {string} - */ - type: "color_output"; - /** - * Color - * @description The output color - */ - color: components["schemas"]["ColorField"]; - }; - /** - * Compel Prompt - * @description Parse prompt using compel package to conditioning. - */ - CompelInvocation: { - /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default compel + * Type + * @default lblend * @enum {string} */ - type: "compel"; + type: "lblend"; /** - * Prompt - * @description Prompt to be parsed by Compel to create a conditioning tensor - * @default + * Latents A + * @description Latents tensor */ - prompt?: string; + latents_a?: components["schemas"]["LatentsField"]; /** - * CLIP + * Latents B + * @description Latents tensor + */ + latents_b?: components["schemas"]["LatentsField"]; + /** + * Alpha + * @description Blending factor. 0.0 = use input A only, 1.0 = use input B only, 0.5 = 50% mix of input A and input B. + * @default 0.5 + */ + alpha?: number; + }; + /** BoardChanges */ + BoardChanges: { + /** + * Board Name + * @description The board's new name. + */ + board_name?: string; + /** + * Cover Image Name + * @description The name of the board's new cover image. + */ + cover_image_name?: string; + }; + /** + * BoardDTO + * @description Deserialized board record with cover image URL and image count. + */ + BoardDTO: { + /** + * Board Id + * @description The unique ID of the board. + */ + board_id: string; + /** + * Board Name + * @description The name of the board. + */ + board_name: string; + /** + * Created At + * @description The created timestamp of the board. + */ + created_at: string; + /** + * Updated At + * @description The updated timestamp of the board. + */ + updated_at: string; + /** + * Deleted At + * @description The deleted timestamp of the board. + */ + deleted_at?: string; + /** + * Cover Image Name + * @description The name of the board's cover image. + */ + cover_image_name?: string; + /** + * Image Count + * @description The number of images in the board. + */ + image_count: number; + }; + /** Body_add_image_to_board */ + Body_add_image_to_board: { + /** + * Board Id + * @description The id of the board to add to + */ + board_id: string; + /** + * Image Name + * @description The name of the image to add + */ + image_name: string; + }; + /** Body_add_images_to_board */ + Body_add_images_to_board: { + /** + * Board Id + * @description The id of the board to add to + */ + board_id: string; + /** + * Image Names + * @description The names of the images to add + */ + image_names: string[]; + }; + /** Body_delete_images_from_list */ + Body_delete_images_from_list: { + /** + * Image Names + * @description The list of names of images to delete + */ + image_names: string[]; + }; + /** Body_import_model */ + Body_import_model: { + /** + * Location + * @description A model path, repo_id or URL to import + */ + location: string; + /** + * Prediction Type + * @description Prediction type for SDv2 checkpoint files + * @default v_prediction + * @enum {string} + */ + prediction_type?: "v_prediction" | "epsilon" | "sample"; + }; + /** 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; + }; + /** Body_remove_image_from_board */ + Body_remove_image_from_board: { + /** + * Image Name + * @description The name of the image to remove + */ + image_name: string; + }; + /** Body_remove_images_from_board */ + Body_remove_images_from_board: { + /** + * Image Names + * @description The names of the images to remove + */ + image_names: string[]; + }; + /** Body_star_images_in_list */ + Body_star_images_in_list: { + /** + * Image Names + * @description The list of names of images to star + */ + image_names: string[]; + }; + /** Body_unstar_images_in_list */ + Body_unstar_images_in_list: { + /** + * Image Names + * @description The list of names of images to unstar + */ + image_names: string[]; + }; + /** Body_upload_image */ + Body_upload_image: { + /** + * File + * Format: binary + */ + file: Blob; + }; + /** + * Boolean Primitive Collection + * @description A collection of boolean primitive values + */ + BooleanCollectionInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default boolean_collection + * @enum {string} + */ + type: "boolean_collection"; + /** + * Collection + * @description The collection of boolean values + */ + collection?: boolean[]; + }; + /** + * BooleanCollectionOutput + * @description Base class for nodes that output a collection of booleans + */ + BooleanCollectionOutput: { + /** + * Type + * @default boolean_collection_output + * @enum {string} + */ + type: "boolean_collection_output"; + /** + * Collection + * @description The output boolean collection + */ + collection: boolean[]; + }; + /** + * Boolean Primitive + * @description A boolean primitive value + */ + BooleanInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default boolean + * @enum {string} + */ + type: "boolean"; + /** + * Value + * @description The boolean value + * @default false + */ + value?: boolean; + }; + /** + * BooleanOutput + * @description Base class for nodes that output a single boolean + */ + BooleanOutput: { + /** + * Type + * @default boolean_output + * @enum {string} + */ + type: "boolean_output"; + /** + * Value + * @description The output boolean + */ + value: boolean; + }; + /** + * Canny Processor + * @description Canny edge detection for ControlNet + */ + CannyImageProcessorInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default canny_image_processor + * @enum {string} + */ + type: "canny_image_processor"; + /** + * Image + * @description The image to process + */ + image?: components["schemas"]["ImageField"]; + /** + * Low Threshold + * @description The low threshold of the Canny pixel gradient (0-255) + * @default 100 + */ + low_threshold?: number; + /** + * High Threshold + * @description The high threshold of the Canny pixel gradient (0-255) + * @default 200 + */ + high_threshold?: number; + }; + /** ClipField */ + ClipField: { + /** + * Tokenizer + * @description Info to load tokenizer submodel + */ + tokenizer: components["schemas"]["ModelInfo"]; + /** + * Text Encoder + * @description Info to load text_encoder submodel + */ + text_encoder: components["schemas"]["ModelInfo"]; + /** + * Skipped Layers + * @description Number of skipped layers in text_encoder + */ + skipped_layers: number; + /** + * Loras + * @description Loras to apply on model loading + */ + loras: components["schemas"]["LoraInfo"][]; + }; + /** + * CLIP Skip + * @description Skip layers in clip text_encoder model. + */ + ClipSkipInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default clip_skip + * @enum {string} + */ + type: "clip_skip"; + /** + * CLIP + * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count + */ + clip?: components["schemas"]["ClipField"]; + /** + * Skipped Layers + * @description Number of layers to skip in text encoder + * @default 0 + */ + skipped_layers?: number; + }; + /** + * ClipSkipInvocationOutput + * @description Clip skip node output + */ + ClipSkipInvocationOutput: { + /** + * Type + * @default clip_skip_output + * @enum {string} + */ + type: "clip_skip_output"; + /** + * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; }; /** - * Conditioning Primitive Collection - * @description A collection of conditioning tensor primitive values + * CollectInvocation + * @description Collects values into a collection */ - ConditioningCollectionInvocation: { + CollectInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default conditioning_collection + * Type + * @default collect + * @enum {string} + */ + type: "collect"; + /** + * Collection Item + * @description The item to collect (all inputs must be of the same type) + */ + item?: unknown; + /** + * Collection + * @description The collection, will be provided on execution + */ + collection?: unknown[]; + }; + /** + * CollectInvocationOutput + * @description Base class for all invocation outputs + */ + CollectInvocationOutput: { + /** + * Type + * @default collect_output + * @enum {string} + */ + type: "collect_output"; + /** + * Collection + * @description The collection of input items + */ + collection: unknown[]; + }; + /** + * ColorCollectionOutput + * @description Base class for nodes that output a collection of colors + */ + ColorCollectionOutput: { + /** + * Type + * @default color_collection_output + * @enum {string} + */ + type: "color_collection_output"; + /** + * Collection + * @description The output colors + */ + collection: components["schemas"]["ColorField"][]; + }; + /** + * Color Correct + * @description Shifts the colors of a target image to match the reference image, optionally + * using a mask to only color-correct certain regions of the target image. + */ + ColorCorrectInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default color_correct + * @enum {string} + */ + type: "color_correct"; + /** + * Image + * @description The image to color-correct + */ + image?: components["schemas"]["ImageField"]; + /** + * Reference + * @description Reference image for color-correction + */ + reference?: components["schemas"]["ImageField"]; + /** + * Mask + * @description Mask to use when applying color-correction + */ + mask?: components["schemas"]["ImageField"]; + /** + * Mask Blur Radius + * @description Mask blur radius + * @default 8 + */ + mask_blur_radius?: number; + }; + /** + * ColorField + * @description A color primitive field + */ + ColorField: { + /** + * R + * @description The red component + */ + r: number; + /** + * G + * @description The green component + */ + g: number; + /** + * B + * @description The blue component + */ + b: number; + /** + * A + * @description The alpha component + */ + a: number; + }; + /** + * Color Primitive + * @description A color primitive value + */ + ColorInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default color + * @enum {string} + */ + type: "color"; + /** + * Color + * @description The color value + * @default { + * "r": 0, + * "g": 0, + * "b": 0, + * "a": 255 + * } + */ + color?: components["schemas"]["ColorField"]; + }; + /** + * ColorOutput + * @description Base class for nodes that output a single color + */ + ColorOutput: { + /** + * Type + * @default color_output + * @enum {string} + */ + type: "color_output"; + /** + * Color + * @description The output color + */ + color: components["schemas"]["ColorField"]; + }; + /** + * Compel Prompt + * @description Parse prompt using compel package to conditioning. + */ + CompelInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default compel + * @enum {string} + */ + type: "compel"; + /** + * Prompt + * @description Prompt to be parsed by Compel to create a conditioning tensor + * @default + */ + prompt?: string; + /** + * CLIP + * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count + */ + clip?: components["schemas"]["ClipField"]; + }; + /** + * Conditioning Primitive Collection + * @description A collection of conditioning tensor primitive values + */ + ConditioningCollectionInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default conditioning_collection * @enum {string} */ type: "conditioning_collection"; /** - * Collection - * @description The collection of conditioning tensors + * Collection + * @description The collection of conditioning tensors * @default 0 */ - collection?: (components["schemas"]["ConditioningField"])[]; + collection?: components["schemas"]["ConditioningField"][]; }; /** - * ConditioningCollectionOutput + * ConditioningCollectionOutput * @description Base class for nodes that output a collection of conditioning tensors */ ConditioningCollectionOutput: { /** - * Type - * @default conditioning_collection_output + * Type + * @default conditioning_collection_output * @enum {string} */ type: "conditioning_collection_output"; /** - * Collection + * Collection * @description The output conditioning tensors */ - collection: (components["schemas"]["ConditioningField"])[]; + collection: components["schemas"]["ConditioningField"][]; }; /** - * ConditioningField + * ConditioningField * @description A conditioning tensor primitive value */ ConditioningField: { /** - * Conditioning Name + * Conditioning Name * @description The name of conditioning tensor */ conditioning_name: string; }; /** - * Conditioning Primitive + * Conditioning Primitive * @description A conditioning tensor primitive value */ ConditioningInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default conditioning + * Type + * @default conditioning * @enum {string} */ type: "conditioning"; /** - * Conditioning + * Conditioning * @description Conditioning tensor */ conditioning?: components["schemas"]["ConditioningField"]; }; /** - * ConditioningOutput + * ConditioningOutput * @description Base class for nodes that output a single conditioning tensor */ ConditioningOutput: { /** - * Type - * @default conditioning_output + * Type + * @default conditioning_output * @enum {string} */ type: "conditioning_output"; /** - * Conditioning + * Conditioning * @description Conditioning tensor */ conditioning: components["schemas"]["ConditioningField"]; }; /** - * Content Shuffle Processor + * Content Shuffle Processor * @description Applies content shuffle processing to image */ ContentShuffleImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default content_shuffle_image_processor + * Type + * @default content_shuffle_image_processor * @enum {string} */ type: "content_shuffle_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; /** - * H - * @description Content shuffle `h` parameter + * H + * @description Content shuffle `h` parameter * @default 512 */ h?: number; /** - * W - * @description Content shuffle `w` parameter + * W + * @description Content shuffle `w` parameter * @default 512 */ w?: number; /** - * F - * @description Content shuffle `f` parameter + * F + * @description Content shuffle `f` parameter * @default 256 */ f?: number; @@ -1163,110 +1255,110 @@ export type components = { /** ControlField */ ControlField: { /** - * Image + * Image * @description The control image */ image: components["schemas"]["ImageField"]; /** - * Control Model + * Control Model * @description The ControlNet model to use */ control_model: components["schemas"]["ControlNetModelField"]; /** - * Control Weight - * @description The weight given to the ControlNet + * Control Weight + * @description The weight given to the ControlNet * @default 1 */ - control_weight?: number | (number)[]; + control_weight?: number | number[]; /** - * Begin Step Percent - * @description When the ControlNet is first applied (% of total steps) + * Begin Step Percent + * @description When the ControlNet is first applied (% of total steps) * @default 0 */ begin_step_percent?: number; /** - * End Step Percent - * @description When the ControlNet is last applied (% of total steps) + * End Step Percent + * @description When the ControlNet is last applied (% of total steps) * @default 1 */ end_step_percent?: number; /** - * Control Mode - * @description The control mode to use - * @default balanced + * Control Mode + * @description The control mode to use + * @default balanced * @enum {string} */ control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced"; /** - * Resize Mode - * @description The resize mode to use - * @default just_resize + * Resize Mode + * @description The resize mode to use + * @default just_resize * @enum {string} */ resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple"; }; /** - * ControlNet + * ControlNet * @description Collects ControlNet info to pass to other nodes */ ControlNetInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default controlnet + * Type + * @default controlnet * @enum {string} */ type: "controlnet"; /** - * Image + * Image * @description The control image */ image?: components["schemas"]["ImageField"]; /** - * Control Model - * @description ControlNet model to load + * Control Model + * @description ControlNet model to load * @default lllyasviel/sd-controlnet-canny */ control_model?: components["schemas"]["ControlNetModelField"]; /** - * Control Weight - * @description The weight given to the ControlNet + * Control Weight + * @description The weight given to the ControlNet * @default 1 */ - control_weight?: number | (number)[]; + control_weight?: number | number[]; /** - * Begin Step Percent - * @description When the ControlNet is first applied (% of total steps) + * Begin Step Percent + * @description When the ControlNet is first applied (% of total steps) * @default 0 */ begin_step_percent?: number; /** - * End Step Percent - * @description When the ControlNet is last applied (% of total steps) + * End Step Percent + * @description When the ControlNet is last applied (% of total steps) * @default 1 */ end_step_percent?: number; /** - * Control Mode - * @description The control mode used - * @default balanced + * Control Mode + * @description The control mode used + * @default balanced * @enum {string} */ control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced"; /** - * Resize Mode - * @description The resize mode used - * @default just_resize + * Resize Mode + * @description The resize mode used + * @default just_resize * @enum {string} */ resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple"; @@ -1277,7 +1369,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "controlnet"; @@ -1286,7 +1378,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "checkpoint"; @@ -1300,7 +1392,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "controlnet"; @@ -1309,19 +1401,19 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "diffusers"; error?: components["schemas"]["ModelError"]; }; /** - * ControlNetModelField + * ControlNetModelField * @description ControlNet model field */ ControlNetModelField: { /** - * Model Name + * Model Name * @description Name of the ControlNet model */ model_name: string; @@ -1329,193 +1421,198 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; }; /** - * ControlOutput + * ControlOutput * @description node output for ControlNet info */ ControlOutput: { /** - * Type - * @default control_output + * Type + * @default control_output * @enum {string} */ type: "control_output"; /** - * Control + * Control * @description ControlNet(s) to apply */ control: components["schemas"]["ControlField"]; }; /** - * CoreMetadata + * CoreMetadata * @description Core generation metadata for an image generated in InvokeAI. */ CoreMetadata: { /** - * App Version - * @description The version of InvokeAI used to generate this image + * App Version + * @description The version of InvokeAI used to generate this image * @default 3.0.2post1 */ app_version?: string; /** - * Generation Mode + * Generation Mode * @description The generation mode that output this image */ generation_mode: string; /** - * Positive Prompt + * Created By + * @description The name of the creator of the image + */ + created_by?: string; + /** + * Positive Prompt * @description The positive prompt parameter */ positive_prompt: string; /** - * Negative Prompt + * Negative Prompt * @description The negative prompt parameter */ negative_prompt: string; /** - * Width + * Width * @description The width parameter */ width: number; /** - * Height + * Height * @description The height parameter */ height: number; /** - * Seed + * Seed * @description The seed used for noise generation */ seed: number; /** - * Rand Device + * Rand Device * @description The device used for random number generation */ rand_device: string; /** - * Cfg Scale + * Cfg Scale * @description The classifier-free guidance scale parameter */ cfg_scale: number; /** - * Steps + * Steps * @description The number of steps used for inference */ steps: number; /** - * Scheduler + * Scheduler * @description The scheduler used for inference */ scheduler: string; /** - * Clip Skip + * Clip Skip * @description The number of skipped CLIP layers */ clip_skip: number; /** - * Model + * Model * @description The main model used for inference */ model: components["schemas"]["MainModelField"]; /** - * Controlnets + * Controlnets * @description The ControlNets used for inference */ - controlnets: (components["schemas"]["ControlField"])[]; + controlnets: components["schemas"]["ControlField"][]; /** - * Loras + * Loras * @description The LoRAs used for inference */ - loras: (components["schemas"]["LoRAMetadataField"])[]; + loras: components["schemas"]["LoRAMetadataField"][]; /** - * Vae + * Vae * @description The VAE used for decoding, if the main model's default was not used */ vae?: components["schemas"]["VAEModelField"]; /** - * Strength + * Strength * @description The strength used for latents-to-latents */ strength?: number; /** - * Init Image + * Init Image * @description The name of the initial image */ init_image?: string; /** - * Positive Style Prompt + * Positive Style Prompt * @description The positive style prompt parameter */ positive_style_prompt?: string; /** - * Negative Style Prompt + * Negative Style Prompt * @description The negative style prompt parameter */ negative_style_prompt?: string; /** - * Refiner Model + * Refiner Model * @description The SDXL Refiner model used */ refiner_model?: components["schemas"]["MainModelField"]; /** - * Refiner Cfg Scale + * Refiner Cfg Scale * @description The classifier-free guidance scale parameter used for the refiner */ refiner_cfg_scale?: number; /** - * Refiner Steps + * Refiner Steps * @description The number of steps used for the refiner */ refiner_steps?: number; /** - * Refiner Scheduler + * Refiner Scheduler * @description The scheduler used for the refiner */ refiner_scheduler?: string; /** - * Refiner Positive Aesthetic Store + * Refiner Positive Aesthetic Store * @description The aesthetic score used for the refiner */ refiner_positive_aesthetic_store?: number; /** - * Refiner Negative Aesthetic Store + * Refiner Negative Aesthetic Store * @description The aesthetic score used for the refiner */ refiner_negative_aesthetic_store?: number; /** - * Refiner Start + * Refiner Start * @description The start value used for refiner denoising */ refiner_start?: number; }; /** - * OpenCV Inpaint + * OpenCV Inpaint * @description Simple inpaint using opencv. */ CvInpaintInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default cv_inpaint + * Type + * @default cv_inpaint * @enum {string} */ type: "cv_inpaint"; /** - * Image + * Image * @description The image to inpaint */ image?: components["schemas"]["ImageField"]; /** - * Mask + * Mask * @description The mask to use when inpainting */ mask?: components["schemas"]["ImageField"]; @@ -1523,221 +1620,221 @@ export type components = { /** DeleteBoardResult */ DeleteBoardResult: { /** - * Board Id + * Board Id * @description The id of the board that was deleted. */ board_id: string; /** - * Deleted Board Images + * Deleted Board Images * @description The image names of the board-images relationships that were deleted. */ - deleted_board_images: (string)[]; + deleted_board_images: string[]; /** - * Deleted Images + * Deleted Images * @description The names of the images that were deleted. */ - deleted_images: (string)[]; + deleted_images: string[]; }; /** DeleteImagesFromListResult */ DeleteImagesFromListResult: { /** Deleted Images */ - deleted_images: (string)[]; + deleted_images: string[]; }; /** - * Denoise Latents + * Denoise Latents * @description Denoises noisy latents to decodable images */ DenoiseLatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default denoise_latents + * Type + * @default denoise_latents * @enum {string} */ type: "denoise_latents"; /** - * Noise + * Noise * @description Noise tensor */ noise?: components["schemas"]["LatentsField"]; /** - * Steps - * @description Number of steps to run + * Steps + * @description Number of steps to run * @default 10 */ steps?: number; /** - * CFG Scale - * @description Classifier-Free Guidance scale + * CFG Scale + * @description Classifier-Free Guidance scale * @default 7.5 */ - cfg_scale?: number | (number)[]; + cfg_scale?: number | number[]; /** - * Denoising Start - * @description When to start denoising, expressed a percentage of total steps + * Denoising Start + * @description When to start denoising, expressed a percentage of total steps * @default 0 */ denoising_start?: number; /** - * Denoising End - * @description When to stop denoising, expressed a percentage of total steps + * Denoising End + * @description When to stop denoising, expressed a percentage of total steps * @default 1 */ denoising_end?: number; /** - * Scheduler - * @description Scheduler to use during inference - * @default euler + * Scheduler + * @description Scheduler to use during inference + * @default euler * @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 * @description ControlNet(s) to apply */ - control?: components["schemas"]["ControlField"] | (components["schemas"]["ControlField"])[]; + control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][]; /** - * Latents + * Latents * @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Mask + * Mask * @description The mask to use for the operation */ mask?: components["schemas"]["ImageField"]; /** - * Positive Conditioning + * Positive Conditioning * @description Positive conditioning tensor */ positive_conditioning?: components["schemas"]["ConditioningField"]; /** - * Negative Conditioning + * Negative Conditioning * @description Negative conditioning tensor */ negative_conditioning?: components["schemas"]["ConditioningField"]; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; }; /** - * Divide Integers + * Divide Integers * @description Divides two numbers */ DivideInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default div + * Type + * @default div * @enum {string} */ type: "div"; /** - * A - * @description The first number + * A + * @description The first number * @default 0 */ a?: number; /** - * B - * @description The second number + * B + * @description The second number * @default 0 */ b?: number; }; /** - * Dynamic Prompt + * Dynamic Prompt * @description Parses a prompt using adieyal/dynamicprompts' random or combinatorial generator */ DynamicPromptInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default dynamic_prompt + * Type + * @default dynamic_prompt * @enum {string} */ type: "dynamic_prompt"; /** - * Prompt + * Prompt * @description The prompt to parse with dynamicprompts */ prompt?: string; /** - * Max Prompts - * @description The number of prompts to generate + * Max Prompts + * @description The number of prompts to generate * @default 1 */ max_prompts?: number; /** - * Combinatorial - * @description Whether to use the combinatorial generator + * Combinatorial + * @description Whether to use the combinatorial generator * @default false */ combinatorial?: boolean; }; /** - * Upscale (RealESRGAN) + * Upscale (RealESRGAN) * @description Upscales an image using RealESRGAN. */ ESRGANInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default esrgan + * Type + * @default esrgan * @enum {string} */ type: "esrgan"; /** - * Image + * Image * @description The input image */ image?: components["schemas"]["ImageField"]; /** - * Model Name - * @description The Real-ESRGAN model to use - * @default RealESRGAN_x4plus.pth + * Model Name + * @description The Real-ESRGAN model to use + * @default RealESRGAN_x4plus.pth * @enum {string} */ model_name?: "RealESRGAN_x4plus.pth" | "RealESRGAN_x4plus_anime_6B.pth" | "ESRGAN_SRx4_DF2KOST_official-ff704c30.pth" | "RealESRGAN_x2plus.pth"; @@ -1745,12 +1842,12 @@ export type components = { /** Edge */ Edge: { /** - * Source + * Source * @description The connection for the edge's from node and field */ source: components["schemas"]["EdgeConnection"]; /** - * Destination + * Destination * @description The connection for the edge's to node and field */ destination: components["schemas"]["EdgeConnection"]; @@ -1758,144 +1855,144 @@ export type components = { /** EdgeConnection */ EdgeConnection: { /** - * Node Id + * Node Id * @description The id of the node for this edge connection */ node_id: string; /** - * Field + * Field * @description The field for this connection */ field: string; }; /** - * Float Primitive Collection + * Float Primitive Collection * @description A collection of float primitive values */ FloatCollectionInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default float_collection + * Type + * @default float_collection * @enum {string} */ type: "float_collection"; /** - * Collection + * Collection * @description The collection of float values */ - collection?: (number)[]; + collection?: number[]; }; /** - * FloatCollectionOutput + * FloatCollectionOutput * @description Base class for nodes that output a collection of floats */ FloatCollectionOutput: { /** - * Type - * @default float_collection_output + * Type + * @default float_collection_output * @enum {string} */ type: "float_collection_output"; /** - * Collection + * Collection * @description The float collection */ - collection: (number)[]; + collection: number[]; }; /** - * Float Primitive + * Float Primitive * @description A float primitive value */ FloatInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default float + * Type + * @default float * @enum {string} */ type: "float"; /** - * Value - * @description The float value + * Value + * @description The float value * @default 0 */ value?: number; }; /** - * Float Range + * Float Range * @description Creates a range */ FloatLinearRangeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default float_range + * Type + * @default float_range * @enum {string} */ type: "float_range"; /** - * Start - * @description The first value of the range + * Start + * @description The first value of the range * @default 5 */ start?: number; /** - * Stop - * @description The last value of the range + * Stop + * @description The last value of the range * @default 10 */ stop?: number; /** - * Steps - * @description number of values to interpolate over (including start and stop) + * Steps + * @description number of values to interpolate over (including start and stop) * @default 30 */ steps?: number; }; /** - * FloatOutput + * FloatOutput * @description Base class for nodes that output a single float */ FloatOutput: { /** - * Type - * @default float_output + * Type + * @default float_output * @enum {string} */ type: "float_output"; /** - * Value + * Value * @description The output float */ value: number; @@ -1903,118 +2000,118 @@ export type components = { /** Graph */ Graph: { /** - * Id + * Id * @description The id of this graph */ id?: string; /** - * Nodes + * Nodes * @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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | 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"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | 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"]) | undefined; + [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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | 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"]; }; /** - * Edges + * Edges * @description The connections between nodes and their fields in this graph */ - edges?: (components["schemas"]["Edge"])[]; + edges?: components["schemas"]["Edge"][]; }; /** - * GraphExecutionState + * GraphExecutionState * @description Tracks the state of a graph execution */ GraphExecutionState: { /** - * Id + * Id * @description The id of the execution state */ id: string; /** - * Graph + * Graph * @description The graph being executed */ graph: components["schemas"]["Graph"]; /** - * Execution Graph + * Execution Graph * @description The expanded graph of activated and executed nodes */ execution_graph: components["schemas"]["Graph"]; /** - * Executed + * Executed * @description The set of node ids that have been executed */ - executed: (string)[]; + executed: string[]; /** - * Executed History + * Executed History * @description The list of node ids that have been executed, in order of execution */ - executed_history: (string)[]; + executed_history: string[]; /** - * Results + * Results * @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"]["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"]["MetadataAccumulatorOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined; + [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"]["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"]["MetadataAccumulatorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]; }; /** - * Errors + * Errors * @description Errors raised when executing nodes */ errors: { - [key: string]: string | undefined; + [key: string]: string; }; /** - * Prepared Source Mapping + * Prepared Source Mapping * @description The map of prepared nodes to original graph nodes */ prepared_source_mapping: { - [key: string]: string | undefined; + [key: string]: string; }; /** - * Source Prepared Mapping + * Source Prepared Mapping * @description The map of original graph nodes to prepared nodes */ source_prepared_mapping: { - [key: string]: (string)[] | undefined; + [key: string]: string[]; }; }; /** - * GraphInvocation + * GraphInvocation * @description Execute a graph */ GraphInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default graph + * Type + * @default graph * @enum {string} */ type: "graph"; /** - * Graph + * Graph * @description The graph to run */ graph?: components["schemas"]["Graph"]; }; /** - * GraphInvocationOutput + * GraphInvocationOutput * @description Base class for all invocation outputs */ GraphInvocationOutput: { /** - * Type - * @default graph_output + * Type + * @default graph_output * @enum {string} */ type: "graph_output"; @@ -2022,292 +2119,292 @@ export type components = { /** HTTPValidationError */ HTTPValidationError: { /** Detail */ - detail?: (components["schemas"]["ValidationError"])[]; + detail?: components["schemas"]["ValidationError"][]; }; /** - * HED (softedge) Processor + * HED (softedge) Processor * @description Applies HED edge detection to image */ HedImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default hed_image_processor + * Type + * @default hed_image_processor * @enum {string} */ type: "hed_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; /** - * Scribble - * @description Whether or not to use scribble mode + * Scribble + * @description Whether or not to use scribble mode * @default false */ scribble?: boolean; }; /** - * Blur Image + * Blur Image * @description Blurs an image */ ImageBlurInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_blur + * Type + * @default img_blur * @enum {string} */ type: "img_blur"; /** - * Image + * Image * @description The image to blur */ image?: components["schemas"]["ImageField"]; /** - * Radius - * @description The blur radius + * Radius + * @description The blur radius * @default 8 */ radius?: number; /** - * Blur Type - * @description The type of blur - * @default gaussian + * Blur Type + * @description The type of blur + * @default gaussian * @enum {string} */ blur_type?: "gaussian" | "box"; }; /** - * ImageCategory + * ImageCategory * @description The category of an image. - * + * * - GENERAL: The image is an output, init image, or otherwise an image without a specialized purpose. * - MASK: The image is a mask image. * - CONTROL: The image is a ControlNet control image. * - USER: The image is a user-provide image. - * - OTHER: The image is some other type of image with a specialized purpose. To be used by external nodes. + * - OTHER: The image is some other type of image with a specialized purpose. To be used by external nodes. * @enum {string} */ ImageCategory: "general" | "mask" | "control" | "user" | "other"; /** - * Extract Image Channel + * Extract Image Channel * @description Gets a channel from an image. */ ImageChannelInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_chan + * Type + * @default img_chan * @enum {string} */ type: "img_chan"; /** - * Image + * Image * @description The image to get the channel from */ image?: components["schemas"]["ImageField"]; /** - * Channel - * @description The channel to get - * @default A + * Channel + * @description The channel to get + * @default A * @enum {string} */ channel?: "A" | "R" | "G" | "B"; }; /** - * Image Primitive Collection + * Image Primitive Collection * @description A collection of image primitive values */ ImageCollectionInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default image_collection + * Type + * @default image_collection * @enum {string} */ type: "image_collection"; /** - * Collection - * @description The collection of image values + * Collection + * @description The collection of image values * @default 0 */ - collection?: (components["schemas"]["ImageField"])[]; + collection?: components["schemas"]["ImageField"][]; }; /** - * ImageCollectionOutput + * ImageCollectionOutput * @description Base class for nodes that output a collection of images */ ImageCollectionOutput: { /** - * Type - * @default image_collection_output + * Type + * @default image_collection_output * @enum {string} */ type: "image_collection_output"; /** - * Collection + * Collection * @description The output images */ - collection: (components["schemas"]["ImageField"])[]; + collection: components["schemas"]["ImageField"][]; }; /** - * Convert Image Mode + * Convert Image Mode * @description Converts an image to a different mode. */ ImageConvertInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_conv + * Type + * @default img_conv * @enum {string} */ type: "img_conv"; /** - * Image + * Image * @description The image to convert */ image?: components["schemas"]["ImageField"]; /** - * Mode - * @description The mode to convert to - * @default L + * Mode + * @description The mode to convert to + * @default L * @enum {string} */ mode?: "L" | "RGB" | "RGBA" | "CMYK" | "YCbCr" | "LAB" | "HSV" | "I" | "F"; }; /** - * Crop Image + * Crop Image * @description Crops an image to a specified box. The box can be outside of the image. */ ImageCropInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_crop + * Type + * @default img_crop * @enum {string} */ type: "img_crop"; /** - * Image + * Image * @description The image to crop */ image?: components["schemas"]["ImageField"]; /** - * X - * @description The left x coordinate of the crop rectangle + * X + * @description The left x coordinate of the crop rectangle * @default 0 */ x?: number; /** - * Y - * @description The top y coordinate of the crop rectangle + * Y + * @description The top y coordinate of the crop rectangle * @default 0 */ y?: number; /** - * Width - * @description The width of the crop rectangle + * Width + * @description The width of the crop rectangle * @default 512 */ width?: number; /** - * Height - * @description The height of the crop rectangle + * Height + * @description The height of the crop rectangle * @default 512 */ height?: number; }; /** - * ImageDTO + * ImageDTO * @description Deserialized image record, enriched for the frontend. */ ImageDTO: { /** - * Image Name + * Image Name * @description The unique name of the image. */ image_name: string; /** - * Image Url + * Image Url * @description The URL of the image. */ image_url: string; /** - * Thumbnail Url + * Thumbnail Url * @description The URL of the image's thumbnail. */ thumbnail_url: string; @@ -2316,434 +2413,434 @@ export type components = { /** @description The category of the image. */ image_category: components["schemas"]["ImageCategory"]; /** - * Width + * Width * @description The width of the image in px. */ width: number; /** - * Height + * Height * @description The height of the image in px. */ height: number; /** - * Created At + * Created At * @description The created timestamp of the image. */ created_at: string; /** - * Updated At + * Updated At * @description The updated timestamp of the image. */ updated_at: string; /** - * Deleted At + * Deleted At * @description The deleted timestamp of the image. */ deleted_at?: string; /** - * Is Intermediate + * Is Intermediate * @description Whether this is an intermediate image. */ is_intermediate: boolean; /** - * Session Id + * Session Id * @description The session ID that generated this image, if it is a generated image. */ session_id?: string; /** - * Node Id + * Node Id * @description The node ID that generated this image, if it is a generated image. */ node_id?: string; /** - * Starred + * Starred * @description Whether this image is starred. */ starred: boolean; /** - * Board Id + * Board Id * @description The id of the board the image belongs to, if one exists. */ board_id?: string; }; /** - * ImageField + * ImageField * @description An image primitive field */ ImageField: { /** - * Image Name + * Image Name * @description The name of the image */ image_name: string; }; /** - * Image Hue Adjustment + * Image Hue Adjustment * @description Adjusts the Hue of an image. */ ImageHueAdjustmentInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_hue_adjust + * Type + * @default img_hue_adjust * @enum {string} */ type: "img_hue_adjust"; /** - * Image + * Image * @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** - * Hue - * @description The degrees by which to rotate the hue, 0-360 + * Hue + * @description The degrees by which to rotate the hue, 0-360 * @default 0 */ hue?: number; }; /** - * Inverse Lerp Image + * Inverse Lerp Image * @description Inverse linear interpolation of all pixels of an image */ ImageInverseLerpInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_ilerp + * Type + * @default img_ilerp * @enum {string} */ type: "img_ilerp"; /** - * Image + * Image * @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** - * Min - * @description The minimum input value + * Min + * @description The minimum input value * @default 0 */ min?: number; /** - * Max - * @description The maximum input value + * Max + * @description The maximum input value * @default 255 */ max?: number; }; /** - * Image Primitive + * Image Primitive * @description An image primitive value */ ImageInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default image + * Type + * @default image * @enum {string} */ type: "image"; /** - * Image + * Image * @description The image to load */ image?: components["schemas"]["ImageField"]; }; /** - * Lerp Image + * Lerp Image * @description Linear interpolation of all pixels of an image */ ImageLerpInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_lerp + * Type + * @default img_lerp * @enum {string} */ type: "img_lerp"; /** - * Image + * Image * @description The image to lerp */ image?: components["schemas"]["ImageField"]; /** - * Min - * @description The minimum output value + * Min + * @description The minimum output value * @default 0 */ min?: number; /** - * Max - * @description The maximum output value + * Max + * @description The maximum output value * @default 255 */ max?: number; }; /** - * Image Luminosity Adjustment + * Image Luminosity Adjustment * @description Adjusts the Luminosity (Value) of an image. */ ImageLuminosityAdjustmentInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_luminosity_adjust + * Type + * @default img_luminosity_adjust * @enum {string} */ type: "img_luminosity_adjust"; /** - * Image + * Image * @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** - * Luminosity - * @description The factor by which to adjust the luminosity (value) + * Luminosity + * @description The factor by which to adjust the luminosity (value) * @default 1 */ luminosity?: number; }; /** - * ImageMetadata + * ImageMetadata * @description An image's generation metadata */ ImageMetadata: { /** - * Metadata + * Metadata * @description The image's core metadata, if it was created in the Linear or Canvas UI */ metadata?: Record; /** - * Graph + * Graph * @description The graph that created the image */ graph?: Record; }; /** - * Multiply Images + * Multiply Images * @description Multiplies two images together using `PIL.ImageChops.multiply()`. */ ImageMultiplyInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_mul + * Type + * @default img_mul * @enum {string} */ type: "img_mul"; /** - * Image1 + * Image1 * @description The first image to multiply */ image1?: components["schemas"]["ImageField"]; /** - * Image2 + * Image2 * @description The second image to multiply */ image2?: components["schemas"]["ImageField"]; }; /** - * Blur NSFW Image + * Blur NSFW Image * @description Add blur to NSFW-flagged images */ ImageNSFWBlurInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_nsfw + * Type + * @default img_nsfw * @enum {string} */ type: "img_nsfw"; /** - * Metadata + * Metadata * @description Optional core metadata to be written to image */ metadata?: components["schemas"]["CoreMetadata"]; /** - * Image + * Image * @description The image to check */ image?: components["schemas"]["ImageField"]; }; /** - * ImageOutput + * ImageOutput * @description Base class for nodes that output a single image */ ImageOutput: { /** - * Type - * @default image_output + * Type + * @default image_output * @enum {string} */ type: "image_output"; /** - * Image + * Image * @description The output image */ image: components["schemas"]["ImageField"]; /** - * Width + * Width * @description The width of the image in pixels */ width: number; /** - * Height + * Height * @description The height of the image in pixels */ height: number; }; /** - * Paste Image + * Paste Image * @description Pastes an image into another image. */ ImagePasteInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_paste + * Type + * @default img_paste * @enum {string} */ type: "img_paste"; /** - * Base Image + * Base Image * @description The base image */ base_image?: components["schemas"]["ImageField"]; /** - * Image + * Image * @description The image to paste */ image?: components["schemas"]["ImageField"]; /** - * Mask + * Mask * @description The mask to use when pasting */ mask?: components["schemas"]["ImageField"]; /** - * X - * @description The left x coordinate at which to paste the image + * X + * @description The left x coordinate at which to paste the image * @default 0 */ x?: number; /** - * Y - * @description The top y coordinate at which to paste the image + * Y + * @description The top y coordinate at which to paste the image * @default 0 */ y?: number; }; /** - * ImageProcessorInvocation + * ImageProcessorInvocation * @description Base class for invocations that preprocess images for ControlNet */ ImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default image_processor + * Type + * @default image_processor * @enum {string} */ type: "image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; }; /** - * ImageRecordChanges + * ImageRecordChanges * @description A set of changes to apply to an image record. - * + * * Only limited changes are valid: * - `image_category`: change the category of an image * - `session_id`: change the session associated with an image @@ -2754,244 +2851,244 @@ export type components = { /** @description The image's new category. */ image_category?: components["schemas"]["ImageCategory"]; /** - * Session Id + * Session Id * @description The image's new session ID. */ session_id?: string; /** - * Is Intermediate + * Is Intermediate * @description The image's new `is_intermediate` flag. */ is_intermediate?: boolean; /** - * Starred + * Starred * @description The image's new `starred` state */ starred?: boolean; }; /** - * Resize Image + * Resize Image * @description Resizes an image to specific dimensions */ ImageResizeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_resize + * Type + * @default img_resize * @enum {string} */ type: "img_resize"; /** - * Image + * Image * @description The image to resize */ image?: components["schemas"]["ImageField"]; /** - * Width - * @description The width to resize to (px) + * Width + * @description The width to resize to (px) * @default 512 */ width?: number; /** - * Height - * @description The height to resize to (px) + * Height + * @description The height to resize to (px) * @default 512 */ height?: number; /** - * Resample Mode - * @description The resampling mode - * @default bicubic + * Resample Mode + * @description The resampling mode + * @default bicubic * @enum {string} */ resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos"; }; /** - * Image Saturation Adjustment + * Image Saturation Adjustment * @description Adjusts the Saturation of an image. */ ImageSaturationAdjustmentInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_saturation_adjust + * Type + * @default img_saturation_adjust * @enum {string} */ type: "img_saturation_adjust"; /** - * Image + * Image * @description The image to adjust */ image?: components["schemas"]["ImageField"]; /** - * Saturation - * @description The factor by which to adjust the saturation + * Saturation + * @description The factor by which to adjust the saturation * @default 1 */ saturation?: number; }; /** - * Scale Image + * Scale Image * @description Scales an image by a factor */ ImageScaleInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_scale + * Type + * @default img_scale * @enum {string} */ type: "img_scale"; /** - * Image + * Image * @description The image to scale */ image?: components["schemas"]["ImageField"]; /** - * Scale Factor - * @description The factor by which to scale the image + * Scale Factor + * @description The factor by which to scale the image * @default 2 */ scale_factor?: number; /** - * Resample Mode - * @description The resampling mode - * @default bicubic + * Resample Mode + * @description The resampling mode + * @default bicubic * @enum {string} */ resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos"; }; /** - * Image to Latents + * Image to Latents * @description Encodes an image into latents. */ ImageToLatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default i2l + * Type + * @default i2l * @enum {string} */ type: "i2l"; /** - * Image + * Image * @description The image to encode */ image?: components["schemas"]["ImageField"]; /** - * Vae + * Vae * @description VAE */ vae?: components["schemas"]["VaeField"]; /** - * Tiled - * @description Processing using overlapping tiles (reduce memory consumption) + * Tiled + * @description Processing using overlapping tiles (reduce memory consumption) * @default false */ tiled?: boolean; /** - * Fp32 - * @description Whether or not to use full float32 precision + * Fp32 + * @description Whether or not to use full float32 precision * @default false */ fp32?: boolean; }; /** - * ImageUrlsDTO + * ImageUrlsDTO * @description The URLs for an image and its thumbnail. */ ImageUrlsDTO: { /** - * Image Name + * Image Name * @description The unique name of the image. */ image_name: string; /** - * Image Url + * Image Url * @description The URL of the image. */ image_url: string; /** - * Thumbnail Url + * Thumbnail Url * @description The URL of the image's thumbnail. */ thumbnail_url: string; }; /** - * Add Invisible Watermark + * Add Invisible Watermark * @description Add an invisible watermark to an image */ ImageWatermarkInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default img_watermark + * Type + * @default img_watermark * @enum {string} */ type: "img_watermark"; /** - * Image + * Image * @description The image to check */ image?: components["schemas"]["ImageField"]; /** - * Text - * @description Watermark text + * Text + * @description Watermark text * @default InvokeAI */ text?: string; /** - * Metadata + * Metadata * @description Optional core metadata to be written to image */ metadata?: components["schemas"]["CoreMetadata"]; @@ -2999,41 +3096,41 @@ export type components = { /** ImagesUpdatedFromListResult */ ImagesUpdatedFromListResult: { /** - * Updated Image Names + * Updated Image Names * @description The image names that were updated */ - updated_image_names: (string)[]; + updated_image_names: string[]; }; /** - * Solid Color Infill + * Solid Color Infill * @description Infills transparent areas of an image with a solid color */ InfillColorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default infill_rgba + * Type + * @default infill_rgba * @enum {string} */ type: "infill_rgba"; /** - * Image + * Image * @description The image to infill */ image?: components["schemas"]["ImageField"]; /** - * Color - * @description The color to use to infill + * Color + * @description The color to use to infill * @default { * "r": 127, * "g": 127, @@ -3044,537 +3141,565 @@ export type components = { color?: components["schemas"]["ColorField"]; }; /** - * PatchMatch Infill + * PatchMatch Infill * @description Infills transparent areas of an image using the PatchMatch algorithm */ InfillPatchMatchInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default infill_patchmatch + * Type + * @default infill_patchmatch * @enum {string} */ type: "infill_patchmatch"; /** - * Image + * Image * @description The image to infill */ image?: components["schemas"]["ImageField"]; }; /** - * Tile Infill + * Tile Infill * @description Infills transparent areas of an image with tiles of the image */ InfillTileInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default infill_tile + * Type + * @default infill_tile * @enum {string} */ type: "infill_tile"; /** - * Image + * Image * @description The image to infill */ image?: components["schemas"]["ImageField"]; /** - * Tile Size - * @description The tile size (px) + * Tile Size + * @description The tile size (px) * @default 32 */ tile_size?: number; /** - * Seed + * Seed * @description The seed to use for tile generation (omit for random) */ seed?: number; }; /** - * Integer Primitive Collection + * Integer Primitive Collection * @description A collection of integer primitive values */ IntegerCollectionInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default integer_collection + * Type + * @default integer_collection * @enum {string} */ type: "integer_collection"; /** - * Collection - * @description The collection of integer values + * Collection + * @description The collection of integer values * @default 0 */ - collection?: (number)[]; + collection?: number[]; }; /** - * IntegerCollectionOutput + * IntegerCollectionOutput * @description Base class for nodes that output a collection of integers */ IntegerCollectionOutput: { /** - * Type - * @default integer_collection_output + * Type + * @default integer_collection_output * @enum {string} */ type: "integer_collection_output"; /** - * Collection + * Collection * @description The int collection */ - collection: (number)[]; + collection: number[]; }; /** - * Integer Primitive + * Integer Primitive * @description An integer primitive value */ IntegerInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default integer + * Type + * @default integer * @enum {string} */ type: "integer"; /** - * Value - * @description The integer value + * Value + * @description The integer value * @default 0 */ value?: number; }; /** - * IntegerOutput + * IntegerOutput * @description Base class for nodes that output a single integer */ IntegerOutput: { /** - * Type - * @default integer_output + * Type + * @default integer_output * @enum {string} */ type: "integer_output"; /** - * Value + * Value * @description The output integer */ value: number; }; /** - * IterateInvocation + * IterateInvocation * @description Iterates over a list of items */ IterateInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default iterate + * Type + * @default iterate * @enum {string} */ type: "iterate"; /** - * Collection + * Collection * @description The list of items to iterate over */ - collection?: (unknown)[]; + collection?: unknown[]; /** - * Index - * @description The index, will be provided on executed iterators + * Index + * @description The index, will be provided on executed iterators * @default 0 */ index?: number; }; /** - * IterateInvocationOutput + * IterateInvocationOutput * @description Used to connect iteration outputs. Will be expanded to a specific output. */ IterateInvocationOutput: { /** - * Type - * @default iterate_output + * Type + * @default iterate_output * @enum {string} */ type: "iterate_output"; /** - * Collection Item + * Collection Item * @description The item being iterated over */ item?: unknown; }; /** - * Latents Primitive Collection - * @description A collection of latents tensor primitive values + * LaMa Infill + * @description Infills transparent areas of an image using the LaMa model */ - LatentsCollectionInvocation: { + LaMaInfillInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default latents_collection + * Type + * @default infill_lama + * @enum {string} + */ + type: "infill_lama"; + /** + * Image + * @description The image to infill + */ + image?: components["schemas"]["ImageField"]; + }; + /** + * Latents Primitive Collection + * @description A collection of latents tensor primitive values + */ + LatentsCollectionInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default latents_collection * @enum {string} */ type: "latents_collection"; /** - * Collection + * Collection * @description The collection of latents tensors */ - collection?: (components["schemas"]["LatentsField"])[]; + collection?: components["schemas"]["LatentsField"][]; }; /** - * LatentsCollectionOutput + * LatentsCollectionOutput * @description Base class for nodes that output a collection of latents tensors */ LatentsCollectionOutput: { /** - * Type - * @default latents_collection_output + * Type + * @default latents_collection_output * @enum {string} */ type: "latents_collection_output"; /** - * Collection + * Collection * @description Latents tensor */ - collection: (components["schemas"]["LatentsField"])[]; + collection: components["schemas"]["LatentsField"][]; }; /** - * LatentsField + * LatentsField * @description A latents tensor primitive field */ LatentsField: { /** - * Latents Name + * Latents Name * @description The name of the latents */ latents_name: string; /** - * Seed + * Seed * @description Seed used to generate this latents */ seed?: number; }; /** - * Latents Primitive + * Latents Primitive * @description A latents tensor primitive value */ LatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default latents + * Type + * @default latents * @enum {string} */ type: "latents"; /** - * Latents + * Latents * @description The latents tensor */ latents?: components["schemas"]["LatentsField"]; }; /** - * LatentsOutput + * LatentsOutput * @description Base class for nodes that output a single latents tensor */ LatentsOutput: { /** - * Type - * @default latents_output + * Type + * @default latents_output * @enum {string} */ type: "latents_output"; /** - * Latents + * Latents * @description Latents tensor */ latents: components["schemas"]["LatentsField"]; /** - * Width + * Width * @description Width of output (px) */ width: number; /** - * Height + * Height * @description Height of output (px) */ height: number; }; /** - * Latents to Image + * Latents to Image * @description Generates an image from latents. */ LatentsToImageInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default l2i + * Type + * @default l2i * @enum {string} */ type: "l2i"; /** - * Tiled - * @description Processing using overlapping tiles (reduce memory consumption) + * Tiled + * @description Processing using overlapping tiles (reduce memory consumption) * @default false */ tiled?: boolean; /** - * Fp32 - * @description Whether or not to use full float32 precision + * Fp32 + * @description Whether or not to use full float32 precision * @default false */ fp32?: boolean; /** - * Metadata + * Metadata * @description Optional core metadata to be written to image */ metadata?: components["schemas"]["CoreMetadata"]; /** - * Latents + * Latents * @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Vae + * Vae * @description VAE */ vae?: components["schemas"]["VaeField"]; }; /** - * Leres (Depth) Processor + * Leres (Depth) Processor * @description Applies leres processing to image */ LeresImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default leres_image_processor + * Type + * @default leres_image_processor * @enum {string} */ type: "leres_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Thr A - * @description Leres parameter `thr_a` + * Thr A + * @description Leres parameter `thr_a` * @default 0 */ thr_a?: number; /** - * Thr B - * @description Leres parameter `thr_b` + * Thr B + * @description Leres parameter `thr_b` * @default 0 */ thr_b?: number; /** - * Boost - * @description Whether to use boost mode + * Boost + * @description Whether to use boost mode * @default false */ boost?: boolean; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; }; /** - * Lineart Anime Processor + * Lineart Anime Processor * @description Applies line art anime processing to image */ LineartAnimeImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default lineart_anime_image_processor + * Type + * @default lineart_anime_image_processor * @enum {string} */ type: "lineart_anime_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; }; /** - * Lineart Processor + * Lineart Processor * @description Applies line art processing to image */ LineartImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default lineart_image_processor + * Type + * @default lineart_image_processor * @enum {string} */ type: "lineart_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; /** - * Coarse - * @description Whether to use coarse mode + * Coarse + * @description Whether to use coarse mode * @default false */ coarse?: boolean; }; /** - * LoRAMetadataField + * LoRAMetadataField * @description LoRA metadata for an image generated in InvokeAI. */ LoRAMetadataField: { /** - * Lora + * Lora * @description The LoRA model */ lora: components["schemas"]["LoRAModelField"]; /** - * Weight + * Weight * @description The weight of the LoRA model */ weight: number; @@ -3585,7 +3710,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "lora"; @@ -3597,12 +3722,12 @@ export type components = { error?: components["schemas"]["ModelError"]; }; /** - * LoRAModelField + * LoRAModelField * @description LoRA model field */ LoRAModelField: { /** - * Model Name + * Model Name * @description Name of the LoRA model */ model_name: string; @@ -3610,21 +3735,21 @@ export type components = { base_model: components["schemas"]["BaseModelType"]; }; /** - * LoRAModelFormat - * @description An enumeration. + * LoRAModelFormat + * @description An enumeration. * @enum {string} */ LoRAModelFormat: "lycoris" | "diffusers"; /** - * LogLevel - * @description An enumeration. + * LogLevel + * @description An enumeration. * @enum {integer} */ LogLevel: 0 | 10 | 20 | 30 | 40 | 50; /** LoraInfo */ LoraInfo: { /** - * Model Name + * Model Name * @description Info to load submodel */ model_name: string; @@ -3635,84 +3760,84 @@ export type components = { /** @description Info to load submodel */ submodel?: components["schemas"]["SubModelType"]; /** - * Weight + * Weight * @description Lora's weight which to use when apply to model */ weight: number; }; /** - * LoRA + * LoRA * @description Apply selected lora to unet and text_encoder. */ LoraLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default lora_loader + * Type + * @default lora_loader * @enum {string} */ type: "lora_loader"; /** - * LoRA + * LoRA * @description LoRA model to load */ lora: components["schemas"]["LoRAModelField"]; /** - * Weight - * @description The weight at which the LoRA is applied to each model + * Weight + * @description The weight at which the LoRA is applied to each model * @default 0.75 */ weight?: number; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * CLIP + * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; }; /** - * LoraLoaderOutput + * LoraLoaderOutput * @description Model loader output */ LoraLoaderOutput: { /** - * Type - * @default lora_loader_output + * Type + * @default lora_loader_output * @enum {string} */ type: "lora_loader_output"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * CLIP + * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; }; /** - * MainModelField + * MainModelField * @description Main model field */ MainModelField: { /** - * Model Name + * Model Name * @description Name of the model */ model_name: string; @@ -3722,466 +3847,466 @@ export type components = { model_type: components["schemas"]["ModelType"]; }; /** - * Main Model + * Main Model * @description Loads a main model, outputting its submodels. */ MainModelLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default main_model_loader + * Type + * @default main_model_loader * @enum {string} */ type: "main_model_loader"; /** - * Model + * Model * @description Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["MainModelField"]; }; /** - * Combine Mask + * Combine Mask * @description Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`. */ MaskCombineInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default mask_combine + * Type + * @default mask_combine * @enum {string} */ type: "mask_combine"; /** - * Mask1 + * Mask1 * @description The first mask to combine */ mask1?: components["schemas"]["ImageField"]; /** - * Mask2 + * Mask2 * @description The second image to combine */ mask2?: components["schemas"]["ImageField"]; }; /** - * Mask Edge + * Mask Edge * @description Applies an edge mask to an image */ MaskEdgeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default mask_edge + * Type + * @default mask_edge * @enum {string} */ type: "mask_edge"; /** - * Image + * Image * @description The image to apply the mask to */ image?: components["schemas"]["ImageField"]; /** - * Edge Size + * Edge Size * @description The size of the edge */ edge_size?: number; /** - * Edge Blur + * Edge Blur * @description The amount of blur on the edge */ edge_blur?: number; /** - * Low Threshold + * Low Threshold * @description First threshold for the hysteresis procedure in Canny edge detection */ low_threshold?: number; /** - * High Threshold + * High Threshold * @description Second threshold for the hysteresis procedure in Canny edge detection */ high_threshold?: number; }; /** - * Mask from Alpha + * Mask from Alpha * @description Extracts the alpha channel of an image as a mask. */ MaskFromAlphaInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default tomask + * Type + * @default tomask * @enum {string} */ type: "tomask"; /** - * Image + * Image * @description The image to create the mask from */ image?: components["schemas"]["ImageField"]; /** - * Invert - * @description Whether or not to invert the mask + * Invert + * @description Whether or not to invert the mask * @default false */ invert?: boolean; }; /** - * Mediapipe Face Processor + * Mediapipe Face Processor * @description Applies mediapipe face processing to image */ MediapipeFaceProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default mediapipe_face_processor + * Type + * @default mediapipe_face_processor * @enum {string} */ type: "mediapipe_face_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Max Faces - * @description Maximum number of faces to detect + * Max Faces + * @description Maximum number of faces to detect * @default 1 */ max_faces?: number; /** - * Min Confidence - * @description Minimum confidence for face detection + * Min Confidence + * @description Minimum confidence for face detection * @default 0.5 */ min_confidence?: number; }; /** - * MergeInterpolationMethod - * @description An enumeration. + * MergeInterpolationMethod + * @description An enumeration. * @enum {string} */ MergeInterpolationMethod: "weighted_sum" | "sigmoid" | "inv_sigmoid" | "add_difference"; /** - * Metadata Accumulator + * Metadata Accumulator * @description Outputs a Core Metadata Object */ MetadataAccumulatorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default metadata_accumulator + * Type + * @default metadata_accumulator * @enum {string} */ type: "metadata_accumulator"; /** - * Generation Mode + * Generation Mode * @description The generation mode that output this image */ generation_mode?: string; /** - * Positive Prompt + * Positive Prompt * @description The positive prompt parameter */ positive_prompt?: string; /** - * Negative Prompt + * Negative Prompt * @description The negative prompt parameter */ negative_prompt?: string; /** - * Width + * Width * @description The width parameter */ width?: number; /** - * Height + * Height * @description The height parameter */ height?: number; /** - * Seed + * Seed * @description The seed used for noise generation */ seed?: number; /** - * Rand Device + * Rand Device * @description The device used for random number generation */ rand_device?: string; /** - * Cfg Scale + * Cfg Scale * @description The classifier-free guidance scale parameter */ cfg_scale?: number; /** - * Steps + * Steps * @description The number of steps used for inference */ steps?: number; /** - * Scheduler + * Scheduler * @description The scheduler used for inference */ scheduler?: string; /** - * Clip Skip + * Clip Skip * @description The number of skipped CLIP layers */ clip_skip?: number; /** - * Model + * Model * @description The main model used for inference */ model?: components["schemas"]["MainModelField"]; /** - * Controlnets + * Controlnets * @description The ControlNets used for inference */ - controlnets?: (components["schemas"]["ControlField"])[]; + controlnets?: components["schemas"]["ControlField"][]; /** - * Loras + * Loras * @description The LoRAs used for inference */ - loras?: (components["schemas"]["LoRAMetadataField"])[]; + loras?: components["schemas"]["LoRAMetadataField"][]; /** - * Strength + * Strength * @description The strength used for latents-to-latents */ strength?: number; /** - * Init Image + * Init Image * @description The name of the initial image */ init_image?: string; /** - * Vae + * Vae * @description The VAE used for decoding, if the main model's default was not used */ vae?: components["schemas"]["VAEModelField"]; /** - * Positive Style Prompt + * Positive Style Prompt * @description The positive style prompt parameter */ positive_style_prompt?: string; /** - * Negative Style Prompt + * Negative Style Prompt * @description The negative style prompt parameter */ negative_style_prompt?: string; /** - * Refiner Model + * Refiner Model * @description The SDXL Refiner model used */ refiner_model?: components["schemas"]["MainModelField"]; /** - * Refiner Cfg Scale + * Refiner Cfg Scale * @description The classifier-free guidance scale parameter used for the refiner */ refiner_cfg_scale?: number; /** - * Refiner Steps + * Refiner Steps * @description The number of steps used for the refiner */ refiner_steps?: number; /** - * Refiner Scheduler + * Refiner Scheduler * @description The scheduler used for the refiner */ refiner_scheduler?: string; /** - * Refiner Positive Aesthetic Store + * Refiner Positive Aesthetic Store * @description The aesthetic score used for the refiner */ refiner_positive_aesthetic_store?: number; /** - * Refiner Negative Aesthetic Store + * Refiner Negative Aesthetic Store * @description The aesthetic score used for the refiner */ refiner_negative_aesthetic_store?: number; /** - * Refiner Start + * Refiner Start * @description The start value used for refiner denoising */ refiner_start?: number; }; /** - * MetadataAccumulatorOutput + * MetadataAccumulatorOutput * @description The output of the MetadataAccumulator node */ MetadataAccumulatorOutput: { /** - * Type - * @default metadata_accumulator_output + * Type + * @default metadata_accumulator_output * @enum {string} */ type: "metadata_accumulator_output"; /** - * Metadata + * Metadata * @description The core metadata for the image */ metadata: components["schemas"]["CoreMetadata"]; }; /** - * Midas (Depth) Processor + * Midas (Depth) Processor * @description Applies Midas depth processing to image */ MidasDepthImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default midas_depth_image_processor + * Type + * @default midas_depth_image_processor * @enum {string} */ type: "midas_depth_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * A Mult - * @description Midas parameter `a_mult` (a = a_mult * PI) + * A Mult + * @description Midas parameter `a_mult` (a = a_mult * PI) * @default 2 */ a_mult?: number; /** - * Bg Th - * @description Midas parameter `bg_th` + * Bg Th + * @description Midas parameter `bg_th` * @default 0.1 */ bg_th?: number; }; /** - * MLSD Processor + * MLSD Processor * @description Applies MLSD processing to image */ MlsdImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default mlsd_image_processor + * Type + * @default mlsd_image_processor * @enum {string} */ type: "mlsd_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; /** - * Thr V - * @description MLSD parameter `thr_v` + * Thr V + * @description MLSD parameter `thr_v` * @default 0.1 */ thr_v?: number; /** - * Thr D - * @description MLSD parameter `thr_d` + * Thr D + * @description MLSD parameter `thr_d` * @default 0.1 */ thr_d?: number; }; /** - * ModelError - * @description An enumeration. + * ModelError + * @description An enumeration. * @enum {string} */ ModelError: "not_found"; /** ModelInfo */ ModelInfo: { /** - * Model Name + * Model Name * @description Info to load submodel */ model_name: string; @@ -4193,41 +4318,41 @@ export type components = { submodel?: components["schemas"]["SubModelType"]; }; /** - * ModelLoaderOutput + * ModelLoaderOutput * @description Model loader output */ ModelLoaderOutput: { /** - * Type - * @default model_loader_output + * Type + * @default model_loader_output * @enum {string} */ type: "model_loader_output"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet: components["schemas"]["UNetField"]; /** - * CLIP + * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip: components["schemas"]["ClipField"]; /** - * VAE + * VAE * @description VAE */ vae: components["schemas"]["VaeField"]; }; /** - * ModelType - * @description An enumeration. + * ModelType + * @description An enumeration. * @enum {string} */ ModelType: "onnx" | "main" | "vae" | "lora" | "controlnet" | "embedding"; /** - * ModelVariantType - * @description An enumeration. + * ModelVariantType + * @description An enumeration. * @enum {string} */ ModelVariantType: "normal" | "inpaint" | "depth"; @@ -4237,254 +4362,254 @@ export type components = { models: (components["schemas"]["ONNXStableDiffusion1ModelConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelCheckpointConfig"] | components["schemas"]["ControlNetModelDiffusersConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["ONNXStableDiffusion2ModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusionXLModelCheckpointConfig"] | components["schemas"]["StableDiffusionXLModelDiffusersConfig"])[]; }; /** - * Multiply Integers + * Multiply Integers * @description Multiplies two numbers */ MultiplyInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default mul + * Type + * @default mul * @enum {string} */ type: "mul"; /** - * A - * @description The first number + * A + * @description The first number * @default 0 */ a?: number; /** - * B - * @description The second number + * B + * @description The second number * @default 0 */ b?: number; }; /** - * Noise + * Noise * @description Generates latent noise. */ NoiseInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default noise + * Type + * @default noise * @enum {string} */ type: "noise"; /** - * Seed + * Seed * @description Seed for random number generation */ seed?: number; /** - * Width - * @description Width of output (px) + * Width + * @description Width of output (px) * @default 512 */ width?: number; /** - * Height - * @description Height of output (px) + * Height + * @description Height of output (px) * @default 512 */ height?: number; /** - * Use Cpu - * @description Use CPU for noise generation (for reproducible results across platforms) + * Use Cpu + * @description Use CPU for noise generation (for reproducible results across platforms) * @default true */ use_cpu?: boolean; }; /** - * NoiseOutput + * NoiseOutput * @description Invocation noise output */ NoiseOutput: { /** - * Type - * @default noise_output + * Type + * @default noise_output * @enum {string} */ type: "noise_output"; /** - * Noise + * Noise * @description Noise tensor */ noise?: components["schemas"]["LatentsField"]; /** - * Width + * Width * @description Width of output (px) */ width: number; /** - * Height + * Height * @description Height of output (px) */ height: number; }; /** - * Normal BAE Processor + * Normal BAE Processor * @description Applies NormalBae processing to image */ NormalbaeImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default normalbae_image_processor + * Type + * @default normalbae_image_processor * @enum {string} */ type: "normalbae_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; }; /** - * ONNX Latents to Image + * ONNX Latents to Image * @description Generates an image from latents. */ ONNXLatentsToImageInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default l2i_onnx + * Type + * @default l2i_onnx * @enum {string} */ type: "l2i_onnx"; /** - * Latents + * Latents * @description Denoised latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Vae + * Vae * @description VAE */ vae?: components["schemas"]["VaeField"]; /** - * Metadata + * Metadata * @description Optional core metadata to be written to image */ metadata?: components["schemas"]["CoreMetadata"]; }; /** - * ONNXModelLoaderOutput + * ONNXModelLoaderOutput * @description Model loader output */ ONNXModelLoaderOutput: { /** - * Type - * @default model_loader_output_onnx + * Type + * @default model_loader_output_onnx * @enum {string} */ type: "model_loader_output_onnx"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * CLIP + * CLIP * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; /** - * VAE Decoder + * VAE Decoder * @description VAE */ vae_decoder?: components["schemas"]["VaeField"]; /** - * VAE Encoder + * VAE Encoder * @description VAE */ vae_encoder?: components["schemas"]["VaeField"]; }; /** - * ONNX Prompt (Raw) + * ONNX Prompt (Raw) * @description A node to process inputs and produce outputs. * May use dependency injection in __init__ to receive providers. */ ONNXPromptInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default prompt_onnx + * Type + * @default prompt_onnx * @enum {string} */ type: "prompt_onnx"; /** - * Prompt - * @description Raw prompt text (no parsing) + * Prompt + * @description Raw prompt text (no parsing) * @default */ prompt?: string; /** - * Clip + * Clip * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; @@ -4495,7 +4620,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "onnx"; @@ -4504,7 +4629,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "onnx"; @@ -4517,7 +4642,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "onnx"; @@ -4526,7 +4651,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "onnx"; @@ -4537,138 +4662,138 @@ export type components = { upcast_attention: boolean; }; /** - * ONNX Text to Latents + * ONNX Text to Latents * @description Generates latents from conditionings. */ ONNXTextToLatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default t2l_onnx + * Type + * @default t2l_onnx * @enum {string} */ type: "t2l_onnx"; /** - * Positive Conditioning + * Positive Conditioning * @description Positive conditioning tensor */ positive_conditioning?: components["schemas"]["ConditioningField"]; /** - * Negative Conditioning + * Negative Conditioning * @description Negative conditioning tensor */ negative_conditioning?: components["schemas"]["ConditioningField"]; /** - * Noise + * Noise * @description Noise tensor */ noise?: components["schemas"]["LatentsField"]; /** - * Steps - * @description Number of steps to run + * Steps + * @description Number of steps to run * @default 10 */ steps?: number; /** - * Cfg Scale - * @description Classifier-Free Guidance scale + * Cfg Scale + * @description Classifier-Free Guidance scale * @default 7.5 */ - cfg_scale?: number | (number)[]; + cfg_scale?: number | number[]; /** - * Scheduler - * @description Scheduler to use during inference - * @default euler + * Scheduler + * @description Scheduler to use during inference + * @default euler * @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"; /** - * Precision - * @description Precision to use - * @default tensor(float16) + * Precision + * @description Precision to use + * @default tensor(float16) * @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 + * Unet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * Control + * Control * @description ControlNet(s) to apply */ - control?: components["schemas"]["ControlField"] | (components["schemas"]["ControlField"])[]; + control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][]; }; /** - * OffsetPaginatedResults[BoardDTO] + * OffsetPaginatedResults[BoardDTO] * @description Offset-paginated results */ OffsetPaginatedResults_BoardDTO_: { /** - * Items + * Items * @description Items */ - items: (components["schemas"]["BoardDTO"])[]; + items: components["schemas"]["BoardDTO"][]; /** - * Offset + * Offset * @description Offset from which to retrieve items */ offset: number; /** - * Limit + * Limit * @description Limit of items to get */ limit: number; /** - * Total + * Total * @description Total number of items in result */ total: number; }; /** - * OffsetPaginatedResults[ImageDTO] + * OffsetPaginatedResults[ImageDTO] * @description Offset-paginated results */ OffsetPaginatedResults_ImageDTO_: { /** - * Items + * Items * @description Items */ - items: (components["schemas"]["ImageDTO"])[]; + items: components["schemas"]["ImageDTO"][]; /** - * Offset + * Offset * @description Offset from which to retrieve items */ offset: number; /** - * Limit + * Limit * @description Limit of items to get */ limit: number; /** - * Total + * Total * @description Total number of items in result */ total: number; }; /** - * OnnxModelField + * OnnxModelField * @description Onnx model field */ OnnxModelField: { /** - * Model Name + * Model Name * @description Name of the model */ model_name: string; @@ -4678,371 +4803,371 @@ export type components = { model_type: components["schemas"]["ModelType"]; }; /** - * ONNX Main Model + * ONNX Main Model * @description Loads a main model, outputting its submodels. */ OnnxModelLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default onnx_model_loader + * Type + * @default onnx_model_loader * @enum {string} */ type: "onnx_model_loader"; /** - * Model + * Model * @description ONNX Main model (UNet, VAE, CLIP) to load */ model: components["schemas"]["OnnxModelField"]; }; /** - * Openpose Processor + * Openpose Processor * @description Applies Openpose processing to image */ OpenposeImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default openpose_image_processor + * Type + * @default openpose_image_processor * @enum {string} */ type: "openpose_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Hand And Face - * @description Whether to use hands and face mode + * Hand And Face + * @description Whether to use hands and face mode * @default false */ hand_and_face?: boolean; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; }; /** - * PaginatedResults[GraphExecutionState] + * PaginatedResults[GraphExecutionState] * @description Paginated results */ PaginatedResults_GraphExecutionState_: { /** - * Items + * Items * @description Items */ - items: (components["schemas"]["GraphExecutionState"])[]; + items: components["schemas"]["GraphExecutionState"][]; /** - * Page + * Page * @description Current Page */ page: number; /** - * Pages + * Pages * @description Total number of pages */ pages: number; /** - * Per Page + * Per Page * @description Number of items per page */ per_page: number; /** - * Total + * Total * @description Total number of items in result */ total: number; }; /** - * PIDI Processor + * PIDI Processor * @description Applies PIDI processing to image */ PidiImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default pidi_image_processor + * Type + * @default pidi_image_processor * @enum {string} */ type: "pidi_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Detect Resolution - * @description Pixel resolution for detection + * Detect Resolution + * @description Pixel resolution for detection * @default 512 */ detect_resolution?: number; /** - * Image Resolution - * @description Pixel resolution for output image + * Image Resolution + * @description Pixel resolution for output image * @default 512 */ image_resolution?: number; /** - * Safe - * @description Whether or not to use safe mode + * Safe + * @description Whether or not to use safe mode * @default false */ safe?: boolean; /** - * Scribble - * @description Whether or not to use scribble mode + * Scribble + * @description Whether or not to use scribble mode * @default false */ scribble?: boolean; }; /** - * Prompts from File + * Prompts from File * @description Loads prompts from a text file */ PromptsFromFileInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default prompt_from_file + * Type + * @default prompt_from_file * @enum {string} */ type: "prompt_from_file"; /** - * File Path + * File Path * @description Path to prompt text file */ file_path?: string; /** - * Pre Prompt + * Pre Prompt * @description String to prepend to each prompt */ pre_prompt?: string; /** - * Post Prompt + * Post Prompt * @description String to append to each prompt */ post_prompt?: string; /** - * Start Line - * @description Line in the file to start start from + * Start Line + * @description Line in the file to start start from * @default 1 */ start_line?: number; /** - * Max Prompts - * @description Max lines to read from file (0=all) + * Max Prompts + * @description Max lines to read from file (0=all) * @default 1 */ max_prompts?: number; }; /** - * Random Integer + * Random Integer * @description Outputs a single random integer. */ RandomIntInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default rand_int + * Type + * @default rand_int * @enum {string} */ type: "rand_int"; /** - * Low - * @description The inclusive low value + * Low + * @description The inclusive low value * @default 0 */ low?: number; /** - * High - * @description The exclusive high value + * High + * @description The exclusive high value * @default 2147483647 */ high?: number; }; /** - * Random Range + * Random Range * @description Creates a collection of random numbers */ RandomRangeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default random_range + * Type + * @default random_range * @enum {string} */ type: "random_range"; /** - * Low - * @description The inclusive low value + * Low + * @description The inclusive low value * @default 0 */ low?: number; /** - * High - * @description The exclusive high value + * High + * @description The exclusive high value * @default 2147483647 */ high?: number; /** - * Size - * @description The number of values to generate + * Size + * @description The number of values to generate * @default 1 */ size?: number; /** - * Seed + * Seed * @description The seed for the RNG (omit for random) */ seed?: number; }; /** - * Integer Range + * Integer Range * @description Creates a range of numbers from start to stop with step */ RangeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default range + * Type + * @default range * @enum {string} */ type: "range"; /** - * Start - * @description The start of the range + * Start + * @description The start of the range * @default 0 */ start?: number; /** - * Stop - * @description The stop of the range + * Stop + * @description The stop of the range * @default 10 */ stop?: number; /** - * Step - * @description The step of the range + * Step + * @description The step of the range * @default 1 */ step?: number; }; /** - * Integer Range of Size + * Integer Range of Size * @description Creates a range from start to start + size with step */ RangeOfSizeInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default range_of_size + * Type + * @default range_of_size * @enum {string} */ type: "range_of_size"; /** - * Start - * @description The start of the range + * Start + * @description The start of the range * @default 0 */ start?: number; /** - * Size - * @description The number of values + * Size + * @description The number of values * @default 1 */ size?: number; /** - * Step - * @description The step of the range + * Step + * @description The step of the range * @default 1 */ step?: number; @@ -5050,502 +5175,502 @@ export type components = { /** RemoveImagesFromBoardResult */ RemoveImagesFromBoardResult: { /** - * Removed Image Names + * Removed Image Names * @description The image names that were removed from their board */ - removed_image_names: (string)[]; + removed_image_names: string[]; }; /** - * Resize Latents + * Resize Latents * @description Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8. */ ResizeLatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default lresize + * Type + * @default lresize * @enum {string} */ type: "lresize"; /** - * Latents + * Latents * @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Width + * Width * @description Width of output (px) */ width?: number; /** - * Height + * Height * @description Width of output (px) */ height?: number; /** - * Mode - * @description Interpolation mode - * @default bilinear + * Mode + * @description Interpolation mode + * @default bilinear * @enum {string} */ mode?: "nearest" | "linear" | "bilinear" | "bicubic" | "trilinear" | "area" | "nearest-exact"; /** - * Antialias - * @description Whether or not to apply antialiasing (bilinear or bicubic only) + * Antialias + * @description Whether or not to apply antialiasing (bilinear or bicubic only) * @default false */ antialias?: boolean; }; /** - * ResourceOrigin + * ResourceOrigin * @description The origin of a resource (eg image). - * + * * - INTERNAL: The resource was created by the application. * - EXTERNAL: The resource was not created by the application. - * This may be a user-initiated upload, or an internal application upload (eg Canvas init image). + * This may be a user-initiated upload, or an internal application upload (eg Canvas init image). * @enum {string} */ ResourceOrigin: "internal" | "external"; /** - * SDXL Compel Prompt + * SDXL Compel Prompt * @description Parse prompt using compel package to conditioning. */ SDXLCompelPromptInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sdxl_compel_prompt + * Type + * @default sdxl_compel_prompt * @enum {string} */ type: "sdxl_compel_prompt"; /** - * Prompt - * @description Prompt to be parsed by Compel to create a conditioning tensor + * Prompt + * @description Prompt to be parsed by Compel to create a conditioning tensor * @default */ prompt?: string; /** - * Style - * @description Prompt to be parsed by Compel to create a conditioning tensor + * Style + * @description Prompt to be parsed by Compel to create a conditioning tensor * @default */ style?: string; /** - * Original Width + * Original Width * @default 1024 */ original_width?: number; /** - * Original Height + * Original Height * @default 1024 */ original_height?: number; /** - * Crop Top + * Crop Top * @default 0 */ crop_top?: number; /** - * Crop Left + * Crop Left * @default 0 */ crop_left?: number; /** - * Target Width + * Target Width * @default 1024 */ target_width?: number; /** - * Target Height + * Target Height * @default 1024 */ target_height?: number; /** - * Clip + * Clip * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; /** - * Clip2 + * Clip2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2?: components["schemas"]["ClipField"]; }; /** - * SDXL LoRA + * SDXL LoRA * @description Apply selected lora to unet and text_encoder. */ SDXLLoraLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sdxl_lora_loader + * Type + * @default sdxl_lora_loader * @enum {string} */ type: "sdxl_lora_loader"; /** - * LoRA + * LoRA * @description LoRA model to load */ lora: components["schemas"]["LoRAModelField"]; /** - * Weight - * @description The weight at which the LoRA is applied to each model + * Weight + * @description The weight at which the LoRA is applied to each model * @default 0.75 */ weight?: number; /** - * UNET + * UNET * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * CLIP 1 + * CLIP 1 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; /** - * CLIP 2 + * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2?: components["schemas"]["ClipField"]; }; /** - * SDXLLoraLoaderOutput + * SDXLLoraLoaderOutput * @description SDXL LoRA Loader Output */ SDXLLoraLoaderOutput: { /** - * Type - * @default sdxl_lora_loader_output + * Type + * @default sdxl_lora_loader_output * @enum {string} */ type: "sdxl_lora_loader_output"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; /** - * CLIP 1 + * CLIP 1 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip?: components["schemas"]["ClipField"]; /** - * CLIP 2 + * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2?: components["schemas"]["ClipField"]; }; /** - * SDXL Main Model + * SDXL Main Model * @description Loads an sdxl base model, outputting its submodels. */ SDXLModelLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sdxl_model_loader + * Type + * @default sdxl_model_loader * @enum {string} */ type: "sdxl_model_loader"; /** - * Model + * Model * @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load */ model: components["schemas"]["MainModelField"]; }; /** - * SDXLModelLoaderOutput + * SDXLModelLoaderOutput * @description SDXL base model loader output */ SDXLModelLoaderOutput: { /** - * Type - * @default sdxl_model_loader_output + * Type + * @default sdxl_model_loader_output * @enum {string} */ type: "sdxl_model_loader_output"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet: components["schemas"]["UNetField"]; /** - * CLIP 1 + * CLIP 1 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip: components["schemas"]["ClipField"]; /** - * CLIP 2 + * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2: components["schemas"]["ClipField"]; /** - * VAE + * VAE * @description VAE */ vae: components["schemas"]["VaeField"]; }; /** - * SDXL Refiner Compel Prompt + * SDXL Refiner Compel Prompt * @description Parse prompt using compel package to conditioning. */ SDXLRefinerCompelPromptInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sdxl_refiner_compel_prompt + * Type + * @default sdxl_refiner_compel_prompt * @enum {string} */ type: "sdxl_refiner_compel_prompt"; /** - * Style - * @description Prompt to be parsed by Compel to create a conditioning tensor + * Style + * @description Prompt to be parsed by Compel to create a conditioning tensor * @default */ style?: string; /** - * Original Width + * Original Width * @default 1024 */ original_width?: number; /** - * Original Height + * Original Height * @default 1024 */ original_height?: number; /** - * Crop Top + * Crop Top * @default 0 */ crop_top?: number; /** - * Crop Left + * Crop Left * @default 0 */ crop_left?: number; /** - * Aesthetic Score - * @description The aesthetic score to apply to the conditioning tensor + * Aesthetic Score + * @description The aesthetic score to apply to the conditioning tensor * @default 6 */ aesthetic_score?: number; /** - * Clip2 + * Clip2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2?: components["schemas"]["ClipField"]; }; /** - * SDXL Refiner Model + * SDXL Refiner Model * @description Loads an sdxl refiner model, outputting its submodels. */ SDXLRefinerModelLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sdxl_refiner_model_loader + * Type + * @default sdxl_refiner_model_loader * @enum {string} */ type: "sdxl_refiner_model_loader"; /** - * Model + * Model * @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load */ model: components["schemas"]["MainModelField"]; }; /** - * SDXLRefinerModelLoaderOutput + * SDXLRefinerModelLoaderOutput * @description SDXL refiner model loader output */ SDXLRefinerModelLoaderOutput: { /** - * Type - * @default sdxl_refiner_model_loader_output + * Type + * @default sdxl_refiner_model_loader_output * @enum {string} */ type: "sdxl_refiner_model_loader_output"; /** - * UNet + * UNet * @description UNet (scheduler, LoRAs) */ unet: components["schemas"]["UNetField"]; /** - * CLIP 2 + * CLIP 2 * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count */ clip2: components["schemas"]["ClipField"]; /** - * VAE + * VAE * @description VAE */ vae: components["schemas"]["VaeField"]; }; /** - * Scale Latents + * Scale Latents * @description Scales latents by a given factor. */ ScaleLatentsInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default lscale + * Type + * @default lscale * @enum {string} */ type: "lscale"; /** - * Latents + * Latents * @description Latents tensor */ latents?: components["schemas"]["LatentsField"]; /** - * Scale Factor + * Scale Factor * @description The factor by which to scale */ scale_factor?: number; /** - * Mode - * @description Interpolation mode - * @default bilinear + * Mode + * @description Interpolation mode + * @default bilinear * @enum {string} */ mode?: "nearest" | "linear" | "bilinear" | "bicubic" | "trilinear" | "area" | "nearest-exact"; /** - * Antialias - * @description Whether or not to apply antialiasing (bilinear or bicubic only) + * Antialias + * @description Whether or not to apply antialiasing (bilinear or bicubic only) * @default false */ antialias?: boolean; }; /** - * SchedulerPredictionType - * @description An enumeration. + * SchedulerPredictionType + * @description An enumeration. * @enum {string} */ SchedulerPredictionType: "epsilon" | "v_prediction" | "sample"; /** - * Segment Anything Processor + * Segment Anything Processor * @description Applies segment anything processing to image */ SegmentAnythingProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default segment_anything_processor + * Type + * @default segment_anything_processor * @enum {string} */ type: "segment_anything_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; }; /** - * Show Image + * Show Image * @description Displays a provided image, and passes it forward in the pipeline. */ ShowImageInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default show_image + * Type + * @default show_image * @enum {string} */ type: "show_image"; /** - * Image + * Image * @description The image to show */ image?: components["schemas"]["ImageField"]; @@ -5556,7 +5681,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5565,7 +5690,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "checkpoint"; @@ -5582,7 +5707,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5591,7 +5716,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "diffusers"; @@ -5606,7 +5731,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5615,7 +5740,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "checkpoint"; @@ -5632,7 +5757,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5641,7 +5766,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "diffusers"; @@ -5656,7 +5781,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5665,7 +5790,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "checkpoint"; @@ -5682,7 +5807,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "main"; @@ -5691,7 +5816,7 @@ export type components = { /** Description */ description?: string; /** - * Model Format + * Model Format * @enum {string} */ model_format: "diffusers"; @@ -5701,215 +5826,215 @@ export type components = { variant: components["schemas"]["ModelVariantType"]; }; /** - * Step Param Easing + * Step Param Easing * @description Experimental per-step parameter easing for denoising steps */ StepParamEasingInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default step_param_easing + * Type + * @default step_param_easing * @enum {string} */ type: "step_param_easing"; /** - * Easing - * @description The easing function to use - * @default Linear + * Easing + * @description The easing function to use + * @default Linear * @enum {string} */ easing?: "Linear" | "QuadIn" | "QuadOut" | "QuadInOut" | "CubicIn" | "CubicOut" | "CubicInOut" | "QuarticIn" | "QuarticOut" | "QuarticInOut" | "QuinticIn" | "QuinticOut" | "QuinticInOut" | "SineIn" | "SineOut" | "SineInOut" | "CircularIn" | "CircularOut" | "CircularInOut" | "ExponentialIn" | "ExponentialOut" | "ExponentialInOut" | "ElasticIn" | "ElasticOut" | "ElasticInOut" | "BackIn" | "BackOut" | "BackInOut" | "BounceIn" | "BounceOut" | "BounceInOut"; /** - * Num Steps - * @description number of denoising steps + * Num Steps + * @description number of denoising steps * @default 20 */ num_steps?: number; /** - * Start Value - * @description easing starting value + * Start Value + * @description easing starting value * @default 0 */ start_value?: number; /** - * End Value - * @description easing ending value + * End Value + * @description easing ending value * @default 1 */ end_value?: number; /** - * Start Step Percent - * @description fraction of steps at which to start easing + * Start Step Percent + * @description fraction of steps at which to start easing * @default 0 */ start_step_percent?: number; /** - * End Step Percent - * @description fraction of steps after which to end easing + * End Step Percent + * @description fraction of steps after which to end easing * @default 1 */ end_step_percent?: number; /** - * Pre Start Value + * Pre Start Value * @description value before easing start */ pre_start_value?: number; /** - * Post End Value + * Post End Value * @description value after easing end */ post_end_value?: number; /** - * Mirror - * @description include mirror of easing function + * Mirror + * @description include mirror of easing function * @default false */ mirror?: boolean; /** - * Show Easing Plot - * @description show easing plot + * Show Easing Plot + * @description show easing plot * @default false */ show_easing_plot?: boolean; }; /** - * String Primitive Collection + * String Primitive Collection * @description A collection of string primitive values */ StringCollectionInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default string_collection + * Type + * @default string_collection * @enum {string} */ type: "string_collection"; /** - * Collection + * Collection * @description The collection of string values */ - collection?: (string)[]; + collection?: string[]; }; /** - * StringCollectionOutput + * StringCollectionOutput * @description Base class for nodes that output a collection of strings */ StringCollectionOutput: { /** - * Type - * @default string_collection_output + * Type + * @default string_collection_output * @enum {string} */ type: "string_collection_output"; /** - * Collection + * Collection * @description The output strings */ - collection: (string)[]; + collection: string[]; }; /** - * String Primitive + * String Primitive * @description A string primitive value */ StringInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default string + * Type + * @default string * @enum {string} */ type: "string"; /** - * Value - * @description The string value + * Value + * @description The string value * @default */ value?: string; }; /** - * StringOutput + * StringOutput * @description Base class for nodes that output a single string */ StringOutput: { /** - * Type - * @default string_output + * Type + * @default string_output * @enum {string} */ type: "string_output"; /** - * Value + * Value * @description The output string */ value: string; }; /** - * SubModelType - * @description An enumeration. + * SubModelType + * @description An enumeration. * @enum {string} */ SubModelType: "unet" | "text_encoder" | "text_encoder_2" | "tokenizer" | "tokenizer_2" | "vae" | "vae_decoder" | "vae_encoder" | "scheduler" | "safety_checker"; /** - * Subtract Integers + * Subtract Integers * @description Subtracts two numbers */ SubtractInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default sub + * Type + * @default sub * @enum {string} */ type: "sub"; /** - * A - * @description The first number + * A + * @description The first number * @default 0 */ a?: number; /** - * B - * @description The second number + * B + * @description The second number * @default 0 */ b?: number; @@ -5920,7 +6045,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "embedding"; @@ -5933,35 +6058,35 @@ export type components = { error?: components["schemas"]["ModelError"]; }; /** - * Tile Resample Processor + * Tile Resample Processor * @description Tile resampler processor */ TileResamplerProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default tile_image_processor + * Type + * @default tile_image_processor * @enum {string} */ type: "tile_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; /** - * Down Sampling Rate - * @description Down sampling rate + * Down Sampling Rate + * @description Down sampling rate * @default 1 */ down_sampling_rate?: number; @@ -5969,41 +6094,41 @@ export type components = { /** UNetField */ UNetField: { /** - * Unet + * Unet * @description Info to load unet submodel */ unet: components["schemas"]["ModelInfo"]; /** - * Scheduler + * Scheduler * @description Info to load scheduler submodel */ scheduler: components["schemas"]["ModelInfo"]; /** - * Loras + * Loras * @description Loras to apply on model loading */ - loras: (components["schemas"]["LoraInfo"])[]; + loras: components["schemas"]["LoraInfo"][]; }; /** Upscaler */ Upscaler: { /** - * Upscaling Method + * Upscaling Method * @description Name of upscaling method */ upscaling_method: string; /** - * Upscaling Models + * Upscaling Models * @description List of upscaling models for this method */ - upscaling_models: (string)[]; + upscaling_models: string[]; }; /** - * VAEModelField + * VAEModelField * @description Vae model field */ VAEModelField: { /** - * Model Name + * Model Name * @description Name of the model */ model_name: string; @@ -6013,52 +6138,52 @@ export type components = { /** VaeField */ VaeField: { /** - * Vae + * Vae * @description Info to load vae submodel */ vae: components["schemas"]["ModelInfo"]; }; /** - * VAE + * VAE * @description Loads a VAE model, outputting a VaeLoaderOutput */ VaeLoaderInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default vae_loader + * Type + * @default vae_loader * @enum {string} */ type: "vae_loader"; /** - * VAE + * VAE * @description VAE model to load */ vae_model: components["schemas"]["VAEModelField"]; }; /** - * VaeLoaderOutput + * VaeLoaderOutput * @description Model loader output */ VaeLoaderOutput: { /** - * Type - * @default vae_loader_output + * Type + * @default vae_loader_output * @enum {string} */ type: "vae_loader_output"; /** - * VAE + * VAE * @description VAE */ vae: components["schemas"]["VaeField"]; @@ -6069,7 +6194,7 @@ export type components = { model_name: string; base_model: components["schemas"]["BaseModelType"]; /** - * Model Type + * Model Type * @enum {string} */ model_type: "vae"; @@ -6081,8 +6206,8 @@ export type components = { error?: components["schemas"]["ModelError"]; }; /** - * VaeModelFormat - * @description An enumeration. + * VaeModelFormat + * @description An enumeration. * @enum {string} */ VaeModelFormat: "checkpoint" | "diffusers"; @@ -6096,75 +6221,75 @@ export type components = { type: string; }; /** - * Zoe (Depth) Processor + * Zoe (Depth) Processor * @description Applies Zoe depth processing to image */ ZoeDepthImageProcessorInvocation: { /** - * Id + * Id * @description The id of this node. Must be unique among all nodes. */ id: string; /** - * Is Intermediate - * @description Whether or not this node is an intermediate node. + * Is Intermediate + * @description Whether or not this node is an intermediate node. * @default false */ is_intermediate?: boolean; /** - * Type - * @default zoe_depth_image_processor + * Type + * @default zoe_depth_image_processor * @enum {string} */ type: "zoe_depth_image_processor"; /** - * Image + * Image * @description The image to process */ image?: components["schemas"]["ImageField"]; }; /** - * UIConfigBase + * UIConfigBase * @description Provides additional node configuration to the UI. * This is used internally by the @tags and @title decorator logic. You probably want to use those * decorators, though you may add this class to a node definition to specify the title and tags. */ UIConfigBase: { /** - * Tags + * Tags * @description The tags to display in the UI */ - tags?: (string)[]; + tags?: string[]; /** - * Title + * Title * @description The display name of the node */ title?: string; }; /** - * Input + * Input * @description The type of input a field accepts. * - `Input.Direct`: The field must have its value provided directly, when the invocation and field are instantiated. * - `Input.Connection`: The field must have its value provided by a connection. - * - `Input.Any`: The field may have its value provided either directly or by a connection. + * - `Input.Any`: The field may have its value provided either directly or by a connection. * @enum {string} */ Input: "connection" | "direct" | "any"; /** - * UIType + * UIType * @description Type hints for the UI. - * If a field should be provided a data type that does not exactly match the python type of the field, use this to provide the type that should be used instead. See the node development docs for detail on adding a new field type, which involves client-side changes. + * If a field should be provided a data type that does not exactly match the python type of the field, use this to provide the type that should be used instead. See the node development docs for detail on adding a new field type, which involves client-side changes. * @enum {string} */ UIType: "integer" | "float" | "boolean" | "string" | "array" | "ImageField" | "LatentsField" | "ConditioningField" | "ControlField" | "ColorField" | "ImageCollection" | "ConditioningCollection" | "ColorCollection" | "LatentsCollection" | "IntegerCollection" | "FloatCollection" | "StringCollection" | "BooleanCollection" | "MainModelField" | "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VaeModelField" | "LoRAModelField" | "ControlNetModelField" | "UNetField" | "VaeField" | "ClipField" | "Collection" | "CollectionItem" | "FilePath" | "enum" | "Scheduler"; /** - * 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. + * 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 + * _InputField * @description *DO NOT USE* * This helper class is used to tell the client about our custom field attributes via OpenAPI * schema generation, and Typescript type generation from that schema. It serves no functional @@ -6176,9 +6301,11 @@ export type components = { ui_hidden: boolean; ui_type?: components["schemas"]["UIType"]; ui_component?: components["schemas"]["UIComponent"]; + /** Ui Order */ + ui_order?: number; }; /** - * _OutputField + * _OutputField * @description *DO NOT USE* * This helper class is used to tell the client about our custom field attributes via OpenAPI * schema generation, and Typescript type generation from that schema. It serves no functional @@ -6188,37 +6315,39 @@ export type components = { /** Ui Hidden */ ui_hidden: boolean; ui_type?: components["schemas"]["UIType"]; + /** Ui Order */ + ui_order?: number; }; /** - * ControlNetModelFormat - * @description An enumeration. + * ControlNetModelFormat + * @description An enumeration. * @enum {string} */ ControlNetModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusionOnnxModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. + * StableDiffusion1ModelFormat + * @description An enumeration. * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusionXLModelFormat - * @description An enumeration. + * StableDiffusionOnnxModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionOnnxModelFormat: "olive" | "onnx"; + /** + * StableDiffusionXLModelFormat + * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -6227,12 +6356,14 @@ export type components = { pathItems: never; }; +export type $defs = Record; + export type external = Record; export type operations = { /** - * List Sessions + * List Sessions * @description Gets a list of sessions, optionally searching */ list_sessions: { @@ -6262,7 +6393,7 @@ export type operations = { }; }; /** - * Create Session + * Create Session * @description Creates a new session, optionally initializing it with an invocation graph */ create_session: { @@ -6279,7 +6410,9 @@ export type operations = { }; }; /** @description Invalid json */ - 400: never; + 400: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6289,7 +6422,7 @@ export type operations = { }; }; /** - * Get Session + * Get Session * @description Gets a session */ get_session: { @@ -6307,7 +6440,9 @@ export type operations = { }; }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6317,7 +6452,7 @@ export type operations = { }; }; /** - * Add Node + * Add Node * @description Adds a node to the graph */ add_node: { @@ -6329,7 +6464,7 @@ export type operations = { }; 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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | 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"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | 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"]; + "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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | 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"]; }; }; responses: { @@ -6340,9 +6475,13 @@ export type operations = { }; }; /** @description Invalid node or link */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6352,7 +6491,7 @@ export type operations = { }; }; /** - * Update Node + * Update Node * @description Updates a node in the graph and removes all linked edges */ update_node: { @@ -6366,7 +6505,7 @@ export type operations = { }; 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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | 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"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | 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"]; + "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"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | 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"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | 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"]; }; }; responses: { @@ -6377,9 +6516,13 @@ export type operations = { }; }; /** @description Invalid node or link */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6389,7 +6532,7 @@ export type operations = { }; }; /** - * Delete Node + * Delete Node * @description Deletes a node in the graph and removes all linked edges */ delete_node: { @@ -6409,9 +6552,13 @@ export type operations = { }; }; /** @description Invalid node or link */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6421,7 +6568,7 @@ export type operations = { }; }; /** - * Add Edge + * Add Edge * @description Adds an edge to the graph */ add_edge: { @@ -6444,9 +6591,13 @@ export type operations = { }; }; /** @description Invalid node or link */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6456,7 +6607,7 @@ export type operations = { }; }; /** - * Delete Edge + * Delete Edge * @description Deletes an edge from the graph */ delete_edge: { @@ -6482,9 +6633,13 @@ export type operations = { }; }; /** @description Invalid node or link */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6494,7 +6649,7 @@ export type operations = { }; }; /** - * Invoke Session + * Invoke Session * @description Invokes a session */ invoke_session: { @@ -6516,11 +6671,17 @@ export type operations = { }; }; /** @description The invocation is queued */ - 202: never; + 202: { + content: never; + }; /** @description The session has no invocations ready to invoke */ - 400: never; + 400: { + content: never; + }; /** @description Session not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6530,7 +6691,7 @@ export type operations = { }; }; /** - * Cancel Session Invoke + * Cancel Session Invoke * @description Invokes a session */ cancel_session_invoke: { @@ -6548,7 +6709,9 @@ export type operations = { }; }; /** @description The invocation is canceled */ - 202: never; + 202: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6558,14 +6721,14 @@ export type operations = { }; }; /** - * List Models + * List Models * @description Gets a list of models */ list_models: { parameters: { query?: { /** @description Base models to include */ - base_models?: (components["schemas"]["BaseModelType"])[]; + base_models?: components["schemas"]["BaseModelType"][]; /** @description The type of model to get */ model_type?: components["schemas"]["ModelType"]; }; @@ -6586,7 +6749,7 @@ export type operations = { }; }; /** - * Delete Model + * Delete Model * @description Delete Model */ del_model: { @@ -6602,9 +6765,13 @@ export type operations = { }; responses: { /** @description Model deleted successfully */ - 204: never; + 204: { + content: never; + }; /** @description Model not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6614,7 +6781,7 @@ export type operations = { }; }; /** - * Update Model + * Update Model * @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed. */ update_model: { @@ -6641,11 +6808,17 @@ export type operations = { }; }; /** @description Bad request */ - 400: never; + 400: { + content: never; + }; /** @description The model could not be found */ - 404: never; + 404: { + content: never; + }; /** @description There is already a model corresponding to the new name */ - 409: never; + 409: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6655,7 +6828,7 @@ export type operations = { }; }; /** - * Import Model + * Import Model * @description Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically */ import_model: { @@ -6672,11 +6845,17 @@ export type operations = { }; }; /** @description The model could not be found */ - 404: never; + 404: { + content: never; + }; /** @description There is already a model corresponding to this path or repo_id */ - 409: never; + 409: { + content: never; + }; /** @description Unrecognized file/folder format */ - 415: never; + 415: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6684,11 +6863,13 @@ export type operations = { }; }; /** @description The model appeared to import successfully, but could not be found in the model manager */ - 424: never; + 424: { + content: never; + }; }; }; /** - * Add Model + * Add Model * @description Add a model using the configuration information appropriate for its type. Only local models can be added by path */ add_model: { @@ -6705,9 +6886,13 @@ export type operations = { }; }; /** @description The model could not be found */ - 404: never; + 404: { + content: never; + }; /** @description There is already a model corresponding to this path or repo_id */ - 409: never; + 409: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6715,11 +6900,13 @@ export type operations = { }; }; /** @description The model appeared to add successfully, but could not be found in the model manager */ - 424: never; + 424: { + content: never; + }; }; }; /** - * Convert Model + * Convert Model * @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none. */ convert_model: { @@ -6745,9 +6932,13 @@ export type operations = { }; }; /** @description Bad request */ - 400: never; + 400: { + content: never; + }; /** @description Model not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6768,11 +6959,13 @@ export type operations = { /** @description Directory searched successfully */ 200: { content: { - "application/json": (string)[]; + "application/json": string[]; }; }; /** @description Invalid directory path */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6782,7 +6975,7 @@ export type operations = { }; }; /** - * List Ckpt Configs + * List Ckpt Configs * @description Return a list of the legacy checkpoint configuration files stored in `ROOT/configs/stable-diffusion`, relative to ROOT. */ list_ckpt_configs: { @@ -6790,13 +6983,13 @@ export type operations = { /** @description paths retrieved successfully */ 200: { content: { - "application/json": (string)[]; + "application/json": string[]; }; }; }; }; /** - * Sync To Config + * Sync To Config * @description Call after making changes to models.yaml, autoimport directories or models directory to synchronize * in-memory data structures with disk data structures. */ @@ -6811,7 +7004,7 @@ export type operations = { }; }; /** - * Merge Models + * Merge Models * @description Convert a checkpoint model into a diffusers model */ merge_models: { @@ -6834,9 +7027,13 @@ export type operations = { }; }; /** @description Incompatible models */ - 400: never; + 400: { + content: never; + }; /** @description One or more models not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6846,7 +7043,7 @@ export type operations = { }; }; /** - * Upload Image + * Upload Image * @description Uploads an image */ upload_image: { @@ -6877,7 +7074,9 @@ export type operations = { }; }; /** @description Image upload failed */ - 415: never; + 415: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -6887,7 +7086,7 @@ export type operations = { }; }; /** - * Get Image Dto + * Get Image Dto * @description Gets an image's DTO */ get_image_dto: { @@ -6913,7 +7112,7 @@ export type operations = { }; }; /** - * Delete Image + * Delete Image * @description Deletes an image */ delete_image: { @@ -6939,7 +7138,7 @@ export type operations = { }; }; /** - * Update Image + * Update Image * @description Updates an image */ update_image: { @@ -6970,7 +7169,7 @@ export type operations = { }; }; /** - * Clear Intermediates + * Clear Intermediates * @description Clears all intermediates */ clear_intermediates: { @@ -6984,7 +7183,7 @@ export type operations = { }; }; /** - * Get Image Metadata + * Get Image Metadata * @description Gets an image's metadata */ get_image_metadata: { @@ -7010,7 +7209,7 @@ export type operations = { }; }; /** - * Get Image Full + * Get Image Full * @description Gets a full-resolution image file */ get_image_full: { @@ -7028,7 +7227,9 @@ export type operations = { }; }; /** @description Image not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -7038,7 +7239,7 @@ export type operations = { }; }; /** - * Get Image Thumbnail + * Get Image Thumbnail * @description Gets a thumbnail image file */ get_image_thumbnail: { @@ -7056,7 +7257,9 @@ export type operations = { }; }; /** @description Image not found */ - 404: never; + 404: { + content: never; + }; /** @description Validation Error */ 422: { content: { @@ -7066,7 +7269,7 @@ export type operations = { }; }; /** - * Get Image Urls + * Get Image Urls * @description Gets an image and thumbnail URL */ get_image_urls: { @@ -7092,7 +7295,7 @@ export type operations = { }; }; /** - * List Image Dtos + * List Image Dtos * @description Gets a list of image DTOs */ list_image_dtos: { @@ -7101,7 +7304,7 @@ export type operations = { /** @description The origin of images to list. */ image_origin?: components["schemas"]["ResourceOrigin"]; /** @description The categories of image to include. */ - categories?: (components["schemas"]["ImageCategory"])[]; + categories?: components["schemas"]["ImageCategory"][]; /** @description Whether to list intermediate images. */ is_intermediate?: boolean; /** @description The board id to filter by. Use 'none' to find images without a board. */ @@ -7194,7 +7397,7 @@ export type operations = { }; }; /** - * List Boards + * List Boards * @description Gets a list of boards */ list_boards: { @@ -7212,7 +7415,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["OffsetPaginatedResults_BoardDTO_"] | (components["schemas"]["BoardDTO"])[]; + "application/json": components["schemas"]["OffsetPaginatedResults_BoardDTO_"] | components["schemas"]["BoardDTO"][]; }; }; /** @description Validation Error */ @@ -7224,7 +7427,7 @@ export type operations = { }; }; /** - * Create Board + * Create Board * @description Creates a board */ create_board: { @@ -7250,7 +7453,7 @@ export type operations = { }; }; /** - * Get Board + * Get Board * @description Gets a board */ get_board: { @@ -7276,7 +7479,7 @@ export type operations = { }; }; /** - * Delete Board + * Delete Board * @description Deletes a board */ delete_board: { @@ -7306,7 +7509,7 @@ export type operations = { }; }; /** - * Update Board + * Update Board * @description Updates a board */ update_board: { @@ -7337,7 +7540,7 @@ export type operations = { }; }; /** - * List All Board Image Names + * List All Board Image Names * @description Gets a list of images for a board */ list_all_board_image_names: { @@ -7351,7 +7554,7 @@ export type operations = { /** @description Successful Response */ 200: { content: { - "application/json": (string)[]; + "application/json": string[]; }; }; /** @description Validation Error */ @@ -7363,7 +7566,7 @@ export type operations = { }; }; /** - * Add Image To Board + * Add Image To Board * @description Creates a board_image */ add_image_to_board: { @@ -7388,7 +7591,7 @@ export type operations = { }; }; /** - * Remove Image From Board + * Remove Image From Board * @description Removes an image from its board, if it had one */ remove_image_from_board: { @@ -7413,7 +7616,7 @@ export type operations = { }; }; /** - * Add Images To Board + * Add Images To Board * @description Adds a list of images to a board */ add_images_to_board: { @@ -7438,7 +7641,7 @@ export type operations = { }; }; /** - * Remove Images From Board + * Remove Images From Board * @description Removes a list of images from their board, if they had one */ remove_images_from_board: { @@ -7485,7 +7688,7 @@ export type operations = { }; }; /** - * Get Log Level + * Get Log Level * @description Returns the log level */ get_log_level: { @@ -7499,7 +7702,7 @@ export type operations = { }; }; /** - * Set Log Level + * Set Log Level * @description Sets the log verbosity level */ set_log_level: { diff --git a/invokeai/frontend/web/src/services/api/thunks/session.ts b/invokeai/frontend/web/src/services/api/thunks/session.ts index 29b032d1c3..32c612bbc2 100644 --- a/invokeai/frontend/web/src/services/api/thunks/session.ts +++ b/invokeai/frontend/web/src/services/api/thunks/session.ts @@ -30,8 +30,8 @@ export const sessionCreated = createAsyncThunk< CreateSessionThunkConfig >('api/sessionCreated', async (arg, { rejectWithValue }) => { const { graph } = arg; - const { post } = $client.get(); - const { data, error, response } = await post('/api/v1/sessions/', { + const { POST } = $client.get(); + const { data, error, response } = await POST('/api/v1/sessions/', { body: graph, }); @@ -72,8 +72,8 @@ export const sessionInvoked = createAsyncThunk< InvokedSessionThunkConfig >('api/sessionInvoked', async (arg, { rejectWithValue }) => { const { session_id } = arg; - const { put } = $client.get(); - const { data, error, response } = await put( + const { PUT } = $client.get(); + const { data, error, response } = await PUT( '/api/v1/sessions/{session_id}/invoke', { params: { query: { all: true }, path: { session_id } }, @@ -92,11 +92,12 @@ export const sessionInvoked = createAsyncThunk< return rejectWithValue({ arg, status: response.status, - error: error.detail + error: error.detail, }); } - if (error) + if (error) { return rejectWithValue({ arg, status: response.status, error }); + } } }); @@ -122,8 +123,8 @@ export const sessionCanceled = createAsyncThunk< CancelSessionThunkConfig >('api/sessionCanceled', async (arg, { rejectWithValue }) => { const { session_id } = arg; - const { del } = $client.get(); - const { data, error, response } = await del( + const { DELETE } = $client.get(); + const { data, error, response } = await DELETE( '/api/v1/sessions/{session_id}/invoke', { params: { @@ -162,8 +163,8 @@ export const listedSessions = createAsyncThunk< ListSessionsThunkConfig >('api/listSessions', async (arg, { rejectWithValue }) => { const { params } = arg; - const { get } = $client.get(); - const { data, error, response } = await get('/api/v1/sessions/', { + const { GET } = $client.get(); + const { data, error, response } = await GET('/api/v1/sessions/', { params, }); diff --git a/invokeai/frontend/web/src/theme/components/button.ts b/invokeai/frontend/web/src/theme/components/button.ts index c01d564494..056f3c145d 100644 --- a/invokeai/frontend/web/src/theme/components/button.ts +++ b/invokeai/frontend/web/src/theme/components/button.ts @@ -8,7 +8,16 @@ const invokeAI = defineStyle((props) => { if (c === 'base') { const _disabled = { bg: mode('base.150', 'base.700')(props), - color: mode('base.500', 'base.500')(props), + color: mode('base.300', 'base.500')(props), + svg: { + fill: mode('base.500', 'base.500')(props), + }, + opacity: 1, + }; + + const data_progress = { + bg: 'none', + color: mode('base.300', 'base.500')(props), svg: { fill: mode('base.500', 'base.500')(props), }, @@ -31,6 +40,7 @@ const invokeAI = defineStyle((props) => { _disabled, }, _disabled, + '&[data-progress="true"]': { ...data_progress, _hover: data_progress }, }; } @@ -45,6 +55,17 @@ const invokeAI = defineStyle((props) => { filter: mode(undefined, 'saturate(65%)')(props), }; + const data_progress = { + // bg: 'none', + color: mode(`${c}.50`, `${c}.500`)(props), + svg: { + fill: mode(`${c}.50`, `${c}.500`)(props), + filter: 'unset', + }, + opacity: 0.7, + filter: mode(undefined, 'saturate(65%)')(props), + }; + return { bg: mode(`${c}.400`, `${c}.600`)(props), color: mode(`base.50`, `base.100`)(props), @@ -61,6 +82,7 @@ const invokeAI = defineStyle((props) => { }, _disabled, }, + '&[data-progress="true"]': { ...data_progress, _hover: data_progress }, }; }); diff --git a/invokeai/frontend/web/src/theme/components/progress.ts b/invokeai/frontend/web/src/theme/components/progress.ts index 71231869ce..a2aebc8fb1 100644 --- a/invokeai/frontend/web/src/theme/components/progress.ts +++ b/invokeai/frontend/web/src/theme/components/progress.ts @@ -9,7 +9,7 @@ const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(parts.keys); const invokeAIFilledTrack = defineStyle((_props) => ({ - bg: 'accentAlpha.500', + bg: 'accentAlpha.700', })); const invokeAITrack = defineStyle((_props) => { diff --git a/invokeai/frontend/web/src/theme/theme.ts b/invokeai/frontend/web/src/theme/theme.ts index f602fcef1c..039f4c928c 100644 --- a/invokeai/frontend/web/src/theme/theme.ts +++ b/invokeai/frontend/web/src/theme/theme.ts @@ -45,6 +45,11 @@ export const theme: ThemeOverride = { color: 'base.900', '.chakra-ui-dark &': { bg: 'base.800', color: 'base.100' }, }, + third: { + bg: 'base.300', + color: 'base.900', + '.chakra-ui-dark &': { bg: 'base.750', color: 'base.100' }, + }, nodeBody: { bg: 'base.100', color: 'base.900', @@ -53,12 +58,12 @@ export const theme: ThemeOverride = { nodeHeader: { bg: 'base.200', color: 'base.900', - '.chakra-ui-dark &': { bg: 'base.700', color: 'base.100' }, + '.chakra-ui-dark &': { bg: 'base.900', color: 'base.100' }, }, nodeFooter: { bg: 'base.200', color: 'base.900', - '.chakra-ui-dark &': { bg: 'base.700', color: 'base.100' }, + '.chakra-ui-dark &': { bg: 'base.900', color: 'base.100' }, }, }, styles: { @@ -102,10 +107,15 @@ export const theme: ThemeOverride = { '0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 3px var(--invokeai-colors-accent-500)', dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 3px var(--invokeai-colors-accent-400)', }, - nodeSelectedOutline: { + nodeSelected: { light: `0 0 0 2px var(--invokeai-colors-accent-400)`, dark: `0 0 0 2px var(--invokeai-colors-accent-500)`, }, + nodeInProgress: { + light: + '0 0 0 2px var(--invokeai-colors-accent-500), 0 0 10px 2px var(--invokeai-colors-accent-600)', + dark: '0 0 0 2px var(--invokeai-colors-yellow-400), 0 0 20px 2px var(--invokeai-colors-orange-700)', + }, }, colors: InvokeAIColors, components: { diff --git a/invokeai/frontend/web/yarn.lock b/invokeai/frontend/web/yarn.lock index ad55022425..6d0e19fffc 100644 --- a/invokeai/frontend/web/yarn.lock +++ b/invokeai/frontend/web/yarn.lock @@ -7,16 +7,6 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@apidevtools/json-schema-ref-parser@9.0.9": - version "9.0.9" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b" - integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w== - dependencies: - "@jsdevtools/ono" "^7.1.3" - "@types/json-schema" "^7.0.6" - call-me-maybe "^1.0.1" - js-yaml "^4.1.0" - "@babel/code-frame@^7.0.0": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" @@ -55,7 +45,12 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== -"@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.14.8", "@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/parser@^7.21.3": + version "7.22.10" + 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": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== @@ -275,13 +270,6 @@ compute-scroll-into-view "1.0.20" copy-to-clipboard "3.3.3" -"@chakra-ui/icon@3.0.16": - version "3.0.16" - resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.0.16.tgz#6413ec637c0c3acc204301485f05451b5bcd6ba4" - integrity sha512-RpA1X5Ptz8Mt39HSyEIW1wxAz2AXyf9H0JJ5HVx/dBdMZaGMDJ0HyyPBVci0m4RCoJuyG1HHG/DXJaVfUTVAeg== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/icon@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.1.0.tgz#48312c071b3a0ed20ce807c8bd24d5f3e9cfdb7f" @@ -289,12 +277,12 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/icons@^2.0.19": - version "2.0.19" - resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.0.19.tgz#b4581a59c2e2a2b95b01ab251eabb8cf984bb00f" - integrity sha512-0A6U1ZBZhLIxh3QgdjuvIEhAZi3B9v8g6Qvlfa3mu6vSnXQn2CHBZXmJwxpXxO40NK/2gj/gKXrLeUaFR6H/Qw== +"@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== dependencies: - "@chakra-ui/icon" "3.0.16" + "@chakra-ui/icon" "3.1.0" "@chakra-ui/image@2.1.0": version "2.1.0" @@ -1287,22 +1275,22 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.14.tgz#43f66032e0f189b6f394d4dbc903a188bb0c969f" integrity sha512-K0QjGbcskx+gY+qp3v4/940qg8JitpXbdxFhRDA1aYoNaPff88+aEwoq45aqJ+ogpxQxmU0ZTjgnrQD/w8iiUg== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" - integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.7.0.tgz#96e7c05e738327602ae5942437f9c6b177ec279a" + integrity sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA== -"@eslint/eslintrc@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d" - integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A== +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1314,10 +1302,15 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.44.0": - version "8.44.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af" - integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw== +"@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== + +"@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" @@ -1354,15 +1347,15 @@ aria-hidden "^1.1.3" tabbable "^6.0.1" -"@fontsource-variable/inter@^5.0.3": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@fontsource-variable/inter/-/inter-5.0.5.tgz#a03cf816dc1f0df24f61b30f5936bcc99e0aad03" - integrity sha512-hmj/jffr+1tabEPmvm+/b89MtbO6hd5PVbQ6HoMGTO7RMF5eD2C9UcprCgZTOF3OWh5uC21C9HZGN0O9wxe+UQ== +"@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== -"@fontsource/inter@^5.0.3": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.5.tgz#bd3e923660cc4632d09b1882d104b0cb9430dec6" - integrity sha512-RE1JmWRB6Kxo+1nXUnORSSH5uKgUZ2QEQE+h/nsNt758C+17G9y26E9QiAsIqsG13NpKhwn22EeECfyC+da5ew== +"@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== "@humanwhocodes/config-array@^0.11.10": version "0.11.10" @@ -1383,118 +1376,68 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/sourcemap-codec@1.4.14": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jsdevtools/ono@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" - integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== - -"@mantine/core@^6.0.14": - version "6.0.17" - resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.17.tgz#734b31c79199a9cf2bfb0bbd7482f5c2c411ff9a" - integrity sha512-g3EDxcTJKisvEGTsGJPCGXiDumwr4O0nGNXwoGLnrg19nh3FAMfEIq18sJJLtRrBuarSbrvgMVYvKx1R6rTOWg== +"@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== dependencies: "@floating-ui/react" "^0.19.1" - "@mantine/styles" "6.0.17" - "@mantine/utils" "6.0.17" + "@mantine/styles" "6.0.19" + "@mantine/utils" "6.0.19" "@radix-ui/react-scroll-area" "1.0.2" react-remove-scroll "^2.5.5" react-textarea-autosize "8.3.4" -"@mantine/form@^6.0.15": - version "6.0.17" - resolved "https://registry.yarnpkg.com/@mantine/form/-/form-6.0.17.tgz#ab4fe22ea83976a3e621f0fcc2d36eae19f37141" - integrity sha512-hrWlBukErklaFSvKfz4PCl3Cd7UgHf5Q/FyZPD+WvBDT0zZ5uMjatQpVs/HAfhFOA5O2DFKAcs654mLzmJJ6Wg== +"@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== dependencies: fast-deep-equal "^3.1.3" klona "^2.0.5" -"@mantine/hooks@^6.0.14": - version "6.0.17" - resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.17.tgz#dc942c87e6dcfa14a70e4e4a162c22eeb4ff3724" - integrity sha512-7vf2w1NlzKlUynSuyI2DAIKoEOYKYC8k+tlSsk3BRdbzhbJAiWxcYzJy5seg5dFW1WIpKAZ0wiVdHXf/WRlRgg== +"@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== -"@mantine/styles@6.0.17": - version "6.0.17" - resolved "https://registry.yarnpkg.com/@mantine/styles/-/styles-6.0.17.tgz#fef8a64f0e32b970c397e1c22dceb6ab09fb090f" - integrity sha512-utNwQJgKHguNS0iPyyeFRJy4nbt280XMbmfUf4GCxXlyl/mQxq+JoaKP/OmU7+8kfbtLS9kHeuBSghrC65Nt1g== +"@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== dependencies: clsx "1.1.1" csstype "3.0.9" -"@mantine/utils@6.0.17": - version "6.0.17" - resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.17.tgz#7d4a6c7686a3ee19a0ac248ef14780f00730837b" - integrity sha512-U6SWV/asYE6NhiHx4ltmVZdQR3HwGVqJxVulhOylMcV1tX/P1LMQUCbGV2Oe4O9jbX4/YW5B/CBb4BbEhENQFQ== +"@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== -"@microsoft/api-extractor-model@7.27.4": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.27.4.tgz#ddc566ead99737c1032d692829edd954870f7d35" - integrity sha512-HjqQFmuGPOS20rtnu+9Jj0QrqZyR59E+piUWXPMZTTn4jaZI+4UmsHSf3Id8vyueAhOBH2cgwBuRTE5R+MfSMw== +"@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== dependencies: "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.59.5" + "@rushstack/node-core-library" "3.59.7" -"@microsoft/api-extractor@^7.34.4": - version "7.36.2" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.36.2.tgz#8f7696fcc3c9c0c43469e6f59c56349bc1631193" - integrity sha512-ONe/jOmTZtR3OjTkWKHmeSV1P5ozbHDxHr6FV3KoWyIl1AcPk2B3dmvVBM5eOlZB5bgM66nxcWQTZ6msQo2hHg== +"@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== dependencies: - "@microsoft/api-extractor-model" "7.27.4" + "@microsoft/api-extractor-model" "7.27.6" "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.59.5" - "@rushstack/rig-package" "0.4.0" - "@rushstack/ts-command-line" "4.15.1" + "@rushstack/node-core-library" "3.59.7" + "@rushstack/rig-package" "0.4.1" + "@rushstack/ts-command-line" "4.15.2" colors "~1.2.1" lodash "~4.17.15" resolve "~1.22.1" - semver "~7.3.0" + semver "~7.5.4" source-map "~0.6.1" typescript "~5.0.4" @@ -1539,6 +1482,18 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@pkgr/utils@^2.3.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + "@popperjs/core@^2.9.3": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" @@ -1634,28 +1589,28 @@ dependencies: "@babel/runtime" "^7.13.10" -"@reactflow/background@11.2.4": - version "11.2.4" - resolved "https://registry.yarnpkg.com/@reactflow/background/-/background-11.2.4.tgz#06cd4c9f222dbeb2d3ffb2a530b6d88bf130dd9c" - integrity sha512-SYQbCRCU0GuxT/40Tm7ZK+l5wByGnNJSLtZhbL9C/Hl7JhsJXV3UGXr0vrlhVZUBEtkWA7XhZM/5S9XEA5XSFA== +"@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== dependencies: - "@reactflow/core" "11.7.4" + "@reactflow/core" "11.8.3" classcat "^5.0.3" - zustand "^4.3.1" + zustand "^4.4.1" -"@reactflow/controls@11.1.15": - version "11.1.15" - resolved "https://registry.yarnpkg.com/@reactflow/controls/-/controls-11.1.15.tgz#6dc823eb67f38a50907fffcc21b6a20e4fc00e7c" - integrity sha512-//33XfBYu8vQ6brfmlZwKrDoh+8hh93xO2d88XiqfIbrPEEb32SYjsb9mS9VuHKNlSIW+eB27fBA1Gt00mEj5w== +"@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== dependencies: - "@reactflow/core" "11.7.4" + "@reactflow/core" "11.8.3" classcat "^5.0.3" - zustand "^4.3.1" + zustand "^4.4.1" -"@reactflow/core@11.7.4", "@reactflow/core@^11.6.0": - version "11.7.4" - resolved "https://registry.yarnpkg.com/@reactflow/core/-/core-11.7.4.tgz#1a7e4d6cabbd2ea888547133d507f1ab24896520" - integrity sha512-nt0T8ERp8TE7YCDQViaoEY9lb0StDPrWHVx3zBjhStFYET3wc88t8QRasZdf99xRTmyNtI3U3M40M5EBLNUpMw== +"@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== dependencies: "@types/d3" "^7.4.0" "@types/d3-drag" "^3.0.1" @@ -1665,40 +1620,40 @@ d3-drag "^3.0.0" d3-selection "^3.0.0" d3-zoom "^3.0.0" - zustand "^4.3.1" + zustand "^4.4.1" -"@reactflow/minimap@11.5.4": - version "11.5.4" - resolved "https://registry.yarnpkg.com/@reactflow/minimap/-/minimap-11.5.4.tgz#b072094f7d827660f0205796d5f22fbbf6e31cc3" - integrity sha512-1tDBj2zX2gxu2oHU6qvH5RGNrOWRfRxu8369KhDotuuBN5yJrGXJzWIKikwhzjsNsQJYOB+B0cS44yWAfwSwzw== +"@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== dependencies: - "@reactflow/core" "11.7.4" + "@reactflow/core" "11.8.3" "@types/d3-selection" "^3.0.3" "@types/d3-zoom" "^3.0.1" classcat "^5.0.3" d3-selection "^3.0.0" d3-zoom "^3.0.0" - zustand "^4.3.1" + zustand "^4.4.1" -"@reactflow/node-resizer@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@reactflow/node-resizer/-/node-resizer-2.1.1.tgz#8f9b4e362e572dcddb54d43a67b5c5919b25937f" - integrity sha512-5Q+IBmZfpp/bYsw3+KRVJB1nUbj6W3XAp5ycx4uNWH+K98vbssymyQsW0vvKkIhxEPg6tkiMzO4UWRWvwBwt1g== +"@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== dependencies: - "@reactflow/core" "^11.6.0" + "@reactflow/core" "11.8.3" classcat "^5.0.4" d3-drag "^3.0.0" d3-selection "^3.0.0" - zustand "^4.3.1" + zustand "^4.4.1" -"@reactflow/node-toolbar@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@reactflow/node-toolbar/-/node-toolbar-1.2.3.tgz#8ff8408dffee7920752479cd19e7ab7c9c47b4d2" - integrity sha512-uFQy9xpog92s0G1wsPLniwV9nyH4i/MmL7QoMsWdnKaOi7XMhd8SJcCzUdHC3imR21HltsuQITff/XQ51ApMbg== +"@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== dependencies: - "@reactflow/core" "11.7.4" + "@reactflow/core" "11.8.3" classcat "^5.0.3" - zustand "^4.3.1" + zustand "^4.4.1" "@reduxjs/toolkit@^1.9.5": version "1.9.5" @@ -1736,31 +1691,31 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rushstack/node-core-library@3.59.5", "@rushstack/node-core-library@^3.55.2": - version "3.59.5" - resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.5.tgz#38034d4c38b5ddd7d1c7f04233ce1b2209b7ae1f" - integrity sha512-1IpV7LufrI1EoVO8hYsb3t6L8L+yp40Sa0OaOV2CIu1zx4e6ZeVNaVIEXFgMXBKdGXkAh21MnCaIzlDNpG6ZQw== +"@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== dependencies: colors "~1.2.1" fs-extra "~7.0.1" import-lazy "~4.0.0" jju "~1.4.0" resolve "~1.22.1" - semver "~7.3.0" + semver "~7.5.4" z-schema "~5.0.2" -"@rushstack/rig-package@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.4.0.tgz#1dade94da5cd81321ca9ec630b6ceed2d57cc826" - integrity sha512-FnM1TQLJYwSiurP6aYSnansprK5l8WUK8VG38CmAaZs29ZeL1msjK0AP1VS4ejD33G0kE/2cpsPsS9jDenBMxw== +"@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== dependencies: resolve "~1.22.1" strip-json-comments "~3.1.1" -"@rushstack/ts-command-line@4.15.1": - version "4.15.1" - resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.15.1.tgz#8f2ebde6bb19deb2c5b65363854b84aea1bf59f0" - integrity sha512-EL4jxZe5fhb1uVL/P/wQO+Z8Rc8FMiWJ1G7VgnPDvdIt5GVjRfK7vwzder1CZQiX3x0PY6uxENYLNGTFd1InRQ== +"@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== dependencies: "@types/argparse" "1.0.38" argparse "~1.0.9" @@ -1838,16 +1793,6 @@ "@swc/core-win32-ia32-msvc" "1.3.70" "@swc/core-win32-x64-msvc" "1.3.70" -"@ts-morph/common@~0.19.0": - version "0.19.0" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.19.0.tgz#927fcd81d1bbc09c89c4a310a84577fb55f3694e" - integrity sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ== - dependencies: - fast-glob "^3.2.12" - minimatch "^7.4.3" - mkdirp "^2.1.6" - path-browserify "^1.0.1" - "@types/argparse@1.0.38": version "1.0.38" resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" @@ -2099,7 +2044,7 @@ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== -"@types/json-schema@*", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.12": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== @@ -2128,10 +2073,10 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== -"@types/node@^20.3.1": - version "20.4.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9" - integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw== +"@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/parse-json@^4.0.0": version "4.0.0" @@ -2174,7 +2119,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.2.14": +"@types/react@*": version "18.2.15" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.15.tgz#14792b35df676c20ec3cf595b262f8c615a73066" integrity sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA== @@ -2183,12 +2128,21 @@ "@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== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/scheduler@*": version "0.16.3" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== -"@types/semver@^7.3.12": +"@types/semver@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== @@ -2203,49 +2157,51 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b" integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ== -"@typescript-eslint/eslint-plugin@^5.60.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" - integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== +"@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== dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/type-utils" "5.62.0" - "@typescript-eslint/utils" "5.62.0" + "@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" debug "^4.3.4" graphemer "^1.4.0" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^5.60.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" - integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== +"@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== dependencies: - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" + "@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" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== +"@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== dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" -"@typescript-eslint/type-utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" - integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== +"@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== dependencies: - "@typescript-eslint/typescript-estree" "5.62.0" - "@typescript-eslint/utils" "5.62.0" + "@typescript-eslint/typescript-estree" "6.4.1" + "@typescript-eslint/utils" "6.4.1" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.0.1" "@typescript-eslint/types@4.33.0": version "4.33.0" @@ -2257,18 +2213,23 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/typescript-estree@5.62.0", "@typescript-eslint/typescript-estree@^5.55.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== +"@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/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== dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" "@typescript-eslint/typescript-estree@^4.33.0": version "4.33.0" @@ -2283,19 +2244,31 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.62.0": +"@typescript-eslint/typescript-estree@^5.55.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.62.0" "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - eslint-scope "^5.1.1" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" 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== + 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" + semver "^7.5.4" "@typescript-eslint/visitor-keys@4.33.0": version "4.33.0" @@ -2313,6 +2286,14 @@ "@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== + dependencies: + "@typescript-eslint/types" "6.4.1" + 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" @@ -2320,6 +2301,79 @@ dependencies: "@swc/core" "^1.3.61" +"@volar/language-core@1.10.1", "@volar/language-core@~1.10.0": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-1.10.1.tgz#76789c5b0c214eeff8add29cbff0333d89b6fc4a" + integrity sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA== + dependencies: + "@volar/source-map" "1.10.1" + +"@volar/source-map@1.10.1", "@volar/source-map@~1.10.0": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-1.10.1.tgz#b806845782cc615f2beba94624ff34a700f302f5" + integrity sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA== + dependencies: + muggle-string "^0.3.1" + +"@volar/typescript@~1.10.0": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-1.10.1.tgz#b20341c1cc5785b4de0669ea645e1619c97a4764" + integrity sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ== + dependencies: + "@volar/language-core" "1.10.1" + +"@vue/compiler-core@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128" + integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g== + dependencies: + "@babel/parser" "^7.21.3" + "@vue/shared" "3.3.4" + estree-walker "^2.0.2" + source-map-js "^1.0.2" + +"@vue/compiler-dom@^3.3.0": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151" + integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w== + dependencies: + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" + +"@vue/language-core@1.8.8", "@vue/language-core@^1.8.8": + version "1.8.8" + resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.8.tgz#5a8aa8363f4dfacdfcd7808a9926744d7c310ae6" + integrity sha512-i4KMTuPazf48yMdYoebTkgSOJdFraE4pQf0B+FTOFkbB+6hAfjrSou/UmYWRsWyZV6r4Rc6DDZdI39CJwL0rWw== + dependencies: + "@volar/language-core" "~1.10.0" + "@volar/source-map" "~1.10.0" + "@vue/compiler-dom" "^3.3.0" + "@vue/reactivity" "^3.3.0" + "@vue/shared" "^3.3.0" + minimatch "^9.0.0" + muggle-string "^0.3.1" + vue-template-compiler "^2.7.14" + +"@vue/reactivity@^3.3.0": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.3.4.tgz#a27a29c6cd17faba5a0e99fbb86ee951653e2253" + integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ== + dependencies: + "@vue/shared" "3.3.4" + +"@vue/shared@3.3.4", "@vue/shared@^3.3.0": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780" + integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ== + +"@vue/typescript@1.8.8": + version "1.8.8" + resolved "https://registry.yarnpkg.com/@vue/typescript/-/typescript-1.8.8.tgz#8efb375d448862134492a044f4e96afada547500" + integrity sha512-jUnmMB6egu5wl342eaUH236v8tdcEPXXkPgj+eI/F6JwW/lb+yAU6U07ZbQ3MVabZRlupIlPESB7ajgAGixhow== + dependencies: + "@volar/typescript" "~1.10.0" + "@vue/language-core" "1.8.8" + "@xobotyi/scrollbar-width@^1.9.5": version "1.9.5" resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" @@ -2352,20 +2406,19 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" + ajv "^8.0.0" -ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@~6.12.6: +ajv@^6.12.4, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2375,17 +2428,27 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@~6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.10.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-colors@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== +ansi-escapes@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6" + integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== dependencies: - type-fest "^0.21.3" + type-fest "^1.0.2" ansi-regex@^5.0.1: version "5.0.1" @@ -2411,7 +2474,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^6.0.0: +ansi-styles@^6.0.0, ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== @@ -2535,10 +2598,12 @@ ast-module-types@^4.0.0: resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-4.0.0.tgz#17e1cadd5b5b108e7295b0cf0cff21ccc226b639" integrity sha512-Kd0o8r6CDazJGCRzs8Ivpn0xj19oNKrULhoJFzhGjRsLpekF2zyZs9Ukz+JvZhWD6smszfepakTFhAaYpsI12g== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +asynciterator.prototype@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" + integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== + dependencies: + has-symbols "^1.0.3" asynckit@^0.4.0: version "0.4.0" @@ -2596,6 +2661,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +big-integer@^1.6.44: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -2615,6 +2685,13 @@ boolean@^3.1.4: resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2637,11 +2714,6 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -2650,6 +2722,13 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + busboy@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -2665,25 +2744,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-me-maybe@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" - integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -chalk@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" - integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== +chalk@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" @@ -2735,11 +2804,6 @@ classcat@^5.0.3, classcat@^5.0.4: resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.4.tgz#e12d1dfe6df6427f260f03b80dc63571a5107ba6" integrity sha512-sbpkOw6z413p+HDGcBENe498WM9woqWHiJxCq7nvmxe9WmrUmqfAcxpIwAiMtM5Q3AhYkzXcNQHqsWq0mND51g== -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - clear-any-console@^1.16.0: version "1.16.2" resolved "https://registry.yarnpkg.com/clear-any-console/-/clear-any-console-1.16.2.tgz#0543bb068da00151bf77b7a01ebf05d611086bb9" @@ -2760,6 +2824,13 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + cli-handle-error@^4.1.0: version "4.4.0" resolved "https://registry.yarnpkg.com/cli-handle-error/-/cli-handle-error-4.4.0.tgz#f65d7d66c3d648a063696b5c83f3b8cc850da25d" @@ -2780,14 +2851,6 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db" integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - cli-truncate@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" @@ -2824,11 +2887,6 @@ clsx@1.1.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== -code-block-writer@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" - integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2858,7 +2916,7 @@ color2k@^2.0.0: resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.2.tgz#ac2b4aea11c822a6bcb70c768b5a289f4fffcebb" integrity sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w== -colorette@^2.0.19: +colorette@^2.0.20: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== @@ -2875,12 +2933,17 @@ 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@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -commander@^2.16.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1: +commander@^2.16.0, commander@^2.19.0, commander@^2.20.3, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2905,11 +2968,6 @@ compute-scroll-into-view@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@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz#2b444b2b9e4724819d2531efacb7ac094155fdf6" - integrity sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -3075,7 +3133,12 @@ dateformat@^5.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-5.0.3.tgz#fe2223eff3cc70ce716931cb3038b59a9280696e" integrity sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA== -debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== + +debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3102,10 +3165,23 @@ deepmerge@^2.1.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== -deepmerge@^4.2.2: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" defaults@^1.0.3: version "1.0.4" @@ -3119,6 +3195,11 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" @@ -3319,17 +3400,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -downshift@^7.6.0: - version "7.6.2" - resolved "https://registry.yarnpkg.com/downshift/-/downshift-7.6.2.tgz#16fc951b7ff8f9c1c47d0f71b5ff10d78fb06e4c" - integrity sha512-iOv+E1Hyt3JDdL9yYcOgW7nZ7GQ2Uz6YbggwXvKUSleetYhU2nXD482Rz6CzvM4lvI1At34BYruKAL4swRGxaA== - dependencies: - "@babel/runtime" "^7.14.8" - compute-scroll-into-view "^2.0.4" - prop-types "^15.7.2" - react-is "^17.0.2" - tslib "^2.3.0" - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -3345,21 +3415,21 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -engine.io-client@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.1.tgz#1735fb8ae3bae5ae13115e18d2f484daf005dd9c" - integrity sha512-hE5wKXH8Ru4L19MbM1GgYV/2Qo54JSMh1rlJbfpa40bEWkCKNo3ol2eOtGmowcr+ysgbI7+SGL+by42Q3pt/Ng== +engine.io-client@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.2.tgz#8709e22c291d4297ae80318d3c8baeae71f0e002" + integrity sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" - engine.io-parser "~5.1.0" + engine.io-parser "~5.2.1" ws "~8.11.0" xmlhttprequest-ssl "~2.0.0" -engine.io-parser@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.1.0.tgz#d593d6372d7f79212df48f807b8cace1ea1cb1b8" - integrity sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w== +engine.io-parser@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb" + integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ== enhanced-resolve@^5.8.3: version "5.15.0" @@ -3383,7 +3453,7 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.3.4" -es-abstract@^1.19.0, es-abstract@^1.20.4: +es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.3: version "1.22.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== @@ -3428,6 +3498,26 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.10" +es-iterator-helpers@^1.0.12: + version "1.0.13" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz#72101046ffc19baf9996adc70e6177a26e6e8084" + integrity sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA== + dependencies: + asynciterator.prototype "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.21.3" + es-set-tostringtag "^2.0.1" + function-bind "^1.1.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + iterator.prototype "^1.1.0" + safe-array-concat "^1.0.0" + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -3535,32 +3625,34 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" - integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== +eslint-config-prettier@^9.0.0: + version "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@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== +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== dependencies: prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" eslint-plugin-react-hooks@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== -eslint-plugin-react@^7.32.2: - version "7.32.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" - integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== +eslint-plugin-react@^7.33.2: + version "7.33.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== dependencies: array-includes "^3.1.6" array.prototype.flatmap "^1.3.1" array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" @@ -3570,21 +3662,13 @@ eslint-plugin-react@^7.32.2: object.values "^1.1.6" prop-types "^15.8.1" resolve "^2.0.0-next.4" - semver "^6.3.0" + semver "^6.3.1" string.prototype.matchall "^4.0.8" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.2.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.1.tgz#936821d3462675f25a18ac5fd88a67cc15b393bd" - integrity sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -3599,27 +3683,32 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@^8.43.0: - version "8.45.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.45.0.tgz#bab660f90d18e1364352c0a6b7c6db8edb458b78" - integrity sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw== +eslint-visitor-keys@^3.4.3: + version "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== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.1.0" - "@eslint/js" "8.44.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "^8.47.0" "@humanwhocodes/config-array" "^0.11.10" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.1" - espree "^9.6.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -3642,7 +3731,7 @@ eslint@^8.43.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^9.6.0: +espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -3670,11 +3759,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -3690,10 +3774,15 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" - integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== +eventemitter3@^5.0.1: + version "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== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.1" @@ -3705,6 +3794,21 @@ execa@^7.0.0: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.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" @@ -3715,7 +3819,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== @@ -3726,20 +3830,33 @@ fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-json-stringify@^2.7.10: - version "2.7.13" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz#277aa86c2acba4d9851bd6108ed657aa327ed8c0" - integrity sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA== +fast-json-stringify@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-5.8.0.tgz#b229ed01ac5f92f3b82001a916c31324652f46d7" + integrity sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ== dependencies: - ajv "^6.11.0" - deepmerge "^4.2.2" + "@fastify/deepmerge" "^1.0.0" + ajv "^8.10.0" + ajv-formats "^2.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^2.1.0" rfdc "^1.2.0" - string-similarity "^4.0.1" fast-levenshtein@^2.0.6: version "2.0.6" @@ -3763,6 +3880,11 @@ fast-shallow-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== +fast-uri@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.2.0.tgz#519a0f849bef714aad10e9753d69d8f758f7445a" + integrity sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg== + fastest-stable-stringify@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" @@ -3886,10 +4008,10 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formik@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.2.tgz#a1115457cfb012a5c782cea3ad4b40b2fe36fa18" - integrity sha512-C6nx0hifW2uENP3M6HpPmnAE6HFWCcd8/sqBZEOHZY6lpHJ5qehsfAy43ktpFLEmkBmhiZDei726utcUB9leqg== +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== dependencies: deepmerge "^2.1.1" hoist-non-react-statics "^3.3.0" @@ -3899,10 +4021,10 @@ formik@^2.4.2: tiny-warning "^1.0.2" tslib "^2.0.0" -framer-motion@^10.12.17: - version "10.12.22" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.12.22.tgz#f1e7e36cc24fa5407ea33ccbd6d2996f50ceb503" - integrity sha512-bBGYPOxvxcfzS7/py9MEqDucmXBkVl2g42HNlXXPieSTSGGkr8L7+MilCnrU6uX3HrNk/tcB++1SkWE8BosHFw== +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== dependencies: tslib "^2.4.0" optionalDependencies: @@ -3915,24 +4037,6 @@ framesync@6.1.2: dependencies: tslib "2.4.0" -fs-extra@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-extra@^9.0.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -4028,7 +4132,7 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-stream@^6.0.1: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -4122,18 +4226,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -4180,6 +4272,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -4194,6 +4291,11 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + human-signals@^4.3.0: version "4.3.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" @@ -4223,10 +4325,10 @@ i18next-http-backend@^2.2.1: dependencies: cross-fetch "3.1.6" -i18next@^23.2.3: - version "23.2.11" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.2.11.tgz#0c6f3a637fa87d3243e64b78ad285b7f77d41353" - integrity sha512-MA4FsxOjyCaOZtRDB4yuwjCvqYEioD4G4LlXOn7SO3rnQUlxTufyLsOqfL9MKakeLRBkefe8bqcs0D6Z/xFk1w== +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== dependencies: "@babel/runtime" "^7.22.5" @@ -4235,7 +4337,7 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.2.0: +ignore@^5.2.0, ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -4263,11 +4365,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -4329,6 +4426,13 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -4363,7 +4467,7 @@ is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.9.0: dependencies: has "^1.0.3" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -4375,6 +4479,11 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" @@ -4385,6 +4494,13 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -4395,6 +4511,13 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -4409,6 +4532,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -4421,6 +4551,11 @@ is-invalid-path@^0.1.0: dependencies: is-glob "^2.0.0" +is-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -4466,6 +4601,11 @@ is-relative-path@^1.0.2: resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46" integrity sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA== +is-set@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -4473,6 +4613,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" @@ -4521,6 +4666,11 @@ is-valid-path@^0.1.1: dependencies: is-invalid-path "^0.1.0" +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -4528,6 +4678,14 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -4545,6 +4703,17 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +iterator.prototype@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.0.tgz#690c88b043d821f783843aaf725d7ac3b62e3b46" + integrity sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw== + dependencies: + define-properties "^1.1.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + has-tostringtag "^1.0.0" + reflect.getprototypeof "^1.0.3" + its-fine@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.1.1.tgz#e74b93fddd487441f978a50f64f0f5af4d2fc38e" @@ -4579,23 +4748,28 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-schema-ref-parser@^9.0.9: - version "9.0.9" - resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#66ea538e7450b12af342fa3d5b8458bc1e1e013f" - integrity sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q== - dependencies: - "@apidevtools/json-schema-ref-parser" "9.0.9" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stable-stringify@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" + integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== + dependencies: + jsonify "^0.0.1" + json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -4619,6 +4793,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + "jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.3.4" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz#b896535fed5b867650acce5a9bd4135ffc7b3bf9" @@ -4641,7 +4820,7 @@ klona@^2.0.5: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== -kolorist@^1.7.0: +kolorist@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== @@ -4669,24 +4848,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@^13.2.2: - version "13.2.3" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.3.tgz#f899aad6c093473467e9c9e316e3c2d8a28f87a7" - integrity sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg== +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== dependencies: - chalk "5.2.0" - cli-truncate "^3.1.0" - commander "^10.0.0" - debug "^4.3.4" - execa "^7.0.0" + chalk "5.3.0" + commander "11.0.0" + debug "4.3.4" + execa "7.2.0" lilconfig "2.1.0" - listr2 "^5.0.7" - micromatch "^4.0.5" - normalize-path "^3.0.0" - object-inspect "^1.12.3" - pidtree "^0.6.0" - string-argv "^0.3.1" - yaml "^2.2.2" + listr2 "6.6.1" + micromatch "4.0.5" + pidtree "0.6.0" + string-argv "0.3.2" + yaml "2.3.1" liqe@^3.6.0: version "3.6.1" @@ -4696,19 +4872,17 @@ liqe@^3.6.0: nearley "^2.20.1" ts-error "^1.0.6" -listr2@^5.0.7: - version "5.0.8" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" - integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== +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== dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.19" - log-update "^4.0.0" - p-map "^4.0.0" + cli-truncate "^3.1.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^5.0.1" rfdc "^1.3.0" - rxjs "^7.8.0" - through "^2.3.8" - wrap-ansi "^7.0.0" + wrap-ansi "^8.1.0" locate-path@^6.0.0: version "6.0.0" @@ -4762,15 +4936,16 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== +log-update@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" + integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" + ansi-escapes "^5.0.0" + cli-cursor "^4.0.0" + slice-ansi "^5.0.0" + strip-ansi "^7.0.1" + wrap-ansi "^8.0.1" loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" @@ -4814,13 +4989,6 @@ madge@^6.1.0: ts-graphviz "^1.5.0" walkdir "^0.4.1" -magic-string@^0.29.0: - version "0.29.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.29.0.tgz#f034f79f8c43dba4ae1730ffb5e8c4e084b16cf3" - integrity sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.13" - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -4836,7 +5004,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -4873,10 +5041,10 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^7.4.3: - version "7.4.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" - integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== +minimatch@^9.0.0: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" @@ -4885,11 +5053,6 @@ minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -mkdirp@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - module-definition@^3.3.1: version "3.4.0" resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-3.4.0.tgz#953a3861f65df5e43e80487df98bb35b70614c2b" @@ -4927,6 +5090,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +muggle-string@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.3.1.tgz#e524312eb1728c63dd0b2ac49e3282e6ed85963a" + integrity sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg== + nano-css@^5.3.1: version "5.3.5" resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.5.tgz#3075ea29ffdeb0c7cb6d25edb21d8f7fa8e8fe8e" @@ -4951,11 +5119,6 @@ nanostores@^0.9.2: resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.9.3.tgz#a095de5cb695e027b84657d5e31cabd6c5bb269c" integrity sha512-KobZjcVyNndNrb5DAjfs0WG0lRcZu5Q1BOrfTOxokFLi25zFrWPjg+joXC6kuDqNfSt9fQwppyjUBkRPtsL+8w== -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4971,11 +5134,6 @@ nearley@^2.20.1: railroad-diagrams "^1.0.0" randexp "0.4.6" -neo-async@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - new-github-issue-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-1.0.0.tgz#c9e84057c2609b7cbd686d1d8baa53e291292e79" @@ -5007,6 +5165,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + npm-run-path@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" @@ -5081,7 +5246,7 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -5112,37 +5277,43 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -openapi-fetch@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.6.1.tgz#90d785ead213b82beb8f094a756ad9320ba28b32" - integrity sha512-CGWPqqtL31uC2e4eEU9NHoqYMXnJ7Jk4H/4Yguil4tO22MIZi91hlQJ/51E8CiaKdSTODh03yF4ndjIOABVHUw== +open@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.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== + dependencies: + openapi-typescript-helpers "^0.0.1" 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-codegen@^0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/openapi-typescript-codegen/-/openapi-typescript-codegen-0.24.0.tgz#b3e6ade5bae75cd47868e5e3e4dc3bcf899cadab" - integrity sha512-rSt8t1XbMWhv6Db7GUI24NNli7FU5kzHLxcE8BpzgGWRdWyWt9IB2YoLyPahxNrVA7yOaVgnXPkrcTDRMQtJYg== - dependencies: - camelcase "^6.3.0" - commander "^10.0.0" - fs-extra "^11.1.1" - handlebars "^4.7.7" - json-schema-ref-parser "^9.0.9" +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@^6.2.8: - version "6.3.4" - resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.3.4.tgz#5351a73666e876206c50d8c100c8e8b2e4718882" - integrity sha512-icWb7WBBFr8+RxX7NZC5ez0WkTSQAScLnI33vHRLvWxkpOGKLlp94C0wcicZWzh85EoIoFjO+tujcQxo7zeZdA== +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== dependencies: ansi-colors "^4.1.3" - fast-glob "^3.3.0" + fast-glob "^3.3.1" js-yaml "^4.1.0" supports-color "^9.4.0" - undici "^5.22.1" + undici "^5.23.0" yargs-parser "^21.1.1" optionator@^0.9.3: @@ -5201,13 +5372,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5230,10 +5394,10 @@ parse-ms@^2.1.0: resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== -patch-package@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-7.0.2.tgz#c01589bb6964854b5210506a5845d47900641f5a" - integrity sha512-PMYfL8LXxGIRmxXLqlEaBxzKPu7/SdP13ld6GSfAUJUZRmBDPp8chZs0dpzaAFn9TSPnFiMwkC6PJt6pBiAl8Q== +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== dependencies: "@yarnpkg/lockfile" "^1.1.0" chalk "^4.1.2" @@ -5241,6 +5405,7 @@ patch-package@^7.0.0: cross-spawn "^7.0.3" find-yarn-workspace-root "^2.0.0" fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" klaw-sync "^6.0.0" minimist "^1.2.6" open "^7.4.2" @@ -5250,11 +5415,6 @@ patch-package@^7.0.0: tmp "^0.0.33" yaml "^2.2.2" -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -5265,7 +5425,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -5295,7 +5455,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pidtree@^0.6.0: +pidtree@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== @@ -5323,7 +5483,7 @@ postcss-values-parser@^6.0.2: is-url-superb "^4.0.0" quote-unquote "^1.0.0" -postcss@^8.1.7, postcss@^8.4.23, postcss@^8.4.25: +postcss@^8.1.7, postcss@^8.4.23: version "8.4.26" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.26.tgz#1bc62ab19f8e1e5463d98cf74af39702a00a9e94" integrity sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw== @@ -5332,6 +5492,15 @@ postcss@^8.1.7, postcss@^8.4.23, postcss@^8.4.25: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8.4.27: + version "8.4.28" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.28.tgz#c6cc681ed00109072816e1557f889ef51cf950a5" + integrity sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postinstall-postinstall@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" @@ -5391,6 +5560,11 @@ 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== + pretty-ms@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.1.tgz#7d903eaab281f7d8e03c66f867e239dc32fb73e8" @@ -5398,7 +5572,7 @@ pretty-ms@^7.0.1: dependencies: parse-ms "^2.1.0" -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5459,11 +5633,6 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -re-resizable@^6.9.9: - version "6.9.9" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" - integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== - react-clientside-effect@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" @@ -5522,15 +5691,15 @@ react-focus-lock@^2.9.4: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-hotkeys-hook@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.0.tgz#e7c55bb13ecb6ffb447e90ca5525403a5a3ac7b8" - integrity sha512-wOaCWLwgT/f895CMJrR9hmzVf+gfL8IpjWDXWXKngBp9i6Xqzf0tvLv4VI8l3Vlsg/cc4C/Iik3Ck76L/Hj0tw== +react-hotkeys-hook@4.4.1: + version "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.0.1: - version "13.0.2" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.0.2.tgz#1708a9bdabc1fe1dd4a8534f4c3a80ab784b01e9" - integrity sha512-NEVxC32v0oR4egwYM0QM0WE93AiJG5r0NTXTL8mhQfAhsMfDS2fSO6jpluyfsfypP988KzUQrAXncspcJ7+GHA== +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== dependencies: "@babel/runtime" "^7.22.5" html-parse-stringify "^3.0.1" @@ -5545,11 +5714,6 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -5573,10 +5737,10 @@ react-reconciler@~0.29.0: loose-envify "^1.1.0" scheduler "^0.23.0" -react-redux@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a" - integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA== +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== dependencies: "@babel/runtime" "^7.12.1" "@types/hoist-non-react-statics" "^3.3.1" @@ -5604,10 +5768,10 @@ react-remove-scroll@^2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-resizable-panels@^0.0.52: - version "0.0.52" - resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-0.0.52.tgz#d8b1df75c9c13ebef327e6cdf1cffde7103617f6" - integrity sha512-2vMvh7lEUCn19mqnmRLBd9BHvtub2zXCrf1UvzD8jLPVNvX9288PsF+vJwmdd7hXPMc9gdd7/CwFMfKvNnpUhQ== +react-resizable-panels@^0.0.55: + version "0.0.55" + resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-0.0.55.tgz#adf06d35ae09748ab7051a4bd2c5be8087ef1a66" + integrity sha512-J/LTFzUEjJiqwSjVh8gjUXkQDA8MRPjARASfn++d2+KOgA+9UcRYUfE3QBJixer2vkk+ffQ4cq3QzWzzHgqYpQ== react-style-singleton@^2.2.1: version "2.2.1" @@ -5652,10 +5816,10 @@ react-use@^17.4.0: ts-easing "^0.2.0" tslib "^2.1.0" -react-virtuoso@^4.3.11: - version "4.4.1" - resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.4.1.tgz#43d7ac35346c4eba947b40858b375d5844b5ae9f" - integrity sha512-QrZ0JLnZFH8ltMw6q+S7U1+V2vUcSHzoIfLRzQKSv4nMJhEdjiZ+e9PqWCI7xJiy2AmSCAgo7g1V5osuurJo2Q== +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-zoom-pan-pinch@^3.0.8: version "3.1.0" @@ -5669,17 +5833,17 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" -reactflow@^11.7.4: - version "11.7.4" - resolved "https://registry.yarnpkg.com/reactflow/-/reactflow-11.7.4.tgz#b00159c3471d007bc4865b23005c636b1f08ab26" - integrity sha512-QI6+oc1Ft6oFeLSdHlp+SmgymbI5Tm49wj5JyE84O4A54yN/ImfYaBhLit9Cmfzxn9Tz6tDqmGMGbk4bdtB8/w== +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== dependencies: - "@reactflow/background" "11.2.4" - "@reactflow/controls" "11.1.15" - "@reactflow/core" "11.7.4" - "@reactflow/minimap" "11.5.4" - "@reactflow/node-resizer" "2.1.1" - "@reactflow/node-toolbar" "1.2.3" + "@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" readable-stream@^3.4.0: version "3.6.2" @@ -5702,10 +5866,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@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/redux-remember/-/redux-remember-3.3.1.tgz#fad0b3af81458d8e40a54cd30be148c17e40bda9" - integrity sha512-x30eZpdryapH8+hinYcyoTiGCSmtPUPdvL7OxjpMeRgTckJrVW57FgRAmiv41COqi/q4H+qn65Uftsasqj+F9A== +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-thunk@^2.4.2: version "2.4.2" @@ -5719,6 +5883,18 @@ redux@^4.0.0, redux@^4.2.1: dependencies: "@babel/runtime" "^7.9.2" +reflect.getprototypeof@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz#2738fd896fcc3477ffbd4190b40c2458026b6928" + integrity sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.1" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" @@ -5738,6 +5914,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + requirejs-config-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-4.0.0.tgz#4244da5dd1f59874038cc1091d078d620abb6ebc" @@ -5805,6 +5986,14 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -5834,16 +6023,16 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -roarr@^7.15.0: - version "7.15.0" - resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.15.0.tgz#09b792f0cd31b4a7f91030bb1c47550ceec98ee4" - integrity sha512-CV9WefQfUXTX6wr8CrEMhfNef3sjIt9wNhE/5PNu4tNWsaoDNDXqq+OGn/RW9A1UPb0qc7FQlswXRaJJJsqn8A== +roarr@^7.15.1: + version "7.15.1" + resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.15.1.tgz#e4d93105c37b5ea7dd1200d96a3500f757ddc39f" + integrity sha512-0ExL9rjOXeQPvQvQo8IcV8SR2GTXmDr1FQFlY2HiAV+gdVQjaVZNOx9d4FI2RqFFsd0sNsiw2TRS/8RU9g0ZfA== dependencies: boolean "^3.1.4" - fast-json-stringify "^2.7.10" + fast-json-stringify "^5.8.0" fast-printf "^1.6.9" globalthis "^1.0.2" - safe-stable-stringify "^2.4.1" + safe-stable-stringify "^2.4.3" semver-compare "^1.0.0" rollup-plugin-visualizer@^5.9.2: @@ -5863,10 +6052,10 @@ rollup@^2.77.2: optionalDependencies: fsevents "~2.3.2" -rollup@^3.25.2: - version "3.26.3" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.26.3.tgz#bbc8818cadd0aebca348dbb3d68d296d220967b8" - integrity sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ== +rollup@^3.27.1: + version "3.28.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.28.0.tgz#a3c70004b01934760c0cb8df717c7a1d932389a2" + integrity sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw== optionalDependencies: fsevents "~2.3.2" @@ -5877,6 +6066,13 @@ rtl-css-js@^1.14.0: dependencies: "@babel/runtime" "^7.1.2" +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -5884,7 +6080,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.8.0, rxjs@^7.8.1: +rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -5915,7 +6111,7 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-stable-stringify@^2.4.1: +safe-stable-stringify@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== @@ -5944,29 +6140,22 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -semver@^6.3.0: +semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: +semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -semver@~7.3.0: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -serialize-error@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.0.tgz#0129f2b07b19b09bc7a5f2d850ffe9cd2d561582" - integrity sha512-YKrURWDqcT3VGX/s/pCwaWtpfJEEaEw5Y4gAnQDku92b/HjVj4r4UhA5QrMVMFotymK2wIWs5xthny5SMFu7Vw== +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== dependencies: type-fest "^2.12.2" @@ -6001,7 +6190,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.2, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -6016,24 +6205,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - slice-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" @@ -6042,14 +6213,14 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" -socket.io-client@^4.7.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.1.tgz#48e5f703abe4fb0402182bcf9c06b7820fb3453b" - integrity sha512-Qk3Xj8ekbnzKu3faejo4wk2MzXA029XppiXtTF/PkbTg+fcwaTw1PlDrTrrrU4mKoYC4dvlApOnSeyLCKwek2w== +socket.io-client@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08" + integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.2" - engine.io-client "~6.5.1" + engine.io-client "~6.5.2" socket.io-parser "~4.2.4" socket.io-parser@~4.2.4: @@ -6065,14 +6236,6 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" @@ -6083,7 +6246,7 @@ source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -6154,16 +6317,11 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-argv@^0.3.1, string-argv@~0.3.1: +string-argv@0.3.2, string-argv@~0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -string-similarity@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" - integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -6173,7 +6331,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0: +string-width@^5.0.0, string-width@^5.0.1: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -6258,6 +6416,11 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-final-newline@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" @@ -6322,6 +6485,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +synckit@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" + integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + dependencies: + "@pkgr/utils" "^2.3.1" + tslib "^2.5.0" + tabbable@^6.0.1: version "6.2.0" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" @@ -6332,16 +6503,6 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser@^5.18.1: - version "5.19.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.1.tgz#dbd7231f224a9e2401d0f0959542ed74d76d340b" - integrity sha512-27hxBUVdV6GoNg1pKQ7Z5cbR6V9txPVyBA+FQw3BaZ1Wuzvztce5p156DaP0NVZNrMZZ+6iG9Syf7WgMNKDg2Q== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6352,11 +6513,6 @@ throttle-debounce@^3.0.1: resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== -through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - tiny-invariant@^1.0.6: version "1.3.1" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" @@ -6367,6 +6523,11 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6401,6 +6562,11 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +ts-api-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" + integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== + ts-easing@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" @@ -6416,14 +6582,6 @@ ts-graphviz@^1.5.0: resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.8.1.tgz#5d95e58120be8b571847331516327d4840cc44f7" integrity sha512-54/fe5iu0Jb6X0pmDmzsA2UHLfyHjUEUwfHtZcEOR0fZ6Myf+dFoO6eNsyL8CBDMJ9u7WWEewduVaiaXlvjSVw== -ts-morph@18.0.0: - version "18.0.0" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-18.0.0.tgz#b9e7a898ea115064585a8a775d86da6edc9c5b4e" - integrity sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA== - dependencies: - "@ts-morph/common" "~0.19.0" - code-block-writer "^12.0.0" - ts-toolbelt@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5" @@ -6454,7 +6612,7 @@ 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.3.0, tslib@^2.4.0: +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== @@ -6464,6 +6622,11 @@ tslib@^2.0.3: 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== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -6483,10 +6646,10 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^1.0.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== type-fest@^2.12.2: version "2.19.0" @@ -6547,11 +6710,6 @@ typescript@~5.0.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== -uglify-js@^3.1.4: - version "3.17.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" - integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -6562,10 +6720,10 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici@^5.22.1: - version "5.22.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" - integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw== +undici@^5.23.0: + version "5.23.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.23.0.tgz#e7bdb0ed42cebe7b7aca87ced53e6eaafb8f8ca0" + integrity sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg== dependencies: busboy "^1.6.0" @@ -6584,6 +6742,11 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -6653,26 +6816,22 @@ validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== -vite-plugin-css-injected-by-js@^3.1.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.2.1.tgz#c23e10e28a1afb78414fa3c162ac8a253cd1a6a4" - integrity sha512-8UQWy7tcmgwkaUKYfbj/8GOeAD0RPG2tdetAGg7WikWC8IEtNrovs8RRuLjFqdRqORT1XxchBB5tPl6xO/H95g== +vite-plugin-css-injected-by-js@^3.3.0: + version "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@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-2.3.0.tgz#6ab2edf56f48261bfede03958704bfaee2fca3e4" - integrity sha512-WbJgGtsStgQhdm3EosYmIdTGbag5YQpZ3HXWUAPCDyoXI5qN6EY0V7NXq0lAmnv9hVQsvh0htbYcg0Or5Db9JQ== +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== dependencies: - "@babel/parser" "^7.21.4" - "@microsoft/api-extractor" "^7.34.4" + "@microsoft/api-extractor" "^7.36.3" "@rollup/pluginutils" "^5.0.2" - "@rushstack/node-core-library" "^3.55.2" + "@vue/language-core" "^1.8.8" debug "^4.3.4" - fast-glob "^3.2.12" - fs-extra "^10.1.0" - kolorist "^1.7.0" - magic-string "^0.29.0" - ts-morph "18.0.0" + kolorist "^1.8.0" + vue-tsc "^1.8.8" vite-plugin-eslint@^1.8.1: version "1.8.1" @@ -6692,14 +6851,14 @@ vite-tsconfig-paths@^4.2.0: globrex "^0.1.2" tsconfck "^2.1.0" -vite@^4.3.9: - version "4.4.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.4.tgz#b76e6049c0e080cb54e735ad2d18287753752118" - integrity sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg== +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== dependencies: esbuild "^0.18.10" - postcss "^8.4.25" - rollup "^3.25.2" + postcss "^8.4.27" + rollup "^3.27.1" optionalDependencies: fsevents "~2.3.2" @@ -6708,6 +6867,23 @@ void-elements@3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +vue-template-compiler@^2.7.14: + version "2.7.14" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1" + integrity sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ== + dependencies: + de-indent "^1.0.2" + he "^1.2.0" + +vue-tsc@^1.8.8: + version "1.8.8" + resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.8.tgz#67317693eb2ef6747e89e6d834eeb6d2deb8871d" + integrity sha512-bSydNFQsF7AMvwWsRXD7cBIXaNs/KSjvzWLymq/UtKE36697sboX4EccSHFVxvgdBlI1frYPc/VMKJNB7DFeDQ== + dependencies: + "@vue/language-core" "1.8.8" + "@vue/typescript" "1.8.8" + semver "^7.3.8" + walkdir@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" @@ -6744,7 +6920,35 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.10, which-typed-array@^1.1.11: +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.9: version "1.1.11" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== @@ -6762,20 +6966,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -6785,6 +6975,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -6810,16 +7009,16 @@ 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@^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" @@ -6859,14 +7058,19 @@ z-schema@~5.0.2: optionalDependencies: commander "^10.0.0" -zod@^3.21.4: - version "3.21.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" - integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== +zod-validation-error@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-1.5.0.tgz#2b355007a1c3b7fb04fa476bfad4e7b3fd5491e3" + integrity sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw== -zustand@^4.3.1: - version "4.3.9" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.9.tgz#a7d4332bbd75dfd25c6848180b3df1407217f2ad" - integrity sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw== +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== + +zustand@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.1.tgz#0cd3a3e4756f21811bd956418fdc686877e8b3b0" + integrity sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw== dependencies: use-sync-external-store "1.2.0" diff --git a/mkdocs.yml b/mkdocs.yml index 6cbf410971..2888f2e6ba 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -98,6 +98,15 @@ plugins: 'installation/INSTALLING_MODELS.md': 'installation/050_INSTALLING_MODELS.md' 'installation/INSTALL_PATCHMATCH.md': 'installation/060_INSTALL_PATCHMATCH.md' +extra_javascript: + - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js + - javascripts/tablesort.js + +extra: + analytics: + provider: google + property: G-2X4JR4S4FB + nav: - Home: 'index.md' - Installation: @@ -118,9 +127,14 @@ nav: - Manual Installation on Windows: 'installation/deprecated_documentation/INSTALL_WINDOWS.md' - Installing Invoke with pip: 'installation/deprecated_documentation/INSTALL_PCP.md' - Source Installer: 'installation/deprecated_documentation/INSTALL_SOURCE.md' - - Community Nodes: + - Nodes: - Community Nodes: 'nodes/communityNodes.md' - - Overview: 'nodes/overview.md' + - Example Workflows: 'nodes/exampleWorkflows.md' + - Nodes Overview: 'nodes/overview.md' + - List of Default Nodes: 'nodes/defaultNodes.md' + - Node Editor Usage: 'nodes/NODES.md' + - ComfyUI to InvokeAI: 'nodes/comfyToInvoke.md' + - Contributing Nodes: 'nodes/contributingNodes.md' - Features: - Overview: 'features/index.md' - New to InvokeAI?: 'help/gettingStartedWithAI.md' @@ -130,13 +144,12 @@ nav: - Image-to-Image: 'features/IMG2IMG.md' - Controlling Logging: 'features/LOGGING.md' - Model Merging: 'features/MODEL_MERGING.md' - - Nodes Editor (Experimental): 'features/NODES.md' - - NSFW Checker: 'features/NSFW.md' + - Using Nodes : './nodes/overview' + - NSFW Checker: 'features/WATERMARK+NSFW.md' - Postprocessing: 'features/POSTPROCESS.md' - Prompting Features: 'features/PROMPTS.md' - Training: 'features/TRAINING.md' - Unified Canvas: 'features/UNIFIED_CANVAS.md' - - Variations: 'features/VARIATIONS.md' - InvokeAI Web Server: 'features/WEB.md' - WebUI Hotkeys: "features/WEBUIHOTKEYS.md" - Other: 'features/OTHER.md' @@ -148,6 +161,7 @@ nav: - Frontend Documentation: 'contributing/contribution_guides/development_guides/contributingToFrontend.md' - Local Development: 'contributing/LOCAL_DEVELOPMENT.md' - Documentation: 'contributing/contribution_guides/documentation.md' + - Nodes: 'contributing/INVOCATIONS.md' - Translation: 'contributing/contribution_guides/translation.md' - Tutorials: 'contributing/contribution_guides/tutorials.md' - Changelog: 'CHANGELOG.md' @@ -158,6 +172,7 @@ nav: - Outpainting: 'deprecated/OUTPAINTING.md' - Help: - Getting Started: 'help/gettingStartedWithAI.md' + - Diffusion Overview: 'help/diffusion.md' - Sampler Convergence: 'help/SAMPLER_CONVERGENCE.md' - Other: - Contributors: 'other/CONTRIBUTORS.md' diff --git a/pyproject.toml b/pyproject.toml index 02e53f066a..9aef66a35f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,6 +93,7 @@ dependencies = [ "mkdocs-redirects==1.2.0", ] "dev" = [ + "jurigged", "pudb", ] "test" = [ diff --git a/tests/test_config.py b/tests/test_config.py index 0a8d44ad34..88da7a02ab 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -5,6 +5,8 @@ import pytest from omegaconf import OmegaConf from pathlib import Path +from invokeai.app.services.config import InvokeAIAppConfig + @pytest.fixture def patch_rootdir(tmp_path: Path, monkeypatch: Any) -> None: @@ -34,6 +36,21 @@ InvokeAI: """ ) +init3 = OmegaConf.create( + """ +InvokeAI: + Generation: + sequential_guidance: true + attention_type: xformers + attention_slice_size: 7 + forced_tiled_decode: True + Device: + device: cpu + Model Cache: + ram: 1.25 +""" +) + def test_use_init(patch_rootdir): # note that we explicitly set omegaconf dict and argv here @@ -56,9 +73,18 @@ def test_use_init(patch_rootdir): assert not hasattr(conf2, "invalid_attribute") -def test_argv_override(patch_rootdir): - from invokeai.app.services.config import InvokeAIAppConfig +def test_legacy(): + conf = InvokeAIAppConfig.get_config() + assert conf + conf.parse_args(conf=init3, argv=[]) + assert conf.xformers_enabled + assert conf.device == "cpu" + assert conf.use_cpu + assert conf.ram == 1.25 + assert conf.ram_cache_size == 1.25 + +def test_argv_override(): conf = InvokeAIAppConfig.get_config() conf.parse_args(conf=init1, argv=["--always_use_cpu", "--max_cache=10"]) assert conf.always_use_cpu