mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix merge conflicts
This commit is contained in:
commit
83356ec74c
2
.github/workflows/build-installer.yml
vendored
2
.github/workflows/build-installer.yml
vendored
@ -41,5 +41,5 @@ jobs:
|
|||||||
- name: upload installer artifact
|
- name: upload installer artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.create_installer.outputs.INSTALLER_FILENAME }}
|
name: installer
|
||||||
path: ${{ steps.create_installer.outputs.INSTALLER_PATH }}
|
path: ${{ steps.create_installer.outputs.INSTALLER_PATH }}
|
||||||
|
@ -395,9 +395,9 @@ For our latest changes, view our [Release
|
|||||||
Notes](https://github.com/invoke-ai/InvokeAI/releases) and the
|
Notes](https://github.com/invoke-ai/InvokeAI/releases) and the
|
||||||
[CHANGELOG](docs/CHANGELOG.md).
|
[CHANGELOG](docs/CHANGELOG.md).
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting / FAQ
|
||||||
|
|
||||||
Please check out our **[Troubleshooting Guide](https://invoke-ai.github.io/InvokeAI/installation/010_INSTALL_AUTOMATED/#troubleshooting)** to get solutions for common installation
|
Please check out our **[FAQ](https://invoke-ai.github.io/InvokeAI/help/FAQ/)** to get solutions for common installation
|
||||||
problems and other issues. For more help, please join our [Discord][discord link]
|
problems and other issues. For more help, please join our [Discord][discord link]
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
@ -61,11 +61,33 @@ This sets up both python and frontend dependencies and builds the python package
|
|||||||
|
|
||||||
#### Sanity Check & Smoke Test
|
#### Sanity Check & Smoke Test
|
||||||
|
|
||||||
At this point, the release workflow pauses as the remaining publish jobs require approval.
|
At this point, the release workflow pauses as the remaining publish jobs require approval. Time to test the installer.
|
||||||
|
|
||||||
A maintainer should go to the **Summary** tab of the workflow, download the installer and test it. Ensure the app loads and generates.
|
Because the installer pulls from PyPI, and we haven't published to PyPI yet, you will need to install from the wheel:
|
||||||
|
|
||||||
> The same wheel file is bundled in the installer and in the `dist` artifact, which is uploaded to PyPI. You should end up with the exactly the same installation of the `invokeai` package from any of these methods.
|
- Download and unzip `dist.zip` and the installer from the **Summary** tab of the workflow
|
||||||
|
- Run the installer script using the `--wheel` CLI arg, pointing at the wheel:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./install.sh --wheel ../InvokeAI-4.0.0rc6-py3-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
- Install to a temporary directory so you get the new user experience
|
||||||
|
- Download a model and generate
|
||||||
|
|
||||||
|
> The same wheel file is bundled in the installer and in the `dist` artifact, which is uploaded to PyPI. You should end up with the exactly the same installation as if the installer got the wheel from PyPI.
|
||||||
|
|
||||||
|
##### Something isn't right
|
||||||
|
|
||||||
|
If testing reveals any issues, no worries. Cancel the workflow, which will cancel the pending publish jobs (you didn't approve them prematurely, right?).
|
||||||
|
|
||||||
|
Now you can start from the top:
|
||||||
|
|
||||||
|
- Fix the issues and PR the fixes per usual
|
||||||
|
- Get the PR approved and merged per usual
|
||||||
|
- Switch to `main` and pull in the fixes
|
||||||
|
- Run `make tag-release` to move the tag to `HEAD` (which has the fixes) and kick off the release workflow again
|
||||||
|
- Re-do the sanity check
|
||||||
|
|
||||||
#### PyPI Publish Jobs
|
#### PyPI Publish Jobs
|
||||||
|
|
||||||
@ -81,6 +103,12 @@ Both jobs require a maintainer to approve them from the workflow's **Summary** t
|
|||||||
|
|
||||||
> **If the version already exists on PyPI, the publish jobs will fail.** PyPI only allows a given version to be published once - you cannot change it. If version published on PyPI has a problem, you'll need to "fail forward" by bumping the app version and publishing a followup release.
|
> **If the version already exists on PyPI, the publish jobs will fail.** PyPI only allows a given version to be published once - you cannot change it. If version published on PyPI has a problem, you'll need to "fail forward" by bumping the app version and publishing a followup release.
|
||||||
|
|
||||||
|
##### Failing PyPI Publish
|
||||||
|
|
||||||
|
Check the [python infrastructure status page] for incidents.
|
||||||
|
|
||||||
|
If there are no incidents, contact @hipsterusername or @lstein, who have owner access to GH and PyPI, to see if access has expired or something like that.
|
||||||
|
|
||||||
#### `publish-testpypi` Job
|
#### `publish-testpypi` Job
|
||||||
|
|
||||||
Publishes the distribution on the [Test PyPI] index, using the `testpypi` GitHub environment.
|
Publishes the distribution on the [Test PyPI] index, using the `testpypi` GitHub environment.
|
||||||
@ -110,11 +138,13 @@ Publishes the distribution on the production PyPI index, using the `pypi` GitHub
|
|||||||
Once the release is published to PyPI, it's time to publish the GitHub release.
|
Once the release is published to PyPI, it's time to publish the GitHub release.
|
||||||
|
|
||||||
1. [Draft a new release] on GitHub, choosing the tag that triggered the release.
|
1. [Draft a new release] on GitHub, choosing the tag that triggered the release.
|
||||||
2. Write the release notes, describing important changes. The **Generate release notes** button automatically inserts the changelog and new contributors, and you can copy/paste the intro from previous releases.
|
1. Write the release notes, describing important changes. The **Generate release notes** button automatically inserts the changelog and new contributors, and you can copy/paste the intro from previous releases.
|
||||||
3. Upload the zip file created in **`build`** job into the Assets section of the release notes. You can also upload the zip into the body of the release notes, since it can be hard for users to find the Assets section.
|
1. Use `scripts/get_external_contributions.py` to get a list of external contributions to shout out in the release notes.
|
||||||
4. Check the **Set as a pre-release** and **Create a discussion for this release** checkboxes at the bottom of the release page.
|
1. Upload the zip file created in **`build`** job into the Assets section of the release notes.
|
||||||
5. Publish the pre-release.
|
1. Check **Set as a pre-release** if it's a pre-release.
|
||||||
6. Announce the pre-release in Discord.
|
1. Check **Create a discussion for this release**.
|
||||||
|
1. Publish the release.
|
||||||
|
1. Announce the release in Discord.
|
||||||
|
|
||||||
> **TODO** Workflows can create a GitHub release from a template and upload release assets. One popular action to handle this is [ncipollo/release-action]. A future enhancement to the release process could set this up.
|
> **TODO** Workflows can create a GitHub release from a template and upload release assets. One popular action to handle this is [ncipollo/release-action]. A future enhancement to the release process could set this up.
|
||||||
|
|
||||||
@ -140,3 +170,4 @@ This functionality is available as a fallback in case something goes wonky. Typi
|
|||||||
[trusted publishers]: https://docs.pypi.org/trusted-publishers/
|
[trusted publishers]: https://docs.pypi.org/trusted-publishers/
|
||||||
[samuelcolvin/check-python-version]: https://github.com/samuelcolvin/check-python-version
|
[samuelcolvin/check-python-version]: https://github.com/samuelcolvin/check-python-version
|
||||||
[manually]: #manual-release
|
[manually]: #manual-release
|
||||||
|
[python infrastructure status page]: https://status.python.org/
|
||||||
|
@ -840,22 +840,6 @@ and directories at regular intervals when the size of the cache
|
|||||||
exceeds the value specified in Invoke's `convert_cache` configuration
|
exceeds the value specified in Invoke's `convert_cache` configuration
|
||||||
variable.
|
variable.
|
||||||
|
|
||||||
#### List[str]=installer.scan_directory(scan_dir: Path, install: bool)
|
|
||||||
|
|
||||||
This method will recursively scan the directory indicated in
|
|
||||||
`scan_dir` for new models and either install them in the models
|
|
||||||
directory or register them in place, depending on the setting of
|
|
||||||
`install` (default False).
|
|
||||||
|
|
||||||
The return value is the list of keys of the new installed/registered
|
|
||||||
models.
|
|
||||||
|
|
||||||
#### installer.sync_to_config()
|
|
||||||
|
|
||||||
This method synchronizes models in the models directory and autoimport
|
|
||||||
directory to those in the `ModelConfigRecordService` database. New
|
|
||||||
models are registered and orphan models are unregistered.
|
|
||||||
|
|
||||||
#### installer.start(invoker)
|
#### installer.start(invoker)
|
||||||
|
|
||||||
The `start` method is called by the API intialization routines when
|
The `start` method is called by the API intialization routines when
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
## :octicons-log-16: Important Changes Since Version 2.3
|
|
||||||
|
|
||||||
### Nodes
|
|
||||||
|
|
||||||
Behind the scenes, InvokeAI has been completely rewritten to support
|
|
||||||
"nodes," small unitary operations that can be combined into graphs to
|
|
||||||
form arbitrary workflows. For example, there is a prompt node that
|
|
||||||
processes the prompt string and feeds it to a text2latent node that
|
|
||||||
generates a latent image. The latents are then fed to a latent2image
|
|
||||||
node that translates the latent image into a PNG.
|
|
||||||
|
|
||||||
The WebGUI has a node editor that allows you to graphically design and
|
|
||||||
execute custom node graphs. The ability to save and load graphs is
|
|
||||||
still a work in progress, but coming soon.
|
|
||||||
|
|
||||||
### Command-Line Interface Retired
|
|
||||||
|
|
||||||
All "invokeai" command-line interfaces have been retired as of version
|
|
||||||
3.4.
|
|
||||||
|
|
||||||
To launch the Web GUI from the command-line, use the command
|
|
||||||
`invokeai-web` rather than the traditional `invokeai --web`.
|
|
||||||
|
|
||||||
### ControlNet
|
|
||||||
|
|
||||||
This version of InvokeAI features ControlNet, a system that allows you
|
|
||||||
to achieve exact poses for human and animal figures by providing a
|
|
||||||
model to follow. Full details are found in [ControlNet](features/CONTROLNET.md)
|
|
||||||
|
|
||||||
### New Schedulers
|
|
||||||
|
|
||||||
The list of schedulers has been completely revamped and brought up to date:
|
|
||||||
|
|
||||||
| **Short Name** | **Scheduler** | **Notes** |
|
|
||||||
|----------------|---------------------------------|-----------------------------|
|
|
||||||
| **ddim** | DDIMScheduler | |
|
|
||||||
| **ddpm** | DDPMScheduler | |
|
|
||||||
| **deis** | DEISMultistepScheduler | |
|
|
||||||
| **lms** | LMSDiscreteScheduler | |
|
|
||||||
| **pndm** | PNDMScheduler | |
|
|
||||||
| **heun** | HeunDiscreteScheduler | original noise schedule |
|
|
||||||
| **heun_k** | HeunDiscreteScheduler | using karras noise schedule |
|
|
||||||
| **euler** | EulerDiscreteScheduler | original noise schedule |
|
|
||||||
| **euler_k** | EulerDiscreteScheduler | using karras noise schedule |
|
|
||||||
| **kdpm_2** | KDPM2DiscreteScheduler | |
|
|
||||||
| **kdpm_2_a** | KDPM2AncestralDiscreteScheduler | |
|
|
||||||
| **dpmpp_2s** | DPMSolverSinglestepScheduler | |
|
|
||||||
| **dpmpp_2m** | DPMSolverMultistepScheduler | original noise scnedule |
|
|
||||||
| **dpmpp_2m_k** | DPMSolverMultistepScheduler | using karras noise schedule |
|
|
||||||
| **unipc** | UniPCMultistepScheduler | CPU only |
|
|
||||||
| **lcm** | LCMScheduler | |
|
|
||||||
|
|
||||||
Please see [3.0.0 Release Notes](https://github.com/invoke-ai/InvokeAI/releases/tag/v3.0.0) for further details.
|
|
@ -1,589 +0,0 @@
|
|||||||
---
|
|
||||||
title: Command-Line Interface
|
|
||||||
---
|
|
||||||
|
|
||||||
# :material-bash: CLI
|
|
||||||
|
|
||||||
## **Interactive Command Line Interface**
|
|
||||||
|
|
||||||
The InvokeAI command line interface (CLI) provides scriptable access
|
|
||||||
to InvokeAI's features.Some advanced features are only available
|
|
||||||
through the CLI, though they eventually find their way into the WebUI.
|
|
||||||
|
|
||||||
The CLI is accessible from the `invoke.sh`/`invoke.bat` launcher by
|
|
||||||
selecting option (1). Alternatively, it can be launched directly from
|
|
||||||
the command line by activating the InvokeAI environment and giving the
|
|
||||||
command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai
|
|
||||||
```
|
|
||||||
|
|
||||||
After some startup messages, you will be presented with the `invoke> `
|
|
||||||
prompt. Here you can type prompts to generate images and issue other
|
|
||||||
commands to load and manipulate generative models. The CLI has a large
|
|
||||||
number of command-line options that control its behavior. To get a
|
|
||||||
concise summary of the options, call `invokeai` with the `--help` argument:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai --help
|
|
||||||
```
|
|
||||||
|
|
||||||
The script uses the readline library to allow for in-line editing, command
|
|
||||||
history (++up++ and ++down++), autocompletion, and more. To help keep track of
|
|
||||||
which prompts generated which images, the script writes a log file of image
|
|
||||||
names and prompts to the selected output directory.
|
|
||||||
|
|
||||||
Here is a typical session
|
|
||||||
|
|
||||||
```bash
|
|
||||||
PS1:C:\Users\fred> invokeai
|
|
||||||
* Initializing, be patient...
|
|
||||||
* Initializing, be patient...
|
|
||||||
>> Initialization file /home/lstein/invokeai/invokeai.init found. Loading...
|
|
||||||
>> Internet connectivity is True
|
|
||||||
>> InvokeAI, version 2.3.0-rc5
|
|
||||||
>> InvokeAI runtime directory is "/home/lstein/invokeai"
|
|
||||||
>> GFPGAN Initialized
|
|
||||||
>> CodeFormer Initialized
|
|
||||||
>> ESRGAN Initialized
|
|
||||||
>> Using device_type cuda
|
|
||||||
>> xformers memory-efficient attention is available and enabled
|
|
||||||
(...more initialization messages...)
|
|
||||||
* Initialization done! Awaiting your command (-h for help, 'q' to quit)
|
|
||||||
invoke> ashley judd riding a camel -n2 -s150
|
|
||||||
Outputs:
|
|
||||||
outputs/img-samples/00009.png: "ashley judd riding a camel" -n2 -s150 -S 416354203
|
|
||||||
outputs/img-samples/00010.png: "ashley judd riding a camel" -n2 -s150 -S 1362479620
|
|
||||||
|
|
||||||
invoke> "there's a fly in my soup" -n6 -g
|
|
||||||
outputs/img-samples/00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
|
||||||
seeds for individual rows: [2685670268, 1216708065, 2335773498, 822223658, 714542046, 3395302430]
|
|
||||||
invoke> q
|
|
||||||
```
|
|
||||||
|
|
||||||
![invoke-py-demo](../assets/dream-py-demo.png)
|
|
||||||
|
|
||||||
## Arguments
|
|
||||||
|
|
||||||
The script recognizes a series of command-line switches that will
|
|
||||||
change important global defaults, such as the directory for image
|
|
||||||
outputs and the location of the model weight files.
|
|
||||||
|
|
||||||
### List of arguments recognized at the command line
|
|
||||||
|
|
||||||
These command-line arguments can be passed to `invoke.py` when you first run it
|
|
||||||
from the Windows, Mac or Linux command line. Some set defaults that can be
|
|
||||||
overridden on a per-prompt basis (see
|
|
||||||
[List of prompt arguments](#list-of-prompt-arguments). Others
|
|
||||||
|
|
||||||
| Argument <img width="240" align="right"/> | Shortcut <img width="100" align="right"/> | Default <img width="320" align="right"/> | Description |
|
|
||||||
| ----------------------------------------- | ----------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
||||||
| `--help` | `-h` | | Print a concise help message. |
|
|
||||||
| `--outdir <path>` | `-o<path>` | `outputs/img_samples` | Location for generated images. |
|
|
||||||
| `--prompt_as_dir` | `-p` | `False` | Name output directories using the prompt text. |
|
|
||||||
| `--from_file <path>` | | `None` | Read list of prompts from a file. Use `-` to read from standard input |
|
|
||||||
| `--model <modelname>` | | `stable-diffusion-1.5` | Loads the initial model specified in configs/models.yaml. |
|
|
||||||
| `--ckpt_convert ` | | `False` | If provided both .ckpt and .safetensors files will be auto-converted into diffusers format in memory |
|
|
||||||
| `--autoconvert <path>` | | `None` | On startup, scan the indicated directory for new .ckpt/.safetensor files and automatically convert and import them |
|
|
||||||
| `--precision` | | `fp16` | Provide `fp32` for full precision mode, `fp16` for half-precision. `fp32` needed for Macintoshes and some NVidia cards. |
|
|
||||||
| `--png_compression <0-9>` | `-z<0-9>` | `6` | Select level of compression for output files, from 0 (no compression) to 9 (max compression) |
|
|
||||||
| `--safety-checker` | | `False` | Activate safety checker for NSFW and other potentially disturbing imagery |
|
|
||||||
| `--patchmatch`, `--no-patchmatch` | | `--patchmatch` | Load/Don't load the PatchMatch inpainting extension |
|
|
||||||
| `--xformers`, `--no-xformers` | | `--xformers` | Load/Don't load the Xformers memory-efficient attention module (CUDA only) |
|
|
||||||
| `--web` | | `False` | Start in web server mode |
|
|
||||||
| `--host <ip addr>` | | `localhost` | Which network interface web server should listen on. Set to 0.0.0.0 to listen on any. |
|
|
||||||
| `--port <port>` | | `9090` | Which port web server should listen for requests on. |
|
|
||||||
| `--config <path>` | | `configs/models.yaml` | Configuration file for models and their weights. |
|
|
||||||
| `--iterations <int>` | `-n<int>` | `1` | How many images to generate per prompt. |
|
|
||||||
| `--width <int>` | `-W<int>` | `512` | Width of generated image |
|
|
||||||
| `--height <int>` | `-H<int>` | `512` | Height of generated image | `--steps <int>` | `-s<int>` | `50` | How many steps of refinement to apply |
|
|
||||||
| `--strength <float>` | `-s<float>` | `0.75` | For img2img: how hard to try to match the prompt to the initial image. Ranges from 0.0-0.99, with higher values replacing the initial image completely. |
|
|
||||||
| `--fit` | `-F` | `False` | For img2img: scale the init image to fit into the specified -H and -W dimensions |
|
|
||||||
| `--grid` | `-g` | `False` | Save all image series as a grid rather than individually. |
|
|
||||||
| `--sampler <sampler>` | `-A<sampler>` | `k_lms` | Sampler to use. Use `-h` to get list of available samplers. |
|
|
||||||
| `--seamless` | | `False` | Create interesting effects by tiling elements of the image. |
|
|
||||||
| `--embedding_path <path>` | | `None` | Path to pre-trained embedding manager checkpoints, for custom models |
|
|
||||||
| `--gfpgan_model_path` | | `experiments/pretrained_models/GFPGANv1.4.pth` | Path to GFPGAN model file. |
|
|
||||||
| `--free_gpu_mem` | | `False` | Free GPU memory after sampling, to allow image decoding and saving in low VRAM conditions |
|
|
||||||
| `--precision` | | `auto` | Set model precision, default is selected by device. Options: auto, float32, float16, autocast |
|
|
||||||
|
|
||||||
!!! warning "These arguments are deprecated but still work"
|
|
||||||
|
|
||||||
<div align="center" markdown>
|
|
||||||
|
|
||||||
| Argument | Shortcut | Default | Description |
|
|
||||||
|--------------------|------------|---------------------|--------------|
|
|
||||||
| `--full_precision` | | `False` | Same as `--precision=fp32`|
|
|
||||||
| `--weights <path>` | | `None` | Path to weights file; use `--model stable-diffusion-1.4` instead |
|
|
||||||
| `--laion400m` | `-l` | `False` | Use older LAION400m weights; use `--model=laion400m` instead |
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
On Windows systems, you may run into
|
|
||||||
problems when passing the invoke script standard backslashed path
|
|
||||||
names because the Python interpreter treats "\" as an escape.
|
|
||||||
You can either double your slashes (ick): `C:\\path\\to\\my\\file`, or
|
|
||||||
use Linux/Mac style forward slashes (better): `C:/path/to/my/file`.
|
|
||||||
|
|
||||||
## The .invokeai initialization file
|
|
||||||
|
|
||||||
To start up invoke.py with your preferred settings, place your desired
|
|
||||||
startup options in a file in your home directory named `.invokeai` The
|
|
||||||
file should contain the startup options as you would type them on the
|
|
||||||
command line (`--steps=10 --grid`), one argument per line, or a
|
|
||||||
mixture of both using any of the accepted command switch formats:
|
|
||||||
|
|
||||||
!!! example "my unmodified initialization file"
|
|
||||||
|
|
||||||
```bash title="~/.invokeai" linenums="1"
|
|
||||||
# InvokeAI initialization file
|
|
||||||
# This is the InvokeAI initialization file, which contains command-line default values.
|
|
||||||
# Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting
|
|
||||||
# or renaming it and then running invokeai-configure again.
|
|
||||||
|
|
||||||
# The --root option below points to the folder in which InvokeAI stores its models, configs and outputs.
|
|
||||||
--root="/Users/mauwii/invokeai"
|
|
||||||
|
|
||||||
# the --outdir option controls the default location of image files.
|
|
||||||
--outdir="/Users/mauwii/invokeai/outputs"
|
|
||||||
|
|
||||||
# You may place other frequently-used startup commands here, one or more per line.
|
|
||||||
# Examples:
|
|
||||||
# --web --host=0.0.0.0
|
|
||||||
# --steps=20
|
|
||||||
# -Ak_euler_a -C10.0
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
The initialization file only accepts the command line arguments.
|
|
||||||
There are additional arguments that you can provide on the `invoke>` command
|
|
||||||
line (such as `-n` or `--iterations`) that cannot be entered into this file.
|
|
||||||
Also be alert for empty blank lines at the end of the file, which will cause
|
|
||||||
an arguments error at startup time.
|
|
||||||
|
|
||||||
## List of prompt arguments
|
|
||||||
|
|
||||||
After the invoke.py script initializes, it will present you with a `invoke>`
|
|
||||||
prompt. Here you can enter information to generate images from text
|
|
||||||
([txt2img](#txt2img)), to embellish an existing image or sketch
|
|
||||||
([img2img](#img2img)), or to selectively alter chosen regions of the image
|
|
||||||
([inpainting](#inpainting)).
|
|
||||||
|
|
||||||
### txt2img
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> waterfall and rainbow -W640 -H480
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create the requested image with the dimensions 640 (width)
|
|
||||||
and 480 (height).
|
|
||||||
|
|
||||||
Here are the invoke> command that apply to txt2img:
|
|
||||||
|
|
||||||
| Argument <img width="680" align="right"/> | Shortcut <img width="420" align="right"/> | Default <img width="480" align="right"/> | Description |
|
|
||||||
| ----------------------------------------- | ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| "my prompt" | | | Text prompt to use. The quotation marks are optional. |
|
|
||||||
| `--width <int>` | `-W<int>` | `512` | Width of generated image |
|
|
||||||
| `--height <int>` | `-H<int>` | `512` | Height of generated image |
|
|
||||||
| `--iterations <int>` | `-n<int>` | `1` | How many images to generate from this prompt |
|
|
||||||
| `--steps <int>` | `-s<int>` | `50` | How many steps of refinement to apply |
|
|
||||||
| `--cfg_scale <float>` | `-C<float>` | `7.5` | How hard to try to match the prompt to the generated image; any number greater than 1.0 works, but the useful range is roughly 5.0 to 20.0 |
|
|
||||||
| `--seed <int>` | `-S<int>` | `None` | Set the random seed for the next series of images. This can be used to recreate an image generated previously. |
|
|
||||||
| `--sampler <sampler>` | `-A<sampler>` | `k_lms` | Sampler to use. Use -h to get list of available samplers. |
|
|
||||||
| `--karras_max <int>` | | `29` | When using k\_\* samplers, set the maximum number of steps before shifting from using the Karras noise schedule (good for low step counts) to the LatentDiffusion noise schedule (good for high step counts) This value is sticky. [29] |
|
|
||||||
| `--hires_fix` | | | Larger images often have duplication artefacts. This option suppresses duplicates by generating the image at low res, and then using img2img to increase the resolution |
|
|
||||||
| `--png_compression <0-9>` | `-z<0-9>` | `6` | Select level of compression for output files, from 0 (no compression) to 9 (max compression) |
|
|
||||||
| `--grid` | `-g` | `False` | Turn on grid mode to return a single image combining all the images generated by this prompt |
|
|
||||||
| `--individual` | `-i` | `True` | Turn off grid mode (deprecated; leave off --grid instead) |
|
|
||||||
| `--outdir <path>` | `-o<path>` | `outputs/img_samples` | Temporarily change the location of these images |
|
|
||||||
| `--seamless` | | `False` | Activate seamless tiling for interesting effects |
|
|
||||||
| `--seamless_axes` | | `x,y` | Specify which axes to use circular convolution on. |
|
|
||||||
| `--log_tokenization` | `-t` | `False` | Display a color-coded list of the parsed tokens derived from the prompt |
|
|
||||||
| `--skip_normalization` | `-x` | `False` | Weighted subprompts will not be normalized. See [Weighted Prompts](../features/OTHER.md#weighted-prompts) |
|
|
||||||
| `--upscale <int> <float>` | `-U <int> <float>` | `-U 1 0.75` | Upscale image by magnification factor (2, 4), and set strength of upscaling (0.0-1.0). If strength not set, will default to 0.75. |
|
|
||||||
| `--facetool_strength <float>` | `-G <float> ` | `-G0` | Fix faces (defaults to using the GFPGAN algorithm); argument indicates how hard the algorithm should try (0.0-1.0) |
|
|
||||||
| `--facetool <name>` | `-ft <name>` | `-ft gfpgan` | Select face restoration algorithm to use: gfpgan, codeformer |
|
|
||||||
| `--codeformer_fidelity` | `-cf <float>` | `0.75` | Used along with CodeFormer. Takes values between 0 and 1. 0 produces high quality but low accuracy. 1 produces high accuracy but low quality |
|
|
||||||
| `--save_original` | `-save_orig` | `False` | When upscaling or fixing faces, this will cause the original image to be saved rather than replaced. |
|
|
||||||
| `--variation <float>` | `-v<float>` | `0.0` | Add a bit of noise (0.0=none, 1.0=high) to the image in order to generate a series of variations. Usually used in combination with `-S<seed>` and `-n<int>` to generate a series a riffs on a starting image. See [Variations](VARIATIONS.md). |
|
|
||||||
| `--with_variations <pattern>` | | `None` | Combine two or more variations. See [Variations](VARIATIONS.md) for now to use this. |
|
|
||||||
| `--save_intermediates <n>` | | `None` | Save the image from every nth step into an "intermediates" folder inside the output directory |
|
|
||||||
| `--h_symmetry_time_pct <float>` | | `None` | Create symmetry along the X axis at the desired percent complete of the generation process. (Must be between 0.0 and 1.0; set to a very small number like 0.0001 for just after the first step of generation.) |
|
|
||||||
| `--v_symmetry_time_pct <float>` | | `None` | Create symmetry along the Y axis at the desired percent complete of the generation process. (Must be between 0.0 and 1.0; set to a very small number like 0.0001 for just after the first step of generation.) |
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
the width and height of the image must be multiples of 64. You can
|
|
||||||
provide different values, but they will be rounded down to the nearest multiple
|
|
||||||
of 64.
|
|
||||||
|
|
||||||
!!! example "This is a example of img2img"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit
|
|
||||||
```
|
|
||||||
|
|
||||||
This will modify the indicated vacation photograph by making it more like the
|
|
||||||
prompt. Results will vary greatly depending on what is in the image. We also ask
|
|
||||||
to --fit the image into a box no bigger than 640x480. Otherwise the image size
|
|
||||||
will be identical to the provided photo and you may run out of memory if it is
|
|
||||||
large.
|
|
||||||
|
|
||||||
In addition to the command-line options recognized by txt2img, img2img accepts
|
|
||||||
additional options:
|
|
||||||
|
|
||||||
| Argument <img width="160" align="right"/> | Shortcut | Default | Description |
|
|
||||||
| ----------------------------------------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| `--init_img <path>` | `-I<path>` | `None` | Path to the initialization image |
|
|
||||||
| `--fit` | `-F` | `False` | Scale the image to fit into the specified -H and -W dimensions |
|
|
||||||
| `--strength <float>` | `-s<float>` | `0.75` | How hard to try to match the prompt to the initial image. Ranges from 0.0-0.99, with higher values replacing the initial image completely. |
|
|
||||||
|
|
||||||
### inpainting
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit
|
|
||||||
```
|
|
||||||
|
|
||||||
This will do the same thing as img2img, but image alterations will
|
|
||||||
only occur within transparent areas defined by the mask file specified
|
|
||||||
by `-M`. You may also supply just a single initial image with the areas
|
|
||||||
to overpaint made transparent, but you must be careful not to destroy
|
|
||||||
the pixels underneath when you create the transparent areas. See
|
|
||||||
[Inpainting](INPAINTING.md) for details.
|
|
||||||
|
|
||||||
inpainting accepts all the arguments used for txt2img and img2img, as well as
|
|
||||||
the --mask (-M) and --text_mask (-tm) arguments:
|
|
||||||
|
|
||||||
| Argument <img width="100" align="right"/> | Shortcut | Default | Description |
|
|
||||||
| ----------------------------------------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------------ |
|
|
||||||
| `--init_mask <path>` | `-M<path>` | `None` | Path to an image the same size as the initial_image, with areas for inpainting made transparent. |
|
|
||||||
| `--invert_mask ` | | False | If true, invert the mask so that transparent areas are opaque and vice versa. |
|
|
||||||
| `--text_mask <prompt> [<float>]` | `-tm <prompt> [<float>]` | <none> | Create a mask from a text prompt describing part of the image |
|
|
||||||
|
|
||||||
The mask may either be an image with transparent areas, in which case the
|
|
||||||
inpainting will occur in the transparent areas only, or a black and white image,
|
|
||||||
in which case all black areas will be painted into.
|
|
||||||
|
|
||||||
`--text_mask` (short form `-tm`) is a way to generate a mask using a text
|
|
||||||
description of the part of the image to replace. For example, if you have an
|
|
||||||
image of a breakfast plate with a bagel, toast and scrambled eggs, you can
|
|
||||||
selectively mask the bagel and replace it with a piece of cake this way:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a piece of cake -I /path/to/breakfast.png -tm bagel
|
|
||||||
```
|
|
||||||
|
|
||||||
The algorithm uses <a
|
|
||||||
href="https://github.com/timojl/clipseg">clipseg</a> to classify different
|
|
||||||
regions of the image. The classifier puts out a confidence score for each region
|
|
||||||
it identifies. Generally regions that score above 0.5 are reliable, but if you
|
|
||||||
are getting too much or too little masking you can adjust the threshold down (to
|
|
||||||
get more mask), or up (to get less). In this example, by passing `-tm` a higher
|
|
||||||
value, we are insisting on a more stringent classification.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a piece of cake -I /path/to/breakfast.png -tm bagel 0.6
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom Styles and Subjects
|
|
||||||
|
|
||||||
You can load and use hundreds of community-contributed Textual
|
|
||||||
Inversion models just by typing the appropriate trigger phrase. Please
|
|
||||||
see [Concepts Library](../features/CONCEPTS.md) for more details.
|
|
||||||
|
|
||||||
## Other Commands
|
|
||||||
|
|
||||||
The CLI offers a number of commands that begin with "!".
|
|
||||||
|
|
||||||
### Postprocessing images
|
|
||||||
|
|
||||||
To postprocess a file using face restoration or upscaling, use the `!fix`
|
|
||||||
command.
|
|
||||||
|
|
||||||
#### `!fix`
|
|
||||||
|
|
||||||
This command runs a post-processor on a previously-generated image. It takes a
|
|
||||||
PNG filename or path and applies your choice of the `-U`, `-G`, or `--embiggen`
|
|
||||||
switches in order to fix faces or upscale. If you provide a filename, the script
|
|
||||||
will look for it in the current output directory. Otherwise you can provide a
|
|
||||||
full or partial path to the desired file.
|
|
||||||
|
|
||||||
Some examples:
|
|
||||||
|
|
||||||
!!! example "Upscale to 4X its original size and fix faces using codeformer"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! example "Use the GFPGAN algorithm to fix faces, then upscale to 3X using --embiggen"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix 0000045.4829112.png -G0.8 -ft gfpgan
|
|
||||||
>> fixing outputs/img-samples/0000045.4829112.png
|
|
||||||
>> retrieved seed 4829112 and prompt "boy enjoying a banana split"
|
|
||||||
>> GFPGAN - Restoring Faces for image seed:4829112
|
|
||||||
Outputs:
|
|
||||||
[1] outputs/img-samples/000017.4829112.gfpgan-00.png: !fix "outputs/img-samples/0000045.4829112.png" -s 50 -S -W 512 -H 512 -C 7.5 -A k_lms -G 0.8
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `!mask`
|
|
||||||
|
|
||||||
This command takes an image, a text prompt, and uses the `clipseg` algorithm to
|
|
||||||
automatically generate a mask of the area that matches the text prompt. It is
|
|
||||||
useful for debugging the text masking process prior to inpainting with the
|
|
||||||
`--text_mask` argument. See [INPAINTING.md] for details.
|
|
||||||
|
|
||||||
### Model selection and importation
|
|
||||||
|
|
||||||
The CLI allows you to add new models on the fly, as well as to switch
|
|
||||||
among them rapidly without leaving the script. There are several
|
|
||||||
different model formats, each described in the [Model Installation
|
|
||||||
Guide](../installation/050_INSTALLING_MODELS.md).
|
|
||||||
|
|
||||||
#### `!models`
|
|
||||||
|
|
||||||
This prints out a list of the models defined in `config/models.yaml'. The active
|
|
||||||
model is bold-faced
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
inpainting-1.5 not loaded Stable Diffusion inpainting model
|
|
||||||
<b>stable-diffusion-1.5 active Stable Diffusion v1.5</b>
|
|
||||||
waifu-diffusion not loaded Waifu Diffusion v1.4
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
#### `!switch <model>`
|
|
||||||
|
|
||||||
This quickly switches from one model to another without leaving the CLI script.
|
|
||||||
`invoke.py` uses a memory caching system; once a model has been loaded,
|
|
||||||
switching back and forth is quick. The following example shows this in action.
|
|
||||||
Note how the second column of the `!models` table changes to `cached` after a
|
|
||||||
model is first loaded, and that the long initialization step is not needed when
|
|
||||||
loading a cached model.
|
|
||||||
|
|
||||||
#### `!import_model <hugging_face_repo_ID>`
|
|
||||||
|
|
||||||
This imports and installs a `diffusers`-style model that is stored on
|
|
||||||
the [HuggingFace Web Site](https://huggingface.co). You can look up
|
|
||||||
any [Stable Diffusion diffusers
|
|
||||||
model](https://huggingface.co/models?library=diffusers) and install it
|
|
||||||
with a command like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
!import_model prompthero/openjourney
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `!import_model <path/to/diffusers/directory>`
|
|
||||||
|
|
||||||
If you have a copy of a `diffusers`-style model saved to disk, you can
|
|
||||||
import it by passing the path to model's top-level directory.
|
|
||||||
|
|
||||||
#### `!import_model <url>`
|
|
||||||
|
|
||||||
For a `.ckpt` or `.safetensors` file, if you have a direct download
|
|
||||||
URL for the file, you can provide it to `!import_model` and the file
|
|
||||||
will be downloaded and installed for you.
|
|
||||||
|
|
||||||
#### `!import_model <path/to/model/weights.ckpt>`
|
|
||||||
|
|
||||||
This command imports a new model weights file into InvokeAI, makes it available
|
|
||||||
for image generation within the script, and writes out the configuration for the
|
|
||||||
model into `config/models.yaml` for use in subsequent sessions.
|
|
||||||
|
|
||||||
Provide `!import_model` with the path to a weights file ending in `.ckpt`. If
|
|
||||||
you type a partial path and press tab, the CLI will autocomplete. Although it
|
|
||||||
will also autocomplete to `.vae` files, these are not currenty supported (but
|
|
||||||
will be soon).
|
|
||||||
|
|
||||||
When you hit return, the CLI will prompt you to fill in additional information
|
|
||||||
about the model, including the short name you wish to use for it with the
|
|
||||||
`!switch` command, a brief description of the model, the default image width and
|
|
||||||
height to use with this model, and the model's configuration file. The latter
|
|
||||||
three fields are automatically filled with reasonable defaults. In the example
|
|
||||||
below, the bold-faced text shows what the user typed in with the exception of
|
|
||||||
the width, height and configuration file paths, which were filled in
|
|
||||||
automatically.
|
|
||||||
|
|
||||||
#### `!import_model <path/to/directory_of_models>`
|
|
||||||
|
|
||||||
If you provide the path of a directory that contains one or more
|
|
||||||
`.ckpt` or `.safetensors` files, the CLI will scan the directory and
|
|
||||||
interactively offer to import the models it finds there. Also see the
|
|
||||||
`--autoconvert` command-line option.
|
|
||||||
|
|
||||||
#### `!edit_model <name_of_model>`
|
|
||||||
|
|
||||||
The `!edit_model` command can be used to modify a model that is already defined
|
|
||||||
in `config/models.yaml`. Call it with the short name of the model you wish to
|
|
||||||
modify, and it will allow you to modify the model's `description`, `weights` and
|
|
||||||
other fields.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
invoke> <b>!edit_model waifu-diffusion</b>
|
|
||||||
>> Editing model waifu-diffusion from configuration file ./configs/models.yaml
|
|
||||||
description: <b>Waifu diffusion v1.4beta</b>
|
|
||||||
weights: models/ldm/stable-diffusion-v1/<b>model-epoch10-float16.ckpt</b>
|
|
||||||
config: configs/stable-diffusion/v1-inference.yaml
|
|
||||||
width: 512
|
|
||||||
height: 512
|
|
||||||
|
|
||||||
>> New configuration:
|
|
||||||
waifu-diffusion:
|
|
||||||
config: configs/stable-diffusion/v1-inference.yaml
|
|
||||||
description: Waifu diffusion v1.4beta
|
|
||||||
weights: models/ldm/stable-diffusion-v1/model-epoch10-float16.ckpt
|
|
||||||
height: 512
|
|
||||||
width: 512
|
|
||||||
|
|
||||||
OK to import [n]? y
|
|
||||||
>> Caching model stable-diffusion-1.4 in system RAM
|
|
||||||
>> Loading waifu-diffusion from models/ldm/stable-diffusion-v1/model-epoch10-float16.ckpt
|
|
||||||
...
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
### History processing
|
|
||||||
|
|
||||||
The CLI provides a series of convenient commands for reviewing previous actions,
|
|
||||||
retrieving them, modifying them, and re-running them.
|
|
||||||
|
|
||||||
#### `!history`
|
|
||||||
|
|
||||||
The invoke script keeps track of all the commands you issue during a session,
|
|
||||||
allowing you to re-run them. On Mac and Linux systems, it also writes the
|
|
||||||
command-line history out to disk, giving you access to the most recent 1000
|
|
||||||
commands issued.
|
|
||||||
|
|
||||||
The `!history` command will return a numbered list of all the commands issued
|
|
||||||
during the session (Windows), or the most recent 1000 commands (Mac|Linux). You
|
|
||||||
can then repeat a command by using the command `!NNN`, where "NNN" is the
|
|
||||||
history line number. For example:
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !history
|
|
||||||
...
|
|
||||||
[14] happy woman sitting under tree wearing broad hat and flowing garment
|
|
||||||
[15] beautiful woman sitting under tree wearing broad hat and flowing garment
|
|
||||||
[18] beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6
|
|
||||||
[20] watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
|
||||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
|
||||||
...
|
|
||||||
invoke> !20
|
|
||||||
invoke> watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
|
||||||
```
|
|
||||||
|
|
||||||
####`!fetch`
|
|
||||||
|
|
||||||
This command retrieves the generation parameters from a previously generated
|
|
||||||
image and either loads them into the command line (Linux|Mac), or prints them
|
|
||||||
out in a comment for copy-and-paste (Windows). You may provide either the name
|
|
||||||
of a file in the current output directory, or a full file path. Specify path to
|
|
||||||
a folder with image png files, and wildcard \*.png to retrieve the dream command
|
|
||||||
used to generate the images, and save them to a file commands.txt for further
|
|
||||||
processing.
|
|
||||||
|
|
||||||
!!! example "load the generation command for a single png file"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fetch 0000015.8929913.png
|
|
||||||
# the script returns the next line, ready for editing and running:
|
|
||||||
invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! example "fetch the generation commands from a batch of files and store them into `selected.txt`"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fetch outputs\selected-imgs\*.png selected.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `!replay`
|
|
||||||
|
|
||||||
This command replays a text file generated by !fetch or created manually
|
|
||||||
|
|
||||||
!!! example
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !replay outputs\selected-imgs\selected.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
These commands may behave unexpectedly if given a PNG file that was
|
|
||||||
not generated by InvokeAI.
|
|
||||||
|
|
||||||
#### `!search <search string>`
|
|
||||||
|
|
||||||
This is similar to !history but it only returns lines that contain
|
|
||||||
`search string`. For example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !search surreal
|
|
||||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `!clear`
|
|
||||||
|
|
||||||
This clears the search history from memory and disk. Be advised that this
|
|
||||||
operation is irreversible and does not issue any warnings!
|
|
||||||
|
|
||||||
## Command-line editing and completion
|
|
||||||
|
|
||||||
The command-line offers convenient history tracking, editing, and command
|
|
||||||
completion.
|
|
||||||
|
|
||||||
- To scroll through previous commands and potentially edit/reuse them, use the
|
|
||||||
++up++ and ++down++ keys.
|
|
||||||
- To edit the current command, use the ++left++ and ++right++ keys to position
|
|
||||||
the cursor, and then ++backspace++, ++delete++ or insert characters.
|
|
||||||
- To move to the very beginning of the command, type ++ctrl+a++ (or
|
|
||||||
++command+a++ on the Mac)
|
|
||||||
- To move to the end of the command, type ++ctrl+e++.
|
|
||||||
- To cut a section of the command, position the cursor where you want to start
|
|
||||||
cutting and type ++ctrl+k++
|
|
||||||
- To paste a cut section back in, position the cursor where you want to paste,
|
|
||||||
and type ++ctrl+y++
|
|
||||||
|
|
||||||
Windows users can get similar, but more limited, functionality if they launch
|
|
||||||
`invoke.py` with the `winpty` program and have the `pyreadline3` library
|
|
||||||
installed:
|
|
||||||
|
|
||||||
```batch
|
|
||||||
> winpty python scripts\invoke.py
|
|
||||||
```
|
|
||||||
|
|
||||||
On the Mac and Linux platforms, when you exit invoke.py, the last 1000 lines of
|
|
||||||
your command-line history will be saved. When you restart `invoke.py`, you can
|
|
||||||
access the saved history using the ++up++ key.
|
|
||||||
|
|
||||||
In addition, limited command-line completion is installed. In various contexts,
|
|
||||||
you can start typing your command and press ++tab++. A list of potential
|
|
||||||
completions will be presented to you. You can then type a little more, hit
|
|
||||||
++tab++ again, and eventually autocomplete what you want.
|
|
||||||
|
|
||||||
When specifying file paths using the one-letter shortcuts, the CLI will attempt
|
|
||||||
to complete pathnames for you. This is most handy for the `-I` (init image) and
|
|
||||||
`-M` (init mask) paths. To initiate completion, start the path with a slash
|
|
||||||
(`/`) or `./`. For example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> zebra with a mustache -I./test-pictures<TAB>
|
|
||||||
-I./test-pictures/Lincoln-and-Parrot.png -I./test-pictures/zebra.jpg -I./test-pictures/madonna.png
|
|
||||||
-I./test-pictures/bad-sketch.png -I./test-pictures/man_with_eagle/
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then type ++z++, hit ++tab++ again, and it will autofill to `zebra.jpg`.
|
|
||||||
|
|
||||||
More text completion features (such as autocompleting seeds) are on their way.
|
|
@ -1,167 +0,0 @@
|
|||||||
---
|
|
||||||
title: Embiggen
|
|
||||||
---
|
|
||||||
|
|
||||||
# :material-loupe: Embiggen
|
|
||||||
|
|
||||||
**upscale your images on limited memory machines**
|
|
||||||
|
|
||||||
GFPGAN and Real-ESRGAN are both memory intensive. In order to avoid
|
|
||||||
crashes and memory overloads during the Stable Diffusion process,
|
|
||||||
these effects are applied after Stable Diffusion has completed its
|
|
||||||
work.
|
|
||||||
|
|
||||||
In single image generations, you will see the output right away but
|
|
||||||
when you are using multiple iterations, the images will first be
|
|
||||||
generated and then upscaled and face restored after that process is
|
|
||||||
complete. While the image generation is taking place, you will still
|
|
||||||
be able to preview the base images.
|
|
||||||
|
|
||||||
If you wish to stop during the image generation but want to upscale or
|
|
||||||
face restore a particular generated image, pass it again with the same
|
|
||||||
prompt and generated seed along with the `-U` and `-G` prompt
|
|
||||||
arguments to perform those actions.
|
|
||||||
|
|
||||||
## Embiggen
|
|
||||||
|
|
||||||
If you wanted to be able to do more (pixels) without running out of VRAM,
|
|
||||||
or you want to upscale with details that couldn't possibly appear
|
|
||||||
without the context of a prompt, this is the feature to try out.
|
|
||||||
|
|
||||||
Embiggen automates the process of taking an init image, upscaling it,
|
|
||||||
cutting it into smaller tiles that slightly overlap, running all the
|
|
||||||
tiles through img2img to refine details with respect to the prompt,
|
|
||||||
and "stitching" the tiles back together into a cohesive image.
|
|
||||||
|
|
||||||
It automatically computes how many tiles are needed, and so it can be fed
|
|
||||||
*ANY* size init image and perform Img2Img on it (though it will be run only
|
|
||||||
one tile at a time, which can cause problems, see the Note at the end).
|
|
||||||
|
|
||||||
If you're familiar with "GoBig" (ala [progrock-stable](https://github.com/lowfuel/progrock-stable))
|
|
||||||
it's similar to that, except it can work up to an arbitrarily large size
|
|
||||||
(instead of just 2x), with tile overlaps configurable as a ratio, and
|
|
||||||
has extra logic to re-run any number of the tile sub-sections of the image
|
|
||||||
if for example a small part of a huge run got messed up.
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
`-embiggen <scaling_factor> <esrgan_strength> <overlap_ratio OR overlap_pixels>`
|
|
||||||
|
|
||||||
Takes a scaling factor relative to the size of the `--init_img` (`-I`), followed by
|
|
||||||
ESRGAN upscaling strength (0 - 1.0), followed by minimum amount of overlap
|
|
||||||
between tiles as a decimal ratio (0 - 1.0) *OR* a number of pixels.
|
|
||||||
|
|
||||||
The scaling factor is how much larger than the `--init_img` the output
|
|
||||||
should be, and will multiply both x and y axis, so an image that is a
|
|
||||||
scaling factor of 3.0 has 3*3= 9 times as many pixels, and will take
|
|
||||||
(at least) 9 times as long (see overlap for why it might be
|
|
||||||
longer). If the `--init_img` is already the right size `-embiggen 1`,
|
|
||||||
and it can also be less than one if the init_img is too big.
|
|
||||||
|
|
||||||
Esrgan_strength defaults to 0.75, and the overlap_ratio defaults to
|
|
||||||
0.25, both are optional.
|
|
||||||
|
|
||||||
Unlike Img2Img, the `--width` (`-W`) and `--height` (`-H`) arguments
|
|
||||||
do not control the size of the image as a whole, but the size of the
|
|
||||||
tiles used to Embiggen the image.
|
|
||||||
|
|
||||||
ESRGAN is used to upscale the `--init_img` prior to cutting it into
|
|
||||||
tiles/pieces to run through img2img and then stitch back
|
|
||||||
together. Embiggen can be run without ESRGAN; just set the strength to
|
|
||||||
zero (e.g. `-embiggen 1.75 0`). The output of Embiggen can also be
|
|
||||||
upscaled after it's finished (`-U`).
|
|
||||||
|
|
||||||
The overlap is the minimum that tiles will overlap with adjacent
|
|
||||||
tiles, specified as either a ratio or a number of pixels. How much the
|
|
||||||
tiles overlap determines the likelihood the tiling will be noticable,
|
|
||||||
really small overlaps (e.g. a couple of pixels) may produce noticeable
|
|
||||||
grid-like fuzzy distortions in the final stitched image. Though, as
|
|
||||||
the overlapping space doesn't contribute to making the image bigger,
|
|
||||||
and the larger the overlap the more tiles (and the more time) it will
|
|
||||||
take to finish.
|
|
||||||
|
|
||||||
Because the overlapping parts of tiles don't "contribute" to
|
|
||||||
increasing size, every tile after the first in a row or column
|
|
||||||
effectively only covers an extra `1 - overlap_ratio` on each axis. If
|
|
||||||
the input/`--init_img` is same size as a tile, the ideal (for time)
|
|
||||||
scaling factors with the default overlap (0.25) are 1.75, 2.5, 3.25,
|
|
||||||
4.0, etc.
|
|
||||||
|
|
||||||
`-embiggen_tiles <spaced list of tiles>`
|
|
||||||
|
|
||||||
An advanced usage useful if you only want to alter parts of the image
|
|
||||||
while running Embiggen. It takes a list of tiles by number to run and
|
|
||||||
replace onto the initial image e.g. `1 3 5`. It's useful for either
|
|
||||||
fixing problem spots from a previous Embiggen run, or selectively
|
|
||||||
altering the prompt for sections of an image - for creative or
|
|
||||||
coherency reasons.
|
|
||||||
|
|
||||||
Tiles are numbered starting with one, and left-to-right,
|
|
||||||
top-to-bottom. So, if you are generating a 3x3 tiled image, the
|
|
||||||
middle row would be `4 5 6`.
|
|
||||||
|
|
||||||
`-embiggen_strength <strength>`
|
|
||||||
|
|
||||||
Another advanced option if you want to experiment with the strength parameter
|
|
||||||
that embiggen uses when it calls Img2Img. Values range from 0.0 to 1.0
|
|
||||||
and lower values preserve more of the character of the initial image.
|
|
||||||
Values that are too high will result in a completely different end image,
|
|
||||||
while values that are too low will result in an image not dissimilar to one
|
|
||||||
you would get with ESRGAN upscaling alone. The default value is 0.4.
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
Running Embiggen with 512x512 tiles on an existing image, scaling up by a factor of 2.5x;
|
|
||||||
and doing the same again (default ESRGAN strength is 0.75, default overlap between tiles is 0.25):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5
|
|
||||||
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25
|
|
||||||
```
|
|
||||||
|
|
||||||
If your starting image was also 512x512 this should have taken 9 tiles.
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
If there weren't enough clouds in the sky of that forest you just made
|
|
||||||
(and that image is about 1280 pixels (512*2.5) wide A.K.A. three
|
|
||||||
512x512 tiles with 0.25 overlaps wide) we can replace that top row of
|
|
||||||
tiles:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3
|
|
||||||
```
|
|
||||||
|
|
||||||
## Fixing Previously-Generated Images
|
|
||||||
|
|
||||||
It is easy to apply embiggen to any previously-generated file without having to
|
|
||||||
look up the original prompt and provide an initial image. Just use the
|
|
||||||
syntax `!fix path/to/file.png <embiggen>`. For example, you can rewrite the
|
|
||||||
previous command to look like this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3
|
|
||||||
```
|
|
||||||
|
|
||||||
A new file named `000002.seed.fixed.png` will be created in the output directory. Note that
|
|
||||||
the `!fix` command does not replace the original file, unlike the behavior at generate time.
|
|
||||||
You do not need to provide the prompt, and `!fix` automatically selects a good strength for
|
|
||||||
embiggen-ing.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
Because the same prompt is used on all the tiled images, and the model
|
|
||||||
doesn't have the context of anything outside the tile being run - it
|
|
||||||
can end up creating repeated pattern (also called 'motifs') across all
|
|
||||||
the tiles based on that prompt. The best way to combat this is
|
|
||||||
lowering the `--strength` (`-f`) to stay more true to the init image,
|
|
||||||
and increasing the number of steps so there is more compute-time to
|
|
||||||
create the detail. Anecdotally `--strength` 0.35-0.45 works pretty
|
|
||||||
well on most things. It may also work great in some examples even with
|
|
||||||
the `--strength` set high for patterns, landscapes, or subjects that
|
|
||||||
are more abstract. Because this is (relatively) fast, you can also
|
|
||||||
preserve the best parts from each.
|
|
||||||
|
|
||||||
Author: [Travco](https://github.com/travco)
|
|
@ -1,310 +0,0 @@
|
|||||||
---
|
|
||||||
title: Inpainting
|
|
||||||
---
|
|
||||||
|
|
||||||
# :octicons-paintbrush-16: Inpainting
|
|
||||||
|
|
||||||
## **Creating Transparent Regions for Inpainting**
|
|
||||||
|
|
||||||
Inpainting is really cool. To do it, you start with an initial image and use a
|
|
||||||
photoeditor to make one or more regions transparent (i.e. they have a "hole" in
|
|
||||||
them). You then provide the path to this image at the dream> command line using
|
|
||||||
the `-I` switch. Stable Diffusion will only paint within the transparent region.
|
|
||||||
|
|
||||||
There's a catch. In the current implementation, you have to prepare the initial
|
|
||||||
image correctly so that the underlying colors are preserved under the
|
|
||||||
transparent area. Many imaging editing applications will by default erase the
|
|
||||||
color information under the transparent pixels and replace them with white or
|
|
||||||
black, which will lead to suboptimal inpainting. It often helps to apply
|
|
||||||
incomplete transparency, such as any value between 1 and 99%
|
|
||||||
|
|
||||||
You also must take care to export the PNG file in such a way that the color
|
|
||||||
information is preserved. There is often an option in the export dialog that
|
|
||||||
lets you specify this.
|
|
||||||
|
|
||||||
If your photoeditor is erasing the underlying color information, `dream.py` will
|
|
||||||
give you a big fat warning. If you can't find a way to coax your photoeditor to
|
|
||||||
retain color values under transparent areas, then you can combine the `-I` and
|
|
||||||
`-M` switches to provide both the original unedited image and the masked
|
|
||||||
(partially transparent) image:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png
|
|
||||||
```
|
|
||||||
|
|
||||||
## **Masking using Text**
|
|
||||||
|
|
||||||
You can also create a mask using a text prompt to select the part of the image
|
|
||||||
you want to alter, using the [clipseg](https://github.com/timojl/clipseg)
|
|
||||||
algorithm. This works on any image, not just ones generated by InvokeAI.
|
|
||||||
|
|
||||||
The `--text_mask` (short form `-tm`) option takes two arguments. The first
|
|
||||||
argument is a text description of the part of the image you wish to mask (paint
|
|
||||||
over). If the text description contains a space, you must surround it with
|
|
||||||
quotation marks. The optional second argument is the minimum threshold for the
|
|
||||||
mask classifier's confidence score, described in more detail below.
|
|
||||||
|
|
||||||
To see how this works in practice, here's an image of a still life painting that
|
|
||||||
I got off the web.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![still life scaled](../assets/still-life-scaled.jpg)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
You can selectively mask out the orange and replace it with a baseball in this
|
|
||||||
way:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a baseball -I /path/to/still_life.png -tm orange
|
|
||||||
```
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![](../assets/still-life-inpainted.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
The clipseg classifier produces a confidence score for each region it
|
|
||||||
identifies. Generally regions that score above 0.5 are reliable, but if you are
|
|
||||||
getting too much or too little masking you can adjust the threshold down (to get
|
|
||||||
more mask), or up (to get less). In this example, by passing `-tm` a higher
|
|
||||||
value, we are insisting on a tigher mask. However, if you make it too high, the
|
|
||||||
orange may not be picked up at all!
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a baseball -I /path/to/breakfast.png -tm orange 0.6
|
|
||||||
```
|
|
||||||
|
|
||||||
The `!mask` command may be useful for debugging problems with the text2mask
|
|
||||||
feature. The syntax is `!mask /path/to/image.png -tm <text> <threshold>`
|
|
||||||
|
|
||||||
It will generate three files:
|
|
||||||
|
|
||||||
- The image with the selected area highlighted.
|
|
||||||
- it will be named XXXXX.<imagename>.<prompt>.selected.png
|
|
||||||
- The image with the un-selected area highlighted.
|
|
||||||
- it will be named XXXXX.<imagename>.<prompt>.deselected.png
|
|
||||||
- The image with the selected area converted into a black and white image
|
|
||||||
according to the threshold level
|
|
||||||
- it will be named XXXXX.<imagename>.<prompt>.masked.png
|
|
||||||
|
|
||||||
The `.masked.png` file can then be directly passed to the `invoke>` prompt in
|
|
||||||
the CLI via the `-M` argument. Do not attempt this with the `selected.png` or
|
|
||||||
`deselected.png` files, as they contain some transparency throughout the image
|
|
||||||
and will not produce the desired results.
|
|
||||||
|
|
||||||
Here is an example of how `!mask` works:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !mask ./test-pictures/curly.png -tm hair 0.5
|
|
||||||
>> generating masks from ./test-pictures/curly.png
|
|
||||||
>> Initializing clipseg model for text to mask inference
|
|
||||||
Outputs:
|
|
||||||
[941.1] outputs/img-samples/000019.curly.hair.deselected.png: !mask ./test-pictures/curly.png -tm hair 0.5
|
|
||||||
[941.2] outputs/img-samples/000019.curly.hair.selected.png: !mask ./test-pictures/curly.png -tm hair 0.5
|
|
||||||
[941.3] outputs/img-samples/000019.curly.hair.masked.png: !mask ./test-pictures/curly.png -tm hair 0.5
|
|
||||||
```
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly](../assets/outpainting/curly.png)
|
|
||||||
<figcaption>Original image "curly.png"</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly hair selected](../assets/inpainting/000019.curly.hair.selected.png)
|
|
||||||
<figcaption>000019.curly.hair.selected.png</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly hair deselected](../assets/inpainting/000019.curly.hair.deselected.png)
|
|
||||||
<figcaption>000019.curly.hair.deselected.png</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly hair masked](../assets/inpainting/000019.curly.hair.masked.png)
|
|
||||||
<figcaption>000019.curly.hair.masked.png</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
It looks like we selected the hair pretty well at the 0.5 threshold (which is
|
|
||||||
the default, so we didn't actually have to specify it), so let's have some fun:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> medusa with cobras -I ./test-pictures/curly.png -M 000019.curly.hair.masked.png -C20
|
|
||||||
>> loaded input image of size 512x512 from ./test-pictures/curly.png
|
|
||||||
...
|
|
||||||
Outputs:
|
|
||||||
[946] outputs/img-samples/000024.801380492.png: "medusa with cobras" -s 50 -S 801380492 -W 512 -H 512 -C 20.0 -I ./test-pictures/curly.png -A k_lms -f 0.75
|
|
||||||
```
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![](../assets/inpainting/000024.801380492.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
You can also skip the `!mask` creation step and just select the masked
|
|
||||||
|
|
||||||
region directly:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> medusa with cobras -I ./test-pictures/curly.png -tm hair -C20
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using the RunwayML inpainting model
|
|
||||||
|
|
||||||
The
|
|
||||||
[RunwayML Inpainting Model v1.5](https://huggingface.co/runwayml/stable-diffusion-inpainting)
|
|
||||||
is a specialized version of
|
|
||||||
[Stable Diffusion v1.5](https://huggingface.co/spaces/runwayml/stable-diffusion-v1-5)
|
|
||||||
that contains extra channels specifically designed to enhance inpainting and
|
|
||||||
outpainting. While it can do regular `txt2img` and `img2img`, it really shines
|
|
||||||
when filling in missing regions. It has an almost uncanny ability to blend the
|
|
||||||
new regions with existing ones in a semantically coherent way.
|
|
||||||
|
|
||||||
To install the inpainting model, follow the
|
|
||||||
[instructions](../installation/050_INSTALLING_MODELS.md) for installing a new model.
|
|
||||||
You may use either the CLI (`invoke.py` script) or directly edit the
|
|
||||||
`configs/models.yaml` configuration file to do this. The main thing to watch out
|
|
||||||
for is that the the model `config` option must be set up to use
|
|
||||||
`v1-inpainting-inference.yaml` rather than the `v1-inference.yaml` file that is
|
|
||||||
used by Stable Diffusion 1.4 and 1.5.
|
|
||||||
|
|
||||||
After installation, your `models.yaml` should contain an entry that looks like
|
|
||||||
this one:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
inpainting-1.5:
|
|
||||||
weights: models/ldm/stable-diffusion-v1/sd-v1-5-inpainting.ckpt
|
|
||||||
description: SD inpainting v1.5
|
|
||||||
config: configs/stable-diffusion/v1-inpainting-inference.yaml
|
|
||||||
vae: models/ldm/stable-diffusion-v1/vae-ft-mse-840000-ema-pruned.ckpt
|
|
||||||
width: 512
|
|
||||||
height: 512
|
|
||||||
```
|
|
||||||
|
|
||||||
As shown in the example, you may include a VAE fine-tuning weights file as well.
|
|
||||||
This is strongly recommended.
|
|
||||||
|
|
||||||
To use the custom inpainting model, launch `invoke.py` with the argument
|
|
||||||
`--model inpainting-1.5` or alternatively from within the script use the
|
|
||||||
`!switch inpainting-1.5` command to load and switch to the inpainting model.
|
|
||||||
|
|
||||||
You can now do inpainting and outpainting exactly as described above, but there
|
|
||||||
will (likely) be a noticeable improvement in coherence. Txt2img and Img2img will
|
|
||||||
work as well.
|
|
||||||
|
|
||||||
There are a few caveats to be aware of:
|
|
||||||
|
|
||||||
1. The inpainting model is larger than the standard model, and will use nearly 4
|
|
||||||
GB of GPU VRAM. This makes it unlikely to run on a 4 GB graphics card.
|
|
||||||
|
|
||||||
2. When operating in Img2img mode, the inpainting model is much less steerable
|
|
||||||
than the standard model. It is great for making small changes, such as
|
|
||||||
changing the pattern of a fabric, or slightly changing a subject's expression
|
|
||||||
or hair, but the model will resist making the dramatic alterations that the
|
|
||||||
standard model lets you do.
|
|
||||||
|
|
||||||
3. While the `--hires` option works fine with the inpainting model, some special
|
|
||||||
features, such as `--embiggen` are disabled.
|
|
||||||
|
|
||||||
4. Prompt weighting (`banana++ sushi`) and merging work well with the inpainting
|
|
||||||
model, but prompt swapping
|
|
||||||
(`a ("fluffy cat").swap("smiling dog") eating a hotdog`) will not have any
|
|
||||||
effect due to the way the model is set up. You may use text masking (with
|
|
||||||
`-tm thing-to-mask`) as an effective replacement.
|
|
||||||
|
|
||||||
5. The model tends to oversharpen image if you use high step or CFG values. If
|
|
||||||
you need to do large steps, use the standard model.
|
|
||||||
|
|
||||||
6. The `--strength` (`-f`) option has no effect on the inpainting model due to
|
|
||||||
its fundamental differences with the standard model. It will always take the
|
|
||||||
full number of steps you specify.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
Here are some troubleshooting tips for inpainting and outpainting.
|
|
||||||
|
|
||||||
## Inpainting is not changing the masked region enough!
|
|
||||||
|
|
||||||
One of the things to understand about how inpainting works is that it is
|
|
||||||
equivalent to running img2img on just the masked (transparent) area. img2img
|
|
||||||
builds on top of the existing image data, and therefore will attempt to preserve
|
|
||||||
colors, shapes and textures to the best of its ability. Unfortunately this means
|
|
||||||
that if you want to make a dramatic change in the inpainted region, for example
|
|
||||||
replacing a red wall with a blue one, the algorithm will fight you.
|
|
||||||
|
|
||||||
You have a couple of options. The first is to increase the values of the
|
|
||||||
requested steps (`-sXXX`), strength (`-f0.XX`), and/or condition-free guidance
|
|
||||||
(`-CXX.X`). If this is not working for you, a more extreme step is to provide
|
|
||||||
the `--inpaint_replace 0.X` (`-r0.X`) option. This value ranges from 0.0 to 1.0.
|
|
||||||
The higher it is the less attention the algorithm will pay to the data
|
|
||||||
underneath the masked region. At high values this will enable you to replace
|
|
||||||
colored regions entirely, but beware that the masked region mayl not blend in
|
|
||||||
with the surrounding unmasked regions as well.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recipe for GIMP
|
|
||||||
|
|
||||||
[GIMP](https://www.gimp.org/) is a popular Linux photoediting tool.
|
|
||||||
|
|
||||||
1. Open image in GIMP.
|
|
||||||
2. Layer->Transparency->Add Alpha Channel
|
|
||||||
3. Use lasso tool to select region to mask
|
|
||||||
4. Choose Select -> Float to create a floating selection
|
|
||||||
5. Open the Layers toolbar (^L) and select "Floating Selection"
|
|
||||||
6. Set opacity to a value between 0% and 99%
|
|
||||||
7. Export as PNG
|
|
||||||
8. In the export dialogue, Make sure the "Save colour values from transparent
|
|
||||||
pixels" checkbox is selected.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recipe for Adobe Photoshop
|
|
||||||
|
|
||||||
1. Open image in Photoshop
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step1](../assets/step1.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
2. Use any of the selection tools (Marquee, Lasso, or Wand) to select the area
|
|
||||||
you desire to inpaint.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step2](../assets/step2.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
3. Because we'll be applying a mask over the area we want to preserve, you
|
|
||||||
should now select the inverse by using the ++shift+ctrl+i++ shortcut, or
|
|
||||||
right clicking and using the "Select Inverse" option.
|
|
||||||
|
|
||||||
4. You'll now create a mask by selecting the image layer, and Masking the
|
|
||||||
selection. Make sure that you don't delete any of the underlying image, or
|
|
||||||
your inpainting results will be dramatically impacted.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step4](../assets/step4.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
5. Make sure to hide any background layers that are present. You should see the
|
|
||||||
mask applied to your image layer, and the image on your canvas should display
|
|
||||||
the checkered background.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step5](../assets/step5.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
6. Save the image as a transparent PNG by using `File`-->`Save a Copy` from the
|
|
||||||
menu bar, or by using the keyboard shortcut ++alt+ctrl+s++
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step6](../assets/step6.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
7. After following the inpainting instructions above (either through the CLI or
|
|
||||||
the Web UI), marvel at your newfound ability to selectively invoke. Lookin'
|
|
||||||
good!
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![step7](../assets/step7.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
8. In the export dialogue, Make sure the "Save colour values from transparent
|
|
||||||
pixels" checkbox is selected.
|
|
@ -1,171 +0,0 @@
|
|||||||
---
|
|
||||||
title: Outpainting
|
|
||||||
---
|
|
||||||
|
|
||||||
# :octicons-paintbrush-16: Outpainting
|
|
||||||
|
|
||||||
## Outpainting and outcropping
|
|
||||||
|
|
||||||
Outpainting is a process by which the AI generates parts of the image that are
|
|
||||||
outside its original frame. It can be used to fix up images in which the subject
|
|
||||||
is off center, or when some detail (often the top of someone's head!) is cut
|
|
||||||
off.
|
|
||||||
|
|
||||||
InvokeAI supports two versions of outpainting, one called "outpaint" and the
|
|
||||||
other "outcrop." They work slightly differently and each has its advantages and
|
|
||||||
drawbacks.
|
|
||||||
|
|
||||||
### Outpainting
|
|
||||||
|
|
||||||
Outpainting is the same as inpainting, except that the painting occurs in the
|
|
||||||
regions outside of the original image. To outpaint using the `invoke.py` command
|
|
||||||
line script, prepare an image in which the borders to be extended are pure
|
|
||||||
black. Add an alpha channel (if there isn't one already), and make the borders
|
|
||||||
completely transparent and the interior completely opaque. If you wish to modify
|
|
||||||
the interior as well, you may create transparent holes in the transparency
|
|
||||||
layer, which `img2img` will paint into as usual.
|
|
||||||
|
|
||||||
Pass the image as the argument to the `-I` switch as you would for regular
|
|
||||||
inpainting:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> a stream by a river -I /path/to/transparent_img.png
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll likely be delighted by the results.
|
|
||||||
|
|
||||||
### Tips
|
|
||||||
|
|
||||||
1. Do not try to expand the image too much at once. Generally it is best to
|
|
||||||
expand the margins in 64-pixel increments. 128 pixels often works, but your
|
|
||||||
mileage may vary depending on the nature of the image you are trying to
|
|
||||||
outpaint into.
|
|
||||||
|
|
||||||
2. There are a series of switches that can be used to adjust how the inpainting
|
|
||||||
algorithm operates. In particular, you can use these to minimize the seam
|
|
||||||
that sometimes appears between the original image and the extended part.
|
|
||||||
These switches are:
|
|
||||||
|
|
||||||
| switch | default | description |
|
|
||||||
| -------------------------- | ------- | ---------------------------------------------------------------------- |
|
|
||||||
| `--seam_size SEAM_SIZE ` | `0` | Size of the mask around the seam between original and outpainted image |
|
|
||||||
| `--seam_blur SEAM_BLUR` | `0` | The amount to blur the seam inwards |
|
|
||||||
| `--seam_strength STRENGTH` | `0.7` | The img2img strength to use when filling the seam |
|
|
||||||
| `--seam_steps SEAM_STEPS` | `10` | The number of steps to use to fill the seam. |
|
|
||||||
| `--tile_size TILE_SIZE` | `32` | The tile size to use for filling outpaint areas |
|
|
||||||
|
|
||||||
### Outcrop
|
|
||||||
|
|
||||||
The `outcrop` extension gives you a convenient `!fix` postprocessing command
|
|
||||||
that allows you to extend a previously-generated image in 64 pixel increments in
|
|
||||||
any direction. You can apply the module to any image previously-generated by
|
|
||||||
InvokeAI. Note that it works with arbitrary PNG photographs, but not currently
|
|
||||||
with JPG or other formats. Outcropping is particularly effective when combined
|
|
||||||
with the
|
|
||||||
[runwayML custom inpainting model](INPAINTING.md#using-the-runwayml-inpainting-model).
|
|
||||||
|
|
||||||
Consider this image:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly_woman](../assets/outpainting/curly.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
Pretty nice, but it's annoying that the top of her head is cut off. She's also a
|
|
||||||
bit off center. Let's fix that!
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix images/curly.png --outcrop top 128 right 64 bottom 64
|
|
||||||
```
|
|
||||||
|
|
||||||
This is saying to apply the `outcrop` extension by extending the top of the
|
|
||||||
image by 128 pixels, and the right and bottom of the image by 64 pixels. You can
|
|
||||||
use any combination of top|left|right|bottom, and specify any number of pixels
|
|
||||||
to extend. You can also abbreviate `--outcrop` to `-c`.
|
|
||||||
|
|
||||||
The result looks like this:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly_woman_outcrop](../assets/outpainting/curly-outcrop-2.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
The new image is larger than the original (576x704) because 64 pixels were added
|
|
||||||
to the top and right sides. You will need enough VRAM to process an image of
|
|
||||||
this size.
|
|
||||||
|
|
||||||
#### Outcropping non-InvokeAI images
|
|
||||||
|
|
||||||
You can outcrop an arbitrary image that was not generated by InvokeAI,
|
|
||||||
but your results will vary. The `inpainting-1.5` model is highly
|
|
||||||
recommended, but if not feasible, then you may be able to improve the
|
|
||||||
output by conditioning the outcropping with a text prompt that
|
|
||||||
describes the scene using the `--new_prompt` argument:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix images/vacation.png --outcrop top 128 --new_prompt "family vacation"
|
|
||||||
```
|
|
||||||
|
|
||||||
You may also provide a different seed for outcropping to use by passing
|
|
||||||
`-S<seed>`. A negative seed will generate a new random seed.
|
|
||||||
|
|
||||||
A number of caveats:
|
|
||||||
|
|
||||||
1. Although you can specify any pixel values, they will be rounded up to the
|
|
||||||
nearest multiple of 64. Smaller values are better. Larger extensions are more
|
|
||||||
likely to generate artefacts. However, if you wish you can run the !fix
|
|
||||||
command repeatedly to cautiously expand the image.
|
|
||||||
|
|
||||||
2. The extension is stochastic, meaning that each time you run it you'll get a
|
|
||||||
slightly different result. You can run it repeatedly until you get an image
|
|
||||||
you like. Unfortunately `!fix` does not currently respect the `-n`
|
|
||||||
(`--iterations`) argument.
|
|
||||||
|
|
||||||
3. Your results will be _much_ better if you use the `inpaint-1.5` model
|
|
||||||
released by runwayML and installed by default by `invokeai-configure`.
|
|
||||||
This model was trained specifically to harmoniously fill in image gaps. The
|
|
||||||
standard model will work as well, but you may notice color discontinuities at
|
|
||||||
the border.
|
|
||||||
|
|
||||||
4. When using the `inpaint-1.5` model, you may notice subtle changes to the area
|
|
||||||
outside the masked region. This is because the model performs an
|
|
||||||
encoding/decoding on the image as a whole. This does not occur with the
|
|
||||||
standard model.
|
|
||||||
|
|
||||||
## Outpaint
|
|
||||||
|
|
||||||
The `outpaint` extension does the same thing, but with subtle differences.
|
|
||||||
Starting with the same image, here is how we would add an additional 64 pixels
|
|
||||||
to the top of the image:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> !fix images/curly.png --out_direction top 64
|
|
||||||
```
|
|
||||||
|
|
||||||
(you can abbreviate `--out_direction` as `-D`.
|
|
||||||
|
|
||||||
The result is shown here:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![curly_woman_outpaint](../assets/outpainting/curly-outpaint.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
Although the effect is similar, there are significant differences from
|
|
||||||
outcropping:
|
|
||||||
|
|
||||||
- You can only specify one direction to extend at a time.
|
|
||||||
- The image is **not** resized. Instead, the image is shifted by the specified
|
|
||||||
number of pixels. If you look carefully, you'll see that less of the lady's
|
|
||||||
torso is visible in the image.
|
|
||||||
- Because the image dimensions remain the same, there's no rounding to multiples
|
|
||||||
of 64.
|
|
||||||
- Attempting to outpaint larger areas will frequently give rise to ugly ghosting
|
|
||||||
effects.
|
|
||||||
- For best results, try increasing the step number.
|
|
||||||
- If you don't specify a pixel value in `-D`, it will default to half of the
|
|
||||||
whole image, which is likely not what you want.
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
Neither `outpaint` nor `outcrop` are perfect, but we continue to tune
|
|
||||||
and improve them. If one doesn't work, try the other. You may also
|
|
||||||
wish to experiment with other `img2img` arguments, such as `-C`, `-f`
|
|
||||||
and `-s`.
|
|
@ -1,19 +0,0 @@
|
|||||||
# Translation
|
|
||||||
|
|
||||||
InvokeAI uses [Weblate](https://weblate.org) for translation. Weblate is a FOSS project providing a scalable translation service. Weblate automates the tedious parts of managing translation of a growing project, and the service is generously provided at no cost to FOSS projects like InvokeAI.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
If you'd like to contribute by adding or updating a translation, please visit our [Weblate project](https://hosted.weblate.org/engage/invokeai/). You'll need to sign in with your GitHub account (a number of other accounts are supported, including Google).
|
|
||||||
|
|
||||||
Once signed in, select a language and then the Web UI component. From here you can Browse and Translate strings from English to your chosen language. Zen mode offers a simpler translation experience.
|
|
||||||
|
|
||||||
Your changes will be attributed to you in the automated PR process; you don't need to do anything else.
|
|
||||||
|
|
||||||
## Help & Questions
|
|
||||||
|
|
||||||
Please check Weblate's [documentation](https://docs.weblate.org/en/latest/index.html) or ping @psychedelicious or @blessedcoolant on Discord if you have any questions.
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
|
|
||||||
Thanks to the InvokeAI community for their efforts to translate the project!
|
|
@ -1,131 +0,0 @@
|
|||||||
---
|
|
||||||
title: Variations
|
|
||||||
---
|
|
||||||
|
|
||||||
# :material-tune-variant: Variations
|
|
||||||
|
|
||||||
## Intro
|
|
||||||
|
|
||||||
InvokeAI's support for variations enables you to do the following:
|
|
||||||
|
|
||||||
1. Generate a series of systematic variations of an image, given a prompt. The
|
|
||||||
amount of variation from one image to the next can be controlled.
|
|
||||||
|
|
||||||
2. Given two or more variations that you like, you can combine them in a
|
|
||||||
weighted fashion.
|
|
||||||
|
|
||||||
!!! Information ""
|
|
||||||
|
|
||||||
This cheat sheet provides a quick guide for how this works in practice, using
|
|
||||||
variations to create the desired image of Xena, Warrior Princess.
|
|
||||||
|
|
||||||
## Step 1 -- Find a base image that you like
|
|
||||||
|
|
||||||
The prompt we will use throughout is:
|
|
||||||
|
|
||||||
`#!bash "lucy lawless as xena, warrior princess, character portrait, high resolution."`
|
|
||||||
|
|
||||||
This will be indicated as `#!bash "prompt"` in the examples below.
|
|
||||||
|
|
||||||
First we let SD create a series of images in the usual way, in this case
|
|
||||||
requesting six iterations.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![var1](../assets/variation_walkthru/000001.3357757885.png)
|
|
||||||
<figcaption> Seed 3357757885 looks nice </figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 2 - Generating Variations
|
|
||||||
|
|
||||||
Let's try to generate some variations on this image. We select the "*"
|
|
||||||
symbol in the line of icons above the image in order to fix the prompt
|
|
||||||
and seed. Then we open up the "Variations" section of the generation
|
|
||||||
panel and use the slider to set the variation amount to 0.2. The
|
|
||||||
higher this value, the more each generated image will differ from the
|
|
||||||
previous one.
|
|
||||||
|
|
||||||
Now we run the prompt a second time, requesting six iterations. You
|
|
||||||
will see six images that are thematically related to each other. Try
|
|
||||||
increasing and decreasing the variation amount and see what happens.
|
|
||||||
|
|
||||||
### **Variation Sub Seeding**
|
|
||||||
|
|
||||||
Note that the output for each image has a `-V` option giving the "variant
|
|
||||||
subseed" for that image, consisting of a seed followed by the variation amount
|
|
||||||
used to generate it.
|
|
||||||
|
|
||||||
This gives us a series of closely-related variations, including the two shown
|
|
||||||
here.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![var2](../assets/variation_walkthru/000002.3647897225.png)
|
|
||||||
<figcaption>subseed 3647897225</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![var3](../assets/variation_walkthru/000002.1614299449.png)
|
|
||||||
<figcaption>subseed 1614299449</figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
I like the expression on Xena's face in the first one (subseed 3647897225), and
|
|
||||||
the armor on her shoulder in the second one (subseed 1614299449). Can we combine
|
|
||||||
them to get the best of both worlds?
|
|
||||||
|
|
||||||
We combine the two variations using `-V` (`--with_variations`). Again, we must
|
|
||||||
provide the seed for the originally-chosen image in order for this to work.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1
|
|
||||||
Outputs:
|
|
||||||
./outputs/Xena/000003.1614299449.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1 -S3357757885
|
|
||||||
```
|
|
||||||
|
|
||||||
Here we are providing equal weights (0.1 and 0.1) for both the subseeds. The
|
|
||||||
resulting image is close, but not exactly what I wanted:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![var4](../assets/variation_walkthru/000003.1614299449.png)
|
|
||||||
<figcaption> subseed 1614299449 </figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
We could either try combining the images with different weights, or we can
|
|
||||||
generate more variations around the almost-but-not-quite image. We do the
|
|
||||||
latter, using both the `-V` (combining) and `-v` (variation strength) options.
|
|
||||||
Note that we use `-n6` to generate 6 variations:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6
|
|
||||||
Outputs:
|
|
||||||
./outputs/Xena/000004.3279757577.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3279757577:0.05 -S3357757885
|
|
||||||
./outputs/Xena/000004.2853129515.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2853129515:0.05 -S3357757885
|
|
||||||
./outputs/Xena/000004.3747154981.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3747154981:0.05 -S3357757885
|
|
||||||
./outputs/Xena/000004.2664260391.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2664260391:0.05 -S3357757885
|
|
||||||
./outputs/Xena/000004.1642517170.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,1642517170:0.05 -S3357757885
|
|
||||||
./outputs/Xena/000004.2183375608.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2183375608:0.05 -S3357757885
|
|
||||||
```
|
|
||||||
|
|
||||||
This produces six images, all slight variations on the combination of the chosen
|
|
||||||
two images. Here's the one I like best:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![var5](../assets/variation_walkthru/000004.3747154981.png)
|
|
||||||
<figcaption> subseed 3747154981 </figcaption>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
As you can see, this is a very powerful tool, which when combined with subprompt
|
|
||||||
weighting, gives you great control over the content and quality of your
|
|
||||||
generated images.
|
|
||||||
|
|
||||||
## Variations and Samplers
|
|
||||||
|
|
||||||
The sampler you choose has a strong effect on variation strength. Some
|
|
||||||
samplers, such as `k_euler_a` are very "creative" and produce significant
|
|
||||||
amounts of image-to-image variation even when the seed is fixed and the
|
|
||||||
`-v` argument is very low. Others are more deterministic. Feel free to
|
|
||||||
experiment until you find the combination that you like.
|
|
||||||
|
|
||||||
Also be aware of the [Perlin Noise](../features/OTHER.md#thresholding-and-perlin-noise-initialization-options)
|
|
||||||
feature, which provides another way of introducing variability into your
|
|
||||||
image generation requests.
|
|
@ -137,15 +137,7 @@ Most common algorithms are supported, like `md5`, `sha256`, and `sha512`. These
|
|||||||
|
|
||||||
#### Path Settings
|
#### Path Settings
|
||||||
|
|
||||||
These options set the paths of various directories and files used by
|
These options set the paths of various directories and files used by InvokeAI. Any user-defined paths should be absolute paths.
|
||||||
InvokeAI. Relative paths are interpreted relative to the root directory, so
|
|
||||||
if root is `/home/fred/invokeai` and the path is
|
|
||||||
`autoimport/main`, then the corresponding directory will be located at
|
|
||||||
`/home/fred/invokeai/autoimport/main`.
|
|
||||||
|
|
||||||
Note that the autoimport directory will be searched recursively,
|
|
||||||
allowing you to organize the models into folders and subfolders in any
|
|
||||||
way you wish.
|
|
||||||
|
|
||||||
#### Logging
|
#### Logging
|
||||||
|
|
||||||
|
@ -20,10 +20,7 @@ are applied to generate imagery. LoRAs may be supplied with a
|
|||||||
simply apply their effect without being triggered.
|
simply apply their effect without being triggered.
|
||||||
|
|
||||||
LoRAs are typically stored in .safetensors files, which are the most
|
LoRAs are typically stored in .safetensors files, which are the most
|
||||||
secure way to store and transmit these types of weights. You may
|
secure way to store and transmit these types of weights.
|
||||||
install any number of `.safetensors` LoRA files simply by copying them
|
|
||||||
into the `autoimport/lora` directory of the corresponding InvokeAI models
|
|
||||||
directory (usually `invokeai` in your home directory).
|
|
||||||
|
|
||||||
To use these when generating, open the LoRA menu item in the options
|
To use these when generating, open the LoRA menu item in the options
|
||||||
panel, select the LoRAs you want to apply and ensure that they have
|
panel, select the LoRAs you want to apply and ensure that they have
|
||||||
|
204
docs/help/FAQ.md
204
docs/help/FAQ.md
@ -1,43 +1,197 @@
|
|||||||
# FAQs
|
# FAQ
|
||||||
|
|
||||||
**Where do I get started? How can I install Invoke?**
|
!!! info "How to Reinstall"
|
||||||
|
|
||||||
- You can download the latest installers [here](https://github.com/invoke-ai/InvokeAI/releases) - Note that any releases marked as *pre-release* are in a beta state. You may experience some issues, but we appreciate your help testing those! For stable/reliable installations, please install the **[Latest Release](https://github.com/invoke-ai/InvokeAI/releases/latest)**
|
Many issues can be resolved by re-installing the application. You won't lose any data by re-installing. We suggest downloading the [latest release](https://github.com/invoke-ai/InvokeAI/releases/latest) and using it to re-install the application. Consult the [installer guide](../installation/010_INSTALL_AUTOMATED.md) for more information.
|
||||||
|
|
||||||
**How can I download models? Can I use models I already have downloaded?**
|
When you run the installer, you'll have an option to select the version to install. If you aren't ready to upgrade, you choose the current version to fix a broken install.
|
||||||
|
|
||||||
- Models can be downloaded through the model manager, or through option [4] in the invoke.bat/invoke.sh launcher script. To download a model through the Model Manager, use the HuggingFace Repo ID by pressing the “Copy” button next to the repository name. Alternatively, to download a model from CivitAi, use the download link in the Model Manager.
|
If the troubleshooting steps on this page don't get you up and running, please either [create an issue] or hop on [discord] for help.
|
||||||
- Models that are already downloaded can be used by creating a symlink to the model location in the `autoimport` folder or by using the Model Manger’s “Scan for Models” function.
|
|
||||||
|
|
||||||
**My images are taking a long time to generate. How can I speed up generation?**
|
## How to Install
|
||||||
|
|
||||||
- A common solution is to reduce the size of your RAM & VRAM cache to 0.25. This ensures your system has enough memory to generate images.
|
You can download the latest installers [here](https://github.com/invoke-ai/InvokeAI/releases).
|
||||||
- Additionally, check the [hardware requirements](https://invoke-ai.github.io/InvokeAI/#hardware-requirements) to ensure that your system is capable of generating images.
|
|
||||||
- Lastly, double check your generations are happening on your GPU (if you have one). InvokeAI will log what is being used for generation upon startup.
|
|
||||||
|
|
||||||
**I’ve installed Python on Windows but the installer says it can’t find it?**
|
Note that any releases marked as _pre-release_ are in a beta state. You may experience some issues, but we appreciate your help testing those! For stable/reliable installations, please install the [latest release].
|
||||||
|
|
||||||
- Then ensure that you checked **'Add python.exe to PATH'** when installing Python. This can be found at the bottom of the Python Installer window. If you already have Python installed, this can be done with the modify / repair feature of the installer.
|
## Downloading models and using existing models
|
||||||
|
|
||||||
**I’ve installed everything successfully but I still get an error about Triton when starting Invoke?**
|
The Model Manager tab in the UI provides a few ways to install models, including using your already-downloaded models. You'll see a popup directing you there on first startup. For more information, see the [model install docs].
|
||||||
|
|
||||||
- This can be safely ignored. InvokeAI doesn't use Triton, but if you are on Linux and wish to dismiss the error, you can install Triton.
|
## Slow generation
|
||||||
|
|
||||||
**I updated to 3.4.0 and now xFormers can’t load C++/CUDA?**
|
- Check the [system requirements] to ensure that your system is capable of generating images.
|
||||||
|
- Check the `ram` setting in `invokeai.yaml`. This setting tells Invoke how much of your system RAM can be used to cache models. Having this too high or too low can slow things down. That said, it's generally safest to not set this at all and instead let Invoke manage it.
|
||||||
|
- Check the `vram` setting in `invokeai.yaml`. This setting tells Invoke how much of your GPU VRAM can be used to cache models. Counter-intuitively, if this setting is too high, Invoke will need to do a lot of shuffling of models as it juggles the VRAM cache and the currently-loaded model. The default value of 0.25 is generally works well for GPUs without 16GB or more VRAM. Even on a 24GB card, the default works well.
|
||||||
|
- Check that your generations are happening on your GPU (if you have one). InvokeAI will log what is being used for generation upon startup. If your GPU isn't used, re-install to ensure the correct versions of torch get installed.
|
||||||
|
|
||||||
- An issue occurred with your PyTorch update. Follow these steps to fix :
|
## Installer cannot find python (Windows)
|
||||||
1. Launch your invoke.bat / invoke.sh and select the option to open the developer console
|
|
||||||
2. Run:`pip install ".[xformers]" --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121`
|
|
||||||
- If you run into an error with `typing_extensions`, re-open the developer console and run: `pip install -U typing-extensions`
|
|
||||||
|
|
||||||
**It says my pip is out of date - is that why my install isn't working?**
|
Ensure that you checked **Add python.exe to PATH** when installing Python. This can be found at the bottom of the Python Installer window. If you already have Python installed, you can re-run the python installer, choose the Modify option and check the box.
|
||||||
- An out of date won't cause an installation to fail. The cause of the error can likely be found above the message that says pip is out of date.
|
|
||||||
- If you saw that warning but the install went well, don't worry about it (but you can update pip afterwards if you'd like).
|
## Triton error on startup
|
||||||
|
|
||||||
|
This can be safely ignored. InvokeAI doesn't use Triton, but if you are on Linux and wish to dismiss the error, you can install Triton.
|
||||||
|
|
||||||
|
## Updated to 3.4.0 and xformers can’t load C++/CUDA
|
||||||
|
|
||||||
|
An issue occurred with your PyTorch update. Follow these steps to fix :
|
||||||
|
|
||||||
|
1. Launch your invoke.bat / invoke.sh and select the option to open the developer console
|
||||||
|
2. Run:`pip install ".[xformers]" --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121`
|
||||||
|
- If you run into an error with `typing_extensions`, re-open the developer console and run: `pip install -U typing-extensions`
|
||||||
|
|
||||||
|
Note that v3.4.0 is an old, unsupported version. Please upgrade to the [latest release].
|
||||||
|
|
||||||
|
## Install failed and says `pip` is out of date
|
||||||
|
|
||||||
|
An out of date `pip` typically won't cause an installation to fail. The cause of the error can likely be found above the message that says `pip` is out of date.
|
||||||
|
|
||||||
|
If you saw that warning but the install went well, don't worry about it (but you can update `pip` afterwards if you'd like).
|
||||||
|
|
||||||
|
## Replicate image found online
|
||||||
|
|
||||||
**How can I generate the exact same that I found on the internet?**
|
|
||||||
Most example images with prompts that you'll find on the internet have been generated using different software, so you can't expect to get identical results. In order to reproduce an image, you need to replicate the exact settings and processing steps, including (but not limited to) the model, the positive and negative prompts, the seed, the sampler, the exact image size, any upscaling steps, etc.
|
Most example images with prompts that you'll find on the internet have been generated using different software, so you can't expect to get identical results. In order to reproduce an image, you need to replicate the exact settings and processing steps, including (but not limited to) the model, the positive and negative prompts, the seed, the sampler, the exact image size, any upscaling steps, etc.
|
||||||
|
|
||||||
|
## OSErrors on Windows while installing dependencies
|
||||||
|
|
||||||
**Where can I get more help?**
|
During a zip file installation or an update, installation stops with an error like this:
|
||||||
|
|
||||||
- Create an issue on [GitHub](https://github.com/invoke-ai/InvokeAI/issues) or post in the [#help channel](https://discord.com/channels/1020123559063990373/1149510134058471514) of the InvokeAI Discord
|
![broken-dependency-screenshot](../assets/troubleshooting/broken-dependency.png){:width="800px"}
|
||||||
|
|
||||||
|
To resolve this, re-install the application as described above.
|
||||||
|
|
||||||
|
## HuggingFace install failed due to invalid access token
|
||||||
|
|
||||||
|
Some HuggingFace models require you to authenticate using an [access token].
|
||||||
|
|
||||||
|
Invoke doesn't manage this token for you, but it's easy to set it up:
|
||||||
|
|
||||||
|
- Follow the instructions in the link above to create an access token. Copy it.
|
||||||
|
- Run the launcher script.
|
||||||
|
- Select option 2 (developer console).
|
||||||
|
- Paste the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python -c "import huggingface_hub; huggingface_hub.login()"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Paste your access token when prompted and press Enter. You won't see anything when you paste it.
|
||||||
|
- Type `n` if prompted about git credentials.
|
||||||
|
|
||||||
|
If you get an error, try the command again - maybe the token didn't paste correctly.
|
||||||
|
|
||||||
|
Once your token is set, start Invoke and try downloading the model again. The installer will automatically use the access token.
|
||||||
|
|
||||||
|
If the install still fails, you may not have access to the model.
|
||||||
|
|
||||||
|
## Stable Diffusion XL generation fails after trying to load UNet
|
||||||
|
|
||||||
|
InvokeAI is working in other respects, but when trying to generate
|
||||||
|
images with Stable Diffusion XL you get a "Server Error". The text log
|
||||||
|
in the launch window contains this log line above several more lines of
|
||||||
|
error messages:
|
||||||
|
|
||||||
|
`INFO --> Loading model:D:\LONG\PATH\TO\MODEL, type sdxl:main:unet`
|
||||||
|
|
||||||
|
This failure mode occurs when there is a network glitch during
|
||||||
|
downloading the very large SDXL model.
|
||||||
|
|
||||||
|
To address this, first go to the Model Manager and delete the
|
||||||
|
Stable-Diffusion-XL-base-1.X model. Then, click the HuggingFace tab,
|
||||||
|
paste the Repo ID stabilityai/stable-diffusion-xl-base-1.0 and install
|
||||||
|
the model.
|
||||||
|
|
||||||
|
## Package dependency conflicts during installation or update
|
||||||
|
|
||||||
|
If you have previously installed InvokeAI or another Stable Diffusion
|
||||||
|
package, the installer may occasionally pick up outdated libraries and
|
||||||
|
either the installer or `invoke` will fail with complaints about
|
||||||
|
library conflicts.
|
||||||
|
|
||||||
|
To resolve this, re-install the application as described above.
|
||||||
|
|
||||||
|
## Invalid configuration file
|
||||||
|
|
||||||
|
Everything seems to install ok, you get a `ValidationError` when starting up the app.
|
||||||
|
|
||||||
|
This is caused by an invalid setting in the `invokeai.yaml` configuration file. The error message should tell you what is wrong.
|
||||||
|
|
||||||
|
Check the [configuration docs] for more detail about the settings and how to specify them.
|
||||||
|
|
||||||
|
## Out of Memory Issues
|
||||||
|
|
||||||
|
The models are large, VRAM is expensive, and you may find yourself
|
||||||
|
faced with Out of Memory errors when generating images. Here are some
|
||||||
|
tips to reduce the problem:
|
||||||
|
|
||||||
|
!!! info "Optimizing for GPU VRAM"
|
||||||
|
|
||||||
|
=== "4GB VRAM GPU"
|
||||||
|
|
||||||
|
This should be adequate for 512x512 pixel images using Stable Diffusion 1.5
|
||||||
|
and derived models, provided that you do not use the NSFW checker. It won't be loaded unless you go into the UI settings and turn it on.
|
||||||
|
|
||||||
|
If you are on a CUDA-enabled GPU, we will automatically use xformers or torch-sdp to reduce VRAM requirements, though you can explicitly configure this. See the [configuration docs].
|
||||||
|
|
||||||
|
=== "6GB VRAM GPU"
|
||||||
|
|
||||||
|
This is a border case. Using the SD 1.5 series you should be able to
|
||||||
|
generate images up to 640x640 with the NSFW checker enabled, and up to
|
||||||
|
1024x1024 with it disabled.
|
||||||
|
|
||||||
|
If you run into persistent memory issues there are a series of
|
||||||
|
environment variables that you can set before launching InvokeAI that
|
||||||
|
alter how the PyTorch machine learning library manages memory. See
|
||||||
|
<https://pytorch.org/docs/stable/notes/cuda.html#memory-management> for
|
||||||
|
a list of these tweaks.
|
||||||
|
|
||||||
|
=== "12GB VRAM GPU"
|
||||||
|
|
||||||
|
This should be sufficient to generate larger images up to about 1280x1280.
|
||||||
|
|
||||||
|
## Memory Leak (Linux)
|
||||||
|
|
||||||
|
If you notice a memory leak, it could be caused to memory fragmentation as models are loaded and/or moved from CPU to GPU.
|
||||||
|
|
||||||
|
A workaround is to tune memory allocation with an environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Force blocks >1MB to be allocated with `mmap` so that they are released to the system immediately when they are freed.
|
||||||
|
MALLOC_MMAP_THRESHOLD_=1048576
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! warning "Speed vs Memory Tradeoff"
|
||||||
|
|
||||||
|
Your generations may be slower overall when setting this environment variable.
|
||||||
|
|
||||||
|
!!! info "Possibly dependent on `libc` implementation"
|
||||||
|
|
||||||
|
It's not known if this issue occurs with other `libc` implementations such as `musl`.
|
||||||
|
|
||||||
|
If you encounter this issue and your system uses a different implementation, please try this environment variable and let us know if it fixes the issue.
|
||||||
|
|
||||||
|
<h3>Detailed Discussion</h3>
|
||||||
|
|
||||||
|
Python (and PyTorch) relies on the memory allocator from the C Standard Library (`libc`). On linux, with the GNU C Standard Library implementation (`glibc`), our memory access patterns have been observed to cause severe memory fragmentation.
|
||||||
|
|
||||||
|
This fragmentation results in large amounts of memory that has been freed but can't be released back to the OS. Loading models from disk and moving them between CPU/CUDA seem to be the operations that contribute most to the fragmentation.
|
||||||
|
|
||||||
|
This memory fragmentation issue can result in OOM crashes during frequent model switching, even if `ram` (the max RAM cache size) is set to a reasonable value (e.g. a OOM crash with `ram=16` on a system with 32GB of RAM).
|
||||||
|
|
||||||
|
This problem may also exist on other OSes, and other `libc` implementations. But, at the time of writing, it has only been investigated on linux with `glibc`.
|
||||||
|
|
||||||
|
To better understand how the `glibc` memory allocator works, see these references:
|
||||||
|
|
||||||
|
- Basics: <https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html>
|
||||||
|
- Details: <https://sourceware.org/glibc/wiki/MallocInternals>
|
||||||
|
|
||||||
|
Note the differences between memory allocated as chunks in an arena vs. memory allocated with `mmap`. Under `glibc`'s default configuration, most model tensors get allocated as chunks in an arena making them vulnerable to the problem of fragmentation.
|
||||||
|
|
||||||
|
[model install docs]: ../installation/050_INSTALLING_MODELS.md
|
||||||
|
[system requirements]: ../installation/INSTALL_REQUIREMENTS.md
|
||||||
|
[latest release]: https://github.com/invoke-ai/InvokeAI/releases/latest
|
||||||
|
[create an issue]: https://github.com/invoke-ai/InvokeAI/issues
|
||||||
|
[discord]: https://discord.gg/ZmtBAhwWhy
|
||||||
|
[configuration docs]: ../features/CONFIGURATION.md
|
||||||
|
[access token]: https://huggingface.co/docs/hub/security-tokens#how-to-manage-user-access-tokens
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
---
|
|
||||||
title: F.A.Q.
|
|
||||||
---
|
|
||||||
|
|
||||||
# :material-frequently-asked-questions: F.A.Q.
|
|
||||||
|
|
||||||
## **Frequently-Asked-Questions**
|
|
||||||
|
|
||||||
Here are a few common installation problems and their solutions. Often these are
|
|
||||||
caused by incomplete installations or crashes during the install process.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### During `conda env create`, conda hangs indefinitely
|
|
||||||
|
|
||||||
If it is because of the last PIP step (usually stuck in the Git Clone step, you
|
|
||||||
can check the detailed log by this method):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PIP_LOG="/tmp/pip_log.txt"
|
|
||||||
touch ${PIP_LOG}
|
|
||||||
tail -f ${PIP_LOG} &
|
|
||||||
conda env create -f environment-mac.yaml --debug --verbose
|
|
||||||
killall tail
|
|
||||||
rm ${PIP_LOG}
|
|
||||||
```
|
|
||||||
|
|
||||||
**SOLUTION**
|
|
||||||
|
|
||||||
Conda sometimes gets stuck at the last PIP step, in which several git
|
|
||||||
repositories are cloned and built.
|
|
||||||
|
|
||||||
Enter the stable-diffusion directory and completely remove the `src` directory
|
|
||||||
and all its contents. The safest way to do this is to enter the stable-diffusion
|
|
||||||
directory and give the command `git clean -f`. If this still doesn't fix the
|
|
||||||
problem, try "conda clean -all" and then restart at the `conda env create` step.
|
|
||||||
|
|
||||||
To further understand the problem to checking the install lot using this method:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PIP_LOG="/tmp/pip_log.txt"
|
|
||||||
touch ${PIP_LOG}
|
|
||||||
tail -f ${PIP_LOG} &
|
|
||||||
conda env create -f environment-mac.yaml --debug --verbose
|
|
||||||
killall tail
|
|
||||||
rm ${PIP_LOG}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `invoke.py` crashes with the complaint that it can't find `ldm.simplet2i.py`
|
|
||||||
|
|
||||||
Or it complains that function is being passed incorrect parameters.
|
|
||||||
|
|
||||||
**SOLUTION**
|
|
||||||
|
|
||||||
Reinstall the stable diffusion modules. Enter the `stable-diffusion` directory
|
|
||||||
and give the command `pip install -e .`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Missing modules
|
|
||||||
|
|
||||||
`invoke.py` dies, complaining of various missing modules, none of which starts
|
|
||||||
with `ldm`.
|
|
||||||
|
|
||||||
**SOLUTION**
|
|
||||||
|
|
||||||
From within the `InvokeAI` directory, run `conda env update` This is also
|
|
||||||
frequently the solution to complaints about an unknown function in a module.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How can I try new features
|
|
||||||
|
|
||||||
There's a feature or bugfix in the Stable Diffusion GitHub that you want to try
|
|
||||||
out.
|
|
||||||
|
|
||||||
**SOLUTIONS**
|
|
||||||
|
|
||||||
#### **Main Branch**
|
|
||||||
|
|
||||||
If the fix/feature is on the `main` branch, enter the stable-diffusion directory
|
|
||||||
and do a `git pull`.
|
|
||||||
|
|
||||||
Usually this will be sufficient, but if you start to see errors about missing or
|
|
||||||
incorrect modules, use the command `pip install -e .` and/or `conda env update`
|
|
||||||
(These commands won't break anything.)
|
|
||||||
|
|
||||||
`pip install -e .` and/or `conda env update -f environment.yaml`
|
|
||||||
|
|
||||||
(These commands won't break anything.)
|
|
||||||
|
|
||||||
#### **Sub Branch**
|
|
||||||
|
|
||||||
If the feature/fix is on a branch (e.g. "_foo-bugfix_"), the recipe is similar,
|
|
||||||
but do a `git pull <name of branch>`.
|
|
||||||
|
|
||||||
#### **Not Committed**
|
|
||||||
|
|
||||||
If the feature/fix is in a pull request that has not yet been made part of the
|
|
||||||
main branch or a feature/bugfix branch, then from the page for the desired pull
|
|
||||||
request, look for the line at the top that reads "_xxxx wants to merge xx
|
|
||||||
commits into lstein:main from YYYYYY_". Copy the URL in YYYY. It should have the
|
|
||||||
format
|
|
||||||
|
|
||||||
`https://github.com/<name of contributor>/stable-diffusion/tree/<name of branch>`
|
|
||||||
|
|
||||||
Then **go to the directory above stable-diffusion** and rename the directory to
|
|
||||||
"_stable-diffusion.lstein_", "_stable-diffusion.old_", or anything else. You can
|
|
||||||
then git clone the branch that contains the pull request:
|
|
||||||
|
|
||||||
`git clone https://github.com/<name of contributor>/stable-diffusion/tree/<name of branch>`
|
|
||||||
|
|
||||||
You will need to go through the install procedure again, but it should be fast
|
|
||||||
because all the dependencies are already loaded.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### CUDA out of memory
|
|
||||||
|
|
||||||
Image generation crashed with CUDA out of memory error after successful
|
|
||||||
sampling.
|
|
||||||
|
|
||||||
**SOLUTION**
|
|
||||||
|
|
||||||
Try to run script with option `--free_gpu_mem` This will free memory before
|
|
||||||
image decoding step.
|
|
@ -153,8 +153,7 @@ Mac and Linux machines, and runs on GPU cards with as little as 4 GB of RAM.
|
|||||||
## :material-target: Troubleshooting
|
## :material-target: Troubleshooting
|
||||||
|
|
||||||
Please check out our **[:material-frequently-asked-questions:
|
Please check out our **[:material-frequently-asked-questions:
|
||||||
Troubleshooting
|
FAQ](help/FAQ/)** to
|
||||||
Guide](installation/010_INSTALL_AUTOMATED.md#troubleshooting)** to
|
|
||||||
get solutions for common installation problems and other issues.
|
get solutions for common installation problems and other issues.
|
||||||
|
|
||||||
## :octicons-repo-push-24: Contributing
|
## :octicons-repo-push-24: Contributing
|
||||||
|
@ -1,424 +1,105 @@
|
|||||||
---
|
# Automatic Install
|
||||||
title: Installing with the Automated Installer
|
|
||||||
---
|
|
||||||
|
|
||||||
# InvokeAI Automated Installation
|
The installer is used for both new installs and updates.
|
||||||
|
|
||||||
## Introduction
|
Both release and pre-release versions can be installed using it. It also supports install a wheel if needed.
|
||||||
|
|
||||||
The automated installer is a Python script that automates the steps
|
Be sure to review the [installation requirements] and ensure your system has everything it needs to install Invoke.
|
||||||
needed to install and run InvokeAI on a stock computer running recent
|
|
||||||
versions of Linux, MacOS or Windows. It will leave you with a version
|
|
||||||
that runs a stable version of InvokeAI with the option to upgrade to
|
|
||||||
experimental versions later.
|
|
||||||
|
|
||||||
## Walk through
|
## Getting the Latest Installer
|
||||||
|
|
||||||
1. <a name="hardware_requirements">**Hardware Requirements**: </a>Make sure that your system meets the [hardware
|
Download the `InvokeAI-installer-vX.Y.Z.zip` file from the [latest release] page. It is at the bottom of the page, under **Assets**.
|
||||||
requirements](../index.md#hardware-requirements) and has the
|
|
||||||
appropriate GPU drivers installed. For a system with an NVIDIA
|
|
||||||
card installed, you will need to install the CUDA driver, while
|
|
||||||
AMD-based cards require the ROCm driver. In most cases, if you've
|
|
||||||
already used the system for gaming or other graphics-intensive
|
|
||||||
tasks, the appropriate drivers will already be installed. If
|
|
||||||
unsure, check the [GPU Driver Guide](030_INSTALL_CUDA_AND_ROCM.md)
|
|
||||||
|
|
||||||
!!! info "Required Space"
|
After unzipping the installer, you should have a `InvokeAI-Installer` folder with some files inside, including `install.bat` and `install.sh`.
|
||||||
|
|
||||||
Installation requires roughly 18G of free disk space to load
|
## Running the Installer
|
||||||
the libraries and recommended model weights files.
|
|
||||||
|
|
||||||
Regardless of your destination disk, your *system drive*
|
!!! tip
|
||||||
(`C:\` on Windows, `/` on macOS/Linux) requires at least 6GB
|
|
||||||
of free disk space to download and cache python
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
NOTE for Linux users: if your temporary directory is mounted
|
Windows users should first double-click the `WinLongPathsEnabled.reg` file to prevent a failed installation due to long file paths.
|
||||||
as a `tmpfs`, ensure it has sufficient space.
|
|
||||||
|
|
||||||
2. <a name="software_requirements">**Software Requirements**: </a>Check that your system has an up-to-date Python installed. To do
|
Double-click the install script:
|
||||||
this, open up a command-line window ("Terminal" on Linux and
|
|
||||||
Macintosh, "Command" or "Powershell" on Windows) and type `python
|
|
||||||
--version`. If Python is installed, it will print out the version
|
|
||||||
number. If it is version `3.10.*` or `3.11.*` you meet
|
|
||||||
requirements.
|
|
||||||
|
|
||||||
!!! warning "What to do if you have an unsupported version"
|
=== "Windows"
|
||||||
|
|
||||||
Go to [Python Downloads](https://www.python.org/downloads/)
|
```sh
|
||||||
and download the appropriate installer package for your
|
install.bat
|
||||||
platform. We recommend [Version
|
|
||||||
3.10.12](https://www.python.org/downloads/release/python-3109/),
|
|
||||||
which has been extensively tested with InvokeAI.
|
|
||||||
|
|
||||||
_Please select your platform in the section below for platform-specific
|
|
||||||
setup requirements._
|
|
||||||
|
|
||||||
=== "Windows"
|
|
||||||
During the Python configuration process, look out for a
|
|
||||||
checkbox to add Python to your PATH and select it. If the
|
|
||||||
install script complains that it can't find python, then open
|
|
||||||
the Python installer again and choose "Modify" existing
|
|
||||||
installation.
|
|
||||||
|
|
||||||
Installation requires an up to date version of the Microsoft
|
|
||||||
Visual C libraries. Please install the 2015-2022 libraries
|
|
||||||
available here:
|
|
||||||
https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170
|
|
||||||
|
|
||||||
Please double-click on the file `WinLongPathsEnabled.reg` and
|
|
||||||
accept the dialog box that asks you if you wish to modify your registry.
|
|
||||||
This activates long filename support on your system and will prevent
|
|
||||||
mysterious errors during installation.
|
|
||||||
|
|
||||||
=== "Linux"
|
|
||||||
To install an appropriate version of Python on Ubuntu 22.04
|
|
||||||
and higher, run the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y python3 python3-pip python3-venv
|
|
||||||
sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python3.10 3
|
|
||||||
```
|
|
||||||
|
|
||||||
On Ubuntu 20.04, the process is slightly different:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y software-properties-common
|
|
||||||
sudo add-apt-repository -y ppa:deadsnakes/ppa
|
|
||||||
sudo apt install -y python3.10 python3-pip python3.10-venv
|
|
||||||
sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python3.10 3
|
|
||||||
```
|
|
||||||
|
|
||||||
Both `python` and `python3` commands are now pointing at
|
|
||||||
Python3.10. You can still access older versions of Python by
|
|
||||||
calling `python2`, `python3.8`, etc.
|
|
||||||
|
|
||||||
Linux systems require a couple of additional graphics
|
|
||||||
libraries to be installed for proper functioning of
|
|
||||||
`python3-opencv`. Please run the following:
|
|
||||||
|
|
||||||
`sudo apt update && sudo apt install -y libglib2.0-0 libgl1-mesa-glx`
|
|
||||||
|
|
||||||
=== "Mac"
|
|
||||||
|
|
||||||
After installing Python, you may need to run the
|
|
||||||
following command from the Terminal in order to install the Web
|
|
||||||
certificates needed to download model data from https sites. If
|
|
||||||
you see lots of CERTIFICATE ERRORS during the last part of the
|
|
||||||
install, this is the problem, and you can fix it with this command:
|
|
||||||
|
|
||||||
`/Applications/Python\ 3.10/Install\ Certificates.command`
|
|
||||||
|
|
||||||
You may need to install the Xcode command line tools. These
|
|
||||||
are a set of tools that are needed to run certain applications in a
|
|
||||||
Terminal, including InvokeAI. This package is provided
|
|
||||||
directly by Apple. To install, open a terminal window and run `xcode-select --install`. You will get a macOS system popup guiding you through the
|
|
||||||
install. If you already have them installed, you will instead see some
|
|
||||||
output in the Terminal advising you that the tools are already installed. More information can be found at [FreeCode Camp](https://www.freecodecamp.org/news/install-xcode-command-line-tools/)
|
|
||||||
|
|
||||||
3. **Download the Installer**: The InvokeAI installer is distributed as a ZIP files. Go to the
|
|
||||||
[latest release](https://github.com/invoke-ai/InvokeAI/releases/latest),
|
|
||||||
and look for a file named:
|
|
||||||
|
|
||||||
- InvokeAI-installer-v4.X.X.zip
|
|
||||||
|
|
||||||
where "4.X.X" is the latest released version. The file is located
|
|
||||||
at the very bottom of the release page, under **Assets**.
|
|
||||||
|
|
||||||
4. **Unpack the installer**: Unpack the zip file into a convenient directory. This will create a new
|
|
||||||
directory named "InvokeAI-Installer". When unpacked, the directory
|
|
||||||
will look like this:
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![zipfile-screenshot](../assets/installer-walkthrough/unpacked-zipfile.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
5. **Launch the installer script from the desktop**: If you are using a desktop GUI, double-click the installer file
|
|
||||||
appropriate for your platform. It will be named `install.bat` on
|
|
||||||
Windows systems and `install.sh` on Linux and Macintosh
|
|
||||||
systems. Be aware that your system's file browser may suppress the
|
|
||||||
display of the file extension.
|
|
||||||
|
|
||||||
On Windows systems if you get an "Untrusted Publisher" warning.
|
|
||||||
Click on "More Info" and then select "Run Anyway." You trust us, right?
|
|
||||||
|
|
||||||
6. **[Alternative] Launch the installer script from the command line**: Alternatively, from the command line, run the shell script or .bat file:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
C:\Documents\Linco> cd InvokeAI-Installer
|
|
||||||
C:\Documents\Linco\invokeAI> .\install.bat
|
|
||||||
```
|
```
|
||||||
|
|
||||||
7. **Select the location to install InvokeAI**: The script will ask you to choose where to install InvokeAI. Select a
|
=== "Linux/macOS"
|
||||||
directory with at least 18G of free space for a full install. InvokeAI and
|
|
||||||
all its support files will be installed into a new directory named
|
|
||||||
`invokeai` located at the location you specify.
|
|
||||||
|
|
||||||
<figure markdown>
|
```sh
|
||||||
![confirm-install-directory-screenshot](../assets/installer-walkthrough/confirm-directory.png)
|
install.sh
|
||||||
</figure>
|
|
||||||
|
|
||||||
- The default is to install the `invokeai` directory in your home directory,
|
|
||||||
usually `C:\Users\YourName\invokeai` on Windows systems,
|
|
||||||
`/home/YourName/invokeai` on Linux systems, and `/Users/YourName/invokeai`
|
|
||||||
on Macintoshes, where "YourName" is your login name.
|
|
||||||
|
|
||||||
-If you have previously installed InvokeAI, you will be asked to
|
|
||||||
confirm whether you want to reinstall into this directory. You
|
|
||||||
may choose to reinstall, in which case your version will be upgraded,
|
|
||||||
or choose a different directory.
|
|
||||||
|
|
||||||
- The script uses tab autocompletion to suggest directory path completions.
|
|
||||||
Type part of the path (e.g. "C:\Users") and press ++tab++ repeatedly
|
|
||||||
to suggest completions.
|
|
||||||
|
|
||||||
8. **Select your GPU**: The installer will autodetect your platform and will request you to
|
|
||||||
confirm the type of GPU your graphics card has. On Linux systems,
|
|
||||||
you will have the choice of CUDA (NVidia cards), ROCm (AMD cards),
|
|
||||||
or CPU (no graphics acceleration). On Windows, you'll have the
|
|
||||||
choice of CUDA vs CPU, and on Macs you'll be offered CPU only. When
|
|
||||||
you select CPU on M1/M2/M3 Macintoshes, you will get MPS-based
|
|
||||||
graphics acceleration without installing additional drivers. If you
|
|
||||||
are unsure what GPU you are using, you can ask the installer to
|
|
||||||
guess.
|
|
||||||
|
|
||||||
9. **Watch it go!**: Sit back and let the install script work. It will install the third-party
|
|
||||||
libraries needed by InvokeAI and the application itself.
|
|
||||||
|
|
||||||
Be aware that some of the library download and install steps take a long
|
|
||||||
time. In particular, the `pytorch` package is quite large and often appears
|
|
||||||
to get "stuck" at 99.9%. Have patience and the installation step will
|
|
||||||
eventually resume. However, there are occasions when the library install
|
|
||||||
does legitimately get stuck. If you have been waiting for more than ten
|
|
||||||
minutes and nothing is happening, you can interrupt the script with ^C. You
|
|
||||||
may restart it and it will pick up where it left off.
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
![initial-settings-screenshot](../assets/installer-walkthrough/settings-form.png)
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
10. **Running InvokeAI for the first time**: The script will now exit and you'll be ready to generate some images. Look
|
|
||||||
for the directory `invokeai` installed in the location you chose at the
|
|
||||||
beginning of the install session. Look for a shell script named `invoke.sh`
|
|
||||||
(Linux/Mac) or `invoke.bat` (Windows). Launch the script by double-clicking
|
|
||||||
it or typing its name at the command-line:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
C:\Documents\Linco> cd invokeai
|
|
||||||
C:\Documents\Linco\invokeAI> invoke.bat
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- The `invoke.bat` (`invoke.sh`) script will give you the choice
|
!!! info "Running the Installer from the commandline"
|
||||||
of starting (1) the command-line interface, (2) the web GUI, (3)
|
|
||||||
textual inversion training, and (4) model merging.
|
|
||||||
|
|
||||||
- By default, the script will launch the web interface. When you
|
You can also run the install script from cmd/powershell (Windows) or terminal (Linux/macOS).
|
||||||
do this, you'll see a series of startup messages ending with
|
|
||||||
instructions to point your browser at
|
|
||||||
http://localhost:9090. Click on this link to open up a browser
|
|
||||||
and start exploring InvokeAI's features.
|
|
||||||
|
|
||||||
12. **InvokeAI Options**: You can configure using the `invokeai.yaml` config file.
|
!!! warning "Untrusted Publisher (Windows)"
|
||||||
For example, you can change the location of the
|
|
||||||
image output directory or balance memory usage vs performance. See
|
|
||||||
[Configuration](../features/CONFIGURATION.md) for a full list of the options.
|
|
||||||
|
|
||||||
- To set defaults that will take effect every time you launch InvokeAI,
|
You may get a popup saying the file comes from an `Untrusted Publisher`. Click `More Info` and `Run Anyway` to get past this.
|
||||||
use a text editor (e.g. Notepad) to exit the file
|
|
||||||
`invokeai\invokeai.yaml`. It contains a variety of examples that you can
|
|
||||||
follow to add and modify launch options.
|
|
||||||
|
|
||||||
- The launcher script also offers you an option labeled "open the developer
|
The installation process is simple, with a few prompts:
|
||||||
console". If you choose this option, you will be dropped into a
|
|
||||||
command-line interface in which you can run python commands directly,
|
|
||||||
access developer tools, and launch InvokeAI with customized options.
|
|
||||||
|
|
||||||
|
- Select the version to install. Unless you have a specific reason to install a specific version, select the default (the latest version).
|
||||||
|
- Select location for the install. Be sure you have enough space in this folder for the base application, as described in the [installation requirements].
|
||||||
|
- Select a GPU device. If you are unsure, you can let the installer figure it out.
|
||||||
|
|
||||||
!!! warning "Do not move or remove the `invokeai` directory"
|
!!! info "Slow Installation"
|
||||||
|
|
||||||
The `invokeai` directory contains the `invokeai` application, its
|
The installer needs to download several GB of data and install it all. It may appear to get stuck at 99.9% when installing `pytorch` or during a step labeled "Installing collected packages".
|
||||||
configuration files, the model weight files, and outputs of image generation.
|
|
||||||
Once InvokeAI is installed, do not move or remove this directory."
|
|
||||||
|
|
||||||
|
If it is stuck for over 10 minutes, something has probably gone wrong and you should close the window and restart.
|
||||||
|
|
||||||
<a name="troubleshooting"></a>
|
## Running the Application
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### _OSErrors on Windows while installing dependencies_
|
Find the install location you selected earlier. Double-click the launcher script to run the app:
|
||||||
|
|
||||||
During a zip file installation or an online update, installation stops
|
=== "Windows"
|
||||||
with an error like this:
|
|
||||||
|
|
||||||
![broken-dependency-screenshot](../assets/troubleshooting/broken-dependency.png){:width="800px"}
|
```sh
|
||||||
|
invoke.bat
|
||||||
|
```
|
||||||
|
|
||||||
This seems to happen particularly often with the `pydantic` and
|
=== "Linux/macOS"
|
||||||
`numpy` packages. The most reliable solution requires several manual
|
|
||||||
steps to complete installation.
|
|
||||||
|
|
||||||
Open up a Powershell window and navigate to the `invokeai` directory
|
```sh
|
||||||
created by the installer. Then give the following series of commands:
|
invoke.sh
|
||||||
|
```
|
||||||
|
|
||||||
```cmd
|
Choose the first option to run the UI. After a series of startup messages, you'll see something like this:
|
||||||
rm .\.venv -r -force
|
|
||||||
python -mvenv .venv
|
```
|
||||||
.\.venv\Scripts\activate
|
Uvicorn running on http://127.0.0.1:9090 (Press CTRL+C to quit)
|
||||||
pip install invokeai
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you see anything marked as an error during this process please stop
|
Copy the URL into your browser and you should see the UI.
|
||||||
and seek help on the Discord [installation support
|
|
||||||
channel](https://discord.com/channels/1020123559063990373/1041391462190956654). A
|
|
||||||
few warning messages are OK.
|
|
||||||
|
|
||||||
If you are updating from a previous version, this should restore your
|
## First-time Setup
|
||||||
system to a working state. If you are installing from scratch, there
|
|
||||||
is one additional command to give:
|
|
||||||
|
|
||||||
```cmd
|
You will need to [install some models] before you can generate.
|
||||||
wget -O invoke.bat https://raw.githubusercontent.com/invoke-ai/InvokeAI/main/installer/templates/invoke.bat.in
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create the `invoke.bat` script needed to launch InvokeAI and
|
Check the [configuration docs] for details on configuring the application.
|
||||||
its related programs.
|
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
### _Stable Diffusion XL Generation Fails after Trying to Load unet_
|
Updating is exactly the same as installing - download the latest installer, choose the latest version and off you go.
|
||||||
|
|
||||||
InvokeAI is working in other respects, but when trying to generate
|
!!! info "Dependency Resolution Issues"
|
||||||
images with Stable Diffusion XL you get a "Server Error". The text log
|
|
||||||
in the launch window contains this log line above several more lines of
|
|
||||||
error messages:
|
|
||||||
|
|
||||||
```INFO --> Loading model:D:\LONG\PATH\TO\MODEL, type sdxl:main:unet```
|
We've found that pip's dependency resolution can cause issues when upgrading packages. One very common problem was pip "downgrading" torch from CUDA to CPU, but things broke in other novel ways.
|
||||||
|
|
||||||
This failure mode occurs when there is a network glitch during
|
The installer doesn't have this kind of problem, so we use it for updating as well.
|
||||||
downloading the very large SDXL model.
|
|
||||||
|
|
||||||
To address this, first go to the Model Manager and delete the
|
## Installation Issues
|
||||||
Stable-Diffusion-XL-base-1.X model. Then, click the HuggingFace tab,
|
|
||||||
paste the Repo ID stabilityai/stable-diffusion-xl-base-1.0 and install
|
|
||||||
the model.
|
|
||||||
|
|
||||||
### _Package dependency conflicts_
|
If you have installation issues, please review the [FAQ]. You can also [create an issue] or ask for help on [discord].
|
||||||
|
|
||||||
If you have previously installed InvokeAI or another Stable Diffusion
|
[installation requirements]: INSTALLATION.md#installation-requirements
|
||||||
package, the installer may occasionally pick up outdated libraries and
|
[FAQ]: ../help/FAQ.md
|
||||||
either the installer or `invoke` will fail with complaints about
|
[install some models]: 050_INSTALLING_MODELS.md
|
||||||
library conflicts. In this case, run the `invoke.sh`/`invoke.bat`
|
[configuration docs]: ../features/CONFIGURATION.md
|
||||||
command and enter the Developer's Console by picking option (5). This
|
[latest release]: https://github.com/invoke-ai/InvokeAI/releases/latest
|
||||||
will take you to a command-line prompt.
|
[create an issue]: https://github.com/invoke-ai/InvokeAI/issues
|
||||||
|
[discord]: https://discord.gg/ZmtBAhwWhy
|
||||||
Then give this command:
|
|
||||||
|
|
||||||
`pip install InvokeAI --force-reinstall`
|
|
||||||
|
|
||||||
This should fix the issues.
|
|
||||||
|
|
||||||
### InvokeAI runs extremely slowly on Linux or Windows systems
|
|
||||||
|
|
||||||
The most frequent cause of this problem is when the installation
|
|
||||||
process installed the CPU-only version of the torch machine-learning
|
|
||||||
library, rather than a version that takes advantage of GPU
|
|
||||||
acceleration. To confirm this issue, look at the InvokeAI startup
|
|
||||||
messages. If you see a message saying ">> Using device CPU", then
|
|
||||||
this is what happened.
|
|
||||||
|
|
||||||
To fix this problem, first determine whether you have an NVidia or an
|
|
||||||
AMD GPU. The former uses the CUDA driver, and the latter uses ROCm
|
|
||||||
(only available on Linux). Then run the `invoke.sh`/`invoke.bat`
|
|
||||||
command and enter the Developer's Console by picking option (5). This
|
|
||||||
will take you to a command-line prompt.
|
|
||||||
|
|
||||||
Then type the following commands:
|
|
||||||
|
|
||||||
=== "NVIDIA System"
|
|
||||||
```bash
|
|
||||||
pip install torch torchvision --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
|
||||||
pip install xformers
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "AMD System"
|
|
||||||
```bash
|
|
||||||
pip install torch torchvision --force-reinstall --extra-index-url https://download.pytorch.org/whl/rocm5.6
|
|
||||||
```
|
|
||||||
|
|
||||||
### Corrupted configuration file
|
|
||||||
|
|
||||||
Everything seems to install ok, but `invokeai` complains of a corrupted
|
|
||||||
configuration file and goes back into the configuration process (asking you to
|
|
||||||
download models, etc), but this doesn't fix the problem.
|
|
||||||
|
|
||||||
This issue is often caused by a misconfigured configuration directive in the
|
|
||||||
`invokeai\invokeai.init` initialization file that contains startup settings. The
|
|
||||||
easiest way to fix the problem is to move the file out of the way and restart the app.
|
|
||||||
|
|
||||||
_If none of these maneuvers fixes the problem_ then please report the problem to
|
|
||||||
the [InvokeAI Issues](https://github.com/invoke-ai/InvokeAI/issues) section, or
|
|
||||||
visit our [Discord Server](https://discord.gg/ZmtBAhwWhy) for interactive
|
|
||||||
assistance.
|
|
||||||
|
|
||||||
### Out of Memory Issues
|
|
||||||
|
|
||||||
The models are large, VRAM is expensive, and you may find yourself
|
|
||||||
faced with Out of Memory errors when generating images. Here are some
|
|
||||||
tips to reduce the problem:
|
|
||||||
|
|
||||||
* **4 GB of VRAM**
|
|
||||||
|
|
||||||
This should be adequate for 512x512 pixel images using Stable Diffusion 1.5
|
|
||||||
and derived models, provided that you **disable** the NSFW checker. To
|
|
||||||
disable the filter, do one of the following:
|
|
||||||
|
|
||||||
* Select option (6) "_change InvokeAI startup options_" from the
|
|
||||||
launcher. This will bring up the console-based startup settings
|
|
||||||
dialogue and allow you to unselect the "NSFW Checker" option.
|
|
||||||
* Start the startup settings dialogue directly by running
|
|
||||||
`invokeai-configure --skip-sd-weights --skip-support-models`
|
|
||||||
from the command line.
|
|
||||||
* Find the `invokeai.init` initialization file in the InvokeAI root
|
|
||||||
directory, open it in a text editor, and change `--nsfw_checker`
|
|
||||||
to `--no-nsfw_checker`
|
|
||||||
|
|
||||||
If you are on a CUDA system, you can realize significant memory
|
|
||||||
savings by activating the `xformers` library as described above. The
|
|
||||||
downside is `xformers` introduces non-deterministic behavior, such
|
|
||||||
that images generated with exactly the same prompt and settings will
|
|
||||||
be slightly different from each other. See above for more information.
|
|
||||||
|
|
||||||
* **6 GB of VRAM**
|
|
||||||
|
|
||||||
This is a border case. Using the SD 1.5 series you should be able to
|
|
||||||
generate images up to 640x640 with the NSFW checker enabled, and up to
|
|
||||||
1024x1024 with it disabled and `xformers` activated.
|
|
||||||
|
|
||||||
If you run into persistent memory issues there are a series of
|
|
||||||
environment variables that you can set before launching InvokeAI that
|
|
||||||
alter how the PyTorch machine learning library manages memory. See
|
|
||||||
https://pytorch.org/docs/stable/notes/cuda.html#memory-management for
|
|
||||||
a list of these tweaks.
|
|
||||||
|
|
||||||
* **12 GB of VRAM**
|
|
||||||
|
|
||||||
This should be sufficient to generate larger images up to about
|
|
||||||
1280x1280. If you wish to push further, consider activating
|
|
||||||
`xformers`.
|
|
||||||
|
|
||||||
### Other Problems
|
|
||||||
|
|
||||||
If you run into problems during or after installation, the InvokeAI team is
|
|
||||||
available to help you. Either create an
|
|
||||||
[Issue](https://github.com/invoke-ai/InvokeAI/issues) at our GitHub site, or
|
|
||||||
make a request for help on the "bugs-and-support" channel of our
|
|
||||||
[Discord server](https://discord.gg/ZmtBAhwWhy). We are a 100% volunteer
|
|
||||||
organization, but typically somebody will be available to help you within 24
|
|
||||||
hours, and often much sooner.
|
|
||||||
|
|
||||||
## Updating to newer versions
|
|
||||||
|
|
||||||
This distribution is changing rapidly, and we add new features
|
|
||||||
regularly. Releases are announced at
|
|
||||||
http://github.com/invoke-ai/InvokeAI/releases, and at
|
|
||||||
https://pypi.org/project/InvokeAI/ To update to the latest released
|
|
||||||
version (recommended), download the latest release and run the installer.
|
|
||||||
|
@ -1,122 +1,59 @@
|
|||||||
---
|
# Manual Install
|
||||||
title: Installing Manually
|
|
||||||
---
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
|
|
||||||
# :fontawesome-brands-linux: Linux | :fontawesome-brands-apple: macOS | :fontawesome-brands-windows: Windows
|
|
||||||
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
!!! warning "This is for Advanced Users"
|
!!! warning "This is for Advanced Users"
|
||||||
|
|
||||||
**Python experience is mandatory**
|
**Python experience is mandatory.**
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
!!! tip "Conda"
|
!!! tip "Conda"
|
||||||
|
|
||||||
As of InvokeAI v2.3.0 installation using the `conda` package manager is no longer being supported. It will likely still work, but we are not testing this installation method.
|
As of InvokeAI v2.3.0 installation using the `conda` package manager is no longer being supported. It will likely still work, but we are not testing this installation method.
|
||||||
|
|
||||||
On Windows systems, you are encouraged to install and use the
|
InvokeAI is distributed as a python package on PyPI, installable with `pip`. There are a few things that are handled by the installer that you'll need to manage manually, described in this guide.
|
||||||
[PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.3),
|
|
||||||
which provides compatibility with Linux and Mac shells and nice
|
|
||||||
features such as command-line completion.
|
|
||||||
|
|
||||||
### Prerequisites
|
### Requirements
|
||||||
|
|
||||||
Before you start, make sure you have the following preqrequisites
|
Before you start, go through the [installation requirements].
|
||||||
installed. These are described in more detail in [Automated
|
|
||||||
Installation](010_INSTALL_AUTOMATED.md), and in many cases will
|
|
||||||
already be installed (if, for example, you have used your system for
|
|
||||||
gaming):
|
|
||||||
|
|
||||||
* **Python**
|
|
||||||
|
|
||||||
version 3.10 through 3.11
|
|
||||||
|
|
||||||
* **CUDA Tools**
|
|
||||||
|
|
||||||
For those with _NVidia GPUs_, you will need to
|
|
||||||
install the [CUDA toolkit and optionally the XFormers library](070_INSTALL_XFORMERS.md).
|
|
||||||
|
|
||||||
* **ROCm Tools**
|
|
||||||
|
|
||||||
For _Linux users with AMD GPUs_, you will need
|
|
||||||
to install the [ROCm toolkit](./030_INSTALL_CUDA_AND_ROCM.md). Note that
|
|
||||||
InvokeAI does not support AMD GPUs on Windows systems due to
|
|
||||||
lack of a Windows ROCm library.
|
|
||||||
|
|
||||||
* **Visual C++ Libraries**
|
|
||||||
|
|
||||||
_Windows users_ must install the free
|
|
||||||
[Visual C++ libraries from Microsoft](https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170)
|
|
||||||
|
|
||||||
* **The Xcode command line tools**
|
|
||||||
|
|
||||||
for _Macintosh users_. Instructions are available at
|
|
||||||
[Free Code Camp](https://www.freecodecamp.org/news/install-xcode-command-line-tools/)
|
|
||||||
|
|
||||||
* _Macintosh users_ may also need to run the `Install Certificates` command
|
|
||||||
if model downloads give lots of certificate errors. Run:
|
|
||||||
`/Applications/Python\ 3.10/Install\ Certificates.command`
|
|
||||||
|
|
||||||
### Installation Walkthrough
|
### Installation Walkthrough
|
||||||
|
|
||||||
To install InvokeAI with virtual environments and the PIP package
|
1. Create a directory to contain your InvokeAI library, configuration
|
||||||
manager, please follow these steps:
|
|
||||||
|
|
||||||
1. Please make sure you are using Python 3.10 through 3.11. The rest of the install
|
|
||||||
procedure depends on this and will not work with other versions:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -V
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a directory to contain your InvokeAI library, configuration
|
|
||||||
files, and models. This is known as the "runtime" or "root"
|
files, and models. This is known as the "runtime" or "root"
|
||||||
directory, and often lives in your home directory under the name `invokeai`.
|
directory, and often lives in your home directory under the name `invokeai`.
|
||||||
|
|
||||||
Please keep in mind the disk space requirements - you will need at
|
We will refer to this directory as `INVOKEAI_ROOT`. For convenience, create an environment variable pointing to the directory.
|
||||||
least 20GB for the models and the virtual environment. From now
|
|
||||||
on we will refer to this directory as `INVOKEAI_ROOT`. For convenience,
|
|
||||||
the steps below create a shell variable of that name which contains the
|
|
||||||
path to `HOME/invokeai`.
|
|
||||||
|
|
||||||
=== "Linux/Mac"
|
=== "Linux/macOS"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export INVOKEAI_ROOT=~/invokeai
|
export INVOKEAI_ROOT=~/invokeai
|
||||||
mkdir $INVOKEAI_ROOT
|
mkdir $INVOKEAI_ROOT
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Windows (Powershell)"
|
=== "Windows (PowerShell)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
Set-Variable -Name INVOKEAI_ROOT -Value $Home/invokeai
|
Set-Variable -Name INVOKEAI_ROOT -Value $Home/invokeai
|
||||||
mkdir $INVOKEAI_ROOT
|
mkdir $INVOKEAI_ROOT
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Enter the root (invokeai) directory and create a virtual Python
|
1. Enter the root (invokeai) directory and create a virtual Python environment within it named `.venv`.
|
||||||
environment within it named `.venv`. If the command `python`
|
|
||||||
doesn't work, try `python3`. Note that while you may create the
|
!!! info "Virtual Environment Location"
|
||||||
virtual environment anywhere in the file system, we recommend that
|
|
||||||
you create it within the root directory as shown here. This makes
|
While you may create the virtual environment anywhere in the file system, we recommend that you create it within the root directory as shown here. This allows the application to automatically detect its data directories.
|
||||||
it possible for the InvokeAI applications to find the model data
|
|
||||||
and configuration. If you do not choose to install the virtual
|
If you choose a different location for the venv, then you must set the `INVOKEAI_ROOT` environment variable or pass the directory using the `--root` CLI arg.
|
||||||
environment inside the root directory, then you **must** set the
|
|
||||||
`INVOKEAI_ROOT` environment variable in your shell environment, for
|
|
||||||
example, by editing `~/.bashrc` or `~/.zshrc` files, or setting the
|
|
||||||
Windows environment variable using the Advanced System Settings dialogue.
|
|
||||||
Refer to your operating system documentation for details.
|
|
||||||
|
|
||||||
```terminal
|
```terminal
|
||||||
cd $INVOKEAI_ROOT
|
cd $INVOKEAI_ROOT
|
||||||
python -m venv .venv --prompt InvokeAI
|
python3 -m venv .venv --prompt InvokeAI
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Activate the new environment:
|
1. Activate the new environment:
|
||||||
|
|
||||||
=== "Linux/Mac"
|
=== "Linux/macOS"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
@ -128,51 +65,51 @@ manager, please follow these steps:
|
|||||||
.venv\Scripts\activate
|
.venv\Scripts\activate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! info "Permissions Error (Windows)"
|
||||||
|
|
||||||
If you get a permissions error at this point, run this command and try again
|
If you get a permissions error at this point, run this command and try again
|
||||||
|
|
||||||
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
||||||
|
|
||||||
The command-line prompt should change to to show `(InvokeAI)` at the
|
The command-line prompt should change to to show `(InvokeAI)` at the beginning of the prompt.
|
||||||
beginning of the prompt. Note that all the following steps should be
|
|
||||||
run while inside the INVOKEAI_ROOT directory
|
|
||||||
|
|
||||||
5. Make sure that pip is installed in your virtual environment and up to date:
|
The following steps should be run while inside the `INVOKEAI_ROOT` directory.
|
||||||
|
|
||||||
|
1. Make sure that pip is installed in your virtual environment and up to date:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m pip install --upgrade pip
|
python3 -m pip install --upgrade pip
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Install the InvokeAI Package. The `--extra-index-url` option is used to select among
|
1. Install the InvokeAI Package. The `--extra-index-url` option is used to select the correct `torch` backend:
|
||||||
CUDA, ROCm and CPU/MPS drivers as shown below:
|
|
||||||
|
|
||||||
=== "CUDA (NVidia)"
|
=== "CUDA (NVidia)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install "InvokeAI[xformers]" --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121
|
pip install "InvokeAI[xformers]" --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ROCm (AMD)"
|
=== "ROCm (AMD)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.6
|
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.6
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "CPU (Intel Macs & non-GPU systems)"
|
=== "CPU (Intel Macs & non-GPU systems)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu
|
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "MPS (M1 and M2 Macs)"
|
=== "MPS (Apple Silicon)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install InvokeAI --use-pep517
|
pip install InvokeAI --use-pep517
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Deactivate and reactivate your runtime directory so that the invokeai-specific commands
|
1. Deactivate and reactivate your runtime directory so that the invokeai-specific commands become available in the environment:
|
||||||
become available in the environment
|
|
||||||
|
|
||||||
=== "Linux/Macintosh"
|
=== "Linux/macOS"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
deactivate && source .venv/bin/activate
|
deactivate && source .venv/bin/activate
|
||||||
@ -185,221 +122,41 @@ manager, please follow these steps:
|
|||||||
.venv\Scripts\activate
|
.venv\Scripts\activate
|
||||||
```
|
```
|
||||||
|
|
||||||
8. Set up the runtime directory
|
1. Run the application:
|
||||||
|
|
||||||
In this step you will initialize your runtime directory with the downloaded
|
Run `invokeai-web` to start the UI. You must activate the virtual environment before running the app.
|
||||||
models, model config files, directory for textual inversion embeddings, and
|
|
||||||
your outputs.
|
|
||||||
|
|
||||||
```terminal
|
If the virtual environment you selected is NOT inside `INVOKEAI_ROOT`, then you must specify the path to the root directory by adding
|
||||||
invokeai-configure --root .
|
`--root_dir \path\to\invokeai`.
|
||||||
```
|
|
||||||
|
|
||||||
Don't miss the dot at the end of the command!
|
|
||||||
|
|
||||||
The script `invokeai-configure` will interactively guide you through the
|
|
||||||
process of downloading and installing the weights files needed for InvokeAI.
|
|
||||||
Note that the main Stable Diffusion weights file is protected by a license
|
|
||||||
agreement that you have to agree to. The script will list the steps you need
|
|
||||||
to take to create an account on the site that hosts the weights files,
|
|
||||||
accept the agreement, and provide an access token that allows InvokeAI to
|
|
||||||
legally download and install the weights files.
|
|
||||||
|
|
||||||
If you get an error message about a module not being installed, check that
|
|
||||||
the `invokeai` environment is active and if not, repeat step 5.
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
If you have already downloaded the weights file(s) for another Stable
|
|
||||||
Diffusion distribution, you may skip this step (by selecting "skip" when
|
|
||||||
prompted) and configure InvokeAI to use the previously-downloaded files. The
|
|
||||||
process for this is described in [Installing Models](050_INSTALLING_MODELS.md).
|
|
||||||
|
|
||||||
9. Run the command-line- or the web- interface:
|
|
||||||
|
|
||||||
From within INVOKEAI_ROOT, activate the environment
|
|
||||||
(with `source .venv/bin/activate` or `.venv\scripts\activate`), and then run
|
|
||||||
the script `invokeai`. If the virtual environment you selected is NOT inside
|
|
||||||
INVOKEAI_ROOT, then you must specify the path to the root directory by adding
|
|
||||||
`--root_dir \path\to\invokeai` to the commands below:
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
!!! warning "Make sure that the virtual environment is activated, which should create `(.venv)` in front of your prompt!"
|
|
||||||
|
|
||||||
=== "local Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai-web
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Public Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai-web --host 0.0.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "CLI"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai
|
|
||||||
```
|
|
||||||
|
|
||||||
If you choose the run the web interface, point your browser at
|
|
||||||
http://localhost:9090 in order to load the GUI.
|
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
|
|
||||||
You can permanently set the location of the runtime directory
|
You can permanently set the location of the runtime directory
|
||||||
by setting the environment variable `INVOKEAI_ROOT` to the
|
by setting the environment variable `INVOKEAI_ROOT` to the
|
||||||
path of the directory. As mentioned previously, this is
|
path of the directory. As mentioned previously, this is
|
||||||
*highly recommended** if your virtual environment is located outside of
|
recommended if your virtual environment is located outside of
|
||||||
your runtime directory.
|
your runtime directory.
|
||||||
|
|
||||||
!!! tip
|
## Unsupported Conda Install
|
||||||
|
|
||||||
On linux, it is recommended to run invokeai with the following env var: `MALLOC_MMAP_THRESHOLD_=1048576`. For example: `MALLOC_MMAP_THRESHOLD_=1048576 invokeai --web`. This helps to prevent memory fragmentation that can lead to memory accumulation over time. This env var is set automatically when running via `invoke.sh`.
|
Congratulations, you found the "secret" Conda installation instructions. If you really **really** want to use Conda with InvokeAI, you can do so using this unsupported recipe:
|
||||||
|
|
||||||
10. Render away!
|
```sh
|
||||||
|
|
||||||
Browse the [features](../features/index.md) section to learn about all the
|
|
||||||
things you can do with InvokeAI.
|
|
||||||
|
|
||||||
|
|
||||||
11. Subsequently, to relaunch the script, activate the virtual environment, and
|
|
||||||
then launch `invokeai` command. If you forget to activate the virtual
|
|
||||||
environment you will most likeley receive a `command not found` error.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
|
|
||||||
Do not move the runtime directory after installation. The virtual environment will get confused if the directory is moved.
|
|
||||||
|
|
||||||
12. Other scripts
|
|
||||||
|
|
||||||
The [Textual Inversion](../features/TRAINING.md) script can be launched with the command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai-ti --gui
|
|
||||||
```
|
|
||||||
|
|
||||||
Similarly, the [Model Merging](../features/MODEL_MERGING.md) script can be launched with the command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invokeai-merge --gui
|
|
||||||
```
|
|
||||||
|
|
||||||
Leave off the `--gui` option to run the script using command-line arguments. Pass the `--help` argument
|
|
||||||
to get usage instructions.
|
|
||||||
|
|
||||||
## Developer Install
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
|
|
||||||
InvokeAI uses a SQLite database. By running on `main`, you accept responsibility for your database. This
|
|
||||||
means making regular backups (especially before pulling) and/or fixing it yourself in the event that a
|
|
||||||
PR introduces a schema change.
|
|
||||||
|
|
||||||
If you don't need persistent backend storage, you can use an ephemeral in-memory database by setting
|
|
||||||
`use_memory_db: true` under `Path:` in your `invokeai.yaml` file.
|
|
||||||
|
|
||||||
If this is untenable, you should run the application via the official installer or a manual install of the
|
|
||||||
python package from pypi. These releases will not break your database.
|
|
||||||
|
|
||||||
|
|
||||||
If you have an interest in how InvokeAI works, or you would like to
|
|
||||||
add features or bugfixes, you are encouraged to install the source
|
|
||||||
code for InvokeAI. For this to work, you will need to install the
|
|
||||||
`git` source code management program. If it is not already installed
|
|
||||||
on your system, please see the [Git Installation
|
|
||||||
Guide](https://github.com/git-guides/install-git)
|
|
||||||
|
|
||||||
You will also need to install the [frontend development toolchain](https://github.com/invoke-ai/InvokeAI/blob/main/invokeai/frontend/web/README.md).
|
|
||||||
|
|
||||||
If you have a "normal" installation, you should create a totally separate virtual environment for the git-based installation, else the two may interfere.
|
|
||||||
|
|
||||||
> **Why do I need the frontend toolchain**?
|
|
||||||
>
|
|
||||||
> The InvokeAI project uses trunk-based development. That means our `main` branch is the development branch, and releases are tags on that branch. Because development is very active, we don't keep an updated build of the UI in `main` - we only build it for production releases.
|
|
||||||
>
|
|
||||||
> That means that between releases, to have a functioning application when running directly from the repo, you will need to run the UI in dev mode or build it regularly (any time the UI code changes).
|
|
||||||
|
|
||||||
1. Create a fork of the InvokeAI repository through the GitHub UI or [this link](https://github.com/invoke-ai/InvokeAI/fork)
|
|
||||||
2. From the command line, run this command:
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/<your_github_username>/InvokeAI.git
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create a directory named `InvokeAI` and populate it with the
|
|
||||||
full source code from your fork of the InvokeAI repository.
|
|
||||||
|
|
||||||
3. Activate the InvokeAI virtual environment as per step (4) of the manual
|
|
||||||
installation protocol (important!)
|
|
||||||
|
|
||||||
4. Enter the InvokeAI repository directory and run one of these
|
|
||||||
commands, based on your GPU:
|
|
||||||
|
|
||||||
=== "CUDA (NVidia)"
|
|
||||||
```bash
|
|
||||||
pip install -e .[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "ROCm (AMD)"
|
|
||||||
```bash
|
|
||||||
pip install -e . --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.6
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "CPU (Intel Macs & non-GPU systems)"
|
|
||||||
```bash
|
|
||||||
pip install -e . --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "MPS (M1 and M2 Macs)"
|
|
||||||
```bash
|
|
||||||
pip install -e . --use-pep517
|
|
||||||
```
|
|
||||||
|
|
||||||
Be sure to pass `-e` (for an editable install) and don't forget the
|
|
||||||
dot ("."). It is part of the command.
|
|
||||||
|
|
||||||
5. Install the [frontend toolchain](https://github.com/invoke-ai/InvokeAI/blob/main/invokeai/frontend/web/README.md) and do a production build of the UI as described.
|
|
||||||
|
|
||||||
6. You can now run `invokeai` and its related commands. The code will be
|
|
||||||
read from the repository, so that you can edit the .py source files
|
|
||||||
and watch the code's behavior change.
|
|
||||||
|
|
||||||
When you pull in new changes to the repo, be sure to re-build the UI.
|
|
||||||
|
|
||||||
7. If you wish to contribute to the InvokeAI project, you are
|
|
||||||
encouraged to establish a GitHub account and "fork"
|
|
||||||
https://github.com/invoke-ai/InvokeAI into your own copy of the
|
|
||||||
repository. You can then use GitHub functions to create and submit
|
|
||||||
pull requests to contribute improvements to the project.
|
|
||||||
|
|
||||||
Please see [Contributing](../index.md#contributing) for hints
|
|
||||||
on getting started.
|
|
||||||
|
|
||||||
### Unsupported Conda Install
|
|
||||||
|
|
||||||
Congratulations, you found the "secret" Conda installation
|
|
||||||
instructions. If you really **really** want to use Conda with InvokeAI
|
|
||||||
you can do so using this unsupported recipe:
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir ~/invokeai
|
mkdir ~/invokeai
|
||||||
conda create -n invokeai python=3.10
|
conda create -n invokeai python=3.11
|
||||||
conda activate invokeai
|
conda activate invokeai
|
||||||
|
# Adjust this as described above for the appropriate torch backend
|
||||||
pip install InvokeAI[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121
|
pip install InvokeAI[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||||
invokeai-configure --root ~/invokeai
|
invokeai-web --root ~/invokeai
|
||||||
invokeai --root ~/invokeai --web
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `pip install` command shown in this recipe is for Linux/Windows
|
The `pip install` command shown in this recipe is for Linux/Windows
|
||||||
systems with an NVIDIA GPU. See step (6) above for the command to use
|
systems with an NVIDIA GPU. See step (6) above for the command to use
|
||||||
with other platforms/GPU combinations. If you don't wish to pass the
|
with other platforms/GPU combinations. If you don't wish to pass the
|
||||||
`--root` argument to `invokeai` with each launch, you may set the
|
`--root` argument to `invokeai` with each launch, you may set the
|
||||||
environment variable INVOKEAI_ROOT to point to the installation directory.
|
environment variable `INVOKEAI_ROOT` to point to the installation directory.
|
||||||
|
|
||||||
Note that if you run into problems with the Conda installation, the InvokeAI
|
Note that if you run into problems with the Conda installation, the InvokeAI
|
||||||
staff will **not** be able to help you out. Caveat Emptor!
|
staff will **not** be able to help you out. Caveat Emptor!
|
||||||
|
|
||||||
[dev-chat]: https://discord.com/channels/1020123559063990373/1049495067846524939
|
[installation requirements]: INSTALL_REQUIREMENTS.md
|
||||||
|
@ -1,149 +0,0 @@
|
|||||||
---
|
|
||||||
title: NVIDIA Cuda / AMD ROCm
|
|
||||||
---
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
|
|
||||||
# :simple-nvidia: CUDA | :simple-amd: ROCm
|
|
||||||
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
In order for InvokeAI to run at full speed, you will need a graphics
|
|
||||||
card with a supported GPU. InvokeAI supports NVidia cards via the CUDA
|
|
||||||
driver on Windows and Linux, and AMD cards via the ROCm driver on Linux.
|
|
||||||
|
|
||||||
## :simple-nvidia: CUDA
|
|
||||||
|
|
||||||
### Linux and Windows Install
|
|
||||||
|
|
||||||
If you have used your system for other graphics-intensive tasks, such
|
|
||||||
as gaming, you may very well already have the CUDA drivers
|
|
||||||
installed. To confirm, open up a command-line window and type:
|
|
||||||
|
|
||||||
```
|
|
||||||
nvidia-smi
|
|
||||||
```
|
|
||||||
|
|
||||||
If this command produces a status report on the GPU(s) installed on
|
|
||||||
your system, CUDA is installed and you have no more work to do. If
|
|
||||||
instead you get "command not found", or similar, then the driver will
|
|
||||||
need to be installed.
|
|
||||||
|
|
||||||
We strongly recommend that you install the CUDA Toolkit package
|
|
||||||
directly from NVIDIA. **Do not try to install Ubuntu's
|
|
||||||
nvidia-cuda-toolkit package. It is out of date and will cause
|
|
||||||
conflicts among the NVIDIA driver and binaries.**
|
|
||||||
|
|
||||||
Go to [CUDA Toolkit
|
|
||||||
Downloads](https://developer.nvidia.com/cuda-downloads), and use the
|
|
||||||
target selection wizard to choose your operating system, hardware
|
|
||||||
platform, and preferred installation method (e.g. "local" versus
|
|
||||||
"network").
|
|
||||||
|
|
||||||
This will provide you with a downloadable install file or, depending
|
|
||||||
on your choices, a recipe for downloading and running a install shell
|
|
||||||
script. Be sure to read and follow the full installation instructions.
|
|
||||||
|
|
||||||
After an install that seems successful, you can confirm by again
|
|
||||||
running `nvidia-smi` from the command line.
|
|
||||||
|
|
||||||
### Linux Install with a Runtime Container
|
|
||||||
|
|
||||||
On Linux systems, an alternative to installing CUDA Toolkit directly on
|
|
||||||
your system is to run an NVIDIA software container that has the CUDA
|
|
||||||
libraries already in place. This is recommended if you are already
|
|
||||||
familiar with containerization technologies such as Docker.
|
|
||||||
|
|
||||||
For downloads and instructions, visit the [NVIDIA CUDA Container
|
|
||||||
Runtime Site](https://developer.nvidia.com/nvidia-container-runtime)
|
|
||||||
|
|
||||||
### cuDNN Installation for 40/30 Series Optimization* (Optional)
|
|
||||||
|
|
||||||
1. Find the InvokeAI folder
|
|
||||||
2. Click on .venv folder - e.g., YourInvokeFolderHere\\.venv
|
|
||||||
3. Click on Lib folder - e.g., YourInvokeFolderHere\\.venv\Lib
|
|
||||||
4. Click on site-packages folder - e.g., YourInvokeFolderHere\\.venv\Lib\site-packages
|
|
||||||
5. Click on Torch directory - e.g., YourInvokeFolderHere\InvokeAI\\.venv\Lib\site-packages\torch
|
|
||||||
6. Click on the lib folder - e.g., YourInvokeFolderHere\\.venv\Lib\site-packages\torch\lib
|
|
||||||
7. Copy everything inside the folder and save it elsewhere as a backup.
|
|
||||||
8. Go to __https://developer.nvidia.com/cudnn__
|
|
||||||
9. Login or create an Account.
|
|
||||||
10. Choose the newer version of cuDNN. **Note:**
|
|
||||||
There are two versions, 11.x or 12.x for the differents architectures(Turing,Maxwell Etc...) of GPUs.
|
|
||||||
You can find which version you should download from [this link](https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html).
|
|
||||||
13. Download the latest version and extract it from the download location
|
|
||||||
14. Find the bin folder E\cudnn-windows-x86_64-__Whatever Version__\bin
|
|
||||||
15. Copy and paste the .dll files into YourInvokeFolderHere\\.venv\Lib\site-packages\torch\lib **Make sure to copy, and not move the files**
|
|
||||||
16. If prompted, replace any existing files
|
|
||||||
|
|
||||||
**Notes:**
|
|
||||||
* If no change is seen or any issues are encountered, follow the same steps as above and paste the torch/lib backup folder you made earlier and replace it. If you didn't make a backup, you can also uninstall and reinstall torch through the command line to repair this folder.
|
|
||||||
* This optimization is intended for the newer version of graphics card (40/30 series) but results have been seen with older graphics card.
|
|
||||||
|
|
||||||
|
|
||||||
### Torch Installation
|
|
||||||
|
|
||||||
When installing torch and torchvision manually with `pip`, remember to provide
|
|
||||||
the argument `--extra-index-url
|
|
||||||
https://download.pytorch.org/whl/cu121` as described in the [Manual
|
|
||||||
Installation Guide](020_INSTALL_MANUAL.md).
|
|
||||||
|
|
||||||
## :simple-amd: ROCm
|
|
||||||
|
|
||||||
### Linux Install
|
|
||||||
|
|
||||||
AMD GPUs are only supported on Linux platforms due to the lack of a
|
|
||||||
Windows ROCm driver at the current time. Also be aware that support
|
|
||||||
for newer AMD GPUs is spotty. Your mileage may vary.
|
|
||||||
|
|
||||||
It is possible that the ROCm driver is already installed on your
|
|
||||||
machine. To test, open up a terminal window and issue the following
|
|
||||||
command:
|
|
||||||
|
|
||||||
```
|
|
||||||
rocm-smi
|
|
||||||
```
|
|
||||||
|
|
||||||
If you get a table labeled "ROCm System Management Interface" the
|
|
||||||
driver is installed and you are done. If you get "command not found,"
|
|
||||||
then the driver needs to be installed.
|
|
||||||
|
|
||||||
Go to AMD's [ROCm Downloads
|
|
||||||
Guide](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation_new.html#installation-methods)
|
|
||||||
and scroll to the _Installation Methods_ section. Find the subsection
|
|
||||||
for the install method for your preferred Linux distribution, and
|
|
||||||
issue the commands given in the recipe.
|
|
||||||
|
|
||||||
Annoyingly, the official AMD site does not have a recipe for the most
|
|
||||||
recent version of Ubuntu, 22.04. However, this [community-contributed
|
|
||||||
recipe](https://novaspirit.github.io/amdgpu-rocm-ubu22/) is reported
|
|
||||||
to work well.
|
|
||||||
|
|
||||||
After installation, please run `rocm-smi` a second time to confirm
|
|
||||||
that the driver is present and the GPU is recognized. You may need to
|
|
||||||
do a reboot in order to load the driver.
|
|
||||||
|
|
||||||
### Linux Install with a ROCm-docker Container
|
|
||||||
|
|
||||||
If you are comfortable with the Docker containerization system, then
|
|
||||||
you can build a ROCm docker file. The source code and installation
|
|
||||||
recipes are available
|
|
||||||
[Here](https://github.com/RadeonOpenCompute/ROCm-docker/blob/master/quick-start.md)
|
|
||||||
|
|
||||||
### Torch Installation
|
|
||||||
|
|
||||||
When installing torch and torchvision manually with `pip`, remember to provide
|
|
||||||
the argument `--extra-index-url
|
|
||||||
https://download.pytorch.org/whl/rocm5.6` as described in the [Manual
|
|
||||||
Installation Guide](020_INSTALL_MANUAL.md).
|
|
||||||
|
|
||||||
This will be done automatically for you if you use the installer
|
|
||||||
script.
|
|
||||||
|
|
||||||
Be aware that the torch machine learning library does not seamlessly
|
|
||||||
interoperate with all AMD GPUs and you may experience garbled images,
|
|
||||||
black images, or long startup delays before rendering commences. Most
|
|
||||||
of these issues can be solved by Googling for workarounds. If you have
|
|
||||||
a problem and find a solution, please post an
|
|
||||||
[Issue](https://github.com/invoke-ai/InvokeAI/issues) so that other
|
|
||||||
users benefit and we can update this document.
|
|
@ -1,186 +1,52 @@
|
|||||||
---
|
# Installing Models
|
||||||
title: Installing Models
|
|
||||||
---
|
|
||||||
|
|
||||||
# :octicons-paintbrush-16: Installing Models
|
|
||||||
|
|
||||||
## Checkpoint and Diffusers Models
|
## Checkpoint and Diffusers Models
|
||||||
|
|
||||||
The model checkpoint files ('\*.ckpt') are the Stable Diffusion
|
The model checkpoint files (`*.ckpt`) are the Stable Diffusion "secret sauce". They are the product of training the AI on millions of captioned images gathered from multiple sources.
|
||||||
"secret sauce". They are the product of training the AI on millions of
|
|
||||||
captioned images gathered from multiple sources.
|
|
||||||
|
|
||||||
Originally there was only a single Stable Diffusion weights file,
|
Originally there was only a single Stable Diffusion weights file, which many people named `model.ckpt`.
|
||||||
which many people named `model.ckpt`. Now there are dozens or more
|
|
||||||
that have been fine tuned to provide particulary styles, genres, or
|
|
||||||
other features. In addition, there are several new formats that
|
|
||||||
improve on the original checkpoint format: a `.safetensors` format
|
|
||||||
which prevents malware from masquerading as a model, and `diffusers`
|
|
||||||
models, the most recent innovation.
|
|
||||||
|
|
||||||
InvokeAI supports all three formats but strongly prefers the
|
Today, there are thousands of models, fine tuned to excel at specific styles, genres, or themes.
|
||||||
`diffusers` format. These are distributed as directories containing
|
|
||||||
multiple subfolders, each of which contains a different aspect of the
|
|
||||||
model. The advantage of this is that the models load from disk really
|
|
||||||
fast. Another advantage is that `diffusers` models are supported by a
|
|
||||||
large and active set of open source developers working at and with
|
|
||||||
HuggingFace organization, and improvements in both rendering quality
|
|
||||||
and performance are being made at a rapid pace. Among other features
|
|
||||||
is the ability to download and install a `diffusers` model just by
|
|
||||||
providing its HuggingFace repository ID.
|
|
||||||
|
|
||||||
While InvokeAI will continue to support `.ckpt` and `.safetensors`
|
!!! tip "Model Formats"
|
||||||
models for the near future, these are deprecated and support will
|
|
||||||
likely be withdrawn at some point in the not-too-distant future.
|
|
||||||
|
|
||||||
This manual will guide you through installing and configuring model
|
We also have two more popular model formats, both created [HuggingFace](https://huggingface.co/):
|
||||||
weight files and converting legacy `.ckpt` and `.safetensors` files
|
|
||||||
into performant `diffusers` models.
|
|
||||||
|
|
||||||
## Base Models
|
- `safetensors`: Single file, like `.ckpt` files. Prevents malware from lurking in a model.
|
||||||
|
- `diffusers`: Splits the model components into separate files, allowing very fast loading.
|
||||||
|
|
||||||
InvokeAI comes with support for a good set of starter models. You'll
|
InvokeAI supports all three formats. Our backend will convert models to `diffusers` format before running them. This is a transparent process.
|
||||||
find them listed in the master models file
|
|
||||||
`configs/INITIAL_MODELS.yaml` in the InvokeAI root directory. The
|
|
||||||
subset that are currently installed are found in
|
|
||||||
`configs/models.yaml`.
|
|
||||||
|
|
||||||
Note that these files are covered by an "Ethical AI" license which
|
## Starter Models
|
||||||
forbids certain uses. When you initially download them, you are asked
|
|
||||||
to accept the license terms. In addition, some of these models carry
|
|
||||||
additional license terms that limit their use in commercial
|
|
||||||
applications or on public servers. Be sure to familiarize yourself
|
|
||||||
with the model terms by visiting the URLs in the table above.
|
|
||||||
|
|
||||||
## Community-Contributed Models
|
When you first start InvokeAI, you'll see a popup prompting you to install some starter models from the Model Manager. Click the `Starter Models` tab to see the list.
|
||||||
|
|
||||||
[HuggingFace](https://huggingface.co/models?library=diffusers)
|
You'll find a collection of popular and high-quality models available for easy download.
|
||||||
is a great resource for diffusers models, and is also the home of a
|
|
||||||
[fast-growing repository](https://huggingface.co/sd-concepts-library)
|
|
||||||
of embedding (".bin") models that add subjects and/or styles to your
|
|
||||||
images. The latter are automatically installed on the fly when you
|
|
||||||
include the text `<concept-name>` in your prompt. See [Concepts
|
|
||||||
Library](../features/CONCEPTS.md) for more information.
|
|
||||||
|
|
||||||
Another popular site for community-contributed models is
|
Some models carry license terms that limit their use in commercial applications or on public servers. It's your responsibility to adhere to the license terms.
|
||||||
[CIVITAI](https://civitai.com). This extensive site currently supports
|
|
||||||
only `.safetensors` and `.ckpt` models, but they can be easily loaded
|
|
||||||
into InvokeAI and/or converted into optimized `diffusers` models. Be
|
|
||||||
aware that CIVITAI hosts many models that generate NSFW content.
|
|
||||||
|
|
||||||
## Installation
|
## Other Models
|
||||||
|
|
||||||
There are two ways to install and manage models:
|
You can install other models using the Model Manager. You'll find tabs for the following install methods:
|
||||||
|
|
||||||
1. The `invokeai-model-install` script which will download and install
|
- **URL or Local Path**: Provide the path to a model on your computer, or a direct link to the model. Some sites require you to use an API token to download models, which you can [set up in the config file].
|
||||||
them for you. In addition to supporting main models, you can install
|
- **HuggingFace**: Paste a HF Repo ID to install it. If there are multiple models in the repo, you'll get a list to choose from. Repo IDs look like this: `XpucT/Deliberate`. There is a copy button on each repo to copy the ID.
|
||||||
ControlNet, LoRA and Textual Inversion models.
|
- **Scan Folder**: Scan a local folder for models. You can install all of the detected models in one click.
|
||||||
|
|
||||||
2. The web interface (WebUI) has a GUI for importing and managing
|
!!! tip "Autoimport"
|
||||||
models.
|
|
||||||
|
|
||||||
3. By placing models (or symbolic links to models) inside one of the
|
The dedicated autoimport folder is removed as of v4.0.0. You can do the same thing on the **Scan Folder** tab - paste the folder you'd like to import from and then click `Install All`.
|
||||||
InvokeAI root directory's `autoimport` folder.
|
|
||||||
|
|
||||||
### Installation via `invokeai-model-install`
|
### Diffusers models in HF repo subfolders
|
||||||
|
|
||||||
From the `invoke` launcher, choose option [4] "Download and install
|
HuggingFace repos can be structured in any way. Some model authors include multiple models within the same folder.
|
||||||
models." This will launch the same script that prompted you to select
|
|
||||||
models at install time. You can use this to add models that you
|
|
||||||
skipped the first time around. It is all right to specify a model that
|
|
||||||
was previously downloaded; the script will just confirm that the files
|
|
||||||
are complete.
|
|
||||||
|
|
||||||
The installer has different panels for installing main models from
|
In this situation, you may need to provide some additional information to identify the model you want, by adding `:subfolder_name` to the repo ID.
|
||||||
HuggingFace, models from Civitai and other arbitrary web sites,
|
|
||||||
ControlNet models, LoRA/LyCORIS models, and Textual Inversion
|
|
||||||
embeddings. Each section has a text box in which you can enter a new
|
|
||||||
model to install. You can refer to a model using its:
|
|
||||||
|
|
||||||
1. Local path to the .ckpt, .safetensors or diffusers folder on your local machine
|
!!! example
|
||||||
2. A directory on your machine that contains multiple models
|
|
||||||
3. A URL that points to a downloadable model
|
|
||||||
4. A HuggingFace repo id
|
|
||||||
|
|
||||||
Previously-installed models are shown with checkboxes. Uncheck a box
|
Say you have a repo ID `monster-labs/control_v1p_sd15_qrcode_monster`, and the model you want is inside the `v2` subfolder.
|
||||||
to unregister the model from InvokeAI. Models that are physically
|
|
||||||
installed inside the InvokeAI root directory will be deleted and
|
|
||||||
purged (after a confirmation warning). Models that are located outside
|
|
||||||
the InvokeAI root directory will be unregistered but not deleted.
|
|
||||||
|
|
||||||
Note: The installer script uses a console-based text interface that requires
|
Add `:v2` to the repo ID and use that when installing the model: `monster-labs/control_v1p_sd15_qrcode_monster:v2`
|
||||||
significant amounts of horizontal and vertical space. If the display
|
|
||||||
looks messed up, just enlarge the terminal window and/or relaunch the
|
|
||||||
script.
|
|
||||||
|
|
||||||
If you wish you can script model addition and deletion, as well as
|
[set up in the config file]: ../../features/CONFIGURATION#model-marketplace-api-keys
|
||||||
listing installed models. Start the "developer's console" and give the
|
|
||||||
command `invokeai-model-install --help`. This will give you a series
|
|
||||||
of command-line parameters that will let you control model
|
|
||||||
installation. Examples:
|
|
||||||
|
|
||||||
```
|
|
||||||
# (list all controlnet models)
|
|
||||||
invokeai-model-install --list controlnet
|
|
||||||
|
|
||||||
# (install the model at the indicated URL)
|
|
||||||
invokeai-model-install --add https://civitai.com/api/download/models/128713
|
|
||||||
|
|
||||||
# (delete the named model)
|
|
||||||
invokeai-model-install --delete sd-1/main/analog-diffusion
|
|
||||||
```
|
|
||||||
|
|
||||||
### Installation via the Web GUI
|
|
||||||
|
|
||||||
To install a new model using the Web GUI, do the following:
|
|
||||||
|
|
||||||
1. Open the InvokeAI Model Manager (cube at the bottom of the
|
|
||||||
left-hand panel) and navigate to *Import Models*
|
|
||||||
|
|
||||||
2. In the field labeled *Location* type in the path to the model you
|
|
||||||
wish to install. You may use a URL, HuggingFace repo id, or a path on
|
|
||||||
your local disk.
|
|
||||||
|
|
||||||
3. Alternatively, the *Scan for Models* button allows you to paste in
|
|
||||||
the path to a folder somewhere on your machine. It will be scanned for
|
|
||||||
importable models and prompt you to add the ones of your choice.
|
|
||||||
|
|
||||||
4. Press *Add Model* and wait for confirmation that the model
|
|
||||||
was added.
|
|
||||||
|
|
||||||
To delete a model, Select *Model Manager* to list all the currently
|
|
||||||
installed models. Press the trash can icons to delete any models you
|
|
||||||
wish to get rid of. Models whose weights are located inside the
|
|
||||||
InvokeAI `models` directory will be purged from disk, while those
|
|
||||||
located outside will be unregistered from InvokeAI, but not deleted.
|
|
||||||
|
|
||||||
You can see where model weights are located by clicking on the model name.
|
|
||||||
This will bring up an editable info panel showing the model's characteristics,
|
|
||||||
including the `Model Location` of its files.
|
|
||||||
|
|
||||||
### Installation via the `autoimport` function
|
|
||||||
|
|
||||||
In the InvokeAI root directory you will find a series of folders under
|
|
||||||
`autoimport`, one each for main models, controlnets, embeddings and
|
|
||||||
Loras. Any models that you add to these directories will be scanned
|
|
||||||
at startup time and registered automatically.
|
|
||||||
|
|
||||||
You may create symbolic links from these folders to models located
|
|
||||||
elsewhere on disk and they will be autoimported. You can also create
|
|
||||||
subfolders and organize them as you wish.
|
|
||||||
|
|
||||||
The location of the autoimport directories are controlled by settings
|
|
||||||
in `invokeai.yaml`. See [Configuration](../features/CONFIGURATION.md).
|
|
||||||
|
|
||||||
### Installing models that live in HuggingFace subfolders
|
|
||||||
|
|
||||||
On rare occasions you may need to install a diffusers-style model that
|
|
||||||
lives in a subfolder of a HuggingFace repo id. In this event, simply
|
|
||||||
add ":_subfolder-name_" to the end of the repo id. For example, if the
|
|
||||||
repo id is "monster-labs/control_v1p_sd15_qrcode_monster" and the model
|
|
||||||
you wish to fetch lives in a subfolder named "v2", then the repo id to
|
|
||||||
pass to the various model installers should be
|
|
||||||
|
|
||||||
```
|
|
||||||
monster-labs/control_v1p_sd15_qrcode_monster:v2
|
|
||||||
```
|
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
---
|
|
||||||
title: Installing xFormers
|
|
||||||
---
|
|
||||||
|
|
||||||
# :material-image-size-select-large: Installing xformers
|
|
||||||
|
|
||||||
xFormers is toolbox that integrates with the pyTorch and CUDA
|
|
||||||
libraries to provide accelerated performance and reduced memory
|
|
||||||
consumption for applications using the transformers machine learning
|
|
||||||
architecture. After installing xFormers, InvokeAI users who have
|
|
||||||
CUDA GPUs will see a noticeable decrease in GPU memory consumption and
|
|
||||||
an increase in speed.
|
|
||||||
|
|
||||||
xFormers can be installed into a working InvokeAI installation without
|
|
||||||
any code changes or other updates. This document explains how to
|
|
||||||
install xFormers.
|
|
||||||
|
|
||||||
## Pip Install
|
|
||||||
|
|
||||||
For both Windows and Linux, you can install `xformers` in just a
|
|
||||||
couple of steps from the command line.
|
|
||||||
|
|
||||||
If you are used to launching `invoke.sh` or `invoke.bat` to start
|
|
||||||
InvokeAI, then run the launcher and select the "developer's console"
|
|
||||||
to get to the command line. If you run invoke.py directly from the
|
|
||||||
command line, then just be sure to activate it's virtual environment.
|
|
||||||
|
|
||||||
Then run the following three commands:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pip install xformers~=0.0.22
|
|
||||||
pip install triton # WON'T WORK ON WINDOWS
|
|
||||||
python -m xformers.info output
|
|
||||||
```
|
|
||||||
|
|
||||||
The first command installs `xformers`, the second installs the
|
|
||||||
`triton` training accelerator, and the third prints out the `xformers`
|
|
||||||
installation status. On Windows, please omit the `triton` package,
|
|
||||||
which is not available on that platform.
|
|
||||||
|
|
||||||
If all goes well, you'll see a report like the
|
|
||||||
following:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
xFormers 0.0.22
|
|
||||||
memory_efficient_attention.cutlassF: available
|
|
||||||
memory_efficient_attention.cutlassB: available
|
|
||||||
memory_efficient_attention.flshattF: available
|
|
||||||
memory_efficient_attention.flshattB: available
|
|
||||||
memory_efficient_attention.smallkF: available
|
|
||||||
memory_efficient_attention.smallkB: available
|
|
||||||
memory_efficient_attention.tritonflashattF: available
|
|
||||||
memory_efficient_attention.tritonflashattB: available
|
|
||||||
indexing.scaled_index_addF: available
|
|
||||||
indexing.scaled_index_addB: available
|
|
||||||
indexing.index_select: available
|
|
||||||
swiglu.dual_gemm_silu: available
|
|
||||||
swiglu.gemm_fused_operand_sum: available
|
|
||||||
swiglu.fused.p.cpp: available
|
|
||||||
is_triton_available: True
|
|
||||||
is_functorch_available: False
|
|
||||||
pytorch.version: 2.1.0+cu121
|
|
||||||
pytorch.cuda: available
|
|
||||||
gpu.compute_capability: 8.9
|
|
||||||
gpu.name: NVIDIA GeForce RTX 4070
|
|
||||||
build.info: available
|
|
||||||
build.cuda_version: 1108
|
|
||||||
build.python_version: 3.10.11
|
|
||||||
build.torch_version: 2.1.0+cu121
|
|
||||||
build.env.TORCH_CUDA_ARCH_LIST: 5.0+PTX 6.0 6.1 7.0 7.5 8.0 8.6
|
|
||||||
build.env.XFORMERS_BUILD_TYPE: Release
|
|
||||||
build.env.XFORMERS_ENABLE_DEBUG_ASSERTIONS: None
|
|
||||||
build.env.NVCC_FLAGS: None
|
|
||||||
build.env.XFORMERS_PACKAGE_FROM: wheel-v0.0.20
|
|
||||||
build.nvcc_version: 11.8.89
|
|
||||||
source.privacy: open source
|
|
||||||
```
|
|
||||||
|
|
||||||
## Source Builds
|
|
||||||
|
|
||||||
`xformers` is currently under active development and at some point you
|
|
||||||
may wish to build it from sourcce to get the latest features and
|
|
||||||
bugfixes.
|
|
||||||
|
|
||||||
### Source Build on Linux
|
|
||||||
|
|
||||||
Note that xFormers only works with true NVIDIA GPUs and will not work
|
|
||||||
properly with the ROCm driver for AMD acceleration.
|
|
||||||
|
|
||||||
xFormers is not currently available as a pip binary wheel and must be
|
|
||||||
installed from source. These instructions were written for a system
|
|
||||||
running Ubuntu 22.04, but other Linux distributions should be able to
|
|
||||||
adapt this recipe.
|
|
||||||
|
|
||||||
#### 1. Install CUDA Toolkit 12.1
|
|
||||||
|
|
||||||
You will need the CUDA developer's toolkit in order to compile and
|
|
||||||
install xFormers. **Do not try to install Ubuntu's nvidia-cuda-toolkit
|
|
||||||
package.** It is out of date and will cause conflicts among the NVIDIA
|
|
||||||
driver and binaries. Instead install the CUDA Toolkit package provided
|
|
||||||
by NVIDIA itself. Go to [CUDA Toolkit 12.1
|
|
||||||
Downloads](https://developer.nvidia.com/cuda-12-1-0-download-archive)
|
|
||||||
and use the target selection wizard to choose your platform and Linux
|
|
||||||
distribution. Select an installer type of "runfile (local)" at the
|
|
||||||
last step.
|
|
||||||
|
|
||||||
This will provide you with a recipe for downloading and running a
|
|
||||||
install shell script that will install the toolkit and drivers.
|
|
||||||
|
|
||||||
#### 2. Confirm/Install pyTorch 2.1.0 with CUDA 12.1 support
|
|
||||||
|
|
||||||
If you are using InvokeAI 3.0.2 or higher, these will already be
|
|
||||||
installed. If not, you can check whether you have the needed libraries
|
|
||||||
using a quick command. Activate the invokeai virtual environment,
|
|
||||||
either by entering the "developer's console", or manually with a
|
|
||||||
command similar to `source ~/invokeai/.venv/bin/activate` (depending
|
|
||||||
on where your `invokeai` directory is.
|
|
||||||
|
|
||||||
Then run the command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
python -c 'exec("import torch\nprint(torch.__version__)")'
|
|
||||||
```
|
|
||||||
|
|
||||||
If it prints __2.1.0+cu121__ you're good. If not, you can install the
|
|
||||||
most up to date libraries with this command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pip install --upgrade --force-reinstall torch torchvision
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Install the triton module
|
|
||||||
|
|
||||||
This module isn't necessary for xFormers image inference optimization,
|
|
||||||
but avoids a startup warning.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pip install triton
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Install source code build prerequisites
|
|
||||||
|
|
||||||
To build xFormers from source, you will need the `build-essentials`
|
|
||||||
package. If you don't have it installed already, run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo apt install build-essential
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5. Build xFormers
|
|
||||||
|
|
||||||
There is no pip wheel package for xFormers at this time (January
|
|
||||||
2023). Although there is a conda package, InvokeAI no longer
|
|
||||||
officially supports conda installations and you're on your own if you
|
|
||||||
wish to try this route.
|
|
||||||
|
|
||||||
Following the recipe provided at the [xFormers GitHub
|
|
||||||
page](https://github.com/facebookresearch/xformers), and with the
|
|
||||||
InvokeAI virtual environment active (see step 1) run the following
|
|
||||||
commands:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pip install ninja
|
|
||||||
export TORCH_CUDA_ARCH_LIST="6.0;6.1;6.2;7.0;7.2;7.5;8.0;8.6"
|
|
||||||
pip install -v -U git+https://github.com/facebookresearch/xformers.git@main#egg=xformers
|
|
||||||
```
|
|
||||||
|
|
||||||
The TORCH_CUDA_ARCH_LIST is a list of GPU architectures to compile
|
|
||||||
xFormer support for. You can speed up compilation by selecting
|
|
||||||
the architecture specific for your system. You'll find the list of
|
|
||||||
GPUs and their architectures at NVIDIA's [GPU Compute
|
|
||||||
Capability](https://developer.nvidia.com/cuda-gpus) table.
|
|
||||||
|
|
||||||
If the compile and install completes successfully, you can check that
|
|
||||||
xFormers is installed with this command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
python -m xformers.info
|
|
||||||
```
|
|
||||||
|
|
||||||
If suiccessful, the top of the listing should indicate "available" for
|
|
||||||
each of the `memory_efficient_attention` modules, as shown here:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
memory_efficient_attention.cutlassF: available
|
|
||||||
memory_efficient_attention.cutlassB: available
|
|
||||||
memory_efficient_attention.flshattF: available
|
|
||||||
memory_efficient_attention.flshattB: available
|
|
||||||
memory_efficient_attention.smallkF: available
|
|
||||||
memory_efficient_attention.smallkB: available
|
|
||||||
memory_efficient_attention.tritonflashattF: available
|
|
||||||
memory_efficient_attention.tritonflashattB: available
|
|
||||||
[...]
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now launch InvokeAI and enjoy the benefits of xFormers.
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
To come
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
(c) Copyright 2023 Lincoln Stein and the InvokeAI Development Team
|
|
@ -1,89 +0,0 @@
|
|||||||
---
|
|
||||||
title: build binary installers
|
|
||||||
---
|
|
||||||
|
|
||||||
# :simple-buildkite: How to build "binary" installers (InvokeAI-mac/windows/linux_on_*.zip)
|
|
||||||
|
|
||||||
## 1. Ensure `installers/requirements.in` is correct
|
|
||||||
|
|
||||||
and up to date on the branch to be installed.
|
|
||||||
|
|
||||||
## <a name="step-2"></a> 2. Run `pip-compile` on each platform.
|
|
||||||
|
|
||||||
On each target platform, in the branch that is to be installed, and
|
|
||||||
inside the InvokeAI git root folder, run the following commands:
|
|
||||||
|
|
||||||
```commandline
|
|
||||||
conda activate invokeai # or however you activate python
|
|
||||||
pip install pip-tools
|
|
||||||
pip-compile --allow-unsafe --generate-hashes --output-file=binary_installer/<reqsfile>.txt binary_installer/requirements.in
|
|
||||||
```
|
|
||||||
where `<reqsfile>.txt` is whichever of
|
|
||||||
```commandline
|
|
||||||
py3.10-darwin-arm64-mps-reqs.txt
|
|
||||||
py3.10-darwin-x86_64-reqs.txt
|
|
||||||
py3.10-linux-x86_64-cuda-reqs.txt
|
|
||||||
py3.10-windows-x86_64-cuda-reqs.txt
|
|
||||||
```
|
|
||||||
matches the current OS and architecture.
|
|
||||||
> There is no way to cross-compile these. They must be done on a system matching the target OS and arch.
|
|
||||||
|
|
||||||
## <a name="step-3"></a> 3. Set github repository and branch
|
|
||||||
|
|
||||||
Once all reqs files have been collected and committed **to the branch
|
|
||||||
to be installed**, edit `binary_installer/install.sh.in` and `binary_installer/install.bat.in` so that `RELEASE_URL`
|
|
||||||
and `RELEASE_SOURCEBALL` point to the github repo and branch that is
|
|
||||||
to be installed.
|
|
||||||
|
|
||||||
For example, to install `main` branch of `InvokeAI`, they should be
|
|
||||||
set as follows:
|
|
||||||
|
|
||||||
`install.sh.in`:
|
|
||||||
```commandline
|
|
||||||
RELEASE_URL=https://github.com/invoke-ai/InvokeAI
|
|
||||||
RELEASE_SOURCEBALL=/archive/refs/heads/main.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
`install.bat.in`:
|
|
||||||
```commandline
|
|
||||||
set RELEASE_URL=https://github.com/invoke-ai/InvokeAI
|
|
||||||
set RELEASE_SOURCEBALL=/archive/refs/heads/main.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, to install `damians-cool-feature` branch of `damian0815`, set them
|
|
||||||
as follows:
|
|
||||||
|
|
||||||
`install.sh.in`:
|
|
||||||
```commandline
|
|
||||||
RELEASE_URL=https://github.com/damian0815/InvokeAI
|
|
||||||
RELEASE_SOURCEBALL=/archive/refs/heads/damians-cool-feature.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
`install.bat.in`:
|
|
||||||
```commandline
|
|
||||||
set RELEASE_URL=https://github.com/damian0815/InvokeAI
|
|
||||||
set RELEASE_SOURCEBALL=/archive/refs/heads/damians-cool-feature.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
The branch and repo specified here **must** contain the correct reqs
|
|
||||||
files. The installer zip files **do not** contain requirements files,
|
|
||||||
they are pulled from the specified branch during the installation
|
|
||||||
process.
|
|
||||||
|
|
||||||
## 4. Create zip files.
|
|
||||||
|
|
||||||
cd into the `installers/` folder and run
|
|
||||||
`./create_installers.sh`. This will create
|
|
||||||
`InvokeAI-mac_on_<branch>.zip`,
|
|
||||||
`InvokeAI-windows_on_<branch>.zip` and
|
|
||||||
`InvokeAI-linux_on_<branch>.zip`. These files can be distributed to end users.
|
|
||||||
|
|
||||||
These zips will continue to function as installers for all future
|
|
||||||
pushes to those branches, as long as necessary changes to
|
|
||||||
`requirements.in` are propagated in a timely manner to the
|
|
||||||
`py3.10-*-reqs.txt` files using pip-compile as outlined in [step
|
|
||||||
2](#step-2).
|
|
||||||
|
|
||||||
To actually install, users should unzip the appropriate zip file into an empty
|
|
||||||
folder and run `install.sh` on macOS/Linux or `install.bat` on
|
|
||||||
Windows.
|
|
@ -1,88 +1,41 @@
|
|||||||
# Overview
|
# Installation Overview
|
||||||
|
|
||||||
We offer several ways to install InvokeAI, each one suited to your
|
Before installing, review the [installation requirements] to ensure your system is set up properly.
|
||||||
experience and preferences. We suggest that everyone start by
|
|
||||||
reviewing the
|
|
||||||
[hardware](010_INSTALL_AUTOMATED.md#hardware_requirements) and
|
|
||||||
[software](010_INSTALL_AUTOMATED.md#software_requirements)
|
|
||||||
requirements, as they are the same across each install method. Then
|
|
||||||
pick the install method most suitable to your level of experience and
|
|
||||||
needs.
|
|
||||||
|
|
||||||
See the [troubleshooting
|
See the [FAQ] for frequently-encountered installation issues.
|
||||||
section](010_INSTALL_AUTOMATED.md#troubleshooting) of the automated
|
|
||||||
install guide for frequently-encountered installation issues.
|
|
||||||
|
|
||||||
This fork is supported across Linux, Windows and Macintosh. Linux users can use
|
If you need more help, join our [discord] or [create an issue].
|
||||||
either an Nvidia-based card (with CUDA support) or an AMD card (using the ROCm
|
|
||||||
driver).
|
|
||||||
|
|
||||||
|
<h2>Automatic Install</h2>
|
||||||
|
|
||||||
## **[Automated Installer (Recommended)](010_INSTALL_AUTOMATED.md)**
|
✅ The automatic install is the best way to run InvokeAI. Check out the [installation guide] to get started.
|
||||||
✅ This is the recommended installation method for first-time users.
|
|
||||||
|
|
||||||
This is a script that will install all of InvokeAI's essential
|
<h2>Manual Install</h2>
|
||||||
third party libraries and InvokeAI itself.
|
|
||||||
|
|
||||||
🖥️ **Download the latest installer .zip file here** : https://github.com/invoke-ai/InvokeAI/releases/latest
|
If you are familiar with python and want more control over the packages that are installed, you can [install InvokeAI manually via PyPI].
|
||||||
|
|
||||||
- *Look for the file labelled "InvokeAI-installer-v4.X.X.zip" at the bottom of the page*
|
<h2>Developer Install</h2>
|
||||||
- If you experience issues, read through the full [installation instructions](010_INSTALL_AUTOMATED.md) to make sure you have met all of the installation requirements. If you need more help, join the [Discord](discord.gg/invoke-ai) or create an issue on [Github](https://github.com/invoke-ai/InvokeAI).
|
|
||||||
|
|
||||||
|
If you want to contribute to InvokeAI, consult the [developer install guide].
|
||||||
|
|
||||||
|
<h2>Docker Install</h2>
|
||||||
|
|
||||||
## **[Manual Installation](020_INSTALL_MANUAL.md)**
|
|
||||||
This method is recommended for experienced users and developers.
|
|
||||||
|
|
||||||
In this method you will manually run the commands needed to install
|
|
||||||
InvokeAI and its dependencies. We offer two recipes: one suited to
|
|
||||||
those who prefer the `conda` tool, and one suited to those who prefer
|
|
||||||
`pip` and Python virtual environments. In our hands the pip install
|
|
||||||
is faster and more reliable, but your mileage may vary.
|
|
||||||
Note that the conda installation method is currently deprecated and
|
|
||||||
will not be supported at some point in the future.
|
|
||||||
|
|
||||||
## **[Docker Installation](040_INSTALL_DOCKER.md)**
|
|
||||||
This method is recommended for those familiar with running Docker containers.
|
This method is recommended for those familiar with running Docker containers.
|
||||||
|
|
||||||
We offer a method for creating Docker containers containing InvokeAI and its dependencies. This method is recommended for individuals with experience with Docker containers and understand the pluses and minuses of a container-based install.
|
We offer a method for creating Docker containers containing InvokeAI and its dependencies. This method is recommended for individuals with experience with Docker containers and understand the pluses and minuses of a container-based install.
|
||||||
|
|
||||||
## Other Installation Guides
|
See the [docker installation guide].
|
||||||
- [PyPatchMatch](060_INSTALL_PATCHMATCH.md)
|
|
||||||
- [XFormers](070_INSTALL_XFORMERS.md)
|
|
||||||
- [CUDA and ROCm Drivers](030_INSTALL_CUDA_AND_ROCM.md)
|
|
||||||
- [Installing New Models](050_INSTALLING_MODELS.md)
|
|
||||||
|
|
||||||
## :fontawesome-solid-computer: Hardware Requirements
|
<h2>Other Installation Guides</h2>
|
||||||
|
|
||||||
### :octicons-cpu-24: System
|
- [PyPatchMatch](060_INSTALL_PATCHMATCH.md)
|
||||||
|
- [Installing Models](050_INSTALLING_MODELS.md)
|
||||||
You wil need one of the following:
|
|
||||||
|
|
||||||
- :simple-nvidia: An NVIDIA-based graphics card with 4 GB or more VRAM memory.
|
|
||||||
- :simple-amd: An AMD-based graphics card with 4 GB or more VRAM memory (Linux
|
|
||||||
only)
|
|
||||||
- :fontawesome-brands-apple: An Apple computer with an M1 chip.
|
|
||||||
|
|
||||||
** SDXL 1.0 Requirements*
|
|
||||||
To use SDXL, user must have one of the following:
|
|
||||||
- :simple-nvidia: An NVIDIA-based graphics card with 8 GB or more VRAM memory.
|
|
||||||
- :simple-amd: An AMD-based graphics card with 16 GB or more VRAM memory (Linux
|
|
||||||
only)
|
|
||||||
- :fontawesome-brands-apple: An Apple computer with an M1 chip.
|
|
||||||
|
|
||||||
|
|
||||||
### :fontawesome-solid-memory: Memory and Disk
|
|
||||||
|
|
||||||
- At least 12 GB Main Memory RAM.
|
|
||||||
- At least 18 GB of free disk space for the machine learning model, Python, and
|
|
||||||
all its dependencies.
|
|
||||||
|
|
||||||
We do **not recommend** the following video cards due to issues with their
|
|
||||||
running in half-precision mode and having insufficient VRAM to render 512x512
|
|
||||||
images in full-precision mode:
|
|
||||||
|
|
||||||
- NVIDIA 10xx series cards such as the 1080ti
|
|
||||||
- GTX 1650 series cards
|
|
||||||
- GTX 1660 series cards
|
|
||||||
|
|
||||||
|
[install InvokeAI manually via PyPI]: 020_INSTALL_MANUAL.md
|
||||||
|
[developer install guide]: INSTALL_DEVELOPMENT.md
|
||||||
|
[docker installation guide]: 040_INSTALL_DOCKER.md
|
||||||
|
[installation guide]: 010_INSTALL_AUTOMATED.md
|
||||||
|
[FAQ]: ../help/FAQ.md
|
||||||
|
[discord]: discord.gg/invoke-ai
|
||||||
|
[create an issue]: https://github.com/invoke-ai/InvokeAI/issues
|
||||||
|
[installation requirements]: INSTALL_REQUIREMENTS.md
|
||||||
|
36
docs/installation/INSTALL_DEVELOPMENT.md
Normal file
36
docs/installation/INSTALL_DEVELOPMENT.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Developer Install
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
|
||||||
|
InvokeAI uses a SQLite database. By running on `main`, you accept responsibility for your database. This
|
||||||
|
means making regular backups (especially before pulling) and/or fixing it yourself in the event that a
|
||||||
|
PR introduces a schema change.
|
||||||
|
|
||||||
|
If you don't need persistent backend storage, you can use an ephemeral in-memory database by setting
|
||||||
|
`use_memory_db: true` in your `invokeai.yaml` file. You'll also want to set `scan_models_on_startup: true`
|
||||||
|
so that your models are registered on startup.
|
||||||
|
|
||||||
|
If this is untenable, you should run the application via the official installer or a manual install of the
|
||||||
|
python package from PyPI. These releases will not break your database.
|
||||||
|
|
||||||
|
If you have an interest in how InvokeAI works, or you would like to add features or bugfixes, you are encouraged to install the source code for InvokeAI.
|
||||||
|
|
||||||
|
!!! info "Why do I need the frontend toolchain?"
|
||||||
|
|
||||||
|
The repo doesn't contain a build of the frontend. You'll be responsible for rebuilding it (or running it in dev mode) to use the app, as described in the [frontend dev toolchain] docs.
|
||||||
|
|
||||||
|
<h2> Installation </h2>
|
||||||
|
|
||||||
|
1. [Fork and clone] the [InvokeAI repo].
|
||||||
|
1. Follow the [manual installation] docs to create a new virtual environment for the development install.
|
||||||
|
- When installing the InvokeAI package, add `-e` to the command so you get an [editable install].
|
||||||
|
1. Install the [frontend dev toolchain] and do a production build of the UI as described.
|
||||||
|
1. You can now run the app as described in the [manual installation] docs.
|
||||||
|
|
||||||
|
As described in the [frontend dev toolchain] docs, you can run the UI using a dev server. If you do this, you won't need to continually rebuild the frontend. Instead, you run the dev server and use the app with the server URL it provides.
|
||||||
|
|
||||||
|
[Fork and clone]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo
|
||||||
|
[InvokeAI repo]: https://github.com/invoke-ai/InvokeAI
|
||||||
|
[frontend dev toolchain]: ../contributing/frontend/OVERVIEW.md
|
||||||
|
[manual installation]: installation/020_INSTALL_MANUAL.md
|
||||||
|
[editable install]: https://pip.pypa.io/en/latest/cli/pip_install/#cmdoption-e
|
181
docs/installation/INSTALL_REQUIREMENTS.md
Normal file
181
docs/installation/INSTALL_REQUIREMENTS.md
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
# Requirements
|
||||||
|
|
||||||
|
## GPU
|
||||||
|
|
||||||
|
!!! warning "Problematic Nvidia GPUs"
|
||||||
|
|
||||||
|
We do not recommend these GPUs. They cannot operate with half precision, but have insufficient VRAM to generate 512x512 images at full precision.
|
||||||
|
|
||||||
|
- NVIDIA 10xx series cards such as the 1080 TI
|
||||||
|
- GTX 1650 series cards
|
||||||
|
- GTX 1660 series cards
|
||||||
|
|
||||||
|
Invoke runs best with a dedicated GPU, but will fall back to running on CPU, albeit much slower. You'll need a beefier GPU for SDXL.
|
||||||
|
|
||||||
|
!!! example "Stable Diffusion 1.5"
|
||||||
|
|
||||||
|
=== "Nvidia"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any GPU with at least 4GB VRAM.
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "AMD"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any GPU with at least 4GB VRAM. Linux only.
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Mac"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any Apple Silicon Mac with at least 8GB memory.
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! example "Stable Diffusion XL"
|
||||||
|
|
||||||
|
=== "Nvidia"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any GPU with at least 8GB VRAM. Linux only.
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "AMD"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any GPU with at least 16GB VRAM.
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Mac"
|
||||||
|
|
||||||
|
```
|
||||||
|
Any Apple Silicon Mac with at least 16GB memory.
|
||||||
|
```
|
||||||
|
|
||||||
|
## RAM
|
||||||
|
|
||||||
|
At least 12GB of RAM.
|
||||||
|
|
||||||
|
## Disk
|
||||||
|
|
||||||
|
SSDs will, of course, offer the best performance.
|
||||||
|
|
||||||
|
The base application disk usage depends on the torch backend.
|
||||||
|
|
||||||
|
!!! example "Disk"
|
||||||
|
|
||||||
|
=== "Nvidia (CUDA)"
|
||||||
|
|
||||||
|
```
|
||||||
|
~6.5GB
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "AMD (ROCm)"
|
||||||
|
|
||||||
|
```
|
||||||
|
~12GB
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Mac (MPS)"
|
||||||
|
|
||||||
|
```
|
||||||
|
~3.5GB
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll need to set aside some space for images, depending on how much you generate. A couple GB is enough to get started.
|
||||||
|
|
||||||
|
You'll need a good chunk of space for models. Even if you only install the most popular models and the usual support models (ControlNet, IP Adapter ,etc), you will quickly hit 50GB of models.
|
||||||
|
|
||||||
|
!!! info "`tmpfs` on Linux"
|
||||||
|
|
||||||
|
If your temporary directory is mounted as a `tmpfs`, ensure it has sufficient space.
|
||||||
|
|
||||||
|
## Python
|
||||||
|
|
||||||
|
Invoke requires python 3.10 or 3.11. If you don't already have one of these versions installed, we suggest installing 3.11, as it will be supported for longer.
|
||||||
|
|
||||||
|
Check that your system has an up-to-date Python installed by running `python --version` in the terminal (Linux, macOS) or cmd/powershell (Windows).
|
||||||
|
|
||||||
|
<h3>Installing Python (Windows)</h3>
|
||||||
|
|
||||||
|
- Install python 3.11 with [an official installer].
|
||||||
|
- The installer includes an option to add python to your PATH. Be sure to enable this. If you missed it, re-run the installer, choose to modify an existing installation, and tick that checkbox.
|
||||||
|
- You may need to install [Microsoft Visual C++ Redistributable].
|
||||||
|
|
||||||
|
<h3>Installing Python (macOS)</h3>
|
||||||
|
|
||||||
|
- Install python 3.11 with [an official installer].
|
||||||
|
- If model installs fail with a certificate error, you may need to run this command (changing the python version to match what you have installed): `/Applications/Python\ 3.10/Install\ Certificates.command`
|
||||||
|
- If you haven't already, you will need to install the XCode CLI Tools by running `xcode-select --install` in a terminal.
|
||||||
|
|
||||||
|
<h3>Installing Python (Linux)</h3>
|
||||||
|
|
||||||
|
- Follow the [linux install instructions], being sure to install python 3.11.
|
||||||
|
- You'll need to install `libglib2.0-0` and `libgl1-mesa-glx` for OpenCV to work. For example, on a Debian system: `sudo apt update && sudo apt install -y libglib2.0-0 libgl1-mesa-glx`
|
||||||
|
|
||||||
|
## Drivers
|
||||||
|
|
||||||
|
If you have an Nvidia or AMD GPU, you may need to manually install drivers or other support packages for things to work well or at all.
|
||||||
|
|
||||||
|
### Nvidia
|
||||||
|
|
||||||
|
Run `nvidia-smi` on your system's command line to verify that drivers and CUDA are installed. If this command fails, or doesn't report versions, you will need to install drivers.
|
||||||
|
|
||||||
|
Go to the [CUDA Toolkit Downloads] and carefully follow the instructions for your system to get everything installed.
|
||||||
|
|
||||||
|
Confirm that `nvidia-smi` displays driver and CUDA versions after installation.
|
||||||
|
|
||||||
|
#### Linux - via Nvidia Container Runtime
|
||||||
|
|
||||||
|
An alternative to installing CUDA locally is to use the [Nvidia Container Runtime] to run the application in a container.
|
||||||
|
|
||||||
|
#### Windows - Nvidia cuDNN DLLs
|
||||||
|
|
||||||
|
An out-of-date cuDNN library can greatly hamper performance on 30-series and 40-series cards. Check with the community on discord to compare your `it/s` if you think you may need this fix.
|
||||||
|
|
||||||
|
First, locate the destination for the DLL files and make a quick back up:
|
||||||
|
|
||||||
|
1. Find your InvokeAI installation folder, e.g. `C:\Users\Username\InvokeAI\`.
|
||||||
|
1. Open the `.venv` folder, e.g. `C:\Users\Username\InvokeAI\.venv` (you may need to show hidden files to see it).
|
||||||
|
1. Navigate deeper to the `torch` package, e.g. `C:\Users\Username\InvokeAI\.venv\Lib\site-packages\torch`.
|
||||||
|
1. Copy the `lib` folder inside `torch` and back it up somewhere.
|
||||||
|
|
||||||
|
Next, download and copy the updated cuDNN DLLs:
|
||||||
|
|
||||||
|
1. Go to <https://developer.nvidia.com/cudnn>.
|
||||||
|
1. Create an account if needed and log in.
|
||||||
|
1. Choose the newest version of cuDNN that works with your GPU architecture. Consult the [cuDNN support matrix] to determine the correct version for your GPU.
|
||||||
|
1. Download the latest version and extract it.
|
||||||
|
1. Find the `bin` folder, e.g. `cudnn-windows-x86_64-SOME_VERSION\bin`.
|
||||||
|
1. Copy and paste the `.dll` files into the `lib` folder you located earlier. Replace files when prompted.
|
||||||
|
|
||||||
|
If, after restarting the app, this doesn't improve your performance, either restore your back up or re-run the installer to reset `torch` back to its original state.
|
||||||
|
|
||||||
|
### AMD
|
||||||
|
|
||||||
|
!!! info "Linux Only"
|
||||||
|
|
||||||
|
AMD GPUs are supported on Linux only, due to ROCm (the AMD equivalent of CUDA) support being Linux only.
|
||||||
|
|
||||||
|
!!! warning "Bumps Ahead"
|
||||||
|
|
||||||
|
While the application does run on AMD GPUs, there are occasional bumps related to spotty torch support.
|
||||||
|
|
||||||
|
Run `rocm-smi` on your system's command line verify that drivers and ROCm are installed. If this command fails, or doesn't report versions, you will need to install them.
|
||||||
|
|
||||||
|
Go to the [ROCm Documentation] and carefully follow the instructions for your system to get everything installed.
|
||||||
|
|
||||||
|
Confirm that `rocm-smi` displays driver and CUDA versions after installation.
|
||||||
|
|
||||||
|
#### Linux - via Docker Container
|
||||||
|
|
||||||
|
An alternative to installing ROCm locally is to use a [ROCm docker container] to run the application in a container.
|
||||||
|
|
||||||
|
[ROCm docker container]: https://github.com/ROCm/ROCm-docker
|
||||||
|
[ROCm Documentation]: https://rocm.docs.amd.com/projects/install-on-linux/en/latest/tutorial/quick-start.html
|
||||||
|
[cuDNN support matrix]: https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html
|
||||||
|
[Nvidia Container Runtime]: https://developer.nvidia.com/container-runtime
|
||||||
|
[linux install instructions]: https://docs.python-guide.org/starting/install3/linux/
|
||||||
|
[Microsoft Visual C++ Redistributable]: https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170
|
||||||
|
[an official installer]: https://www.python.org/downloads/release/python-3118/
|
||||||
|
[CUDA Toolkit Downloads]: https://developer.nvidia.com/cuda-downloads
|
@ -1,64 +0,0 @@
|
|||||||
---
|
|
||||||
title: InvokeAI Binary Installer
|
|
||||||
---
|
|
||||||
|
|
||||||
The InvokeAI binary installer is a shell script that will install InvokeAI onto a stock
|
|
||||||
computer running recent versions of Linux, MacOSX or Windows. It will leave you
|
|
||||||
with a version that runs a stable version of InvokeAI. When a new version of
|
|
||||||
InvokeAI is released, you will download and reinstall the new version.
|
|
||||||
|
|
||||||
If you wish to tinker with unreleased versions of InvokeAI that introduce
|
|
||||||
potentially unstable new features, you should consider using the
|
|
||||||
[source installer](INSTALL_SOURCE.md) or one of the
|
|
||||||
[manual install](../020_INSTALL_MANUAL.md) methods.
|
|
||||||
|
|
||||||
**Important Caveats**
|
|
||||||
- This script does not support AMD GPUs. For Linux AMD support,
|
|
||||||
please use the manual or source code installer methods.
|
|
||||||
|
|
||||||
- This script has difficulty on some Macintosh machines
|
|
||||||
that have previously been used for Python development due to
|
|
||||||
conflicting development tools versions. Mac developers may wish
|
|
||||||
to try the source code installer or one of the manual methods instead.
|
|
||||||
|
|
||||||
!!! todo
|
|
||||||
|
|
||||||
Before you begin, make sure that you meet
|
|
||||||
the[hardware requirements](/#hardware-requirements) and has the
|
|
||||||
appropriate GPU drivers installed. In particular, if you are a Linux user with
|
|
||||||
an AMD GPU installed, you may need to install the
|
|
||||||
[ROCm-driver](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html).
|
|
||||||
|
|
||||||
Installation requires roughly 18G of free disk space to load the libraries and
|
|
||||||
recommended model weights files.
|
|
||||||
|
|
||||||
## Steps to Install
|
|
||||||
|
|
||||||
1. Download the
|
|
||||||
[latest release](https://github.com/invoke-ai/InvokeAI/releases/latest) of
|
|
||||||
InvokeAI's installer for your platform. Look for a file named `InvokeAI-binary-<your platform>.zip`
|
|
||||||
|
|
||||||
2. Place the downloaded package someplace where you have plenty of HDD space,
|
|
||||||
and have full permissions (i.e. `~/` on Lin/Mac; your home folder on Windows)
|
|
||||||
|
|
||||||
3. Extract the 'InvokeAI' folder from the downloaded package
|
|
||||||
|
|
||||||
4. Open the extracted 'InvokeAI' folder
|
|
||||||
|
|
||||||
5. Double-click 'install.bat' (Windows), or 'install.sh' (Lin/Mac) (or run from
|
|
||||||
a terminal)
|
|
||||||
|
|
||||||
6. Follow the prompts
|
|
||||||
|
|
||||||
7. After installation, please run the 'invoke.bat' file (on Windows) or
|
|
||||||
'invoke.sh' file (on Linux/Mac) to start InvokeAI.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If you run into problems during or after installation, the InvokeAI team is
|
|
||||||
available to help you. Either create an
|
|
||||||
[Issue](https://github.com/invoke-ai/InvokeAI/issues) at our GitHub site, or
|
|
||||||
make a request for help on the "bugs-and-support" channel of our
|
|
||||||
[Discord server](https://discord.gg/ZmtBAhwWhy). We are a 100% volunteer
|
|
||||||
organization, but typically somebody will be available to help you within 24
|
|
||||||
hours, and often much sooner.
|
|
@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
title: Running InvokeAI on Google Colab using a Jupyter Notebook
|
|
||||||
---
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
We have a [Jupyter
|
|
||||||
notebook](https://github.com/invoke-ai/InvokeAI/blob/main/notebooks/Stable_Diffusion_AI_Notebook.ipynb)
|
|
||||||
with cell-by-cell installation steps. It will download the code in
|
|
||||||
this repo as one of the steps, so instead of cloning this repo, simply
|
|
||||||
download the notebook from the link above and load it up in VSCode
|
|
||||||
(with the appropriate extensions installed)/Jupyter/JupyterLab and
|
|
||||||
start running the cells one-by-one.
|
|
||||||
|
|
||||||
!!! Note "you will need NVIDIA drivers, Python 3.10, and Git installed beforehand"
|
|
||||||
|
|
||||||
## Running Online On Google Colabotary
|
|
||||||
[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/invoke-ai/InvokeAI/blob/main/notebooks/Stable_Diffusion_AI_Notebook.ipynb)
|
|
||||||
|
|
||||||
## Running Locally (Cloning)
|
|
||||||
|
|
||||||
1. Install the Jupyter Notebook python library (one-time):
|
|
||||||
pip install jupyter
|
|
||||||
|
|
||||||
2. Clone the InvokeAI repository:
|
|
||||||
git clone https://github.com/invoke-ai/InvokeAI.git
|
|
||||||
cd invoke-ai
|
|
||||||
3. Create a virtual environment using conda:
|
|
||||||
conda create -n invoke jupyter
|
|
||||||
4. Activate the environment and start the Jupyter notebook:
|
|
||||||
conda activate invoke
|
|
||||||
jupyter notebook
|
|
@ -1,135 +0,0 @@
|
|||||||
---
|
|
||||||
title: Manual Installation, Linux
|
|
||||||
---
|
|
||||||
|
|
||||||
# :fontawesome-brands-linux: Linux
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. You will need to install the following prerequisites if they are not already
|
|
||||||
available. Use your operating system's preferred installer.
|
|
||||||
|
|
||||||
- Python (version 3.8.5 recommended; higher may work)
|
|
||||||
- git
|
|
||||||
|
|
||||||
2. Install the Python Anaconda environment manager.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
~$ wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh
|
|
||||||
~$ chmod +x Anaconda3-2022.05-Linux-x86_64.sh
|
|
||||||
~$ ./Anaconda3-2022.05-Linux-x86_64.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
After installing anaconda, you should log out of your system and log back
|
|
||||||
in. If the installation worked, your command prompt will be prefixed by the
|
|
||||||
name of the current anaconda environment - `(base)`.
|
|
||||||
|
|
||||||
3. Copy the InvokeAI source code from GitHub:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(base) ~$ git clone https://github.com/invoke-ai/InvokeAI.git
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create InvokeAI folder where you will follow the rest of the
|
|
||||||
steps.
|
|
||||||
|
|
||||||
4. Enter the newly-created InvokeAI folder. From this step forward make sure
|
|
||||||
that you are working in the InvokeAI directory!
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(base) ~$ cd InvokeAI
|
|
||||||
(base) ~/InvokeAI$
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Use anaconda to copy necessary python packages, create a new python
|
|
||||||
environment named `invokeai` and then activate the environment.
|
|
||||||
|
|
||||||
!!! todo "For systems with a CUDA (Nvidia) card:"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(base) rm -rf src # (this is a precaution in case there is already a src directory)
|
|
||||||
(base) ~/InvokeAI$ conda env create -f environment-cuda.yml
|
|
||||||
(base) ~/InvokeAI$ conda activate invokeai
|
|
||||||
(invokeai) ~/InvokeAI$
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "For systems with an AMD card (using ROCm driver):"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(base) rm -rf src # (this is a precaution in case there is already a src directory)
|
|
||||||
(base) ~/InvokeAI$ conda env create -f environment-AMD.yml
|
|
||||||
(base) ~/InvokeAI$ conda activate invokeai
|
|
||||||
(invokeai) ~/InvokeAI$
|
|
||||||
```
|
|
||||||
|
|
||||||
After these steps, your command prompt will be prefixed by `(invokeai)` as
|
|
||||||
shown above.
|
|
||||||
|
|
||||||
6. Load the big stable diffusion weights files and a couple of smaller
|
|
||||||
machine-learning models:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(invokeai) ~/InvokeAI$ python3 scripts/configure_invokeai.py
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
This script will lead you through the process of creating an account on Hugging Face,
|
|
||||||
accepting the terms and conditions of the Stable Diffusion model license,
|
|
||||||
and obtaining an access token for downloading. It will then download and
|
|
||||||
install the weights files for you.
|
|
||||||
|
|
||||||
Please look [here](../020_INSTALL_MANUAL.md) for a manual process for doing
|
|
||||||
the same thing.
|
|
||||||
|
|
||||||
7. Start generating images!
|
|
||||||
|
|
||||||
!!! todo "Run InvokeAI!"
|
|
||||||
|
|
||||||
!!! warning "IMPORTANT"
|
|
||||||
|
|
||||||
Make sure that the conda environment is activated, which should create
|
|
||||||
`(invokeai)` in front of your prompt!
|
|
||||||
|
|
||||||
=== "CLI"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "local Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Public Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web --host 0.0.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
To use an alternative model you may invoke the `!switch` command in
|
|
||||||
the CLI, or pass `--model <model_name>` during `invoke.py` launch for
|
|
||||||
either the CLI or the Web UI. See [Command Line
|
|
||||||
Client](../../deprecated/CLI.md#model-selection-and-importation). The
|
|
||||||
model names are defined in `configs/models.yaml`.
|
|
||||||
|
|
||||||
8. Subsequently, to relaunch the script, be sure to run "conda activate
|
|
||||||
invokeai" (step 5, second command), enter the `InvokeAI` directory, and then
|
|
||||||
launch the invoke script (step 8). If you forget to activate the 'invokeai'
|
|
||||||
environment, the script will fail with multiple `ModuleNotFound` errors.
|
|
||||||
|
|
||||||
## Updating to newer versions of the script
|
|
||||||
|
|
||||||
This distribution is changing rapidly. If you used the `git clone` method
|
|
||||||
(step 5) to download the InvokeAI directory, then to update to the latest and
|
|
||||||
greatest version, launch the Anaconda window, enter `InvokeAI` and type:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(invokeai) ~/InvokeAI$ git pull
|
|
||||||
(invokeai) ~/InvokeAI$ rm -rf src # prevents conda freezing errors
|
|
||||||
(invokeai) ~/InvokeAI$ conda env update -f environment.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
This will bring your local copy into sync with the remote one.
|
|
@ -1,525 +0,0 @@
|
|||||||
---
|
|
||||||
title: Manual Installation, macOS
|
|
||||||
---
|
|
||||||
|
|
||||||
# :fontawesome-brands-apple: macOS
|
|
||||||
|
|
||||||
Invoke AI runs quite well on M1 Macs and we have a number of M1 users in the
|
|
||||||
community.
|
|
||||||
|
|
||||||
While the repo does run on Intel Macs, we only have a couple reports. If you
|
|
||||||
have an Intel Mac and run into issues, please create an issue on Github and we
|
|
||||||
will do our best to help.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- macOS 12.3 Monterey or later
|
|
||||||
- About 10GB of storage (and 10GB of data if your internet connection has data
|
|
||||||
caps)
|
|
||||||
- Any M1 Macs or an Intel Macs with 4GB+ of VRAM (ideally more)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
!!! todo "Homebrew"
|
|
||||||
|
|
||||||
First you will install the "brew" package manager. Skip this if brew is already installed.
|
|
||||||
|
|
||||||
```bash title="install brew (and Xcode command line tools)"
|
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "Conda Installation"
|
|
||||||
|
|
||||||
Now there are two different ways to set up the Python (miniconda) environment:
|
|
||||||
|
|
||||||
1. Standalone
|
|
||||||
2. with pyenv
|
|
||||||
|
|
||||||
If you don't know what we are talking about, choose Standalone. If you are familiar with python environments, choose "with pyenv"
|
|
||||||
|
|
||||||
=== "Standalone"
|
|
||||||
|
|
||||||
```bash title="Install cmake, protobuf, and rust"
|
|
||||||
brew install cmake protobuf rust
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash title="Clone the InvokeAI repository"
|
|
||||||
# Clone the Invoke AI repo
|
|
||||||
git clone https://github.com/invoke-ai/InvokeAI.git
|
|
||||||
cd InvokeAI
|
|
||||||
```
|
|
||||||
|
|
||||||
Choose the appropriate architecture for your system and install miniconda:
|
|
||||||
|
|
||||||
=== "M1 arm64"
|
|
||||||
|
|
||||||
```bash title="Install miniconda for M1 arm64"
|
|
||||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh \
|
|
||||||
-o Miniconda3-latest-MacOSX-arm64.sh
|
|
||||||
/bin/bash Miniconda3-latest-MacOSX-arm64.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Intel x86_64"
|
|
||||||
|
|
||||||
```bash title="Install miniconda for Intel"
|
|
||||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh \
|
|
||||||
-o Miniconda3-latest-MacOSX-x86_64.sh
|
|
||||||
/bin/bash Miniconda3-latest-MacOSX-x86_64.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "with pyenv"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install pyenv-virtualenv
|
|
||||||
pyenv install anaconda3-2022.05
|
|
||||||
pyenv virtualenv anaconda3-2022.05
|
|
||||||
eval "$(pyenv init -)"
|
|
||||||
pyenv activate anaconda3-2022.05
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "Clone the Invoke AI repo"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/invoke-ai/InvokeAI.git
|
|
||||||
cd InvokeAI
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "Create the environment & install packages"
|
|
||||||
|
|
||||||
=== "M1 Mac"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 conda env create -f environment-mac.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Intel x86_64 Mac"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-64 conda env create -f environment-mac.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Activate the environment (you need to do this every time you want to run SD)
|
|
||||||
conda activate invokeai
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! info
|
|
||||||
|
|
||||||
`export PIP_EXISTS_ACTION=w` is a precaution to fix `conda env
|
|
||||||
create -f environment-mac.yml` never finishing in some situations. So
|
|
||||||
it isn't required but won't hurt.
|
|
||||||
|
|
||||||
!!! todo "Download the model weight files"
|
|
||||||
|
|
||||||
The `configure_invokeai.py` script downloads and installs the model weight
|
|
||||||
files for you. It will lead you through the process of getting a Hugging Face
|
|
||||||
account, accepting the Stable Diffusion model weight license agreement, and
|
|
||||||
creating a download token:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# This will take some time, depending on the speed of your internet connection
|
|
||||||
# and will consume about 10GB of space
|
|
||||||
python scripts/configure_invokeai.py
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "Run InvokeAI!"
|
|
||||||
|
|
||||||
!!! warning "IMPORTANT"
|
|
||||||
|
|
||||||
Make sure that the conda environment is activated, which should create
|
|
||||||
`(invokeai)` in front of your prompt!
|
|
||||||
|
|
||||||
=== "CLI"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "local Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Public Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web --host 0.0.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
To use an alternative model you may invoke the `!switch` command in
|
|
||||||
the CLI, or pass `--model <model_name>` during `invoke.py` launch for
|
|
||||||
either the CLI or the Web UI. See [Command Line
|
|
||||||
Client](../../deprecated/CLI.md#model-selection-and-importation). The
|
|
||||||
model names are defined in `configs/models.yaml`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Common problems
|
|
||||||
|
|
||||||
After you followed all the instructions and try to run invoke.py, you might get
|
|
||||||
several errors. Here's the errors I've seen and found solutions for.
|
|
||||||
|
|
||||||
### Is it slow?
|
|
||||||
|
|
||||||
```bash title="Be sure to specify 1 sample and 1 iteration."
|
|
||||||
python ./scripts/orig_scripts/txt2img.py \
|
|
||||||
--prompt "ocean" \
|
|
||||||
--ddim_steps 5 \
|
|
||||||
--n_samples 1 \
|
|
||||||
--n_iter 1
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Doesn't work anymore?
|
|
||||||
|
|
||||||
PyTorch nightly includes support for MPS. Because of this, this setup is
|
|
||||||
inherently unstable. One morning I woke up and it no longer worked no matter
|
|
||||||
what I did until I switched to miniforge. However, I have another Mac that works
|
|
||||||
just fine with Anaconda. If you can't get it to work, please search a little
|
|
||||||
first because many of the errors will get posted and solved. If you can't find a
|
|
||||||
solution please [create an issue](https://github.com/invoke-ai/InvokeAI/issues).
|
|
||||||
|
|
||||||
One debugging step is to update to the latest version of PyTorch nightly.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda install \
|
|
||||||
pytorch \
|
|
||||||
torchvision \
|
|
||||||
-c pytorch-nightly \
|
|
||||||
-n invokeai
|
|
||||||
```
|
|
||||||
|
|
||||||
If it takes forever to run `conda env create -f environment-mac.yml`, try this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clean -f
|
|
||||||
conda clean \
|
|
||||||
--yes \
|
|
||||||
--all
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you could try to completley reset Anaconda:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda update \
|
|
||||||
--force-reinstall \
|
|
||||||
-y \
|
|
||||||
-n base \
|
|
||||||
-c defaults conda
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### "No module named cv2", torch, 'invokeai', 'transformers', 'taming', etc
|
|
||||||
|
|
||||||
There are several causes of these errors:
|
|
||||||
|
|
||||||
1. Did you remember to `conda activate invokeai`? If your terminal prompt begins
|
|
||||||
with "(invokeai)" then you activated it. If it begins with "(base)" or
|
|
||||||
something else you haven't.
|
|
||||||
|
|
||||||
2. You might've run `./scripts/configure_invokeai.py` or `./scripts/invoke.py`
|
|
||||||
instead of `python ./scripts/configure_invokeai.py` or
|
|
||||||
`python ./scripts/invoke.py`. The cause of this error is long so it's below.
|
|
||||||
|
|
||||||
<!-- I could not find out where the error is, otherwise would have marked it as a footnote -->
|
|
||||||
|
|
||||||
3. if it says you're missing taming you need to rebuild your virtual
|
|
||||||
environment.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda deactivate
|
|
||||||
conda env remove -n invokeai
|
|
||||||
conda env create -f environment-mac.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
4. If you have activated the invokeai virtual environment and tried rebuilding
|
|
||||||
it, maybe the problem could be that I have something installed that you don't
|
|
||||||
and you'll just need to manually install it. Make sure you activate the
|
|
||||||
virtual environment so it installs there instead of globally.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda activate invokeai
|
|
||||||
pip install <package name>
|
|
||||||
```
|
|
||||||
|
|
||||||
You might also need to install Rust (I mention this again below).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How many snakes are living in your computer?
|
|
||||||
|
|
||||||
You might have multiple Python installations on your system, in which case it's
|
|
||||||
important to be explicit and consistent about which one to use for a given
|
|
||||||
project. This is because virtual environments are coupled to the Python that
|
|
||||||
created it (and all the associated 'system-level' modules).
|
|
||||||
|
|
||||||
When you run `python` or `python3`, your shell searches the colon-delimited
|
|
||||||
locations in the `PATH` environment variable (`echo $PATH` to see that list) in
|
|
||||||
that order - first match wins. You can ask for the location of the first
|
|
||||||
`python3` found in your `PATH` with the `which` command like this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% which python3
|
|
||||||
/usr/bin/python3
|
|
||||||
```
|
|
||||||
|
|
||||||
Anything in `/usr/bin` is
|
|
||||||
[part of the OS](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6).
|
|
||||||
However, `/usr/bin/python3` is not actually python3, but rather a stub that
|
|
||||||
offers to install Xcode (which includes python 3). If you have Xcode installed
|
|
||||||
already, `/usr/bin/python3` will execute
|
|
||||||
`/Library/Developer/CommandLineTools/usr/bin/python3` or
|
|
||||||
`/Applications/Xcode.app/Contents/Developer/usr/bin/python3` (depending on which
|
|
||||||
Xcode you've selected with `xcode-select`).
|
|
||||||
|
|
||||||
Note that `/usr/bin/python` is an entirely different python - specifically,
|
|
||||||
python 2. Note: starting in macOS 12.3, `/usr/bin/python` no longer exists.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% which python3
|
|
||||||
/opt/homebrew/bin/python3
|
|
||||||
```
|
|
||||||
|
|
||||||
If you installed python3 with Homebrew and you've modified your path to search
|
|
||||||
for Homebrew binaries before system ones, you'll see the above path.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% which python
|
|
||||||
/opt/anaconda3/bin/python
|
|
||||||
```
|
|
||||||
|
|
||||||
If you have Anaconda installed, you will see the above path. There is a
|
|
||||||
`/opt/anaconda3/bin/python3` also.
|
|
||||||
|
|
||||||
We expect that `/opt/anaconda3/bin/python` and `/opt/anaconda3/bin/python3`
|
|
||||||
should actually be the _same python_, which you can verify by comparing the
|
|
||||||
output of `python3 -V` and `python -V`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(invokeai) % which python
|
|
||||||
/Users/name/miniforge3/envs/invokeai/bin/python
|
|
||||||
```
|
|
||||||
|
|
||||||
The above is what you'll see if you have miniforge and correctly activated the
|
|
||||||
invokeai environment, while usingd the standalone setup instructions above.
|
|
||||||
|
|
||||||
If you otherwise installed via pyenv, you will get this result:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(anaconda3-2022.05) % which python
|
|
||||||
/Users/name/.pyenv/shims/python
|
|
||||||
```
|
|
||||||
|
|
||||||
It's all a mess and you should know
|
|
||||||
[how to modify the path environment variable](https://support.apple.com/guide/terminal/use-environment-variables-apd382cc5fa-4f58-4449-b20a-41c53c006f8f/mac)
|
|
||||||
if you want to fix it. Here's a brief hint of the most common ways you can
|
|
||||||
modify it (don't really have the time to explain it all here).
|
|
||||||
|
|
||||||
- ~/.zshrc
|
|
||||||
- ~/.bash_profile
|
|
||||||
- ~/.bashrc
|
|
||||||
- /etc/paths.d
|
|
||||||
- /etc/path
|
|
||||||
|
|
||||||
Which one you use will depend on what you have installed, except putting a file
|
|
||||||
in /etc/paths.d - which also is the way I prefer to do.
|
|
||||||
|
|
||||||
Finally, to answer the question posed by this section's title, it may help to
|
|
||||||
list all of the `python` / `python3` things found in `$PATH` instead of just the
|
|
||||||
first hit. To do so, add the `-a` switch to `which`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% which -a python3
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
This will show a list of all binaries which are actually available in your PATH.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Debugging?
|
|
||||||
|
|
||||||
Tired of waiting for your renders to finish before you can see if it works?
|
|
||||||
Reduce the steps! The image quality will be horrible but at least you'll get
|
|
||||||
quick feedback.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python ./scripts/txt2img.py \
|
|
||||||
--prompt "ocean" \
|
|
||||||
--ddim_steps 5 \
|
|
||||||
--n_samples 1 \
|
|
||||||
--n_iter 1
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### OSError: Can't load tokenizer for 'openai/clip-vit-large-patch14'
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/configure_invokeai.py
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### "The operator [name] is not current implemented for the MPS device." (sic)
|
|
||||||
|
|
||||||
!!! example "example error"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
... NotImplementedError: The operator 'aten::_index_put_impl_' is not current
|
|
||||||
implemented for the MPS device. If you want this op to be added in priority
|
|
||||||
during the prototype phase of this feature, please comment on
|
|
||||||
https://github.com/pytorch/pytorch/issues/77764.
|
|
||||||
As a temporary fix, you can set the environment variable
|
|
||||||
`PYTORCH_ENABLE_MPS_FALLBACK=1` to use the CPU as a fallback for this op.
|
|
||||||
WARNING: this will be slower than running natively on MPS.
|
|
||||||
```
|
|
||||||
|
|
||||||
The InvokeAI version includes this fix in
|
|
||||||
[environment-mac.yml](https://github.com/invoke-ai/InvokeAI/blob/main/environment-mac.yml).
|
|
||||||
|
|
||||||
### "Could not build wheels for tokenizers"
|
|
||||||
|
|
||||||
I have not seen this error because I had Rust installed on my computer before I
|
|
||||||
started playing with Stable Diffusion. The fix is to install Rust.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl \
|
|
||||||
--proto '=https' \
|
|
||||||
--tlsv1.2 \
|
|
||||||
-sSf https://sh.rustup.rs | sh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How come `--seed` doesn't work?
|
|
||||||
|
|
||||||
!!! Information
|
|
||||||
|
|
||||||
Completely reproducible results are not guaranteed across PyTorch releases,
|
|
||||||
individual commits, or different platforms. Furthermore, results may not be
|
|
||||||
reproducible between CPU and GPU executions, even when using identical seeds.
|
|
||||||
|
|
||||||
[PyTorch docs](https://pytorch.org/docs/stable/notes/randomness.html)
|
|
||||||
|
|
||||||
Second, we might have a fix that at least gets a consistent seed sort of. We're
|
|
||||||
still working on it.
|
|
||||||
|
|
||||||
### libiomp5.dylib error?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
OMP: Error #15: Initializing libiomp5.dylib, but found libomp.dylib already initialized.
|
|
||||||
```
|
|
||||||
|
|
||||||
You are likely using an Intel package by mistake. Be sure to run conda with the
|
|
||||||
environment variable `CONDA_SUBDIR=osx-arm64`, like so:
|
|
||||||
|
|
||||||
`CONDA_SUBDIR=osx-arm64 conda install ...`
|
|
||||||
|
|
||||||
This error happens with Anaconda on Macs when the Intel-only `mkl` is pulled in
|
|
||||||
by a dependency.
|
|
||||||
[nomkl](https://stackoverflow.com/questions/66224879/what-is-the-nomkl-python-package-used-for)
|
|
||||||
is a metapackage designed to prevent this, by making it impossible to install
|
|
||||||
`mkl`, but if your environment is already broken it may not work.
|
|
||||||
|
|
||||||
Do _not_ use `os.environ['KMP_DUPLICATE_LIB_OK']='True'` or equivalents as this
|
|
||||||
masks the underlying issue of using Intel packages.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Not enough memory
|
|
||||||
|
|
||||||
This seems to be a common problem and is probably the underlying problem for a
|
|
||||||
lot of symptoms (listed below). The fix is to lower your image size or to add
|
|
||||||
`model.half()` right after the model is loaded. I should probably test it out.
|
|
||||||
I've read that the reason this fixes problems is because it converts the model
|
|
||||||
from 32-bit to 16-bit and that leaves more RAM for other things. I have no idea
|
|
||||||
how that would affect the quality of the images though.
|
|
||||||
|
|
||||||
See [this issue](https://github.com/CompVis/stable-diffusion/issues/71).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### "Error: product of dimension sizes > 2\*\*31'"
|
|
||||||
|
|
||||||
This error happens with img2img, which I haven't played with too much yet. But I
|
|
||||||
know it's because your image is too big or the resolution isn't a multiple of
|
|
||||||
32x32. Because the stable-diffusion model was trained on images that were 512 x
|
|
||||||
512, it's always best to use that output size (which is the default). However,
|
|
||||||
if you're using that size and you get the above error, try 256 x 256 or 512 x
|
|
||||||
256 or something as the source image.
|
|
||||||
|
|
||||||
BTW, 2\*\*31-1 =
|
|
||||||
[2,147,483,647](https://en.wikipedia.org/wiki/2,147,483,647#In_computing), which
|
|
||||||
is also 32-bit signed [LONG_MAX](https://en.wikipedia.org/wiki/C_data_types) in
|
|
||||||
C.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### I just got Rickrolled! Do I have a virus?
|
|
||||||
|
|
||||||
You don't have a virus. It's part of the project. Here's
|
|
||||||
[Rick](https://github.com/invoke-ai/InvokeAI/blob/main/assets/rick.jpeg) and
|
|
||||||
here's
|
|
||||||
[the code](https://github.com/invoke-ai/InvokeAI/blob/69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc/scripts/txt2img.py#L79)
|
|
||||||
that swaps him in. It's a NSFW filter, which IMO, doesn't work very good (and we
|
|
||||||
call this "computer vision", sheesh).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### My images come out black
|
|
||||||
|
|
||||||
We might have this fixed, we are still testing.
|
|
||||||
|
|
||||||
There's a [similar issue](https://github.com/CompVis/stable-diffusion/issues/69)
|
|
||||||
on CUDA GPU's where the images come out green. Maybe it's the same issue?
|
|
||||||
Someone in that issue says to use "--precision full", but this fork actually
|
|
||||||
disables that flag. I don't know why, someone else provided that code and I
|
|
||||||
don't know what it does. Maybe the `model.half()` suggestion above would fix
|
|
||||||
this issue too. I should probably test it.
|
|
||||||
|
|
||||||
### "view size is not compatible with input tensor's size and stride"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
File "/opt/anaconda3/envs/invokeai/lib/python3.10/site-packages/torch/nn/functional.py", line 2511, in layer_norm
|
|
||||||
return torch.layer_norm(input, normalized_shape, weight, bias, eps, torch.backends.cudnn.enabled)
|
|
||||||
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
|
|
||||||
```
|
|
||||||
|
|
||||||
Update to the latest version of invoke-ai/InvokeAI. We were patching pytorch but
|
|
||||||
we found a file in stable-diffusion that we could change instead. This is a
|
|
||||||
32-bit vs 16-bit problem.
|
|
||||||
|
|
||||||
### The processor must support the Intel bla bla bla
|
|
||||||
|
|
||||||
What? Intel? On an Apple Silicon?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Intel MKL FATAL ERROR: This system does not meet the minimum requirements for use of the Intel(R) Math Kernel Library. The processor must support the Intel(R) Supplemental Streaming SIMD Extensions 3 (Intel(R) SSSE3) instructions. The processor must support the Intel(R) Streaming SIMD Extensions 4.2 (Intel(R) SSE4.2) instructions. The processor must support the Intel(R) Advanced Vector Extensions (Intel(R) AVX) instructions.
|
|
||||||
```
|
|
||||||
|
|
||||||
This is due to the Intel `mkl` package getting picked up when you try to install
|
|
||||||
something that depends on it-- Rosetta can translate some Intel instructions but
|
|
||||||
not the specialized ones here. To avoid this, make sure to use the environment
|
|
||||||
variable `CONDA_SUBDIR=osx-arm64`, which restricts the Conda environment to only
|
|
||||||
use ARM packages, and use `nomkl` as described above.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### input types 'tensor<2x1280xf32>' and 'tensor<\*xf16>' are not broadcast compatible
|
|
||||||
|
|
||||||
May appear when just starting to generate, e.g.:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
invoke> clouds
|
|
||||||
Generating: 0%| | 0/1 [00:00<?, ?it/s]/Users/[...]/dev/stable-diffusion/ldm/modules/embedding_manager.py:152: UserWarning: The operator 'aten::nonzero' is not currently supported on the MPS backend and will fall back to run on the CPU. This may have performance implications. (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1662016319283/work/aten/src/ATen/mps/MPSFallback.mm:11.)
|
|
||||||
placeholder_idx = torch.where(
|
|
||||||
loc("mps_add"("(mpsFileLoc): /AppleInternal/Library/BuildRoots/20d6c351-ee94-11ec-bcaf-7247572f23b4/Library/Caches/com.apple.xbs/Sources/MetalPerformanceShadersGraph/mpsgraph/MetalPerformanceShadersGraph/Core/Files/MPSGraphUtilities.mm":219:0)): error: input types 'tensor<2x1280xf32>' and 'tensor<*xf16>' are not broadcast compatible
|
|
||||||
LLVM ERROR: Failed to infer result type(s).
|
|
||||||
Abort trap: 6
|
|
||||||
/Users/[...]/opt/anaconda3/envs/invokeai/lib/python3.9/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown
|
|
||||||
warnings.warn('resource_tracker: There appear to be %d '
|
|
||||||
```
|
|
@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
title: Installing InvokeAI with the Pre-Compiled PIP Installer
|
|
||||||
---
|
|
||||||
|
|
||||||
# THIS NEEDS TO BE FLESHED OUT
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
## Walkthrough
|
|
||||||
|
|
||||||
## Updating to newer versions
|
|
||||||
|
|
||||||
### Updating the stable version
|
|
||||||
|
|
||||||
### Updating to the development version
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
@ -1,225 +0,0 @@
|
|||||||
---
|
|
||||||
title: Source Installer
|
|
||||||
---
|
|
||||||
|
|
||||||
# The InvokeAI Source Installer
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
The source installer is a shell script that attempts to automate every step
|
|
||||||
needed to install and run InvokeAI on a stock computer running recent versions
|
|
||||||
of Linux, MacOS or Windows. It will leave you with a version that runs a stable
|
|
||||||
version of InvokeAI with the option to upgrade to experimental versions later.
|
|
||||||
|
|
||||||
Before you begin, make sure that you meet the
|
|
||||||
[hardware requirements](../../index.md#hardware-requirements) and has the appropriate
|
|
||||||
GPU drivers installed. In particular, if you are a Linux user with an AMD GPU
|
|
||||||
installed, you may need to install the
|
|
||||||
[ROCm driver](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html).
|
|
||||||
|
|
||||||
Installation requires roughly 18G of free disk space to load the libraries and
|
|
||||||
recommended model weights files.
|
|
||||||
|
|
||||||
## Walk through
|
|
||||||
|
|
||||||
Though there are multiple steps, there really is only one click involved to kick
|
|
||||||
off the process.
|
|
||||||
|
|
||||||
1. The source installer is distributed in ZIP files. Go to the
|
|
||||||
[latest release](https://github.com/invoke-ai/InvokeAI/releases/latest), and
|
|
||||||
look for a series of files named:
|
|
||||||
|
|
||||||
- [invokeAI-src-installer-2.2.3-mac.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/invokeAI-src-installer-2.2.3-mac.zip)
|
|
||||||
- [invokeAI-src-installer-2.2.3-windows.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/invokeAI-src-installer-2.2.3-windows.zip)
|
|
||||||
- [invokeAI-src-installer-2.2.3-linux.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/invokeAI-src-installer-2.2.3-linux.zip)
|
|
||||||
|
|
||||||
Download the one that is appropriate for your operating system.
|
|
||||||
|
|
||||||
2. Unpack the zip file into a directory that has at least 18G of free space. Do
|
|
||||||
_not_ unpack into a directory that has an earlier version of InvokeAI.
|
|
||||||
|
|
||||||
This will create a new directory named "InvokeAI". This example shows how
|
|
||||||
this would look using the `unzip` command-line tool, but you may use any
|
|
||||||
graphical or command-line Zip extractor:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
C:\Documents\Linco> unzip invokeAI-windows.zip
|
|
||||||
Archive: C: \Linco\Downloads\invokeAI-linux.zip
|
|
||||||
creating: invokeAI\
|
|
||||||
inflating: invokeAI\install.bat
|
|
||||||
inflating: invokeAI\readme.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
3. If you are a macOS user, you may need to install the Xcode command line tools.
|
|
||||||
These are a set of tools that are needed to run certain applications in a Terminal,
|
|
||||||
including InvokeAI. This package is provided directly by Apple.
|
|
||||||
|
|
||||||
To install, open a terminal window and run `xcode-select --install`. You will get
|
|
||||||
a macOS system popup guiding you through the install. If you already have them
|
|
||||||
installed, you will instead see some output in the Terminal advising you that the
|
|
||||||
tools are already installed.
|
|
||||||
|
|
||||||
More information can be found here:
|
|
||||||
https://www.freecodecamp.org/news/install-xcode-command-line-tools/
|
|
||||||
|
|
||||||
4. If you are using a desktop GUI, double-click the installer file. It will be
|
|
||||||
named `install.bat` on Windows systems and `install.sh` on Linux and
|
|
||||||
Macintosh systems.
|
|
||||||
|
|
||||||
5. Alternatively, from the command line, run the shell script or .bat file:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
C:\Documents\Linco> cd invokeAI
|
|
||||||
C:\Documents\Linco\invokeAI> install.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Sit back and let the install script work. It will install various binary
|
|
||||||
requirements including Conda, Git and Python, then download the current
|
|
||||||
InvokeAI code and install it along with its dependencies.
|
|
||||||
|
|
||||||
Be aware that some of the library download and install steps take a long time.
|
|
||||||
In particular, the `pytorch` package is quite large and often appears to get
|
|
||||||
"stuck" at 99.9%. Similarly, the `pip installing requirements` step may
|
|
||||||
appear to hang. Have patience and the installation step will eventually
|
|
||||||
resume. However, there are occasions when the library install does
|
|
||||||
legitimately get stuck. If you have been waiting for more than ten minutes
|
|
||||||
and nothing is happening, you can interrupt the script with ^C. You may restart
|
|
||||||
it and it will pick up where it left off.
|
|
||||||
|
|
||||||
7. After installation completes, the installer will launch a script called
|
|
||||||
`configure_invokeai.py`, which will guide you through the first-time process of
|
|
||||||
selecting one or more Stable Diffusion model weights files, downloading and
|
|
||||||
configuring them.
|
|
||||||
|
|
||||||
Note that the main Stable Diffusion weights file is protected by a license
|
|
||||||
agreement that you must agree to in order to use. The script will list the
|
|
||||||
steps you need to take to create an account on the official site that hosts
|
|
||||||
the weights files, accept the agreement, and provide an access token that
|
|
||||||
allows InvokeAI to legally download and install the weights files.
|
|
||||||
|
|
||||||
If you have already downloaded the weights file(s) for another Stable
|
|
||||||
Diffusion distribution, you may skip this step (by selecting "skip" when
|
|
||||||
prompted) and configure InvokeAI to use the previously-downloaded files. The
|
|
||||||
process for this is described in [Installing Models](../050_INSTALLING_MODELS.md).
|
|
||||||
|
|
||||||
8. The script will now exit and you'll be ready to generate some images. The
|
|
||||||
invokeAI directory will contain numerous files. Look for a shell script
|
|
||||||
named `invoke.sh` (Linux/Mac) or `invoke.bat` (Windows). Launch the script
|
|
||||||
by double-clicking it or typing its name at the command-line:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
C:\Documents\Linco> cd invokeAI
|
|
||||||
C:\Documents\Linco\invokeAI> invoke.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
The `invoke.bat` (`invoke.sh`) script will give you the choice of starting (1)
|
|
||||||
the command-line interface, or (2) the web GUI. If you start the latter, you can
|
|
||||||
load the user interface by pointing your browser at http://localhost:9090.
|
|
||||||
|
|
||||||
The `invoke` script also offers you a third option labeled "open the developer
|
|
||||||
console". If you choose this option, you will be dropped into a command-line
|
|
||||||
interface in which you can run python commands directly, access developer tools,
|
|
||||||
and launch InvokeAI with customized options. To do the latter, you would launch
|
|
||||||
the script `scripts/invoke.py` as shown in this example:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
python scripts/invoke.py --web --max_load_models=3 \
|
|
||||||
--model=waifu-1.3 --steps=30 --outdir=C:/Documents/AIPhotos
|
|
||||||
```
|
|
||||||
|
|
||||||
These options are described in detail in the
|
|
||||||
[Command-Line Interface](../../deprecated/CLI.md) documentation.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
_Package dependency conflicts_ If you have previously installed
|
|
||||||
InvokeAI or another Stable Diffusion package, the installer may
|
|
||||||
occasionally pick up outdated libraries and either the installer or
|
|
||||||
`invoke` will fail with complaints out library conflicts. There are
|
|
||||||
two steps you can take to clear this problem. Both of these are done
|
|
||||||
from within the "developer's console", which you can get to by
|
|
||||||
launching `invoke.sh` (or `invoke.bat`) and selecting launch option
|
|
||||||
#3:
|
|
||||||
|
|
||||||
1. Remove the previous `invokeai` environment completely. From within
|
|
||||||
the developer's console, give the command `conda env remove -n
|
|
||||||
invokeai`. This will delete previous files installed by `invoke`.
|
|
||||||
|
|
||||||
Then exit from the developer's console and launch the script
|
|
||||||
`update.sh` (or `update.bat`). This will download the most recent
|
|
||||||
InvokeAI (including bug fixes) and reinstall the environment.
|
|
||||||
You should then be able to run `invoke.sh`/`invoke.bat`.
|
|
||||||
|
|
||||||
2. If this doesn't work, you can try cleaning your system's conda
|
|
||||||
cache. This is slightly more extreme, but won't interfere with
|
|
||||||
any other python-based programs installed on your computer.
|
|
||||||
From the developer's console, run the command `conda clean -a`
|
|
||||||
and answer "yes" to all prompts.
|
|
||||||
|
|
||||||
After this is done, run `update.sh` and try again as before.
|
|
||||||
|
|
||||||
_"Corrupted configuration file."__ Everything seems to install ok, but
|
|
||||||
`invoke` complains of a corrupted configuration file and goes calls
|
|
||||||
`configure_invokeai.py` to fix, but this doesn't fix the problem.
|
|
||||||
|
|
||||||
This issue is often caused by a misconfigured configuration directive
|
|
||||||
in the `.invokeai` initialization file that contains startup settings.
|
|
||||||
This can be corrected by fixing the offending line.
|
|
||||||
|
|
||||||
First find `.invokeai`. It is a small text file located in your home
|
|
||||||
directory, `~/.invokeai` on Mac and Linux systems, and `C:\Users\*your
|
|
||||||
name*\.invokeai` on Windows systems. Open it with a text editor
|
|
||||||
(e.g. Notepad on Windows, TextEdit on Macs, or `nano` on Linux)
|
|
||||||
and look for the lines starting with `--root` and `--outdir`.
|
|
||||||
|
|
||||||
An example is here:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
--root="/home/lstein/invokeai"
|
|
||||||
--outdir="/home/lstein/invokeai/outputs"
|
|
||||||
```
|
|
||||||
|
|
||||||
There should not be whitespace before or after the directory paths,
|
|
||||||
and the paths should not end with slashes:
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
--root="/home/lstein/invokeai " # wrong! no whitespace here
|
|
||||||
--root="/home\lstein\invokeai\" # wrong! shouldn't end in a slash
|
|
||||||
```
|
|
||||||
|
|
||||||
Fix the problem with your text editor and save as a **plain text**
|
|
||||||
file. This should clear the issue.
|
|
||||||
|
|
||||||
_If none of these maneuvers fixes the problem_ then please report the
|
|
||||||
problem to the [InvokeAI
|
|
||||||
Issues](https://github.com/invoke-ai/InvokeAI/issues) section, or
|
|
||||||
visit our [Discord Server](https://discord.gg/ZmtBAhwWhy) for interactive assistance.
|
|
||||||
|
|
||||||
## Updating to newer versions
|
|
||||||
|
|
||||||
This section describes how to update InvokeAI to new versions of the software.
|
|
||||||
|
|
||||||
### Updating the stable version
|
|
||||||
|
|
||||||
This distribution is changing rapidly, and we add new features on a daily basis.
|
|
||||||
To update to the latest released version (recommended), run the `update.sh`
|
|
||||||
(Linux/Mac) or `update.bat` (Windows) scripts. This will fetch the latest
|
|
||||||
release and re-run the `configure_invokeai` script to download any updated models
|
|
||||||
files that may be needed. You can also use this to add additional models that
|
|
||||||
you did not select at installation time.
|
|
||||||
|
|
||||||
You can now close the developer console and run `invoke` as before. If you get
|
|
||||||
complaints about missing models, then you may need to do the additional step of
|
|
||||||
running `configure_invokeai.py`. This happens relatively infrequently. To do this,
|
|
||||||
simply open up the developer's console again and type
|
|
||||||
`python scripts/configure_invokeai.py`.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If you run into problems during or after installation, the InvokeAI team is
|
|
||||||
available to help you. Either create an
|
|
||||||
[Issue](https://github.com/invoke-ai/InvokeAI/issues) at our GitHub site, or
|
|
||||||
make a request for help on the "bugs-and-support" channel of our
|
|
||||||
[Discord server](https://discord.gg/ZmtBAhwWhy). We are a 100% volunteer
|
|
||||||
organization, but typically somebody will be available to help you within 24
|
|
||||||
hours, and often much sooner.
|
|
@ -1,137 +0,0 @@
|
|||||||
---
|
|
||||||
title: Manual Installation, Windows
|
|
||||||
---
|
|
||||||
|
|
||||||
# :fontawesome-brands-windows: Windows
|
|
||||||
|
|
||||||
## **Notebook install (semi-automated)**
|
|
||||||
|
|
||||||
We have a
|
|
||||||
[Jupyter notebook](https://github.com/invoke-ai/InvokeAI/blob/main/notebooks/Stable_Diffusion_AI_Notebook.ipynb)
|
|
||||||
with cell-by-cell installation steps. It will download the code in this repo as
|
|
||||||
one of the steps, so instead of cloning this repo, simply download the notebook
|
|
||||||
from the link above and load it up in VSCode (with the appropriate extensions
|
|
||||||
installed)/Jupyter/JupyterLab and start running the cells one-by-one.
|
|
||||||
|
|
||||||
Note that you will need NVIDIA drivers, Python 3.10, and Git installed beforehand.
|
|
||||||
|
|
||||||
## **Manual Install with Conda**
|
|
||||||
|
|
||||||
1. Install Anaconda3 (miniconda3 version) from [here](https://docs.anaconda.com/anaconda/install/windows/)
|
|
||||||
|
|
||||||
2. Install Git from [here](https://git-scm.com/download/win)
|
|
||||||
|
|
||||||
3. Launch Anaconda from the Windows Start menu. This will bring up a command
|
|
||||||
window. Type all the remaining commands in this window.
|
|
||||||
|
|
||||||
4. Run the command:
|
|
||||||
|
|
||||||
```batch
|
|
||||||
git clone https://github.com/invoke-ai/InvokeAI.git
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create stable-diffusion folder where you will follow the rest of
|
|
||||||
the steps.
|
|
||||||
|
|
||||||
5. Enter the newly-created InvokeAI folder. From this step forward make sure that you are working in the InvokeAI directory!
|
|
||||||
|
|
||||||
```batch
|
|
||||||
cd InvokeAI
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Run the following commands:
|
|
||||||
|
|
||||||
!!! todo "For systems with a CUDA (Nvidia) card:"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rmdir src # (this is a precaution in case there is already a src directory)
|
|
||||||
conda env create -f environment-cuda.yml
|
|
||||||
conda activate invokeai
|
|
||||||
(invokeai)>
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! todo "For systems with an AMD card (using ROCm driver):"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rmdir src # (this is a precaution in case there is already a src directory)
|
|
||||||
conda env create -f environment-AMD.yml
|
|
||||||
conda activate invokeai
|
|
||||||
(invokeai)>
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install all python requirements and activate the "invokeai" environment
|
|
||||||
which sets PATH and other environment variables properly.
|
|
||||||
|
|
||||||
7. Load the big stable diffusion weights files and a couple of smaller machine-learning models:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/configure_invokeai.py
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
This script will lead you through the process of creating an account on Hugging Face,
|
|
||||||
accepting the terms and conditions of the Stable Diffusion model license, and
|
|
||||||
obtaining an access token for downloading. It will then download and install the
|
|
||||||
weights files for you.
|
|
||||||
|
|
||||||
Please look [here](../020_INSTALL_MANUAL.md) for a manual process for doing the
|
|
||||||
same thing.
|
|
||||||
|
|
||||||
8. Start generating images!
|
|
||||||
|
|
||||||
!!! example ""
|
|
||||||
|
|
||||||
!!! warning "IMPORTANT"
|
|
||||||
|
|
||||||
Make sure that the conda environment is activated, which should create
|
|
||||||
`(invokeai)` in front of your prompt!
|
|
||||||
|
|
||||||
=== "CLI"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "local Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "Public Webserver"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python scripts/invoke.py --web --host 0.0.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
To use an alternative model you may invoke the `!switch` command in
|
|
||||||
the CLI, or pass `--model <model_name>` during `invoke.py` launch for
|
|
||||||
either the CLI or the Web UI. See [Command Line
|
|
||||||
Client](../../deprecated/CLI.md#model-selection-and-importation). The
|
|
||||||
model names are defined in `configs/models.yaml`.
|
|
||||||
|
|
||||||
9. Subsequently, to relaunch the script, first activate the Anaconda
|
|
||||||
command window (step 3),enter the InvokeAI directory (step 5, `cd
|
|
||||||
\path\to\InvokeAI`), run `conda activate invokeai` (step 6b), and then
|
|
||||||
launch the invoke script (step 9).
|
|
||||||
|
|
||||||
!!! tip "Tildebyte has written an alternative"
|
|
||||||
|
|
||||||
["Easy peasy Windows install"](https://github.com/invoke-ai/InvokeAI/wiki/Easy-peasy-Windows-install)
|
|
||||||
which uses the Windows Powershell and pew. If you are having trouble with
|
|
||||||
Anaconda on Windows, give this a try (or try it first!)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This distribution is changing rapidly. If you used the `git clone` method
|
|
||||||
(step 5) to download the stable-diffusion directory, then to update to the
|
|
||||||
latest and greatest version, launch the Anaconda window, enter
|
|
||||||
`stable-diffusion`, and type:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git pull
|
|
||||||
conda env update
|
|
||||||
```
|
|
||||||
|
|
||||||
This will bring your local copy into sync with the remote one.
|
|
@ -16,7 +16,7 @@ if "%1" == "use-cache" (
|
|||||||
@rem The version in the next line is replaced by an up to date release number
|
@rem The version in the next line is replaced by an up to date release number
|
||||||
@rem when create_installer.sh is run. Change the release number there.
|
@rem when create_installer.sh is run. Change the release number there.
|
||||||
set INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/
|
set INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/
|
||||||
set TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting
|
set TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/help/FAQ/
|
||||||
set PYTHON_URL=https://www.python.org/downloads/windows/
|
set PYTHON_URL=https://www.python.org/downloads/windows/
|
||||||
set MINIMUM_PYTHON_VERSION=3.10.0
|
set MINIMUM_PYTHON_VERSION=3.10.0
|
||||||
set PYTHON_URL=https://www.python.org/downloads/release/python-3109/
|
set PYTHON_URL=https://www.python.org/downloads/release/python-3109/
|
||||||
|
@ -5,6 +5,7 @@ InvokeAI installer script
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -16,12 +17,23 @@ from typing import Optional, Tuple
|
|||||||
SUPPORTED_PYTHON = ">=3.10.0,<=3.11.100"
|
SUPPORTED_PYTHON = ">=3.10.0,<=3.11.100"
|
||||||
INSTALLER_REQS = ["rich", "semver", "requests", "plumbum", "prompt-toolkit"]
|
INSTALLER_REQS = ["rich", "semver", "requests", "plumbum", "prompt-toolkit"]
|
||||||
BOOTSTRAP_VENV_PREFIX = "invokeai-installer-tmp"
|
BOOTSTRAP_VENV_PREFIX = "invokeai-installer-tmp"
|
||||||
|
DOCS_URL = "https://invoke-ai.github.io/InvokeAI/"
|
||||||
|
DISCORD_URL = "https://discord.gg/ZmtBAhwWhy"
|
||||||
|
|
||||||
OS = platform.uname().system
|
OS = platform.uname().system
|
||||||
ARCH = platform.uname().machine
|
ARCH = platform.uname().machine
|
||||||
VERSION = "latest"
|
VERSION = "latest"
|
||||||
|
|
||||||
|
|
||||||
|
def get_version_from_wheel_filename(wheel_filename: str) -> str:
|
||||||
|
match = re.search(r"-(\d+\.\d+\.\d+)", wheel_filename)
|
||||||
|
if match:
|
||||||
|
version = match.group(1)
|
||||||
|
return version
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Could not extract version from wheel filename: {wheel_filename}")
|
||||||
|
|
||||||
|
|
||||||
class Installer:
|
class Installer:
|
||||||
"""
|
"""
|
||||||
Deploys an InvokeAI installation into a given path
|
Deploys an InvokeAI installation into a given path
|
||||||
@ -36,7 +48,7 @@ class Installer:
|
|||||||
self.bootstrap()
|
self.bootstrap()
|
||||||
self.available_releases = get_github_releases()
|
self.available_releases = get_github_releases()
|
||||||
|
|
||||||
def mktemp_venv(self) -> TemporaryDirectory:
|
def mktemp_venv(self) -> TemporaryDirectory[str]:
|
||||||
"""
|
"""
|
||||||
Creates a temporary virtual environment for the installer itself
|
Creates a temporary virtual environment for the installer itself
|
||||||
|
|
||||||
@ -58,7 +70,7 @@ class Installer:
|
|||||||
|
|
||||||
return venv_dir
|
return venv_dir
|
||||||
|
|
||||||
def bootstrap(self, verbose: bool = False) -> TemporaryDirectory | None:
|
def bootstrap(self, verbose: bool = False) -> TemporaryDirectory[str] | None:
|
||||||
"""
|
"""
|
||||||
Bootstrap the installer venv with packages required at install time
|
Bootstrap the installer venv with packages required at install time
|
||||||
"""
|
"""
|
||||||
@ -87,7 +99,7 @@ class Installer:
|
|||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
def app_venv(self, venv_parent) -> Path:
|
def app_venv(self, venv_parent: Path) -> Path:
|
||||||
"""
|
"""
|
||||||
Create a virtualenv for the InvokeAI installation
|
Create a virtualenv for the InvokeAI installation
|
||||||
"""
|
"""
|
||||||
@ -106,26 +118,29 @@ class Installer:
|
|||||||
return venv_dir
|
return venv_dir
|
||||||
|
|
||||||
def install(
|
def install(
|
||||||
self, version=None, root: str = "~/invokeai", yes_to_all=False, find_links: Optional[Path] = None
|
self,
|
||||||
|
root: str = "~/invokeai",
|
||||||
|
yes_to_all: bool = False,
|
||||||
|
find_links: Optional[str] = None,
|
||||||
|
wheel: Optional[Path] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""Install the InvokeAI application into the given runtime path
|
||||||
Install the InvokeAI application into the given runtime path
|
|
||||||
|
|
||||||
:param root: Destination path for the installation
|
Args:
|
||||||
:type root: str
|
root: Destination path for the installation
|
||||||
:param version: InvokeAI version to install
|
yes_to_all: Accept defaults to all questions
|
||||||
:type version: str
|
find_links: A local directory to search for requirement wheels before going to remote indexes
|
||||||
:param yes: Accept defaults to all questions
|
wheel: A wheel file to install
|
||||||
:type yes: bool
|
|
||||||
:param find_links: A local directory to search for requirement wheels before going to remote indexes
|
|
||||||
:type find_links: Path
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import messages
|
import messages
|
||||||
|
|
||||||
messages.welcome(self.available_releases)
|
if wheel:
|
||||||
|
messages.installing_from_wheel(wheel.name)
|
||||||
version = messages.choose_version(self.available_releases)
|
version = get_version_from_wheel_filename(wheel.name)
|
||||||
|
else:
|
||||||
|
messages.welcome(self.available_releases)
|
||||||
|
version = messages.choose_version(self.available_releases)
|
||||||
|
|
||||||
auto_dest = Path(os.environ.get("INVOKEAI_ROOT", root)).expanduser().resolve()
|
auto_dest = Path(os.environ.get("INVOKEAI_ROOT", root)).expanduser().resolve()
|
||||||
destination = auto_dest if yes_to_all else messages.dest_path(root)
|
destination = auto_dest if yes_to_all else messages.dest_path(root)
|
||||||
@ -140,15 +155,25 @@ class Installer:
|
|||||||
|
|
||||||
# install dependencies and the InvokeAI application
|
# install dependencies and the InvokeAI application
|
||||||
(extra_index_url, optional_modules) = get_torch_source() if not yes_to_all else (None, None)
|
(extra_index_url, optional_modules) = get_torch_source() if not yes_to_all else (None, None)
|
||||||
self.instance.install(
|
self.instance.install(extra_index_url, optional_modules, find_links, wheel)
|
||||||
extra_index_url,
|
|
||||||
optional_modules,
|
|
||||||
find_links,
|
|
||||||
)
|
|
||||||
|
|
||||||
# install the launch/update scripts into the runtime directory
|
# install the launch/update scripts into the runtime directory
|
||||||
self.instance.install_user_scripts()
|
self.instance.install_user_scripts()
|
||||||
|
|
||||||
|
message = f"""
|
||||||
|
*** Installation Successful ***
|
||||||
|
|
||||||
|
To start the application, run:
|
||||||
|
{destination}/invoke.{"bat" if sys.platform == "win32" else "sh"}
|
||||||
|
|
||||||
|
For more information, troubleshooting and support, visit our docs at:
|
||||||
|
{DOCS_URL}
|
||||||
|
|
||||||
|
Join the community on Discord:
|
||||||
|
{DISCORD_URL}
|
||||||
|
"""
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
|
||||||
class InvokeAiInstance:
|
class InvokeAiInstance:
|
||||||
"""
|
"""
|
||||||
@ -178,18 +203,20 @@ class InvokeAiInstance:
|
|||||||
|
|
||||||
return (self.runtime, self.venv)
|
return (self.runtime, self.venv)
|
||||||
|
|
||||||
def install(self, extra_index_url=None, optional_modules=None, find_links=None):
|
def install(
|
||||||
"""
|
self,
|
||||||
Install the package from PyPi.
|
extra_index_url: Optional[str] = None,
|
||||||
|
optional_modules: Optional[str] = None,
|
||||||
|
find_links: Optional[str] = None,
|
||||||
|
wheel: Optional[Path] = None,
|
||||||
|
):
|
||||||
|
"""Install the package from PyPi or a wheel, if provided.
|
||||||
|
|
||||||
:param extra_index_url: the "--extra-index-url ..." line for pip to look in extra indexes.
|
Args:
|
||||||
:type extra_index_url: str
|
extra_index_url: the "--extra-index-url ..." line for pip to look in extra indexes.
|
||||||
|
optional_modules: optional modules to install using "[module1,module2]" format.
|
||||||
:param optional_modules: optional modules to install using "[module1,module2]" format.
|
find_links: path to a directory containing wheels to be searched prior to going to the internet
|
||||||
:type optional_modules: str
|
wheel: a wheel file to install
|
||||||
|
|
||||||
:param find_links: path to a directory containing wheels to be searched prior to going to the internet
|
|
||||||
:type find_links: Path
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import messages
|
import messages
|
||||||
@ -213,7 +240,7 @@ class InvokeAiInstance:
|
|||||||
|
|
||||||
messages.simple_banner("Installing the InvokeAI Application :art:")
|
messages.simple_banner("Installing the InvokeAI Application :art:")
|
||||||
|
|
||||||
from plumbum import FG, ProcessExecutionError, local # type: ignore
|
from plumbum import FG, ProcessExecutionError, local
|
||||||
|
|
||||||
pip = local[self.pip]
|
pip = local[self.pip]
|
||||||
|
|
||||||
@ -222,12 +249,12 @@ class InvokeAiInstance:
|
|||||||
"--require-virtualenv",
|
"--require-virtualenv",
|
||||||
"--force-reinstall",
|
"--force-reinstall",
|
||||||
"--use-pep517",
|
"--use-pep517",
|
||||||
str(src),
|
str(src) if not wheel else str(wheel),
|
||||||
"--find-links" if find_links is not None else None,
|
"--find-links" if find_links is not None else None,
|
||||||
find_links,
|
find_links,
|
||||||
"--extra-index-url" if extra_index_url is not None else None,
|
"--extra-index-url" if extra_index_url is not None else None,
|
||||||
extra_index_url,
|
extra_index_url,
|
||||||
pre_flag,
|
pre_flag if not wheel else None, # Ignore the flag if we are installing a wheel
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -320,7 +347,7 @@ def set_sys_path(venv_path: Path) -> None:
|
|||||||
sys.path.append(str(Path(venv_path, lib, "site-packages").expanduser().resolve()))
|
sys.path.append(str(Path(venv_path, lib, "site-packages").expanduser().resolve()))
|
||||||
|
|
||||||
|
|
||||||
def get_github_releases() -> tuple[list, list] | None:
|
def get_github_releases() -> tuple[list[str], list[str]] | None:
|
||||||
"""
|
"""
|
||||||
Query Github for published (pre-)release versions.
|
Query Github for published (pre-)release versions.
|
||||||
Return a tuple where the first element is a list of stable releases and the second element is a list of pre-releases.
|
Return a tuple where the first element is a list of stable releases and the second element is a list of pre-releases.
|
||||||
@ -331,7 +358,8 @@ def get_github_releases() -> tuple[list, list] | None:
|
|||||||
|
|
||||||
## get latest releases using github api
|
## get latest releases using github api
|
||||||
url = "https://api.github.com/repos/invoke-ai/InvokeAI/releases"
|
url = "https://api.github.com/repos/invoke-ai/InvokeAI/releases"
|
||||||
releases, pre_releases = [], []
|
releases: list[str] = []
|
||||||
|
pre_releases: list[str] = []
|
||||||
try:
|
try:
|
||||||
res = requests.get(url)
|
res = requests.get(url)
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
|
@ -30,16 +30,17 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--version",
|
"--find-links",
|
||||||
dest="version",
|
dest="find_links",
|
||||||
help="Version of InvokeAI to install. Default to the latest stable release. A special 'pre' value will install the latest published pre-release version.",
|
help="Specifies a directory of local wheel files to be searched prior to searching the online repositories.",
|
||||||
|
type=Path,
|
||||||
default=None,
|
default=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--find-links",
|
"--wheel",
|
||||||
dest="find_links",
|
dest="wheel",
|
||||||
help="Specifies a directory of local wheel files to be searched prior to searching the online repositories.",
|
help="Specifies a wheel for the InvokeAI package. Used for troubleshooting or testing prereleases.",
|
||||||
type=Path,
|
type=Path,
|
||||||
default=None,
|
default=None,
|
||||||
)
|
)
|
||||||
|
@ -7,6 +7,7 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from prompt_toolkit import prompt
|
from prompt_toolkit import prompt
|
||||||
from prompt_toolkit.completion import FuzzyWordCompleter, PathCompleter
|
from prompt_toolkit.completion import FuzzyWordCompleter, PathCompleter
|
||||||
@ -19,13 +20,6 @@ from rich.style import Style
|
|||||||
from rich.syntax import Syntax
|
from rich.syntax import Syntax
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
"""
|
|
||||||
INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/archive/refs/tags/${INVOKEAI_VERSION}.zip
|
|
||||||
INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/
|
|
||||||
TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
OS = platform.uname().system
|
OS = platform.uname().system
|
||||||
ARCH = platform.uname().machine
|
ARCH = platform.uname().machine
|
||||||
|
|
||||||
@ -36,7 +30,7 @@ else:
|
|||||||
console = Console(style=Style(color="grey74", bgcolor="grey19"))
|
console = Console(style=Style(color="grey74", bgcolor="grey19"))
|
||||||
|
|
||||||
|
|
||||||
def welcome(available_releases: tuple | None = None) -> None:
|
def welcome(available_releases: tuple[list[str], list[str]] | None = None) -> None:
|
||||||
@group()
|
@group()
|
||||||
def text():
|
def text():
|
||||||
if (platform_specific := _platform_specific_help()) is not None:
|
if (platform_specific := _platform_specific_help()) is not None:
|
||||||
@ -72,7 +66,34 @@ def welcome(available_releases: tuple | None = None) -> None:
|
|||||||
console.line()
|
console.line()
|
||||||
|
|
||||||
|
|
||||||
def choose_version(available_releases: tuple | None = None) -> str:
|
def installing_from_wheel(wheel_filename: str) -> None:
|
||||||
|
"""Display a message about installing from a wheel"""
|
||||||
|
|
||||||
|
@group()
|
||||||
|
def text():
|
||||||
|
yield Text.from_markup(f"You are installing from a wheel file: [bold]{wheel_filename}\n")
|
||||||
|
yield Text.from_markup(
|
||||||
|
"[bold orange3]If you are not sure why you are doing this, you should cancel and install InvokeAI normally."
|
||||||
|
)
|
||||||
|
|
||||||
|
console.print(
|
||||||
|
Panel(
|
||||||
|
title="Installing from Wheel",
|
||||||
|
renderable=text(),
|
||||||
|
box=box.DOUBLE,
|
||||||
|
expand=True,
|
||||||
|
padding=(1, 2),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
should_proceed = Confirm.ask("Do you want to proceed?")
|
||||||
|
|
||||||
|
if not should_proceed:
|
||||||
|
console.print("Installation cancelled.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
def choose_version(available_releases: tuple[list[str], list[str]] | None = None) -> str:
|
||||||
"""
|
"""
|
||||||
Prompt the user to choose an Invoke version to install
|
Prompt the user to choose an Invoke version to install
|
||||||
"""
|
"""
|
||||||
@ -114,7 +135,7 @@ def confirm_install(dest: Path) -> bool:
|
|||||||
return dest_confirmed
|
return dest_confirmed
|
||||||
|
|
||||||
|
|
||||||
def dest_path(dest=None) -> Path | None:
|
def dest_path(dest: Optional[str | Path] = None) -> Path | None:
|
||||||
"""
|
"""
|
||||||
Prompt the user for the destination path and create the path
|
Prompt the user for the destination path and create the path
|
||||||
|
|
||||||
|
@ -10,11 +10,13 @@ set INVOKEAI_ROOT=.
|
|||||||
echo Desired action:
|
echo Desired action:
|
||||||
echo 1. Generate images with the browser-based interface
|
echo 1. Generate images with the browser-based interface
|
||||||
echo 2. Open the developer console
|
echo 2. Open the developer console
|
||||||
echo 3. Update InvokeAI (DEPRECATED - please use the installer)
|
echo 3. Run the InvokeAI image database maintenance script
|
||||||
echo 4. Run the InvokeAI image database maintenance script
|
echo 4. Command-line help
|
||||||
echo 5. Command-line help
|
|
||||||
echo Q - Quit
|
echo Q - Quit
|
||||||
set /P choice="Please enter 1-10, Q: [1] "
|
echo.
|
||||||
|
echo To update, download and run the installer from https://github.com/invoke-ai/InvokeAI/releases/latest.
|
||||||
|
echo.
|
||||||
|
set /P choice="Please enter 1-4, Q: [1] "
|
||||||
if not defined choice set choice=1
|
if not defined choice set choice=1
|
||||||
IF /I "%choice%" == "1" (
|
IF /I "%choice%" == "1" (
|
||||||
echo Starting the InvokeAI browser-based UI..
|
echo Starting the InvokeAI browser-based UI..
|
||||||
@ -32,14 +34,9 @@ IF /I "%choice%" == "1" (
|
|||||||
echo *** Type `exit` to quit this shell and deactivate the Python virtual environment ***
|
echo *** Type `exit` to quit this shell and deactivate the Python virtual environment ***
|
||||||
call cmd /k
|
call cmd /k
|
||||||
) ELSE IF /I "%choice%" == "3" (
|
) ELSE IF /I "%choice%" == "3" (
|
||||||
echo UPDATING FROM WITHIN THE APP IS BEING DEPRECATED.
|
|
||||||
echo Please download the installer from https://github.com/invoke-ai/InvokeAI/releases/latest and run it to update your installation.
|
|
||||||
timeout 4
|
|
||||||
python -m invokeai.frontend.install.invokeai_update
|
|
||||||
) ELSE IF /I "%choice%" == "4" (
|
|
||||||
echo Running the db maintenance script...
|
echo Running the db maintenance script...
|
||||||
python .venv\Scripts\invokeai-db-maintenance.exe
|
python .venv\Scripts\invokeai-db-maintenance.exe
|
||||||
) ELSE IF /I "%choice%" == "5" (
|
) ELSE IF /I "%choice%" == "4" (
|
||||||
echo Displaying command line help...
|
echo Displaying command line help...
|
||||||
python .venv\Scripts\invokeai-web.exe --help %*
|
python .venv\Scripts\invokeai-web.exe --help %*
|
||||||
pause
|
pause
|
||||||
|
@ -23,32 +23,15 @@ cd "$scriptdir"
|
|||||||
. .venv/bin/activate
|
. .venv/bin/activate
|
||||||
|
|
||||||
export INVOKEAI_ROOT="$scriptdir"
|
export INVOKEAI_ROOT="$scriptdir"
|
||||||
|
|
||||||
|
# Stash the CLI args - when we prompt for user input, `$@` is overwritten
|
||||||
PARAMS=$@
|
PARAMS=$@
|
||||||
|
|
||||||
# Check to see if dialog is installed (it seems to be fairly standard, but good to check regardless) and if the user has passed the --no-tui argument to disable the dialog TUI
|
# This setting allows torch to fall back to CPU for operations that are not supported by MPS on macOS.
|
||||||
tui=true
|
|
||||||
if command -v dialog &>/dev/null; then
|
|
||||||
# This must use $@ to properly loop through the arguments passed by the user
|
|
||||||
for arg in "$@"; do
|
|
||||||
if [ "$arg" == "--no-tui" ]; then
|
|
||||||
tui=false
|
|
||||||
# Remove the --no-tui argument to avoid errors later on when passing arguments to InvokeAI
|
|
||||||
PARAMS=$(echo "$PARAMS" | sed 's/--no-tui//')
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
tui=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set required env var for torch on mac MPS
|
|
||||||
if [ "$(uname -s)" == "Darwin" ]; then
|
if [ "$(uname -s)" == "Darwin" ]; then
|
||||||
export PYTORCH_ENABLE_MPS_FALLBACK=1
|
export PYTORCH_ENABLE_MPS_FALLBACK=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Avoid glibc memory fragmentation. See invokeai/backend/model_management/README.md for details.
|
|
||||||
export MALLOC_MMAP_THRESHOLD_=1048576
|
|
||||||
|
|
||||||
# Primary function for the case statement to determine user input
|
# Primary function for the case statement to determine user input
|
||||||
do_choice() {
|
do_choice() {
|
||||||
case $1 in
|
case $1 in
|
||||||
@ -64,18 +47,11 @@ do_choice() {
|
|||||||
bash --init-file "$file_name"
|
bash --init-file "$file_name"
|
||||||
;;
|
;;
|
||||||
3)
|
3)
|
||||||
clear
|
|
||||||
printf "UPDATING FROM WITHIN THE APP IS BEING DEPRECATED\n"
|
|
||||||
printf "Please download the installer from https://github.com/invoke-ai/InvokeAI/releases/latest and run it to update your installation.\n"
|
|
||||||
sleep 4
|
|
||||||
python -m invokeai.frontend.install.invokeai_update
|
|
||||||
;;
|
|
||||||
4)
|
|
||||||
clear
|
clear
|
||||||
printf "Running the db maintenance script\n"
|
printf "Running the db maintenance script\n"
|
||||||
invokeai-db-maintenance --root ${INVOKEAI_ROOT}
|
invokeai-db-maintenance --root ${INVOKEAI_ROOT}
|
||||||
;;
|
;;
|
||||||
5)
|
4)
|
||||||
clear
|
clear
|
||||||
printf "Command-line help\n"
|
printf "Command-line help\n"
|
||||||
invokeai-web --help
|
invokeai-web --help
|
||||||
@ -89,59 +65,26 @@ do_choice() {
|
|||||||
clear
|
clear
|
||||||
}
|
}
|
||||||
|
|
||||||
# Dialog-based TUI for launcing Invoke functions
|
|
||||||
do_dialog() {
|
|
||||||
options=(
|
|
||||||
1 "Generate images with a browser-based interface"
|
|
||||||
2 "Open the developer console"
|
|
||||||
3 "Update InvokeAI (DEPRECATED - please use the installer)"
|
|
||||||
4 "Run the InvokeAI image database maintenance script"
|
|
||||||
5 "Command-line help"
|
|
||||||
)
|
|
||||||
|
|
||||||
choice=$(dialog --clear \
|
|
||||||
--backtitle "\Zb\Zu\Z3InvokeAI" \
|
|
||||||
--colors \
|
|
||||||
--title "What would you like to do?" \
|
|
||||||
--ok-label "Run" \
|
|
||||||
--cancel-label "Exit" \
|
|
||||||
--help-button \
|
|
||||||
--help-label "CLI Help" \
|
|
||||||
--menu "Select an option:" \
|
|
||||||
0 0 0 \
|
|
||||||
"${options[@]}" \
|
|
||||||
2>&1 >/dev/tty) || clear
|
|
||||||
do_choice "$choice"
|
|
||||||
clear
|
|
||||||
}
|
|
||||||
|
|
||||||
# Command-line interface for launching Invoke functions
|
# Command-line interface for launching Invoke functions
|
||||||
do_line_input() {
|
do_line_input() {
|
||||||
clear
|
clear
|
||||||
printf " ** For a more attractive experience, please install the 'dialog' utility using your package manager. **\n\n"
|
|
||||||
printf "What would you like to do?\n"
|
printf "What would you like to do?\n"
|
||||||
printf "1: Generate images using the browser-based interface\n"
|
printf "1: Generate images using the browser-based interface\n"
|
||||||
printf "2: Open the developer console\n"
|
printf "2: Open the developer console\n"
|
||||||
printf "3: Update InvokeAI\n"
|
printf "3: Run the InvokeAI image database maintenance script\n"
|
||||||
printf "4: Run the InvokeAI image database maintenance script\n"
|
printf "4: Command-line help\n"
|
||||||
printf "5: Command-line help\n"
|
|
||||||
printf "Q: Quit\n\n"
|
printf "Q: Quit\n\n"
|
||||||
read -p "Please enter 1-10, Q: [1] " yn
|
printf "To update, download and run the installer from https://github.com/invoke-ai/InvokeAI/releases/latest.\n\n"
|
||||||
|
read -p "Please enter 1-4, Q: [1] " yn
|
||||||
choice=${yn:='1'}
|
choice=${yn:='1'}
|
||||||
do_choice $choice
|
do_choice $choice
|
||||||
clear
|
clear
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main IF statement for launching Invoke with either the TUI or CLI, and for checking if the user is in the developer console
|
# Main IF statement for launching Invoke, and for checking if the user is in the developer console
|
||||||
if [ "$0" != "bash" ]; then
|
if [ "$0" != "bash" ]; then
|
||||||
while true; do
|
while true; do
|
||||||
if $tui; then
|
do_line_input
|
||||||
# .dialogrc must be located in the same directory as the invoke.sh script
|
|
||||||
export DIALOGRC="./.dialogrc"
|
|
||||||
do_dialog
|
|
||||||
else
|
|
||||||
do_line_input
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
else # in developer console
|
else # in developer console
|
||||||
python --version
|
python --version
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
# Copyright (c) 2023 Lincoln D. Stein
|
# Copyright (c) 2023 Lincoln D. Stein
|
||||||
"""FastAPI route for model configuration records."""
|
"""FastAPI route for model configuration records."""
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import io
|
import io
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import traceback
|
import traceback
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from enum import Enum
|
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
import huggingface_hub
|
|
||||||
from fastapi import Body, Path, Query, Response, UploadFile
|
from fastapi import Body, Path, Query, Response, UploadFile
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from fastapi.routing import APIRouter
|
from fastapi.routing import APIRouter
|
||||||
@ -21,11 +18,11 @@ from typing_extensions import Annotated
|
|||||||
|
|
||||||
from invokeai.app.services.model_install import ModelInstallJob
|
from invokeai.app.services.model_install import ModelInstallJob
|
||||||
from invokeai.app.services.model_records import (
|
from invokeai.app.services.model_records import (
|
||||||
|
DuplicateModelException,
|
||||||
InvalidModelException,
|
InvalidModelException,
|
||||||
|
ModelRecordChanges,
|
||||||
UnknownModelException,
|
UnknownModelException,
|
||||||
)
|
)
|
||||||
from invokeai.app.services.model_records.model_records_base import DuplicateModelException, ModelRecordChanges
|
|
||||||
from invokeai.app.util.suppress_output import SuppressOutput
|
|
||||||
from invokeai.backend.model_manager.config import (
|
from invokeai.backend.model_manager.config import (
|
||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
@ -37,7 +34,7 @@ from invokeai.backend.model_manager.config import (
|
|||||||
from invokeai.backend.model_manager.metadata.fetch.huggingface import HuggingFaceMetadataFetch
|
from invokeai.backend.model_manager.metadata.fetch.huggingface import HuggingFaceMetadataFetch
|
||||||
from invokeai.backend.model_manager.metadata.metadata_base import ModelMetadataWithFiles, UnknownMetadataException
|
from invokeai.backend.model_manager.metadata.metadata_base import ModelMetadataWithFiles, UnknownMetadataException
|
||||||
from invokeai.backend.model_manager.search import ModelSearch
|
from invokeai.backend.model_manager.search import ModelSearch
|
||||||
from invokeai.backend.model_manager.starter_models import STARTER_MODELS, StarterModel
|
from invokeai.backend.model_manager.starter_models import STARTER_MODELS, StarterModel, StarterModelWithoutDependencies
|
||||||
|
|
||||||
from ..dependencies import ApiDependencies
|
from ..dependencies import ApiDependencies
|
||||||
|
|
||||||
@ -309,8 +306,10 @@ async def update_model_record(
|
|||||||
"""Update a model's config."""
|
"""Update a model's config."""
|
||||||
logger = ApiDependencies.invoker.services.logger
|
logger = ApiDependencies.invoker.services.logger
|
||||||
record_store = ApiDependencies.invoker.services.model_manager.store
|
record_store = ApiDependencies.invoker.services.model_manager.store
|
||||||
|
installer = ApiDependencies.invoker.services.model_manager.install
|
||||||
try:
|
try:
|
||||||
model_response: AnyModelConfig = record_store.update_model(key, changes=changes)
|
record_store.update_model(key, changes=changes)
|
||||||
|
model_response: AnyModelConfig = installer.sync_model_path(key)
|
||||||
logger.info(f"Updated model: {key}")
|
logger.info(f"Updated model: {key}")
|
||||||
except UnknownModelException as e:
|
except UnknownModelException as e:
|
||||||
raise HTTPException(status_code=404, detail=str(e))
|
raise HTTPException(status_code=404, detail=str(e))
|
||||||
@ -442,41 +441,6 @@ async def delete_model_image(
|
|||||||
raise HTTPException(status_code=404, detail=str(e))
|
raise HTTPException(status_code=404, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
# @model_manager_router.post(
|
|
||||||
# "/i/",
|
|
||||||
# operation_id="add_model_record",
|
|
||||||
# responses={
|
|
||||||
# 201: {
|
|
||||||
# "description": "The model added successfully",
|
|
||||||
# "content": {"application/json": {"example": example_model_config}},
|
|
||||||
# },
|
|
||||||
# 409: {"description": "There is already a model corresponding to this path or repo_id"},
|
|
||||||
# 415: {"description": "Unrecognized file/folder format"},
|
|
||||||
# },
|
|
||||||
# status_code=201,
|
|
||||||
# )
|
|
||||||
# async def add_model_record(
|
|
||||||
# config: Annotated[
|
|
||||||
# AnyModelConfig, Body(description="Model config", discriminator="type", example=example_model_input)
|
|
||||||
# ],
|
|
||||||
# ) -> AnyModelConfig:
|
|
||||||
# """Add a model using the configuration information appropriate for its type."""
|
|
||||||
# logger = ApiDependencies.invoker.services.logger
|
|
||||||
# record_store = ApiDependencies.invoker.services.model_manager.store
|
|
||||||
# try:
|
|
||||||
# record_store.add_model(config)
|
|
||||||
# except DuplicateModelException as e:
|
|
||||||
# logger.error(str(e))
|
|
||||||
# raise HTTPException(status_code=409, detail=str(e))
|
|
||||||
# except InvalidModelException as e:
|
|
||||||
# logger.error(str(e))
|
|
||||||
# raise HTTPException(status_code=415)
|
|
||||||
|
|
||||||
# # now fetch it out
|
|
||||||
# result: AnyModelConfig = record_store.get_model(config.key)
|
|
||||||
# return result
|
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.post(
|
@model_manager_router.post(
|
||||||
"/install",
|
"/install",
|
||||||
operation_id="install_model",
|
operation_id="install_model",
|
||||||
@ -628,25 +592,6 @@ async def prune_model_install_jobs() -> Response:
|
|||||||
return Response(status_code=204)
|
return Response(status_code=204)
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.patch(
|
|
||||||
"/sync",
|
|
||||||
operation_id="sync_models_to_config",
|
|
||||||
responses={
|
|
||||||
204: {"description": "Model config record database resynced with files on disk"},
|
|
||||||
400: {"description": "Bad request"},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
async def sync_models_to_config() -> Response:
|
|
||||||
"""
|
|
||||||
Traverse the models and autoimport directories.
|
|
||||||
|
|
||||||
Model files without a corresponding
|
|
||||||
record in the database are added. Orphan records without a models file are deleted.
|
|
||||||
"""
|
|
||||||
ApiDependencies.invoker.services.model_manager.install.sync_to_config()
|
|
||||||
return Response(status_code=204)
|
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.put(
|
@model_manager_router.put(
|
||||||
"/convert/{key}",
|
"/convert/{key}",
|
||||||
operation_id="convert_model",
|
operation_id="convert_model",
|
||||||
@ -669,8 +614,8 @@ async def convert_model(
|
|||||||
The return value is the model configuration for the converted model.
|
The return value is the model configuration for the converted model.
|
||||||
"""
|
"""
|
||||||
model_manager = ApiDependencies.invoker.services.model_manager
|
model_manager = ApiDependencies.invoker.services.model_manager
|
||||||
|
loader = model_manager.load
|
||||||
logger = ApiDependencies.invoker.services.logger
|
logger = ApiDependencies.invoker.services.logger
|
||||||
loader = ApiDependencies.invoker.services.model_manager.load
|
|
||||||
store = ApiDependencies.invoker.services.model_manager.store
|
store = ApiDependencies.invoker.services.model_manager.store
|
||||||
installer = ApiDependencies.invoker.services.model_manager.install
|
installer = ApiDependencies.invoker.services.model_manager.install
|
||||||
|
|
||||||
@ -685,7 +630,13 @@ async def convert_model(
|
|||||||
raise HTTPException(400, f"The model with key {key} is not a main checkpoint model.")
|
raise HTTPException(400, f"The model with key {key} is not a main checkpoint model.")
|
||||||
|
|
||||||
# loading the model will convert it into a cached diffusers file
|
# loading the model will convert it into a cached diffusers file
|
||||||
model_manager.load.load_model(model_config, submodel_type=SubModelType.Scheduler)
|
try:
|
||||||
|
cc_size = loader.convert_cache.max_size
|
||||||
|
if cc_size == 0: # temporary set the convert cache to a positive number so that cached model is written
|
||||||
|
loader._convert_cache.max_size = 1.0
|
||||||
|
loader.load_model(model_config, submodel_type=SubModelType.Scheduler)
|
||||||
|
finally:
|
||||||
|
loader._convert_cache.max_size = cc_size
|
||||||
|
|
||||||
# Get the path of the converted model from the loader
|
# Get the path of the converted model from the loader
|
||||||
cache_path = loader.convert_cache.cache_path(key)
|
cache_path = loader.convert_cache.cache_path(key)
|
||||||
@ -723,71 +674,6 @@ async def convert_model(
|
|||||||
return new_config
|
return new_config
|
||||||
|
|
||||||
|
|
||||||
# @model_manager_router.put(
|
|
||||||
# "/merge",
|
|
||||||
# operation_id="merge",
|
|
||||||
# responses={
|
|
||||||
# 200: {
|
|
||||||
# "description": "Model converted successfully",
|
|
||||||
# "content": {"application/json": {"example": example_model_config}},
|
|
||||||
# },
|
|
||||||
# 400: {"description": "Bad request"},
|
|
||||||
# 404: {"description": "Model not found"},
|
|
||||||
# 409: {"description": "There is already a model registered at this location"},
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# async def merge(
|
|
||||||
# keys: List[str] = Body(description="Keys for two to three models to merge", min_length=2, max_length=3),
|
|
||||||
# merged_model_name: Optional[str] = Body(description="Name of destination model", default=None),
|
|
||||||
# alpha: float = Body(description="Alpha weighting strength to apply to 2d and 3d models", default=0.5),
|
|
||||||
# force: bool = Body(
|
|
||||||
# description="Force merging of models created with different versions of diffusers",
|
|
||||||
# default=False,
|
|
||||||
# ),
|
|
||||||
# interp: Optional[MergeInterpolationMethod] = Body(description="Interpolation method", default=None),
|
|
||||||
# merge_dest_directory: Optional[str] = Body(
|
|
||||||
# description="Save the merged model to the designated directory (with 'merged_model_name' appended)",
|
|
||||||
# default=None,
|
|
||||||
# ),
|
|
||||||
# ) -> AnyModelConfig:
|
|
||||||
# """
|
|
||||||
# Merge diffusers models. The process is controlled by a set parameters provided in the body of the request.
|
|
||||||
# ```
|
|
||||||
# Argument Description [default]
|
|
||||||
# -------- ----------------------
|
|
||||||
# keys List of 2-3 model keys to merge together. All models must use the same base type.
|
|
||||||
# merged_model_name Name for the merged model [Concat model names]
|
|
||||||
# alpha Alpha value (0.0-1.0). Higher values give more weight to the second model [0.5]
|
|
||||||
# force If true, force the merge even if the models were generated by different versions of the diffusers library [False]
|
|
||||||
# interp Interpolation method. One of "weighted_sum", "sigmoid", "inv_sigmoid" or "add_difference" [weighted_sum]
|
|
||||||
# merge_dest_directory Specify a directory to store the merged model in [models directory]
|
|
||||||
# ```
|
|
||||||
# """
|
|
||||||
# logger = ApiDependencies.invoker.services.logger
|
|
||||||
# try:
|
|
||||||
# logger.info(f"Merging models: {keys} into {merge_dest_directory or '<MODELS>'}/{merged_model_name}")
|
|
||||||
# dest = pathlib.Path(merge_dest_directory) if merge_dest_directory else None
|
|
||||||
# installer = ApiDependencies.invoker.services.model_manager.install
|
|
||||||
# merger = ModelMerger(installer)
|
|
||||||
# model_names = [installer.record_store.get_model(x).name for x in keys]
|
|
||||||
# response = merger.merge_diffusion_models_and_save(
|
|
||||||
# model_keys=keys,
|
|
||||||
# merged_model_name=merged_model_name or "+".join(model_names),
|
|
||||||
# alpha=alpha,
|
|
||||||
# interp=interp,
|
|
||||||
# force=force,
|
|
||||||
# merge_dest_directory=dest,
|
|
||||||
# )
|
|
||||||
# except UnknownModelException:
|
|
||||||
# raise HTTPException(
|
|
||||||
# status_code=404,
|
|
||||||
# detail=f"One or more of the models '{keys}' not found",
|
|
||||||
# )
|
|
||||||
# except ValueError as e:
|
|
||||||
# raise HTTPException(status_code=400, detail=str(e))
|
|
||||||
# return response
|
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.get("/starter_models", operation_id="get_starter_models", response_model=list[StarterModel])
|
@model_manager_router.get("/starter_models", operation_id="get_starter_models", response_model=list[StarterModel])
|
||||||
async def get_starter_models() -> list[StarterModel]:
|
async def get_starter_models() -> list[StarterModel]:
|
||||||
installed_models = ApiDependencies.invoker.services.model_manager.store.search_by_attr()
|
installed_models = ApiDependencies.invoker.services.model_manager.store.search_by_attr()
|
||||||
@ -797,58 +683,10 @@ async def get_starter_models() -> list[StarterModel]:
|
|||||||
if model.source in installed_model_sources:
|
if model.source in installed_model_sources:
|
||||||
model.is_installed = True
|
model.is_installed = True
|
||||||
# Remove already-installed dependencies
|
# Remove already-installed dependencies
|
||||||
missing_deps: list[str] = []
|
missing_deps: list[StarterModelWithoutDependencies] = []
|
||||||
for dep in model.dependencies or []:
|
for dep in model.dependencies or []:
|
||||||
if dep not in installed_model_sources:
|
if dep.source not in installed_model_sources:
|
||||||
missing_deps.append(dep)
|
missing_deps.append(dep)
|
||||||
model.dependencies = missing_deps
|
model.dependencies = missing_deps
|
||||||
|
|
||||||
return starter_models
|
return starter_models
|
||||||
|
|
||||||
|
|
||||||
class HFTokenStatus(str, Enum):
|
|
||||||
VALID = "valid"
|
|
||||||
INVALID = "invalid"
|
|
||||||
UNKNOWN = "unknown"
|
|
||||||
|
|
||||||
|
|
||||||
class HFTokenHelper:
|
|
||||||
@classmethod
|
|
||||||
def get_status(cls) -> HFTokenStatus:
|
|
||||||
try:
|
|
||||||
if huggingface_hub.get_token_permission(huggingface_hub.get_token()):
|
|
||||||
# Valid token!
|
|
||||||
return HFTokenStatus.VALID
|
|
||||||
# No token set
|
|
||||||
return HFTokenStatus.INVALID
|
|
||||||
except Exception:
|
|
||||||
return HFTokenStatus.UNKNOWN
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def set_token(cls, token: str) -> HFTokenStatus:
|
|
||||||
with SuppressOutput(), contextlib.suppress(Exception):
|
|
||||||
huggingface_hub.login(token=token, add_to_git_credential=False)
|
|
||||||
return cls.get_status()
|
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.get("/hf_login", operation_id="get_hf_login_status", response_model=HFTokenStatus)
|
|
||||||
async def get_hf_login_status() -> HFTokenStatus:
|
|
||||||
token_status = HFTokenHelper.get_status()
|
|
||||||
|
|
||||||
if token_status is HFTokenStatus.UNKNOWN:
|
|
||||||
ApiDependencies.invoker.services.logger.warning("Unable to verify HF token")
|
|
||||||
|
|
||||||
return token_status
|
|
||||||
|
|
||||||
|
|
||||||
@model_manager_router.post("/hf_login", operation_id="do_hf_login", response_model=HFTokenStatus)
|
|
||||||
async def do_hf_login(
|
|
||||||
token: str = Body(description="Hugging Face token to use for login", embed=True),
|
|
||||||
) -> HFTokenStatus:
|
|
||||||
HFTokenHelper.set_token(token)
|
|
||||||
token_status = HFTokenHelper.get_status()
|
|
||||||
|
|
||||||
if token_status is HFTokenStatus.UNKNOWN:
|
|
||||||
ApiDependencies.invoker.services.logger.warning("Unable to verify HF token")
|
|
||||||
|
|
||||||
return token_status
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import socket
|
import socket
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
@ -6,6 +7,7 @@ from inspect import signature
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import torch
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
@ -26,6 +28,7 @@ from invokeai.app.api.no_cache_staticfiles import NoCacheStaticFiles
|
|||||||
from invokeai.app.invocations.model import ModelIdentifierField
|
from invokeai.app.invocations.model import ModelIdentifierField
|
||||||
from invokeai.app.services.config.config_default import get_config
|
from invokeai.app.services.config.config_default import get_config
|
||||||
from invokeai.app.services.session_processor.session_processor_common import ProgressImage
|
from invokeai.app.services.session_processor.session_processor_common import ProgressImage
|
||||||
|
from invokeai.backend.util.devices import get_torch_device_name
|
||||||
|
|
||||||
from ..backend.util.logging import InvokeAILogger
|
from ..backend.util.logging import InvokeAILogger
|
||||||
from .api.dependencies import ApiDependencies
|
from .api.dependencies import ApiDependencies
|
||||||
@ -60,6 +63,9 @@ logger = InvokeAILogger.get_logger(config=app_config)
|
|||||||
mimetypes.add_type("application/javascript", ".js")
|
mimetypes.add_type("application/javascript", ".js")
|
||||||
mimetypes.add_type("text/css", ".css")
|
mimetypes.add_type("text/css", ".css")
|
||||||
|
|
||||||
|
torch_device_name = get_torch_device_name()
|
||||||
|
logger.info(f"Using torch device: {torch_device_name}")
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
@ -222,6 +228,22 @@ app.mount(
|
|||||||
) # docs favicon is in here
|
) # docs favicon is in here
|
||||||
|
|
||||||
|
|
||||||
|
def check_cudnn(logger: logging.Logger) -> None:
|
||||||
|
"""Check for cuDNN issues that could be causing degraded performance."""
|
||||||
|
if torch.backends.cudnn.is_available():
|
||||||
|
try:
|
||||||
|
# Note: At the time of writing (torch 2.2.1), torch.backends.cudnn.version() only raises an error the first
|
||||||
|
# time it is called. Subsequent calls will return the version number without complaining about a mismatch.
|
||||||
|
cudnn_version = torch.backends.cudnn.version()
|
||||||
|
logger.info(f"cuDNN version: {cudnn_version}")
|
||||||
|
except RuntimeError as e:
|
||||||
|
logger.warning(
|
||||||
|
"Encountered a cuDNN version issue. This may result in degraded performance. This issue is usually "
|
||||||
|
"caused by an incompatible cuDNN version installed in your python environment, or on the host "
|
||||||
|
f"system. Full error message:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def invoke_api() -> None:
|
def invoke_api() -> None:
|
||||||
def find_port(port: int) -> int:
|
def find_port(port: int) -> int:
|
||||||
"""Find a port not in use starting at given port"""
|
"""Find a port not in use starting at given port"""
|
||||||
@ -248,6 +270,8 @@ def invoke_api() -> None:
|
|||||||
if port != app_config.port:
|
if port != app_config.port:
|
||||||
logger.warn(f"Port {app_config.port} in use, using port {port}")
|
logger.warn(f"Port {app_config.port} in use, using port {port}")
|
||||||
|
|
||||||
|
check_cudnn(logger)
|
||||||
|
|
||||||
# Start our own event loop for eventing usage
|
# Start our own event loop for eventing usage
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
config = uvicorn.Config(
|
config = uvicorn.Config(
|
||||||
|
@ -967,3 +967,56 @@ class CanvasPasteBackInvocation(BaseInvocation, WithMetadata, WithBoard):
|
|||||||
|
|
||||||
image_dto = context.images.save(image=source_image)
|
image_dto = context.images.save(image=source_image)
|
||||||
return ImageOutput.build(image_dto)
|
return ImageOutput.build(image_dto)
|
||||||
|
|
||||||
|
|
||||||
|
@invocation(
|
||||||
|
"mask_from_id",
|
||||||
|
title="Mask from ID",
|
||||||
|
tags=["image", "mask", "id"],
|
||||||
|
category="image",
|
||||||
|
version="1.0.0",
|
||||||
|
)
|
||||||
|
class MaskFromIDInvocation(BaseInvocation, WithMetadata, WithBoard):
|
||||||
|
"""Generate a mask for a particular color in an ID Map"""
|
||||||
|
|
||||||
|
image: ImageField = InputField(description="The image to create the mask from")
|
||||||
|
color: ColorField = InputField(description="ID color to mask")
|
||||||
|
threshold: int = InputField(default=100, description="Threshold for color detection")
|
||||||
|
invert: bool = InputField(default=False, description="Whether or not to invert the mask")
|
||||||
|
|
||||||
|
def rgba_to_hex(self, rgba_color: tuple[int, int, int, int]):
|
||||||
|
r, g, b, a = rgba_color
|
||||||
|
hex_code = "#{:02X}{:02X}{:02X}{:02X}".format(r, g, b, int(a * 255))
|
||||||
|
return hex_code
|
||||||
|
|
||||||
|
def id_to_mask(self, id_mask: Image.Image, color: tuple[int, int, int, int], threshold: int = 100):
|
||||||
|
if id_mask.mode != "RGB":
|
||||||
|
id_mask = id_mask.convert("RGB")
|
||||||
|
|
||||||
|
# Can directly just use the tuple but I'll leave this rgba_to_hex here
|
||||||
|
# incase anyone prefers using hex codes directly instead of the color picker
|
||||||
|
hex_color_str = self.rgba_to_hex(color)
|
||||||
|
rgb_color = numpy.array([int(hex_color_str[i : i + 2], 16) for i in (1, 3, 5)])
|
||||||
|
|
||||||
|
# Maybe there's a faster way to calculate this distance but I can't think of any right now.
|
||||||
|
color_distance = numpy.linalg.norm(id_mask - rgb_color, axis=-1)
|
||||||
|
|
||||||
|
# Create a mask based on the threshold and the distance calculated above
|
||||||
|
binary_mask = (color_distance < threshold).astype(numpy.uint8) * 255
|
||||||
|
|
||||||
|
# Convert the mask back to PIL
|
||||||
|
binary_mask_pil = Image.fromarray(binary_mask)
|
||||||
|
|
||||||
|
return binary_mask_pil
|
||||||
|
|
||||||
|
def invoke(self, context: InvocationContext) -> ImageOutput:
|
||||||
|
image = context.images.get_pil(self.image.image_name)
|
||||||
|
|
||||||
|
mask = self.id_to_mask(image, self.color.tuple(), self.threshold)
|
||||||
|
|
||||||
|
if self.invert:
|
||||||
|
mask = ImageOps.invert(mask)
|
||||||
|
|
||||||
|
image_dto = context.images.save(image=mask, image_category=ImageCategory.MASK)
|
||||||
|
|
||||||
|
return ImageOutput.build(image_dto)
|
||||||
|
@ -31,7 +31,7 @@ ESRGAN_MODELS = Literal[
|
|||||||
ESRGAN_MODEL_URLS: dict[str, str] = {
|
ESRGAN_MODEL_URLS: dict[str, str] = {
|
||||||
"RealESRGAN_x4plus.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
|
"RealESRGAN_x4plus.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
|
||||||
"RealESRGAN_x4plus_anime_6B.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
|
"RealESRGAN_x4plus_anime_6B.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
|
||||||
"ESRGAN_SRx4_DF2KOST_official.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth",
|
"ESRGAN_SRx4_DF2KOST_official-ff704c30.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth",
|
||||||
"RealESRGAN_x2plus.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
|
"RealESRGAN_x2plus.pth": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ class InvokeAIAppConfig(BaseSettings):
|
|||||||
ssl_keyfile: SSL key file for HTTPS. See https://www.uvicorn.org/settings/#https.
|
ssl_keyfile: SSL key file for HTTPS. See https://www.uvicorn.org/settings/#https.
|
||||||
log_tokenization: Enable logging of parsed prompt tokens.
|
log_tokenization: Enable logging of parsed prompt tokens.
|
||||||
patchmatch: Enable patchmatch inpaint code.
|
patchmatch: Enable patchmatch inpaint code.
|
||||||
autoimport_dir: Path to a directory of models files to be imported on startup.
|
|
||||||
models_dir: Path to the models directory.
|
models_dir: Path to the models directory.
|
||||||
convert_cache_dir: Path to the converted models cache directory. When loading a non-diffusers model, it will be converted and store on disk at this location.
|
convert_cache_dir: Path to the converted models cache directory. When loading a non-diffusers model, it will be converted and store on disk at this location.
|
||||||
legacy_conf_dir: Path to directory of legacy checkpoint config files.
|
legacy_conf_dir: Path to directory of legacy checkpoint config files.
|
||||||
@ -114,6 +113,7 @@ class InvokeAIAppConfig(BaseSettings):
|
|||||||
node_cache_size: How many cached nodes to keep in memory.
|
node_cache_size: How many cached nodes to keep in memory.
|
||||||
hashing_algorithm: Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.<br>Valid values: `blake3_multi`, `blake3_single`, `random`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `blake2b`, `blake2s`, `sha3_224`, `sha3_256`, `sha3_384`, `sha3_512`, `shake_128`, `shake_256`
|
hashing_algorithm: Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.<br>Valid values: `blake3_multi`, `blake3_single`, `random`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `blake2b`, `blake2s`, `sha3_224`, `sha3_256`, `sha3_384`, `sha3_512`, `shake_128`, `shake_256`
|
||||||
remote_api_tokens: List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.
|
remote_api_tokens: List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.
|
||||||
|
scan_models_on_startup: Scan the models directory on startup, registering orphaned models. This is typically only used in conjunction with `use_memory_db` for testing purposes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_root: Optional[Path] = PrivateAttr(default=None)
|
_root: Optional[Path] = PrivateAttr(default=None)
|
||||||
@ -141,7 +141,6 @@ class InvokeAIAppConfig(BaseSettings):
|
|||||||
patchmatch: bool = Field(default=True, description="Enable patchmatch inpaint code.")
|
patchmatch: bool = Field(default=True, description="Enable patchmatch inpaint code.")
|
||||||
|
|
||||||
# PATHS
|
# PATHS
|
||||||
autoimport_dir: Path = Field(default=Path("autoimport"), description="Path to a directory of models files to be imported on startup.")
|
|
||||||
models_dir: Path = Field(default=Path("models"), description="Path to the models directory.")
|
models_dir: Path = Field(default=Path("models"), description="Path to the models directory.")
|
||||||
convert_cache_dir: Path = Field(default=Path("models/.cache"), description="Path to the converted models cache directory. When loading a non-diffusers model, it will be converted and store on disk at this location.")
|
convert_cache_dir: Path = Field(default=Path("models/.cache"), description="Path to the converted models cache directory. When loading a non-diffusers model, it will be converted and store on disk at this location.")
|
||||||
legacy_conf_dir: Path = Field(default=Path("configs"), description="Path to directory of legacy checkpoint config files.")
|
legacy_conf_dir: Path = Field(default=Path("configs"), description="Path to directory of legacy checkpoint config files.")
|
||||||
@ -188,6 +187,7 @@ class InvokeAIAppConfig(BaseSettings):
|
|||||||
# MODEL INSTALL
|
# MODEL INSTALL
|
||||||
hashing_algorithm: HASHING_ALGORITHMS = Field(default="blake3_single", description="Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.")
|
hashing_algorithm: HASHING_ALGORITHMS = Field(default="blake3_single", description="Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.")
|
||||||
remote_api_tokens: Optional[list[URLRegexTokenPair]] = Field(default=None, description="List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.")
|
remote_api_tokens: Optional[list[URLRegexTokenPair]] = Field(default=None, description="List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.")
|
||||||
|
scan_models_on_startup: bool = Field(default=False, description="Scan the models directory on startup, registering orphaned models. This is typically only used in conjunction with `use_memory_db` for testing purposes.")
|
||||||
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
@ -270,11 +270,6 @@ class InvokeAIAppConfig(BaseSettings):
|
|||||||
assert resolved_path is not None
|
assert resolved_path is not None
|
||||||
return resolved_path
|
return resolved_path
|
||||||
|
|
||||||
@property
|
|
||||||
def autoimport_path(self) -> Path:
|
|
||||||
"""Path to the autoimports directory, resolved to an absolute path.."""
|
|
||||||
return self._resolve(self.autoimport_dir)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def outputs_path(self) -> Optional[Path]:
|
def outputs_path(self) -> Optional[Path]:
|
||||||
"""Path to the outputs directory, resolved to an absolute path.."""
|
"""Path to the outputs directory, resolved to an absolute path.."""
|
||||||
|
@ -85,7 +85,7 @@ class DownloadQueueService(DownloadQueueServiceBase):
|
|||||||
self._logger.info(f"Waiting for {len(active_jobs)} active download jobs to complete")
|
self._logger.info(f"Waiting for {len(active_jobs)} active download jobs to complete")
|
||||||
with self._queue.mutex:
|
with self._queue.mutex:
|
||||||
self._queue.queue.clear()
|
self._queue.queue.clear()
|
||||||
self.join() # wait for all active jobs to finish
|
self.cancel_all_jobs()
|
||||||
self._stop_event.set()
|
self._stop_event.set()
|
||||||
for thread in self._worker_pool:
|
for thread in self._worker_pool:
|
||||||
thread.join()
|
thread.join()
|
||||||
|
@ -455,19 +455,18 @@ class ModelInstallServiceBase(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def scan_directory(self, scan_dir: Path, install: bool = False) -> List[str]:
|
def sync_model_path(self, key: str) -> AnyModelConfig:
|
||||||
"""
|
"""
|
||||||
Recursively scan directory for new models and register or install them.
|
Move model into the location indicated by its basetype, type and name.
|
||||||
|
|
||||||
:param scan_dir: Path to the directory to scan.
|
Call this after updating a model's attributes in order to move
|
||||||
:param install: Install if True, otherwise register in place.
|
the model's path into the location indicated by its basetype, type and
|
||||||
:returns list of IDs: Returns list of IDs of models registered/installed
|
name. Applies only to models whose paths are within the root `models_dir`
|
||||||
|
directory.
|
||||||
|
|
||||||
|
May raise an UnknownModelException.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def sync_to_config(self) -> None:
|
|
||||||
"""Synchronize models on disk to those in the model record database."""
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def download_and_cache(self, source: Union[str, AnyHttpUrl], access_token: Optional[str] = None) -> Path:
|
def download_and_cache(self, source: Union[str, AnyHttpUrl], access_token: Optional[str] = None) -> Path:
|
||||||
"""
|
"""
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import signal
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
@ -9,7 +10,7 @@ from pathlib import Path
|
|||||||
from queue import Empty, Queue
|
from queue import Empty, Queue
|
||||||
from shutil import copyfile, copytree, move, rmtree
|
from shutil import copyfile, copytree, move, rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from typing import Any, Dict, List, Optional, Set, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from huggingface_hub import HfFolder
|
from huggingface_hub import HfFolder
|
||||||
@ -24,12 +25,10 @@ from invokeai.app.services.model_records import DuplicateModelException, ModelRe
|
|||||||
from invokeai.app.services.model_records.model_records_base import ModelRecordChanges
|
from invokeai.app.services.model_records.model_records_base import ModelRecordChanges
|
||||||
from invokeai.backend.model_manager.config import (
|
from invokeai.backend.model_manager.config import (
|
||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
|
||||||
CheckpointConfigBase,
|
CheckpointConfigBase,
|
||||||
InvalidModelConfigException,
|
InvalidModelConfigException,
|
||||||
ModelRepoVariant,
|
ModelRepoVariant,
|
||||||
ModelSourceType,
|
ModelSourceType,
|
||||||
ModelType,
|
|
||||||
)
|
)
|
||||||
from invokeai.backend.model_manager.metadata import (
|
from invokeai.backend.model_manager.metadata import (
|
||||||
AnyModelRepoMetadata,
|
AnyModelRepoMetadata,
|
||||||
@ -41,7 +40,7 @@ from invokeai.backend.model_manager.metadata import (
|
|||||||
from invokeai.backend.model_manager.metadata.metadata_base import HuggingFaceMetadata
|
from invokeai.backend.model_manager.metadata.metadata_base import HuggingFaceMetadata
|
||||||
from invokeai.backend.model_manager.probe import ModelProbe
|
from invokeai.backend.model_manager.probe import ModelProbe
|
||||||
from invokeai.backend.model_manager.search import ModelSearch
|
from invokeai.backend.model_manager.search import ModelSearch
|
||||||
from invokeai.backend.util import Chdir, InvokeAILogger
|
from invokeai.backend.util import InvokeAILogger
|
||||||
from invokeai.backend.util.devices import choose_precision, choose_torch_device
|
from invokeai.backend.util.devices import choose_precision, choose_torch_device
|
||||||
|
|
||||||
from .model_install_base import (
|
from .model_install_base import (
|
||||||
@ -83,8 +82,6 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
self._logger = InvokeAILogger.get_logger(name=self.__class__.__name__)
|
self._logger = InvokeAILogger.get_logger(name=self.__class__.__name__)
|
||||||
self._install_jobs: List[ModelInstallJob] = []
|
self._install_jobs: List[ModelInstallJob] = []
|
||||||
self._install_queue: Queue[ModelInstallJob] = Queue()
|
self._install_queue: Queue[ModelInstallJob] = Queue()
|
||||||
self._cached_model_paths: Set[Path] = set()
|
|
||||||
self._models_installed: Set[str] = set()
|
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
self._downloads_changed_event = threading.Event()
|
self._downloads_changed_event = threading.Event()
|
||||||
@ -112,25 +109,46 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
# makes the installer harder to use outside the web app
|
# makes the installer harder to use outside the web app
|
||||||
def start(self, invoker: Optional[Invoker] = None) -> None:
|
def start(self, invoker: Optional[Invoker] = None) -> None:
|
||||||
"""Start the installer thread."""
|
"""Start the installer thread."""
|
||||||
|
|
||||||
|
# Yes, this is weird. When the installer thread is running, the
|
||||||
|
# thread masks the ^C signal. When we receive a
|
||||||
|
# sigINT, we stop the thread, reset sigINT, and send a new
|
||||||
|
# sigINT to the parent process.
|
||||||
|
def sigint_handler(signum, frame):
|
||||||
|
self.stop()
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
signal.raise_signal(signal.SIGINT)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if self._running:
|
if self._running:
|
||||||
raise Exception("Attempt to start the installer service twice")
|
raise Exception("Attempt to start the installer service twice")
|
||||||
self._start_installer_thread()
|
self._start_installer_thread()
|
||||||
self._remove_dangling_install_dirs()
|
self._remove_dangling_install_dirs()
|
||||||
self._migrate_yaml()
|
self._migrate_yaml()
|
||||||
self.sync_to_config()
|
# In normal use, we do not want to scan the models directory - it should never have orphaned models.
|
||||||
|
# We should only do the scan when the flag is set (which should only be set when testing).
|
||||||
|
if self.app_config.scan_models_on_startup:
|
||||||
|
self._register_orphaned_models()
|
||||||
|
|
||||||
|
# Check all models' paths and confirm they exist. A model could be missing if it was installed on a volume
|
||||||
|
# that isn't currently mounted. In this case, we don't want to delete the model from the database, but we do
|
||||||
|
# want to alert the user.
|
||||||
|
for model in self._scan_for_missing_models():
|
||||||
|
self._logger.warning(f"Missing model file: {model.name} at {model.path}")
|
||||||
|
|
||||||
def stop(self, invoker: Optional[Invoker] = None) -> None:
|
def stop(self, invoker: Optional[Invoker] = None) -> None:
|
||||||
"""Stop the installer thread; after this the object can be deleted and garbage collected."""
|
"""Stop the installer thread; after this the object can be deleted and garbage collected."""
|
||||||
with self._lock:
|
if not self._running:
|
||||||
if not self._running:
|
raise Exception("Attempt to stop the install service before it was started")
|
||||||
raise Exception("Attempt to stop the install service before it was started")
|
self._logger.debug("calling stop_event.set()")
|
||||||
self._stop_event.set()
|
self._stop_event.set()
|
||||||
self._clear_pending_jobs()
|
self._clear_pending_jobs()
|
||||||
self._download_cache.clear()
|
self._download_cache.clear()
|
||||||
assert self._install_thread is not None
|
assert self._install_thread is not None
|
||||||
self._install_thread.join()
|
self._install_thread.join()
|
||||||
self._running = False
|
self._running = False
|
||||||
|
|
||||||
def _clear_pending_jobs(self) -> None:
|
def _clear_pending_jobs(self) -> None:
|
||||||
for job in self.list_jobs():
|
for job in self.list_jobs():
|
||||||
@ -293,15 +311,6 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
unfinished_jobs = [x for x in self._install_jobs if not x.in_terminal_state]
|
unfinished_jobs = [x for x in self._install_jobs if not x.in_terminal_state]
|
||||||
self._install_jobs = unfinished_jobs
|
self._install_jobs = unfinished_jobs
|
||||||
|
|
||||||
def sync_to_config(self) -> None:
|
|
||||||
"""Synchronize models on disk to those in the config record store database."""
|
|
||||||
self._scan_models_directory()
|
|
||||||
if self._app_config.autoimport_path:
|
|
||||||
self._logger.info("Scanning autoimport directory for new models")
|
|
||||||
installed = self.scan_directory(self._app_config.autoimport_path)
|
|
||||||
self._logger.info(f"{len(installed)} new models registered")
|
|
||||||
self._logger.info("Model installer (re)initialized")
|
|
||||||
|
|
||||||
def _migrate_yaml(self) -> None:
|
def _migrate_yaml(self) -> None:
|
||||||
db_models = self.record_store.all_models()
|
db_models = self.record_store.all_models()
|
||||||
|
|
||||||
@ -339,8 +348,13 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
config: dict[str, Any] = {}
|
config: dict[str, Any] = {}
|
||||||
config["name"] = model_name
|
config["name"] = model_name
|
||||||
config["description"] = stanza.get("description")
|
config["description"] = stanza.get("description")
|
||||||
config["config_path"] = stanza.get("config")
|
legacy_config_path = stanza.get("config")
|
||||||
|
if legacy_config_path:
|
||||||
|
# In v3, these paths were relative to the root. Migrate them to be relative to the legacy_conf_dir.
|
||||||
|
legacy_config_path: Path = self._app_config.root_path / legacy_config_path
|
||||||
|
if legacy_config_path.is_relative_to(self._app_config.legacy_conf_path):
|
||||||
|
legacy_config_path = legacy_config_path.relative_to(self._app_config.legacy_conf_path)
|
||||||
|
config["config_path"] = str(legacy_config_path)
|
||||||
try:
|
try:
|
||||||
id = self.register_path(model_path=model_path, config=config)
|
id = self.register_path(model_path=model_path, config=config)
|
||||||
self._logger.info(f"Migrated {model_name} with id {id}")
|
self._logger.info(f"Migrated {model_name} with id {id}")
|
||||||
@ -353,34 +367,28 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
# Unset the path - we are done with it either way
|
# Unset the path - we are done with it either way
|
||||||
self._app_config.legacy_models_yaml_path = None
|
self._app_config.legacy_models_yaml_path = None
|
||||||
|
|
||||||
def scan_directory(self, scan_dir: Path, install: bool = False) -> List[str]: # noqa D102
|
|
||||||
self._cached_model_paths = {Path(x.path).resolve() for x in self.record_store.all_models()}
|
|
||||||
callback = self._scan_install if install else self._scan_register
|
|
||||||
search = ModelSearch(on_model_found=callback)
|
|
||||||
self._models_installed.clear()
|
|
||||||
search.search(scan_dir)
|
|
||||||
return list(self._models_installed)
|
|
||||||
|
|
||||||
def unregister(self, key: str) -> None: # noqa D102
|
def unregister(self, key: str) -> None: # noqa D102
|
||||||
self.record_store.del_model(key)
|
self.record_store.del_model(key)
|
||||||
|
|
||||||
def delete(self, key: str) -> None: # noqa D102
|
def delete(self, key: str) -> None: # noqa D102
|
||||||
"""Unregister the model. Delete its files only if they are within our models directory."""
|
"""Unregister the model. Delete its files only if they are within our models directory."""
|
||||||
model = self.record_store.get_model(key)
|
model = self.record_store.get_model(key)
|
||||||
models_dir = self.app_config.models_path
|
model_path = self.app_config.models_path / model.path
|
||||||
model_path = models_dir / Path(model.path) # handle legacy relative model paths
|
|
||||||
if model_path.is_relative_to(models_dir):
|
if model_path.is_relative_to(self.app_config.models_path):
|
||||||
|
# If the models is in the Invoke-managed models dir, we delete it
|
||||||
self.unconditionally_delete(key)
|
self.unconditionally_delete(key)
|
||||||
else:
|
else:
|
||||||
|
# Else we only unregister it, leaving the file in place
|
||||||
self.unregister(key)
|
self.unregister(key)
|
||||||
|
|
||||||
def unconditionally_delete(self, key: str) -> None: # noqa D102
|
def unconditionally_delete(self, key: str) -> None: # noqa D102
|
||||||
model = self.record_store.get_model(key)
|
model = self.record_store.get_model(key)
|
||||||
model_path = self.app_config.models_path / model.path
|
model_path = self.app_config.models_path / model.path
|
||||||
if model_path.is_dir():
|
if model_path.is_file() or model_path.is_symlink():
|
||||||
rmtree(model_path)
|
|
||||||
else:
|
|
||||||
model_path.unlink()
|
model_path.unlink()
|
||||||
|
elif model_path.is_dir():
|
||||||
|
rmtree(model_path)
|
||||||
self.unregister(key)
|
self.unregister(key)
|
||||||
|
|
||||||
def download_and_cache(
|
def download_and_cache(
|
||||||
@ -444,11 +452,10 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
elif job.waiting or job.downloads_done:
|
elif job.waiting or job.downloads_done:
|
||||||
self._register_or_install(job)
|
self._register_or_install(job)
|
||||||
|
|
||||||
except InvalidModelConfigException as excp:
|
except Exception as e:
|
||||||
self._set_error(job, excp)
|
# Expected errors include InvalidModelConfigException, DuplicateModelException, OSError, but we must
|
||||||
|
# gracefully handle _any_ error here.
|
||||||
except (OSError, DuplicateModelException) as excp:
|
self._set_error(job, e)
|
||||||
self._set_error(job, excp)
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# if this is an install of a remote file, then clean up the temporary directory
|
# if this is an install of a remote file, then clean up the temporary directory
|
||||||
@ -497,36 +504,48 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
self._logger.info(f"Removing dangling temporary directory {tmpdir}")
|
self._logger.info(f"Removing dangling temporary directory {tmpdir}")
|
||||||
rmtree(tmpdir)
|
rmtree(tmpdir)
|
||||||
|
|
||||||
def _scan_models_directory(self) -> None:
|
def _scan_for_missing_models(self) -> list[AnyModelConfig]:
|
||||||
|
"""Scan the models directory for missing models and return a list of them."""
|
||||||
|
missing_models: list[AnyModelConfig] = []
|
||||||
|
for model_config in self.record_store.all_models():
|
||||||
|
if not (self.app_config.models_path / model_config.path).resolve().exists():
|
||||||
|
missing_models.append(model_config)
|
||||||
|
return missing_models
|
||||||
|
|
||||||
|
def _register_orphaned_models(self) -> None:
|
||||||
|
"""Scan the invoke-managed models directory for orphaned models and registers them.
|
||||||
|
|
||||||
|
This is typically only used during testing with a new DB or when using the memory DB, because those are the
|
||||||
|
only situations in which we may have orphaned models in the models directory.
|
||||||
"""
|
"""
|
||||||
Scan the models directory for new and missing models.
|
|
||||||
|
|
||||||
New models will be added to the storage backend. Missing models
|
installed_model_paths = {
|
||||||
will be deleted.
|
(self._app_config.models_path / x.path).resolve() for x in self.record_store.all_models()
|
||||||
"""
|
}
|
||||||
defunct_models = set()
|
|
||||||
installed = set()
|
|
||||||
|
|
||||||
with Chdir(self._app_config.models_path):
|
# The bool returned by this callback determines if the model is added to the list of models found by the search
|
||||||
self._logger.info("Checking for models that have been moved or deleted from disk")
|
def on_model_found(model_path: Path) -> bool:
|
||||||
for model_config in self.record_store.all_models():
|
resolved_path = model_path.resolve()
|
||||||
path = Path(model_config.path)
|
# Already registered models should be in the list of found models, but not re-registered.
|
||||||
if not path.exists():
|
if resolved_path in installed_model_paths:
|
||||||
self._logger.info(f"{model_config.name}: path {path.as_posix()} no longer exists. Unregistering")
|
return True
|
||||||
defunct_models.add(model_config.key)
|
# Skip core models entirely - these aren't registered with the model manager.
|
||||||
for key in defunct_models:
|
if str(resolved_path).startswith(str(self.app_config.models_path / "core")):
|
||||||
self.unregister(key)
|
return False
|
||||||
|
try:
|
||||||
|
model_id = self.register_path(model_path)
|
||||||
|
self._logger.info(f"Registered {model_path.name} with id {model_id}")
|
||||||
|
except DuplicateModelException:
|
||||||
|
# In case a duplicate models sneaks by, we will ignore this error - we "found" the model
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
|
||||||
self._logger.info(f"Scanning {self._app_config.models_path} for new and orphaned models")
|
self._logger.info(f"Scanning {self._app_config.models_path} for orphaned models")
|
||||||
for cur_base_model in BaseModelType:
|
search = ModelSearch(on_model_found=on_model_found)
|
||||||
for cur_model_type in ModelType:
|
found_models = search.search(self._app_config.models_path)
|
||||||
models_dir = self._app_config.models_path / Path(cur_base_model.value, cur_model_type.value)
|
self._logger.info(f"{len(found_models)} new models registered")
|
||||||
if not models_dir.exists():
|
|
||||||
continue
|
|
||||||
installed.update(self.scan_directory(models_dir))
|
|
||||||
self._logger.info(f"{len(installed)} new models registered; {len(defunct_models)} unregistered")
|
|
||||||
|
|
||||||
def _sync_model_path(self, key: str) -> AnyModelConfig:
|
def sync_model_path(self, key: str) -> AnyModelConfig:
|
||||||
"""
|
"""
|
||||||
Move model into the location indicated by its basetype, type and name.
|
Move model into the location indicated by its basetype, type and name.
|
||||||
|
|
||||||
@ -538,49 +557,24 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
May raise an UnknownModelException.
|
May raise an UnknownModelException.
|
||||||
"""
|
"""
|
||||||
model = self.record_store.get_model(key)
|
model = self.record_store.get_model(key)
|
||||||
old_path = Path(model.path)
|
|
||||||
models_dir = self.app_config.models_path
|
models_dir = self.app_config.models_path
|
||||||
|
old_path = self.app_config.models_path / model.path
|
||||||
|
|
||||||
try:
|
if not old_path.is_relative_to(models_dir):
|
||||||
old_path.relative_to(models_dir)
|
# The model is not in the models directory - we don't need to move it.
|
||||||
return model
|
return model
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
new_path = models_dir / model.base.value / model.type.value / old_path.name
|
new_path = (models_dir / model.base.value / model.type.value / model.name).with_suffix(old_path.suffix)
|
||||||
|
|
||||||
if old_path == new_path or new_path.exists() and old_path == new_path.resolve():
|
if old_path == new_path or new_path.exists() and old_path == new_path.resolve():
|
||||||
return model
|
return model
|
||||||
|
|
||||||
self._logger.info(f"Moving {model.name} to {new_path}.")
|
self._logger.info(f"Moving {model.name} to {new_path}.")
|
||||||
new_path = self._move_model(old_path, new_path)
|
new_path = self._move_model(old_path, new_path)
|
||||||
model.path = new_path.as_posix()
|
model.path = new_path.relative_to(models_dir).as_posix()
|
||||||
self.record_store.update_model(key, ModelRecordChanges(path=model.path))
|
self.record_store.update_model(key, ModelRecordChanges(path=model.path))
|
||||||
return model
|
return model
|
||||||
|
|
||||||
def _scan_register(self, model: Path) -> bool:
|
|
||||||
if model in self._cached_model_paths:
|
|
||||||
return True
|
|
||||||
try:
|
|
||||||
id = self.register_path(model)
|
|
||||||
self._sync_model_path(id) # possibly move it to right place in `models`
|
|
||||||
self._logger.info(f"Registered {model.name} with id {id}")
|
|
||||||
self._models_installed.add(id)
|
|
||||||
except DuplicateModelException:
|
|
||||||
pass
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _scan_install(self, model: Path) -> bool:
|
|
||||||
if model in self._cached_model_paths:
|
|
||||||
return True
|
|
||||||
try:
|
|
||||||
id = self.install_path(model)
|
|
||||||
self._logger.info(f"Installed {model} with id {id}")
|
|
||||||
self._models_installed.add(id)
|
|
||||||
except DuplicateModelException:
|
|
||||||
pass
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _copy_model(self, old_path: Path, new_path: Path) -> Path:
|
def _copy_model(self, old_path: Path, new_path: Path) -> Path:
|
||||||
if old_path == new_path:
|
if old_path == new_path:
|
||||||
return old_path
|
return old_path
|
||||||
@ -616,12 +610,19 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
|
|
||||||
model_path = model_path.resolve()
|
model_path = model_path.resolve()
|
||||||
|
|
||||||
|
# Models in the Invoke-managed models dir should use relative paths.
|
||||||
|
if model_path.is_relative_to(self.app_config.models_path):
|
||||||
|
model_path = model_path.relative_to(self.app_config.models_path)
|
||||||
|
|
||||||
info.path = model_path.as_posix()
|
info.path = model_path.as_posix()
|
||||||
|
|
||||||
# Checkpoints have a config file needed for conversion - resolve this to an absolute path
|
|
||||||
if isinstance(info, CheckpointConfigBase):
|
if isinstance(info, CheckpointConfigBase):
|
||||||
legacy_conf = (self.app_config.legacy_conf_path / info.config_path).resolve()
|
# Checkpoints have a config file needed for conversion. Same handling as the model weights - if it's in the
|
||||||
info.config_path = legacy_conf.as_posix()
|
# invoke-managed legacy config dir, we use a relative path.
|
||||||
|
legacy_config_path = self.app_config.legacy_conf_path / info.config_path
|
||||||
|
if legacy_config_path.is_relative_to(self.app_config.legacy_conf_path):
|
||||||
|
legacy_config_path = legacy_config_path.relative_to(self.app_config.legacy_conf_path)
|
||||||
|
info.config_path = legacy_config_path.as_posix()
|
||||||
self.record_store.add_model(info)
|
self.record_store.add_model(info)
|
||||||
return info.key
|
return info.key
|
||||||
|
|
||||||
@ -901,7 +902,7 @@ class ModelInstallService(ModelInstallServiceBase):
|
|||||||
self._event_bus.emit_model_install_completed(str(job.source), key, id=job.id)
|
self._event_bus.emit_model_install_completed(str(job.source), key, id=job.id)
|
||||||
|
|
||||||
def _signal_job_errored(self, job: ModelInstallJob) -> None:
|
def _signal_job_errored(self, job: ModelInstallJob) -> None:
|
||||||
self._logger.info(f"Model install error: {job.source}, {job.error_type}\n{job.error}")
|
self._logger.error(f"Model install error: {job.source}\n{job.error_type}: {job.error}")
|
||||||
if self._event_bus:
|
if self._event_bus:
|
||||||
error_type = job.error_type
|
error_type = job.error_type
|
||||||
error = job.error
|
error = job.error
|
||||||
|
@ -6,6 +6,7 @@ from .model_records_base import ( # noqa F401
|
|||||||
ModelRecordServiceBase,
|
ModelRecordServiceBase,
|
||||||
UnknownModelException,
|
UnknownModelException,
|
||||||
ModelSummary,
|
ModelSummary,
|
||||||
|
ModelRecordChanges,
|
||||||
ModelRecordOrderBy,
|
ModelRecordOrderBy,
|
||||||
)
|
)
|
||||||
from .model_records_sql import ModelRecordServiceSQL # noqa F401
|
from .model_records_sql import ModelRecordServiceSQL # noqa F401
|
||||||
@ -17,5 +18,6 @@ __all__ = [
|
|||||||
"InvalidModelException",
|
"InvalidModelException",
|
||||||
"UnknownModelException",
|
"UnknownModelException",
|
||||||
"ModelSummary",
|
"ModelSummary",
|
||||||
|
"ModelRecordChanges",
|
||||||
"ModelRecordOrderBy",
|
"ModelRecordOrderBy",
|
||||||
]
|
]
|
||||||
|
@ -70,8 +70,18 @@ class DefaultSessionProcessor(SessionProcessorBase):
|
|||||||
async def _on_queue_event(self, event: FastAPIEvent) -> None:
|
async def _on_queue_event(self, event: FastAPIEvent) -> None:
|
||||||
event_name = event[1]["event"]
|
event_name = event[1]["event"]
|
||||||
|
|
||||||
if event_name == "session_canceled" or event_name == "queue_cleared":
|
if (
|
||||||
# These both mean we should cancel the current session.
|
event_name == "session_canceled"
|
||||||
|
and self._queue_item
|
||||||
|
and self._queue_item.item_id == event[1]["data"]["queue_item_id"]
|
||||||
|
):
|
||||||
|
self._cancel_event.set()
|
||||||
|
self._poll_now()
|
||||||
|
elif (
|
||||||
|
event_name == "queue_cleared"
|
||||||
|
and self._queue_item
|
||||||
|
and self._queue_item.queue_id == event[1]["data"]["queue_id"]
|
||||||
|
):
|
||||||
self._cancel_event.set()
|
self._cancel_event.set()
|
||||||
self._poll_now()
|
self._poll_now()
|
||||||
elif event_name == "batch_enqueued":
|
elif event_name == "batch_enqueued":
|
||||||
@ -111,146 +121,153 @@ class DefaultSessionProcessor(SessionProcessorBase):
|
|||||||
poll_now_event.clear()
|
poll_now_event.clear()
|
||||||
# Middle processor try block; any unhandled exception is a non-fatal processor error
|
# Middle processor try block; any unhandled exception is a non-fatal processor error
|
||||||
try:
|
try:
|
||||||
# Get the next session to process
|
# If we are paused, wait for resume event
|
||||||
self._queue_item = self._invoker.services.session_queue.dequeue()
|
if resume_event.is_set():
|
||||||
if self._queue_item is not None and resume_event.is_set():
|
# Get the next session to process
|
||||||
self._invoker.services.logger.debug(f"Executing queue item {self._queue_item.item_id}")
|
self._queue_item = self._invoker.services.session_queue.dequeue()
|
||||||
cancel_event.clear()
|
|
||||||
|
|
||||||
# If profiling is enabled, start the profiler
|
if self._queue_item is not None:
|
||||||
if self._profiler is not None:
|
self._invoker.services.logger.debug(f"Executing queue item {self._queue_item.item_id}")
|
||||||
self._profiler.start(profile_id=self._queue_item.session_id)
|
cancel_event.clear()
|
||||||
|
|
||||||
# Prepare invocations and take the first
|
# If profiling is enabled, start the profiler
|
||||||
self._invocation = self._queue_item.session.next()
|
if self._profiler is not None:
|
||||||
|
self._profiler.start(profile_id=self._queue_item.session_id)
|
||||||
|
|
||||||
# Loop over invocations until the session is complete or canceled
|
# Prepare invocations and take the first
|
||||||
while self._invocation is not None and not cancel_event.is_set():
|
self._invocation = self._queue_item.session.next()
|
||||||
# get the source node id to provide to clients (the prepared node id is not as useful)
|
|
||||||
source_invocation_id = self._queue_item.session.prepared_source_mapping[self._invocation.id]
|
|
||||||
|
|
||||||
# Send starting event
|
# Loop over invocations until the session is complete or canceled
|
||||||
self._invoker.services.events.emit_invocation_started(
|
while self._invocation is not None and not cancel_event.is_set():
|
||||||
queue_batch_id=self._queue_item.batch_id,
|
# get the source node id to provide to clients (the prepared node id is not as useful)
|
||||||
queue_item_id=self._queue_item.item_id,
|
source_invocation_id = self._queue_item.session.prepared_source_mapping[
|
||||||
queue_id=self._queue_item.queue_id,
|
self._invocation.id
|
||||||
graph_execution_state_id=self._queue_item.session_id,
|
]
|
||||||
node=self._invocation.model_dump(),
|
|
||||||
source_node_id=source_invocation_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Innermost processor try block; any unhandled exception is an invocation error & will fail the graph
|
# Send starting event
|
||||||
try:
|
self._invoker.services.events.emit_invocation_started(
|
||||||
with self._invoker.services.performance_statistics.collect_stats(
|
queue_batch_id=self._queue_item.batch_id,
|
||||||
self._invocation, self._queue_item.session.id
|
queue_item_id=self._queue_item.item_id,
|
||||||
):
|
queue_id=self._queue_item.queue_id,
|
||||||
# Build invocation context (the node-facing API)
|
graph_execution_state_id=self._queue_item.session_id,
|
||||||
data = InvocationContextData(
|
node=self._invocation.model_dump(),
|
||||||
invocation=self._invocation,
|
source_node_id=source_invocation_id,
|
||||||
source_invocation_id=source_invocation_id,
|
)
|
||||||
queue_item=self._queue_item,
|
|
||||||
)
|
# Innermost processor try block; any unhandled exception is an invocation error & will fail the graph
|
||||||
context = build_invocation_context(
|
try:
|
||||||
data=data,
|
with self._invoker.services.performance_statistics.collect_stats(
|
||||||
services=self._invoker.services,
|
self._invocation, self._queue_item.session.id
|
||||||
cancel_event=self._cancel_event,
|
):
|
||||||
|
# Build invocation context (the node-facing API)
|
||||||
|
data = InvocationContextData(
|
||||||
|
invocation=self._invocation,
|
||||||
|
source_invocation_id=source_invocation_id,
|
||||||
|
queue_item=self._queue_item,
|
||||||
|
)
|
||||||
|
context = build_invocation_context(
|
||||||
|
data=data,
|
||||||
|
services=self._invoker.services,
|
||||||
|
cancel_event=self._cancel_event,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Invoke the node
|
||||||
|
outputs = self._invocation.invoke_internal(
|
||||||
|
context=context, services=self._invoker.services
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save outputs and history
|
||||||
|
self._queue_item.session.complete(self._invocation.id, outputs)
|
||||||
|
|
||||||
|
# Send complete event
|
||||||
|
self._invoker.services.events.emit_invocation_complete(
|
||||||
|
queue_batch_id=self._queue_item.batch_id,
|
||||||
|
queue_item_id=self._queue_item.item_id,
|
||||||
|
queue_id=self._queue_item.queue_id,
|
||||||
|
graph_execution_state_id=self._queue_item.session.id,
|
||||||
|
node=self._invocation.model_dump(),
|
||||||
|
source_node_id=source_invocation_id,
|
||||||
|
result=outputs.model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
# TODO(MM2): Create an event for this
|
||||||
|
pass
|
||||||
|
|
||||||
|
except CanceledException:
|
||||||
|
# When the user cancels the graph, we first set the cancel event. The event is checked
|
||||||
|
# between invocations, in this loop. Some invocations are long-running, and we need to
|
||||||
|
# be able to cancel them mid-execution.
|
||||||
|
#
|
||||||
|
# For example, denoising is a long-running invocation with many steps. A step callback
|
||||||
|
# is executed after each step. This step callback checks if the canceled event is set,
|
||||||
|
# then raises a CanceledException to stop execution immediately.
|
||||||
|
#
|
||||||
|
# When we get a CanceledException, we don't need to do anything - just pass and let the
|
||||||
|
# loop go to its next iteration, and the cancel event will be handled correctly.
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error = traceback.format_exc()
|
||||||
|
|
||||||
|
# Save error
|
||||||
|
self._queue_item.session.set_node_error(self._invocation.id, error)
|
||||||
|
self._invoker.services.logger.error(
|
||||||
|
f"Error while invoking session {self._queue_item.session_id}, invocation {self._invocation.id} ({self._invocation.get_type()}):\n{e}"
|
||||||
)
|
)
|
||||||
|
self._invoker.services.logger.error(error)
|
||||||
|
|
||||||
# Invoke the node
|
# Send error event
|
||||||
outputs = self._invocation.invoke_internal(
|
self._invoker.services.events.emit_invocation_error(
|
||||||
context=context, services=self._invoker.services
|
queue_batch_id=self._queue_item.session_id,
|
||||||
)
|
|
||||||
|
|
||||||
# Save outputs and history
|
|
||||||
self._queue_item.session.complete(self._invocation.id, outputs)
|
|
||||||
|
|
||||||
# Send complete event
|
|
||||||
self._invoker.services.events.emit_invocation_complete(
|
|
||||||
queue_batch_id=self._queue_item.batch_id,
|
|
||||||
queue_item_id=self._queue_item.item_id,
|
queue_item_id=self._queue_item.item_id,
|
||||||
queue_id=self._queue_item.queue_id,
|
queue_id=self._queue_item.queue_id,
|
||||||
graph_execution_state_id=self._queue_item.session.id,
|
graph_execution_state_id=self._queue_item.session.id,
|
||||||
node=self._invocation.model_dump(),
|
node=self._invocation.model_dump(),
|
||||||
source_node_id=source_invocation_id,
|
source_node_id=source_invocation_id,
|
||||||
result=outputs.model_dump(),
|
error_type=e.__class__.__name__,
|
||||||
|
error=error,
|
||||||
)
|
)
|
||||||
|
pass
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
# The session is complete if the all invocations are complete or there was an error
|
||||||
# TODO(MM2): Create an event for this
|
if self._queue_item.session.is_complete() or cancel_event.is_set():
|
||||||
pass
|
# Send complete event
|
||||||
|
self._invoker.services.events.emit_graph_execution_complete(
|
||||||
except CanceledException:
|
queue_batch_id=self._queue_item.batch_id,
|
||||||
# When the user cancels the graph, we first set the cancel event. The event is checked
|
queue_item_id=self._queue_item.item_id,
|
||||||
# between invocations, in this loop. Some invocations are long-running, and we need to
|
queue_id=self._queue_item.queue_id,
|
||||||
# be able to cancel them mid-execution.
|
graph_execution_state_id=self._queue_item.session.id,
|
||||||
#
|
|
||||||
# For example, denoising is a long-running invocation with many steps. A step callback
|
|
||||||
# is executed after each step. This step callback checks if the canceled event is set,
|
|
||||||
# then raises a CanceledException to stop execution immediately.
|
|
||||||
#
|
|
||||||
# When we get a CanceledException, we don't need to do anything - just pass and let the
|
|
||||||
# loop go to its next iteration, and the cancel event will be handled correctly.
|
|
||||||
pass
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
error = traceback.format_exc()
|
|
||||||
|
|
||||||
# Save error
|
|
||||||
self._queue_item.session.set_node_error(self._invocation.id, error)
|
|
||||||
self._invoker.services.logger.error(
|
|
||||||
f"Error while invoking session {self._queue_item.session_id}, invocation {self._invocation.id} ({self._invocation.get_type()}):\n{e}"
|
|
||||||
)
|
|
||||||
self._invoker.services.logger.error(error)
|
|
||||||
|
|
||||||
# Send error event
|
|
||||||
self._invoker.services.events.emit_invocation_error(
|
|
||||||
queue_batch_id=self._queue_item.session_id,
|
|
||||||
queue_item_id=self._queue_item.item_id,
|
|
||||||
queue_id=self._queue_item.queue_id,
|
|
||||||
graph_execution_state_id=self._queue_item.session.id,
|
|
||||||
node=self._invocation.model_dump(),
|
|
||||||
source_node_id=source_invocation_id,
|
|
||||||
error_type=e.__class__.__name__,
|
|
||||||
error=error,
|
|
||||||
)
|
|
||||||
pass
|
|
||||||
|
|
||||||
# The session is complete if the all invocations are complete or there was an error
|
|
||||||
if self._queue_item.session.is_complete() or cancel_event.is_set():
|
|
||||||
# Send complete event
|
|
||||||
self._invoker.services.events.emit_graph_execution_complete(
|
|
||||||
queue_batch_id=self._queue_item.batch_id,
|
|
||||||
queue_item_id=self._queue_item.item_id,
|
|
||||||
queue_id=self._queue_item.queue_id,
|
|
||||||
graph_execution_state_id=self._queue_item.session.id,
|
|
||||||
)
|
|
||||||
# If we are profiling, stop the profiler and dump the profile & stats
|
|
||||||
if self._profiler:
|
|
||||||
profile_path = self._profiler.stop()
|
|
||||||
stats_path = profile_path.with_suffix(".json")
|
|
||||||
self._invoker.services.performance_statistics.dump_stats(
|
|
||||||
graph_execution_state_id=self._queue_item.session.id, output_path=stats_path
|
|
||||||
)
|
)
|
||||||
# We'll get a GESStatsNotFoundError if we try to log stats for an untracked graph, but in the processor
|
# If we are profiling, stop the profiler and dump the profile & stats
|
||||||
# we don't care about that - suppress the error.
|
if self._profiler:
|
||||||
with suppress(GESStatsNotFoundError):
|
profile_path = self._profiler.stop()
|
||||||
self._invoker.services.performance_statistics.log_stats(self._queue_item.session.id)
|
stats_path = profile_path.with_suffix(".json")
|
||||||
self._invoker.services.performance_statistics.reset_stats()
|
self._invoker.services.performance_statistics.dump_stats(
|
||||||
|
graph_execution_state_id=self._queue_item.session.id, output_path=stats_path
|
||||||
|
)
|
||||||
|
# We'll get a GESStatsNotFoundError if we try to log stats for an untracked graph, but in the processor
|
||||||
|
# we don't care about that - suppress the error.
|
||||||
|
with suppress(GESStatsNotFoundError):
|
||||||
|
self._invoker.services.performance_statistics.log_stats(
|
||||||
|
self._queue_item.session.id
|
||||||
|
)
|
||||||
|
self._invoker.services.performance_statistics.reset_stats()
|
||||||
|
|
||||||
# Set the invocation to None to prepare for the next session
|
# Set the invocation to None to prepare for the next session
|
||||||
self._invocation = None
|
self._invocation = None
|
||||||
else:
|
else:
|
||||||
# Prepare the next invocation
|
# Prepare the next invocation
|
||||||
self._invocation = self._queue_item.session.next()
|
self._invocation = self._queue_item.session.next()
|
||||||
|
|
||||||
# The session is complete, immediately poll for next session
|
# The session is complete, immediately poll for next session
|
||||||
self._queue_item = None
|
self._queue_item = None
|
||||||
poll_now_event.set()
|
poll_now_event.set()
|
||||||
else:
|
else:
|
||||||
# The queue was empty, wait for next polling interval or event to try again
|
# The queue was empty, wait for next polling interval or event to try again
|
||||||
self._invoker.services.logger.debug("Waiting for next polling interval or event")
|
self._invoker.services.logger.debug("Waiting for next polling interval or event")
|
||||||
poll_now_event.wait(self._polling_interval)
|
poll_now_event.wait(self._polling_interval)
|
||||||
continue
|
continue
|
||||||
except Exception:
|
except Exception:
|
||||||
# Non-fatal error in processor
|
# Non-fatal error in processor
|
||||||
self._invoker.services.logger.error(
|
self._invoker.services.logger.error(
|
||||||
|
@ -1043,23 +1043,32 @@ class GraphExecutionState(BaseModel):
|
|||||||
"""Gets the deepest node that is ready to be executed"""
|
"""Gets the deepest node that is ready to be executed"""
|
||||||
g = self.execution_graph.nx_graph()
|
g = self.execution_graph.nx_graph()
|
||||||
|
|
||||||
# Depth-first search with pre-order traversal is a depth-first topological sort
|
# Perform a topological sort using depth-first search
|
||||||
sorted_nodes = nx.dfs_preorder_nodes(g)
|
topo_order = list(nx.dfs_postorder_nodes(g))
|
||||||
|
|
||||||
next_node = next(
|
# Get all IterateInvocation nodes
|
||||||
(
|
iterate_nodes = [n for n in topo_order if isinstance(self.execution_graph.nodes[n], IterateInvocation)]
|
||||||
n
|
|
||||||
for n in sorted_nodes
|
|
||||||
if n not in self.executed # the node must not already be executed...
|
|
||||||
and all((e[0] in self.executed for e in g.in_edges(n))) # ...and all its inputs must be executed
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
|
|
||||||
if next_node is None:
|
# Sort the IterateInvocation nodes based on their index attribute
|
||||||
return None
|
iterate_nodes.sort(key=lambda x: self.execution_graph.nodes[x].index)
|
||||||
|
|
||||||
return self.execution_graph.nodes[next_node]
|
# Prioritize IterateInvocation nodes and their children
|
||||||
|
for iterate_node in iterate_nodes:
|
||||||
|
if iterate_node not in self.executed and all((e[0] in self.executed for e in g.in_edges(iterate_node))):
|
||||||
|
return self.execution_graph.nodes[iterate_node]
|
||||||
|
|
||||||
|
# Check the children of the IterateInvocation node
|
||||||
|
for child_node in nx.dfs_postorder_nodes(g, iterate_node):
|
||||||
|
if child_node not in self.executed and all((e[0] in self.executed for e in g.in_edges(child_node))):
|
||||||
|
return self.execution_graph.nodes[child_node]
|
||||||
|
|
||||||
|
# If no IterateInvocation node or its children are ready, return the first ready node in the topological order
|
||||||
|
for node in topo_order:
|
||||||
|
if node not in self.executed and all((e[0] in self.executed for e in g.in_edges(node))):
|
||||||
|
return self.execution_graph.nodes[node]
|
||||||
|
|
||||||
|
# If no node is found, return None
|
||||||
|
return None
|
||||||
|
|
||||||
def _prepare_inputs(self, node: BaseInvocation):
|
def _prepare_inputs(self, node: BaseInvocation):
|
||||||
input_edges = [e for e in self.execution_graph.edges if e.destination.node_id == node.id]
|
input_edges = [e for e in self.execution_graph.edges if e.destination.node_id == node.id]
|
||||||
|
@ -10,6 +10,7 @@ from invokeai.app.services.shared.sqlite_migrator.migrations.migration_4 import
|
|||||||
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_5 import build_migration_5
|
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_5 import build_migration_5
|
||||||
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_6 import build_migration_6
|
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_6 import build_migration_6
|
||||||
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_7 import build_migration_7
|
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_7 import build_migration_7
|
||||||
|
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_8 import build_migration_8
|
||||||
from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_impl import SqliteMigrator
|
from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_impl import SqliteMigrator
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ def init_db(config: InvokeAIAppConfig, logger: Logger, image_files: ImageFileSto
|
|||||||
migrator.register_migration(build_migration_5())
|
migrator.register_migration(build_migration_5())
|
||||||
migrator.register_migration(build_migration_6())
|
migrator.register_migration(build_migration_6())
|
||||||
migrator.register_migration(build_migration_7())
|
migrator.register_migration(build_migration_7())
|
||||||
|
migrator.register_migration(build_migration_8(app_config=config))
|
||||||
migrator.run_migrations()
|
migrator.run_migrations()
|
||||||
|
|
||||||
return db
|
return db
|
||||||
|
@ -11,7 +11,7 @@ class Migration7Callback:
|
|||||||
def _drop_old_models_tables(self, cursor: sqlite3.Cursor) -> None:
|
def _drop_old_models_tables(self, cursor: sqlite3.Cursor) -> None:
|
||||||
"""Drops the old model_records, model_metadata, model_tags and tags tables."""
|
"""Drops the old model_records, model_metadata, model_tags and tags tables."""
|
||||||
|
|
||||||
tables = ["model_records", "model_metadata", "model_tags", "tags"]
|
tables = ["model_config", "model_metadata", "model_tags", "tags"]
|
||||||
|
|
||||||
for table in tables:
|
for table in tables:
|
||||||
cursor.execute(f"DROP TABLE IF EXISTS {table};")
|
cursor.execute(f"DROP TABLE IF EXISTS {table};")
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
import sqlite3
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from invokeai.app.services.config.config_default import InvokeAIAppConfig
|
||||||
|
from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_common import Migration
|
||||||
|
|
||||||
|
|
||||||
|
class Migration8Callback:
|
||||||
|
def __init__(self, app_config: InvokeAIAppConfig) -> None:
|
||||||
|
self._app_config = app_config
|
||||||
|
|
||||||
|
def __call__(self, cursor: sqlite3.Cursor) -> None:
|
||||||
|
self._drop_model_config_table(cursor)
|
||||||
|
self._migrate_abs_models_to_rel(cursor)
|
||||||
|
|
||||||
|
def _drop_model_config_table(self, cursor: sqlite3.Cursor) -> None:
|
||||||
|
"""Drops the old model_config table. This was missed in a previous migration."""
|
||||||
|
|
||||||
|
cursor.execute("DROP TABLE IF EXISTS model_config;")
|
||||||
|
|
||||||
|
def _migrate_abs_models_to_rel(self, cursor: sqlite3.Cursor) -> None:
|
||||||
|
"""Check all model paths & legacy config paths to determine if they are inside Invoke-managed directories. If
|
||||||
|
they are, update the paths to be relative to the managed directories.
|
||||||
|
|
||||||
|
This migration is a no-op for normal users (their paths will already be relative), but is necessary for users
|
||||||
|
who have been testing the RCs with their live databases. The paths were made absolute in the initial RC, but this
|
||||||
|
change was reverted. To smooth over the revert for our tests, we can migrate the paths back to relative.
|
||||||
|
"""
|
||||||
|
|
||||||
|
models_path = self._app_config.models_path
|
||||||
|
legacy_conf_path = self._app_config.legacy_conf_path
|
||||||
|
legacy_conf_dir = self._app_config.legacy_conf_dir
|
||||||
|
|
||||||
|
stmt = """---sql
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
path,
|
||||||
|
json_extract(config, '$.config_path') as config_path
|
||||||
|
FROM models;
|
||||||
|
"""
|
||||||
|
|
||||||
|
all_models = cursor.execute(stmt).fetchall()
|
||||||
|
|
||||||
|
for model_id, model_path, model_config_path in all_models:
|
||||||
|
# If the model path is inside the models directory, update it to be relative to the models directory.
|
||||||
|
if Path(model_path).is_relative_to(models_path):
|
||||||
|
new_path = Path(model_path).relative_to(models_path)
|
||||||
|
cursor.execute(
|
||||||
|
"""--sql
|
||||||
|
UPDATE models
|
||||||
|
SET config = json_set(config, '$.path', ?)
|
||||||
|
WHERE id = ?;
|
||||||
|
""",
|
||||||
|
(str(new_path), model_id),
|
||||||
|
)
|
||||||
|
# If the model has a legacy config path and it is inside the legacy conf directory, update it to be
|
||||||
|
# relative to the legacy conf directory. This also fixes up cases in which the config path was
|
||||||
|
# incorrectly relativized to the root directory. It will now be relativized to the legacy conf directory.
|
||||||
|
if model_config_path:
|
||||||
|
if Path(model_config_path).is_relative_to(legacy_conf_path):
|
||||||
|
new_config_path = Path(model_config_path).relative_to(legacy_conf_path)
|
||||||
|
elif Path(model_config_path).is_relative_to(legacy_conf_dir):
|
||||||
|
new_config_path = Path(*Path(model_config_path).parts[1:])
|
||||||
|
else:
|
||||||
|
new_config_path = None
|
||||||
|
if new_config_path:
|
||||||
|
cursor.execute(
|
||||||
|
"""--sql
|
||||||
|
UPDATE models
|
||||||
|
SET config = json_set(config, '$.config_path', ?)
|
||||||
|
WHERE id = ?;
|
||||||
|
""",
|
||||||
|
(str(new_config_path), model_id),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_migration_8(app_config: InvokeAIAppConfig) -> Migration:
|
||||||
|
"""
|
||||||
|
Build the migration from database version 7 to 8.
|
||||||
|
|
||||||
|
This migration does the following:
|
||||||
|
- Removes the `model_config` table.
|
||||||
|
- Migrates absolute model & legacy config paths to be relative to the models directory.
|
||||||
|
"""
|
||||||
|
migration_8 = Migration(
|
||||||
|
from_version=7,
|
||||||
|
to_version=8,
|
||||||
|
callback=Migration8Callback(app_config),
|
||||||
|
)
|
||||||
|
|
||||||
|
return migration_8
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
|||||||
"name": "Prompt from File",
|
"name": "Prompt from File",
|
||||||
"author": "InvokeAI",
|
"author": "InvokeAI",
|
||||||
"description": "Sample workflow using Prompt from File node",
|
"description": "Sample workflow using Prompt from File node",
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"contact": "invoke@invoke.ai",
|
"contact": "invoke@invoke.ai",
|
||||||
"tags": "text2image, prompt from file, default",
|
"tags": "text2image, prompt from file, default",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
@ -14,11 +14,31 @@
|
|||||||
{
|
{
|
||||||
"nodeId": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
"nodeId": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
||||||
"fieldName": "file_path"
|
"fieldName": "file_path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
||||||
|
"fieldName": "pre_prompt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
||||||
|
"fieldName": "post_prompt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
||||||
|
"fieldName": "width"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
||||||
|
"fieldName": "height"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1",
|
||||||
|
"fieldName": "board"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"category": "default",
|
"category": "default",
|
||||||
"version": "2.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
@ -26,847 +46,361 @@
|
|||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "c2eaf1ba-5708-4679-9e15-945b8b432692",
|
"id": "c2eaf1ba-5708-4679-9e15-945b8b432692",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "compel",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "dcdf3f6d-9b96-4bcd-9b8d-f992fefe4f62",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "3f1981c9-d8a9-42eb-a739-4f120eb80745",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "46205e6c-c5e2-44cb-9c82-1cd20b95674a",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 925,
|
"x": 925,
|
||||||
"y": -200
|
"y": -200
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
"id": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
"id": "1b7e0df8-8589-4915-a4ea-c0088f15d642",
|
||||||
"type": "prompt_from_file",
|
"version": "1.0.2",
|
||||||
"label": "Prompts from File",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.1",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "Prompts from File",
|
||||||
|
"notes": "",
|
||||||
|
"type": "prompt_from_file",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"file_path": {
|
"file_path": {
|
||||||
"id": "37e37684-4f30-4ec8-beae-b333e550f904",
|
|
||||||
"name": "file_path",
|
"name": "file_path",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "Prompts File Path",
|
"label": "Prompts File Path",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"pre_prompt": {
|
"pre_prompt": {
|
||||||
"id": "7de02feb-819a-4992-bad3-72a30920ddea",
|
|
||||||
"name": "pre_prompt",
|
"name": "pre_prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"post_prompt": {
|
"post_prompt": {
|
||||||
"id": "95f191d8-a282-428e-bd65-de8cb9b7513a",
|
|
||||||
"name": "post_prompt",
|
"name": "post_prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"start_line": {
|
"start_line": {
|
||||||
"id": "efee9a48-05ab-4829-8429-becfa64a0782",
|
|
||||||
"name": "start_line",
|
"name": "start_line",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
"max_prompts": {
|
"max_prompts": {
|
||||||
"id": "abebb428-3d3d-49fd-a482-4e96a16fff08",
|
|
||||||
"name": "max_prompts",
|
"name": "max_prompts",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 1
|
"value": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"collection": {
|
"isIntermediate": true,
|
||||||
"id": "77d5d7f1-9877-4ab1-9a8c-33e9ffa9abf3",
|
"useCache": true
|
||||||
"name": "collection",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": true,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 475,
|
"x": 475,
|
||||||
"y": -400
|
"y": -400
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 506
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
"id": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
"id": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
||||||
"type": "iterate",
|
|
||||||
"label": "",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "iterate",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"collection": {
|
"collection": {
|
||||||
"id": "4c564bf8-5ed6-441e-ad2c-dda265d5785f",
|
|
||||||
"name": "collection",
|
"name": "collection",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": true,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "CollectionField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"item": {
|
"isIntermediate": true,
|
||||||
"id": "36340f9a-e7a5-4afa-b4b5-313f4e292380",
|
"useCache": true
|
||||||
"name": "item",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "CollectionItemField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"index": {
|
|
||||||
"id": "1beca95a-2159-460f-97ff-c8bab7d89336",
|
|
||||||
"name": "index",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"id": "ead597b8-108e-4eda-88a8-5c29fa2f8df9",
|
|
||||||
"name": "total",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 925,
|
"x": 925,
|
||||||
"y": -400
|
"y": -400
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "d6353b7f-b447-4e17-8f2e-80a88c91d426",
|
"id": "d6353b7f-b447-4e17-8f2e-80a88c91d426",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "d6353b7f-b447-4e17-8f2e-80a88c91d426",
|
"id": "d6353b7f-b447-4e17-8f2e-80a88c91d426",
|
||||||
"type": "main_model_loader",
|
"version": "1.0.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "main_model_loader",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"model": {
|
"model": {
|
||||||
"id": "3f264259-3418-47d5-b90d-b6600e36ae46",
|
|
||||||
"name": "model",
|
"name": "model",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MainModelField"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"model_name": "stable-diffusion-v1-5",
|
|
||||||
"base_model": "sd-1",
|
|
||||||
"model_type": "main"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"unet": {
|
"isIntermediate": true,
|
||||||
"id": "8e182ea2-9d0a-4c02-9407-27819288d4b5",
|
"useCache": true
|
||||||
"name": "unet",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"clip": {
|
|
||||||
"id": "d67d9d30-058c-46d5-bded-3d09d6d1aa39",
|
|
||||||
"name": "clip",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vae": {
|
|
||||||
"id": "89641601-0429-4448-98d5-190822d920d8",
|
|
||||||
"name": "vae",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -375
|
"y": -375
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 193
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6",
|
"id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6",
|
"id": "fc9d0e35-a6de-4a19-84e1-c72497c823f6",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "compel",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "dcdf3f6d-9b96-4bcd-9b8d-f992fefe4f62",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "3f1981c9-d8a9-42eb-a739-4f120eb80745",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "46205e6c-c5e2-44cb-9c82-1cd20b95674a",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 925,
|
"x": 925,
|
||||||
"y": -275
|
"y": -275
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
"id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
"id": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77",
|
||||||
"type": "noise",
|
"version": "1.0.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.1",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "noise",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"seed": {
|
"seed": {
|
||||||
"id": "b722d84a-eeee-484f-bef2-0250c027cb67",
|
|
||||||
"name": "seed",
|
"name": "seed",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"id": "d5f8ce11-0502-4bfc-9a30-5757dddf1f94",
|
|
||||||
"name": "width",
|
"name": "width",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
"value": 512
|
||||||
},
|
},
|
||||||
"height": {
|
"height": {
|
||||||
"id": "f187d5ff-38a5-4c3f-b780-fc5801ef34af",
|
|
||||||
"name": "height",
|
"name": "height",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
"value": 512
|
||||||
},
|
},
|
||||||
"use_cpu": {
|
"use_cpu": {
|
||||||
"id": "12f112b8-8b76-4816-b79e-662edc9f9aa5",
|
|
||||||
"name": "use_cpu",
|
"name": "use_cpu",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"noise": {
|
"isIntermediate": true,
|
||||||
"id": "08576ad1-96d9-42d2-96ef-6f5c1961933f",
|
"useCache": true
|
||||||
"name": "noise",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "f3e1f94a-258d-41ff-9789-bd999bd9f40d",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "6cefc357-4339-415e-a951-49b9c2be32f4",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 925,
|
"x": 925,
|
||||||
"y": 25
|
"y": 25
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5",
|
"id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5",
|
"id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5",
|
||||||
"type": "rand_int",
|
"version": "1.0.1",
|
||||||
"label": "",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": false,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "rand_int",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"low": {
|
"low": {
|
||||||
"id": "b9fc6cf1-469c-4037-9bf0-04836965826f",
|
|
||||||
"name": "low",
|
"name": "low",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"high": {
|
"high": {
|
||||||
"id": "06eac725-0f60-4ba2-b8cd-7ad9f757488c",
|
|
||||||
"name": "high",
|
"name": "high",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 2147483647
|
"value": 2147483647
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"value": {
|
"isIntermediate": true,
|
||||||
"id": "df08c84e-7346-4e92-9042-9e5cb773aaff",
|
"useCache": false
|
||||||
"name": "value",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 925,
|
"x": 925,
|
||||||
"y": -50
|
"y": -50
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1",
|
"id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1",
|
"id": "491ec988-3c77-4c37-af8a-39a0c4e7a2a1",
|
||||||
"type": "l2i",
|
"version": "1.2.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.2.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "l2i",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"board": {
|
||||||
|
"name": "board",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"id": "022e4b33-562b-438d-b7df-41c3fd931f40",
|
|
||||||
"name": "metadata",
|
"name": "metadata",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MetadataField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "67cb6c77-a394-4a66-a6a9-a0a7dcca69ec",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"vae": {
|
"vae": {
|
||||||
"id": "7b3fd9ad-a4ef-4e04-89fa-3832a9902dbd",
|
|
||||||
"name": "vae",
|
"name": "vae",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tiled": {
|
"tiled": {
|
||||||
"id": "5ac5680d-3add-4115-8ec0-9ef5bb87493b",
|
|
||||||
"name": "tiled",
|
"name": "tiled",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"fp32": {
|
"fp32": {
|
||||||
"id": "db8297f5-55f8-452f-98cf-6572c2582152",
|
|
||||||
"name": "fp32",
|
"name": "fp32",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": false
|
"value": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"image": {
|
"isIntermediate": true,
|
||||||
"id": "d8778d0c-592a-4960-9280-4e77e00a7f33",
|
"useCache": true
|
||||||
"name": "image",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ImageField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "c8b0a75a-f5de-4ff2-9227-f25bb2b97bec",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "83c05fbf-76b9-49ab-93c4-fa4b10e793e4",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 2037.861329274915,
|
"x": 2037.861329274915,
|
||||||
"y": -329.8393457509562
|
"y": -329.8393457509562
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 224
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e",
|
"id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e",
|
"id": "2fb1577f-0a56-4f12-8711-8afcaaaf1d5e",
|
||||||
"type": "denoise_latents",
|
"version": "1.5.3",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.5.1",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "denoise_latents",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"positive_conditioning": {
|
"positive_conditioning": {
|
||||||
"id": "751fb35b-3f23-45ce-af1c-053e74251337",
|
|
||||||
"name": "positive_conditioning",
|
"name": "positive_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"negative_conditioning": {
|
"negative_conditioning": {
|
||||||
"id": "b9dc06b6-7481-4db1-a8c2-39d22a5eacff",
|
|
||||||
"name": "negative_conditioning",
|
"name": "negative_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"noise": {
|
"noise": {
|
||||||
"id": "6e15e439-3390-48a4-8031-01e0e19f0e1d",
|
|
||||||
"name": "noise",
|
"name": "noise",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"steps": {
|
"steps": {
|
||||||
"id": "bfdfb3df-760b-4d51-b17b-0abb38b976c2",
|
|
||||||
"name": "steps",
|
"name": "steps",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": 30
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 10
|
|
||||||
},
|
},
|
||||||
"cfg_scale": {
|
"cfg_scale": {
|
||||||
"id": "47770858-322e-41af-8494-d8b63ed735f3",
|
|
||||||
"name": "cfg_scale",
|
"name": "cfg_scale",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 7.5
|
"value": 7.5
|
||||||
},
|
},
|
||||||
"denoising_start": {
|
"denoising_start": {
|
||||||
"id": "2ba78720-ee02-4130-a348-7bc3531f790b",
|
|
||||||
"name": "denoising_start",
|
"name": "denoising_start",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"denoising_end": {
|
"denoising_end": {
|
||||||
"id": "a874dffb-d433-4d1a-9f59-af4367bb05e4",
|
|
||||||
"name": "denoising_end",
|
"name": "denoising_end",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"id": "36e021ad-b762-4fe4-ad4d-17f0291c40b2",
|
|
||||||
"name": "scheduler",
|
"name": "scheduler",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "SchedulerField"
|
|
||||||
},
|
|
||||||
"value": "euler"
|
"value": "euler"
|
||||||
},
|
},
|
||||||
"unet": {
|
"unet": {
|
||||||
"id": "98d3282d-f9f6-4b5e-b9e8-58658f1cac78",
|
|
||||||
"name": "unet",
|
"name": "unet",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"control": {
|
"control": {
|
||||||
"id": "f2ea3216-43d5-42b4-887f-36e8f7166d53",
|
|
||||||
"name": "control",
|
"name": "control",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "ControlField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"ip_adapter": {
|
"ip_adapter": {
|
||||||
"id": "d0780610-a298-47c8-a54e-70e769e0dfe2",
|
|
||||||
"name": "ip_adapter",
|
"name": "ip_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "IPAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"t2i_adapter": {
|
"t2i_adapter": {
|
||||||
"id": "fdb40970-185e-4ea8-8bb5-88f06f91f46a",
|
|
||||||
"name": "t2i_adapter",
|
"name": "t2i_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "T2IAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"cfg_rescale_multiplier": {
|
"cfg_rescale_multiplier": {
|
||||||
"id": "3af2d8c5-de83-425c-a100-49cb0f1f4385",
|
|
||||||
"name": "cfg_rescale_multiplier",
|
"name": "cfg_rescale_multiplier",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "e05b538a-1b5a-4aa5-84b1-fd2361289a81",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"denoise_mask": {
|
"denoise_mask": {
|
||||||
"id": "463a419e-df30-4382-8ffb-b25b25abe425",
|
|
||||||
"name": "denoise_mask",
|
"name": "denoise_mask",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "DenoiseMaskField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"latents": {
|
"isIntermediate": true,
|
||||||
"id": "559ee688-66cf-4139-8b82-3d3aa69995ce",
|
"useCache": true
|
||||||
"name": "latents",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "0b4285c2-e8b9-48e5-98f6-0a49d3f98fd2",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "8b0881b9-45e5-47d5-b526-24b6661de0ee",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1570.9941088179146,
|
"x": 1570.9941088179146,
|
||||||
"y": -407.6505491604564
|
"y": -407.6505491604564
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 612
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"edges": [
|
"edges": [
|
||||||
@ -876,12 +410,6 @@
|
|||||||
"source": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
"source": "1b89067c-3f6b-42c8-991f-e3055789b251",
|
||||||
"target": "fc9d0e35-a6de-4a19-84e1-c72497c823f6"
|
"target": "fc9d0e35-a6de-4a19-84e1-c72497c823f6"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5-0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77-collapsed",
|
|
||||||
"type": "collapsed",
|
|
||||||
"source": "dfc20e07-7aef-4fc0-a3a1-7bf68ec6a4e5",
|
|
||||||
"target": "0eb5f3f5-1b91-49eb-9ef0-41d67c7eae77"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "reactflow__edge-1b7e0df8-8589-4915-a4ea-c0088f15d642collection-1b89067c-3f6b-42c8-991f-e3055789b251collection",
|
"id": "reactflow__edge-1b7e0df8-8589-4915-a4ea-c0088f15d642collection-1b89067c-3f6b-42c8-991f-e3055789b251collection",
|
||||||
"type": "default",
|
"type": "default",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
|||||||
"name": "Text to Image - SD1.5",
|
"name": "Text to Image - SD1.5",
|
||||||
"author": "InvokeAI",
|
"author": "InvokeAI",
|
||||||
"description": "Sample text to image workflow for Stable Diffusion 1.5/2",
|
"description": "Sample text to image workflow for Stable Diffusion 1.5/2",
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"contact": "invoke@invoke.ai",
|
"contact": "invoke@invoke.ai",
|
||||||
"tags": "text2image, SD1.5, SD2, default",
|
"tags": "text2image, SD1.5, SD2, default",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
@ -26,11 +26,15 @@
|
|||||||
{
|
{
|
||||||
"nodeId": "55705012-79b9-4aac-9f26-c0b10309785b",
|
"nodeId": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
"fieldName": "height"
|
"fieldName": "height"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
|
||||||
|
"fieldName": "board"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"category": "default",
|
"category": "default",
|
||||||
"version": "2.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
@ -38,687 +42,291 @@
|
|||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
|
"id": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "Negative Compel Prompt",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "Negative Compel Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "compel",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "7739aff6-26cb-4016-8897-5a1fb2305e4e",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "Negative Prompt",
|
"label": "Negative Prompt",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "48d23dce-a6ae-472a-9f8c-22a714ea5ce0",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "37cf3a9d-f6b7-4b64-8ff6-2558c5ecc447",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1000,
|
"x": 1000,
|
||||||
"y": 350
|
"y": 350
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 219
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
"type": "noise",
|
"version": "1.0.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.1",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "noise",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"seed": {
|
"seed": {
|
||||||
"id": "6431737c-918a-425d-a3b4-5d57e2f35d4d",
|
|
||||||
"name": "seed",
|
"name": "seed",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"id": "38fc5b66-fe6e-47c8-bba9-daf58e454ed7",
|
|
||||||
"name": "width",
|
"name": "width",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
"value": 512
|
||||||
},
|
},
|
||||||
"height": {
|
"height": {
|
||||||
"id": "16298330-e2bf-4872-a514-d6923df53cbb",
|
|
||||||
"name": "height",
|
"name": "height",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": 768
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
|
||||||
},
|
},
|
||||||
"use_cpu": {
|
"use_cpu": {
|
||||||
"id": "c7c436d3-7a7a-4e76-91e4-c6deb271623c",
|
|
||||||
"name": "use_cpu",
|
"name": "use_cpu",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"noise": {
|
"isIntermediate": true,
|
||||||
"id": "50f650dc-0184-4e23-a927-0497a96fe954",
|
"useCache": true
|
||||||
"name": "noise",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "bb8a452b-133d-42d1-ae4a-3843d7e4109a",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "35cfaa12-3b8b-4b7a-a884-327ff3abddd9",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 600,
|
"x": 600,
|
||||||
"y": 325
|
"y": 325
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 388
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
|
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
|
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
|
||||||
"type": "main_model_loader",
|
"version": "1.0.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "main_model_loader",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"model": {
|
"model": {
|
||||||
"id": "993eabd2-40fd-44fe-bce7-5d0c7075ddab",
|
|
||||||
"name": "model",
|
"name": "model",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MainModelField"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"model_name": "stable-diffusion-v1-5",
|
|
||||||
"base_model": "sd-1",
|
|
||||||
"model_type": "main"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"unet": {
|
"isIntermediate": true,
|
||||||
"id": "5c18c9db-328d-46d0-8cb9-143391c410be",
|
"useCache": true
|
||||||
"name": "unet",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"clip": {
|
|
||||||
"id": "6effcac0-ec2f-4bf5-a49e-a2c29cf921f4",
|
|
||||||
"name": "clip",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vae": {
|
|
||||||
"id": "57683ba3-f5f5-4f58-b9a2-4b83dacad4a1",
|
|
||||||
"name": "vae",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 600,
|
"x": 600,
|
||||||
"y": 25
|
"y": 25
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 193
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
|
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
|
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "Positive Compel Prompt",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "Positive Compel Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "compel",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "7739aff6-26cb-4016-8897-5a1fb2305e4e",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "Positive Prompt",
|
"label": "Positive Prompt",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": "Super cute tiger cub, national geographic award-winning photograph"
|
"value": "Super cute tiger cub, national geographic award-winning photograph"
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "48d23dce-a6ae-472a-9f8c-22a714ea5ce0",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "37cf3a9d-f6b7-4b64-8ff6-2558c5ecc447",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1000,
|
"x": 1000,
|
||||||
"y": 25
|
"y": 25
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 219
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
||||||
"type": "rand_int",
|
"version": "1.0.1",
|
||||||
"label": "Random Seed",
|
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": false,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "Random Seed",
|
||||||
|
"notes": "",
|
||||||
|
"type": "rand_int",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"low": {
|
"low": {
|
||||||
"id": "3ec65a37-60ba-4b6c-a0b2-553dd7a84b84",
|
|
||||||
"name": "low",
|
"name": "low",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"high": {
|
"high": {
|
||||||
"id": "085f853a-1a5f-494d-8bec-e4ba29a3f2d1",
|
|
||||||
"name": "high",
|
"name": "high",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 2147483647
|
"value": 2147483647
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"value": {
|
"isIntermediate": true,
|
||||||
"id": "812ade4d-7699-4261-b9fc-a6c9d2ab55ee",
|
"useCache": false
|
||||||
"name": "value",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 600,
|
"x": 600,
|
||||||
"y": 275
|
"y": 275
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 32
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
|
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
|
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
|
||||||
"type": "denoise_latents",
|
"version": "1.5.3",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": true,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.5.1",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "denoise_latents",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"positive_conditioning": {
|
"positive_conditioning": {
|
||||||
"id": "90b7f4f8-ada7-4028-8100-d2e54f192052",
|
|
||||||
"name": "positive_conditioning",
|
"name": "positive_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"negative_conditioning": {
|
"negative_conditioning": {
|
||||||
"id": "9393779e-796c-4f64-b740-902a1177bf53",
|
|
||||||
"name": "negative_conditioning",
|
"name": "negative_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"noise": {
|
"noise": {
|
||||||
"id": "8e17f1e5-4f98-40b1-b7f4-86aeeb4554c1",
|
|
||||||
"name": "noise",
|
"name": "noise",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"steps": {
|
"steps": {
|
||||||
"id": "9b63302d-6bd2-42c9-ac13-9b1afb51af88",
|
|
||||||
"name": "steps",
|
"name": "steps",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": 30
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 50
|
|
||||||
},
|
},
|
||||||
"cfg_scale": {
|
"cfg_scale": {
|
||||||
"id": "87dd04d3-870e-49e1-98bf-af003a810109",
|
|
||||||
"name": "cfg_scale",
|
"name": "cfg_scale",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 7.5
|
"value": 7.5
|
||||||
},
|
},
|
||||||
"denoising_start": {
|
"denoising_start": {
|
||||||
"id": "f369d80f-4931-4740-9bcd-9f0620719fab",
|
|
||||||
"name": "denoising_start",
|
"name": "denoising_start",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"denoising_end": {
|
"denoising_end": {
|
||||||
"id": "747d10e5-6f02-445c-994c-0604d814de8c",
|
|
||||||
"name": "denoising_end",
|
"name": "denoising_end",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"id": "1de84a4e-3a24-4ec8-862b-16ce49633b9b",
|
|
||||||
"name": "scheduler",
|
"name": "scheduler",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": "dpmpp_sde_k"
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "SchedulerField"
|
|
||||||
},
|
|
||||||
"value": "unipc"
|
|
||||||
},
|
},
|
||||||
"unet": {
|
"unet": {
|
||||||
"id": "ffa6fef4-3ce2-4bdb-9296-9a834849489b",
|
|
||||||
"name": "unet",
|
"name": "unet",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"control": {
|
"control": {
|
||||||
"id": "077b64cb-34be-4fcc-83f2-e399807a02bd",
|
|
||||||
"name": "control",
|
"name": "control",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "ControlField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"ip_adapter": {
|
"ip_adapter": {
|
||||||
"id": "1d6948f7-3a65-4a65-a20c-768b287251aa",
|
|
||||||
"name": "ip_adapter",
|
"name": "ip_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "IPAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"t2i_adapter": {
|
"t2i_adapter": {
|
||||||
"id": "75e67b09-952f-4083-aaf4-6b804d690412",
|
|
||||||
"name": "t2i_adapter",
|
"name": "t2i_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "T2IAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"cfg_rescale_multiplier": {
|
"cfg_rescale_multiplier": {
|
||||||
"id": "9101f0a6-5fe0-4826-b7b3-47e5d506826c",
|
|
||||||
"name": "cfg_rescale_multiplier",
|
"name": "cfg_rescale_multiplier",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "334d4ba3-5a99-4195-82c5-86fb3f4f7d43",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"denoise_mask": {
|
"denoise_mask": {
|
||||||
"id": "0d3dbdbf-b014-4e95-8b18-ff2ff9cb0bfa",
|
|
||||||
"name": "denoise_mask",
|
"name": "denoise_mask",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "DenoiseMaskField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"latents": {
|
"isIntermediate": true,
|
||||||
"id": "70fa5bbc-0c38-41bb-861a-74d6d78d2f38",
|
"useCache": true
|
||||||
"name": "latents",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "98ee0e6c-82aa-4e8f-8be5-dc5f00ee47f0",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "e8cb184a-5e1a-47c8-9695-4b8979564f5d",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1400,
|
"x": 1400,
|
||||||
"y": 25
|
"y": 25
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 612
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
|
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
|
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
|
||||||
"type": "l2i",
|
"version": "1.2.2",
|
||||||
"label": "",
|
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
|
||||||
"isIntermediate": false,
|
|
||||||
"useCache": true,
|
|
||||||
"version": "1.2.0",
|
|
||||||
"nodePack": "invokeai",
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "l2i",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"board": {
|
||||||
|
"name": "board",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"id": "ab375f12-0042-4410-9182-29e30db82c85",
|
|
||||||
"name": "metadata",
|
"name": "metadata",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MetadataField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "3a7e7efd-bff5-47d7-9d48-615127afee78",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"vae": {
|
"vae": {
|
||||||
"id": "a1f5f7a1-0795-4d58-b036-7820c0b0ef2b",
|
|
||||||
"name": "vae",
|
"name": "vae",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tiled": {
|
"tiled": {
|
||||||
"id": "da52059a-0cee-4668-942f-519aa794d739",
|
|
||||||
"name": "tiled",
|
"name": "tiled",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"fp32": {
|
"fp32": {
|
||||||
"id": "c4841df3-b24e-4140-be3b-ccd454c2522c",
|
|
||||||
"name": "fp32",
|
"name": "fp32",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"image": {
|
"isIntermediate": false,
|
||||||
"id": "72d667d0-cf85-459d-abf2-28bd8b823fe7",
|
"useCache": true
|
||||||
"name": "image",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ImageField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "c8c907d8-1066-49d1-b9a6-83bdcd53addc",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "230f359c-b4ea-436c-b372-332d7dcdca85",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1800,
|
"x": 1800,
|
||||||
"y": 25
|
"y": 25
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 224
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"edges": [
|
"edges": [
|
||||||
|
@ -0,0 +1,704 @@
|
|||||||
|
{
|
||||||
|
"name": "Text to Image - SDXL",
|
||||||
|
"author": "InvokeAI",
|
||||||
|
"description": "Sample text to image workflow for SDXL",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"contact": "invoke@invoke.ai",
|
||||||
|
"tags": "text2image, SDXL, default",
|
||||||
|
"notes": "",
|
||||||
|
"exposedFields": [
|
||||||
|
{
|
||||||
|
"nodeId": "ade2c0d3-0384-4157-b39b-29ce429cfa15",
|
||||||
|
"fieldName": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "719dabe8-8297-4749-aea1-37be301cd425",
|
||||||
|
"fieldName": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"fieldName": "model"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "0093692f-9cf4-454d-a5b8-62f0e3eb3bb8",
|
||||||
|
"fieldName": "vae_model"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "63e91020-83b2-4f35-b174-ad9692aabb48",
|
||||||
|
"fieldName": "board"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"category": "default",
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "3774ec24-a69e-4254-864c-097d07a6256f",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "3774ec24-a69e-4254-864c-097d07a6256f",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"label": "Positive Style Concat",
|
||||||
|
"notes": "",
|
||||||
|
"type": "string_join",
|
||||||
|
"inputs": {
|
||||||
|
"string_left": {
|
||||||
|
"name": "string_left",
|
||||||
|
"label": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"string_right": {
|
||||||
|
"name": "string_right",
|
||||||
|
"label": "Positive Style Concat",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": false,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": -225
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "719dabe8-8297-4749-aea1-37be301cd425",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "719dabe8-8297-4749-aea1-37be301cd425",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"label": "Negative Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "string",
|
||||||
|
"inputs": {
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"label": "Negative Prompt",
|
||||||
|
"value": "photograph"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": -125
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"version": "1.1.1",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "SDXL Negative Compel Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "sdxl_compel_prompt",
|
||||||
|
"inputs": {
|
||||||
|
"prompt": {
|
||||||
|
"name": "prompt",
|
||||||
|
"label": "Negative Prompt",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"name": "style",
|
||||||
|
"label": "Negative Style",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"original_width": {
|
||||||
|
"name": "original_width",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"original_height": {
|
||||||
|
"name": "original_height",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"crop_top": {
|
||||||
|
"name": "crop_top",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"crop_left": {
|
||||||
|
"name": "crop_left",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"target_width": {
|
||||||
|
"name": "target_width",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"target_height": {
|
||||||
|
"name": "target_height",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"clip": {
|
||||||
|
"name": "clip",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"clip2": {
|
||||||
|
"name": "clip2",
|
||||||
|
"label": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": false,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "noise",
|
||||||
|
"inputs": {
|
||||||
|
"seed": {
|
||||||
|
"name": "seed",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"name": "width",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"height": {
|
||||||
|
"name": "height",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"use_cpu": {
|
||||||
|
"name": "use_cpu",
|
||||||
|
"label": "",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 375,
|
||||||
|
"y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "Random Seed",
|
||||||
|
"notes": "",
|
||||||
|
"type": "rand_int",
|
||||||
|
"inputs": {
|
||||||
|
"low": {
|
||||||
|
"name": "low",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"high": {
|
||||||
|
"name": "high",
|
||||||
|
"label": "",
|
||||||
|
"value": 2147483647
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": false,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 375,
|
||||||
|
"y": -50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "sdxl_model_loader",
|
||||||
|
"inputs": {
|
||||||
|
"model": {
|
||||||
|
"name": "model",
|
||||||
|
"label": "",
|
||||||
|
"value": {
|
||||||
|
"key": "4a63b226-e8ff-4da4-854e-0b9f04b562ba",
|
||||||
|
"hash": "blake3:d279309ea6e5ee6e8fd52504275865cc280dac71cbf528c5b07c98b888bddaba",
|
||||||
|
"name": "dreamshaper-xl-v2-turbo",
|
||||||
|
"base": "sdxl",
|
||||||
|
"type": "main"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 375,
|
||||||
|
"y": -500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"version": "1.1.1",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "SDXL Positive Compel Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "sdxl_compel_prompt",
|
||||||
|
"inputs": {
|
||||||
|
"prompt": {
|
||||||
|
"name": "prompt",
|
||||||
|
"label": "Positive Prompt",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"name": "style",
|
||||||
|
"label": "Positive Style",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"original_width": {
|
||||||
|
"name": "original_width",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"original_height": {
|
||||||
|
"name": "original_height",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"crop_top": {
|
||||||
|
"name": "crop_top",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"crop_left": {
|
||||||
|
"name": "crop_left",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"target_width": {
|
||||||
|
"name": "target_width",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"target_height": {
|
||||||
|
"name": "target_height",
|
||||||
|
"label": "",
|
||||||
|
"value": 1024
|
||||||
|
},
|
||||||
|
"clip": {
|
||||||
|
"name": "clip",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"clip2": {
|
||||||
|
"name": "clip2",
|
||||||
|
"label": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": false,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": -175
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "63e91020-83b2-4f35-b174-ad9692aabb48",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "63e91020-83b2-4f35-b174-ad9692aabb48",
|
||||||
|
"version": "1.2.2",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "l2i",
|
||||||
|
"inputs": {
|
||||||
|
"board": {
|
||||||
|
"name": "board",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"latents": {
|
||||||
|
"name": "latents",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"vae": {
|
||||||
|
"name": "vae",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"tiled": {
|
||||||
|
"name": "tiled",
|
||||||
|
"label": "",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"fp32": {
|
||||||
|
"name": "fp32",
|
||||||
|
"label": "",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": false,
|
||||||
|
"useCache": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 1475,
|
||||||
|
"y": -500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"nodePack": "invokeai",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "denoise_latents",
|
||||||
|
"inputs": {
|
||||||
|
"positive_conditioning": {
|
||||||
|
"name": "positive_conditioning",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"negative_conditioning": {
|
||||||
|
"name": "negative_conditioning",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"noise": {
|
||||||
|
"name": "noise",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"steps": {
|
||||||
|
"name": "steps",
|
||||||
|
"label": "",
|
||||||
|
"value": 32
|
||||||
|
},
|
||||||
|
"cfg_scale": {
|
||||||
|
"name": "cfg_scale",
|
||||||
|
"label": "",
|
||||||
|
"value": 6
|
||||||
|
},
|
||||||
|
"denoising_start": {
|
||||||
|
"name": "denoising_start",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"denoising_end": {
|
||||||
|
"name": "denoising_end",
|
||||||
|
"label": "",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
"scheduler": {
|
||||||
|
"name": "scheduler",
|
||||||
|
"label": "",
|
||||||
|
"value": "dpmpp_2m_sde_k"
|
||||||
|
},
|
||||||
|
"unet": {
|
||||||
|
"name": "unet",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"control": {
|
||||||
|
"name": "control",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"ip_adapter": {
|
||||||
|
"name": "ip_adapter",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"t2i_adapter": {
|
||||||
|
"name": "t2i_adapter",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"cfg_rescale_multiplier": {
|
||||||
|
"name": "cfg_rescale_multiplier",
|
||||||
|
"label": "",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"latents": {
|
||||||
|
"name": "latents",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
|
"denoise_mask": {
|
||||||
|
"name": "denoise_mask",
|
||||||
|
"label": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 1125,
|
||||||
|
"y": -500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0093692f-9cf4-454d-a5b8-62f0e3eb3bb8",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "0093692f-9cf4-454d-a5b8-62f0e3eb3bb8",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"label": "",
|
||||||
|
"notes": "",
|
||||||
|
"type": "vae_loader",
|
||||||
|
"inputs": {
|
||||||
|
"vae_model": {
|
||||||
|
"name": "vae_model",
|
||||||
|
"label": "VAE (use the FP16 model)",
|
||||||
|
"value": {
|
||||||
|
"key": "f20f9e5c-1bce-4c46-a84d-34ebfa7df069",
|
||||||
|
"hash": "blake3:9705ab1c31fa96b308734214fb7571a958621c7a9247eed82b7d277145f8d9fa",
|
||||||
|
"name": "sdxl-vae-fp16-fix",
|
||||||
|
"base": "sdxl",
|
||||||
|
"type": "vae"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 375,
|
||||||
|
"y": -225
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ade2c0d3-0384-4157-b39b-29ce429cfa15",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "ade2c0d3-0384-4157-b39b-29ce429cfa15",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"label": "Positive Prompt",
|
||||||
|
"notes": "",
|
||||||
|
"type": "string",
|
||||||
|
"inputs": {
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"label": "Positive Prompt",
|
||||||
|
"value": "Super cute tiger cub, fierce, traditional chinese watercolor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": true,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": -500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ad8fa655-3a76-43d0-9c02-4d7644dea650",
|
||||||
|
"type": "invocation",
|
||||||
|
"data": {
|
||||||
|
"id": "ad8fa655-3a76-43d0-9c02-4d7644dea650",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"label": "Negative Style Concat",
|
||||||
|
"notes": "",
|
||||||
|
"type": "string_join",
|
||||||
|
"inputs": {
|
||||||
|
"string_left": {
|
||||||
|
"name": "string_left",
|
||||||
|
"label": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"string_right": {
|
||||||
|
"name": "string_right",
|
||||||
|
"label": "Negative Style Prompt",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isOpen": false,
|
||||||
|
"isIntermediate": true,
|
||||||
|
"useCache": true
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"x": 750,
|
||||||
|
"y": 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"id": "3774ec24-a69e-4254-864c-097d07a6256f-faf965a4-7530-427b-b1f3-4ba6505c2a08-collapsed",
|
||||||
|
"type": "collapsed",
|
||||||
|
"source": "3774ec24-a69e-4254-864c-097d07a6256f",
|
||||||
|
"target": "faf965a4-7530-427b-b1f3-4ba6505c2a08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ad8fa655-3a76-43d0-9c02-4d7644dea650-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204-collapsed",
|
||||||
|
"type": "collapsed",
|
||||||
|
"source": "ad8fa655-3a76-43d0-9c02-4d7644dea650",
|
||||||
|
"target": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-ea94bc37-d995-4a83-aa99-4af42479f2f2value-55705012-79b9-4aac-9f26-c0b10309785bseed",
|
||||||
|
"type": "default",
|
||||||
|
"source": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
|
||||||
|
"target": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "seed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22clip-faf965a4-7530-427b-b1f3-4ba6505c2a08clip",
|
||||||
|
"type": "default",
|
||||||
|
"source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"target": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"sourceHandle": "clip",
|
||||||
|
"targetHandle": "clip"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22clip2-faf965a4-7530-427b-b1f3-4ba6505c2a08clip2",
|
||||||
|
"type": "default",
|
||||||
|
"source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"target": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"sourceHandle": "clip2",
|
||||||
|
"targetHandle": "clip2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22clip-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204clip",
|
||||||
|
"type": "default",
|
||||||
|
"source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"target": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"sourceHandle": "clip",
|
||||||
|
"targetHandle": "clip"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22clip2-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204clip2",
|
||||||
|
"type": "default",
|
||||||
|
"source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"target": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"sourceHandle": "clip2",
|
||||||
|
"targetHandle": "clip2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-30d3289c-773c-4152-a9d2-bd8a99c8fd22unet-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbunet",
|
||||||
|
"type": "default",
|
||||||
|
"source": "30d3289c-773c-4152-a9d2-bd8a99c8fd22",
|
||||||
|
"target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"sourceHandle": "unet",
|
||||||
|
"targetHandle": "unet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-faf965a4-7530-427b-b1f3-4ba6505c2a08conditioning-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbpositive_conditioning",
|
||||||
|
"type": "default",
|
||||||
|
"source": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"sourceHandle": "conditioning",
|
||||||
|
"targetHandle": "positive_conditioning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204conditioning-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbnegative_conditioning",
|
||||||
|
"type": "default",
|
||||||
|
"source": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"sourceHandle": "conditioning",
|
||||||
|
"targetHandle": "negative_conditioning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfbnoise",
|
||||||
|
"type": "default",
|
||||||
|
"source": "55705012-79b9-4aac-9f26-c0b10309785b",
|
||||||
|
"target": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"sourceHandle": "noise",
|
||||||
|
"targetHandle": "noise"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-50a36525-3c0a-4cc5-977c-e4bfc3fd6dfblatents-63e91020-83b2-4f35-b174-ad9692aabb48latents",
|
||||||
|
"type": "default",
|
||||||
|
"source": "50a36525-3c0a-4cc5-977c-e4bfc3fd6dfb",
|
||||||
|
"target": "63e91020-83b2-4f35-b174-ad9692aabb48",
|
||||||
|
"sourceHandle": "latents",
|
||||||
|
"targetHandle": "latents"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-0093692f-9cf4-454d-a5b8-62f0e3eb3bb8vae-63e91020-83b2-4f35-b174-ad9692aabb48vae",
|
||||||
|
"type": "default",
|
||||||
|
"source": "0093692f-9cf4-454d-a5b8-62f0e3eb3bb8",
|
||||||
|
"target": "63e91020-83b2-4f35-b174-ad9692aabb48",
|
||||||
|
"sourceHandle": "vae",
|
||||||
|
"targetHandle": "vae"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-ade2c0d3-0384-4157-b39b-29ce429cfa15value-faf965a4-7530-427b-b1f3-4ba6505c2a08prompt",
|
||||||
|
"type": "default",
|
||||||
|
"source": "ade2c0d3-0384-4157-b39b-29ce429cfa15",
|
||||||
|
"target": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "prompt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-719dabe8-8297-4749-aea1-37be301cd425value-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204prompt",
|
||||||
|
"type": "default",
|
||||||
|
"source": "719dabe8-8297-4749-aea1-37be301cd425",
|
||||||
|
"target": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "prompt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-719dabe8-8297-4749-aea1-37be301cd425value-ad8fa655-3a76-43d0-9c02-4d7644dea650string_left",
|
||||||
|
"type": "default",
|
||||||
|
"source": "719dabe8-8297-4749-aea1-37be301cd425",
|
||||||
|
"target": "ad8fa655-3a76-43d0-9c02-4d7644dea650",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "string_left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-ad8fa655-3a76-43d0-9c02-4d7644dea650value-3193ad09-a7c2-4bf4-a3a9-1c61cc33a204style",
|
||||||
|
"type": "default",
|
||||||
|
"source": "ad8fa655-3a76-43d0-9c02-4d7644dea650",
|
||||||
|
"target": "3193ad09-a7c2-4bf4-a3a9-1c61cc33a204",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "style"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-ade2c0d3-0384-4157-b39b-29ce429cfa15value-3774ec24-a69e-4254-864c-097d07a6256fstring_left",
|
||||||
|
"type": "default",
|
||||||
|
"source": "ade2c0d3-0384-4157-b39b-29ce429cfa15",
|
||||||
|
"target": "3774ec24-a69e-4254-864c-097d07a6256f",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "string_left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactflow__edge-3774ec24-a69e-4254-864c-097d07a6256fvalue-faf965a4-7530-427b-b1f3-4ba6505c2a08style",
|
||||||
|
"type": "default",
|
||||||
|
"source": "3774ec24-a69e-4254-864c-097d07a6256f",
|
||||||
|
"target": "faf965a4-7530-427b-b1f3-4ba6505c2a08",
|
||||||
|
"sourceHandle": "value",
|
||||||
|
"targetHandle": "style"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
"name": "Text to Image with LoRA",
|
"name": "Text to Image with LoRA",
|
||||||
"author": "InvokeAI",
|
"author": "InvokeAI",
|
||||||
"description": "Simple text to image workflow with a LoRA",
|
"description": "Simple text to image workflow with a LoRA",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"contact": "invoke@invoke.ai",
|
"contact": "invoke@invoke.ai",
|
||||||
"tags": "text to image, lora, default",
|
"tags": "text to image, lora, default",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
@ -22,11 +22,23 @@
|
|||||||
{
|
{
|
||||||
"nodeId": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
"nodeId": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
||||||
"fieldName": "prompt"
|
"fieldName": "prompt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
||||||
|
"fieldName": "width"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
||||||
|
"fieldName": "height"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "a9683c0a-6b1f-4a5e-8187-c57e764b3400",
|
||||||
|
"fieldName": "board"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"category": "default",
|
"category": "default",
|
||||||
"version": "2.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
@ -34,773 +46,321 @@
|
|||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "85b77bb2-c67a-416a-b3e8-291abe746c44",
|
"id": "85b77bb2-c67a-416a-b3e8-291abe746c44",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "compel",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "39fe92c4-38eb-4cc7-bf5e-cbcd31847b11",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "Negative Prompt",
|
"label": "Negative Prompt",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "14313164-e5c4-4e40-a599-41b614fe3690",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "02140b9d-50f3-470b-a0b7-01fc6ed2dcd6",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 3425,
|
"x": 3425,
|
||||||
"y": -300
|
"y": -300
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 219
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "24e9d7ed-4836-4ec4-8f9e-e747721f9818",
|
"id": "24e9d7ed-4836-4ec4-8f9e-e747721f9818",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "24e9d7ed-4836-4ec4-8f9e-e747721f9818",
|
"id": "24e9d7ed-4836-4ec4-8f9e-e747721f9818",
|
||||||
"type": "main_model_loader",
|
"version": "1.0.2",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "main_model_loader",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"model": {
|
"model": {
|
||||||
"id": "e2e1c177-ae39-4244-920e-d621fa156a24",
|
|
||||||
"name": "model",
|
"name": "model",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MainModelField"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"model_name": "Analog-Diffusion",
|
|
||||||
"base_model": "sd-1",
|
|
||||||
"model_type": "main"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"vae": {
|
"isIntermediate": true,
|
||||||
"id": "f91410e8-9378-4298-b285-f0f40ffd9825",
|
"useCache": true
|
||||||
"name": "vae",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"clip": {
|
|
||||||
"id": "928d91bf-de0c-44a8-b0c8-4de0e2e5b438",
|
|
||||||
"name": "clip",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"unet": {
|
|
||||||
"id": "eacaf530-4e7e-472e-b904-462192189fc1",
|
|
||||||
"name": "unet",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 2500,
|
"x": 2500,
|
||||||
"y": -600
|
"y": -600
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 193
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "c41e705b-f2e3-4d1a-83c4-e34bb9344966",
|
"id": "c41e705b-f2e3-4d1a-83c4-e34bb9344966",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "c41e705b-f2e3-4d1a-83c4-e34bb9344966",
|
"id": "c41e705b-f2e3-4d1a-83c4-e34bb9344966",
|
||||||
"type": "lora_loader",
|
"version": "1.0.2",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "lora_loader",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"lora": {
|
"lora": {
|
||||||
"id": "36d867e8-92ea-4c3f-9ad5-ba05c64cf326",
|
|
||||||
"name": "lora",
|
"name": "lora",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LoRAModelField"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"model_name": "Ink scenery",
|
|
||||||
"base_model": "sd-1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"weight": {
|
"weight": {
|
||||||
"id": "8be86540-ba81-49b3-b394-2b18fa70b867",
|
|
||||||
"name": "weight",
|
"name": "weight",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "LoRA Weight",
|
"label": "LoRA Weight",
|
||||||
"type": {
|
"value": 1
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0.75
|
|
||||||
},
|
},
|
||||||
"unet": {
|
"unet": {
|
||||||
"id": "9c4d5668-e9e1-411b-8f4b-e71115bc4a01",
|
|
||||||
"name": "unet",
|
"name": "unet",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "918ec00e-e76f-4ad0-aee1-3927298cf03b",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"unet": {
|
"isIntermediate": true,
|
||||||
"id": "c63f7825-1bcf-451d-b7a7-aa79f5c77416",
|
"useCache": true
|
||||||
"name": "unet",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"clip": {
|
|
||||||
"id": "6f79ef2d-00f7-4917-bee3-53e845bf4192",
|
|
||||||
"name": "clip",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 2975,
|
"x": 2975,
|
||||||
"y": -600
|
"y": -600
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 218
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
"id": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
"id": "c3fa6872-2599-4a82-a596-b3446a66cf8b",
|
||||||
"type": "compel",
|
"version": "1.1.1",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "compel",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"id": "39fe92c4-38eb-4cc7-bf5e-cbcd31847b11",
|
|
||||||
"name": "prompt",
|
"name": "prompt",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "Positive Prompt",
|
"label": "Positive Prompt",
|
||||||
"type": {
|
"value": "super cute tiger cub"
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "StringField"
|
|
||||||
},
|
|
||||||
"value": "cute tiger cub"
|
|
||||||
},
|
},
|
||||||
"clip": {
|
"clip": {
|
||||||
"id": "14313164-e5c4-4e40-a599-41b614fe3690",
|
|
||||||
"name": "clip",
|
"name": "clip",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ClipField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"conditioning": {
|
"isIntermediate": true,
|
||||||
"id": "02140b9d-50f3-470b-a0b7-01fc6ed2dcd6",
|
"useCache": true
|
||||||
"name": "conditioning",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 3425,
|
"x": 3425,
|
||||||
"y": -575
|
"y": -575
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 219
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ad487d0c-dcbb-49c5-bb8e-b28d4cbc5a63",
|
"id": "ad487d0c-dcbb-49c5-bb8e-b28d4cbc5a63",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "ad487d0c-dcbb-49c5-bb8e-b28d4cbc5a63",
|
"id": "ad487d0c-dcbb-49c5-bb8e-b28d4cbc5a63",
|
||||||
"type": "denoise_latents",
|
"version": "1.5.3",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "denoise_latents",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.5.1",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"positive_conditioning": {
|
"positive_conditioning": {
|
||||||
"id": "025ff44b-c4c6-4339-91b4-5f461e2cadc5",
|
|
||||||
"name": "positive_conditioning",
|
"name": "positive_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"negative_conditioning": {
|
"negative_conditioning": {
|
||||||
"id": "2d92b45a-a7fb-4541-9a47-7c7495f50f54",
|
|
||||||
"name": "negative_conditioning",
|
"name": "negative_conditioning",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ConditioningField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"noise": {
|
"noise": {
|
||||||
"id": "4d0deeff-24ed-4562-a1ca-7833c0649377",
|
|
||||||
"name": "noise",
|
"name": "noise",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"steps": {
|
"steps": {
|
||||||
"id": "c9907328-aece-4af9-8a95-211b4f99a325",
|
|
||||||
"name": "steps",
|
"name": "steps",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": 30
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 10
|
|
||||||
},
|
},
|
||||||
"cfg_scale": {
|
"cfg_scale": {
|
||||||
"id": "7cf0f031-2078-49f4-9273-bb3a64ad7130",
|
|
||||||
"name": "cfg_scale",
|
"name": "cfg_scale",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 7.5
|
"value": 7.5
|
||||||
},
|
},
|
||||||
"denoising_start": {
|
"denoising_start": {
|
||||||
"id": "44cec3ba-b404-4b51-ba98-add9d783279e",
|
|
||||||
"name": "denoising_start",
|
"name": "denoising_start",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"denoising_end": {
|
"denoising_end": {
|
||||||
"id": "3e7975f3-e438-4a13-8a14-395eba1fb7cd",
|
|
||||||
"name": "denoising_end",
|
"name": "denoising_end",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"id": "a6f6509b-7bb4-477d-b5fb-74baefa38111",
|
|
||||||
"name": "scheduler",
|
"name": "scheduler",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "SchedulerField"
|
|
||||||
},
|
|
||||||
"value": "euler"
|
"value": "euler"
|
||||||
},
|
},
|
||||||
"unet": {
|
"unet": {
|
||||||
"id": "5a87617a-b09f-417b-9b75-0cea4c255227",
|
|
||||||
"name": "unet",
|
"name": "unet",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "UNetField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"control": {
|
"control": {
|
||||||
"id": "db87aace-ace8-4f2a-8f2b-1f752389fa9b",
|
|
||||||
"name": "control",
|
"name": "control",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "ControlField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"ip_adapter": {
|
"ip_adapter": {
|
||||||
"id": "f0c133ed-4d6d-4567-bb9a-b1779810993c",
|
|
||||||
"name": "ip_adapter",
|
"name": "ip_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "IPAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"t2i_adapter": {
|
"t2i_adapter": {
|
||||||
"id": "59ee1233-887f-45e7-aa14-cbad5f6cb77f",
|
|
||||||
"name": "t2i_adapter",
|
"name": "t2i_adapter",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": true,
|
|
||||||
"name": "T2IAdapterField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"cfg_rescale_multiplier": {
|
"cfg_rescale_multiplier": {
|
||||||
"id": "1a12e781-4b30-4707-b432-18c31866b5c3",
|
|
||||||
"name": "cfg_rescale_multiplier",
|
"name": "cfg_rescale_multiplier",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "FloatField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "d0e593ae-305c-424b-9acd-3af830085832",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"denoise_mask": {
|
"denoise_mask": {
|
||||||
"id": "b81b5a79-fc2b-4011-aae6-64c92bae59a7",
|
|
||||||
"name": "denoise_mask",
|
"name": "denoise_mask",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "DenoiseMaskField"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"latents": {
|
"isIntermediate": true,
|
||||||
"id": "9ae4022a-548e-407e-90cf-cc5ca5ff8a21",
|
"useCache": true
|
||||||
"name": "latents",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "730ba4bd-2c52-46bb-8c87-9b3aec155576",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "52b98f0b-b5ff-41b5-acc7-d0b1d1011a6f",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 3975,
|
"x": 3975,
|
||||||
"y": -575
|
"y": -575
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 612
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
"id": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
"id": "ea18915f-2c5b-4569-b725-8e9e9122e8d3",
|
||||||
"type": "noise",
|
"version": "1.0.2",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "noise",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.0.1",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"seed": {
|
"seed": {
|
||||||
"id": "446ac80c-ba0a-4fea-a2d7-21128f52e5bf",
|
|
||||||
"name": "seed",
|
"name": "seed",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"id": "779831b3-20b4-4f5f-9de7-d17de57288d8",
|
|
||||||
"name": "width",
|
"name": "width",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
"value": 512
|
||||||
},
|
},
|
||||||
"height": {
|
"height": {
|
||||||
"id": "08959766-6d67-4276-b122-e54b911f2316",
|
|
||||||
"name": "height",
|
"name": "height",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
"value": 768
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 512
|
|
||||||
},
|
},
|
||||||
"use_cpu": {
|
"use_cpu": {
|
||||||
"id": "53b36a98-00c4-4dc5-97a4-ef3432c0a805",
|
|
||||||
"name": "use_cpu",
|
"name": "use_cpu",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"noise": {
|
"isIntermediate": true,
|
||||||
"id": "eed95824-580b-442f-aa35-c073733cecce",
|
"useCache": true
|
||||||
"name": "noise",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "7985a261-dfee-47a8-908a-c5a8754f5dc4",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "3d00f6c1-84b0-4262-83d9-3bf755babeea",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 3425,
|
"x": 3425,
|
||||||
"y": 75
|
"y": 75
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "6fd74a17-6065-47a5-b48b-f4e2b8fa7953",
|
"id": "6fd74a17-6065-47a5-b48b-f4e2b8fa7953",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "6fd74a17-6065-47a5-b48b-f4e2b8fa7953",
|
"id": "6fd74a17-6065-47a5-b48b-f4e2b8fa7953",
|
||||||
"type": "rand_int",
|
"version": "1.0.1",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": false,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": true,
|
"type": "rand_int",
|
||||||
"useCache": false,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"low": {
|
"low": {
|
||||||
"id": "d25305f3-bfd6-446c-8e2c-0b025ec9e9ad",
|
|
||||||
"name": "low",
|
"name": "low",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"high": {
|
"high": {
|
||||||
"id": "10376a3d-b8fe-4a51-b81a-ea46d8c12c78",
|
|
||||||
"name": "high",
|
"name": "high",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
},
|
|
||||||
"value": 2147483647
|
"value": 2147483647
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": false,
|
||||||
"value": {
|
"isIntermediate": true,
|
||||||
"id": "c64878fa-53b1-4202-b88a-cfb854216a57",
|
"useCache": false
|
||||||
"name": "value",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 3425,
|
"x": 3425,
|
||||||
"y": 0
|
"y": 0
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 24
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "a9683c0a-6b1f-4a5e-8187-c57e764b3400",
|
"id": "a9683c0a-6b1f-4a5e-8187-c57e764b3400",
|
||||||
"type": "invocation",
|
"type": "invocation",
|
||||||
"data": {
|
"data": {
|
||||||
"id": "a9683c0a-6b1f-4a5e-8187-c57e764b3400",
|
"id": "a9683c0a-6b1f-4a5e-8187-c57e764b3400",
|
||||||
"type": "l2i",
|
"version": "1.2.2",
|
||||||
"label": "",
|
"label": "",
|
||||||
"isOpen": true,
|
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"isIntermediate": false,
|
"type": "l2i",
|
||||||
"useCache": true,
|
|
||||||
"version": "1.2.0",
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"board": {
|
||||||
|
"name": "board",
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"id": "b1982e8a-14ad-4029-a697-beb30af8340f",
|
|
||||||
"name": "metadata",
|
"name": "metadata",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "MetadataField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"latents": {
|
"latents": {
|
||||||
"id": "f7669388-9f91-46cc-94fc-301fa7041c3e",
|
|
||||||
"name": "latents",
|
"name": "latents",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "LatentsField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"vae": {
|
"vae": {
|
||||||
"id": "c6f2d4db-4d0a-4e3d-acb4-b5c5a228a3e2",
|
|
||||||
"name": "vae",
|
"name": "vae",
|
||||||
"fieldKind": "input",
|
"label": ""
|
||||||
"label": "",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "VaeField"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tiled": {
|
"tiled": {
|
||||||
"id": "19ef7d31-d96f-4e94-b7e5-95914e9076fc",
|
|
||||||
"name": "tiled",
|
"name": "tiled",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"fp32": {
|
"fp32": {
|
||||||
"id": "a9454533-8ab7-4225-b411-646dc5e76d00",
|
|
||||||
"name": "fp32",
|
"name": "fp32",
|
||||||
"fieldKind": "input",
|
|
||||||
"label": "",
|
"label": "",
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "BooleanField"
|
|
||||||
},
|
|
||||||
"value": false
|
"value": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {
|
"isOpen": true,
|
||||||
"image": {
|
"isIntermediate": false,
|
||||||
"id": "4f81274e-e216-47f3-9fb6-f97493a40e6f",
|
"useCache": true
|
||||||
"name": "image",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "ImageField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"id": "61a9acfb-1547-4f1e-8214-e89bd3855ee5",
|
|
||||||
"name": "width",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"id": "b15cc793-4172-4b07-bcf4-5627bbc7d0d7",
|
|
||||||
"name": "height",
|
|
||||||
"fieldKind": "output",
|
|
||||||
"type": {
|
|
||||||
"isCollection": false,
|
|
||||||
"isCollectionOrScalar": false,
|
|
||||||
"name": "IntegerField"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": 4450,
|
"x": 4450,
|
||||||
"y": -550
|
"y": -550
|
||||||
},
|
}
|
||||||
"width": 320,
|
|
||||||
"height": 224
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"edges": [
|
"edges": [
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -33,42 +33,3 @@ __all__ = [
|
|||||||
"SchedulerPredictionType",
|
"SchedulerPredictionType",
|
||||||
"SubModelType",
|
"SubModelType",
|
||||||
]
|
]
|
||||||
|
|
||||||
########## to help populate the openapi_schema with format enums for each config ###########
|
|
||||||
# This code is no longer necessary?
|
|
||||||
# leave it here just in case
|
|
||||||
#
|
|
||||||
# import inspect
|
|
||||||
# from enum import Enum
|
|
||||||
# from typing import Any, Iterable, Dict, get_args, Set
|
|
||||||
# def _expand(something: Any) -> Iterable[type]:
|
|
||||||
# if isinstance(something, type):
|
|
||||||
# yield something
|
|
||||||
# else:
|
|
||||||
# for x in get_args(something):
|
|
||||||
# for y in _expand(x):
|
|
||||||
# yield y
|
|
||||||
|
|
||||||
# def _find_format(cls: type) -> Iterable[Enum]:
|
|
||||||
# if hasattr(inspect, "get_annotations"):
|
|
||||||
# fields = inspect.get_annotations(cls)
|
|
||||||
# else:
|
|
||||||
# fields = cls.__annotations__
|
|
||||||
# if "format" in fields:
|
|
||||||
# for x in get_args(fields["format"]):
|
|
||||||
# yield x
|
|
||||||
# for parent_class in cls.__bases__:
|
|
||||||
# for x in _find_format(parent_class):
|
|
||||||
# yield x
|
|
||||||
# return None
|
|
||||||
|
|
||||||
# def get_model_config_formats() -> Dict[str, Set[Enum]]:
|
|
||||||
# result: Dict[str, Set[Enum]] = {}
|
|
||||||
# for model_config in _expand(AnyModelConfig):
|
|
||||||
# for field in _find_format(model_config):
|
|
||||||
# if field is None:
|
|
||||||
# continue
|
|
||||||
# if not result.get(model_config.__qualname__):
|
|
||||||
# result[model_config.__qualname__] = set()
|
|
||||||
# result[model_config.__qualname__].add(field)
|
|
||||||
# return result
|
|
||||||
|
@ -146,11 +146,15 @@ class MainModelDefaultSettings(BaseModel):
|
|||||||
width: int | None = Field(default=None, multiple_of=8, ge=64, description="Default width for this model")
|
width: int | None = Field(default=None, multiple_of=8, ge=64, description="Default width for this model")
|
||||||
height: int | None = Field(default=None, multiple_of=8, ge=64, description="Default height for this model")
|
height: int | None = Field(default=None, multiple_of=8, ge=64, description="Default height for this model")
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
||||||
|
|
||||||
class ControlAdapterDefaultSettings(BaseModel):
|
class ControlAdapterDefaultSettings(BaseModel):
|
||||||
# This could be narrowed to controlnet processor nodes, but they change. Leaving this a string is safer.
|
# This could be narrowed to controlnet processor nodes, but they change. Leaving this a string is safer.
|
||||||
preprocessor: str | None
|
preprocessor: str | None
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
||||||
|
|
||||||
class ModelConfigBase(BaseModel):
|
class ModelConfigBase(BaseModel):
|
||||||
"""Base class for model configuration information."""
|
"""Base class for model configuration information."""
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"""Conversion script for the Stable Diffusion checkpoints."""
|
"""Conversion script for the Stable Diffusion checkpoints."""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict, Optional
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from diffusers import AutoencoderKL
|
from diffusers import AutoencoderKL
|
||||||
@ -15,6 +15,8 @@ from diffusers.pipelines.stable_diffusion.convert_from_ckpt import (
|
|||||||
)
|
)
|
||||||
from omegaconf import DictConfig
|
from omegaconf import DictConfig
|
||||||
|
|
||||||
|
from . import AnyModel
|
||||||
|
|
||||||
|
|
||||||
def convert_ldm_vae_to_diffusers(
|
def convert_ldm_vae_to_diffusers(
|
||||||
checkpoint: Dict[str, torch.Tensor],
|
checkpoint: Dict[str, torch.Tensor],
|
||||||
@ -33,11 +35,11 @@ def convert_ldm_vae_to_diffusers(
|
|||||||
|
|
||||||
def convert_ckpt_to_diffusers(
|
def convert_ckpt_to_diffusers(
|
||||||
checkpoint_path: str | Path,
|
checkpoint_path: str | Path,
|
||||||
dump_path: str | Path,
|
dump_path: Optional[str | Path] = None,
|
||||||
precision: torch.dtype = torch.float16,
|
precision: torch.dtype = torch.float16,
|
||||||
use_safetensors: bool = True,
|
use_safetensors: bool = True,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
) -> AnyModel:
|
||||||
"""
|
"""
|
||||||
Takes all the arguments of download_from_original_stable_diffusion_ckpt(),
|
Takes all the arguments of download_from_original_stable_diffusion_ckpt(),
|
||||||
and in addition a path-like object indicating the location of the desired diffusers
|
and in addition a path-like object indicating the location of the desired diffusers
|
||||||
@ -47,18 +49,20 @@ def convert_ckpt_to_diffusers(
|
|||||||
pipe = pipe.to(precision)
|
pipe = pipe.to(precision)
|
||||||
|
|
||||||
# TO DO: save correct repo variant
|
# TO DO: save correct repo variant
|
||||||
pipe.save_pretrained(
|
if dump_path:
|
||||||
dump_path,
|
pipe.save_pretrained(
|
||||||
safe_serialization=use_safetensors,
|
dump_path,
|
||||||
)
|
safe_serialization=use_safetensors,
|
||||||
|
)
|
||||||
|
return pipe
|
||||||
|
|
||||||
|
|
||||||
def convert_controlnet_to_diffusers(
|
def convert_controlnet_to_diffusers(
|
||||||
checkpoint_path: Path,
|
checkpoint_path: Path,
|
||||||
dump_path: Path,
|
dump_path: Optional[Path] = None,
|
||||||
precision: torch.dtype = torch.float16,
|
precision: torch.dtype = torch.float16,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
) -> AnyModel:
|
||||||
"""
|
"""
|
||||||
Takes all the arguments of download_controlnet_from_original_ckpt(),
|
Takes all the arguments of download_controlnet_from_original_ckpt(),
|
||||||
and in addition a path-like object indicating the location of the desired diffusers
|
and in addition a path-like object indicating the location of the desired diffusers
|
||||||
@ -68,4 +72,6 @@ def convert_controlnet_to_diffusers(
|
|||||||
pipe = pipe.to(precision)
|
pipe = pipe.to(precision)
|
||||||
|
|
||||||
# TO DO: save correct repo variant
|
# TO DO: save correct repo variant
|
||||||
pipe.save_pretrained(dump_path, safe_serialization=True)
|
if dump_path:
|
||||||
|
pipe.save_pretrained(dump_path, safe_serialization=True)
|
||||||
|
return pipe
|
||||||
|
@ -19,11 +19,20 @@ class ModelConvertCache(ModelConvertCacheBase):
|
|||||||
self._cache_path = cache_path
|
self._cache_path = cache_path
|
||||||
self._max_size = max_size
|
self._max_size = max_size
|
||||||
|
|
||||||
|
# adjust cache size at startup in case it has been changed
|
||||||
|
if self._cache_path.exists():
|
||||||
|
self.make_room(0.0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_size(self) -> float:
|
def max_size(self) -> float:
|
||||||
"""Return the maximum size of this cache directory (GB)."""
|
"""Return the maximum size of this cache directory (GB)."""
|
||||||
return self._max_size
|
return self._max_size
|
||||||
|
|
||||||
|
@max_size.setter
|
||||||
|
def max_size(self, value: float) -> None:
|
||||||
|
"""Set the maximum size of this cache directory (GB)."""
|
||||||
|
self._max_size = value
|
||||||
|
|
||||||
def cache_path(self, key: str) -> Path:
|
def cache_path(self, key: str) -> Path:
|
||||||
"""Return the path for a model with the indicated key."""
|
"""Return the path for a model with the indicated key."""
|
||||||
return self._cache_path / key
|
return self._cache_path / key
|
||||||
|
@ -82,3 +82,15 @@ class ModelLoaderBase(ABC):
|
|||||||
) -> int:
|
) -> int:
|
||||||
"""Return size in bytes of the model, calculated before loading."""
|
"""Return size in bytes of the model, calculated before loading."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def convert_cache(self) -> ModelConvertCacheBase:
|
||||||
|
"""Return the convert cache associated with this loader."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def ram_cache(self) -> ModelCacheBase[AnyModel]:
|
||||||
|
"""Return the ram cache associated with this loader."""
|
||||||
|
pass
|
||||||
|
@ -3,14 +3,13 @@
|
|||||||
|
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
|
|
||||||
from invokeai.app.services.config import InvokeAIAppConfig
|
from invokeai.app.services.config import InvokeAIAppConfig
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
AnyModel,
|
AnyModel,
|
||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
InvalidModelConfigException,
|
InvalidModelConfigException,
|
||||||
ModelRepoVariant,
|
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
from invokeai.backend.model_manager.config import DiffusersConfigBase, ModelType
|
from invokeai.backend.model_manager.config import DiffusersConfigBase, ModelType
|
||||||
@ -54,51 +53,43 @@ class ModelLoader(ModelLoaderBase):
|
|||||||
if model_config.type is ModelType.Main and not submodel_type:
|
if model_config.type is ModelType.Main and not submodel_type:
|
||||||
raise InvalidModelConfigException("submodel_type is required when loading a main model")
|
raise InvalidModelConfigException("submodel_type is required when loading a main model")
|
||||||
|
|
||||||
model_path, model_config, submodel_type = self._get_model_path(model_config, submodel_type)
|
model_path = self._get_model_path(model_config)
|
||||||
|
|
||||||
if not model_path.exists():
|
if not model_path.exists():
|
||||||
raise InvalidModelConfigException(f"Files for model '{model_config.name}' not found at {model_path}")
|
raise InvalidModelConfigException(f"Files for model '{model_config.name}' not found at {model_path}")
|
||||||
|
|
||||||
model_path = self._convert_if_needed(model_config, model_path, submodel_type)
|
with skip_torch_weight_init():
|
||||||
locker = self._load_if_needed(model_config, model_path, submodel_type)
|
locker = self._convert_and_load(model_config, model_path, submodel_type)
|
||||||
return LoadedModel(config=model_config, _locker=locker)
|
return LoadedModel(config=model_config, _locker=locker)
|
||||||
|
|
||||||
def _get_model_path(
|
@property
|
||||||
self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None
|
def convert_cache(self) -> ModelConvertCacheBase:
|
||||||
) -> Tuple[Path, AnyModelConfig, Optional[SubModelType]]:
|
"""Return the convert cache associated with this loader."""
|
||||||
|
return self._convert_cache
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ram_cache(self) -> ModelCacheBase[AnyModel]:
|
||||||
|
"""Return the ram cache associated with this loader."""
|
||||||
|
return self._ram_cache
|
||||||
|
|
||||||
|
def _get_model_path(self, config: AnyModelConfig) -> Path:
|
||||||
model_base = self._app_config.models_path
|
model_base = self._app_config.models_path
|
||||||
result = (model_base / config.path).resolve(), config, submodel_type
|
return (model_base / config.path).resolve()
|
||||||
return result
|
|
||||||
|
|
||||||
def _convert_if_needed(
|
def _convert_and_load(
|
||||||
self, config: AnyModelConfig, model_path: Path, submodel_type: Optional[SubModelType] = None
|
|
||||||
) -> Path:
|
|
||||||
cache_path: Path = self._convert_cache.cache_path(config.key)
|
|
||||||
|
|
||||||
if not self._needs_conversion(config, model_path, cache_path):
|
|
||||||
return cache_path if cache_path.exists() else model_path
|
|
||||||
|
|
||||||
self._convert_cache.make_room(self.get_size_fs(config, model_path, submodel_type))
|
|
||||||
return self._convert_model(config, model_path, cache_path)
|
|
||||||
|
|
||||||
def _needs_conversion(self, config: AnyModelConfig, model_path: Path, dest_path: Path) -> bool:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _load_if_needed(
|
|
||||||
self, config: AnyModelConfig, model_path: Path, submodel_type: Optional[SubModelType] = None
|
self, config: AnyModelConfig, model_path: Path, submodel_type: Optional[SubModelType] = None
|
||||||
) -> ModelLockerBase:
|
) -> ModelLockerBase:
|
||||||
# TO DO: This is not thread safe!
|
|
||||||
try:
|
try:
|
||||||
return self._ram_cache.get(config.key, submodel_type)
|
return self._ram_cache.get(config.key, submodel_type)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
model_variant = getattr(config, "repo_variant", None)
|
cache_path: Path = self._convert_cache.cache_path(config.key)
|
||||||
self._ram_cache.make_room(self.get_size_fs(config, model_path, submodel_type))
|
if self._needs_conversion(config, model_path, cache_path):
|
||||||
|
loaded_model = self._do_convert(config, model_path, cache_path, submodel_type)
|
||||||
# This is where the model is actually loaded!
|
else:
|
||||||
with skip_torch_weight_init():
|
config.path = str(cache_path) if cache_path.exists() else str(self._get_model_path(config))
|
||||||
loaded_model = self._load_model(model_path, model_variant=model_variant, submodel_type=submodel_type)
|
loaded_model = self._load_model(config, submodel_type)
|
||||||
|
|
||||||
self._ram_cache.put(
|
self._ram_cache.put(
|
||||||
config.key,
|
config.key,
|
||||||
@ -123,15 +114,34 @@ class ModelLoader(ModelLoaderBase):
|
|||||||
variant=config.repo_variant if isinstance(config, DiffusersConfigBase) else None,
|
variant=config.repo_variant if isinstance(config, DiffusersConfigBase) else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _do_convert(
|
||||||
|
self, config: AnyModelConfig, model_path: Path, cache_path: Path, submodel_type: Optional[SubModelType] = None
|
||||||
|
) -> AnyModel:
|
||||||
|
self.convert_cache.make_room(calc_model_size_by_fs(model_path))
|
||||||
|
pipeline = self._convert_model(config, model_path, cache_path if self.convert_cache.max_size > 0 else None)
|
||||||
|
if submodel_type:
|
||||||
|
# Proactively load the various submodels into the RAM cache so that we don't have to re-convert
|
||||||
|
# the entire pipeline every time a new submodel is needed.
|
||||||
|
for subtype in SubModelType:
|
||||||
|
if subtype == submodel_type:
|
||||||
|
continue
|
||||||
|
if submodel := getattr(pipeline, subtype.value, None):
|
||||||
|
self._ram_cache.put(
|
||||||
|
config.key, submodel_type=subtype, model=submodel, size=calc_model_size_by_data(submodel)
|
||||||
|
)
|
||||||
|
return getattr(pipeline, submodel_type.value) if submodel_type else pipeline
|
||||||
|
|
||||||
|
def _needs_conversion(self, config: AnyModelConfig, model_path: Path, dest_path: Path) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
# This needs to be implemented in subclasses that handle checkpoints
|
# This needs to be implemented in subclasses that handle checkpoints
|
||||||
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Path) -> Path:
|
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Optional[Path] = None) -> AnyModel:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
# This needs to be implemented in the subclass
|
# This needs to be implemented in the subclass
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -130,6 +130,11 @@ class ModelCache(ModelCacheBase[AnyModel]):
|
|||||||
"""Return the cap on cache size."""
|
"""Return the cap on cache size."""
|
||||||
return self._max_cache_size
|
return self._max_cache_size
|
||||||
|
|
||||||
|
@max_cache_size.setter
|
||||||
|
def max_cache_size(self, value: float) -> None:
|
||||||
|
"""Set the cap on cache size."""
|
||||||
|
self._max_cache_size = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stats(self) -> Optional[CacheStats]:
|
def stats(self) -> Optional[CacheStats]:
|
||||||
"""Return collected CacheStats object."""
|
"""Return collected CacheStats object."""
|
||||||
@ -166,9 +171,10 @@ class ModelCache(ModelCacheBase[AnyModel]):
|
|||||||
"""Store model under key and optional submodel_type."""
|
"""Store model under key and optional submodel_type."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
key = self._make_cache_key(key, submodel_type)
|
key = self._make_cache_key(key, submodel_type)
|
||||||
assert key not in self._cached_models
|
if key in self._cached_models:
|
||||||
|
return
|
||||||
cache_record = CacheRecord(key=key, model=model, size=size)
|
self.make_room(size)
|
||||||
|
cache_record = CacheRecord(key, model, size)
|
||||||
self._cached_models[key] = cache_record
|
self._cached_models[key] = cache_record
|
||||||
self._cache_stack.append(key)
|
self._cache_stack.append(key)
|
||||||
|
|
||||||
@ -334,6 +340,8 @@ class ModelCache(ModelCacheBase[AnyModel]):
|
|||||||
#
|
#
|
||||||
# Keep in mind that gc is only responsible for handling reference cycles. Most objects should be cleaned up
|
# Keep in mind that gc is only responsible for handling reference cycles. Most objects should be cleaned up
|
||||||
# immediately when their reference count hits 0.
|
# immediately when their reference count hits 0.
|
||||||
|
if self.stats:
|
||||||
|
self.stats.cleared = models_cleared
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
torch.cuda.empty_cache()
|
torch.cuda.empty_cache()
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
"""Class for ControlNet model loading in InvokeAI."""
|
"""Class for ControlNet model loading in InvokeAI."""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
|
AnyModel,
|
||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
@ -33,7 +35,7 @@ class ControlNetLoader(GenericDiffusersLoader):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Path) -> Path:
|
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Optional[Path] = None) -> AnyModel:
|
||||||
assert isinstance(config, CheckpointConfigBase)
|
assert isinstance(config, CheckpointConfigBase)
|
||||||
image_size = (
|
image_size = (
|
||||||
512
|
512
|
||||||
@ -44,8 +46,8 @@ class ControlNetLoader(GenericDiffusersLoader):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._logger.info(f"Converting {model_path} to diffusers format")
|
self._logger.info(f"Converting {model_path} to diffusers format")
|
||||||
with open(self._app_config.root_path / config.config_path, "r") as config_stream:
|
with open(self._app_config.legacy_conf_path / config.config_path, "r") as config_stream:
|
||||||
convert_controlnet_to_diffusers(
|
result = convert_controlnet_to_diffusers(
|
||||||
model_path,
|
model_path,
|
||||||
output_path,
|
output_path,
|
||||||
original_config_file=config_stream,
|
original_config_file=config_stream,
|
||||||
@ -53,4 +55,4 @@ class ControlNetLoader(GenericDiffusersLoader):
|
|||||||
precision=self._torch_dtype,
|
precision=self._torch_dtype,
|
||||||
from_safetensors=model_path.suffix == ".safetensors",
|
from_safetensors=model_path.suffix == ".safetensors",
|
||||||
)
|
)
|
||||||
return output_path
|
return result
|
||||||
|
@ -10,13 +10,14 @@ from diffusers.models.modeling_utils import ModelMixin
|
|||||||
|
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
AnyModel,
|
AnyModel,
|
||||||
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
InvalidModelConfigException,
|
InvalidModelConfigException,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
|
from invokeai.backend.model_manager.config import DiffusersConfigBase
|
||||||
|
|
||||||
from .. import ModelLoader, ModelLoaderRegistry
|
from .. import ModelLoader, ModelLoaderRegistry
|
||||||
|
|
||||||
@ -28,14 +29,15 @@ class GenericDiffusersLoader(ModelLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
|
model_path = Path(config.path)
|
||||||
model_class = self.get_hf_load_class(model_path)
|
model_class = self.get_hf_load_class(model_path)
|
||||||
if submodel_type is not None:
|
if submodel_type is not None:
|
||||||
raise Exception(f"There are no submodels in models of type {model_class}")
|
raise Exception(f"There are no submodels in models of type {model_class}")
|
||||||
variant = model_variant.value if model_variant else None
|
repo_variant = config.repo_variant if isinstance(config, DiffusersConfigBase) else None
|
||||||
|
variant = repo_variant.value if repo_variant else None
|
||||||
try:
|
try:
|
||||||
result: AnyModel = model_class.from_pretrained(model_path, torch_dtype=self._torch_dtype, variant=variant)
|
result: AnyModel = model_class.from_pretrained(model_path, torch_dtype=self._torch_dtype, variant=variant)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
|
@ -9,13 +9,14 @@ import torch
|
|||||||
from invokeai.backend.ip_adapter.ip_adapter import build_ip_adapter
|
from invokeai.backend.ip_adapter.ip_adapter import build_ip_adapter
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
AnyModel,
|
AnyModel,
|
||||||
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
from invokeai.backend.model_manager.load import ModelLoader, ModelLoaderRegistry
|
from invokeai.backend.model_manager.load import ModelLoader, ModelLoaderRegistry
|
||||||
|
from invokeai.backend.raw_model import RawModel
|
||||||
|
|
||||||
|
|
||||||
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.IPAdapter, format=ModelFormat.InvokeAI)
|
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.IPAdapter, format=ModelFormat.InvokeAI)
|
||||||
@ -24,13 +25,13 @@ class IPAdapterInvokeAILoader(ModelLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
if submodel_type is not None:
|
if submodel_type is not None:
|
||||||
raise ValueError("There are no submodels in an IP-Adapter model.")
|
raise ValueError("There are no submodels in an IP-Adapter model.")
|
||||||
model = build_ip_adapter(
|
model_path = Path(config.path)
|
||||||
|
model: RawModel = build_ip_adapter(
|
||||||
ip_adapter_ckpt_path=str(model_path / "ip_adapter.bin"),
|
ip_adapter_ckpt_path=str(model_path / "ip_adapter.bin"),
|
||||||
device=torch.device("cpu"),
|
device=torch.device("cpu"),
|
||||||
dtype=self._torch_dtype,
|
dtype=self._torch_dtype,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
|
|
||||||
from invokeai.app.services.config import InvokeAIAppConfig
|
from invokeai.app.services.config import InvokeAIAppConfig
|
||||||
from invokeai.backend.lora import LoRAModelRaw
|
from invokeai.backend.lora import LoRAModelRaw
|
||||||
@ -12,7 +12,6 @@ from invokeai.backend.model_manager import (
|
|||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
@ -41,12 +40,12 @@ class LoRALoader(ModelLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
if submodel_type is not None:
|
if submodel_type is not None:
|
||||||
raise ValueError("There are no submodels in a LoRA model.")
|
raise ValueError("There are no submodels in a LoRA model.")
|
||||||
|
model_path = Path(config.path)
|
||||||
assert self._model_base is not None
|
assert self._model_base is not None
|
||||||
model = LoRAModelRaw.from_checkpoint(
|
model = LoRAModelRaw.from_checkpoint(
|
||||||
file_path=model_path,
|
file_path=model_path,
|
||||||
@ -56,12 +55,9 @@ class LoRALoader(ModelLoader):
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
# override
|
# override
|
||||||
def _get_model_path(
|
def _get_model_path(self, config: AnyModelConfig) -> Path:
|
||||||
self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None
|
# cheating a little - we remember this variable for using in the subsequent call to _load_model()
|
||||||
) -> Tuple[Path, AnyModelConfig, Optional[SubModelType]]:
|
self._model_base = config.base
|
||||||
self._model_base = (
|
|
||||||
config.base
|
|
||||||
) # cheating a little - we remember this variable for using in the subsequent call to _load_model()
|
|
||||||
|
|
||||||
model_base_path = self._app_config.models_path
|
model_base_path = self._app_config.models_path
|
||||||
model_path = model_base_path / config.path
|
model_path = model_base_path / config.path
|
||||||
@ -73,5 +69,4 @@ class LoRALoader(ModelLoader):
|
|||||||
model_path = path
|
model_path = path
|
||||||
break
|
break
|
||||||
|
|
||||||
result = model_path.resolve(), config, submodel_type
|
return model_path.resolve()
|
||||||
return result
|
|
||||||
|
@ -7,9 +7,9 @@ from typing import Optional
|
|||||||
|
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
AnyModel,
|
AnyModel,
|
||||||
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
@ -25,18 +25,19 @@ class OnnyxDiffusersModel(GenericDiffusersLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
if not submodel_type is not None:
|
if not submodel_type is not None:
|
||||||
raise Exception("A submodel type must be provided when loading onnx pipelines.")
|
raise Exception("A submodel type must be provided when loading onnx pipelines.")
|
||||||
|
model_path = Path(config.path)
|
||||||
load_class = self.get_hf_load_class(model_path, submodel_type)
|
load_class = self.get_hf_load_class(model_path, submodel_type)
|
||||||
variant = model_variant.value if model_variant else None
|
repo_variant = getattr(config, "repo_variant", None)
|
||||||
|
variant = repo_variant.value if repo_variant else None
|
||||||
model_path = model_path / submodel_type.value
|
model_path = model_path / submodel_type.value
|
||||||
result: AnyModel = load_class.from_pretrained(
|
result: AnyModel = load_class.from_pretrained(
|
||||||
model_path,
|
model_path,
|
||||||
torch_dtype=self._torch_dtype,
|
torch_dtype=self._torch_dtype,
|
||||||
variant=variant,
|
variant=variant,
|
||||||
) # type: ignore
|
)
|
||||||
return result
|
return result
|
||||||
|
@ -9,17 +9,27 @@ from invokeai.backend.model_manager import (
|
|||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SchedulerPredictionType,
|
SchedulerPredictionType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
from invokeai.backend.model_manager.config import CheckpointConfigBase, MainCheckpointConfig
|
from invokeai.backend.model_manager.config import (
|
||||||
|
CheckpointConfigBase,
|
||||||
|
DiffusersConfigBase,
|
||||||
|
MainCheckpointConfig,
|
||||||
|
ModelVariantType,
|
||||||
|
)
|
||||||
from invokeai.backend.model_manager.convert_ckpt_to_diffusers import convert_ckpt_to_diffusers
|
from invokeai.backend.model_manager.convert_ckpt_to_diffusers import convert_ckpt_to_diffusers
|
||||||
|
|
||||||
from .. import ModelLoaderRegistry
|
from .. import ModelLoaderRegistry
|
||||||
from .generic_diffusers import GenericDiffusersLoader
|
from .generic_diffusers import GenericDiffusersLoader
|
||||||
|
|
||||||
|
VARIANT_TO_IN_CHANNEL_MAP = {
|
||||||
|
ModelVariantType.Normal: 4,
|
||||||
|
ModelVariantType.Depth: 5,
|
||||||
|
ModelVariantType.Inpaint: 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Main, format=ModelFormat.Diffusers)
|
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Main, format=ModelFormat.Diffusers)
|
||||||
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Main, format=ModelFormat.Checkpoint)
|
@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.Main, format=ModelFormat.Checkpoint)
|
||||||
@ -35,14 +45,15 @@ class StableDiffusionDiffusersModel(GenericDiffusersLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
if not submodel_type is not None:
|
if not submodel_type is not None:
|
||||||
raise Exception("A submodel type must be provided when loading main pipelines.")
|
raise Exception("A submodel type must be provided when loading main pipelines.")
|
||||||
|
model_path = Path(config.path)
|
||||||
load_class = self.get_hf_load_class(model_path, submodel_type)
|
load_class = self.get_hf_load_class(model_path, submodel_type)
|
||||||
variant = model_variant.value if model_variant else None
|
repo_variant = config.repo_variant if isinstance(config, DiffusersConfigBase) else None
|
||||||
|
variant = repo_variant.value if repo_variant else None
|
||||||
model_path = model_path / submodel_type.value
|
model_path = model_path / submodel_type.value
|
||||||
try:
|
try:
|
||||||
result: AnyModel = load_class.from_pretrained(
|
result: AnyModel = load_class.from_pretrained(
|
||||||
@ -72,7 +83,7 @@ class StableDiffusionDiffusersModel(GenericDiffusersLoader):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Path) -> Path:
|
def _convert_model(self, config: AnyModelConfig, model_path: Path, output_path: Optional[Path] = None) -> AnyModel:
|
||||||
assert isinstance(config, MainCheckpointConfig)
|
assert isinstance(config, MainCheckpointConfig)
|
||||||
base = config.base
|
base = config.base
|
||||||
|
|
||||||
@ -87,11 +98,12 @@ class StableDiffusionDiffusersModel(GenericDiffusersLoader):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._logger.info(f"Converting {model_path} to diffusers format")
|
self._logger.info(f"Converting {model_path} to diffusers format")
|
||||||
convert_ckpt_to_diffusers(
|
|
||||||
|
loaded_model = convert_ckpt_to_diffusers(
|
||||||
model_path,
|
model_path,
|
||||||
output_path,
|
output_path,
|
||||||
model_type=self.model_base_to_model_type[base],
|
model_type=self.model_base_to_model_type[base],
|
||||||
original_config_file=self._app_config.root_path / config.config_path,
|
original_config_file=self._app_config.legacy_conf_path / config.config_path,
|
||||||
extract_ema=True,
|
extract_ema=True,
|
||||||
from_safetensors=model_path.suffix == ".safetensors",
|
from_safetensors=model_path.suffix == ".safetensors",
|
||||||
precision=self._torch_dtype,
|
precision=self._torch_dtype,
|
||||||
@ -99,5 +111,6 @@ class StableDiffusionDiffusersModel(GenericDiffusersLoader):
|
|||||||
image_size=image_size,
|
image_size=image_size,
|
||||||
upcast_attention=upcast_attention,
|
upcast_attention=upcast_attention,
|
||||||
load_safety_checker=False,
|
load_safety_checker=False,
|
||||||
|
num_in_channels=VARIANT_TO_IN_CHANNEL_MAP[config.variant],
|
||||||
)
|
)
|
||||||
return output_path
|
return loaded_model
|
||||||
|
@ -2,14 +2,13 @@
|
|||||||
"""Class for TI model loading in InvokeAI."""
|
"""Class for TI model loading in InvokeAI."""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
|
|
||||||
from invokeai.backend.model_manager import (
|
from invokeai.backend.model_manager import (
|
||||||
AnyModel,
|
AnyModel,
|
||||||
AnyModelConfig,
|
AnyModelConfig,
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
ModelFormat,
|
ModelFormat,
|
||||||
ModelRepoVariant,
|
|
||||||
ModelType,
|
ModelType,
|
||||||
SubModelType,
|
SubModelType,
|
||||||
)
|
)
|
||||||
@ -27,22 +26,19 @@ class TextualInversionLoader(ModelLoader):
|
|||||||
|
|
||||||
def _load_model(
|
def _load_model(
|
||||||
self,
|
self,
|
||||||
model_path: Path,
|
config: AnyModelConfig,
|
||||||
model_variant: Optional[ModelRepoVariant] = None,
|
|
||||||
submodel_type: Optional[SubModelType] = None,
|
submodel_type: Optional[SubModelType] = None,
|
||||||
) -> AnyModel:
|
) -> AnyModel:
|
||||||
if submodel_type is not None:
|
if submodel_type is not None:
|
||||||
raise ValueError("There are no submodels in a TI model.")
|
raise ValueError("There are no submodels in a TI model.")
|
||||||
model = TextualInversionModelRaw.from_checkpoint(
|
model = TextualInversionModelRaw.from_checkpoint(
|
||||||
file_path=model_path,
|
file_path=config.path,
|
||||||
dtype=self._torch_dtype,
|
dtype=self._torch_dtype,
|
||||||
)
|
)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
# override
|
# override
|
||||||
def _get_model_path(
|
def _get_model_path(self, config: AnyModelConfig) -> Path:
|
||||||
self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None
|
|
||||||
) -> Tuple[Path, AnyModelConfig, Optional[SubModelType]]:
|
|
||||||
model_path = self._app_config.models_path / config.path
|
model_path = self._app_config.models_path / config.path
|
||||||
|
|
||||||
if config.format == ModelFormat.EmbeddingFolder:
|
if config.format == ModelFormat.EmbeddingFolder:
|
||||||
@ -53,4 +49,4 @@ class TextualInversionLoader(ModelLoader):
|
|||||||
if not path.exists():
|
if not path.exists():
|
||||||
raise OSError(f"The embedding file at {path} was not found")
|
raise OSError(f"The embedding file at {path} was not found")
|
||||||
|
|
||||||
return path, config, submodel_type
|
return path
|
||||||
|
@ -44,7 +44,7 @@ class VAELoader(GenericDiffusersLoader):
|
|||||||
raise Exception(f"VAE conversion not supported for model type: {config.base}")
|
raise Exception(f"VAE conversion not supported for model type: {config.base}")
|
||||||
else:
|
else:
|
||||||
assert isinstance(config, CheckpointConfigBase)
|
assert isinstance(config, CheckpointConfigBase)
|
||||||
config_file = self._app_config.root_path / config.config_path
|
config_file = self._app_config.legacy_conf_path / config.config_path
|
||||||
|
|
||||||
if model_path.suffix == ".safetensors":
|
if model_path.suffix == ".safetensors":
|
||||||
checkpoint = safetensors_load_file(model_path, device="cpu")
|
checkpoint = safetensors_load_file(model_path, device="cpu")
|
||||||
|
@ -28,7 +28,7 @@ from .config import (
|
|||||||
)
|
)
|
||||||
from .util.model_util import lora_token_vector_length, read_checkpoint_meta
|
from .util.model_util import lora_token_vector_length, read_checkpoint_meta
|
||||||
|
|
||||||
CkptType = Dict[str, Any]
|
CkptType = Dict[str | int, Any]
|
||||||
|
|
||||||
LEGACY_CONFIGS: Dict[BaseModelType, Dict[ModelVariantType, Union[str, Dict[SchedulerPredictionType, str]]]] = {
|
LEGACY_CONFIGS: Dict[BaseModelType, Dict[ModelVariantType, Union[str, Dict[SchedulerPredictionType, str]]]] = {
|
||||||
BaseModelType.StableDiffusion1: {
|
BaseModelType.StableDiffusion1: {
|
||||||
@ -37,7 +37,6 @@ LEGACY_CONFIGS: Dict[BaseModelType, Dict[ModelVariantType, Union[str, Dict[Sched
|
|||||||
SchedulerPredictionType.VPrediction: "v1-inference-v.yaml",
|
SchedulerPredictionType.VPrediction: "v1-inference-v.yaml",
|
||||||
},
|
},
|
||||||
ModelVariantType.Inpaint: "v1-inpainting-inference.yaml",
|
ModelVariantType.Inpaint: "v1-inpainting-inference.yaml",
|
||||||
ModelVariantType.Depth: "v2-midas-inference.yaml",
|
|
||||||
},
|
},
|
||||||
BaseModelType.StableDiffusion2: {
|
BaseModelType.StableDiffusion2: {
|
||||||
ModelVariantType.Normal: {
|
ModelVariantType.Normal: {
|
||||||
@ -48,6 +47,7 @@ LEGACY_CONFIGS: Dict[BaseModelType, Dict[ModelVariantType, Union[str, Dict[Sched
|
|||||||
SchedulerPredictionType.Epsilon: "v2-inpainting-inference.yaml",
|
SchedulerPredictionType.Epsilon: "v2-inpainting-inference.yaml",
|
||||||
SchedulerPredictionType.VPrediction: "v2-inpainting-inference-v.yaml",
|
SchedulerPredictionType.VPrediction: "v2-inpainting-inference-v.yaml",
|
||||||
},
|
},
|
||||||
|
ModelVariantType.Depth: "v2-midas-inference.yaml",
|
||||||
},
|
},
|
||||||
BaseModelType.StableDiffusionXL: {
|
BaseModelType.StableDiffusionXL: {
|
||||||
ModelVariantType.Normal: "sd_xl_base.yaml",
|
ModelVariantType.Normal: "sd_xl_base.yaml",
|
||||||
@ -219,7 +219,7 @@ class ModelProbe(object):
|
|||||||
ckpt = checkpoint if checkpoint else read_checkpoint_meta(model_path, scan=True)
|
ckpt = checkpoint if checkpoint else read_checkpoint_meta(model_path, scan=True)
|
||||||
ckpt = ckpt.get("state_dict", ckpt)
|
ckpt = ckpt.get("state_dict", ckpt)
|
||||||
|
|
||||||
for key in ckpt.keys():
|
for key in [str(k) for k in ckpt.keys()]:
|
||||||
if any(key.startswith(v) for v in {"cond_stage_model.", "first_stage_model.", "model.diffusion_model."}):
|
if any(key.startswith(v) for v in {"cond_stage_model.", "first_stage_model.", "model.diffusion_model."}):
|
||||||
return ModelType.Main
|
return ModelType.Main
|
||||||
elif any(key.startswith(v) for v in {"encoder.conv_in", "decoder.conv_in"}):
|
elif any(key.startswith(v) for v in {"encoder.conv_in", "decoder.conv_in"}):
|
||||||
@ -227,7 +227,7 @@ class ModelProbe(object):
|
|||||||
elif any(key.startswith(v) for v in {"lora_te_", "lora_unet_"}):
|
elif any(key.startswith(v) for v in {"lora_te_", "lora_unet_"}):
|
||||||
return ModelType.LoRA
|
return ModelType.LoRA
|
||||||
elif any(key.endswith(v) for v in {"to_k_lora.up.weight", "to_q_lora.down.weight"}):
|
elif any(key.endswith(v) for v in {"to_k_lora.up.weight", "to_q_lora.down.weight"}):
|
||||||
return ModelType.Lora
|
return ModelType.LoRA
|
||||||
elif any(key.startswith(v) for v in {"controlnet", "control_model", "input_blocks"}):
|
elif any(key.startswith(v) for v in {"controlnet", "control_model", "input_blocks"}):
|
||||||
return ModelType.ControlNet
|
return ModelType.ControlNet
|
||||||
elif key in {"emb_params", "string_to_param"}:
|
elif key in {"emb_params", "string_to_param"}:
|
||||||
|
@ -48,9 +48,8 @@ class ModelSearch:
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
search = ModelSearch()
|
search = ModelSearch()
|
||||||
search.model_found = lambda path : 'anime' in path.as_posix()
|
search.on_model_found = lambda path : 'anime' in path.as_posix()
|
||||||
found = search.list_models(['/tmp/models1','/tmp/models2'])
|
found = search.search(Path('/tmp/models1'))
|
||||||
# returns all models that have 'anime' in the path
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -1,149 +1,156 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from invokeai.backend.model_manager.config import BaseModelType, ModelType
|
from invokeai.backend.model_manager.config import BaseModelType, ModelType
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class StarterModelWithoutDependencies(BaseModel):
|
||||||
class StarterModel:
|
|
||||||
description: str
|
description: str
|
||||||
source: str
|
source: str
|
||||||
name: str
|
name: str
|
||||||
base: BaseModelType
|
base: BaseModelType
|
||||||
type: ModelType
|
type: ModelType
|
||||||
# Optional list of model source dependencies that need to be installed before this model can be used
|
|
||||||
dependencies: Optional[list[str]] = None
|
|
||||||
is_installed: bool = False
|
is_installed: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class StarterModel(StarterModelWithoutDependencies):
|
||||||
|
# Optional list of model source dependencies that need to be installed before this model can be used
|
||||||
|
dependencies: Optional[list[StarterModelWithoutDependencies]] = None
|
||||||
|
|
||||||
|
|
||||||
|
sdxl_fp16_vae_fix = StarterModel(
|
||||||
|
name="sdxl-vae-fp16-fix",
|
||||||
|
base=BaseModelType.StableDiffusionXL,
|
||||||
|
source="madebyollin/sdxl-vae-fp16-fix",
|
||||||
|
description="SDXL VAE that works with FP16.",
|
||||||
|
type=ModelType.VAE,
|
||||||
|
)
|
||||||
|
|
||||||
|
ip_adapter_sd_image_encoder = StarterModel(
|
||||||
|
name="IP Adapter SD1.5 Image Encoder",
|
||||||
|
base=BaseModelType.StableDiffusion1,
|
||||||
|
source="InvokeAI/ip_adapter_sd_image_encoder",
|
||||||
|
description="IP Adapter SD Image Encoder",
|
||||||
|
type=ModelType.CLIPVision,
|
||||||
|
)
|
||||||
|
|
||||||
|
ip_adapter_sdxl_image_encoder = StarterModel(
|
||||||
|
name="IP Adapter SDXL Image Encoder",
|
||||||
|
base=BaseModelType.StableDiffusionXL,
|
||||||
|
source="InvokeAI/ip_adapter_sdxl_image_encoder",
|
||||||
|
description="IP Adapter SDXL Image Encoder",
|
||||||
|
type=ModelType.CLIPVision,
|
||||||
|
)
|
||||||
|
|
||||||
|
cyberrealistic_negative = StarterModel(
|
||||||
|
name="CyberRealistic Negative v3",
|
||||||
|
base=BaseModelType.StableDiffusion1,
|
||||||
|
source="https://huggingface.co/cyberdelia/CyberRealistic_Negative/resolve/main/CyberRealistic_Negative_v3.pt",
|
||||||
|
description="Negative embedding specifically for use with CyberRealistic.",
|
||||||
|
type=ModelType.TextualInversion,
|
||||||
|
)
|
||||||
|
|
||||||
# List of starter models, displayed on the frontend.
|
# List of starter models, displayed on the frontend.
|
||||||
# The order/sort of this list is not changed by the frontend - set it how you want it here.
|
# The order/sort of this list is not changed by the frontend - set it how you want it here.
|
||||||
STARTER_MODELS: list[StarterModel] = [
|
STARTER_MODELS: list[StarterModel] = [
|
||||||
# region: Main
|
# region: Main
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="SD 1.5 (base)",
|
name="CyberRealistic v4.1",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusion1,
|
||||||
source="runwayml/stable-diffusion-v1-5",
|
source="https://huggingface.co/cyberdelia/CyberRealistic/resolve/main/CyberRealistic_V4.1_FP16.safetensors",
|
||||||
description="Stable Diffusion version 1.5 diffusers model (4.27 GB)",
|
description="Photorealistic model. See other variants in HF repo 'cyberdelia/CyberRealistic'.",
|
||||||
|
type=ModelType.Main,
|
||||||
|
dependencies=[cyberrealistic_negative],
|
||||||
|
),
|
||||||
|
StarterModel(
|
||||||
|
name="ReV Animated",
|
||||||
|
base=BaseModelType.StableDiffusion1,
|
||||||
|
source="stablediffusionapi/rev-animated",
|
||||||
|
description="Fantasy and anime style images.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="SD 1.5 (inpainting)",
|
name="Dreamshaper 8",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusion1,
|
||||||
source="runwayml/stable-diffusion-inpainting",
|
source="Lykon/dreamshaper-8",
|
||||||
description="RunwayML SD 1.5 model optimized for inpainting, diffusers version (4.27 GB)",
|
description="Popular versatile model.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="Analog Diffusion",
|
name="Dreamshaper 8 (inpainting)",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusion1,
|
||||||
source="wavymulder/Analog-Diffusion",
|
source="Lykon/dreamshaper-8-inpainting",
|
||||||
description="An SD-1.5 model trained on diverse analog photographs (2.13 GB)",
|
description="Inpainting version of Dreamshaper 8.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="Deliberate v5",
|
name="Deliberate v5",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusion1,
|
||||||
source="https://huggingface.co/XpucT/Deliberate/resolve/main/Deliberate_v5.safetensors",
|
source="https://huggingface.co/XpucT/Deliberate/resolve/main/Deliberate_v5.safetensors",
|
||||||
description="Versatile model that produces detailed images up to 768px (4.27 GB)",
|
description="Popular versatile model",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="Dungeons and Diffusion",
|
name="Deliberate v5 (inpainting)",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusion1,
|
||||||
source="0xJustin/Dungeons-and-Diffusion",
|
source="https://huggingface.co/XpucT/Deliberate/resolve/main/Deliberate_v5-inpainting.safetensors",
|
||||||
description="Dungeons & Dragons characters (2.13 GB)",
|
description="Inpainting version of Deliberate v5.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="dreamlike photoreal v2",
|
name="Juggernaut XL v9",
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="dreamlike-art/dreamlike-photoreal-2.0",
|
|
||||||
description="A photorealistic model trained on 768 pixel images based on SD 1.5 (2.13 GB)",
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="Inkpunk Diffusion",
|
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="Envvi/Inkpunk-Diffusion",
|
|
||||||
description='Stylized illustrations inspired by Gorillaz, FLCL and Shinkawa; prompt with "nvinkpunk" (4.27 GB)',
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="OpenJourney",
|
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="prompthero/openjourney",
|
|
||||||
description='An SD 1.5 model fine tuned on Midjourney; prompt with "mdjrny-v4 style" (2.13 GB)',
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="seek.art MEGA",
|
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="coreco/seek.art_MEGA",
|
|
||||||
description='A general use SD-1.5 "anything" model that supports multiple styles (2.1 GB)',
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="TrinArt v2",
|
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="naclbit/trinart_stable_diffusion_v2",
|
|
||||||
description="An SD-1.5 model finetuned with ~40K assorted high resolution manga/anime-style images (2.13 GB)",
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="SD 2.1 (base)",
|
|
||||||
base=BaseModelType.StableDiffusion2,
|
|
||||||
source="stabilityai/stable-diffusion-2-1",
|
|
||||||
description="Stable Diffusion version 2.1 diffusers model, trained on 768 pixel images (5.21 GB)",
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="SD 2.0 (inpainting)",
|
|
||||||
base=BaseModelType.StableDiffusion2,
|
|
||||||
source="stabilityai/stable-diffusion-2-inpainting",
|
|
||||||
description="Stable Diffusion version 2.0 inpainting model (5.21 GB)",
|
|
||||||
type=ModelType.Main,
|
|
||||||
),
|
|
||||||
StarterModel(
|
|
||||||
name="SDXL (base)",
|
|
||||||
base=BaseModelType.StableDiffusionXL,
|
base=BaseModelType.StableDiffusionXL,
|
||||||
source="stabilityai/stable-diffusion-xl-base-1.0",
|
source="RunDiffusion/Juggernaut-XL-v9",
|
||||||
description="Stable Diffusion XL base model (12 GB)",
|
description="Photograph-focused model.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
|
dependencies=[sdxl_fp16_vae_fix],
|
||||||
|
),
|
||||||
|
StarterModel(
|
||||||
|
name="Dreamshaper XL v2 Turbo",
|
||||||
|
base=BaseModelType.StableDiffusionXL,
|
||||||
|
source="Lykon/dreamshaper-xl-v2-turbo",
|
||||||
|
description="For turbo, use CFG Scale 2, 4-8 steps, DPM++ SDE Karras. For non-turbo, use CFG Scale 6, 20-40 steps, DPM++ 2M SDE Karras.",
|
||||||
|
type=ModelType.Main,
|
||||||
|
dependencies=[sdxl_fp16_vae_fix],
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="SDXL Refiner",
|
name="SDXL Refiner",
|
||||||
base=BaseModelType.StableDiffusionXLRefiner,
|
base=BaseModelType.StableDiffusionXLRefiner,
|
||||||
source="stabilityai/stable-diffusion-xl-refiner-1.0",
|
source="stabilityai/stable-diffusion-xl-refiner-1.0",
|
||||||
description="Stable Diffusion XL refiner model (12 GB)",
|
description="The OG Stable Diffusion XL refiner model.",
|
||||||
type=ModelType.Main,
|
type=ModelType.Main,
|
||||||
|
dependencies=[sdxl_fp16_vae_fix],
|
||||||
),
|
),
|
||||||
# endregion
|
# endregion
|
||||||
# region VAE
|
# region VAE
|
||||||
StarterModel(
|
sdxl_fp16_vae_fix,
|
||||||
name="sdxl-vae-fp16-fix",
|
|
||||||
base=BaseModelType.StableDiffusionXL,
|
|
||||||
source="madebyollin/sdxl-vae-fp16-fix",
|
|
||||||
description="Version of the SDXL-1.0 VAE that works in half precision mode",
|
|
||||||
type=ModelType.VAE,
|
|
||||||
),
|
|
||||||
# endregion
|
# endregion
|
||||||
# region LoRA
|
# region LoRA
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="FlatColor",
|
name="Alien Style",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusionXL,
|
||||||
source="https://civitai.com/models/6433/loraflatcolor",
|
source="https://huggingface.co/RalFinger/alien-style-lora-sdxl/resolve/main/alienzkin-sdxl.safetensors",
|
||||||
description="A LoRA that generates scenery using solid blocks of color",
|
description="Futuristic, intricate alien styles. Trigger with 'alienzkin'.",
|
||||||
type=ModelType.LoRA,
|
type=ModelType.LoRA,
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="Ink scenery",
|
name="Noodles Style",
|
||||||
base=BaseModelType.StableDiffusion1,
|
base=BaseModelType.StableDiffusionXL,
|
||||||
source="https://civitai.com/api/download/models/83390",
|
source="https://huggingface.co/RalFinger/noodles-lora-sdxl/resolve/main/noodlez-sdxl.safetensors",
|
||||||
description="Generate india ink-like landscapes",
|
description="Never-ending, no-holds-barred, noodle nightmare. Trigger with 'noodlez'.",
|
||||||
type=ModelType.LoRA,
|
type=ModelType.LoRA,
|
||||||
),
|
),
|
||||||
# endregion
|
# endregion
|
||||||
|
# region TI
|
||||||
|
StarterModel(
|
||||||
|
name="EasyNegative",
|
||||||
|
base=BaseModelType.StableDiffusion1,
|
||||||
|
source="https://huggingface.co/embed/EasyNegative/resolve/main/EasyNegative.safetensors",
|
||||||
|
description="A textual inversion to use in the negative prompt to reduce bad anatomy",
|
||||||
|
type=ModelType.TextualInversion,
|
||||||
|
),
|
||||||
|
# endregion
|
||||||
# region IP Adapter
|
# region IP Adapter
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="IP Adapter",
|
name="IP Adapter",
|
||||||
@ -151,7 +158,7 @@ STARTER_MODELS: list[StarterModel] = [
|
|||||||
source="InvokeAI/ip_adapter_sd15",
|
source="InvokeAI/ip_adapter_sd15",
|
||||||
description="IP-Adapter for SD 1.5 models",
|
description="IP-Adapter for SD 1.5 models",
|
||||||
type=ModelType.IPAdapter,
|
type=ModelType.IPAdapter,
|
||||||
dependencies=["InvokeAI/ip_adapter_sd_image_encoder"],
|
dependencies=[ip_adapter_sd_image_encoder],
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="IP Adapter Plus",
|
name="IP Adapter Plus",
|
||||||
@ -159,7 +166,7 @@ STARTER_MODELS: list[StarterModel] = [
|
|||||||
source="InvokeAI/ip_adapter_plus_sd15",
|
source="InvokeAI/ip_adapter_plus_sd15",
|
||||||
description="Refined IP-Adapter for SD 1.5 models",
|
description="Refined IP-Adapter for SD 1.5 models",
|
||||||
type=ModelType.IPAdapter,
|
type=ModelType.IPAdapter,
|
||||||
dependencies=["InvokeAI/ip_adapter_sd_image_encoder"],
|
dependencies=[ip_adapter_sd_image_encoder],
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="IP Adapter Plus Face",
|
name="IP Adapter Plus Face",
|
||||||
@ -167,7 +174,7 @@ STARTER_MODELS: list[StarterModel] = [
|
|||||||
source="InvokeAI/ip_adapter_plus_face_sd15",
|
source="InvokeAI/ip_adapter_plus_face_sd15",
|
||||||
description="Refined IP-Adapter for SD 1.5 models, adapted for faces",
|
description="Refined IP-Adapter for SD 1.5 models, adapted for faces",
|
||||||
type=ModelType.IPAdapter,
|
type=ModelType.IPAdapter,
|
||||||
dependencies=["InvokeAI/ip_adapter_sd_image_encoder"],
|
dependencies=[ip_adapter_sd_image_encoder],
|
||||||
),
|
),
|
||||||
StarterModel(
|
StarterModel(
|
||||||
name="IP Adapter SDXL",
|
name="IP Adapter SDXL",
|
||||||
@ -175,7 +182,7 @@ STARTER_MODELS: list[StarterModel] = [
|
|||||||
source="InvokeAI/ip_adapter_sdxl",
|
source="InvokeAI/ip_adapter_sdxl",
|
||||||
description="IP-Adapter for SDXL models",
|
description="IP-Adapter for SDXL models",
|
||||||
type=ModelType.IPAdapter,
|
type=ModelType.IPAdapter,
|
||||||
dependencies=["InvokeAI/ip_adapter_sdxl_image_encoder"],
|
dependencies=[ip_adapter_sdxl_image_encoder],
|
||||||
),
|
),
|
||||||
# endregion
|
# endregion
|
||||||
# region ControlNet
|
# region ControlNet
|
||||||
@ -378,15 +385,6 @@ STARTER_MODELS: list[StarterModel] = [
|
|||||||
type=ModelType.T2IAdapter,
|
type=ModelType.T2IAdapter,
|
||||||
),
|
),
|
||||||
# endregion
|
# endregion
|
||||||
# region TI
|
|
||||||
StarterModel(
|
|
||||||
name="EasyNegative",
|
|
||||||
base=BaseModelType.StableDiffusion1,
|
|
||||||
source="https://huggingface.co/embed/EasyNegative/resolve/main/EasyNegative.safetensors",
|
|
||||||
description="A textual inversion to use in the negative prompt to reduce bad anatomy",
|
|
||||||
type=ModelType.TextualInversion,
|
|
||||||
),
|
|
||||||
# endregion
|
|
||||||
]
|
]
|
||||||
|
|
||||||
assert len(STARTER_MODELS) == len({m.source for m in STARTER_MODELS}), "Duplicate starter models"
|
assert len(STARTER_MODELS) == len({m.source for m in STARTER_MODELS}), "Duplicate starter models"
|
||||||
|
@ -28,6 +28,10 @@ def _conv_forward_asymmetric(self, input, weight, bias):
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def set_seamless(model: Union[UNet2DConditionModel, AutoencoderKL, AutoencoderTiny], seamless_axes: List[str]):
|
def set_seamless(model: Union[UNet2DConditionModel, AutoencoderKL, AutoencoderTiny], seamless_axes: List[str]):
|
||||||
|
if not seamless_axes:
|
||||||
|
yield
|
||||||
|
return
|
||||||
|
|
||||||
# Callable: (input: Tensor, weight: Tensor, bias: Optional[Tensor]) -> Tensor
|
# Callable: (input: Tensor, weight: Tensor, bias: Optional[Tensor]) -> Tensor
|
||||||
to_restore: list[tuple[nn.Conv2d | nn.ConvTranspose2d, Callable]] = []
|
to_restore: list[tuple[nn.Conv2d | nn.ConvTranspose2d, Callable]] = []
|
||||||
try:
|
try:
|
||||||
|
@ -31,6 +31,9 @@ class ConfigMapper:
|
|||||||
YAML_FILENAME = "invokeai.yaml"
|
YAML_FILENAME = "invokeai.yaml"
|
||||||
DATABASE_FILENAME = "invokeai.db"
|
DATABASE_FILENAME = "invokeai.db"
|
||||||
|
|
||||||
|
DEFAULT_OUTDIR = "outputs"
|
||||||
|
DEFAULT_DB_DIR = "databases"
|
||||||
|
|
||||||
database_path = None
|
database_path = None
|
||||||
database_backup_dir = None
|
database_backup_dir = None
|
||||||
outputs_path = None
|
outputs_path = None
|
||||||
@ -50,12 +53,18 @@ class ConfigMapper:
|
|||||||
def __load_from_root_config(self, invoke_root):
|
def __load_from_root_config(self, invoke_root):
|
||||||
"""Validate a yaml path exists, confirm the user wants to use it and load config."""
|
"""Validate a yaml path exists, confirm the user wants to use it and load config."""
|
||||||
yaml_path = os.path.join(invoke_root, self.YAML_FILENAME)
|
yaml_path = os.path.join(invoke_root, self.YAML_FILENAME)
|
||||||
|
if not os.path.exists(yaml_path):
|
||||||
|
print(f"Unable to find invokeai.yaml at {yaml_path}!")
|
||||||
|
return False
|
||||||
if os.path.exists(yaml_path):
|
if os.path.exists(yaml_path):
|
||||||
db_dir, outdir = self.__load_paths_from_yaml_file(yaml_path)
|
db_dir, outdir = self.__load_paths_from_yaml_file(yaml_path)
|
||||||
|
|
||||||
if db_dir is None or outdir is None:
|
if db_dir is None:
|
||||||
print("The invokeai.yaml file was found but is missing the db_dir and/or outdir setting!")
|
db_dir = self.DEFAULT_DB_DIR
|
||||||
return False
|
print(f"The invokeai.yaml file was found but is missing the db_dir setting! Defaulting to {db_dir}")
|
||||||
|
if outdir is None:
|
||||||
|
outdir = self.DEFAULT_OUTDIR
|
||||||
|
print(f"The invokeai.yaml file was found but is missing the outdir setting! Defaulting to {outdir}")
|
||||||
|
|
||||||
if os.path.isabs(db_dir):
|
if os.path.isabs(db_dir):
|
||||||
self.database_path = os.path.join(db_dir, self.DATABASE_FILENAME)
|
self.database_path = os.path.join(db_dir, self.DATABASE_FILENAME)
|
||||||
|
@ -28,6 +28,11 @@ def choose_torch_device() -> torch.device:
|
|||||||
return torch.device(config.device)
|
return torch.device(config.device)
|
||||||
|
|
||||||
|
|
||||||
|
def get_torch_device_name() -> str:
|
||||||
|
device = choose_torch_device()
|
||||||
|
return torch.cuda.get_device_name(device) if device.type == "cuda" else device.type.upper()
|
||||||
|
|
||||||
|
|
||||||
# We are in transition here from using a single global AppConfig to allowing multiple
|
# We are in transition here from using a single global AppConfig to allowing multiple
|
||||||
# configurations. It is strongly recommended to pass the app_config to this function.
|
# configurations. It is strongly recommended to pass the app_config to this function.
|
||||||
def choose_precision(
|
def choose_precision(
|
||||||
|
74
invokeai/configs/stable-diffusion/v2-midas-inference.yaml
Normal file
74
invokeai/configs/stable-diffusion/v2-midas-inference.yaml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
model:
|
||||||
|
base_learning_rate: 5.0e-07
|
||||||
|
target: ldm.models.diffusion.ddpm.LatentDepth2ImageDiffusion
|
||||||
|
params:
|
||||||
|
linear_start: 0.00085
|
||||||
|
linear_end: 0.0120
|
||||||
|
num_timesteps_cond: 1
|
||||||
|
log_every_t: 200
|
||||||
|
timesteps: 1000
|
||||||
|
first_stage_key: "jpg"
|
||||||
|
cond_stage_key: "txt"
|
||||||
|
image_size: 64
|
||||||
|
channels: 4
|
||||||
|
cond_stage_trainable: false
|
||||||
|
conditioning_key: hybrid
|
||||||
|
scale_factor: 0.18215
|
||||||
|
monitor: val/loss_simple_ema
|
||||||
|
finetune_keys: null
|
||||||
|
use_ema: False
|
||||||
|
|
||||||
|
depth_stage_config:
|
||||||
|
target: ldm.modules.midas.api.MiDaSInference
|
||||||
|
params:
|
||||||
|
model_type: "dpt_hybrid"
|
||||||
|
|
||||||
|
unet_config:
|
||||||
|
target: ldm.modules.diffusionmodules.openaimodel.UNetModel
|
||||||
|
params:
|
||||||
|
use_checkpoint: True
|
||||||
|
image_size: 32 # unused
|
||||||
|
in_channels: 5
|
||||||
|
out_channels: 4
|
||||||
|
model_channels: 320
|
||||||
|
attention_resolutions: [ 4, 2, 1 ]
|
||||||
|
num_res_blocks: 2
|
||||||
|
channel_mult: [ 1, 2, 4, 4 ]
|
||||||
|
num_head_channels: 64 # need to fix for flash-attn
|
||||||
|
use_spatial_transformer: True
|
||||||
|
use_linear_in_transformer: True
|
||||||
|
transformer_depth: 1
|
||||||
|
context_dim: 1024
|
||||||
|
legacy: False
|
||||||
|
|
||||||
|
first_stage_config:
|
||||||
|
target: ldm.models.autoencoder.AutoencoderKL
|
||||||
|
params:
|
||||||
|
embed_dim: 4
|
||||||
|
monitor: val/rec_loss
|
||||||
|
ddconfig:
|
||||||
|
#attn_type: "vanilla-xformers"
|
||||||
|
double_z: true
|
||||||
|
z_channels: 4
|
||||||
|
resolution: 256
|
||||||
|
in_channels: 3
|
||||||
|
out_ch: 3
|
||||||
|
ch: 128
|
||||||
|
ch_mult:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 4
|
||||||
|
- 4
|
||||||
|
num_res_blocks: 2
|
||||||
|
attn_resolutions: [ ]
|
||||||
|
dropout: 0.0
|
||||||
|
lossconfig:
|
||||||
|
target: torch.nn.Identity
|
||||||
|
|
||||||
|
cond_stage_config:
|
||||||
|
target: ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder
|
||||||
|
params:
|
||||||
|
freeze: True
|
||||||
|
layer: "penultimate"
|
||||||
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
|||||||
"""
|
|
||||||
Minimalist updater script. Prompts user for the tag or branch to update to and runs
|
|
||||||
pip install <path_to_git_source>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
from importlib.metadata import PackageNotFoundError, distribution, distributions
|
|
||||||
|
|
||||||
import psutil
|
|
||||||
import requests
|
|
||||||
from rich import box, print
|
|
||||||
from rich.console import Console, group
|
|
||||||
from rich.panel import Panel
|
|
||||||
from rich.prompt import Confirm, Prompt
|
|
||||||
from rich.style import Style
|
|
||||||
|
|
||||||
from invokeai.version import __version__
|
|
||||||
|
|
||||||
INVOKE_AI_SRC = "https://github.com/invoke-ai/InvokeAI/archive"
|
|
||||||
INVOKE_AI_TAG = "https://github.com/invoke-ai/InvokeAI/archive/refs/tags"
|
|
||||||
INVOKE_AI_BRANCH = "https://github.com/invoke-ai/InvokeAI/archive/refs/heads"
|
|
||||||
INVOKE_AI_REL = "https://api.github.com/repos/invoke-ai/InvokeAI/releases"
|
|
||||||
|
|
||||||
OS = platform.uname().system
|
|
||||||
ARCH = platform.uname().machine
|
|
||||||
|
|
||||||
if OS == "Windows":
|
|
||||||
# Windows terminals look better without a background colour
|
|
||||||
console = Console(style=Style(color="grey74"))
|
|
||||||
else:
|
|
||||||
console = Console(style=Style(color="grey74", bgcolor="grey19"))
|
|
||||||
|
|
||||||
|
|
||||||
def invokeai_is_running() -> bool:
|
|
||||||
for p in psutil.process_iter():
|
|
||||||
try:
|
|
||||||
cmdline = p.cmdline()
|
|
||||||
matches = [x for x in cmdline if x.endswith(("invokeai", "invokeai.exe"))]
|
|
||||||
if matches:
|
|
||||||
print(
|
|
||||||
f":exclamation: [bold red]An InvokeAI instance appears to be running as process {p.pid}[/red bold]"
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
except (psutil.AccessDenied, psutil.NoSuchProcess):
|
|
||||||
continue
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_pypi_versions():
|
|
||||||
url = "https://pypi.org/pypi/invokeai/json"
|
|
||||||
try:
|
|
||||||
data = requests.get(url).json()
|
|
||||||
except Exception:
|
|
||||||
raise Exception("Unable to fetch version information from PyPi")
|
|
||||||
|
|
||||||
versions = list(data["releases"].keys())
|
|
||||||
versions.sort(key=LooseVersion, reverse=True)
|
|
||||||
latest_version = [v for v in versions if "rc" not in v][0]
|
|
||||||
latest_release_candidate = [v for v in versions if "rc" in v][0]
|
|
||||||
return latest_version, latest_release_candidate, versions
|
|
||||||
|
|
||||||
|
|
||||||
def get_torch_extra_index_url() -> str | None:
|
|
||||||
"""
|
|
||||||
Determine torch wheel source URL and optional modules based on the user's OS.
|
|
||||||
"""
|
|
||||||
|
|
||||||
resolved_url = None
|
|
||||||
|
|
||||||
# In all other cases (like MacOS (MPS) or Linux+CUDA), there is no need to specify the extra index URL.
|
|
||||||
torch_package_urls = {
|
|
||||||
"windows_cuda": "https://download.pytorch.org/whl/cu121",
|
|
||||||
"linux_rocm": "https://download.pytorch.org/whl/rocm5.6",
|
|
||||||
"linux_cpu": "https://download.pytorch.org/whl/cpu",
|
|
||||||
}
|
|
||||||
|
|
||||||
nvidia_packages_present = (
|
|
||||||
len([d.metadata["Name"] for d in distributions() if d.metadata["Name"].startswith("nvidia")]) > 0
|
|
||||||
)
|
|
||||||
device = "cuda" if nvidia_packages_present else None
|
|
||||||
manual_gpu_selection_prompt = (
|
|
||||||
"[bold]We tried and failed to guess your GPU capabilities[/] :thinking_face:. Please select the GPU type:"
|
|
||||||
)
|
|
||||||
|
|
||||||
if OS == "Linux":
|
|
||||||
if not device:
|
|
||||||
# do we even need to offer a CPU-only install option?
|
|
||||||
print(manual_gpu_selection_prompt)
|
|
||||||
print("1: NVIDIA (CUDA)")
|
|
||||||
print("2: AMD (ROCm)")
|
|
||||||
print("3: No GPU - CPU only")
|
|
||||||
answer = Prompt.ask("Choice:", choices=["1", "2", "3"], default="1")
|
|
||||||
match answer:
|
|
||||||
case "1":
|
|
||||||
device = "cuda"
|
|
||||||
case "2":
|
|
||||||
device = "rocm"
|
|
||||||
case "3":
|
|
||||||
device = "cpu"
|
|
||||||
|
|
||||||
if device != "cuda":
|
|
||||||
resolved_url = torch_package_urls[f"linux_{device}"]
|
|
||||||
|
|
||||||
if OS == "Windows":
|
|
||||||
if not device:
|
|
||||||
print(manual_gpu_selection_prompt)
|
|
||||||
print("1: NVIDIA (CUDA)")
|
|
||||||
print("2: No GPU - CPU only")
|
|
||||||
answer = Prompt.ask("Your choice:", choices=["1", "2"], default="1")
|
|
||||||
match answer:
|
|
||||||
case "1":
|
|
||||||
device = "cuda"
|
|
||||||
case "2":
|
|
||||||
device = "cpu"
|
|
||||||
|
|
||||||
if device == "cuda":
|
|
||||||
resolved_url = torch_package_urls[f"windows_{device}"]
|
|
||||||
|
|
||||||
return resolved_url
|
|
||||||
|
|
||||||
|
|
||||||
def welcome(latest_release: str, latest_prerelease: str):
|
|
||||||
@group()
|
|
||||||
def text():
|
|
||||||
yield f"InvokeAI Version: [bold yellow]{__version__}"
|
|
||||||
yield ""
|
|
||||||
yield "This script will update InvokeAI to the latest release, or to the development version of your choice."
|
|
||||||
yield ""
|
|
||||||
yield "[bold yellow]Options:"
|
|
||||||
yield f"""[1] Update to the latest [bold]official release[/bold] ([italic]{latest_release}[/italic])
|
|
||||||
[2] Update to the latest [bold]pre-release[/bold] (may be buggy, database backups are recommended before installation; caveat emptor!) ([italic]{latest_prerelease}[/italic])
|
|
||||||
[3] Manually enter the [bold]version[/bold] you wish to update to"""
|
|
||||||
|
|
||||||
console.rule()
|
|
||||||
print(
|
|
||||||
Panel(
|
|
||||||
title="[bold wheat1]InvokeAI Updater",
|
|
||||||
renderable=text(),
|
|
||||||
box=box.DOUBLE,
|
|
||||||
expand=True,
|
|
||||||
padding=(1, 2),
|
|
||||||
style=Style(bgcolor="grey23", color="orange1"),
|
|
||||||
subtitle=f"[bold grey39]{OS}-{ARCH}",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
console.line()
|
|
||||||
|
|
||||||
|
|
||||||
def get_extras():
|
|
||||||
try:
|
|
||||||
distribution("xformers")
|
|
||||||
extras = "[xformers]"
|
|
||||||
except PackageNotFoundError:
|
|
||||||
extras = ""
|
|
||||||
return extras
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if invokeai_is_running():
|
|
||||||
print(":exclamation: [bold red]Please terminate all running instances of InvokeAI before updating.[/red bold]")
|
|
||||||
input("Press any key to continue...")
|
|
||||||
return
|
|
||||||
|
|
||||||
latest_release, latest_prerelease, versions = get_pypi_versions()
|
|
||||||
|
|
||||||
welcome(latest_release, latest_prerelease)
|
|
||||||
|
|
||||||
release = latest_release
|
|
||||||
choice = Prompt.ask("Choice:", choices=["1", "2", "3"], default="1")
|
|
||||||
|
|
||||||
if choice == "1":
|
|
||||||
release = latest_release
|
|
||||||
elif choice == "2":
|
|
||||||
release = latest_prerelease
|
|
||||||
elif choice == "3":
|
|
||||||
while True:
|
|
||||||
release = Prompt.ask("Enter an InvokeAI version")
|
|
||||||
release.strip()
|
|
||||||
if release in versions:
|
|
||||||
break
|
|
||||||
print(f":exclamation: [bold red]'{release}' is not a recognized InvokeAI release.[/red bold]")
|
|
||||||
|
|
||||||
extras = get_extras()
|
|
||||||
|
|
||||||
console.line()
|
|
||||||
force_reinstall = Confirm.ask(
|
|
||||||
"[bold]Force reinstallation of all dependencies?[/] This [i]may[/] help fix a broken upgrade, but is usually not necessary.",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
console.line()
|
|
||||||
flags = []
|
|
||||||
if (index_url := get_torch_extra_index_url()) is not None:
|
|
||||||
flags.append(f"--extra-index-url {index_url}")
|
|
||||||
if force_reinstall:
|
|
||||||
flags.append("--force-reinstall")
|
|
||||||
flags = " ".join(flags)
|
|
||||||
|
|
||||||
print(f":crossed_fingers: Upgrading to [yellow]{release}[/yellow]")
|
|
||||||
cmd = f'pip install "invokeai{extras}=={release}" --use-pep517 --upgrade {flags}'
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("")
|
|
||||||
if os.system(cmd) == 0:
|
|
||||||
print(":heavy_check_mark: Upgrade successful")
|
|
||||||
else:
|
|
||||||
print(":exclamation: [bold red]Upgrade failed[/red bold]")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
main()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
@ -6,22 +6,10 @@ const config: KnipConfig = {
|
|||||||
'src/app/store/middleware/debugLoggerMiddleware.ts',
|
'src/app/store/middleware/debugLoggerMiddleware.ts',
|
||||||
// Autogenerated types - shouldn't ever touch these
|
// Autogenerated types - shouldn't ever touch these
|
||||||
'src/services/api/schema.ts',
|
'src/services/api/schema.ts',
|
||||||
|
'src/features/nodes/types/v1/**',
|
||||||
|
'src/features/nodes/types/v2/**',
|
||||||
],
|
],
|
||||||
ignoreBinaries: ['only-allow'],
|
ignoreBinaries: ['only-allow'],
|
||||||
rules: {
|
|
||||||
files: 'warn',
|
|
||||||
dependencies: 'warn',
|
|
||||||
unlisted: 'warn',
|
|
||||||
binaries: 'warn',
|
|
||||||
unresolved: 'warn',
|
|
||||||
exports: 'warn',
|
|
||||||
types: 'warn',
|
|
||||||
nsExports: 'warn',
|
|
||||||
nsTypes: 'warn',
|
|
||||||
enumMembers: 'warn',
|
|
||||||
classMembers: 'warn',
|
|
||||||
duplicates: 'warn',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"build": "pnpm run lint && vite build",
|
"build": "pnpm run lint && vite build",
|
||||||
"typegen": "node scripts/typegen.js",
|
"typegen": "node scripts/typegen.js",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint:knip": "knip",
|
"lint:knip": "knip --tags=-@knipignore",
|
||||||
"lint:dpdm": "dpdm --no-warning --no-tree --transform --exit-code circular:1 src/main.tsx",
|
"lint:dpdm": "dpdm --no-warning --no-tree --transform --exit-code circular:1 src/main.tsx",
|
||||||
"lint:eslint": "eslint --max-warnings=0 .",
|
"lint:eslint": "eslint --max-warnings=0 .",
|
||||||
"lint:prettier": "prettier --check .",
|
"lint:prettier": "prettier --check .",
|
||||||
@ -52,56 +52,56 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/react-use-size": "^2.1.0",
|
"@chakra-ui/react-use-size": "^2.1.0",
|
||||||
"@dagrejs/graphlib": "^2.1.13",
|
"@dagrejs/graphlib": "^2.2.1",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@fontsource-variable/inter": "^5.0.16",
|
"@fontsource-variable/inter": "^5.0.17",
|
||||||
"@invoke-ai/ui-library": "^0.0.21",
|
"@invoke-ai/ui-library": "^0.0.21",
|
||||||
"@nanostores/react": "^0.7.2",
|
"@nanostores/react": "^0.7.2",
|
||||||
"@reduxjs/toolkit": "2.2.1",
|
"@reduxjs/toolkit": "2.2.2",
|
||||||
"@roarr/browser-log-writer": "^1.3.0",
|
"@roarr/browser-log-writer": "^1.3.0",
|
||||||
"chakra-react-select": "^4.7.6",
|
"chakra-react-select": "^4.7.6",
|
||||||
"compare-versions": "^6.1.0",
|
"compare-versions": "^6.1.0",
|
||||||
"dateformat": "^5.0.3",
|
"dateformat": "^5.0.3",
|
||||||
"framer-motion": "^11.0.6",
|
"framer-motion": "^11.0.22",
|
||||||
"i18next": "^23.10.0",
|
"i18next": "^23.10.1",
|
||||||
"i18next-http-backend": "^2.5.0",
|
"i18next-http-backend": "^2.5.0",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"jsondiffpatch": "^0.6.0",
|
"jsondiffpatch": "^0.6.0",
|
||||||
"konva": "^9.3.3",
|
"konva": "^9.3.6",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"nanostores": "^0.10.0",
|
"nanostores": "^0.10.0",
|
||||||
"new-github-issue-url": "^1.0.0",
|
"new-github-issue-url": "^1.0.0",
|
||||||
"overlayscrollbars": "^2.5.0",
|
"overlayscrollbars": "^2.6.1",
|
||||||
"overlayscrollbars-react": "^0.5.4",
|
"overlayscrollbars-react": "^0.5.5",
|
||||||
"query-string": "^9.0.0",
|
"query-string": "^9.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
"react-error-boundary": "^4.0.12",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-hook-form": "^7.50.1",
|
"react-hook-form": "^7.51.2",
|
||||||
"react-hotkeys-hook": "4.5.0",
|
"react-hotkeys-hook": "4.5.0",
|
||||||
"react-i18next": "^14.0.5",
|
"react-i18next": "^14.1.0",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-redux": "9.1.0",
|
"react-redux": "9.1.0",
|
||||||
"react-resizable-panels": "^2.0.11",
|
"react-resizable-panels": "^2.0.16",
|
||||||
"react-select": "5.8.0",
|
"react-select": "5.8.0",
|
||||||
"react-use": "^17.5.0",
|
"react-use": "^17.5.0",
|
||||||
"react-virtuoso": "^4.7.1",
|
"react-virtuoso": "^4.7.5",
|
||||||
"reactflow": "^11.10.4",
|
"reactflow": "^11.10.4",
|
||||||
"redux-dynamic-middlewares": "^2.2.0",
|
"redux-dynamic-middlewares": "^2.2.0",
|
||||||
"redux-remember": "^5.1.0",
|
"redux-remember": "^5.1.0",
|
||||||
"roarr": "^7.21.0",
|
"roarr": "^7.21.1",
|
||||||
"serialize-error": "^11.0.3",
|
"serialize-error": "^11.0.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.5",
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
"use-image": "^1.1.1",
|
"use-image": "^1.1.1",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
"zod-validation-error": "^3.0.2"
|
"zod-validation-error": "^3.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@chakra-ui/react": "^2.8.2",
|
"@chakra-ui/react": "^2.8.2",
|
||||||
@ -112,40 +112,40 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@invoke-ai/eslint-config-react": "^0.0.14",
|
"@invoke-ai/eslint-config-react": "^0.0.14",
|
||||||
"@invoke-ai/prettier-config-react": "^0.0.7",
|
"@invoke-ai/prettier-config-react": "^0.0.7",
|
||||||
"@storybook/addon-essentials": "^7.6.17",
|
"@storybook/addon-essentials": "^8.0.4",
|
||||||
"@storybook/addon-interactions": "^7.6.17",
|
"@storybook/addon-interactions": "^8.0.4",
|
||||||
"@storybook/addon-links": "^7.6.17",
|
"@storybook/addon-links": "^8.0.4",
|
||||||
"@storybook/addon-storysource": "^7.6.17",
|
"@storybook/addon-storysource": "^8.0.4",
|
||||||
"@storybook/manager-api": "^7.6.17",
|
"@storybook/manager-api": "^8.0.4",
|
||||||
"@storybook/react": "^7.6.17",
|
"@storybook/react": "^8.0.4",
|
||||||
"@storybook/react-vite": "^7.6.17",
|
"@storybook/react-vite": "^8.0.4",
|
||||||
"@storybook/theming": "^7.6.17",
|
"@storybook/theming": "^8.0.4",
|
||||||
"@types/dateformat": "^5.0.2",
|
"@types/dateformat": "^5.0.2",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.11.20",
|
"@types/node": "^20.11.30",
|
||||||
"@types/react": "^18.2.59",
|
"@types/react": "^18.2.73",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.22",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"dpdm": "^3.14.0",
|
"dpdm": "^3.14.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-i18next": "^6.0.3",
|
"eslint-plugin-i18next": "^6.0.3",
|
||||||
"eslint-plugin-path": "^1.2.4",
|
"eslint-plugin-path": "^1.3.0",
|
||||||
"knip": "^5.0.2",
|
"knip": "^5.6.1",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"openapi-typescript": "^6.7.4",
|
"openapi-typescript": "^6.7.5",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"storybook": "^7.6.17",
|
"storybook": "^8.0.4",
|
||||||
"ts-toolbelt": "^9.6.0",
|
"ts-toolbelt": "^9.6.0",
|
||||||
"tsafe": "^1.6.6",
|
"tsafe": "^1.6.6",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.4.3",
|
||||||
"vite": "^5.1.4",
|
"vite": "^5.2.6",
|
||||||
"vite-plugin-css-injected-by-js": "^3.4.0",
|
"vite-plugin-css-injected-by-js": "^3.5.0",
|
||||||
"vite-plugin-dts": "^3.7.3",
|
"vite-plugin-dts": "^3.8.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-tsconfig-paths": "^4.3.1",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^1.3.1"
|
"vitest": "^1.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,8 @@
|
|||||||
"title": "Image"
|
"title": "Image"
|
||||||
},
|
},
|
||||||
"advanced": {
|
"advanced": {
|
||||||
"title": "Advanced"
|
"title": "Advanced",
|
||||||
|
"options": "$t(accordions.advanced.title) Options"
|
||||||
},
|
},
|
||||||
"control": {
|
"control": {
|
||||||
"title": "Control"
|
"title": "Control"
|
||||||
@ -100,6 +101,7 @@
|
|||||||
"load": "Load",
|
"load": "Load",
|
||||||
"loading": "Loading",
|
"loading": "Loading",
|
||||||
"localSystem": "Local System",
|
"localSystem": "Local System",
|
||||||
|
"loglevel": "Log Level",
|
||||||
"learnMore": "Learn More",
|
"learnMore": "Learn More",
|
||||||
"modelManager": "Model Manager",
|
"modelManager": "Model Manager",
|
||||||
"nodeEditor": "Node Editor",
|
"nodeEditor": "Node Editor",
|
||||||
|
@ -11,7 +11,6 @@ import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
|
|||||||
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
||||||
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
||||||
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
||||||
import { useHFLoginToast } from 'features/modelManagerV2/hooks/useHFLoginToast';
|
|
||||||
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
|
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
|
||||||
import { configChanged } from 'features/system/store/configSlice';
|
import { configChanged } from 'features/system/store/configSlice';
|
||||||
import { languageSelector } from 'features/system/store/systemSelectors';
|
import { languageSelector } from 'features/system/store/systemSelectors';
|
||||||
@ -71,7 +70,6 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
useStarterModelsToast();
|
useStarterModelsToast();
|
||||||
useHFLoginToast();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary onReset={handleReset} FallbackComponent={AppErrorBoundaryFallback}>
|
<ErrorBoundary onReset={handleReset} FallbackComponent={AppErrorBoundaryFallback}>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Flex, Image, Spinner } from '@invoke-ai/ui-library';
|
import { Flex, Image, Spinner } from '@invoke-ai/ui-library';
|
||||||
|
/** @knipignore */
|
||||||
import InvokeLogoWhite from 'public/assets/images/invoke-symbol-wht-lrg.svg';
|
import InvokeLogoWhite from 'public/assets/images/invoke-symbol-wht-lrg.svg';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
import type { Item } from '@invoke-ai/ui-library';
|
|
||||||
import type { ModelIdentifierField } from 'features/nodes/types/common';
|
|
||||||
import { MODEL_TYPE_SHORT_MAP } from 'features/parameters/types/constants';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import type { AnyModelConfig } from 'services/api/types';
|
|
||||||
|
|
||||||
type UseModelCustomSelectArg<T extends AnyModelConfig> = {
|
|
||||||
modelConfigs: T[];
|
|
||||||
isLoading: boolean;
|
|
||||||
selectedModel?: ModelIdentifierField | null;
|
|
||||||
onChange: (value: T | null) => void;
|
|
||||||
modelFilter?: (model: T) => boolean;
|
|
||||||
isModelDisabled?: (model: T) => boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type UseModelCustomSelectReturn = {
|
|
||||||
selectedItem: Item | null;
|
|
||||||
items: Item[];
|
|
||||||
onChange: (item: Item | null) => void;
|
|
||||||
placeholder: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const modelFilterDefault = () => true;
|
|
||||||
const isModelDisabledDefault = () => false;
|
|
||||||
|
|
||||||
export const useModelCustomSelect = <T extends AnyModelConfig>({
|
|
||||||
modelConfigs,
|
|
||||||
isLoading,
|
|
||||||
selectedModel,
|
|
||||||
onChange,
|
|
||||||
modelFilter = modelFilterDefault,
|
|
||||||
isModelDisabled = isModelDisabledDefault,
|
|
||||||
}: UseModelCustomSelectArg<T>): UseModelCustomSelectReturn => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const items: Item[] = useMemo(
|
|
||||||
() =>
|
|
||||||
modelConfigs.filter(modelFilter).map<Item>((m) => ({
|
|
||||||
label: m.name,
|
|
||||||
value: m.key,
|
|
||||||
description: m.description,
|
|
||||||
group: MODEL_TYPE_SHORT_MAP[m.base],
|
|
||||||
isDisabled: isModelDisabled(m),
|
|
||||||
})),
|
|
||||||
[modelConfigs, isModelDisabled, modelFilter]
|
|
||||||
);
|
|
||||||
|
|
||||||
const _onChange = useCallback(
|
|
||||||
(item: Item | null) => {
|
|
||||||
if (!item || !modelConfigs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const model = modelConfigs.find((m) => m.key === item.value);
|
|
||||||
if (!model) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onChange(model);
|
|
||||||
},
|
|
||||||
[modelConfigs, onChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedItem = useMemo(() => items.find((o) => o.value === selectedModel?.key) ?? null, [selectedModel, items]);
|
|
||||||
|
|
||||||
const placeholder = useMemo(() => {
|
|
||||||
if (isLoading) {
|
|
||||||
return t('common.loading');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.length === 0) {
|
|
||||||
return t('models.noModelsAvailable');
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('models.selectModel');
|
|
||||||
}, [isLoading, items, t]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
items,
|
|
||||||
onChange: _onChange,
|
|
||||||
selectedItem,
|
|
||||||
placeholder,
|
|
||||||
};
|
|
||||||
};
|
|
@ -0,0 +1,17 @@
|
|||||||
|
import type { RgbaColor } from 'react-colorful';
|
||||||
|
|
||||||
|
export function rgbaToHex(color: RgbaColor, alpha: boolean = false): string {
|
||||||
|
const hex = ((1 << 24) + (color.r << 16) + (color.g << 8) + color.b).toString(16).slice(1);
|
||||||
|
const alphaHex = Math.round(color.a * 255)
|
||||||
|
.toString(16)
|
||||||
|
.padStart(2, '0');
|
||||||
|
return alpha ? `#${hex}${alphaHex}` : `#${hex}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hexToRGBA(hex: string, alpha: number) {
|
||||||
|
hex = hex.replace(/^#/, '');
|
||||||
|
const r = parseInt(hex.substring(0, 2), 16);
|
||||||
|
const g = parseInt(hex.substring(2, 4), 16);
|
||||||
|
const b = parseInt(hex.substring(4, 6), 16);
|
||||||
|
return { r, g, b, a: alpha };
|
||||||
|
}
|
@ -5,7 +5,6 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
|
||||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/useControlAdapterControlImage';
|
import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/useControlAdapterControlImage';
|
||||||
import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage';
|
import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage';
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
selectControlAdaptersSlice,
|
selectControlAdaptersSlice,
|
||||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||||
|
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||||
import { heightChanged, selectOptimalDimension, widthChanged } from 'features/parameters/store/generationSlice';
|
import { heightChanged, selectOptimalDimension, widthChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
@ -92,12 +92,13 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const width = roundToMultiple(controlImage.width, 8);
|
|
||||||
const height = roundToMultiple(controlImage.height, 8);
|
|
||||||
|
|
||||||
if (activeTabName === 'unifiedCanvas') {
|
if (activeTabName === 'unifiedCanvas') {
|
||||||
dispatch(setBoundingBoxDimensions({ width, height }, optimalDimension));
|
dispatch(setBoundingBoxDimensions({ width: controlImage.width, height: controlImage.height }, optimalDimension));
|
||||||
} else {
|
} else {
|
||||||
|
const { width, height } = calculateNewSize(
|
||||||
|
controlImage.width / controlImage.height,
|
||||||
|
optimalDimension * optimalDimension
|
||||||
|
);
|
||||||
dispatch(widthChanged(width));
|
dispatch(widthChanged(width));
|
||||||
dispatch(heightChanged(height));
|
dispatch(heightChanged(height));
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import type { RemoveFromBoardDropData } from 'features/dnd/types';
|
|||||||
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
||||||
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
||||||
import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice';
|
import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice';
|
||||||
|
/** @knipignore */
|
||||||
import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg';
|
import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg';
|
||||||
import { memo, useCallback, useMemo, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -171,6 +171,7 @@ const GalleryImage = (props: HoverableImageProps) => {
|
|||||||
borderTopEndRadius="base"
|
borderTopEndRadius="base"
|
||||||
borderBottomStartRadius="base"
|
borderBottomStartRadius="base"
|
||||||
sx={badgeSx}
|
sx={badgeSx}
|
||||||
|
pointerEvents="none"
|
||||||
>{`${imageDTO.width}x${imageDTO.height}`}</Text>
|
>{`${imageDTO.width}x${imageDTO.height}`}</Text>
|
||||||
)}
|
)}
|
||||||
<IAIDndImageIcon onClick={toggleStarredState} icon={starIcon} tooltip={starTooltip} />
|
<IAIDndImageIcon onClick={toggleStarredState} icon={starIcon} tooltip={starTooltip} />
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
import {
|
|
||||||
Button,
|
|
||||||
ExternalLink,
|
|
||||||
Flex,
|
|
||||||
FormControl,
|
|
||||||
FormErrorMessage,
|
|
||||||
FormHelperText,
|
|
||||||
FormLabel,
|
|
||||||
Input,
|
|
||||||
useToast,
|
|
||||||
} from '@invoke-ai/ui-library';
|
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import type { ChangeEvent } from 'react';
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useGetHFTokenStatusQuery, useSetHFTokenMutation } from 'services/api/endpoints/models';
|
|
||||||
|
|
||||||
export const HFToken = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const isEnabled = useFeatureStatus('hfToken').isFeatureEnabled;
|
|
||||||
const [token, setToken] = useState('');
|
|
||||||
const { currentData } = useGetHFTokenStatusQuery(isEnabled ? undefined : skipToken);
|
|
||||||
const [trigger, { isLoading }] = useSetHFTokenMutation();
|
|
||||||
const toast = useToast();
|
|
||||||
const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setToken(e.target.value);
|
|
||||||
}, []);
|
|
||||||
const onClick = useCallback(() => {
|
|
||||||
trigger({ token })
|
|
||||||
.unwrap()
|
|
||||||
.then((res) => {
|
|
||||||
if (res === 'valid') {
|
|
||||||
setToken('');
|
|
||||||
toast({
|
|
||||||
title: t('modelManager.hfTokenSaved'),
|
|
||||||
status: 'success',
|
|
||||||
duration: 3000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [t, toast, token, trigger]);
|
|
||||||
|
|
||||||
const error = useMemo(() => {
|
|
||||||
if (!currentData || isLoading) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (currentData === 'invalid') {
|
|
||||||
return t('modelManager.hfTokenInvalidErrorMessage');
|
|
||||||
}
|
|
||||||
if (currentData === 'unknown') {
|
|
||||||
return t('modelManager.hfTokenUnableToVerifyErrorMessage');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}, [currentData, isLoading, t]);
|
|
||||||
|
|
||||||
if (!currentData || currentData === 'valid') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex borderRadius="base" w="full">
|
|
||||||
<FormControl isInvalid={Boolean(error)} orientation="vertical">
|
|
||||||
<FormLabel>{t('modelManager.hfToken')}</FormLabel>
|
|
||||||
<Flex gap={3} alignItems="center" w="full">
|
|
||||||
<Input type="password" value={token} onChange={onChange} />
|
|
||||||
<Button onClick={onClick} size="sm" isDisabled={token.trim().length === 0} isLoading={isLoading}>
|
|
||||||
{t('common.save')}
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
<FormHelperText>
|
|
||||||
<ExternalLink label={t('modelManager.hfTokenHelperText')} href="https://huggingface.co/settings/tokens" />
|
|
||||||
</FormHelperText>
|
|
||||||
<FormErrorMessage>{error}</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,33 +0,0 @@
|
|||||||
import type { ButtonProps } from '@invoke-ai/ui-library';
|
|
||||||
import { Button } from '@invoke-ai/ui-library';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { PiArrowsClockwiseBold } from 'react-icons/pi';
|
|
||||||
|
|
||||||
import { useSyncModels } from './useSyncModels';
|
|
||||||
|
|
||||||
export const SyncModelsButton = memo((props: Omit<ButtonProps, 'aria-label'>) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { syncModels, isLoading } = useSyncModels();
|
|
||||||
const isSyncModelEnabled = useFeatureStatus('syncModels').isFeatureEnabled;
|
|
||||||
|
|
||||||
if (!isSyncModelEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
leftIcon={<PiArrowsClockwiseBold />}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onClick={syncModels}
|
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{t('modelManager.syncModels')}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
SyncModelsButton.displayName = 'SyncModelsButton';
|
|
@ -1,33 +0,0 @@
|
|||||||
import type { IconButtonProps } from '@invoke-ai/ui-library';
|
|
||||||
import { IconButton } from '@invoke-ai/ui-library';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { PiArrowsClockwiseBold } from 'react-icons/pi';
|
|
||||||
|
|
||||||
import { useSyncModels } from './useSyncModels';
|
|
||||||
|
|
||||||
export const SyncModelsIconButton = memo((props: Omit<IconButtonProps, 'aria-label'>) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { syncModels, isLoading } = useSyncModels();
|
|
||||||
const isSyncModelEnabled = useFeatureStatus('syncModels').isFeatureEnabled;
|
|
||||||
|
|
||||||
if (!isSyncModelEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IconButton
|
|
||||||
icon={<PiArrowsClockwiseBold />}
|
|
||||||
tooltip={t('modelManager.syncModels')}
|
|
||||||
aria-label={t('modelManager.syncModels')}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onClick={syncModels}
|
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
SyncModelsIconButton.displayName = 'SyncModelsIconButton';
|
|
@ -1,40 +0,0 @@
|
|||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
|
||||||
import { makeToast } from 'features/system/util/makeToast';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useSyncModelsMutation } from 'services/api/endpoints/models';
|
|
||||||
|
|
||||||
export const useSyncModels = () => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [_syncModels, { isLoading }] = useSyncModelsMutation();
|
|
||||||
const syncModels = useCallback(() => {
|
|
||||||
_syncModels()
|
|
||||||
.unwrap()
|
|
||||||
.then((_) => {
|
|
||||||
dispatch(
|
|
||||||
addToast(
|
|
||||||
makeToast({
|
|
||||||
title: `${t('modelManager.modelsSynced')}`,
|
|
||||||
status: 'success',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
if (error) {
|
|
||||||
dispatch(
|
|
||||||
addToast(
|
|
||||||
makeToast({
|
|
||||||
title: `${t('modelManager.modelSyncFailed')}`,
|
|
||||||
status: 'error',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [dispatch, _syncModels, t]);
|
|
||||||
|
|
||||||
return { syncModels, isLoading };
|
|
||||||
};
|
|
@ -1,88 +0,0 @@
|
|||||||
import { Button, Text, useToast } from '@invoke-ai/ui-library';
|
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
|
||||||
import { t } from 'i18next';
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useGetHFTokenStatusQuery } from 'services/api/endpoints/models';
|
|
||||||
import type { S } from 'services/api/types';
|
|
||||||
|
|
||||||
const FEATURE_ID = 'hfToken';
|
|
||||||
|
|
||||||
const getTitle = (token_status: S['HFTokenStatus']) => {
|
|
||||||
switch (token_status) {
|
|
||||||
case 'invalid':
|
|
||||||
return t('modelManager.hfTokenInvalid');
|
|
||||||
case 'unknown':
|
|
||||||
return t('modelManager.hfTokenUnableToVerify');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useHFLoginToast = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const isEnabled = useFeatureStatus(FEATURE_ID).isFeatureEnabled;
|
|
||||||
const [didToast, setDidToast] = useState(false);
|
|
||||||
const { data } = useGetHFTokenStatusQuery(isEnabled ? undefined : skipToken);
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (toast.isActive(FEATURE_ID)) {
|
|
||||||
if (data === 'valid') {
|
|
||||||
setDidToast(true);
|
|
||||||
toast.close(FEATURE_ID);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data && data !== 'valid' && !didToast && isEnabled) {
|
|
||||||
const title = getTitle(data);
|
|
||||||
toast({
|
|
||||||
id: FEATURE_ID,
|
|
||||||
title,
|
|
||||||
description: <ToastDescription token_status={data} />,
|
|
||||||
status: 'info',
|
|
||||||
isClosable: true,
|
|
||||||
duration: null,
|
|
||||||
onCloseComplete: () => setDidToast(true),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [data, didToast, isEnabled, t, toast]);
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
token_status: S['HFTokenStatus'];
|
|
||||||
};
|
|
||||||
|
|
||||||
const ToastDescription = ({ token_status }: Props) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
const onClick = useCallback(() => {
|
|
||||||
dispatch(setActiveTab('modelManager'));
|
|
||||||
toast.close(FEATURE_ID);
|
|
||||||
}, [dispatch, toast]);
|
|
||||||
|
|
||||||
if (token_status === 'invalid') {
|
|
||||||
return (
|
|
||||||
<Text fontSize="md">
|
|
||||||
{t('modelManager.hfTokenInvalidErrorMessage')} {t('modelManager.hfTokenInvalidErrorMessage2')}
|
|
||||||
<Button onClick={onClick} variant="link" color="base.50" flexGrow={0}>
|
|
||||||
{t('modelManager.modelManager')}.
|
|
||||||
</Button>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token_status === 'unknown') {
|
|
||||||
return (
|
|
||||||
<Text fontSize="md">
|
|
||||||
{t('modelManager.hfTokenUnableToErrorMessage')}{' '}
|
|
||||||
<Button onClick={onClick} variant="link" color="base.50" flexGrow={0}>
|
|
||||||
{t('modelManager.modelManager')}.
|
|
||||||
</Button>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user