From 0439b51a26e3c227588a22897309928519ad8412 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sun, 11 Dec 2022 00:37:08 -0500 Subject: [PATCH 01/15] Simple Installer for Unified Directory Structure, Initial Implementation (#1819) * partially working simple installer * works on linux * fix linux requirements files * read root environment variable in right place * fix cat invokeai.init in test workflows * fix classical cp error in test-invoke-pip.yml * respect --root argument now * untested bat installers added * windows install.bat now working fix logic to find frontend files * rename simple_install to "installer" 1. simple_install => 'installer' 2. source and binary install directories are removed * enable update scripts to update requirements - Also pin requirements to known working commits. - This may be a breaking change; exercise with caution - No functional testing performed yet! * update docs and installation requirements NOTE: This may be a breaking commit! Due to the way the installer works, I have to push to a public branch in order to do full end-to-end testing. - Updated installation docs, removing binary and source installers and substituting the "simple" unified installer. - Pin requirements for the "http:" downloads to known working commits. - Removed as much as possible the invoke-ai forks of others' repos. * fix directory path for installer * correct requirement/environment errors * exclude zip files in .gitignore * possible fix for dockerbuild * ready for torture testing - final Windows bat file tweaks - copy environments-and-requirements to the runtime directory so that the `update.sh` script can run. This is not ideal, since we lose control over the requirements. Better for the update script to pull the proper updated requirements script from the repository. * allow update.sh/update.bat to install arbitrary InvokeAI versions - Can pass the zip file path to any InvokeAI release, branch, commit or tag, and the installer will try to install it. - Updated documentation - Added Linux Python install hints. * use binary installer's :err_exit function * user diffusers 0.10.0 * added logic for CPPFLAGS on mac * improve windows install documentation - added information on a couple of gotchas I experienced during windows installation, including DLL loading errors experienced when Visual Studio C++ Redistributable was not present. * tagged to pull from 2.2.4-rc1 - also fix error of shell window closing immediately if suitable python not found Co-authored-by: mauwii --- .github/workflows/test-invoke-conda.yml | 4 +- .gitignore | 11 +- backend/invoke_ai_web_server.py | 8 +- binary_installer/create_installers.sh | 32 -- binary_installer/invoke.sh.in | 4 - docker-build/Dockerfile.cloud | 2 +- docs/index.md | 30 +- docs/installation/INSTALL_AUTOMATED.md | 310 ++++++++++++++++++ docs/installation/INSTALL_MANUAL.md | 2 +- docs/installation/index.md | 39 +-- .../environment-win-cuda.yml | 1 - .../requirements-base.txt | 17 +- .../requirements-lin-cuda.txt | 3 + .../requirements-win-colab-cuda.txt | 2 - .../WinLongPathsEnabled.reg | Bin installer/create_installer.sh | 48 +++ installer/install.bat.in | 215 ++++++++++++ installer/install.sh.in | 216 ++++++++++++ installer/readme.txt | 52 +++ installer/templates/invoke.bat.in | 37 +++ .../templates}/invoke.sh.in | 22 +- installer/templates/update.bat.in | 52 +++ installer/templates/update.sh.in | 52 +++ ldm/generate.py | 1 - ldm/invoke/CLI.py | 1 - ldm/invoke/__init__.py | 1 + ldm/invoke/args.py | 20 +- ldm/invoke/globals.py | 4 +- scripts/configure_invokeai.py | 37 +-- setup.py | 2 +- source_installer/create_installers.sh | 27 -- source_installer/install.bat.in | 127 ------- source_installer/install.sh.in | 152 --------- source_installer/invoke.bat.in | 34 -- source_installer/readme.txt | 16 - source_installer/update.bat.in | 19 -- source_installer/update.sh.in | 26 -- 37 files changed, 1068 insertions(+), 558 deletions(-) delete mode 100755 binary_installer/create_installers.sh create mode 100644 docs/installation/INSTALL_AUTOMATED.md rename {source_installer => installer}/WinLongPathsEnabled.reg (100%) create mode 100755 installer/create_installer.sh create mode 100644 installer/install.bat.in create mode 100644 installer/install.sh.in create mode 100644 installer/readme.txt create mode 100644 installer/templates/invoke.bat.in rename {source_installer => installer/templates}/invoke.sh.in (53%) mode change 100755 => 100644 create mode 100644 installer/templates/update.bat.in create mode 100644 installer/templates/update.sh.in delete mode 100755 source_installer/create_installers.sh delete mode 100644 source_installer/install.bat.in delete mode 100755 source_installer/install.sh.in delete mode 100644 source_installer/invoke.bat.in delete mode 100644 source_installer/readme.txt delete mode 100644 source_installer/update.bat.in delete mode 100755 source_installer/update.sh.in diff --git a/.github/workflows/test-invoke-conda.yml b/.github/workflows/test-invoke-conda.yml index d24b7949a8..b96f50f123 100644 --- a/.github/workflows/test-invoke-conda.yml +++ b/.github/workflows/test-invoke-conda.yml @@ -114,9 +114,9 @@ jobs: run: | python scripts/configure_invokeai.py --no-interactive --yes - - name: cat ~/.invokeai + - name: cat invokeai.init id: cat-invokeai - run: cat ~/.invokeai + run: cat ${{ env.INVOKEAI_ROOT }}/invokeai.init - name: Run the tests id: run-tests diff --git a/.gitignore b/.gitignore index 669b165eba..56217929f6 100644 --- a/.gitignore +++ b/.gitignore @@ -222,12 +222,11 @@ environment.yml requirements.txt # source installer files -source_installer/*zip -source_installer/invokeAI -install.bat -install.sh -update.bat -update.sh +installer/*zip +installer/install.bat +installer/install.sh +installer/update.bat +installer/update.sh # this may be present if the user created a venv invokeai diff --git a/backend/invoke_ai_web_server.py b/backend/invoke_ai_web_server.py index fa3ba79407..cf5922d7af 100644 --- a/backend/invoke_ai_web_server.py +++ b/backend/invoke_ai_web_server.py @@ -246,14 +246,16 @@ class InvokeAIWebServer: def find_frontend(self): my_dir = os.path.dirname(__file__) - for candidate in (os.path.join(my_dir,'..','frontend','dist'), # pip install -e . - os.path.join(my_dir,'../../../../frontend','dist') # pip install . + # LS: setup.py seems to put the frontend in different places on different systems, so + # this is fragile and needs to be replaced with a better way of finding the front end. + for candidate in (os.path.join(my_dir,'..','frontend','dist'), # pip install -e . + os.path.join(my_dir,'../../../../frontend','dist'), # pip install . (Linux, Mac) + os.path.join(my_dir,'../../../frontend','dist'), # pip install . (Windows) ): if os.path.exists(candidate): return candidate assert "Frontend files cannot be found. Cannot continue" - def setup_app(self): self.result_url = "outputs/" self.init_image_url = "outputs/init-images/" diff --git a/binary_installer/create_installers.sh b/binary_installer/create_installers.sh deleted file mode 100755 index 04c68dd777..0000000000 --- a/binary_installer/create_installers.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -IFS=$'\n\t' - -echo "Be certain that you're in the 'installer' directory before continuing." -read -p "Press any key to continue, or CTRL-C to exit..." - -VERSION='2.2.3' - -# make the installer zip for linux and mac -rm -rf InvokeAI -mkdir -p InvokeAI -cp install.sh.in InvokeAI/install.sh -chmod a+x InvokeAI/install.sh -cp readme.txt InvokeAI - -zip -r InvokeAI-binary-$VERSION-linux.zip InvokeAI -zip -r InvokeAI-binary-$VERSION-mac.zip InvokeAI - -# make the installer zip for windows -rm -rf InvokeAI -mkdir -p InvokeAI -cp install.bat.in InvokeAI/install.bat -cp readme.txt InvokeAI -cp WinLongPathsEnabled.reg InvokeAI - -zip -r InvokeAI-binary-$VERSION-windows.zip InvokeAI - -rm -rf InvokeAI - -echo "The installer zips are ready for distribution." diff --git a/binary_installer/invoke.sh.in b/binary_installer/invoke.sh.in index 9a2aae6707..b131b4ae2f 100644 --- a/binary_installer/invoke.sh.in +++ b/binary_installer/invoke.sh.in @@ -2,10 +2,6 @@ set -eu -# ensure we're in the correct folder in case user's CWD is somewhere else -scriptdir=$(dirname "$0") -cd "$scriptdir" - . .venv/bin/activate # set required env var for torch on mac MPS diff --git a/docker-build/Dockerfile.cloud b/docker-build/Dockerfile.cloud index db6e1523b3..b40fabdccc 100644 --- a/docker-build/Dockerfile.cloud +++ b/docker-build/Dockerfile.cloud @@ -36,7 +36,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ COPY . . RUN --mount=type=cache,target=/root/.cache/pip \ - cp binary_installer/py3.10-linux-x86_64-cuda-reqs.txt requirements.txt && \ + cp environments-and-requirements/requirements-lin-cuda.txt requirements.txt && \ pip install -r requirements.txt &&\ pip install -e . diff --git a/docs/index.md b/docs/index.md index 74e5ac3bc1..a5a217ac26 100644 --- a/docs/index.md +++ b/docs/index.md @@ -82,13 +82,18 @@ Mac and Linux machines, and runs on GPU cards with as little as 4 GB or RAM. This fork is supported across Linux, Windows and Macintosh. Linux users can use either an Nvidia-based card (with CUDA support) or an -AMD card (using the ROCm driver). For full installation and upgrade -instructions, please see: -[InvokeAI Installation Overview](https://invoke-ai.github.io/InvokeAI/installation/) +AMD card (using the ROCm driver). + +First time users, please see [Automated +Installer](installation/INSTALL_AUTOMATED.md) for a walkthrough of +getting InvokeAI up and running on your system. For alternative +installation and upgrade instructions, please see: [InvokeAI +Installation Overview](installation/) Linux users who wish to make use of the PyPatchMatch inpainting functions will need to perform a bit of extra work to enable this -module. Instructions can be found at [Installing PyPatchMatch](installation/INSTALL_PATCHMATCH.md). +module. Instructions can be found at [Installing +PyPatchMatch](installation/INSTALL_PATCHMATCH.md). ## :fontawesome-solid-computer: Hardware Requirements @@ -100,9 +105,13 @@ You wil need one of the following: - :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. -We do not recommend the GTX 1650 or 1660 series video cards. They are -unable to run in half-precision mode and do not come with sufficient VRAM -to render 512x512 images. +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 ### :fontawesome-solid-memory: Memory @@ -110,16 +119,11 @@ to render 512x512 images. ### :fontawesome-regular-hard-drive: Disk -- At least 12 GB of free disk space for the machine learning model, Python, and +- At least 18 GB of free disk space for the machine learning model, Python, and all its dependencies. !!! info - If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the invoke script in - full-precision mode as shown below. - - Similarly, specify full-precision mode on Apple M1 hardware. - Precision is auto configured based on the device. If however you encounter errors like `expected type Float but found Half` or `not implemented for Half` you can try starting `invoke.py` with the `--precision=float32` flag: diff --git a/docs/installation/INSTALL_AUTOMATED.md b/docs/installation/INSTALL_AUTOMATED.md new file mode 100644 index 0000000000..950efd80c2 --- /dev/null +++ b/docs/installation/INSTALL_AUTOMATED.md @@ -0,0 +1,310 @@ +--- +title: InvokeAI Automated Installation +--- + +# InvokeAI Automated Installation + +## Introduction + +The automated 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. + +## Walk through + +1. Make sure that your system meets 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. + +2. Check that your system has an up-to-date Python installed. To do +this, open up a command-line window ("Terminal" on Linux and +Macintosh, "Command" or "Powershell" on Windows) and type `python +--version`. If Python is installed, it will print out the version +number. If it is version `3.9.1` or higher, you meet requirements. + + - If you see an older version, or you get a command not found + error, then go to [Python + Downloads](https://www.python.org/downloads/) and download the + appropriate installer package for your platform. We recommend + [Version + 3.10.9](https://www.python.org/downloads/release/python-3109/), + which has been extensively tested with InvokeAI. + + -**Windows users**: During the Python configuration process, + Please 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. + + - **Mac users**: 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: + + `/Applications/Python\ 3.10/Install\ Certificates.command` + + Do not use Python 3.11 at this time due to poor performance + of the underlying pytorch machine learning library. + + - **Linux users**: See [Installing Python in Ubuntu](#installing-python-in-ubuntu) for some + platform-specific tips. + +3. 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-installer-2.2.4-mac.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/InvokeAI-installer-2.2.4-mac.zip) + - [InvokeAI-installer-2.2.4-windows.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/InvokeAI-installer-2.2.4-windows.zip) + - [InvokeAI-installer-2.2.4-linux.zip](https://github.com/invoke-ai/InvokeAI/releases/latest/download/InvokeAI-installer-2.2.4-linux.zip) + + Download the one that is appropriate for your operating system. + +4. 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/ + +5. If you are a Windows users, there is a slight possibility that you + will encountered DLL load errors at the very end of the installation + process. This is caused by not having up to date Visual C++ + redistributable libraries. If this happens to you, you can install + the C++ libraries from this site: + https://learn.microsoft.com/en-us/cpp/windows/deploying-native-desktop-applications-visual-cpp?view=msvc-170 + +6. Unpack the zip file into a convenient directory. This will create + a new directory named "InvokeAI-Installer". 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-installer-2.2.4-windows.zip + Archive: C: \Linco\Downloads\InvokeAI-installer-2.2.4-windows.zip + creating: InvokeAI-Installer\ + inflating: InvokeAI-Installer\install.bat + inflating: InvokeAI-Installer\readme.txt + ... + ``` + + After successful installation, you can delete the + `InvokeAI-Installer` directory. + +7. Windows users should now 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. + +8. 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. + + On Windows systems you will probably get an "Untrusted Publisher" warning. + Click on "More Info" and select "Run Anyway." You trust us, right? + +9. 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 + ``` + +10. The script will ask you to choose where to install InvokeAI. Select + a 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. + + - 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. + + - 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. + +11. Sit back and let the install script work. It will install the + third-party libraries needed by InvokeAI, then download the + current InvokeAI release and install it. + + 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. + +12. 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. We provide a list + of popular models that InvokeAI performs well with. However, you + can add more weight files later on using the command-line client + or the Web UI. See [Installing Models](INSTALLING_MODELS.md) for details. + + 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](INSTALLING_MODELS.md). + +13. 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 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 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. + +14. You can launch InvokeAI with several different command-line arguments +that customize its behavior. For example, you can change the location +of the inage output directory, or select your favorite sampler. See +the [Command-Line Interface](../features/CLI.md) for a full list of +the options. + + - To set defaults that will take effect every time you launch InvokeAI, + use a text editor (e.g. Notepad) to exit the file + `invokeai\invokeai.init`. It contains a variety of examples that you can + follow to add and modify launch options. + + +!!! warning "The `invokeai` directory contains the `invoke` application, its configuration files, the model weight files, and outputs of image generation. Once InvokeAI is installed, do not move or remove this directory." + +## 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 about library conflicts. You can +address this by entering the `invokeai` directory and running +`update.sh`, which will bring InvokeAI up to date with the latest +libraries. + +!!! warning "Some users have tried to correct dependency problems by installing the `ldm` package from PyPi.org. Unfortunately this is an unrelated package that has nothing to do with the 'latent diffusion model' used by InvokeAI. Installing ldm will make matters worse. If you've installed ldm, uninstall it with `pip uninstall ldm`." + +_"Corrupted configuration file."__ Everything seems to install ok, but +`invoke` 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 re-run `configure_invokeai.py`. Enter the +developer's console (option 3 of the launcher script) and run this +command: + +```cmd +configure_invokeai.py --root=. +``` + +Note the dot (.) after `--root`. It is part of the command. + +_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 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`. + +You may also use the `update` script to install any selected version +of InvokeAI. From https://github.com/invoke-ai/InvokeAI, navigate to +the zip file link of the version you wish to install. You can find the +zip links by going to the one of the release pages and looking for the +**Assets** section at the bottom. Alternatively, you can browse +"branches" and "tags" at the top of the big code directory on the +InvokeAI welcome page. When you find the version you want to install, +go to the green "<> Code" button at the top, and copy the +"Download ZIP" link. + +Now run `update.sh` (or `update.bat`) with the URL of the desired +InvokeAI version as its argument. For example, this will install the +old 2.2.0 release. + +```cmd +update.sh https://github.com/invoke-ai/InvokeAI/archive/refs/tags/v2.2.0.zip +``` + +## 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. + +## Installing Python in Ubuntu + +For reasons that are not entirely clear, installing the correct +version of Python can be a bit of a challenge on Ubuntu, Linux Mint, and +other Ubuntu-derived distributions. + +In particular, Ubuntu version 20.04 LTS comes with an old version of +Python, does not come with the PIP package manager installed, and to +make matters worse, the `python` command points to Python2, not +Python3. + +Here is the quick recipe for bringing your system up to date: + +``` +sudo apt update +sudo apt install python3.9 +sudo apt install python3-pip +cd /usr/bin +sudo ln -sf python3.9 python3 +sudo ln -sf python3 python +``` + +You can still access older versions of Python by calling `python2`, +`python3.8`, etc. + diff --git a/docs/installation/INSTALL_MANUAL.md b/docs/installation/INSTALL_MANUAL.md index c17819218c..d94c441776 100644 --- a/docs/installation/INSTALL_MANUAL.md +++ b/docs/installation/INSTALL_MANUAL.md @@ -8,7 +8,7 @@ title: Manual Installation !!! warning "This is for advanced Users" - who are already expirienced with using conda or pip + who are already experienced with using conda or pip ## Introduction diff --git a/docs/installation/index.md b/docs/installation/index.md index a2d58067c3..85690f29da 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -5,39 +5,20 @@ title: Overview We offer several ways to install InvokeAI, each one suited to your experience and preferences. -1. [InvokeAI source code installer](INSTALL_SOURCE.md) - This is a script that will install Python, the Anaconda ("conda") - package manager, all of InvokeAI's its essential third party - libraries and InvokeAI itself. It includes access to a "developer - console" which will help us debug problems with you and give you - to access experimental features. +1. [Automated Installer](INSTALL_AUTOMATED.md) - When a new InvokeAI feature is available, even between releases, - you will be able to upgrade and try it out by running an `update` - script. This method is recommended for individuals who wish to - stay on the cutting edge of InvokeAI development and are not - afraid of occasional breakage. - - To get started go to the bottom of the - [Latest Release Page](https://github.com/invoke-ai/InvokeAI/releases/latest) - and download the .zip file for your platform. Unzip the file. - If you are on a Windows system, double-click on the `install.bat` - script. On a Mac or Linux system, navigate to the file `install.sh` - from within the terminal application, and run the script. - - Sit back and watch the script run. - - **Important Caveats** - - This script is a bit cranky and occasionally hangs or times out, - forcing you to cancel and restart the script (it will pick up where - it left off). + This is a script that will install all of InvokeAI's essential + third party libraries and InvokeAI itself. It includes access to a + "developer console" which will help us debug problems with you and + give you to access experimental features. 2. [Manual Installation](INSTALL_MANUAL.md) 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. + `pip` and Python virtual environments. In our hands the pip install + is faster and more reliable, but your mileage may vary. This method is recommended for users who have previously used `conda` or `pip` in the past, developers, and anyone who wishes to remain on @@ -51,9 +32,3 @@ experience and preferences. individuals with experience with Docker containers and understand the pluses and minuses of a container-based install. -4. [Jupyter Notebooks Installation](INSTALL_JUPYTER.md) - - This method is suitable for running InvokeAI on a Google Colab - account. It is recommended for individuals who have previously - worked on the Colab and are comfortable with the Jupyter notebook - environment. diff --git a/environments-and-requirements/environment-win-cuda.yml b/environments-and-requirements/environment-win-cuda.yml index 6bb9de1d87..52b92e1d00 100644 --- a/environments-and-requirements/environment-win-cuda.yml +++ b/environments-and-requirements/environment-win-cuda.yml @@ -13,7 +13,6 @@ dependencies: - cudatoolkit=11.6 - pip: - albumentations==0.4.3 - - basicsr==1.4.1 - dependency_injector==4.40.0 - diffusers==0.6.0 - einops==0.3.0 diff --git a/environments-and-requirements/requirements-base.txt b/environments-and-requirements/requirements-base.txt index d34bfeb72c..b8f20cead4 100644 --- a/environments-and-requirements/requirements-base.txt +++ b/environments-and-requirements/requirements-base.txt @@ -1,7 +1,7 @@ # pip will resolve the version which matches torch albumentations dependency_injector==4.40.0 -diffusers==0.9.0 +diffusers==0.10.* einops eventlet facexlib @@ -10,6 +10,7 @@ flask_cors==3.0.10 flask_socketio==5.3.0 flaskwebgui==0.3.7 getpass_asterisk +gfpgan==1.3.8 huggingface-hub imageio imageio-ffmpeg @@ -17,6 +18,7 @@ kornia numpy omegaconf opencv-python +picklescan pillow pip>=22 pudb @@ -31,11 +33,8 @@ taming-transformers-rom1504 test-tube>=0.7.5 torch-fidelity torchmetrics -transformers==4.21.* -picklescan -# git+https://github.com/invoke-ai/GFPGAN@basicsr-1.4.1#egg=gfpgan ; platform_system == 'Windows' -git+https://github.com/invoke-ai/GFPGAN@basicsr-1.4.2#egg=gfpgan ; platform_system != 'Windows' -git+https://github.com/openai/CLIP.git@main#egg=clip -git+https://github.com/Birch-san/k-diffusion.git@mps#egg=k-diffusion -git+https://github.com/invoke-ai/clipseg.git@relaxed-python-requirement#egg=clipseg -git+https://github.com/invoke-ai/PyPatchMatch@0.1.4#egg=pypatchmatch +transformers==4.25.* +https://github.com/Birch-san/k-diffusion/archive/refs/heads/mps.zip#egg=k-diffusion +https://github.com/invoke-ai/PyPatchMatch/archive/refs/tags/0.1.4.zip#egg=pypatchmatch +https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip#egg=clip +https://github.com/invoke-ai/clipseg/archive/relaxed-python-requirement.zip#egg=clipseg diff --git a/environments-and-requirements/requirements-lin-cuda.txt b/environments-and-requirements/requirements-lin-cuda.txt index 1578c60334..d815dd8ca3 100644 --- a/environments-and-requirements/requirements-lin-cuda.txt +++ b/environments-and-requirements/requirements-lin-cuda.txt @@ -1,2 +1,5 @@ +--extra-index-url https://download.pytorch.org/whl/cu116 --trusted-host https://download.pytorch.org -r environments-and-requirements/requirements-base.txt +torch +torchvision -e . diff --git a/environments-and-requirements/requirements-win-colab-cuda.txt b/environments-and-requirements/requirements-win-colab-cuda.txt index 2426fe56aa..4083d675e0 100644 --- a/environments-and-requirements/requirements-win-colab-cuda.txt +++ b/environments-and-requirements/requirements-win-colab-cuda.txt @@ -1,8 +1,6 @@ -r environments-and-requirements/requirements-base.txt # Get hardware-appropriate torch/torchvision --extra-index-url https://download.pytorch.org/whl/cu116 --trusted-host https://download.pytorch.org -gfpgan -basicsr torch==1.12.1 torchvision==0.13.1 -e . diff --git a/source_installer/WinLongPathsEnabled.reg b/installer/WinLongPathsEnabled.reg similarity index 100% rename from source_installer/WinLongPathsEnabled.reg rename to installer/WinLongPathsEnabled.reg diff --git a/installer/create_installer.sh b/installer/create_installer.sh new file mode 100755 index 0000000000..83eff14c4c --- /dev/null +++ b/installer/create_installer.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +VERSION=$(grep ^VERSION ../setup.py | awk '{ print $3 }' | sed "s/'//g" ) + +echo "Be certain that you're in the 'installer' directory before continuing." +read -p "Press any key to continue, or CTRL-C to exit..." + +echo Building installer zip fles for InvokeAI v$VERSION + +# get rid of any old ones +rm *.zip + +rm -rf InvokeAI-Installer +mkdir InvokeAI-Installer + +cp -pr ../environments-and-requirements templates readme.txt InvokeAI-Installer/ +mkdir InvokeAI-Installer/templates/rootdir + +cp -pr ../configs InvokeAI-Installer/templates/rootdir/ + +mkdir InvokeAI-Installer/templates/rootdir/{outputs,embeddings,models} + +cp install.sh.in InvokeAI-Installer/install.sh +chmod a+rx InvokeAI-Installer/install.sh + +zip -r InvokeAI-installer-$VERSION-linux.zip InvokeAI-Installer +zip -r InvokeAI-installer-$VERSION-mac.zip InvokeAI-Installer + +# now do the windows installer +rm InvokeAI-Installer/install.sh +cp install.bat.in InvokeAI-Installer/install.bat +cp WinLongPathsEnabled.reg InvokeAI-Installer/ + +# this gets rid of the "-e ." at the end of the windows requirements file +# because it is easier to do it now than in the .bat install script +egrep -v '^-e .' InvokeAI-Installer/environments-and-requirements/requirements-win-colab-cuda.txt >requirements.txt +mv requirements.txt InvokeAI-Installer/environments-and-requirements/requirements-win-colab-cuda.txt +zip -r InvokeAI-installer-$VERSION-windows.zip InvokeAI-Installer + +# clean up +rm -rf InvokeAI-Installer + + +exit 0 + + diff --git a/installer/install.bat.in b/installer/install.bat.in new file mode 100644 index 0000000000..345ac363fe --- /dev/null +++ b/installer/install.bat.in @@ -0,0 +1,215 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +@rem This script requires the user to install Python 3.9 or higher. All other +@rem requirements are downloaded as needed. + +@rem change to the script's directory +PUSHD "%~dp0" + +set "no_cache_dir=--no-cache-dir" +if "%1" == "use-cache" ( + set "no_cache_dir=" +) + +@rem Config +@rem this should be changed to the tagged release! +@rem set INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/archive/main.zip +set INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/refs/tags/2.2.4-rc1.zip +set INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ +set TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting +set PYTHON_URL=https://www.python.org/downloads/windows/ +set MINIMUM_PYTHON_VERSION=3.9.0 +set PYTHON_URL=https://www.python.org/downloads/release/python-3109/ + + +set err_msg=An error has occurred and the script could not continue. + +@rem --------------------------- Intro ------------------------------- +echo This script will install InvokeAI and its dependencies. Before you start, +echo please make sure to do the following: +echo 1. Install python 3.9 or higher. +echo 2. Double-click on the file WinLongPathsEnabled.reg in order to +echo enable long path support on your system. +echo 3. Some users have found they need to install the Visual C++ core +echo libraries or else they experience DLL loading problems at the end of the install. +echo Visual C++ is very likely already installed on your system, but if you get DLL +echo issues, please download and install the libraries by going to: +echo https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170 +echo. +echo See %INSTRUCTIONS% for more details. +echo. +pause + +@rem ---------------------------- check Python version --------------- +echo ***** Checking and Updating Python ***** + +call python --version >.tmp1 2>.tmp2 +if %errorlevel% == 1 ( + set err_msg=Please install Python 3.9 or higher. See %INSTRUCTIONS% for details. + goto err_exit +) + +for /f "tokens=2" %%i in (.tmp1) do set python_version=%%i +if "%python_version%" == "" ( + set err_msg=No python was detected on your system. Please install Python version %MINIMUM_PYTHON_VERSION% or higher. We recommend Python 3.10.9 from %PYTHON_URL% + goto err_exit +) + +call :compareVersions %MINIMUM_PYTHON_VERSION% %python_version% +if %errorlevel% == 1 ( + set err_msg=Your version of Python is too low. You need at least %MINIMUM_PYTHON_VERSION% but you have %python_version%. We recommend Python 3.10.9 from %PYTHON_URL% + goto err_exit +) + +@rem Cleanup +del /q .tmp1 .tmp2 + +echo Updating PIP... +call python -m pip install --no-warn-script-location -q --upgrade pip + +@rem --------------------- Get the requirements file ------------ +echo. +echo Setting up requirements file for your system. +copy /y environments-and-requirements\requirements-win-colab-cuda.txt .\requirements.txt + +@rem --------------------- Get the root directory for installation ------------ +set rootdir="" +set response="" +set selection="" +:pick_rootdir + if %rootdir% neq "" goto :done + set /p selection=Select the path to install InvokeAI's directory into [%UserProfile%]: + if %selection% == "" set selection=%UserProfile% + set dest=%selection%\invokeai + if exist %dest% ( + set response=y + set /p response=The directory %dest% exists. Do you wish to resume install from a previous attempt? [Y/n]: + if !response! == "" set response=y + if /I !response! == y (set rootdir=%dest%) else (goto :pick_rootdir) + ) else ( + set rootdir=!dest! + ) + set response=y + set /p response="You have chosen to install InvokeAI into %rootdir%. OK? [Y/n]: " + if !response! == "" set response=y + if /I !response! neq y set rootdir="" +goto :pick_rootdir +:done + +@rem ---------------------- Initialize the runtime directory --------------------- +echo. +echo *** Creating Runtime Directory %rootdir% *** +if not exist %rootdir% mkdir %rootdir% +@rem for unknown reasons the mkdir works but returns an error code +if not exist %rootdir% ( + set err_msg=Could not create the directory %rootdir%. Please check the directory's permissions and try again. + goto :err_exit +) +echo Successful. + +@rem --------------------------- Create and populate .venv --------------------------- +echo. +echo ** Creating Virtual Environment for InvokeAI ** +call python -mvenv %rootdir%\.venv +if %errorlevel% neq 0 ( + set err_msg=Could not create virtual environment %rootdir%\.venv. Please check the directory's permissions and try again. + goto :err_exit +) +echo Successful. + +echo. +echo *** Installing InvokeAI Requirements *** +call %rootdir%\.venv\Scripts\activate.bat +copy environments-and-requirements\requirements-win-colab-cuda.txt .\requirements.txt +call python -mpip install -r requirements.txt +if %errorlevel% neq 0 ( + set err_msg=Installation of requirements failed. See above for errors and check %TROUBLESHOOTING% for potential solutions. + goto :err_exit +) +echo Installation successful. + +echo. +echo *** Installing InvokeAI Modules and Executables *** +call python -mpip install %INVOKE_AI_SRC% +if %errorlevel% neq 0 ( + set err_msg=Installation of InvokeAI failed. See above for errors and check %TROUBLESHOOTING% for potential solutions. + goto :err_exit +) +echo Installation successful. + +@rem --------------------------- Set up the root directory --------------------------- +xcopy /E /Y .\templates\rootdir %rootdir% +PUSHD "%rootdir%" +call .venv\Scripts\python .venv\Scripts\configure_invokeai.py --root="%rootdir%" +if %errorlevel% neq 0 ( + set err_msg=Configuration failed. See above for error messages and check %TROUBLESHOOTING% for potential solutions. + goto :err_exit +) +POPD +copy .\templates\invoke.bat.in %rootdir%\invoke.bat +copy .\templates\update.bat.in %rootdir%\update.bat + +@rem so that update.bat works +mkdir %rootdir%\environments-and-requirements +xcopy /I /Y .\environments-and-requirements %rootdir%\environments-and-requirements +copy .\requirements.txt %rootdir%\requirements.txt + + +echo. +echo ***** Finished configuration ***** +echo All done. Execute the file %rootdir%\invoke.bat to start InvokeAI. +pause +deactivate +exit + +@rem ------------------------ Subroutines --------------- +@rem routine to do comparison of semantic version numbers +@rem found at https://stackoverflow.com/questions/15807762/compare-version-numbers-in-batch-file +:compareVersions +:: +:: Compares two version numbers and returns the result in the ERRORLEVEL +:: +:: Returns 1 if version1 > version2 +:: 0 if version1 = version2 +:: -1 if version1 < version2 +:: +:: The nodes must be delimited by . or , or - +:: +:: Nodes are normally strictly numeric, without a 0 prefix. A letter suffix +:: is treated as a separate node +:: +setlocal enableDelayedExpansion +set "v1=%~1" +set "v2=%~2" +call :divideLetters v1 +call :divideLetters v2 +:loop +call :parseNode "%v1%" n1 v1 +call :parseNode "%v2%" n2 v2 +if %n1% gtr %n2% exit /b 1 +if %n1% lss %n2% exit /b -1 +if not defined v1 if not defined v2 exit /b 0 +if not defined v1 exit /b -1 +if not defined v2 exit /b 1 +goto :loop + + +:parseNode version nodeVar remainderVar +for /f "tokens=1* delims=.,-" %%A in ("%~1") do ( + set "%~2=%%A" + set "%~3=%%B" +) +exit /b + + +:divideLetters versionVar +for %%C in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set "%~1=!%~1:%%C=.%%C!" +exit /b + +:err_exit +echo %err_msg% +echo The installer will exit now. +pause +exit /b + diff --git a/installer/install.sh.in b/installer/install.sh.in new file mode 100644 index 0000000000..e4055a7000 --- /dev/null +++ b/installer/install.sh.in @@ -0,0 +1,216 @@ +#!/usr/bin/env bash + +# ensure we're in the correct folder in case user's CWD is somewhere else +scriptdir=$(dirname "$0") +cd "$scriptdir" + +# make sure we are not already in a venv +# (don't need to check status) +deactivate >/dev/null 2>&1 + +# this should be changed to the tagged release! +INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/refs/tags/2.2.4-rc1.zip +INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ +TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting +MINIMUM_PYTHON_VERSION=3.9.0 + +set -euo pipefail +IFS=$'\n\t' + +function _err_exit { + if test "$1" -ne 0 + then + echo -e "Error code $1; Error caught was '$2'" + if [ "$OS_NAME" == "osx" ]; then + echo "Something went wrong while installing InvokeAI and/or its requirements." + echo "You may need to use the Xcode command line tools to proceed. See step number 3 of" + echo "https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#walk_through for" + echo "installation instructions and then run this script again." + else + echo "Something went wrong while installing InvokeAI and/or its requirements." + echo "See https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#troubleshooting for troubleshooting" + echo "tips, or visit https://invoke-ai.github.io/InvokeAI/#installation for alternative" + echo "installation methods" + fi + read -p "Press any key to exit..." + exit + fi +} + +function readinput() { + local CLEAN_ARGS="" + while [[ $# -gt 0 ]]; do + local i="$1" + case "$i" in + "-i") + if read -i "default" 2>/dev/null <<< "test"; then + CLEAN_ARGS="$CLEAN_ARGS -i \"$2\"" + fi + shift + shift + ;; + "-p") + CLEAN_ARGS="$CLEAN_ARGS -p \"$2\"" + shift + shift + ;; + *) + CLEAN_ARGS="$CLEAN_ARGS $1" + shift + ;; + esac + done + eval read $CLEAN_ARGS +} + + +function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } + +echo "InvokeAI simple installer..." +echo "" +echo "Some of the installation steps take a long time to run. Please be patient." +echo "If the script appears to hang for more than 10 minutes, please interrupt with control-C and retry." +read -n 1 -s -r -p "" +echo "" + +OS_NAME=$(uname -s) +case "${OS_NAME}" in + Linux*) OS_NAME="linux";; + Darwin*) OS_NAME="osx";; + *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit +esac + +OS_ARCH=$(uname -m) +case "${OS_ARCH}" in + x86_64*) OS_ARCH="64";; + arm64*) OS_ARCH="arm64";; + *) echo "Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64" && exit +esac + +echo "Installing for $OS_NAME-$OS_ARCH" +# confirm that python is installed and is up to date + +PYTHON="" +for candidate in python3.10 python3.9 python3 python python3.11 ; do + if ppath=`which $candidate`; then + python_version=$($ppath -V | awk '{ print $2 }') + if [ $(version $python_version) -ge $(version "$MINIMUM_PYTHON_VERSION") ]; then + PYTHON=$ppath + echo Python $python_version found at $PYTHON + break + fi + fi +done + +if [ -z "$PYTHON" ]; then + echo "A suitable Python interpreter could not be found" + echo "Please install Python 3.9 or higher before running this script. See instructions at $INSTRUCTIONS for help." + read -p "Press any key to exit" + exit -1 +fi + +if [ "$OS_NAME" == "osx" ]; then + xcode_path=$(xcode-select --print-path) + _err_exit $? "xcode_path command not found" + export CPPFLAGS="-I$xcode_path/Library/Frameworks/Python3.framework/Versions/Current/Headers" + echo "Will compile wheels with CPPFLAGS=$CPPFLAGS" +fi + +ROOTDIR="" +while [ "$ROOTDIR" == "" ] +do + echo + readinput -e -p "Select your preferred location for the 'invokeai' directory [$HOME]: " -i $HOME input + ROOTDIR=${input:=$HOME}/invokeai + read -e -p "InvokeAI will be installed into $ROOTDIR. OK? [y]: " input + RESPONSE=${input:='y'} + if [ "$RESPONSE" == 'y' ]; then + if [ -e $ROOTDIR ]; then + echo + read -e -p "Directory $ROOTDIR already exists. Do you want to resume an interrupted install? [y]: " input + RESPONSE=${input:='y'} + if [ "$RESPONSE" != 'y' ]; then + ROOTDIR="" + fi + else + mkdir -p $ROOTDIR + if [ $? -ne 0 ]; then + echo "Could not create $ROOTDIR. Try again with a different install location." + ROOTDIR="" + fi + fi + else + ROOTDIR="" + fi +done + +#-------------------------------------------------------------------------------- +echo +echo "** Creating Virtual Environment for InvokeAI **" + +$PYTHON -mpip install --upgrade pip +$PYTHON -mvenv $ROOTDIR/.venv +_err_exit $? "Python failed to create virtual environment $ROOTDIR/.venv. Please see $TROUBLESHOOTING for help." + +#-------------------------------------------------------------------------------- +echo +echo "** Activating Virtual Environment for InvokeAI **" + +source $ROOTDIR/.venv/bin/activate +_err_exit $? "Failed to activate virtual evironment $ROOTDIR/.venv. Please see $TROUBLESHOOTING for help." + +PYTHON=$ROOTDIR/.venv/bin/python + +#-------------------------------------------------------------------------------- +echo +echo "*** Installing InvokeAI Dependencies ***" + +if [ "$OS_NAME" == "osx" ]; then + echo "macOS detected. Installing MPS and CPU support." + egrep -v '^-e .' environments-and-requirements/requirements-mac-mps-cpu.txt >requirements.txt +else + if (lsmod | grep amdgpu) &>/dev/null ; then + echo "Linux system with AMD GPU driver detected. Installing ROCm and CPU support" + egrep -v '^-e .' environments-and-requirements/requirements-lin-amd.txt >requirements.txt + else + echo "Linux system detected. Installing CUDA and CPU support." + egrep -v '^-e .' environments-and-requirements/requirements-lin-cuda.txt >requirements.txt + fi +fi + +$PYTHON -mpip install -r requirements.txt +_err_exit $? "Failed to install InvokeAI's dependencies." + +#-------------------------------------------------------------------------------- +echo +echo "*** Installing InvokeAI Modules and Executables ***" +$PYTHON -mpip install $INVOKE_AI_SRC +_err_exit $? "Installation of InvokeAI failed." + +#-------------------------------------------------------------------------------- +echo " *** Setting Up Root Directory $ROOTDIR *** " +cp -pr templates/rootdir/* $ROOTDIR/ +cp templates/invoke.sh.in $ROOTDIR/invoke.sh +chmod a+rx $ROOTDIR/invoke.sh +cp templates/update.sh.in $ROOTDIR/update.sh +chmod a+rx $ROOTDIR/update.sh + +# This allows the updater to work! +cp -pr environments-and-requirements requirements.txt $ROOTDIR/ + +#-------------------------------------------------------------------------------- +echo +echo "*** Confguring InvokeAI ***" +pushd $ROOTDIR +./.venv/bin/configure_invokeai.py --root=$ROOTDIR +_err_exit $? "Initial configuration failed. Please see above error messages and $TROUBLESHOOTING for help." + +#-------------------------------------------------------------------------------- +popd +cp templates/invoke.sh.in $ROOTDIR/invoke.sh +chmod a+rx $ROOTDIR/invoke.sh + +cp templates/update.sh.in $ROOTDIR/update.sh +chmod a+rx $ROOTDIR/update.sh + +echo "You may now run InvokeAI by entering the directory $ROOTDIR and running invoke.sh" diff --git a/installer/readme.txt b/installer/readme.txt new file mode 100644 index 0000000000..44961b5c8b --- /dev/null +++ b/installer/readme.txt @@ -0,0 +1,52 @@ +InvokeAI + +Project homepage: https://github.com/invoke-ai/InvokeAI + +Preparations: + + You will need to install Python 3.9 or higher for this installer + to work. Instructions are given here: + https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ + + Before you start the installer, please open up your system's command + line window (Terminal or Command) and type the commands: + + python --version + + If all is well, it will print "Python 3.X.X", where the version number + is at least 3.9.1 + + If this works, check the version of the Python package manager, pip: + + pip --version + + You should get a message that indicates that the pip package + installer was derived from Python 3.9 or 3.10. For example: + "pip 22.3.1 from /usr/bin/pip (python 3.9)" + +Long Paths on Windows: + + If you are on Windows, you will need to enable Windows Long Paths to + run InvokeAI successfully. If you're not sure what this is, you + almost certainly need to do this. + + Simply double-click the "WinLongPathsEnabled.reg" file located in + this directory, and approve the Windows warnings. Note that you will + need to have admin privileges in order to do this. + +Launching the installer: + + Windows: double-click the 'install.bat' file (while keeping it inside + the InvokeAI-Installer folder). + + Linux and Mac: Please open the terminal application and run + './install.sh' (while keeping it inside the InvokeAI-Installer + folder). + +The installer will create a directory named "invokeai" in the folder +of your choice. This directory contains everything you need to run +invokeai. Once InvokeAI is up and running, you may delete the +InvokeAI-Installer folder at your convenience. + +For more information, please see +https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/ diff --git a/installer/templates/invoke.bat.in b/installer/templates/invoke.bat.in new file mode 100644 index 0000000000..19885d8467 --- /dev/null +++ b/installer/templates/invoke.bat.in @@ -0,0 +1,37 @@ +@echo off + +PUSHD "%~dp0" +setlocal + +call .venv\Scripts\activate.bat +set INVOKEAI_ROOT=. + +echo Do you want to generate images using the +echo 1. command-line +echo 2. browser-based UI +echo 3. open the developer console +set /P restore="Please enter 1, 2 or 3: " +IF /I "%restore%" == "1" ( + echo Starting the InvokeAI command-line.. + python .venv\Scripts\invoke.py %* +) ELSE IF /I "%restore%" == "2" ( + echo Starting the InvokeAI browser-based UI.. + python .venv\Scripts\invoke.py --web %* +) ELSE IF /I "%restore%" == "3" ( + echo Developer Console + echo Python command is: + where python + echo Python version is: + python --version + echo ************************* + echo You are now in the system shell, with the local InvokeAI Python virtual environment activated, + echo so that you can troubleshoot this InvokeAI installation as necessary. + echo ************************* + echo *** Type `exit` to quit this shell and deactivate the Python virtual environment *** + call cmd /k +) ELSE ( + echo Invalid selection + pause + exit /b +) +endlocal diff --git a/source_installer/invoke.sh.in b/installer/templates/invoke.sh.in old mode 100755 new mode 100644 similarity index 53% rename from source_installer/invoke.sh.in rename to installer/templates/invoke.sh.in index d2c9d1b0a5..214600fd00 --- a/source_installer/invoke.sh.in +++ b/installer/templates/invoke.sh.in @@ -1,19 +1,19 @@ #!/bin/bash -cd "$(dirname "${BASH_SOURCE[0]}")" +set -eu -INSTALL_ENV_DIR="$(pwd)/installer_files/env" -if [ -e "$INSTALL_ENV_DIR" ]; then export PATH="$INSTALL_ENV_DIR/bin:$PATH"; fi +# ensure we're in the correct folder in case user's CWD is somewhere else +scriptdir=$(dirname "$0") +cd "$scriptdir" -CONDA_BASEPATH=$(conda info --base) -source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # otherwise conda complains about 'shell not initialized' (needed when running in a script) +. .venv/bin/activate -conda activate invokeai +export INVOKEAI_ROOT="$scriptdir" # set required env var for torch on mac MPS -if [ "$(uname -s)" == "Darwin" ]; then - export PYTORCH_ENABLE_MPS_FALLBACK=1 -fi + if [ "$(uname -s)" == "Darwin" ]; then + export PYTORCH_ENABLE_MPS_FALLBACK=1 + fi if [ "$0" != "bash" ]; then echo "Do you want to generate images using the" @@ -22,8 +22,8 @@ if [ "$0" != "bash" ]; then echo "3. open the developer console" read -p "Please enter 1, 2, or 3: " yn case $yn in - 1 ) printf "\nStarting the InvokeAI command-line..\n"; python scripts/invoke.py $*;; - 2 ) printf "\nStarting the InvokeAI browser-based UI..\n"; python scripts/invoke.py --web $*;; + 1 ) printf "\nStarting the InvokeAI command-line..\n"; .venv/bin/python .venv/bin/invoke.py $*;; + 2 ) printf "\nStarting the InvokeAI browser-based UI..\n"; .venv/bin/python .venv/bin/invoke.py --web $*;; 3 ) printf "\nDeveloper Console:\n"; file_name=$(basename "${BASH_SOURCE[0]}"); bash --init-file "$file_name";; * ) echo "Invalid selection"; exit;; esac diff --git a/installer/templates/update.bat.in b/installer/templates/update.bat.in new file mode 100644 index 0000000000..15dd8b60ab --- /dev/null +++ b/installer/templates/update.bat.in @@ -0,0 +1,52 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +PUSHD "%~dp0" + +set INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/archive/main.zip +set arg=%1 +if "%arg%" neq "" ( + if "%arg:~0,4%" neq "http" ( + echo Usage: update.bat ^.zip + echo Updates InvokeAI to use the indicated version of the code base. + echo Find the zip file for the release you want, and pass it as the argument. + echo For example update.sh https://github.com/invoke-ai/InvokeAI/archive/refs/tags/v2.2.4.zip + echo. + echo If no argument provided then will install the most recent development version, equivalent to + echo update.bat https://github.com/invoke-ai/InvokeAI/archive/main.zip + exit /b + ) else ( + set INVOKE_AI_SRC=%arg% + ) +) + + +call .venv\Scripts\activate.bat + +echo This script will update InvokeAI and all its dependencies to !INVOKE_AI_SRC!. +echo If you do not want to do this, press control-C now! +pause + +call pip install -r requirements.txt +if %errorlevel% neq 0 ( + echo Installation of requirements failed. See https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting for suggestions. + exit /b +) + +call pip install !INVOKE_AI_SRC! +if %errorlevel% neq 0 ( + echo Installation of InvokeAI failed. See https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting for suggestions. + exit /b +) + +call .venv\Scripts\python .venv\Scripts\configure_invokeai.py --root="%rootdir%" + +if %errorlevel% neq 0 ( + echo Configuration InvokeAI failed. See https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting for suggestions. + exit /b +) + +echo "Press any key to continue" +pause +endlocal + diff --git a/installer/templates/update.sh.in b/installer/templates/update.sh.in new file mode 100644 index 0000000000..8931f32150 --- /dev/null +++ b/installer/templates/update.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash + +set -eu + +if [ $# -ge 1 ] && [ "${1:0:4}" != "http" ]; then + echo "Usage: update.sh .zip" + echo "Updates InvokeAI to use the indicated version of the code base." + echo "Find the zip file for the release you want, and pass it as the argument." + echo "For example update.sh https://github.com/invoke-ai/InvokeAI/archive/refs/tags/v2.2.3.zip" + echo "" + echo "If no argument provided then will install the most recent development version, equivalent to" + echo "update.sh https://github.com/invoke-ai/InvokeAI/archive/main.zip" + exit -1 +fi + +INVOKE_AI_SRC=${1:-https://github.com/invoke-ai/InvokeAI/archive/main.zip} + +# ensure we're in the correct folder in case user's CWD is somewhere else +scriptdir=$(dirname "$0") +cd "$scriptdir" + +function _err_exit { + if test "$1" -ne 0 + then + echo "Something went wrong while installing InvokeAI and/or its requirements." + echo "Update cannot continue. Please report this error to https://github.com/invoke-ai/InvokeAI/issues" + echo -e "Error code $1; Error caught was '$2'" + read -p "Press any key to exit..." + exit + fi +} + +echo This script will update InvokeAI and all its dependencies from $INVOKE_AI_SRC. +echo If you do not want to do this, press control-C now! +read -p "Press any key to continue, or CTRL-C to exit..." + +. .venv/bin/activate + +pip install -r requirements.txt +_err_exit $? "The pip program failed to install InvokeAI's requirements." + +pip install $INVOKE_AI_SRC +_err_exit $? "The pip program failed to install InvokeAI." + +python .venv/bin/configure_invoke.py +_err_exit $? "The configure script failed to run successfully." + + + + + + diff --git a/ldm/generate.py b/ldm/generate.py index c1dd5aa85f..ff8592d022 100644 --- a/ldm/generate.py +++ b/ldm/generate.py @@ -131,7 +131,6 @@ gr = Generate( """ - class Generate: """Generate class Stores default values for multiple configuration items diff --git a/ldm/invoke/CLI.py b/ldm/invoke/CLI.py index 518063ab19..c6b081eb9c 100644 --- a/ldm/invoke/CLI.py +++ b/ldm/invoke/CLI.py @@ -46,7 +46,6 @@ def main(): args.max_loaded_models = 1 # alert - setting globals here - Globals.root = os.path.expanduser(args.root_dir or os.environ.get('INVOKEAI_ROOT') or os.path.abspath('.')) Globals.try_patchmatch = args.patchmatch print(f'>> InvokeAI runtime directory is "{Globals.root}"') diff --git a/ldm/invoke/__init__.py b/ldm/invoke/__init__.py index e69de29bb2..f9a95b0343 100644 --- a/ldm/invoke/__init__.py +++ b/ldm/invoke/__init__.py @@ -0,0 +1 @@ +__version__='2.2.4' diff --git a/ldm/invoke/args.py b/ldm/invoke/args.py index c5d5ad6f1c..c5b1987924 100644 --- a/ldm/invoke/args.py +++ b/ldm/invoke/args.py @@ -119,7 +119,7 @@ PRECISION_CHOICES = [ # is there a way to pick this up during git commits? APP_ID = 'invoke-ai/InvokeAI' -APP_VERSION = 'v2.2.3' +APP_VERSION = 'v2.2.4' class ArgFormatter(argparse.RawTextHelpFormatter): # use defined argument order to display usage @@ -172,14 +172,20 @@ class Args(object): '''Parse the shell switches and store.''' try: sysargs = sys.argv[1:] - initfile = os.path.expanduser(Globals.initfile) + # pre-parse to get the root directory; ignore the rest + switches = self._arg_parser.parse_args(sysargs) + Globals.root = switches.root_dir or Globals.root + + # now use root directory to find the init file + initfile = os.path.expanduser(os.path.join(Globals.root,Globals.initfile)) + legacyinit = os.path.expanduser('~/.invokeai') if os.path.exists(initfile): print(f'>> Initialization file {initfile} found. Loading...') sysargs.insert(0,f'@{initfile}') - else: - from ldm.invoke.CLI import emergency_model_reconfigure - emergency_model_reconfigure() - sys.exit(-1) + elif os.path.exists(legacyinit): + print(f'>> WARNING: Old initialization file found at {legacyinit}. This location is deprecated. Please move it to {Globals.root}/invokeai.init.') + sysargs.insert(0,f'@{legacyinit}') + self._arg_switches = self._arg_parser.parse_args(sysargs) return self._arg_switches except Exception as e: @@ -411,7 +417,7 @@ class Args(object): model_group.add_argument( '--root_dir', default=None, - help='Path to directory containing "models", "outputs" and "configs". If not present will try to read from ~/.invokeai and then from environment variable INVOKEAI_ROOT. Defaults to the current directory as a last resort.', + help='Path to directory containing "models", "outputs" and "configs". If not present will read from environment variable INVOKEAI_ROOT. Defaults to ~/invokeai.', ) model_group.add_argument( '--config', diff --git a/ldm/invoke/globals.py b/ldm/invoke/globals.py index b29e9aa35d..2e9f9f14bd 100644 --- a/ldm/invoke/globals.py +++ b/ldm/invoke/globals.py @@ -16,10 +16,10 @@ from argparse import Namespace Globals = Namespace() # This is usually overwritten by the command line and/or environment variables -Globals.root = '.' +Globals.root = os.environ.get('INVOKEAI_ROOT') or os.path.expanduser('~/invokeai') # Where to look for the initialization file -Globals.initfile = os.path.expanduser('~/.invokeai') +Globals.initfile = 'invokeai.init' # Awkward workaround to disable attempted loading of pypatchmatch # which is causing CI tests to error out. diff --git a/scripts/configure_invokeai.py b/scripts/configure_invokeai.py index 864187830f..557746f0cf 100755 --- a/scripts/configure_invokeai.py +++ b/scripts/configure_invokeai.py @@ -40,7 +40,7 @@ Dataset_path = './configs/INITIAL_MODELS.yaml' Default_config_file = './configs/models.yaml' SD_Configs = './configs/stable-diffusion' -assert os.path.exists(Dataset_path),"The configs directory cannot be found. Please run this script from within the InvokeAI distribution directory, or from within the invokeai runtime directory." +assert os.path.exists(Dataset_path),"The configs directory cannot be found. Please run this script from within the invokeai runtime directory." Datasets = OmegaConf.load(Dataset_path) completer = generic_completer(['yes','no']) @@ -234,7 +234,7 @@ This involves a few easy steps. "Role" should be "read"). Now copy the token to your clipboard and paste it at the prompt. Windows - users can paste with right-click. + users can paste with right-click or Ctrl-Shift-V. Token: ''' ) access_token = getpass_asterisk.getpass_asterisk() @@ -580,22 +580,7 @@ def get_root(root:str=None)->str: elif os.environ.get('INVOKEAI_ROOT'): return os.environ.get('INVOKEAI_ROOT') else: - init_file = os.path.expanduser(Globals.initfile) - if not os.path.exists(init_file): - return None - - # if we get here, then we read from initfile - root = None - with open(init_file, 'r') as infile: - lines = infile.readlines() - for l in lines: - if re.search('\s*#',l): # ignore comments - continue - match = re.search('--root\s*=?\s*"?([^"]+)"?',l) - if match: - root = match.groups()[0] - root = root.strip() - return root + return Globals.root #------------------------------------- def select_root(root:str, yes_to_all:bool=False): @@ -626,18 +611,16 @@ def initialize_rootdir(root:str,yes_to_all:bool=False): print(f'** INITIALIZING INVOKEAI RUNTIME DIRECTORY **') root_selected = False while not root_selected: - root = select_root(root,yes_to_all) outputs = select_outputs(root,yes_to_all) - Globals.root = os.path.abspath(root) outputs = outputs if os.path.isabs(outputs) else os.path.abspath(os.path.join(Globals.root,outputs)) - print(f'\nInvokeAI models and configuration files will be placed into "{root}" and image outputs will be placed into "{outputs}".') + print(f'\nInvokeAI image outputs will be placed into "{outputs}".') if not yes_to_all: - root_selected = yes_or_no('Accept these locations?') + root_selected = yes_or_no('Accept this location?') else: root_selected = True - print(f'\nYou may change the chosen directories at any time by editing the --root and --outdir options in "{Globals.initfile}",') + print(f'\nYou may change the chosen output directory at any time by editing the --outdir options in "{Globals.initfile}",') print(f'You may also change the runtime directory by setting the environment variable INVOKEAI_ROOT.\n') enable_safety_checker = True @@ -651,6 +634,7 @@ def initialize_rootdir(root:str,yes_to_all:bool=False): print('It can be selectively enabled at run time with --nsfw_checker, and disabled with --no-nsfw_checker.') print('The following option will set whether the checker is enabled by default. Like other options, you can') print(f'change this setting later by editing the file {Globals.initfile}.') + print(f'The NSFW checker is a memory hog. If you have less than 6 GB of VRAM answer NO to this option.') enable_safety_checker = yes_or_no('Enable the NSFW checker by default?',enable_safety_checker) print('\nThe next choice selects the sampler to use by default. Samplers have different speed/performance') @@ -679,7 +663,7 @@ def initialize_rootdir(root:str,yes_to_all:bool=False): shutil.copytree(src,dest,dirs_exist_ok=True) os.makedirs(outputs, exist_ok=True) - init_file = os.path.expanduser(Globals.initfile) + init_file = os.path.join(Globals.root,Globals.initfile) print(f'Creating the initialization file at "{init_file}".\n') with open(init_file,'w') as f: @@ -688,9 +672,6 @@ def initialize_rootdir(root:str,yes_to_all:bool=False): # Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting # or renaming it and then running configure_invokeai.py again. -# The --root option below points to the folder in which InvokeAI stores its models, configs and outputs. ---root="{Globals.root}" - # the --outdir option controls the default location of image files. --outdir="{outputs}" @@ -757,7 +738,7 @@ def main(): # We check for to see if the runtime directory is correctly initialized. if Globals.root == '' \ - or not os.path.exists(os.path.join(Globals.root,'configs/stable-diffusion/v1-inference.yaml')): + or not os.path.exists(os.path.join(Globals.root,'invokeai.init')): initialize_rootdir(Globals.root,opt.yes_to_all) # Optimistically try to download all required assets. If any errors occur, add them and proceed anyway. diff --git a/setup.py b/setup.py index bfba829b4a..4ae036bd84 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ from setuptools import setup, find_packages def list_files(directory): return [os.path.join(directory,x) for x in os.listdir(directory) if os.path.isfile(os.path.join(directory,x))] -VERSION = '2.2.0' +VERSION = '2.2.4' DESCRIPTION = ('An implementation of Stable Diffusion which provides various new features' ' and options to aid the image generation process') LONG_DESCRIPTION = ('This version of Stable Diffusion features a slick WebGUI, an' diff --git a/source_installer/create_installers.sh b/source_installer/create_installers.sh deleted file mode 100755 index 24f8961f46..0000000000 --- a/source_installer/create_installers.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -cd "$(dirname "${BASH_SOURCE[0]}")" - -VERSION='2.2.3' - -# make the installer zip for linux and mac -rm -rf invokeAI -mkdir -p invokeAI -cp install.sh.in invokeAI/install.sh -chmod a+x invokeAI/install.sh -cp readme.txt invokeAI - -zip -r invokeAI-src-installer-$VERSION-linux.zip invokeAI -zip -r invokeAI-src-installer-$VERSION-mac.zip invokeAI - -# make the installer zip for windows -rm -rf invokeAI -mkdir -p invokeAI -cp install.bat.in invokeAI/install.bat -cp readme.txt invokeAI -cp WinLongPathsEnabled.reg invokeAI - -zip -r invokeAI-src-installer-$VERSION-windows.zip invokeAI - -rm -rf invokeAI -echo "The installer zips are ready to be distributed.." diff --git a/source_installer/install.bat.in b/source_installer/install.bat.in deleted file mode 100644 index ad05668e32..0000000000 --- a/source_installer/install.bat.in +++ /dev/null @@ -1,127 +0,0 @@ -@echo off - -@rem This script will install git and conda (if not found on the PATH variable) -@rem using micromamba (an 8mb static-linked single-file binary, conda replacement). -@rem For users who already have git and conda, this step will be skipped. - -@rem Next, it'll checkout the project's git repo, if necessary. -@rem Finally, it'll create the conda environment and configure InvokeAI. - -@rem This enables a user to install this project without manually installing conda and git. - -@rem change to the script's directory -PUSHD "%~dp0" - -echo "InvokeAI source installer..." -echo "" -echo "Some of the installation steps take a long time to run. Please be patient." -echo "If the script appears to hang for more than 10 minutes, please interrupt with control-C and retry." -echo "" -pause -echo "" - -@rem config -set MAMBA_ROOT_PREFIX=%cd%\installer_files\mamba -set INSTALL_ENV_DIR=%cd%\installer_files\env -set MICROMAMBA_DOWNLOAD_URL=https://github.com/cmdr2/stable-diffusion-ui/releases/download/v1.1/micromamba.exe -set REPO_URL=https://github.com/invoke-ai/InvokeAI.git -set umamba_exists=F -@rem Change the download URL to an InvokeAI repo's release URL - -@rem figure out whether git and conda needs to be installed -if exist "%INSTALL_ENV_DIR%" set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH% - -set PACKAGES_TO_INSTALL= - -call conda --version >.tmp1 2>.tmp2 -if "%ERRORLEVEL%" NEQ "0" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% conda - -call git --version >.tmp1 2>.tmp2 -if "%ERRORLEVEL%" NEQ "0" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% git - -call "%MAMBA_ROOT_PREFIX%\micromamba.exe" --version >.tmp1 2>.tmp2 -if "%ERRORLEVEL%" EQU "0" set umamba_exists=T - -@rem (if necessary) install git and conda into a contained environment -if "%PACKAGES_TO_INSTALL%" NEQ "" ( - @rem download micromamba - if "%umamba_exists%" == "F" ( - echo "Downloading micromamba from %MICROMAMBA_DOWNLOAD_URL% to %MAMBA_ROOT_PREFIX%\micromamba.exe" - - mkdir "%MAMBA_ROOT_PREFIX%" - call curl -L "%MICROMAMBA_DOWNLOAD_URL%" > "%MAMBA_ROOT_PREFIX%\micromamba.exe" - - @rem test the mamba binary - echo Micromamba version: - call "%MAMBA_ROOT_PREFIX%\micromamba.exe" --version - ) - - @rem create the installer env - if not exist "%INSTALL_ENV_DIR%" ( - call "%MAMBA_ROOT_PREFIX%\micromamba.exe" create -y --prefix "%INSTALL_ENV_DIR%" - ) - - echo "Packages to install:%PACKAGES_TO_INSTALL%" - - call "%MAMBA_ROOT_PREFIX%\micromamba.exe" install -y --prefix "%INSTALL_ENV_DIR%" -c conda-forge %PACKAGES_TO_INSTALL% - - if not exist "%INSTALL_ENV_DIR%" ( - echo "There was a problem while installing%PACKAGES_TO_INSTALL% using micromamba. Cannot continue." - pause - exit /b - ) -) - -set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH% - -@rem get the repo (and load into the current directory) -if not exist ".git" ( - call git init - call git config --local init.defaultBranch main - call git remote add origin %REPO_URL% - call git fetch - call git checkout origin/main -ft -) - -@rem activate the base env -call conda activate - -@rem create the environment -call conda env remove -n invokeai -copy environments-and-requirements\environment-win-cuda.yml environment.yml -call conda env create -if "%ERRORLEVEL%" NEQ "0" ( - echo "" - echo "Something went wrong while installing Python libraries and cannot continue." - echo "See https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#troubleshooting for troubleshooting" - echo "tips, or visit https://invoke-ai.github.io/InvokeAI/#installation for alternative" - echo "installation methods" - pause - exit /b -) - -copy source_installer\invoke.bat.in .\invoke.bat -copy source_installer\update.bat.in .\update.bat - -call conda activate invokeai -@rem call configure script -call python scripts\configure_invokeai.py -if "%ERRORLEVEL%" NEQ "0" ( - echo "" - echo "The configure script crashed or was cancelled." - echo "InvokeAI is not ready to run. To run preload_models.py again," - echo "run the command 'update.bat' in this directory." - echo "Press any key to continue" - pause - exit /b -) - -@rem tell the user their next steps -echo "" -echo "* InvokeAI installed successfully *" -echo "You can now start generating images by double-clicking the 'invoke.bat' file (inside this folder) -echo "Press any key to continue" -pause -exit /b - - diff --git a/source_installer/install.sh.in b/source_installer/install.sh.in deleted file mode 100755 index 56a712307a..0000000000 --- a/source_installer/install.sh.in +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env bash - -# This script will install git and conda (if not found on the PATH variable) -# using micromamba (an 8mb static-linked single-file binary, conda replacement). -# For users who already have git and conda, this step will be skipped. - -# Next, it'll checkout the project's git repo, if necessary. -# Finally, it'll create the conda environment and configure InvokeAI. - -# This enables a user to install this project without manually installing conda and git. - -cd "$(dirname "${BASH_SOURCE[0]}")" - -echo "InvokeAI source installer..." -echo "" -echo "Some of the installation steps take a long time to run. Please be patient." -echo "If the script appears to hang for more than 10 minutes, please interrupt with control-C and retry." -read -n 1 -s -r -p "" -echo "" - -OS_NAME=$(uname -s) -case "${OS_NAME}" in - Linux*) OS_NAME="linux";; - Darwin*) OS_NAME="osx";; - *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit -esac - -OS_ARCH=$(uname -m) -case "${OS_ARCH}" in - x86_64*) OS_ARCH="64";; - arm64*) OS_ARCH="arm64";; - *) echo "Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64" && exit -esac - -# https://mamba.readthedocs.io/en/latest/installation.html -if [ "$OS_NAME" == "linux" ] && [ "$OS_ARCH" == "arm64" ]; then OS_ARCH="aarch64"; fi - -# config -export MAMBA_ROOT_PREFIX="$(pwd)/installer_files/mamba" -INSTALL_ENV_DIR="$(pwd)/installer_files/env" -MICROMAMBA_DOWNLOAD_URL="https://micro.mamba.pm/api/micromamba/${OS_NAME}-${OS_ARCH}/latest" -REPO_URL="https://github.com/invoke-ai/InvokeAI.git" -umamba_exists="F" - -# figure out whether git and conda needs to be installed -if [ -e "$INSTALL_ENV_DIR" ]; then export PATH="$INSTALL_ENV_DIR/bin:$PATH"; fi - -PACKAGES_TO_INSTALL="" -if ! $(which conda) -V &>/dev/null; then PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL conda"; fi -if ! which git &>/dev/null; then PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL git"; fi - -if "$MAMBA_ROOT_PREFIX/micromamba" --version &>/dev/null; then umamba_exists="T"; fi - -# (if necessary) install git and conda into a contained environment -if [ "$PACKAGES_TO_INSTALL" != "" ]; then - # download micromamba - if [ "$umamba_exists" == "F" ]; then - echo "Downloading micromamba from $MICROMAMBA_DOWNLOAD_URL to $MAMBA_ROOT_PREFIX/micromamba" - - mkdir -p "$MAMBA_ROOT_PREFIX" - curl -L "$MICROMAMBA_DOWNLOAD_URL" | tar -xvjO bin/micromamba > "$MAMBA_ROOT_PREFIX/micromamba" - - chmod u+x "$MAMBA_ROOT_PREFIX/micromamba" - - # test the mamba binary - echo "Micromamba version:" - "$MAMBA_ROOT_PREFIX/micromamba" --version - fi - - # create the installer env - if [ ! -e "$INSTALL_ENV_DIR" ]; then - "$MAMBA_ROOT_PREFIX/micromamba" create -y --prefix "$INSTALL_ENV_DIR" - fi - - echo "Packages to install:$PACKAGES_TO_INSTALL" - - "$MAMBA_ROOT_PREFIX/micromamba" install -y --prefix "$INSTALL_ENV_DIR" -c conda-forge $PACKAGES_TO_INSTALL - - if [ ! -e "$INSTALL_ENV_DIR" ]; then - echo "There was a problem while initializing micromamba. Cannot continue." - exit - fi -fi - -if [ -e "$INSTALL_ENV_DIR" ]; then export PATH="$INSTALL_ENV_DIR/bin:$PATH"; fi - -# get the repo (and load into the current directory) -if [ ! -e ".git" ]; then - git init - git config --local init.defaultBranch main - git remote add origin "$REPO_URL" - git fetch - git checkout origin/main -ft -fi - -# create the environment -CONDA_BASEPATH=$(conda info --base) -source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # otherwise conda complains about 'shell not initialized' (needed when running in a script) - -conda activate -if [ "$OS_NAME" == "osx" ]; then - echo "macOS detected. Installing MPS and CPU support." - ln -sf environments-and-requirements/environment-mac.yml environment.yml -else - if (lsmod | grep amdgpu) &>/dev/null ; then - echo "Linux system with AMD GPU driver detected. Installing ROCm and CPU support" - ln -sf environments-and-requirements/environment-lin-amd.yml environment.yml - else - echo "Linux system detected. Installing CUDA and CPU support." - ln -sf environments-and-requirements/environment-lin-cuda.yml environment.yml - fi -fi -conda env update - -status=$? - -if test $status -ne 0 -then - if [ "$OS_NAME" == "osx" ]; then - echo "Python failed to install the environment. You may need to install" - echo "the Xcode command line tools to proceed. See step number 3 of" - echo "https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#walk_through for" - echo "installation instructions and then run this script again." - else - echo "Something went wrong while installing Python libraries and cannot continue." - echo "See https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#troubleshooting for troubleshooting" - echo "tips, or visit https://invoke-ai.github.io/InvokeAI/#installation for alternative" - echo "installation methods" - fi -else - cp ./source_installer/invoke.sh.in ./invoke.sh - cp ./source_installer/update.sh.in ./update.sh - chmod a+rx ./source_installer/invoke.sh.in - chmod a+rx ./source_installer/update.sh.in - - conda activate invokeai - # configure - echo "Calling the configure_invokeai script" - python scripts/configure_invokeai.py - status=$? - if test $status -ne 0 - then - echo "The configure_invoke.py script crashed or was cancelled." - echo "InvokeAI is not ready to run. Try again by running" - echo "update.sh in this directory." - else - # tell the user their next steps - echo "You can now start generating images by running invoke.sh (inside this folder), using ./invoke.sh" - fi -fi - -conda activate invokeai diff --git a/source_installer/invoke.bat.in b/source_installer/invoke.bat.in deleted file mode 100644 index fd1759105a..0000000000 --- a/source_installer/invoke.bat.in +++ /dev/null @@ -1,34 +0,0 @@ -@echo off - -REM isolate changes to environment variables so that this can be run again with restarting a cmd session -setlocal - -PUSHD "%~dp0" -set INSTALL_ENV_DIR=%cd%\installer_files\env -set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH% - -call conda activate invokeai - -echo Do you want to generate images using the -echo 1. command-line -echo 2. browser-based UI -echo 3. open the developer console -set /P restore="Please enter 1, 2 or 3: " -IF /I "%restore%" == "1" ( - echo Starting the InvokeAI command-line.. - python scripts\invoke.py %* -) ELSE IF /I "%restore%" == "2" ( - echo Starting the InvokeAI browser-based UI.. - python scripts\invoke.py --web %* -) ELSE IF /I "%restore%" == "3" ( - echo Developer Console - call where python - call python --version - - cmd /k -) ELSE ( - echo Invalid selection - pause - exit /b -) -endlocal diff --git a/source_installer/readme.txt b/source_installer/readme.txt deleted file mode 100644 index 8bfc0c9ce5..0000000000 --- a/source_installer/readme.txt +++ /dev/null @@ -1,16 +0,0 @@ -InvokeAI - -Project homepage: https://github.com/invoke-ai/InvokeAI - -Installation on Windows: - You may need to enable Windows Long Paths to install InvokeAI. If you're not - sure what this is, you almost certainly need to do this. Simply double-click the - "WinLongPathsEnabled.reg" file located in this directory, and approve the Windows - warnings. Note that you will need to have admin privileges in order to do this. - - Then double-click the 'install.bat' file (while keeping it inside the invokeAI folder). - -Installation on Linux and Mac: - Please open the terminal, and run './install.sh' (while keeping it inside the invokeAI folder). - -After installation, please run the 'invoke.bat' file (on Windows) or 'invoke.sh' file (on Linux/Mac) to start InvokeAI. diff --git a/source_installer/update.bat.in b/source_installer/update.bat.in deleted file mode 100644 index 5b01a4e85f..0000000000 --- a/source_installer/update.bat.in +++ /dev/null @@ -1,19 +0,0 @@ -@echo off - -set INSTALL_ENV_DIR=%cd%\installer_files\env -set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH% - -@rem update the repo -if exist ".git" ( - call git pull -) - - -conda env update -conda activate invokeai -python scripts/preload_models.py - -echo "Press any key to continue" -pause -exit 0 - diff --git a/source_installer/update.sh.in b/source_installer/update.sh.in deleted file mode 100755 index d634324760..0000000000 --- a/source_installer/update.sh.in +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - - -INSTALL_ENV_DIR="$(pwd)/installer_files/env" -if [ -e "$INSTALL_ENV_DIR" ]; then export PATH="$INSTALL_ENV_DIR/bin:$PATH"; fi - -# update the repo -if [ -e ".git" ]; then - git pull -fi - -CONDA_BASEPATH=$(conda info --base) -source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # otherwise conda complains about 'shell not initialized' (needed when running in a script) - -conda activate invokeai - -OS_NAME=$(uname -s) -case "${OS_NAME}" in - Linux*) conda env update;; - Darwin*) conda env update -f environment-mac.yml;; - *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit -esac - -python scripts/preload_models.py - - From b77f34998cf5048a11f34a7404aa1473cfc301ce Mon Sep 17 00:00:00 2001 From: AdamOStark Date: Mon, 5 Dec 2022 17:12:20 -0800 Subject: [PATCH 02/15] Responsive for devices under 600px This doesn't not work for the Canvas Painting yet, but works on img2img and text2img --- frontend/src/styles/Mixins/_Responsive.scss | 159 ++++++++++++++++++++ frontend/src/styles/Mixins/index.scss | 1 + 2 files changed, 160 insertions(+) create mode 100644 frontend/src/styles/Mixins/_Responsive.scss diff --git a/frontend/src/styles/Mixins/_Responsive.scss b/frontend/src/styles/Mixins/_Responsive.scss new file mode 100644 index 0000000000..1213e088c3 --- /dev/null +++ b/frontend/src/styles/Mixins/_Responsive.scss @@ -0,0 +1,159 @@ +@media (max-width: 600px) { + #root{ + .app-content{ + padding: 5px; + .site-header { + position: fixed; + display: flex; + height: 100px; + z-index: 1; + .site-header-left-side{ + position: absolute; + display: flex; + min-width: 145px; + float: left; + padding-left: 0; + } + .site-header-right-side{ + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; + grid-template-rows: 25px 25px 25px; + grid-template-areas: 'logoSpace logoSpace logoSpace sampler sampler sampler' + 'status status status status status status' + 'btn1 btn2 btn3 btn4 btn5 btn6'; + row-gap: 15px; + .chakra-popover__popper{ + grid-area: logoSpace; + } + > :nth-child(1).chakra-text{ + grid-area: status; + width: 100%; + display: flex; + justify-content: center; + } + > :nth-child(2){ + grid-area: sampler; + display: flex; + justify-content: center; + align-items: center; + select{ + width: 185px; + margin-top: 10px; + } + .chakra-select__icon-wrapper{ + right:10px; + svg{ + margin-top: 10px; + } + } + } + > :nth-child(3){ + grid-area: btn1; + } + > :nth-child(4){ + grid-area: btn2; + } + > :nth-child(6){ + grid-area: btn3; + } + > :nth-child(7){ + grid-area: btn4; + } + > :nth-child(8){ + grid-area: btn5; + } + > :nth-child(9){ + grid-area: btn6; + } + + } + } + .app-tabs{ + position: fixed; + display: flex; + flex-direction: column; + row-gap: 15px; + max-width: 100%; + overflow: hidden; + margin-top: 120px; + .app-tabs-list{ + display: flex; + justify-content: space-between; + } + .app-tabs-panels{ + overflow: hidden; + overflow-y: scroll; + .workarea-main{ + display: grid; + grid-template-areas: 'workarea' + 'options' + 'gallery'; + row-gap: 15px; + .options-panel-wrapper{ + grid-area: options; + width: 100%; + max-width: 100%; + height: inherit; + overflow: inherit; + padding: 0 10px; + .main-options-row{ + max-width: 100%; + } + .advanced-settings-item{ + max-width: 100%; + } + } + .workarea-children-wrapper{ + grid-area: workarea; + .workarea-split-view{ + display: flex; + flex-direction: column; + } + .current-image-options{ + column-gap: 3px; + } + .text-to-image-area{ + padding: 0; + } + .current-image-preview { + height: 430px; + } + + //image 2 image + .image-upload-button { + row-gap: 10px; + padding: 5px; + svg { + width: 2rem; + height: 2rem; + margin-top: 10px; + } + } + + //Cavas Painting + .inpainting-settings{ + display: flex; + flex-wrap: wrap; + row-gap: 10px; + } + .inpainting-canvas-area{ + .konvajs-content{ + height: 400px !important; + } + } + } + .image-gallery-wrapper{ + grid-area: gallery; + min-height: 400px; + .image-gallery-popup{ + width: 100% !important; + max-width: 100% !important; + } + } + } + } + } + } + } +} + diff --git a/frontend/src/styles/Mixins/index.scss b/frontend/src/styles/Mixins/index.scss index 53cf03adf2..8a3639d2bc 100644 --- a/frontend/src/styles/Mixins/index.scss +++ b/frontend/src/styles/Mixins/index.scss @@ -1,3 +1,4 @@ @forward './Shared'; @forward './Buttons'; @forward './Variables'; +@forward './Responsive'; \ No newline at end of file From 09365d6d2e4613119b330854394cb7b5621ded4f Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Mon, 12 Dec 2022 00:53:40 +1300 Subject: [PATCH 03/15] Fix GUI not working (#1916) --- backend/invoke_ai_web_server.py | 3 +-- binary_installer/requirements.in | 2 +- environments-and-requirements/requirements-base.txt | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/invoke_ai_web_server.py b/backend/invoke_ai_web_server.py index cf5922d7af..d91d66e5be 100644 --- a/backend/invoke_ai_web_server.py +++ b/backend/invoke_ai_web_server.py @@ -209,10 +209,9 @@ class InvokeAIWebServer: FlaskUI( app=self.app, socketio=self.socketio, - start_server="flask-socketio", + server="flask_socketio", width=1600, height=1000, - idle_interval=10, port=self.port ).run() except KeyboardInterrupt: diff --git a/binary_installer/requirements.in b/binary_installer/requirements.in index 3161603eab..b4436a6ec0 100644 --- a/binary_installer/requirements.in +++ b/binary_installer/requirements.in @@ -8,7 +8,7 @@ diffusers eventlet flask_cors flask_socketio -flaskwebgui +flaskwebgui==1.0.3 getpass_asterisk imageio-ffmpeg pyreadline3 diff --git a/environments-and-requirements/requirements-base.txt b/environments-and-requirements/requirements-base.txt index b8f20cead4..1301f72323 100644 --- a/environments-and-requirements/requirements-base.txt +++ b/environments-and-requirements/requirements-base.txt @@ -8,7 +8,7 @@ facexlib flask==2.1.3 flask_cors==3.0.10 flask_socketio==5.3.0 -flaskwebgui==0.3.7 +flaskwebgui==1.0.3 getpass_asterisk gfpgan==1.3.8 huggingface-hub From aa68e4e0da641361fe0866e550009ccd738ead4c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 11 Dec 2022 22:54:15 +1100 Subject: [PATCH 04/15] Adds polyfill for `Array.prototype.findLast()` (#1909) --- frontend/dist/assets/index-legacy-4f120d5f.js | 48 ++ frontend/dist/assets/index.637f12bd.js | 623 ------------------ frontend/dist/assets/index.6f857312.js | 623 ++++++++++++++++++ .../dist/assets/polyfills-legacy-dde3a68a.js | 4 + frontend/dist/assets/polyfills.1ff60148.js | 1 + frontend/dist/index.html | 9 +- frontend/package.json | 2 + frontend/vite.config.ts | 16 +- frontend/yarn.lock | 82 ++- 9 files changed, 778 insertions(+), 630 deletions(-) create mode 100644 frontend/dist/assets/index-legacy-4f120d5f.js delete mode 100644 frontend/dist/assets/index.637f12bd.js create mode 100644 frontend/dist/assets/index.6f857312.js create mode 100644 frontend/dist/assets/polyfills-legacy-dde3a68a.js create mode 100644 frontend/dist/assets/polyfills.1ff60148.js diff --git a/frontend/dist/assets/index-legacy-4f120d5f.js b/frontend/dist/assets/index-legacy-4f120d5f.js new file mode 100644 index 0000000000..78a1f407c2 --- /dev/null +++ b/frontend/dist/assets/index-legacy-4f120d5f.js @@ -0,0 +1,48 @@ +!function(){function e(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}System.register([],(function(t,n){"use strict";var r=document.createElement("style");return r.textContent="@font-face{font-family:Inter;src:url("+new URL("Inter.b9a8e5e2.ttf",n.meta.url).href+");font-display:swap;font-weight:400;font-style:normal}@font-face{font-family:Inter;src:url("+new URL("Inter-Bold.790c108b.ttf",n.meta.url).href+');font-display:swap;font-weight:600;font-style:normal}@keyframes slideOut{0%{transform:translate(10rem)}to{transform:translate(0)}}@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.1)}to{transform:scale(1)}}[data-theme=dark]{--white: rgb(255, 255, 255);--accent-color-dim: rgb(57, 25, 153);--accent-color: rgb(80, 40, 200);--accent-color-bright: rgb(104, 60, 230);--accent-color-hover: var(--accent-color-bright);--root-bg-color: rgb(10, 10, 10);--background-color: rgb(26, 26, 32);--background-color-light: rgb(40, 44, 48);--background-color-secondary: rgb(16, 16, 22);--text-color: rgb(255, 255, 255);--text-color-secondary: rgb(160, 162, 188);--subtext-color: rgb(24, 24, 34);--subtext-color-bright: rgb(48, 48, 64);--border-color: rgb(30, 30, 46);--border-color-light: rgb(60, 60, 76);--svg-color: rgb(255, 255, 255);--invalid: rgb(255, 75, 75);--invalid-secondary: rgb(120, 5, 5);--destructive-color: rgb(185, 55, 55);--destructive-color-hover: rgb(255, 75, 75);--warning-color: rgb(200, 88, 40);--warning-color-hover: rgb(230, 117, 60);--border-color-invalid: rgb(255, 80, 50);--box-shadow-color-invalid: rgb(210, 30, 10);--tab-color: rgb(30, 32, 42);--tab-hover-color: rgb(46, 48, 58);--tab-panel-bg: rgb(36, 38, 48);--tab-list-bg: var(--accent-color);--tab-list-text: rgb(202, 204, 216);--tab-list-text-inactive: rgb(92, 94, 114);--btn-base-color: rgb(30, 32, 42);--btn-base-color-hover: rgb(46, 48, 68);--btn-load-more: rgb(30, 32, 42);--btn-load-more-hover: rgb(54, 56, 66);--btn-svg-color: rgb(255, 255, 255);--btn-delete-image: rgb(182, 46, 46);--btn-checkbox-border-hover: rgb(46, 48, 68);--progress-bar-color: var(--accent-color);--prompt-bg-color: rgb(10, 10, 10);--switch-bg-color: rgb(100, 102, 110);--switch-bg-active-color: var(--accent-color);--slider-color: var(--accent-color-bright);--slider-color: rgb(151, 113, 255);--resizeable-handle-border-color: var(--accent-color);--metadata-bg-color: rgba(0, 0, 0, .7);--metadata-json-bg-color: rgba(255, 255, 255, .1);--status-good-color: rgb(125, 255, 100);--status-good-glow: rgb(40, 215, 40);--status-working-color: rgb(255, 175, 55);--status-working-glow: rgb(255, 160, 55);--status-bad-color: rgb(255, 90, 90);--status-bad-glow: rgb(255, 40, 40);--settings-modal-bg: rgb(30, 32, 42);--input-checkbox-bg: rgb(60, 64, 68);--input-checkbox-checked-bg: var(--accent-color);--input-checkbox-checked-tick: rgb(0, 0, 0);--input-border-color: var(--accent-color-bright);--input-box-shadow-color: var(--accent-color);--error-level-info: rgb(200, 202, 224);--error-level-warning: rgb(255, 225, 105);--error-level-error: rgb(255, 81, 46);--console-bg-color: rgb(30, 30, 36);--console-icon-button-bg-color: rgb(50, 53, 64);--console-icon-button-bg-color-hover: rgb(70, 73, 84);--img2img-img-bg-color: rgb(30, 32, 42);--context-menu-bg-color: rgb(46, 48, 58);--context-menu-box-shadow: none;--context-menu-bg-color-hover: rgb(30, 32, 42);--floating-button-drop-shadow-color: var(--accent-color);--inpainting-alerts-bg: rgba(20, 20, 26, .75);--inpainting-alerts-icon-color: rgb(255, 255, 255);--inpainting-alerts-bg-active: var(--accent-color);--inpainting-alerts-icon-active: rgb(255, 255, 255);--inpainting-alerts-bg-alert: var(--invalid);--inpainting-alerts-icon-alert: rgb(255, 255, 255);--checkboard-dots-color: rgb(35, 35, 39)}[data-theme=light]{--white: rgb(255, 255, 255);--accent-color-dim: rgb(186, 146, 0);--accent-color: rgb(235, 185, 5);--accent-color-bright: rgb(255, 200, 0);--accent-color-hover: var(--accent-color-bright);--root-bg-color: rgb(255, 255, 255);--background-color: rgb(220, 222, 224);--background-color-light: rgb(250, 252, 254);--background-color-secondary: rgb(208, 210, 212);--text-color: rgb(0, 0, 0);--text-color-secondary: rgb(40, 40, 40);--subtext-color: rgb(24, 24, 34);--subtext-color-bright: rgb(142, 144, 146);--border-color: rgb(200, 200, 200);--border-color-light: rgb(147, 147, 147);--svg-color: rgb(50, 50, 50);--invalid: rgb(255, 75, 75);--invalid-secondary: rgb(120, 5, 5);--destructive-color: rgb(237, 51, 51);--destructive-color-hover: rgb(255, 55, 55);--warning-color: rgb(224, 142, 42);--warning-color-hover: rgb(255, 167, 60);--border-color-invalid: rgb(255, 80, 50);--box-shadow-color-invalid: none;--tab-color: rgb(202, 204, 206);--tab-hover-color: rgb(196, 198, 200);--tab-panel-bg: rgb(206, 208, 210);--tab-list-bg: rgb(235, 185, 5);--tab-list-text: rgb(0, 0, 0);--tab-list-text-inactive: rgb(106, 108, 110);--btn-base-color: rgb(184, 186, 188);--btn-base-color-hover: rgb(230, 232, 234);--btn-load-more: rgb(202, 204, 206);--btn-load-more-hover: rgb(178, 180, 182);--btn-svg-color: rgb(0, 0, 0);--btn-delete-image: rgb(213, 49, 49);--btn-checkbox-border-hover: rgb(176, 178, 182);--progress-bar-color: rgb(235, 185, 5);--prompt-bg-color: rgb(225, 227, 229);--switch-bg-color: rgb(178, 180, 182);--switch-bg-active-color: rgb(235, 185, 5);--slider-color: rgb(0, 0, 0);--resizeable-handle-border-color: rgb(160, 162, 164);--metadata-bg-color: rgba(230, 230, 230, .9);--metadata-json-bg-color: rgba(0, 0, 0, .1);--status-good-color: rgb(21, 126, 0);--status-good-glow: var(--background-color);--status-working-color: rgb(235, 141, 0);--status-working-glow: var(--background-color);--status-bad-color: rgb(202, 0, 0);--status-bad-glow: var(--background-color);--settings-modal-bg: rgb(202, 204, 206);--input-checkbox-bg: rgb(167, 167, 171);--input-checkbox-checked-bg: rgb(235, 185, 5);--input-checkbox-checked-tick: rgb(0, 0, 0);--input-border-color: rgb(0, 0, 0);--input-box-shadow-color: none;--error-level-info: rgb(42, 42, 42);--error-level-warning: rgb(173, 121, 0);--error-level-error: rgb(145, 14, 0);--console-bg-color: rgb(220, 224, 230);--console-icon-button-bg-color: var(--switch-bg-color);--console-icon-button-bg-color-hover: var(--resizeable-handle-border-color);--img2img-img-bg-color: rgb(180, 182, 184);--context-menu-bg-color: var(--background-color);--context-menu-box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, .35), 0px 10px 20px -15px rgba(22, 23, 24, .2);--context-menu-bg-color-hover: var(--background-color-secondary);--floating-button-drop-shadow-color: rgba(0, 0, 0, .7);--inpainting-alerts-bg: rgba(220, 222, 224, .75);--inpainting-alerts-icon-color: rgb(0, 0, 0);--inpainting-alerts-bg-active: rgb(255, 200, 0);--inpainting-alerts-icon-active: rgb(0, 0, 0);--inpainting-alerts-bg-alert: var(--invalid);--inpainting-alerts-icon-alert: rgb(0, 0, 0);--checkboard-dots-color: rgb(160, 160, 172)}[data-theme=green]{--white: rgb(255, 255, 255);--accent-color-dim: rgb(10, 60, 40);--accent-color: rgb(20, 110, 70);--accent-color-bright: rgb(30, 180, 100);--accent-color-hover: var(--accent-color-bright);--root-bg-color: rgb(10, 10, 14);--background-color: rgb(30, 32, 37);--background-color-light: rgb(40, 44, 48);--background-color-secondary: rgb(22, 24, 28);--text-color: rgb(255, 255, 255);--text-color-secondary: rgb(160, 164, 168);--subtext-color: rgb(24, 24, 28);--subtext-color-bright: rgb(68, 72, 76);--border-color: rgb(40, 44, 48);--border-color-light: rgb(60, 60, 64);--svg-color: rgb(220, 224, 228);--invalid: rgb(255, 75, 75);--invalid-secondary: rgb(120, 5, 5);--destructive-color: rgb(185, 55, 55);--destructive-color-hover: rgb(255, 75, 75);--warning-color: rgb(200, 88, 40);--warning-color-hover: rgb(230, 117, 60);--border-color-invalid: rgb(255, 80, 50);--box-shadow-color-invalid: rgb(210, 30, 10);--tab-color: rgb(40, 44, 48);--tab-hover-color: rgb(48, 52, 56);--tab-panel-bg: rgb(36, 40, 44);--tab-list-bg: var(--accent-color);--tab-list-text: rgb(202, 204, 206);--tab-list-text-inactive: rgb(92, 94, 96);--btn-base-color: rgb(40, 44, 48);--btn-base-color-hover: rgb(56, 60, 64);--btn-load-more: rgb(30, 32, 42);--btn-load-more-hover: rgb(54, 56, 66);--btn-svg-color: rgb(255, 255, 255);--btn-delete-image: rgb(182, 46, 46);--btn-checkbox-border-hover: rgb(46, 48, 68);--progress-bar-color: var(--accent-color);--prompt-bg-color: rgb(10, 10, 14);--switch-bg-color: rgb(100, 102, 110);--switch-bg-active-color: var(--accent-color);--slider-color: var(--accent-color-bright);--resizeable-handle-border-color: var(--accent-color);--metadata-bg-color: rgba(0, 0, 0, .7);--metadata-json-bg-color: rgba(255, 255, 255, .1);--status-good-color: rgb(125, 255, 100);--status-good-glow: rgb(40, 215, 40);--status-working-color: rgb(255, 175, 55);--status-working-glow: rgb(255, 160, 55);--status-bad-color: rgb(255, 90, 90);--status-bad-glow: rgb(255, 40, 40);--settings-modal-bg: rgb(30, 32, 42);--input-checkbox-bg: rgb(60, 64, 68);--input-checkbox-checked-bg: var(--accent-color);--input-checkbox-checked-tick: rgb(0, 0, 0);--input-border-color: var(--accent-color-bright);--input-box-shadow-color: var(--accent-color);--error-level-info: rgb(200, 202, 224);--error-level-warning: rgb(255, 225, 105);--error-level-error: rgb(255, 81, 46);--console-bg-color: rgb(30, 30, 36);--console-icon-button-bg-color: rgb(50, 53, 64);--console-icon-button-bg-color-hover: rgb(70, 73, 84);--img2img-img-bg-color: rgb(30, 32, 42);--context-menu-bg-color: rgb(46, 48, 58);--context-menu-box-shadow: none;--context-menu-bg-color-hover: rgb(30, 32, 42);--floating-button-drop-shadow-color: var(--accent-color);--inpainting-alerts-bg: rgba(20, 20, 26, .75);--inpainting-alerts-icon-color: rgb(255, 255, 255);--inpainting-alerts-bg-active: var(--accent-color);--inpainting-alerts-icon-active: rgb(255, 255, 255);--inpainting-alerts-bg-alert: var(--invalid);--inpainting-alerts-icon-alert: rgb(255, 255, 255);--checkboard-dots-color: rgb(35, 35, 39)}svg{fill:var(--svg-color)}.App{display:grid;width:100vw;height:100vh;background-color:var(--background-color)}.app-content{display:grid;row-gap:1rem;padding:1rem;grid-auto-rows:min-content auto;width:calc(100vw + -0px);height:calc(100vh - .3rem)}.site-header{display:grid;grid-template-columns:auto max-content}.site-header-left-side{display:flex;align-items:center;column-gap:.7rem;padding-left:.5rem}.site-header-left-side img{width:32px;height:32px}.site-header-left-side h1{font-size:1.4rem}.site-header-right-side{display:flex;align-items:center;column-gap:.5rem}.status{font-size:.8rem;font-weight:700}.status-good{color:var(--status-good-color);text-shadow:0 0 10px var(--status-good-glow)}.status-bad{color:var(--status-bad-color);text-shadow:0 0 10px var(--status-bad-glow)}.status-working{color:var(--status-working-color);text-shadow:0 0 10px var(--status-working-glow)}.settings-modal{max-height:36rem;font-family:Inter}.settings-modal .settings-modal-content{display:grid;row-gap:2rem;overflow-y:scroll}.settings-modal .settings-modal-header{font-weight:700}.settings-modal .settings-modal-items{display:grid;row-gap:.5rem}.settings-modal .settings-modal-items .settings-modal-item{display:grid;grid-auto-flow:column;background-color:var(--background-color);padding:.4rem 1rem;border-radius:.5rem;align-items:center;width:100%}.settings-modal .settings-modal-reset{display:grid;row-gap:1rem}.settings-modal .settings-modal-reset button{min-width:100%;min-height:100%;background-color:var(--destructive-color)!important}.settings-modal .settings-modal-reset button:hover{background-color:var(--destructive-color-hover)}.settings-modal .settings-modal-reset button:disabled{background-color:var(--btn-base-color)}.settings-modal .settings-modal-reset button:disabled:hover{background-color:var(--btn-base-color)}.settings-modal .settings-modal-reset button svg{width:20px;height:20px;color:var(--btn-svg-color)}.model-list-accordion{outline:none;padding:.25rem}.model-list-accordion button{padding:0;margin:0}.model-list-accordion button:hover{background-color:unset}.model-list-accordion div{border:none}.model-list-accordion .model-list-button{display:flex;flex-direction:row;row-gap:.5rem;justify-content:space-between;align-items:center;width:100%}.model-list-accordion .model-list-header-hint{color:var(--text-color-secondary);font-weight:400}.model-list-accordion .model-list-list{display:flex;flex-direction:column;row-gap:.5rem}.model-list-accordion .model-list-list .model-list-item{display:flex;column-gap:.5rem;width:100%;justify-content:space-between;align-items:center}.model-list-accordion .model-list-list .model-list-item .model-list-item-description{font-size:.9rem}.model-list-accordion .model-list-list .model-list-item .model-list-item-status.active{color:var(--status-good-color)}.model-list-accordion .model-list-list .model-list-item .model-list-item-status.cached{color:var(--status-working-color)}.model-list-accordion .model-list-list .model-list-item .model-list-item-status.not-loaded{color:var(--text-color-secondary)}.model-list-accordion .model-list-list .model-list-item .model-list-item-load-btn button{padding:.5rem;background-color:var(--btn-base-color);color:var(--text-color);border-radius:.2rem}.model-list-accordion .model-list-list .model-list-item .model-list-item-load-btn button:hover{background-color:var(--btn-base-color-hover)}.hotkeys-modal{width:36rem;max-width:36rem;display:grid;padding:1rem;row-gap:1rem;font-family:Inter}.hotkeys-modal h1{font-size:1.2rem;font-weight:700}.hotkeys-modal h2{font-weight:700}.hotkeys-modal-button{display:flex;align-items:center;justify-content:space-between}.hotkeys-modal-items{max-height:36rem;overflow-y:scroll;-ms-overflow-style:none;scrollbar-width:none}.hotkeys-modal-items::-webkit-scrollbar{display:none}.hotkeys-modal-items .chakra-accordion{display:grid;row-gap:.5rem}.hotkeys-modal-items .chakra-accordion__item{border:none;border-radius:.3rem;background-color:var(--tab-hover-color)}.hotkeys-modal-items button{border-radius:.3rem}.hotkeys-modal-items button[aria-expanded=true]{background-color:var(--tab-hover-color);border-radius:.3rem}.hotkey-modal-category{display:grid;row-gap:.5rem}.hotkey-modal-item{display:grid;grid-template-columns:auto max-content;justify-content:space-between;align-items:center;background-color:var(--background-color);padding:.5rem 1rem;border-radius:.3rem}.hotkey-modal-item .hotkey-info{display:grid}.hotkey-modal-item .hotkey-info .hotkey-title{font-weight:700}.hotkey-modal-item .hotkey-info .hotkey-description{font-size:.9rem;color:var(--text-color-secondary)}.hotkey-modal-item .hotkey-key{font-size:.8rem;font-weight:700;background-color:var(--background-color-light);padding:.2rem .5rem;border-radius:.3rem}.console{width:100vw;display:flex;flex-direction:column;background:var(--console-bg-color);overflow:auto;direction:column;font-family:monospace;padding:0 1rem 1rem 3rem;border-top-width:.3rem;border-color:var(--resizeable-handle-border-color)}.console .console-info-color{color:var(--error-level-info)}.console .console-warning-color{color:var(--error-level-warning)}.console .console-error-color{color:var(--status-bad-color)}.console .console-entry{display:flex;column-gap:.5rem}.console .console-entry .console-timestamp{font-weight:semibold}.console .console-entry .console-message{word-break:break-all}.console-toggle-icon-button{background:var(--console-icon-button-bg-color);position:fixed;left:.5rem;bottom:.5rem;z-index:10000}.console-toggle-icon-button:hover{background:var(--console-icon-button-bg-color-hover)}.console-toggle-icon-button[data-error-seen=true],.console-toggle-icon-button[data-error-seen=true]:hover{background:var(--status-bad-color)}.console-autoscroll-icon-button{background:var(--console-icon-button-bg-color);position:fixed;left:.5rem;bottom:3rem;z-index:10000}.console-autoscroll-icon-button:hover{background:var(--console-icon-button-bg-color-hover)}.console-autoscroll-icon-button[data-autoscroll-enabled=true]{background:var(--accent-color)}.console-autoscroll-icon-button[data-autoscroll-enabled=true]:hover{background:var(--accent-color-hover)}.prompt-bar{display:grid;row-gap:1rem}.prompt-bar input,.prompt-bar textarea{background-color:var(--prompt-bg-color);font-size:1rem;border:2px solid var(--border-color)}.prompt-bar input:hover,.prompt-bar textarea:hover{border:2px solid var(--border-color-light)}.prompt-bar input:focus-visible,.prompt-bar textarea:focus-visible{border:2px solid var(--input-border-color);box-shadow:0 0 10px 0 var(--input-box-shadow-color)}.prompt-bar input[aria-invalid=true],.prompt-bar textarea[aria-invalid=true]{border:2px solid var(--border-color-invalid);box-shadow:0 0 10px 0 var(--box-shadow-color-invalid)}.prompt-bar input:disabled,.prompt-bar textarea:disabled{border:2px solid var(--border-color);box-shadow:none}.prompt-bar textarea{min-height:10rem}.process-buttons{display:flex;column-gap:.5rem}.invoke-btn{flex-grow:1;width:100%;min-width:100%;min-height:100%;background-color:var(--accent-color)!important}.invoke-btn:hover{background-color:var(--accent-color-hover)}.invoke-btn:disabled{background-color:var(--btn-base-color)}.invoke-btn:disabled:hover{background-color:var(--btn-base-color)}.invoke-btn svg{width:16px;height:16px;color:var(--btn-svg-color)}.cancel-btn{min-width:3rem;min-height:100%;background-color:var(--destructive-color)!important}.cancel-btn:hover{background-color:var(--destructive-color-hover)}.cancel-btn:disabled{background-color:var(--btn-base-color)}.cancel-btn:disabled:hover{background-color:var(--btn-base-color)}.cancel-btn svg{width:20px;height:20px;color:var(--btn-svg-color)}.loopback-btn[data-as-checkbox=true]{background-color:var(--btn-btn-base-color);border:3px solid var(--btn-btn-base-color)}.loopback-btn[data-as-checkbox=true] svg{fill:var(--text-color)}.loopback-btn[data-as-checkbox=true]:hover{background-color:var(--btn-btn-base-color);border-color:var(--btn-checkbox-border-hover)}.loopback-btn[data-as-checkbox=true]:hover svg{fill:var(--text-color)}.loopback-btn[data-as-checkbox=true][data-selected=true]{border-color:var(--accent-color);background-color:var(--btn-btn-base-color)}.loopback-btn[data-as-checkbox=true][data-selected=true] svg{fill:var(--text-color)}.loopback-btn[data-as-checkbox=true][data-selected=true]:hover{border-color:var(--accent-color);background-color:var(--btn-btn-base-color)}.loopback-btn[data-as-checkbox=true][data-selected=true]:hover svg{fill:var(--text-color)}.main-options,.main-options-list{display:grid;row-gap:1rem}.main-options-row{display:grid;grid-template-columns:repeat(3,auto);column-gap:.5rem;max-width:22.5rem}.main-option-block{border-radius:.5rem;display:grid!important;grid-template-columns:auto!important;row-gap:.5rem}.main-option-block .invokeai__number-input-form-label,.main-option-block .invokeai__select-label{font-weight:700;font-size:.9rem!important}.main-option-block .invokeai__select-label{margin:0}.advanced-options-checkbox{background-color:var(--background-color-secondary);padding:.5rem 1rem;border-radius:.4rem;font-weight:700}.advanced-settings{padding-top:.5rem;display:grid;row-gap:.5rem}.advanced-settings-item{display:grid;max-width:22.5rem;border:none;border-top:0px;border-radius:.4rem;background-color:var(--tab-panel-bg)}.advanced-settings-item[aria-expanded=true]{background-color:var(--tab-hover-color);border-radius:0 0 .4rem .4rem}.advanced-settings-panel{background-color:var(--tab-panel-bg);border-radius:0 0 .4rem .4rem;padding:1rem}.advanced-settings-panel button{background-color:var(--btn-base-color)}.advanced-settings-panel button:hover{background-color:var(--btn-base-color-hover)}.advanced-settings-panel button:disabled:hover{background-color:var(--btn-base-color)}.advanced-settings-header{border-radius:.4rem;font-weight:700}.advanced-settings-header[aria-expanded=true]{background-color:var(--tab-hover-color);border-radius:.4rem .4rem 0 0}.advanced-settings-header:hover{background-color:var(--tab-hover-color)}.upscale-options{display:grid;grid-template-columns:auto 1fr;column-gap:1rem}.inpainting-bounding-box-settings{display:flex;flex-direction:column;border-radius:.4rem;border:2px solid var(--tab-color)}.inpainting-bounding-box-header{background-color:var(--tab-color);display:flex;flex-direction:row;justify-content:space-between;padding:.5rem 1rem;border-radius:.3rem .3rem 0 0;align-items:center}.inpainting-bounding-box-header button{width:.5rem;height:1.2rem;background:none}.inpainting-bounding-box-header button:hover{background:none}.inpainting-bounding-box-settings-items{padding:1rem;display:flex;flex-direction:column;row-gap:1rem}.inpainting-bounding-box-settings-items .inpainting-bounding-box-reset-icon-btn{background-color:var(--btn-base-color)}.inpainting-bounding-box-settings-items .inpainting-bounding-box-reset-icon-btn:hover{background-color:var(--btn-base-color-hover)}.inpainting-bounding-box-dimensions-slider-numberinput{display:grid;grid-template-columns:repeat(3,auto);column-gap:1rem}.inpainting-bounding-box-darken{width:max-content}.progress-bar{background-color:var(--root-bg-color);height:.3rem;z-index:99}.progress-bar div{background-color:var(--progress-bar-color)}.progress-bar div[data-indeterminate]{background-color:unset;background-image:linear-gradient(to right,transparent 0%,var(--progress-bar-color) 50%,transparent 100%)}.current-image-area{display:flex;flex-direction:column;height:100%;row-gap:1rem;background-color:var(--background-color-secondary);border-radius:.5rem}.current-image-preview{position:relative;justify-content:center;align-items:center;display:flex;width:100%;height:100%}.current-image-preview img{border-radius:.5rem;object-fit:contain;max-width:100%;max-height:100%;height:auto;position:absolute}.current-image-metadata{grid-area:current-image-preview}.current-image-next-prev-buttons{grid-area:current-image-content;display:flex;justify-content:space-between;z-index:1;height:100%;width:100%;pointer-events:none}.next-prev-button-trigger-area{width:7rem;height:100%;width:15%;display:grid;align-items:center;pointer-events:auto}.next-prev-button-trigger-area.prev-button-trigger-area{justify-content:flex-start}.next-prev-button-trigger-area.next-button-trigger-area{justify-content:flex-end}.next-prev-button{font-size:4rem;fill:var(--white);filter:drop-shadow(0 0 1rem var(--text-color-secondary));opacity:70%}.current-image-display-placeholder{background-color:var(--background-color-secondary);display:grid;display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:.5rem}.current-image-display-placeholder svg{width:10rem;height:10rem;color:var(--svg-color)}.current-image-options{width:100%;display:flex;justify-content:center;align-items:center;column-gap:.5em}.current-image-options .current-image-send-to-popover,.current-image-options .current-image-postprocessing-popover{display:flex;flex-direction:column;row-gap:.5rem;max-width:25rem}.current-image-options .current-image-send-to-popover .invokeai__button{place-content:start}.current-image-options .chakra-popover__popper{z-index:11}.current-image-options .delete-image-btn{background-color:var(--btn-base-color)}.current-image-options .delete-image-btn svg{fill:var(--btn-delete-image)}.image-gallery-wrapper-enter{transform:translate(150%)}.image-gallery-wrapper-enter-active{transform:translate(0);transition:all .12s ease-out}.image-gallery-wrapper-exit{transform:translate(0)}.image-gallery-wrapper-exit-active{transform:translate(150%);transition:all .12s ease-out}.image-gallery-wrapper[data-pinned=false]{position:fixed;height:100vh;top:0;right:0}.image-gallery-wrapper[data-pinned=false] .image-gallery-popup{border-radius:0;box-shadow:0 0 1rem var(--text-color-a3)}.image-gallery-wrapper[data-pinned=false] .image-gallery-popup .image-gallery-container{max-height:calc(100vh + 4.7rem)}.image-gallery-wrapper .image-gallery-popup{background-color:var(--background-color-secondary);padding:1rem;display:flex;flex-direction:column;row-gap:1rem;border-radius:.5rem;border-left-width:.3rem;border-color:var(--tab-list-text-inactive)}.image-gallery-wrapper .image-gallery-popup[data-resize-alert=true]{border-color:var(--status-bad-color)}.image-gallery-wrapper .image-gallery-popup .image-gallery-header{display:flex;align-items:center;column-gap:.5rem;justify-content:space-between}.image-gallery-wrapper .image-gallery-popup .image-gallery-header .image-gallery-header-right-icons{display:flex;flex-direction:row;column-gap:.5rem}.image-gallery-wrapper .image-gallery-popup .image-gallery-header .image-gallery-icon-btn{background-color:var(--btn-load-more)}.image-gallery-wrapper .image-gallery-popup .image-gallery-header .image-gallery-icon-btn:hover{background-color:var(--btn-load-more-hover)}.image-gallery-wrapper .image-gallery-popup .image-gallery-header .image-gallery-settings-popover{display:flex;flex-direction:column;row-gap:.5rem}.image-gallery-wrapper .image-gallery-popup .image-gallery-header .image-gallery-settings-popover div{display:flex;column-gap:.5rem;align-items:center;justify-content:space-between}.image-gallery-wrapper .image-gallery-popup .image-gallery-header h1{font-weight:700}.image-gallery-wrapper .image-gallery-popup .image-gallery-container{display:flex;flex-direction:column;max-height:calc(100vh - (70px + 7rem));overflow-y:scroll;-ms-overflow-style:none;scrollbar-width:none}.image-gallery-wrapper .image-gallery-popup .image-gallery-container::-webkit-scrollbar{display:none}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-container-placeholder{display:flex;flex-direction:column;row-gap:.5rem;background-color:var(--background-color);border-radius:.5rem;place-items:center;padding:2rem;text-align:center}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-container-placeholder p{color:var(--subtext-color-bright);font-family:Inter}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-container-placeholder svg{width:4rem;height:4rem;color:var(--svg-color)}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-load-more-btn{background-color:var(--btn-load-more);font-size:.85rem;padding:.5rem;margin-top:1rem}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-load-more-btn:disabled:hover{background-color:var(--btn-load-more)}.image-gallery-wrapper .image-gallery-popup .image-gallery-container .image-gallery-load-more-btn:hover{background-color:var(--btn-load-more-hover)}.image-gallery-category-btn-group{width:max-content;column-gap:0;justify-content:stretch}.image-gallery-category-btn-group button{background-color:var(--btn-base-color);flex-grow:1}.image-gallery-category-btn-group button:hover{background-color:var(--btn-base-color-hover)}.image-gallery-category-btn-group button[data-selected=true]{background-color:var(--accent-color)}.image-gallery-category-btn-group button[data-selected=true]:hover{background-color:var(--accent-color-hover)}.image-gallery{display:grid;grid-gap:.5rem}.image-gallery .hoverable-image{padding:.5rem;position:relative}.image-gallery .hoverable-image:before{content:"";display:block;padding-bottom:100%}.image-gallery .hoverable-image .hoverable-image-image{position:absolute;max-width:100%;top:50%;left:50%;transform:translate(-50%,-50%)}.hoverable-image{display:flex;justify-content:center;transition:transform .2s ease-out}.hoverable-image:hover{cursor:pointer;border-radius:.5rem;z-index:2}.hoverable-image .hoverable-image-image{width:100%;height:100%;max-width:100%;max-height:100%}.hoverable-image .hoverable-image-delete-button{position:absolute;top:.25rem;right:.25rem}.hoverable-image .hoverable-image-content{display:flex;position:absolute;top:0;left:0;width:100%;height:100%;align-items:center;justify-content:center}.hoverable-image .hoverable-image-content .hoverable-image-check{fill:var(--status-good-color)}.hoverable-image .hoverable-image-icons{position:absolute;bottom:-2rem;display:grid;width:min-content;grid-template-columns:repeat(2,max-content);border-radius:.4rem;background-color:var(--background-color-secondary);padding:.2rem;gap:.2rem;grid-auto-rows:max-content}.hoverable-image .hoverable-image-icons button{width:12px;height:12px;border-radius:.2rem;padding:10px 0;flex-shrink:2}.hoverable-image .hoverable-image-icons button svg{width:12px;height:12px}.hoverable-image-context-menu{z-index:15;padding:.4rem;border-radius:.25rem;background-color:var(--context-menu-bg-color);box-shadow:var(--context-menu-box-shadow)}.hoverable-image-context-menu [role=menuitem]{font-size:.8rem;line-height:1rem;border-radius:3px;display:flex;align-items:center;height:1.75rem;padding:0 .5rem;position:relative;user-select:none;cursor:pointer;outline:none}.hoverable-image-context-menu [role=menuitem][data-disabled]{color:gray;pointer-events:none;cursor:not-allowed}.hoverable-image-context-menu [role=menuitem][data-warning]{color:var(--status-bad-color)}.hoverable-image-context-menu [role=menuitem][data-highlighted]{background-color:var(--context-menu-bg-color-hover)}.image-metadata-viewer{position:absolute;top:0;width:100%;border-radius:.5rem;padding:1rem;background-color:var(--metadata-bg-color);overflow:scroll;max-height:calc(100vh - (70px + 5.4rem));height:100%;z-index:10}.image-json-viewer{border-radius:.5rem;margin:0 .5rem 1rem;padding:1rem;overflow-x:scroll;word-break:break-all;background-color:var(--metadata-json-bg-color)}.lightbox-container{width:100%;height:100%;color:var(--text-color);overflow:hidden;position:absolute;left:0;top:0;background-color:var(--background-color-secondary);z-index:30;animation:popIn .3s ease-in}.lightbox-container .image-gallery-wrapper{max-height:100%!important}.lightbox-container .image-gallery-wrapper .image-gallery-container{max-height:calc(100vh - 5rem)}.lightbox-container .current-image-options{z-index:2;position:absolute;top:1rem}.lightbox-container .image-metadata-viewer{left:0;max-height:100%}.lightbox-close-btn{z-index:3;position:absolute;left:1rem;top:1rem;background-color:var(--btn-base-color)}.lightbox-close-btn:hover{background-color:var(--btn-base-color-hover)}.lightbox-close-btn:disabled:hover{background-color:var(--btn-base-color)}.lightbox-display-container{display:flex;flex-direction:row}.lightbox-preview-wrapper{overflow:hidden;background-color:var(--background-color-secondary);display:grid;grid-template-columns:auto max-content;place-items:center;width:100vw;height:100vh}.lightbox-preview-wrapper .current-image-next-prev-buttons{position:absolute}.lightbox-preview-wrapper .lightbox-image{grid-area:lightbox-content;border-radius:.5rem}.lightbox-preview-wrapper .lightbox-image-options{position:absolute;z-index:2;left:1rem;top:4.5rem;user-select:none;border-radius:.5rem;display:flex;flex-direction:column;row-gap:.5rem}@keyframes popIn{0%{opacity:0;filter:blur(100)}to{opacity:1;filter:blur(0)}}.app-tabs{display:grid;grid-template-columns:min-content auto;column-gap:1rem;height:calc(100vh - (70px + 1rem))}.app-tabs-list{display:grid;row-gap:.3rem;grid-auto-rows:min-content;color:var(--tab-list-text-inactive)}.app-tabs-list button{font-size:.85rem;padding:.5rem}.app-tabs-list button:hover{background-color:var(--tab-hover-color);border-radius:.3rem}.app-tabs-list button svg{width:26px;height:26px}.app-tabs-list button[aria-selected=true]{background-color:var(--tab-list-bg);color:var(--tab-list-text);font-weight:700;border-radius:.3rem;border:none}.app-tabs-panels .app-tabs-panel{padding:0;height:100%}.workarea-wrapper{position:relative;width:100%;height:100%}.workarea-wrapper .workarea-main{display:flex;column-gap:1rem;height:100%}.workarea-wrapper .workarea-main .workarea-children-wrapper{position:relative;width:100%;height:100%}.workarea-wrapper .workarea-main .workarea-split-view{width:100%;height:100%;display:grid;grid-template-columns:1fr 1fr;background-color:var(--background-color-secondary);border-radius:.5rem}.workarea-wrapper .workarea-main .workarea-split-view .workarea-split-view-left{padding-right:.5rem}.workarea-wrapper .workarea-main .workarea-split-view .workarea-split-view-right{padding-left:.5rem}.workarea-wrapper .workarea-main .workarea-single-view{width:100%;height:100%;background-color:var(--background-color-secondary);border-radius:.5rem}.workarea-wrapper .workarea-main .workarea-split-view-left,.workarea-wrapper .workarea-main .workarea-split-view-right{display:flex;flex-direction:column;height:100%;width:100%;row-gap:1rem;background-color:var(--background-color-secondary);border-radius:.5rem;padding:1rem}.workarea-split-button{position:absolute;cursor:pointer;padding:.5rem;top:0;right:0}.workarea-split-button[data-selected=true]{top:0;right:0}.workarea-split-button[data-selected=true] svg{opacity:1}.workarea-split-button svg{opacity:.5}.options-panel-wrapper-enter{transform:translate(-150%)}.options-panel-wrapper-enter-active{transform:translate(0);transition:all .12s ease-out}.options-panel-wrapper-exit{transform:translate(0)}.options-panel-wrapper-exit-active{transform:translate(-150%);transition:all .12s ease-out}.options-panel-wrapper{background-color:var(--background-color);height:calc(100vh - (70px + 1rem));width:22.5rem;max-width:22.5rem;flex-shrink:0;position:relative;overflow-y:scroll;-ms-overflow-style:none;scrollbar-width:none}.options-panel-wrapper::-webkit-scrollbar{display:none}.options-panel-wrapper .options-panel{display:flex;flex-direction:column;row-gap:1rem;height:100%;-ms-overflow-style:none;scrollbar-width:none;background-color:var(--background-color)}.options-panel-wrapper .options-panel::-webkit-scrollbar{display:none}.options-panel-wrapper[data-pinned=false]{z-index:20;position:fixed;top:0;left:0;filter:var(--floating-panel-drop-shadow);width:24.5rem;max-width:24.5rem;height:100%}.options-panel-wrapper[data-pinned=false] .options-panel-margin{margin:1rem}.options-panel-wrapper .options-panel-pin-button{position:absolute;cursor:pointer;padding:.5rem;top:1rem;right:1rem;z-index:20}.options-panel-wrapper .options-panel-pin-button[data-selected=true]{top:0;right:0}.options-panel-wrapper .options-panel-pin-button svg{opacity:.5}.invoke-ai-logo-wrapper{display:flex;align-items:center;column-gap:.7rem;padding-left:.5rem;padding-top:.3rem}.invoke-ai-logo-wrapper img{width:32px;height:32px}.invoke-ai-logo-wrapper h1{font-size:1.4rem}.text-to-image-area{padding:1rem;height:100%}.image-to-image-area{display:flex;flex-direction:column;row-gap:1rem;width:100%;height:100%}.image-to-image-strength-main-option{display:flex;row-gap:.5rem!important}.image-to-image-strength-main-option .invokeai__slider-component-label{color:var(--text-color-secondary);font-size:.9rem!important}.init-image-preview-header{display:flex;align-items:center;justify-content:space-between;width:100%}.init-image-preview-header h2{font-weight:700;font-size:.9rem}.init-image-preview{position:relative;height:100%;width:100%;display:flex;align-items:center;justify-content:center}.init-image-preview img{border-radius:.5rem;object-fit:contain;position:absolute}.image-to-image-current-image-display{position:relative}.floating-show-hide-button{position:absolute;top:50%;transform:translateY(-50%);z-index:20;padding:0;background-color:red!important;min-width:2rem;min-height:12rem;background-color:var(--btn-btn-base-color)!important}.floating-show-hide-button.left{left:0;border-radius:0 .5rem .5rem 0}.floating-show-hide-button.right{right:0;border-radius:.5rem 0 0 .5rem}.floating-show-hide-button:hover{background-color:var(--btn-btn-base-color-hover)}.floating-show-hide-button:disabled{background-color:var(--btn-base-color)}.floating-show-hide-button:disabled:hover{background-color:var(--btn-base-color)}.floating-show-hide-button svg{width:20px;height:20px;color:var(--btn-svg-color)}.show-hide-button-options{position:absolute;transform:translateY(-50%);z-index:20;min-width:2rem;top:50%;left:calc(42px + 2rem);border-radius:0 .5rem .5rem 0;display:flex;flex-direction:column;row-gap:.5rem}.show-hide-button-options button{border-radius:0 .3rem .3rem 0}.show-hide-button-gallery{padding-left:.75rem;padding-right:.75rem;background-color:var(--background-color)!important}.inpainting-main-area{display:flex;flex-direction:column;align-items:center;row-gap:1rem;width:100%;height:100%}.inpainting-main-area .inpainting-settings{display:flex;align-items:center;column-gap:.5rem}.inpainting-main-area .inpainting-settings svg{transform:scale(.9)}.inpainting-main-area .inpainting-settings .inpainting-buttons-group{display:flex;align-items:center;column-gap:.5rem}.inpainting-main-area .inpainting-settings .inpainting-button-dropdown{display:flex;flex-direction:column;row-gap:.5rem}.inpainting-main-area .inpainting-settings .inpainting-color-picker{margin-left:1rem}.inpainting-main-area .inpainting-settings .inpainting-brush-options{display:flex;align-items:center;column-gap:1rem}.inpainting-main-area .inpainting-canvas-area{display:flex;flex-direction:column;align-items:center;justify-content:center;row-gap:1rem;width:100%;height:100%}.inpainting-main-area .inpainting-canvas-spiner{display:flex;align-items:center;width:100%;height:100%}.inpainting-main-area .inpainting-canvas-container{display:flex;align-items:center;justify-content:center;height:100%;width:100%;border-radius:.5rem}.inpainting-main-area .inpainting-canvas-container .inpainting-canvas-wrapper{position:relative}.inpainting-main-area .inpainting-canvas-container .inpainting-canvas-stage{outline:none;border-radius:.5rem;box-shadow:0 0 0 1px var(--border-color-light);overflow:hidden}.inpainting-main-area .inpainting-canvas-container .inpainting-canvas-stage canvas{outline:none;border-radius:.5rem}.inpainting-options-btn{min-height:2rem}.canvas-status-text{position:absolute;top:0;left:0;background-color:var(--background-color);opacity:.65;display:flex;flex-direction:column;font-size:.8rem;padding:.25rem;min-width:12rem;border-radius:.25rem;margin:.25rem;pointer-events:none}.invokeai__number-input-form-control{display:flex;align-items:center;column-gap:1rem}.invokeai__number-input-form-control .invokeai__number-input-form-label{color:var(--text-color-secondary);margin-right:0;font-size:1rem;margin-bottom:0;white-space:nowrap}.invokeai__number-input-form-control .invokeai__number-input-form-label[data-focus]+.invokeai__number-input-root{outline:none;border:2px solid var(--input-border-color);box-shadow:0 0 10px 0 var(--input-box-shadow-color)}.invokeai__number-input-form-control .invokeai__number-input-form-label[aria-invalid=true]+.invokeai__number-input-root{outline:none;border:2px solid var(--border-color-invalid);box-shadow:0 0 10px 0 var(--box-shadow-color-invalid)}.invokeai__number-input-form-control .invokeai__number-input-root{height:2rem;display:grid;grid-template-columns:auto max-content;column-gap:.5rem;align-items:center;background-color:var(--background-color-secondary);border:2px solid var(--border-color);border-radius:.3rem}.invokeai__number-input-form-control .invokeai__number-input-field{border:none;font-weight:700;width:100%;height:auto;font-size:.9rem;padding:0 .5rem}.invokeai__number-input-form-control .invokeai__number-input-field:focus{outline:none;box-shadow:none}.invokeai__number-input-form-control .invokeai__number-input-field:disabled{opacity:.2}.invokeai__number-input-form-control .invokeai__number-input-stepper{display:grid;padding-right:.5rem}.invokeai__number-input-form-control .invokeai__number-input-stepper .invokeai__number-input-stepper-button{border:none;padding:0 .5rem;margin:0 -.5rem}.invokeai__number-input-form-control .invokeai__number-input-stepper .invokeai__number-input-stepper-button svg{width:10px;height:10px}.input{display:grid;grid-template-columns:max-content auto;column-gap:1rem;align-items:center}.input .input-label{color:var(--text-color-secondary);margin-right:0}.input .input-entry{background-color:var(--background-color-secondary);border:2px solid var(--border-color);border-radius:.2rem;font-weight:700}.input .input-entry:focus{outline:none;border:2px solid var(--input-border-color);box-shadow:0 0 10px 0 var(--input-box-shadow-color)}.input .input-entry:disabled{opacity:.2}.input .input-entry[aria-invalid=true]{outline:none;border:2px solid var(--border-color-invalid);box-shadow:0 0 10px 0 var(--box-shadow-color-invalid)}.invokeai__icon-button{background:var(--btn-base-color);cursor:pointer}.invokeai__icon-button:hover{background-color:var(--btn-base-color-hover)}.invokeai__icon-button[data-selected=true]{background-color:var(--accent-color)}.invokeai__icon-button[data-selected=true]:hover{background-color:var(--accent-color-hover)}.invokeai__icon-button[disabled]{cursor:not-allowed}.invokeai__icon-button[data-variant=link],.invokeai__icon-button[data-variant=link]:hover{background:none}.invokeai__icon-button[data-as-checkbox=true]{background-color:var(--btn-base-color);border:3px solid var(--btn-base-color)}.invokeai__icon-button[data-as-checkbox=true] svg{fill:var(--text-color)}.invokeai__icon-button[data-as-checkbox=true]:hover{background-color:var(--btn-base-color);border-color:var(--btn-checkbox-border-hover)}.invokeai__icon-button[data-as-checkbox=true]:hover svg{fill:var(--text-color)}.invokeai__icon-button[data-as-checkbox=true][data-selected=true]{border-color:var(--accent-color)}.invokeai__icon-button[data-as-checkbox=true][data-selected=true] svg{fill:var(--accent-color-hover)}.invokeai__icon-button[data-as-checkbox=true][data-selected=true]:hover svg{fill:var(--accent-color-hover)}.invokeai__icon-button[data-alert=true]{animation-name:pulseColor;animation-duration:1s;animation-timing-function:ease-in-out;animation-iteration-count:infinite}.invokeai__icon-button[data-alert=true]:hover{animation:none;background-color:var(--accent-color-hover)}@keyframes pulseColor{0%{background-color:var(--accent-color)}50%{background-color:var(--accent-color-dim)}to{background-color:var(--accent-color)}}.invokeai__button{background-color:var(--btn-base-color);place-content:center}.invokeai__button:hover{background-color:var(--btn-base-color-hover)}.invokeai__switch-form-control .invokeai__switch-form-label{display:flex;column-gap:1rem;justify-content:space-between;align-items:center;color:var(--text-color-secondary);font-size:1rem;margin-right:0;margin-bottom:.1rem;white-space:nowrap;width:auto}.invokeai__switch-form-control .invokeai__switch-form-label .invokeai__switch-root span{background-color:var(--switch-bg-color)}.invokeai__switch-form-control .invokeai__switch-form-label .invokeai__switch-root span span{background-color:var(--white)}.invokeai__switch-form-control .invokeai__switch-form-label .invokeai__switch-root[data-checked] span{background:var(--switch-bg-active-color)}.invokeai__switch-form-control .invokeai__switch-form-label .invokeai__switch-root[data-checked] span span{background-color:var(--white)}.invokeai__select{display:flex;column-gap:1rem;align-items:center}.invokeai__select .invokeai__select-label{color:var(--text-color-secondary);margin-right:0}.invokeai__select .invokeai__select-picker{border:2px solid var(--border-color);background-color:var(--background-color-secondary);font-weight:700;font-size:.9rem;height:2rem;border-radius:.2rem}.invokeai__select .invokeai__select-picker:focus{outline:none;border:2px solid var(--input-border-color);box-shadow:0 0 10px 0 var(--input-box-shadow-color)}.invokeai__select .invokeai__select-option{background-color:var(--background-color-secondary);color:var(--text-color-secondary)}.invokeai__slider-component{display:flex;gap:1rem;align-items:center}.invokeai__slider-component .invokeai__slider-component-label{min-width:max-content;margin:0;font-weight:700;font-size:.9rem;color:var(--text-color-secondary)}.invokeai__slider-component .invokeai__slider_track{background-color:var(--tab-color)}.invokeai__slider-component .invokeai__slider_track-filled{background-color:var(--slider-color)}.invokeai__slider-component .invokeai__slider-thumb{width:4px}.invokeai__slider-component .invokeai__slider-mark{font-size:.75rem;font-weight:700;color:var(--slider-color);margin-top:.3rem}.invokeai__slider-component .invokeai__slider-number-input{border:none;font-size:.9rem;font-weight:700;height:2rem;background-color:var(--background-color-secondary);border:2px solid var(--border-color)}.invokeai__slider-component .invokeai__slider-number-input:focus{outline:none;box-shadow:none;border:2px solid var(--input-border-color);box-shadow:0 0 10px 0 var(--input-box-shadow-color)}.invokeai__slider-component .invokeai__slider-number-input:disabled{opacity:.2}.invokeai__slider-component .invokeai__slider-number-stepper{border:none}.invokeai__slider-component[data-markers=true] .invokeai__slider_container{margin-top:-1rem}.invokeai__checkbox .chakra-checkbox__label{margin-top:1px;color:var(--text-color-secondary);font-size:.9rem}.invokeai__checkbox .chakra-checkbox__control{width:1rem;height:1rem;border:none;border-radius:.2rem;background-color:var(--input-checkbox-bg)}.invokeai__checkbox .chakra-checkbox__control svg{width:.6rem;height:.6rem;stroke-width:3px}.invokeai__checkbox .chakra-checkbox__control[data-checked]{color:var(--text-color);background-color:var(--input-checkbox-checked-bg)}.invokeai__popover-content{min-width:unset;width:unset;padding:1rem;border-radius:.5rem;background-color:var(--background-color);border:2px solid var(--border-color)}.invokeai__popover-content .invokeai__popover-arrow{background-color:var(--background-color)!important}.invokeai__color-picker .react-colorful__hue-pointer,.invokeai__color-picker .react-colorful__saturation-pointer{width:1.5rem;height:1.5rem;border-color:var(--white)}.dropzone-container{position:absolute;top:0;left:0;width:100vw;height:100vh;z-index:999;backdrop-filter:blur(20px)}.dropzone-container .dropzone-overlay{opacity:.5;width:100%;height:100%;display:flex;flex-direction:column;row-gap:1rem;align-items:center;justify-content:center;background-color:var(--background-color)}.dropzone-container .dropzone-overlay.is-drag-accept{box-shadow:inset 0 0 20rem 1rem var(--accent-color)}.dropzone-container .dropzone-overlay.is-drag-reject{box-shadow:inset 0 0 20rem 1rem var(--status-bad-color)}.dropzone-container .dropzone-overlay.is-handling-upload{box-shadow:inset 0 0 20rem 1rem var(--status-working-color)}.image-uploader-button-outer{width:100%;height:100%;display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:.5rem;color:var(--tab-list-text-inactive);background-color:var(--background-color)}.image-uploader-button-outer:hover{background-color:var(--background-color-light)}.image-upload-button-inner{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.image-upload-button{display:flex;flex-direction:column;row-gap:2rem;align-items:center;justify-content:center;text-align:center}.image-upload-button svg{width:4rem;height:4rem}.image-upload-button h2{font-size:1.2rem}.work-in-progress{display:grid;width:100%;height:calc(100vh - (70px + 1rem));grid-auto-rows:max-content;background-color:var(--background-color-secondary);border-radius:.4rem;place-content:center;place-items:center;row-gap:1rem}.work-in-progress h1{font-size:2rem;font-weight:700}.work-in-progress p{text-align:center;max-width:50rem;color:var(--subtext-color-bright)}.guide-popover-arrow{background-color:var(--tab-panel-bg);box-shadow:none}.guide-popover-content{background-color:var(--background-color-secondary);border:none}.guide-popover-guide-content{background:var(--tab-panel-bg);border:2px solid var(--tab-hover-color);border-radius:.4rem;padding:.75rem 1rem;display:grid;grid-template-rows:repeat(auto-fill,1fr);grid-row-gap:.5rem;justify-content:space-between}.modal{background-color:var(--background-color-secondary);color:var(--text-color)}.modal-close-btn{background-color:var(--btn-base-color)}.modal-close-btn:hover{background-color:var(--btn-base-color-hover)}.modal-close-btn:disabled:hover{background-color:var(--btn-base-color)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body{-ms-overflow-style:none;scrollbar-width:none;background-color:var(--root-bg-color);overflow:hidden}html::-webkit-scrollbar,body::-webkit-scrollbar{display:none}#root{background-color:var(--root-bg-color);color:var(--text-color);font-family:Inter,Arial,Helvetica,sans-serif}\n',document.head.appendChild(r),{execute:function(){function t(e,t){for(var n=0;nr[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}var r="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function o(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var i={exports:{}},a={},s=Symbol.for("react.element"),l=Symbol.for("react.portal"),c=Symbol.for("react.fragment"),u=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),h=Symbol.for("react.provider"),f=Symbol.for("react.context"),p=Symbol.for("react.forward_ref"),g=Symbol.for("react.suspense"),m=Symbol.for("react.memo"),v=Symbol.for("react.lazy"),b=Symbol.iterator;var y={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},x=Object.assign,w={};function S(e,t,n){this.props=e,this.context=t,this.refs=w,this.updater=n||y}function k(){}function C(e,t,n){this.props=e,this.context=t,this.refs=w,this.updater=n||y}S.prototype.isReactComponent={},S.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},S.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},k.prototype=S.prototype;var _=C.prototype=new k;_.constructor=C,x(_,S.prototype),_.isPureReactComponent=!0;var E=Array.isArray,L=Object.prototype.hasOwnProperty,P={current:null},M={key:!0,ref:!0,__self:!0,__source:!0};function A(e,t,n){var r,o={},i=null,a=null;if(null!=t)for(r in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(i=""+t.key),t)L.call(t,r)&&!M.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(1===l)o.children=n;else if(1>>1,i=e[r];if(!(0>>1;ro(l,n))co(u,l)?(e[r]=u,e[c]=n,r=c):(e[r]=l,e[s]=n,r=s);else{if(!(co(u,n)))break e;e[r]=u,e[c]=n,r=c}}}return t}function o(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;e.unstable_now=function(){return i.now()}}else{var a=Date,s=a.now();e.unstable_now=function(){return a.now()-s}}var l=[],c=[],u=1,d=null,h=3,f=!1,p=!1,g=!1,m="function"==typeof setTimeout?setTimeout:null,v="function"==typeof clearTimeout?clearTimeout:null,b="undefined"!=typeof setImmediate?setImmediate:null;function y(e){for(var o=n(c);null!==o;){if(null===o.callback)r(c);else{if(!(o.startTime<=e))break;r(c),o.sortIndex=o.expirationTime,t(l,o)}o=n(c)}}function x(e){if(g=!1,y(e),!p)if(null!==n(l))p=!0,O(w);else{var t=n(c);null!==t&&I(x,t.startTime-e)}}function w(t,o){p=!1,g&&(g=!1,v(_),_=-1),f=!0;var i=h;try{for(y(o),d=n(l);null!==d&&(!(d.expirationTime>o)||t&&!P());){var a=d.callback;if("function"==typeof a){d.callback=null,h=d.priorityLevel;var s=a(d.expirationTime<=o);o=e.unstable_now(),"function"==typeof s?d.callback=s:d===n(l)&&r(l),y(o)}else r(l);d=n(l)}if(null!==d)var u=!0;else{var m=n(c);null!==m&&I(x,m.startTime-o),u=!1}return u}finally{d=null,h=i,f=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var S,k=!1,C=null,_=-1,E=5,L=-1;function P(){return!(e.unstable_now()-Le||125a?(r.sortIndex=i,t(c,r),null===n(l)&&r===n(c)&&(g?(v(_),_=-1):g=!0,I(x,i-a))):(r.sortIndex=s,t(l,r),p||f||(p=!0,O(w))),r},e.unstable_shouldYield=P,e.unstable_wrapCallback=function(e){var t=h;return function(){var n=h;h=t;try{return e.apply(this,arguments)}finally{h=n}}}}(G),function(e){e.exports=G}($); +/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +var q=i.exports,Z=$.exports;function Y(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n