mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Compare commits
168 Commits
feat/restr
...
v2.3.3-rc3
Author | SHA1 | Date | |
---|---|---|---|
41a8fdea53 | |||
8e2fd4c96a | |||
2f424f29a0 | |||
90f00db032 | |||
77a63e5310 | |||
8f921741a5 | |||
589a817952 | |||
dcb21c0f46 | |||
1cb88960fe | |||
610a1483b7 | |||
b4e7fc0d1d | |||
b792b7d68c | |||
abaa91195d | |||
1806bfb755 | |||
7377855c02 | |||
5f2a6f24cf | |||
5b8b92d957 | |||
352202a7bc | |||
82144de85f | |||
b70d713e89 | |||
e39dde4140 | |||
c151541703 | |||
29b348ece1 | |||
9f7c86c33e | |||
a79d40519c | |||
4515d52a42 | |||
2a8513eee0 | |||
b856fac713 | |||
4a3951681c | |||
ba89444e36 | |||
a044403ac3 | |||
16dea46b79 | |||
1f80b5335b | |||
eee7f13771 | |||
6db509a4ff | |||
b7965e1ee6 | |||
c3d292e8f9 | |||
206593ec99 | |||
1b62c781d7 | |||
c4de509983 | |||
8d80802a35 | |||
694925f427 | |||
61d5cb2536 | |||
c23fe4f6d2 | |||
e6e93bbb80 | |||
b5bd5240b6 | |||
827ac82d54 | |||
9c2f3259ca | |||
6abe2bfe42 | |||
acf955fc7b | |||
023db8ac41 | |||
65cf733a0c | |||
8323169864 | |||
bf5cd1bd3b | |||
c9db01e272 | |||
6d5e9161fb | |||
0636348585 | |||
4c44523ba0 | |||
5372800e60 | |||
2ae396640b | |||
252f222068 | |||
142ba8c8ea | |||
84dfd2003e | |||
5a633ba811 | |||
f207647f0f | |||
ad16581ab8 | |||
fd722ddf7d | |||
d669e69755 | |||
d912bab4c2 | |||
68c2722c02 | |||
426fea9681 | |||
62cfdb9f11 | |||
46b4d6497c | |||
757c0a5775 | |||
9c8f0b44ad | |||
21433a948c | |||
183344b878 | |||
fc164d5be2 | |||
45aa770cd1 | |||
6d0e782d71 | |||
117f70e1ec | |||
c840bd8c12 | |||
3c64fad379 | |||
bc813e4065 | |||
7c1d2422f0 | |||
a5b11e1071 | |||
c7e4daf431 | |||
4c61f3a514 | |||
2a179799d8 | |||
650f4bb58c | |||
7b92b27ceb | |||
8f1b301d01 | |||
e3a19d4f3e | |||
70283f7d8d | |||
ecbb385447 | |||
8dc56471ef | |||
282ba201d2 | |||
2394f6458f | |||
47c1be3322 | |||
741464b053 | |||
3aab5e7e20 | |||
1e7a6dc676 | |||
81fd2ee8c1 | |||
357601e2d6 | |||
71ff759692 | |||
b0657d5fde | |||
fa391c0b78 | |||
6082aace6d | |||
7ef63161ba | |||
b731b55de4 | |||
51956ba356 | |||
f494077003 | |||
317165c410 | |||
f5aadbc200 | |||
774230f7b9 | |||
72e25d99c7 | |||
7c7c1ba02d | |||
9c6af74556 | |||
57daa3e1c2 | |||
ce98fdc5c4 | |||
f901645c12 | |||
f514f17e92 | |||
8744dd0c46 | |||
f3d669319e | |||
ace7032067 | |||
d32819875a | |||
5b5898827c | |||
8a233174de | |||
bec81170b5 | |||
2f25363d76 | |||
2aa5688d90 | |||
ed06a70eca | |||
e80160f8dd | |||
bfe64b1510 | |||
bb1769abab | |||
e3f906e90d | |||
d77dc68119 | |||
ee3d695e2e | |||
0443befd2f | |||
b4fd02b910 | |||
4e0fe4ad6e | |||
3231499992 | |||
c134161a45 | |||
c3f533f20f | |||
519a9071a8 | |||
87b4663026 | |||
6c11e8ee06 | |||
2a739890a3 | |||
02e84c9565 | |||
39715017f9 | |||
35518542f8 | |||
0aa1106c96 | |||
33f832e6ab | |||
281c788489 | |||
3858bef185 | |||
f9a1afd09c | |||
251e9c0294 | |||
d8bf2e3c10 | |||
218f30b7d0 | |||
da983c7773 | |||
7012e16c43 | |||
b1050abf7f | |||
210998081a | |||
604acb9d91 | |||
5beeb1a897 | |||
de6304b729 | |||
d0be79c33d | |||
c22326f9f8 |
@ -1,5 +1,8 @@
|
||||
root = true
|
||||
|
||||
# All files
|
||||
[*]
|
||||
max_line_length = 80
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
@ -10,3 +13,18 @@ trim_trailing_whitespace = true
|
||||
# Python
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
max_line_length = 120
|
||||
|
||||
# css
|
||||
[*.css]
|
||||
indent_size = 4
|
||||
|
||||
# flake8
|
||||
[.flake8]
|
||||
indent_size = 4
|
||||
|
||||
# Markdown MkDocs
|
||||
[docs/**/*.md]
|
||||
max_line_length = 80
|
||||
indent_size = 4
|
||||
indent_style = unset
|
||||
|
37
.flake8
Normal file
37
.flake8
Normal file
@ -0,0 +1,37 @@
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
extend-ignore =
|
||||
# See https://github.com/PyCQA/pycodestyle/issues/373
|
||||
E203,
|
||||
# use Bugbear's B950 instead
|
||||
E501,
|
||||
# from black repo https://github.com/psf/black/blob/main/.flake8
|
||||
E266, W503, B907
|
||||
extend-select =
|
||||
# Bugbear line length
|
||||
B950
|
||||
extend-exclude =
|
||||
scripts/orig_scripts/*
|
||||
ldm/models/*
|
||||
ldm/modules/*
|
||||
ldm/data/*
|
||||
ldm/generate.py
|
||||
ldm/util.py
|
||||
ldm/simplet2i.py
|
||||
per-file-ignores =
|
||||
# B950 line too long
|
||||
# W605 invalid escape sequence
|
||||
# F841 assigned to but never used
|
||||
# F401 imported but unused
|
||||
tests/test_prompt_parser.py: B950, W605, F401
|
||||
tests/test_textual_inversion.py: F841, B950
|
||||
# B023 Function definition does not bind loop variable
|
||||
scripts/legacy_api.py: F401, B950, B023, F841
|
||||
ldm/invoke/__init__.py: F401
|
||||
# B010 Do not call setattr with a constant attribute value
|
||||
ldm/invoke/server_legacy.py: B010
|
||||
# =====================
|
||||
# flake-quote settings:
|
||||
# =====================
|
||||
# Set this to match black style:
|
||||
inline-quotes = double
|
50
.github/CODEOWNERS
vendored
50
.github/CODEOWNERS
vendored
@ -2,50 +2,60 @@
|
||||
/.github/workflows/ @mauwii @lstein @blessedcoolant
|
||||
|
||||
# documentation
|
||||
/docs/ @lstein @mauwii @tildebyte @blessedcoolant
|
||||
mkdocs.yml @lstein @mauwii @blessedcoolant
|
||||
/docs/ @lstein @mauwii @blessedcoolant
|
||||
mkdocs.yml @mauwii @lstein
|
||||
|
||||
# installation and configuration
|
||||
/pyproject.toml @mauwii @lstein @ebr @blessedcoolant
|
||||
/docker/ @mauwii @lstein @blessedcoolant
|
||||
/pyproject.toml @mauwii @lstein @ebr
|
||||
/docker/ @mauwii
|
||||
/scripts/ @ebr @lstein @blessedcoolant
|
||||
/installer/ @ebr @lstein @tildebyte @blessedcoolant
|
||||
ldm/invoke/config @lstein @ebr @blessedcoolant
|
||||
invokeai/assets @lstein @ebr @blessedcoolant
|
||||
/installer/ @ebr @lstein
|
||||
ldm/invoke/config @lstein @ebr
|
||||
invokeai/assets @lstein @blessedcoolant
|
||||
invokeai/configs @lstein @ebr @blessedcoolant
|
||||
/ldm/invoke/_version.py @lstein @blessedcoolant
|
||||
|
||||
# web ui
|
||||
/invokeai/frontend @blessedcoolant @psychedelicious @lstein
|
||||
/invokeai/backend @blessedcoolant @psychedelicious @lstein
|
||||
/invokeai/frontend @blessedcoolant @psychedelicious
|
||||
/invokeai/backend @blessedcoolant @psychedelicious
|
||||
|
||||
# generation and model management
|
||||
/ldm/*.py @lstein @blessedcoolant
|
||||
/ldm/generate.py @lstein @keturn @blessedcoolant
|
||||
/ldm/generate.py @lstein @keturn
|
||||
/ldm/invoke/args.py @lstein @blessedcoolant
|
||||
/ldm/invoke/ckpt* @lstein @blessedcoolant
|
||||
/ldm/invoke/ckpt_generator @lstein @blessedcoolant
|
||||
/ldm/invoke/CLI.py @lstein @blessedcoolant
|
||||
/ldm/invoke/config @lstein @ebr @mauwii @blessedcoolant
|
||||
/ldm/invoke/generator @keturn @damian0815 @blessedcoolant
|
||||
/ldm/invoke/generator @keturn @damian0815
|
||||
/ldm/invoke/globals.py @lstein @blessedcoolant
|
||||
/ldm/invoke/merge_diffusers.py @lstein @blessedcoolant
|
||||
/ldm/invoke/model_manager.py @lstein @blessedcoolant
|
||||
/ldm/invoke/txt2mask.py @lstein @blessedcoolant
|
||||
/ldm/invoke/patchmatch.py @Kyle0654 @blessedcoolant @lstein
|
||||
/ldm/invoke/patchmatch.py @Kyle0654 @lstein
|
||||
/ldm/invoke/restoration @lstein @blessedcoolant
|
||||
|
||||
# attention, textual inversion, model configuration
|
||||
/ldm/models @damian0815 @keturn @lstein @blessedcoolant
|
||||
/ldm/modules @damian0815 @keturn @lstein @blessedcoolant
|
||||
/ldm/models @damian0815 @keturn @blessedcoolant
|
||||
/ldm/modules/textual_inversion_manager.py @lstein @blessedcoolant
|
||||
/ldm/modules/attention.py @damian0815 @keturn
|
||||
/ldm/modules/diffusionmodules @damian0815 @keturn
|
||||
/ldm/modules/distributions @damian0815 @keturn
|
||||
/ldm/modules/ema.py @damian0815 @keturn
|
||||
/ldm/modules/embedding_manager.py @lstein
|
||||
/ldm/modules/encoders @damian0815 @keturn
|
||||
/ldm/modules/image_degradation @damian0815 @keturn
|
||||
/ldm/modules/losses @damian0815 @keturn
|
||||
/ldm/modules/x_transformer.py @damian0815 @keturn
|
||||
|
||||
# Nodes
|
||||
apps/ @Kyle0654 @lstein @blessedcoolant
|
||||
apps/ @Kyle0654 @jpphoto
|
||||
|
||||
# legacy REST API
|
||||
# is CapableWeb still engaged?
|
||||
/ldm/invoke/pngwriter.py @CapableWeb @lstein @blessedcoolant
|
||||
/ldm/invoke/server_legacy.py @CapableWeb @lstein @blessedcoolant
|
||||
/scripts/legacy_api.py @CapableWeb @lstein @blessedcoolant
|
||||
/tests/legacy_tests.sh @CapableWeb @lstein @blessedcoolant
|
||||
# these are dead code
|
||||
#/ldm/invoke/pngwriter.py @CapableWeb
|
||||
#/ldm/invoke/server_legacy.py @CapableWeb
|
||||
#/scripts/legacy_api.py @CapableWeb
|
||||
#/tests/legacy_tests.sh @CapableWeb
|
||||
|
||||
|
||||
|
10
.github/workflows/mkdocs-material.yml
vendored
10
.github/workflows/mkdocs-material.yml
vendored
@ -9,6 +9,10 @@ jobs:
|
||||
mkdocs-material:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REPO_URL: '${{ github.server_url }}/${{ github.repository }}'
|
||||
REPO_NAME: '${{ github.repository }}'
|
||||
SITE_URL: 'https://${{ github.repository_owner }}.github.io/InvokeAI'
|
||||
steps:
|
||||
- name: checkout sources
|
||||
uses: actions/checkout@v3
|
||||
@ -19,11 +23,15 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: pip
|
||||
cache-dependency-path: pyproject.toml
|
||||
|
||||
- name: install requirements
|
||||
env:
|
||||
PIP_USE_PEP517: 1
|
||||
run: |
|
||||
python -m \
|
||||
pip install -r docs/requirements-mkdocs.txt
|
||||
pip install ".[docs]"
|
||||
|
||||
- name: confirm buildability
|
||||
run: |
|
||||
|
41
.pre-commit-config.yaml
Normal file
41
.pre-commit-config.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-black
|
||||
- flake8-bugbear
|
||||
- flake8-comprehensions
|
||||
- flake8-simplify
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: 'v3.0.0-alpha.4'
|
||||
hooks:
|
||||
- id: prettier
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-merge-conflict
|
||||
- id: check-symlinks
|
||||
- id: check-toml
|
||||
- id: end-of-file-fixer
|
||||
- id: no-commit-to-branch
|
||||
args: ['--branch', 'main']
|
||||
- id: trailing-whitespace
|
14
.prettierignore
Normal file
14
.prettierignore
Normal file
@ -0,0 +1,14 @@
|
||||
invokeai/frontend/.husky
|
||||
invokeai/frontend/patches
|
||||
|
||||
# Ignore artifacts:
|
||||
build
|
||||
coverage
|
||||
static
|
||||
invokeai/frontend/dist
|
||||
|
||||
# Ignore all HTML files:
|
||||
*.html
|
||||
|
||||
# Ignore deprecated docs
|
||||
docs/installation/deprecated_documentation
|
@ -1,9 +1,9 @@
|
||||
endOfLine: lf
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
singleQuote: true
|
||||
quoteProps: as-needed
|
||||
embeddedLanguageFormatting: auto
|
||||
endOfLine: lf
|
||||
singleQuote: true
|
||||
semi: true
|
||||
trailingComma: es5
|
||||
useTabs: false
|
||||
overrides:
|
||||
- files: '*.md'
|
||||
options:
|
||||
@ -11,3 +11,9 @@ overrides:
|
||||
printWidth: 80
|
||||
parser: markdown
|
||||
cursorOffset: -1
|
||||
- files: docs/**/*.md
|
||||
options:
|
||||
tabWidth: 4
|
||||
- files: 'invokeai/frontend/public/locales/*.json'
|
||||
options:
|
||||
tabWidth: 4
|
||||
|
@ -145,7 +145,7 @@ not supported.
|
||||
_For Linux with an AMD GPU:_
|
||||
|
||||
```sh
|
||||
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.2
|
||||
pip install InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.4.2
|
||||
```
|
||||
|
||||
_For Macintoshes, either Intel or M1/M2:_
|
||||
|
Binary file not shown.
@ -1,164 +0,0 @@
|
||||
@echo off
|
||||
|
||||
@rem This script will install git (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, this step will be skipped.
|
||||
|
||||
@rem Next, it'll download the project's source code.
|
||||
@rem Then it will download a self-contained, standalone Python and unpack it.
|
||||
@rem Finally, it'll create the Python virtual environment and preload the models.
|
||||
|
||||
@rem This enables a user to install this project without manually installing git or Python
|
||||
|
||||
@rem change to the script's directory
|
||||
PUSHD "%~dp0"
|
||||
|
||||
set "no_cache_dir=--no-cache-dir"
|
||||
if "%1" == "use-cache" (
|
||||
set "no_cache_dir="
|
||||
)
|
||||
|
||||
echo ***** Installing InvokeAI.. *****
|
||||
@rem Config
|
||||
set INSTALL_ENV_DIR=%cd%\installer_files\env
|
||||
@rem https://mamba.readthedocs.io/en/latest/installation.html
|
||||
set MICROMAMBA_DOWNLOAD_URL=https://github.com/cmdr2/stable-diffusion-ui/releases/download/v1.1/micromamba.exe
|
||||
set RELEASE_URL=https://github.com/invoke-ai/InvokeAI
|
||||
set RELEASE_SOURCEBALL=/archive/refs/heads/main.tar.gz
|
||||
set PYTHON_BUILD_STANDALONE_URL=https://github.com/indygreg/python-build-standalone/releases/download
|
||||
set PYTHON_BUILD_STANDALONE=20221002/cpython-3.10.7+20221002-x86_64-pc-windows-msvc-shared-install_only.tar.gz
|
||||
|
||||
set PACKAGES_TO_INSTALL=
|
||||
|
||||
call git --version >.tmp1 2>.tmp2
|
||||
if "%ERRORLEVEL%" NEQ "0" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% git
|
||||
|
||||
@rem Cleanup
|
||||
del /q .tmp1 .tmp2
|
||||
|
||||
@rem (if necessary) install git into a contained environment
|
||||
if "%PACKAGES_TO_INSTALL%" NEQ "" (
|
||||
@rem download micromamba
|
||||
echo ***** Downloading micromamba from %MICROMAMBA_DOWNLOAD_URL% to micromamba.exe *****
|
||||
|
||||
call curl -L "%MICROMAMBA_DOWNLOAD_URL%" > micromamba.exe
|
||||
|
||||
@rem test the mamba binary
|
||||
echo ***** Micromamba version: *****
|
||||
call micromamba.exe --version
|
||||
|
||||
@rem create the installer env
|
||||
if not exist "%INSTALL_ENV_DIR%" (
|
||||
call micromamba.exe create -y --prefix "%INSTALL_ENV_DIR%"
|
||||
)
|
||||
|
||||
echo ***** Packages to install:%PACKAGES_TO_INSTALL% *****
|
||||
|
||||
call 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
|
||||
)
|
||||
)
|
||||
|
||||
del /q micromamba.exe
|
||||
|
||||
@rem For 'git' only
|
||||
set PATH=%INSTALL_ENV_DIR%\Library\bin;%PATH%
|
||||
|
||||
@rem Download/unpack/clean up InvokeAI release sourceball
|
||||
set err_msg=----- InvokeAI source download failed -----
|
||||
echo Trying to download "%RELEASE_URL%%RELEASE_SOURCEBALL%"
|
||||
curl -L %RELEASE_URL%%RELEASE_SOURCEBALL% --output InvokeAI.tgz
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
set err_msg=----- InvokeAI source unpack failed -----
|
||||
tar -zxf InvokeAI.tgz
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
del /q InvokeAI.tgz
|
||||
|
||||
set err_msg=----- InvokeAI source copy failed -----
|
||||
cd InvokeAI-*
|
||||
xcopy . .. /e /h
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
cd ..
|
||||
|
||||
@rem cleanup
|
||||
for /f %%i in ('dir /b InvokeAI-*') do rd /s /q %%i
|
||||
rd /s /q .dev_scripts .github docker-build tests
|
||||
del /q requirements.in requirements-mkdocs.txt shell.nix
|
||||
|
||||
echo ***** Unpacked InvokeAI source *****
|
||||
|
||||
@rem Download/unpack/clean up python-build-standalone
|
||||
set err_msg=----- Python download failed -----
|
||||
curl -L %PYTHON_BUILD_STANDALONE_URL%/%PYTHON_BUILD_STANDALONE% --output python.tgz
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
set err_msg=----- Python unpack failed -----
|
||||
tar -zxf python.tgz
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
del /q python.tgz
|
||||
|
||||
echo ***** Unpacked python-build-standalone *****
|
||||
|
||||
@rem create venv
|
||||
set err_msg=----- problem creating venv -----
|
||||
.\python\python -E -s -m venv .venv
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
call .venv\Scripts\activate.bat
|
||||
|
||||
echo ***** Created Python virtual environment *****
|
||||
|
||||
@rem Print venv's Python version
|
||||
set err_msg=----- problem calling venv's python -----
|
||||
echo We're running under
|
||||
.venv\Scripts\python --version
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
set err_msg=----- pip update failed -----
|
||||
.venv\Scripts\python -m pip install %no_cache_dir% --no-warn-script-location --upgrade pip wheel
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
echo ***** Updated pip and wheel *****
|
||||
|
||||
set err_msg=----- requirements file copy failed -----
|
||||
copy binary_installer\py3.10-windows-x86_64-cuda-reqs.txt requirements.txt
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
set err_msg=----- main pip install failed -----
|
||||
.venv\Scripts\python -m pip install %no_cache_dir% --no-warn-script-location -r requirements.txt
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
echo ***** Installed Python dependencies *****
|
||||
|
||||
set err_msg=----- InvokeAI setup failed -----
|
||||
.venv\Scripts\python -m pip install %no_cache_dir% --no-warn-script-location -e .
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
|
||||
copy binary_installer\invoke.bat.in .\invoke.bat
|
||||
echo ***** Installed invoke launcher script ******
|
||||
|
||||
@rem more cleanup
|
||||
rd /s /q binary_installer installer_files
|
||||
|
||||
@rem preload the models
|
||||
call .venv\Scripts\python ldm\invoke\config\invokeai_configure.py
|
||||
set err_msg=----- model download clone failed -----
|
||||
if %errorlevel% neq 0 goto err_exit
|
||||
deactivate
|
||||
|
||||
echo ***** Finished downloading models *****
|
||||
|
||||
echo All done! Execute the file invoke.bat in this directory to start InvokeAI
|
||||
pause
|
||||
exit
|
||||
|
||||
:err_exit
|
||||
echo %err_msg%
|
||||
pause
|
||||
exit
|
@ -1,235 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ensure we're in the correct folder in case user's CWD is somewhere else
|
||||
scriptdir=$(dirname "$0")
|
||||
cd "$scriptdir"
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
function _err_exit {
|
||||
if test "$1" -ne 0
|
||||
then
|
||||
echo -e "Error code $1; Error caught was '$2'"
|
||||
read -p "Press any key to exit..."
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# This script will install git (if not found on the PATH variable)
|
||||
# using micromamba (an 8mb static-linked single-file binary, conda replacement).
|
||||
# For users who already have git, this step will be skipped.
|
||||
|
||||
# Next, it'll download the project's source code.
|
||||
# Then it will download a self-contained, standalone Python and unpack it.
|
||||
# Finally, it'll create the Python virtual environment and preload the models.
|
||||
|
||||
# This enables a user to install this project without manually installing git or Python
|
||||
|
||||
echo -e "\n***** Installing InvokeAI into $(pwd)... *****\n"
|
||||
|
||||
export no_cache_dir="--no-cache-dir"
|
||||
if [ $# -ge 1 ]; then
|
||||
if [ "$1" = "use-cache" ]; then
|
||||
export no_cache_dir=""
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
OS_NAME=$(uname -s)
|
||||
case "${OS_NAME}" in
|
||||
Linux*) OS_NAME="linux";;
|
||||
Darwin*) OS_NAME="darwin";;
|
||||
*) echo -e "\n----- Unknown OS: $OS_NAME! This script runs only on Linux or macOS -----\n" && exit
|
||||
esac
|
||||
|
||||
OS_ARCH=$(uname -m)
|
||||
case "${OS_ARCH}" in
|
||||
x86_64*) ;;
|
||||
arm64*) ;;
|
||||
*) echo -e "\n----- Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64 -----\n" && exit
|
||||
esac
|
||||
|
||||
# https://mamba.readthedocs.io/en/latest/installation.html
|
||||
MAMBA_OS_NAME=$OS_NAME
|
||||
MAMBA_ARCH=$OS_ARCH
|
||||
if [ "$OS_NAME" == "darwin" ]; then
|
||||
MAMBA_OS_NAME="osx"
|
||||
fi
|
||||
|
||||
if [ "$OS_ARCH" == "linux" ]; then
|
||||
MAMBA_ARCH="aarch64"
|
||||
fi
|
||||
|
||||
if [ "$OS_ARCH" == "x86_64" ]; then
|
||||
MAMBA_ARCH="64"
|
||||
fi
|
||||
|
||||
PY_ARCH=$OS_ARCH
|
||||
if [ "$OS_ARCH" == "arm64" ]; then
|
||||
PY_ARCH="aarch64"
|
||||
fi
|
||||
|
||||
# Compute device ('cd' segment of reqs files) detect goes here
|
||||
# This needs a ton of work
|
||||
# Suggestions:
|
||||
# - lspci
|
||||
# - check $PATH for nvidia-smi, gtt CUDA/GPU version from output
|
||||
# - Surely there's a similar utility for AMD?
|
||||
CD="cuda"
|
||||
if [ "$OS_NAME" == "darwin" ] && [ "$OS_ARCH" == "arm64" ]; then
|
||||
CD="mps"
|
||||
fi
|
||||
|
||||
# config
|
||||
INSTALL_ENV_DIR="$(pwd)/installer_files/env"
|
||||
MICROMAMBA_DOWNLOAD_URL="https://micro.mamba.pm/api/micromamba/${MAMBA_OS_NAME}-${MAMBA_ARCH}/latest"
|
||||
RELEASE_URL=https://github.com/invoke-ai/InvokeAI
|
||||
RELEASE_SOURCEBALL=/archive/refs/heads/main.tar.gz
|
||||
PYTHON_BUILD_STANDALONE_URL=https://github.com/indygreg/python-build-standalone/releases/download
|
||||
if [ "$OS_NAME" == "darwin" ]; then
|
||||
PYTHON_BUILD_STANDALONE=20221002/cpython-3.10.7+20221002-${PY_ARCH}-apple-darwin-install_only.tar.gz
|
||||
elif [ "$OS_NAME" == "linux" ]; then
|
||||
PYTHON_BUILD_STANDALONE=20221002/cpython-3.10.7+20221002-${PY_ARCH}-unknown-linux-gnu-install_only.tar.gz
|
||||
fi
|
||||
echo "INSTALLING $RELEASE_SOURCEBALL FROM $RELEASE_URL"
|
||||
|
||||
PACKAGES_TO_INSTALL=""
|
||||
|
||||
if ! hash "git" &>/dev/null; then PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL git"; fi
|
||||
|
||||
# (if necessary) install git and conda into a contained environment
|
||||
if [ "$PACKAGES_TO_INSTALL" != "" ]; then
|
||||
# download micromamba
|
||||
echo -e "\n***** Downloading micromamba from $MICROMAMBA_DOWNLOAD_URL to micromamba *****\n"
|
||||
|
||||
curl -L "$MICROMAMBA_DOWNLOAD_URL" | tar -xvjO bin/micromamba > micromamba
|
||||
|
||||
chmod u+x ./micromamba
|
||||
|
||||
# test the mamba binary
|
||||
echo -e "\n***** Micromamba version: *****\n"
|
||||
./micromamba --version
|
||||
|
||||
# create the installer env
|
||||
if [ ! -e "$INSTALL_ENV_DIR" ]; then
|
||||
./micromamba create -y --prefix "$INSTALL_ENV_DIR"
|
||||
fi
|
||||
|
||||
echo -e "\n***** Packages to install:$PACKAGES_TO_INSTALL *****\n"
|
||||
|
||||
./micromamba install -y --prefix "$INSTALL_ENV_DIR" -c conda-forge "$PACKAGES_TO_INSTALL"
|
||||
|
||||
if [ ! -e "$INSTALL_ENV_DIR" ]; then
|
||||
echo -e "\n----- There was a problem while initializing micromamba. Cannot continue. -----\n"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f micromamba.exe
|
||||
|
||||
export PATH="$INSTALL_ENV_DIR/bin:$PATH"
|
||||
|
||||
# Download/unpack/clean up InvokeAI release sourceball
|
||||
_err_msg="\n----- InvokeAI source download failed -----\n"
|
||||
curl -L $RELEASE_URL/$RELEASE_SOURCEBALL --output InvokeAI.tgz
|
||||
_err_exit $? _err_msg
|
||||
_err_msg="\n----- InvokeAI source unpack failed -----\n"
|
||||
tar -zxf InvokeAI.tgz
|
||||
_err_exit $? _err_msg
|
||||
|
||||
rm -f InvokeAI.tgz
|
||||
|
||||
_err_msg="\n----- InvokeAI source copy failed -----\n"
|
||||
cd InvokeAI-*
|
||||
cp -r . ..
|
||||
_err_exit $? _err_msg
|
||||
cd ..
|
||||
|
||||
# cleanup
|
||||
rm -rf InvokeAI-*/
|
||||
rm -rf .dev_scripts/ .github/ docker-build/ tests/ requirements.in requirements-mkdocs.txt shell.nix
|
||||
|
||||
echo -e "\n***** Unpacked InvokeAI source *****\n"
|
||||
|
||||
# Download/unpack/clean up python-build-standalone
|
||||
_err_msg="\n----- Python download failed -----\n"
|
||||
curl -L $PYTHON_BUILD_STANDALONE_URL/$PYTHON_BUILD_STANDALONE --output python.tgz
|
||||
_err_exit $? _err_msg
|
||||
_err_msg="\n----- Python unpack failed -----\n"
|
||||
tar -zxf python.tgz
|
||||
_err_exit $? _err_msg
|
||||
|
||||
rm -f python.tgz
|
||||
|
||||
echo -e "\n***** Unpacked python-build-standalone *****\n"
|
||||
|
||||
# create venv
|
||||
_err_msg="\n----- problem creating venv -----\n"
|
||||
|
||||
if [ "$OS_NAME" == "darwin" ]; then
|
||||
# patch sysconfig so that extensions can build properly
|
||||
# adapted from https://github.com/cashapp/hermit-packages/commit/fcba384663892f4d9cfb35e8639ff7a28166ee43
|
||||
PYTHON_INSTALL_DIR="$(pwd)/python"
|
||||
SYSCONFIG="$(echo python/lib/python*/_sysconfigdata_*.py)"
|
||||
TMPFILE="$(mktemp)"
|
||||
chmod +w "${SYSCONFIG}"
|
||||
cp "${SYSCONFIG}" "${TMPFILE}"
|
||||
sed "s,'/install,'${PYTHON_INSTALL_DIR},g" "${TMPFILE}" > "${SYSCONFIG}"
|
||||
rm -f "${TMPFILE}"
|
||||
fi
|
||||
|
||||
./python/bin/python3 -E -s -m venv .venv
|
||||
_err_exit $? _err_msg
|
||||
source .venv/bin/activate
|
||||
|
||||
echo -e "\n***** Created Python virtual environment *****\n"
|
||||
|
||||
# Print venv's Python version
|
||||
_err_msg="\n----- problem calling venv's python -----\n"
|
||||
echo -e "We're running under"
|
||||
.venv/bin/python3 --version
|
||||
_err_exit $? _err_msg
|
||||
|
||||
_err_msg="\n----- pip update failed -----\n"
|
||||
.venv/bin/python3 -m pip install $no_cache_dir --no-warn-script-location --upgrade pip
|
||||
_err_exit $? _err_msg
|
||||
|
||||
echo -e "\n***** Updated pip *****\n"
|
||||
|
||||
_err_msg="\n----- requirements file copy failed -----\n"
|
||||
cp binary_installer/py3.10-${OS_NAME}-"${OS_ARCH}"-${CD}-reqs.txt requirements.txt
|
||||
_err_exit $? _err_msg
|
||||
|
||||
_err_msg="\n----- main pip install failed -----\n"
|
||||
.venv/bin/python3 -m pip install $no_cache_dir --no-warn-script-location -r requirements.txt
|
||||
_err_exit $? _err_msg
|
||||
|
||||
echo -e "\n***** Installed Python dependencies *****\n"
|
||||
|
||||
_err_msg="\n----- InvokeAI setup failed -----\n"
|
||||
.venv/bin/python3 -m pip install $no_cache_dir --no-warn-script-location -e .
|
||||
_err_exit $? _err_msg
|
||||
|
||||
echo -e "\n***** Installed InvokeAI *****\n"
|
||||
|
||||
cp binary_installer/invoke.sh.in ./invoke.sh
|
||||
chmod a+rx ./invoke.sh
|
||||
echo -e "\n***** Installed invoke launcher script ******\n"
|
||||
|
||||
# more cleanup
|
||||
rm -rf binary_installer/ installer_files/
|
||||
|
||||
# preload the models
|
||||
.venv/bin/python3 scripts/configure_invokeai.py
|
||||
_err_msg="\n----- model download clone failed -----\n"
|
||||
_err_exit $? _err_msg
|
||||
deactivate
|
||||
|
||||
echo -e "\n***** Finished downloading models *****\n"
|
||||
|
||||
echo "All done! Run the command"
|
||||
echo " $scriptdir/invoke.sh"
|
||||
echo "to start InvokeAI."
|
||||
read -p "Press any key to exit..."
|
||||
exit
|
@ -1,36 +0,0 @@
|
||||
@echo off
|
||||
|
||||
PUSHD "%~dp0"
|
||||
call .venv\Scripts\activate.bat
|
||||
|
||||
echo Do you want to generate images using the
|
||||
echo 1. command-line
|
||||
echo 2. browser-based UI
|
||||
echo OR
|
||||
echo 3. open the developer console
|
||||
set /p choice="Please enter 1, 2 or 3: "
|
||||
if /i "%choice%" == "1" (
|
||||
echo Starting the InvokeAI command-line.
|
||||
.venv\Scripts\python scripts\invoke.py %*
|
||||
) else if /i "%choice%" == "2" (
|
||||
echo Starting the InvokeAI browser-based UI.
|
||||
.venv\Scripts\python scripts\invoke.py --web %*
|
||||
) else if /i "%choice%" == "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
|
||||
)
|
||||
|
||||
deactivate
|
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -eu
|
||||
|
||||
. .venv/bin/activate
|
||||
|
||||
# set required env var for torch on mac MPS
|
||||
if [ "$(uname -s)" == "Darwin" ]; then
|
||||
export PYTORCH_ENABLE_MPS_FALLBACK=1
|
||||
fi
|
||||
|
||||
echo "Do you want to generate images using the"
|
||||
echo "1. command-line"
|
||||
echo "2. browser-based UI"
|
||||
echo "OR"
|
||||
echo "3. open the developer console"
|
||||
echo "Please enter 1, 2, or 3:"
|
||||
read choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
printf "\nStarting the InvokeAI command-line..\n";
|
||||
.venv/bin/python scripts/invoke.py $*;
|
||||
;;
|
||||
2)
|
||||
printf "\nStarting the InvokeAI browser-based UI..\n";
|
||||
.venv/bin/python scripts/invoke.py --web $*;
|
||||
;;
|
||||
3)
|
||||
printf "\nDeveloper Console:\n";
|
||||
printf "Python command is:\n\t";
|
||||
which python;
|
||||
printf "Python version is:\n\t";
|
||||
python --version;
|
||||
echo "*************************"
|
||||
echo "You are now in your user shell ($SHELL) with the local InvokeAI Python virtual environment activated,";
|
||||
echo "so that you can troubleshoot this InvokeAI installation as necessary.";
|
||||
printf "*************************\n"
|
||||
echo "*** Type \`exit\` to quit this shell and deactivate the Python virtual environment *** ";
|
||||
/usr/bin/env "$SHELL";
|
||||
;;
|
||||
*)
|
||||
echo "Invalid selection";
|
||||
exit
|
||||
;;
|
||||
esac
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
InvokeAI
|
||||
|
||||
Project homepage: https://github.com/invoke-ai/InvokeAI
|
||||
|
||||
Installation on Windows:
|
||||
NOTE: You might need to enable Windows Long Paths. If you're not sure,
|
||||
then you almost certainly need to. Simply double-click the 'WinLongPathsEnabled.reg'
|
||||
file. Note that you will need to have admin privileges in order to
|
||||
do this.
|
||||
|
||||
Please 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.
|
@ -1,33 +0,0 @@
|
||||
--prefer-binary
|
||||
--extra-index-url https://download.pytorch.org/whl/torch_stable.html
|
||||
--extra-index-url https://download.pytorch.org/whl/cu116
|
||||
--trusted-host https://download.pytorch.org
|
||||
accelerate~=0.15
|
||||
albumentations
|
||||
diffusers[torch]~=0.11
|
||||
einops
|
||||
eventlet
|
||||
flask_cors
|
||||
flask_socketio
|
||||
flaskwebgui==1.0.3
|
||||
getpass_asterisk
|
||||
imageio-ffmpeg
|
||||
pyreadline3
|
||||
realesrgan
|
||||
send2trash
|
||||
streamlit
|
||||
taming-transformers-rom1504
|
||||
test-tube
|
||||
torch-fidelity
|
||||
torch==1.12.1 ; platform_system == 'Darwin'
|
||||
torch==1.12.0+cu116 ; platform_system == 'Linux' or platform_system == 'Windows'
|
||||
torchvision==0.13.1 ; platform_system == 'Darwin'
|
||||
torchvision==0.13.0+cu116 ; platform_system == 'Linux' or platform_system == 'Windows'
|
||||
transformers
|
||||
picklescan
|
||||
https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip
|
||||
https://github.com/invoke-ai/clipseg/archive/1f754751c85d7d4255fa681f4491ff5711c1c288.zip
|
||||
https://github.com/invoke-ai/GFPGAN/archive/3f5d2397361199bc4a91c08bb7d80f04d7805615.zip ; platform_system=='Windows'
|
||||
https://github.com/invoke-ai/GFPGAN/archive/c796277a1cf77954e5fc0b288d7062d162894248.zip ; platform_system=='Linux' or platform_system=='Darwin'
|
||||
https://github.com/Birch-san/k-diffusion/archive/363386981fee88620709cf8f6f2eea167bd6cd74.zip
|
||||
https://github.com/invoke-ai/PyPatchMatch/archive/129863937a8ab37f6bbcec327c994c0f932abdbc.zip
|
5
docs/.markdownlint.jsonc
Normal file
5
docs/.markdownlint.jsonc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"MD046": false,
|
||||
"MD007": false,
|
||||
"MD030": false
|
||||
}
|
@ -154,8 +154,11 @@ training sets will converge with 2000-3000 steps.
|
||||
|
||||
This adjusts how many training images are processed simultaneously in
|
||||
each step. Higher values will cause the training process to run more
|
||||
quickly, but use more memory. The default size will run with GPUs with
|
||||
as little as 12 GB.
|
||||
quickly, but use more memory. The default size is selected based on
|
||||
whether you have the `xformers` memory-efficient attention library
|
||||
installed. If `xformers` is available, the batch size will be 8,
|
||||
otherwise 3. These values were chosen to allow training to run with
|
||||
GPUs with as little as 12 GB VRAM.
|
||||
|
||||
### Learning rate
|
||||
|
||||
@ -172,8 +175,10 @@ learning rate to improve performance.
|
||||
|
||||
### Use xformers acceleration
|
||||
|
||||
This will activate XFormers memory-efficient attention. You need to
|
||||
have XFormers installed for this to have an effect.
|
||||
This will activate XFormers memory-efficient attention, which will
|
||||
reduce memory requirements by half or more and allow you to select a
|
||||
higher batch size. You need to have XFormers installed for this to
|
||||
have an effect.
|
||||
|
||||
### Learning rate scheduler
|
||||
|
||||
@ -250,6 +255,49 @@ invokeai-ti \
|
||||
--only_save_embeds
|
||||
```
|
||||
|
||||
## Using Distributed Training
|
||||
|
||||
If you have multiple GPUs on one machine, or a cluster of GPU-enabled
|
||||
machines, you can activate distributed training. See the [HuggingFace
|
||||
Accelerate pages](https://huggingface.co/docs/accelerate/index) for
|
||||
full information, but the basic recipe is:
|
||||
|
||||
1. Enter the InvokeAI developer's console command line by selecting
|
||||
option [8] from the `invoke.sh`/`invoke.bat` script.
|
||||
|
||||
2. Configurate Accelerate using `accelerate config`:
|
||||
```sh
|
||||
accelerate config
|
||||
```
|
||||
This will guide you through the configuration process, including
|
||||
specifying how many machines you will run training on and the number
|
||||
of GPUs pe rmachine.
|
||||
|
||||
You only need to do this once.
|
||||
|
||||
3. Launch training from the command line using `accelerate launch`. Be sure
|
||||
that your current working directory is the InvokeAI root directory (usually
|
||||
named `invokeai` in your home directory):
|
||||
|
||||
```sh
|
||||
accelerate launch .venv/bin/invokeai-ti \
|
||||
--model=stable-diffusion-1.5 \
|
||||
--resolution=512 \
|
||||
--learnable_property=object \
|
||||
--initializer_token='*' \
|
||||
--placeholder_token='<shraddha>' \
|
||||
--train_data_dir=/home/lstein/invokeai/text-inversion-training-data/shraddha \
|
||||
--output_dir=/home/lstein/invokeai/text-inversion-training/shraddha \
|
||||
--scale_lr \
|
||||
--train_batch_size=10 \
|
||||
--gradient_accumulation_steps=4 \
|
||||
--max_train_steps=2000 \
|
||||
--learning_rate=0.0005 \
|
||||
--lr_scheduler=constant \
|
||||
--mixed_precision=fp16 \
|
||||
--only_save_embeds
|
||||
```
|
||||
|
||||
## Using Embeddings
|
||||
|
||||
After training completes, the resultant embeddings will be saved into your `$INVOKEAI_ROOT/embeddings/<trigger word>/learned_embeds.bin`.
|
||||
|
@ -2,62 +2,82 @@
|
||||
title: Overview
|
||||
---
|
||||
|
||||
Here you can find the documentation for InvokeAI's various features.
|
||||
- The Basics
|
||||
|
||||
## The Basics
|
||||
### * The [Web User Interface](WEB.md)
|
||||
Guide to the Web interface. Also see the [WebUI Hotkeys Reference Guide](WEBUIHOTKEYS.md)
|
||||
- The [Web User Interface](WEB.md)
|
||||
|
||||
### * The [Unified Canvas](UNIFIED_CANVAS.md)
|
||||
Build complex scenes by combine and modifying multiple images in a stepwise
|
||||
fashion. This feature combines img2img, inpainting and outpainting in
|
||||
a single convenient digital artist-optimized user interface.
|
||||
Guide to the Web interface. Also see the
|
||||
[WebUI Hotkeys Reference Guide](WEBUIHOTKEYS.md)
|
||||
|
||||
### * The [Command Line Interface (CLI)](CLI.md)
|
||||
Scriptable access to InvokeAI's features.
|
||||
- The [Unified Canvas](UNIFIED_CANVAS.md)
|
||||
|
||||
## Image Generation
|
||||
### * [Prompt Engineering](PROMPTS.md)
|
||||
Get the images you want with the InvokeAI prompt engineering language.
|
||||
Build complex scenes by combine and modifying multiple images in a
|
||||
stepwise fashion. This feature combines img2img, inpainting and
|
||||
outpainting in a single convenient digital artist-optimized user
|
||||
interface.
|
||||
|
||||
## * [Post-Processing](POSTPROCESS.md)
|
||||
Restore mangled faces and make images larger with upscaling. Also see the [Embiggen Upscaling Guide](EMBIGGEN.md).
|
||||
- The [Command Line Interface (CLI)](CLI.md)
|
||||
|
||||
## * The [Concepts Library](CONCEPTS.md)
|
||||
Add custom subjects and styles using HuggingFace's repository of embeddings.
|
||||
Scriptable access to InvokeAI's features.
|
||||
|
||||
### * [Image-to-Image Guide for the CLI](IMG2IMG.md)
|
||||
Use a seed image to build new creations in the CLI.
|
||||
- Image Generation
|
||||
|
||||
### * [Inpainting Guide for the CLI](INPAINTING.md)
|
||||
Selectively erase and replace portions of an existing image in the CLI.
|
||||
- [Prompt Engineering](PROMPTS.md)
|
||||
|
||||
### * [Outpainting Guide for the CLI](OUTPAINTING.md)
|
||||
Extend the borders of the image with an "outcrop" function within the CLI.
|
||||
Get the images you want with the InvokeAI prompt engineering language.
|
||||
|
||||
### * [Generating Variations](VARIATIONS.md)
|
||||
Have an image you like and want to generate many more like it? Variations
|
||||
are the ticket.
|
||||
- [Post-Processing](POSTPROCESS.md)
|
||||
|
||||
## Model Management
|
||||
Restore mangled faces and make images larger with upscaling. Also see
|
||||
the [Embiggen Upscaling Guide](EMBIGGEN.md).
|
||||
|
||||
## * [Model Installation](../installation/050_INSTALLING_MODELS.md)
|
||||
Learn how to import third-party models and switch among them. This
|
||||
guide also covers optimizing models to load quickly.
|
||||
- The [Concepts Library](CONCEPTS.md)
|
||||
|
||||
## * [Merging Models](MODEL_MERGING.md)
|
||||
Teach an old model new tricks. Merge 2-3 models together to create a
|
||||
new model that combines characteristics of the originals.
|
||||
Add custom subjects and styles using HuggingFace's repository of
|
||||
embeddings.
|
||||
|
||||
## * [Textual Inversion](TEXTUAL_INVERSION.md)
|
||||
Personalize models by adding your own style or subjects.
|
||||
- [Image-to-Image Guide for the CLI](IMG2IMG.md)
|
||||
|
||||
# Other Features
|
||||
Use a seed image to build new creations in the CLI.
|
||||
|
||||
## * [The NSFW Checker](NSFW.md)
|
||||
Prevent InvokeAI from displaying unwanted racy images.
|
||||
- [Inpainting Guide for the CLI](INPAINTING.md)
|
||||
|
||||
## * [Miscellaneous](OTHER.md)
|
||||
Run InvokeAI on Google Colab, generate images with repeating patterns,
|
||||
batch process a file of prompts, increase the "creativity" of image
|
||||
generation by adding initial noise, and more!
|
||||
Selectively erase and replace portions of an existing image in the CLI.
|
||||
|
||||
- [Outpainting Guide for the CLI](OUTPAINTING.md)
|
||||
|
||||
Extend the borders of the image with an "outcrop" function within the
|
||||
CLI.
|
||||
|
||||
- [Generating Variations](VARIATIONS.md)
|
||||
|
||||
Have an image you like and want to generate many more like it?
|
||||
Variations are the ticket.
|
||||
|
||||
- Model Management
|
||||
|
||||
- [Model Installation](../installation/050_INSTALLING_MODELS.md)
|
||||
|
||||
Learn how to import third-party models and switch among them. This guide
|
||||
also covers optimizing models to load quickly.
|
||||
|
||||
- [Merging Models](MODEL_MERGING.md)
|
||||
|
||||
Teach an old model new tricks. Merge 2-3 models together to create a new
|
||||
model that combines characteristics of the originals.
|
||||
|
||||
- [Textual Inversion](TEXTUAL_INVERSION.md)
|
||||
|
||||
Personalize models by adding your own style or subjects.
|
||||
|
||||
- Other Features
|
||||
|
||||
- [The NSFW Checker](NSFW.md)
|
||||
|
||||
Prevent InvokeAI from displaying unwanted racy images.
|
||||
|
||||
- [Miscellaneous](OTHER.md)
|
||||
|
||||
Run InvokeAI on Google Colab, generate images with repeating patterns,
|
||||
batch process a file of prompts, increase the "creativity" of image
|
||||
generation by adding initial noise, and more!
|
||||
|
4
docs/help/IDE-Settings/index.md
Normal file
4
docs/help/IDE-Settings/index.md
Normal file
@ -0,0 +1,4 @@
|
||||
# :octicons-file-code-16: IDE-Settings
|
||||
|
||||
Here we will share settings for IDEs used by our developers, maybe you can find
|
||||
something interestening which will help to boost your development efficency 🔥
|
250
docs/help/IDE-Settings/vs-code.md
Normal file
250
docs/help/IDE-Settings/vs-code.md
Normal file
@ -0,0 +1,250 @@
|
||||
---
|
||||
title: Visual Studio Code
|
||||
---
|
||||
|
||||
# :material-microsoft-visual-studio-code:Visual Studio Code
|
||||
|
||||
The Workspace Settings are stored in the project (repository) root and get
|
||||
higher priorized than your user settings.
|
||||
|
||||
This helps to have different settings for different projects, while the user
|
||||
settings get used as a default value if no workspace settings are provided.
|
||||
|
||||
## tasks.json
|
||||
|
||||
First we will create a task configuration which will create a virtual
|
||||
environment and update the deps (pip, setuptools and wheel).
|
||||
|
||||
Into this venv we will then install the pyproject.toml in editable mode with
|
||||
dev, docs and test dependencies.
|
||||
|
||||
```json title=".vscode/tasks.json"
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Create virtual environment",
|
||||
"detail": "Create .venv and upgrade pip, setuptools and wheel",
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"-m",
|
||||
"venv",
|
||||
".venv",
|
||||
"--prompt",
|
||||
"InvokeAI",
|
||||
"--upgrade-deps"
|
||||
],
|
||||
"runOptions": {
|
||||
"instanceLimit": 1,
|
||||
"reevaluateOnRerun": true
|
||||
},
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared",
|
||||
"showReuseMessage": true,
|
||||
"clear": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build InvokeAI",
|
||||
"detail": "Build pyproject.toml with extras dev, docs and test",
|
||||
"command": "${workspaceFolder}/.venv/bin/python3",
|
||||
"args": [
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"--use-pep517",
|
||||
"--editable",
|
||||
".[dev,docs,test]"
|
||||
],
|
||||
"dependsOn": "Create virtual environment",
|
||||
"dependsOrder": "sequence",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared",
|
||||
"showReuseMessage": true,
|
||||
"clear": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The fastest way to build InvokeAI now is ++cmd+shift+b++
|
||||
|
||||
## launch.json
|
||||
|
||||
This file is used to define debugger configurations, so that you can one-click
|
||||
launch and monitor the application, set halt points to inspect specific states,
|
||||
...
|
||||
|
||||
```json title=".vscode/launch.json"
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "invokeai web",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": ".venv/bin/invokeai",
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "invokeai cli",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": ".venv/bin/invokeai",
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "mkdocs serve",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": ".venv/bin/mkdocs",
|
||||
"args": ["serve"],
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Then you only need to hit ++f5++ and the fun begins :nerd: (It is asumed that
|
||||
you have created a virtual environment via the [tasks](#tasksjson) from the
|
||||
previous step.)
|
||||
|
||||
## extensions.json
|
||||
|
||||
A list of recommended vscode-extensions to make your life easier:
|
||||
|
||||
```json title=".vscode/extensions.json"
|
||||
{
|
||||
"recommendations": [
|
||||
"editorconfig.editorconfig",
|
||||
"github.vscode-pull-request-github",
|
||||
"ms-python.black-formatter",
|
||||
"ms-python.flake8",
|
||||
"ms-python.isort",
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"redhat.vscode-yaml",
|
||||
"tamasfe.even-better-toml",
|
||||
"eamodio.gitlens",
|
||||
"foxundermoon.shell-format",
|
||||
"timonwong.shellcheck",
|
||||
"esbenp.prettier-vscode",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"bierner.github-markdown-preview",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"mads-hartmann.bash-ide-vscode"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## settings.json
|
||||
|
||||
With bellow settings your files already get formated when you save them (only
|
||||
your modifications if available), which will help you to not run into trouble
|
||||
with the pre-commit hooks. If the hooks fail, they will prevent you from
|
||||
commiting, but most hooks directly add a fixed version, so that you just need to
|
||||
stage and commit them:
|
||||
|
||||
```json title=".vscode/settings.json"
|
||||
{
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.quickSuggestions": {
|
||||
"comments": false,
|
||||
"strings": true,
|
||||
"other": true
|
||||
},
|
||||
"editor.suggest.insertMode": "replace",
|
||||
"gitlens.codeLens.scopes": ["document"]
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "modificationsIfAvailable"
|
||||
},
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "file"
|
||||
},
|
||||
"[toml]": {
|
||||
"editor.defaultFormatter": "tamasfe.even-better-toml",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "modificationsIfAvailable"
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "modificationsIfAvailable"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.rulers": [80],
|
||||
"editor.unicodeHighlight.ambiguousCharacters": false,
|
||||
"editor.unicodeHighlight.invisibleCharacters": false,
|
||||
"diffEditor.ignoreTrimWhitespace": false,
|
||||
"editor.wordWrap": "on",
|
||||
"editor.quickSuggestions": {
|
||||
"comments": "off",
|
||||
"strings": "off",
|
||||
"other": "off"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "modificationsIfAvailable"
|
||||
},
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[ignore]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"editor.rulers": [88],
|
||||
"evenBetterToml.formatter.alignEntries": false,
|
||||
"evenBetterToml.formatter.allowedBlankLines": 1,
|
||||
"evenBetterToml.formatter.arrayAutoExpand": true,
|
||||
"evenBetterToml.formatter.arrayTrailingComma": true,
|
||||
"evenBetterToml.formatter.arrayAutoCollapse": true,
|
||||
"evenBetterToml.formatter.columnWidth": 88,
|
||||
"evenBetterToml.formatter.compactArrays": true,
|
||||
"evenBetterToml.formatter.compactInlineTables": true,
|
||||
"evenBetterToml.formatter.indentEntries": false,
|
||||
"evenBetterToml.formatter.inlineTableExpand": true,
|
||||
"evenBetterToml.formatter.reorderArrays": true,
|
||||
"evenBetterToml.formatter.reorderKeys": true,
|
||||
"evenBetterToml.formatter.compactEntries": false,
|
||||
"evenBetterToml.schema.enabled": true,
|
||||
"python.analysis.typeCheckingMode": "basic",
|
||||
"python.formatting.provider": "black",
|
||||
"python.languageServer": "Pylance",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.flake8Enabled": true,
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.testing.pytestArgs": [
|
||||
"tests",
|
||||
"--cov=ldm",
|
||||
"--cov-branch",
|
||||
"--cov-report=term:skip-covered"
|
||||
],
|
||||
"yaml.schemas": {
|
||||
"https://json.schemastore.org/prettierrc.json": "${workspaceFolder}/.prettierrc.yaml"
|
||||
}
|
||||
}
|
||||
```
|
135
docs/help/contributing/010_PULL_REQUEST.md
Normal file
135
docs/help/contributing/010_PULL_REQUEST.md
Normal file
@ -0,0 +1,135 @@
|
||||
---
|
||||
title: Pull-Request
|
||||
---
|
||||
|
||||
# :octicons-git-pull-request-16: Pull-Request
|
||||
|
||||
## pre-requirements
|
||||
|
||||
To follow the steps in this tutorial you will need:
|
||||
|
||||
- [GitHub](https://github.com) account
|
||||
- [git](https://git-scm.com/downloads) source controll
|
||||
- Text / Code Editor (personally I preffer
|
||||
[Visual Studio Code](https://code.visualstudio.com/Download))
|
||||
- Terminal:
|
||||
- If you are on Linux/MacOS you can use bash or zsh
|
||||
- for Windows Users the commands are written for PowerShell
|
||||
|
||||
## Fork Repository
|
||||
|
||||
The first step to be done if you want to contribute to InvokeAI, is to fork the
|
||||
rpeository.
|
||||
|
||||
Since you are already reading this doc, the easiest way to do so is by clicking
|
||||
[here](https://github.com/invoke-ai/InvokeAI/fork). You could also open
|
||||
[InvokeAI](https://github.com/invoke-ai/InvoekAI) and click on the "Fork" Button
|
||||
in the top right.
|
||||
|
||||
## Clone your fork
|
||||
|
||||
After you forked the Repository, you should clone it to your dev machine:
|
||||
|
||||
=== ":fontawesome-brands-linux:Linux / :simple-apple:macOS"
|
||||
|
||||
``` sh
|
||||
git clone https://github.com/<github username>/InvokeAI \
|
||||
&& cd InvokeAI
|
||||
```
|
||||
|
||||
=== ":fontawesome-brands-windows:Windows"
|
||||
|
||||
``` powershell
|
||||
git clone https://github.com/<github username>/InvokeAI `
|
||||
&& cd InvokeAI
|
||||
```
|
||||
|
||||
## Install in Editable Mode
|
||||
|
||||
To install InvokeAI in editable mode, (as always) we recommend to create and
|
||||
activate a venv first. Afterwards you can install the InvokeAI Package,
|
||||
including dev and docs extras in editable mode, follwed by the installation of
|
||||
the pre-commit hook:
|
||||
|
||||
=== ":fontawesome-brands-linux:Linux / :simple-apple:macOS"
|
||||
|
||||
``` sh
|
||||
python -m venv .venv \
|
||||
--prompt InvokeAI \
|
||||
--upgrade-deps \
|
||||
&& source .venv/bin/activate \
|
||||
&& pip install \
|
||||
--upgrade-deps \
|
||||
--use-pep517 \
|
||||
--editable=".[dev,docs]" \
|
||||
&& pre-commit install
|
||||
```
|
||||
|
||||
=== ":fontawesome-brands-windows:Windows"
|
||||
|
||||
``` powershell
|
||||
python -m venv .venv `
|
||||
--prompt InvokeAI `
|
||||
--upgrade-deps `
|
||||
&& .venv/scripts/activate.ps1 `
|
||||
&& pip install `
|
||||
--upgrade `
|
||||
--use-pep517 `
|
||||
--editable=".[dev,docs]" `
|
||||
&& pre-commit install
|
||||
```
|
||||
|
||||
## Create a branch
|
||||
|
||||
Make sure you are on main branch, from there create your feature branch:
|
||||
|
||||
=== ":fontawesome-brands-linux:Linux / :simple-apple:macOS"
|
||||
|
||||
``` sh
|
||||
git checkout main \
|
||||
&& git pull \
|
||||
&& git checkout -B <branch name>
|
||||
```
|
||||
|
||||
=== ":fontawesome-brands-windows:Windows"
|
||||
|
||||
``` powershell
|
||||
git checkout main `
|
||||
&& git pull `
|
||||
&& git checkout -B <branch name>
|
||||
```
|
||||
|
||||
## Commit your changes
|
||||
|
||||
When you are done with adding / updating content, you need to commit those
|
||||
changes to your repository before you can actually open an PR:
|
||||
|
||||
```{ .sh .annotate }
|
||||
git add <files you have changed> # (1)!
|
||||
git commit -m "A commit message which describes your change"
|
||||
git push
|
||||
```
|
||||
|
||||
1. Replace this with a space seperated list of the files you changed, like:
|
||||
`README.md foo.sh bar.json baz`
|
||||
|
||||
## Create a Pull Request
|
||||
|
||||
After pushing your changes, you are ready to create a Pull Request. just head
|
||||
over to your fork on [GitHub](https://github.com), which should already show you
|
||||
a message that there have been recent changes on your feature branch and a green
|
||||
button which you could use to create the PR.
|
||||
|
||||
The default target for your PRs would be the main branch of
|
||||
[invoke-ai/InvokeAI](https://github.com/invoke-ai/InvokeAI)
|
||||
|
||||
Another way would be to create it in VS-Code or via the GitHub CLI (or even via
|
||||
the GitHub CLI in a VS-Code Terminal Window 🤭):
|
||||
|
||||
```sh
|
||||
gh pr create
|
||||
```
|
||||
|
||||
The CLI will inform you if there are still unpushed commits on your branch. It
|
||||
will also prompt you for things like the the Title and the Body (Description) if
|
||||
you did not already pass them as arguments.
|
26
docs/help/contributing/020_ISSUES.md
Normal file
26
docs/help/contributing/020_ISSUES.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Issues
|
||||
---
|
||||
|
||||
# :octicons-issue-opened-16: Issues
|
||||
|
||||
## :fontawesome-solid-bug: Report a bug
|
||||
|
||||
If you stumbled over a bug while using InvokeAI, we would apreciate it a lot if
|
||||
you
|
||||
[open a issue](https://github.com/invoke-ai/InvokeAI/issues/new?assignees=&labels=bug&template=BUG_REPORT.yml&title=%5Bbug%5D%3A+)
|
||||
to inform us about the details so that our developers can look into it.
|
||||
|
||||
If you also know how to fix the bug, take a look [here](010_PULL_REQUEST.md) to
|
||||
find out how to create a Pull Request.
|
||||
|
||||
## Request a feature
|
||||
|
||||
If you have a idea for a new feature on your mind which you would like to see in
|
||||
InvokeAI, there is a
|
||||
[feature request](https://github.com/invoke-ai/InvokeAI/issues/new?assignees=&labels=bug&template=BUG_REPORT.yml&title=%5Bbug%5D%3A+)
|
||||
available in the issues section of the repository.
|
||||
|
||||
If you are just curious which features already got requested you can find the
|
||||
overview of open requests
|
||||
[here](https://github.com/invoke-ai/InvokeAI/labels/enhancement)
|
32
docs/help/contributing/030_DOCS.md
Normal file
32
docs/help/contributing/030_DOCS.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
title: docs
|
||||
---
|
||||
|
||||
# :simple-readthedocs: MkDocs-Material
|
||||
|
||||
If you want to contribute to the docs, there is a easy way to verify the results
|
||||
of your changes before commiting them.
|
||||
|
||||
Just follow the steps in the [Pull-Requests](010_PULL_REQUEST.md) docs, there we
|
||||
already
|
||||
[create a venv and install the docs extras](010_PULL_REQUEST.md#install-in-editable-mode).
|
||||
When installed it's as simple as:
|
||||
|
||||
```sh
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
This will build the docs locally and serve them on your local host, even
|
||||
auto-refresh is included, so you can just update a doc, save it and tab to the
|
||||
browser, without the needs of restarting the `mkdocs serve`.
|
||||
|
||||
More information about the "mkdocs flavored markdown syntax" can be found
|
||||
[here](https://squidfunk.github.io/mkdocs-material/reference/).
|
||||
|
||||
## :material-microsoft-visual-studio-code:VS-Code
|
||||
|
||||
We also provide a
|
||||
[launch configuration for VS-Code](../IDE-Settings/vs-code.md#launchjson) which
|
||||
includes a `mkdocs serve` entrypoint as well. You also don't have to worry about
|
||||
the formatting since this is automated via prettier, but this is of course not
|
||||
limited to VS-Code.
|
76
docs/help/contributing/090_NODE_TRANSFORMATION.md
Normal file
76
docs/help/contributing/090_NODE_TRANSFORMATION.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Tranformation to nodes
|
||||
|
||||
## Current state
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
web[WebUI];
|
||||
cli[CLI];
|
||||
web --> |img2img| generate(generate);
|
||||
web --> |txt2img| generate(generate);
|
||||
cli --> |txt2img| generate(generate);
|
||||
cli --> |img2img| generate(generate);
|
||||
generate --> model_manager;
|
||||
generate --> generators;
|
||||
generate --> ti_manager[TI Manager];
|
||||
generate --> etc;
|
||||
```
|
||||
|
||||
## Transitional Architecture
|
||||
|
||||
### first step
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
web[WebUI];
|
||||
cli[CLI];
|
||||
web --> |img2img| img2img_node(Img2img node);
|
||||
web --> |txt2img| generate(generate);
|
||||
img2img_node --> model_manager;
|
||||
img2img_node --> generators;
|
||||
cli --> |txt2img| generate;
|
||||
cli --> |img2img| generate;
|
||||
generate --> model_manager;
|
||||
generate --> generators;
|
||||
generate --> ti_manager[TI Manager];
|
||||
generate --> etc;
|
||||
```
|
||||
|
||||
### second step
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
web[WebUI];
|
||||
cli[CLI];
|
||||
web --> |img2img| img2img_node(img2img node);
|
||||
img2img_node --> model_manager;
|
||||
img2img_node --> generators;
|
||||
web --> |txt2img| txt2img_node(txt2img node);
|
||||
cli --> |txt2img| txt2img_node;
|
||||
cli --> |img2img| generate(generate);
|
||||
generate --> model_manager;
|
||||
generate --> generators;
|
||||
generate --> ti_manager[TI Manager];
|
||||
generate --> etc;
|
||||
txt2img_node --> model_manager;
|
||||
txt2img_node --> generators;
|
||||
txt2img_node --> ti_manager[TI Manager];
|
||||
```
|
||||
|
||||
## Final Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
web[WebUI];
|
||||
cli[CLI];
|
||||
web --> |img2img|img2img_node(img2img node);
|
||||
cli --> |img2img|img2img_node;
|
||||
web --> |txt2img|txt2img_node(txt2img node);
|
||||
cli --> |txt2img|txt2img_node;
|
||||
img2img_node --> model_manager;
|
||||
txt2img_node --> model_manager;
|
||||
img2img_node --> generators;
|
||||
txt2img_node --> generators;
|
||||
img2img_node --> ti_manager[TI Manager];
|
||||
txt2img_node --> ti_manager[TI Manager];
|
||||
```
|
16
docs/help/contributing/index.md
Normal file
16
docs/help/contributing/index.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: Contributing
|
||||
---
|
||||
|
||||
# :fontawesome-solid-code-commit: Contributing
|
||||
|
||||
There are different ways how you can contribute to
|
||||
[InvokeAI](https://github.com/invoke-ai/InvokeAI), like Translations, opening
|
||||
Issues for Bugs or ideas how to improve.
|
||||
|
||||
This Section of the docs will explain some of the different ways of how you can
|
||||
contribute to make it easier for newcommers as well as advanced users :nerd:
|
||||
|
||||
If you want to contribute code, but you do not have an exact idea yet, take a
|
||||
look at the currently open
|
||||
[:fontawesome-solid-bug: Bug Reports](https://github.com/invoke-ai/InvokeAI/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
12
docs/help/index.md
Normal file
12
docs/help/index.md
Normal file
@ -0,0 +1,12 @@
|
||||
# :material-help:Help
|
||||
|
||||
If you are looking for help with the installation of InvokeAI, please take a
|
||||
look into the [Installation](../installation/index.md) section of the docs.
|
||||
|
||||
Here you will find help to topics like
|
||||
|
||||
- how to contribute
|
||||
- configuration recommendation for IDEs
|
||||
|
||||
If you have an Idea about what's missing and aren't scared from contributing,
|
||||
just take a look at [DOCS](./contributing/030_DOCS.md) to find out how to do so.
|
295
docs/index.md
295
docs/index.md
@ -2,6 +2,8 @@
|
||||
title: Home
|
||||
---
|
||||
|
||||
# :octicons-home-16: Home
|
||||
|
||||
<!--
|
||||
The Docs you find here (/docs/*) are built and deployed via mkdocs. If you want to run a local version to verify your changes, it's as simple as::
|
||||
|
||||
@ -29,36 +31,36 @@ title: Home
|
||||
[![github open prs badge]][github open prs link]
|
||||
|
||||
[ci checks on dev badge]:
|
||||
https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||
https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||
[ci checks on dev link]:
|
||||
https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment
|
||||
https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment
|
||||
[ci checks on main badge]:
|
||||
https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||
https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||
[ci checks on main link]:
|
||||
https://github.com/invoke-ai/InvokeAI/actions/workflows/test-invoke-conda.yml
|
||||
https://github.com/invoke-ai/InvokeAI/actions/workflows/test-invoke-conda.yml
|
||||
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
||||
[discord link]: https://discord.gg/ZmtBAhwWhy
|
||||
[github forks badge]:
|
||||
https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
||||
https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
||||
[github forks link]:
|
||||
https://useful-forks.github.io/?repo=lstein%2Fstable-diffusion
|
||||
https://useful-forks.github.io/?repo=lstein%2Fstable-diffusion
|
||||
[github open issues badge]:
|
||||
https://flat.badgen.net/github/open-issues/invoke-ai/InvokeAI?icon=github
|
||||
https://flat.badgen.net/github/open-issues/invoke-ai/InvokeAI?icon=github
|
||||
[github open issues link]:
|
||||
https://github.com/invoke-ai/InvokeAI/issues?q=is%3Aissue+is%3Aopen
|
||||
https://github.com/invoke-ai/InvokeAI/issues?q=is%3Aissue+is%3Aopen
|
||||
[github open prs badge]:
|
||||
https://flat.badgen.net/github/open-prs/invoke-ai/InvokeAI?icon=github
|
||||
https://flat.badgen.net/github/open-prs/invoke-ai/InvokeAI?icon=github
|
||||
[github open prs link]:
|
||||
https://github.com/invoke-ai/InvokeAI/pulls?q=is%3Apr+is%3Aopen
|
||||
https://github.com/invoke-ai/InvokeAI/pulls?q=is%3Apr+is%3Aopen
|
||||
[github stars badge]:
|
||||
https://flat.badgen.net/github/stars/invoke-ai/InvokeAI?icon=github
|
||||
https://flat.badgen.net/github/stars/invoke-ai/InvokeAI?icon=github
|
||||
[github stars link]: https://github.com/invoke-ai/InvokeAI/stargazers
|
||||
[latest commit to dev badge]:
|
||||
https://flat.badgen.net/github/last-commit/invoke-ai/InvokeAI/development?icon=github&color=yellow&label=last%20dev%20commit&cache=900
|
||||
https://flat.badgen.net/github/last-commit/invoke-ai/InvokeAI/development?icon=github&color=yellow&label=last%20dev%20commit&cache=900
|
||||
[latest commit to dev link]:
|
||||
https://github.com/invoke-ai/InvokeAI/commits/development
|
||||
https://github.com/invoke-ai/InvokeAI/commits/development
|
||||
[latest release badge]:
|
||||
https://flat.badgen.net/github/release/invoke-ai/InvokeAI/development?icon=github
|
||||
https://flat.badgen.net/github/release/invoke-ai/InvokeAI/development?icon=github
|
||||
[latest release link]: https://github.com/invoke-ai/InvokeAI/releases
|
||||
|
||||
</div>
|
||||
@ -87,24 +89,24 @@ Q&A</a>]
|
||||
|
||||
You wil need one of the following:
|
||||
|
||||
- :simple-nvidia: An NVIDIA-based graphics card with 4 GB or more VRAM memory.
|
||||
- :simple-amd: An AMD-based graphics card with 4 GB or more VRAM memory (Linux
|
||||
only)
|
||||
- :fontawesome-brands-apple: An Apple computer with an M1 chip.
|
||||
- :simple-nvidia: An NVIDIA-based graphics card with 4 GB or more VRAM memory.
|
||||
- :simple-amd: An AMD-based graphics card with 4 GB or more VRAM memory (Linux
|
||||
only)
|
||||
- :fontawesome-brands-apple: An Apple computer with an M1 chip.
|
||||
|
||||
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
|
||||
- NVIDIA 10xx series cards such as the 1080ti
|
||||
- GTX 1650 series cards
|
||||
- GTX 1660 series cards
|
||||
|
||||
### :fontawesome-solid-memory: Memory and Disk
|
||||
|
||||
- At least 12 GB Main Memory RAM.
|
||||
- At least 18 GB of free disk space for the machine learning model, Python, and
|
||||
all its dependencies.
|
||||
- At least 12 GB Main Memory RAM.
|
||||
- At least 18 GB of free disk space for the machine learning model, Python,
|
||||
and all its dependencies.
|
||||
|
||||
## :octicons-package-dependencies-24: Installation
|
||||
|
||||
@ -113,48 +115,65 @@ either an Nvidia-based card (with CUDA support) or an AMD card (using the ROCm
|
||||
driver).
|
||||
|
||||
### [Installation Getting Started Guide](installation)
|
||||
|
||||
#### [Automated Installer](installation/010_INSTALL_AUTOMATED.md)
|
||||
|
||||
This method is recommended for 1st time users
|
||||
|
||||
#### [Manual Installation](installation/020_INSTALL_MANUAL.md)
|
||||
|
||||
This method is recommended for experienced users and developers
|
||||
|
||||
#### [Docker Installation](installation/040_INSTALL_DOCKER.md)
|
||||
|
||||
This method is recommended for those familiar with running Docker containers
|
||||
|
||||
### Other Installation Guides
|
||||
- [PyPatchMatch](installation/060_INSTALL_PATCHMATCH.md)
|
||||
- [XFormers](installation/070_INSTALL_XFORMERS.md)
|
||||
- [CUDA and ROCm Drivers](installation/030_INSTALL_CUDA_AND_ROCM.md)
|
||||
- [Installing New Models](installation/050_INSTALLING_MODELS.md)
|
||||
|
||||
- [PyPatchMatch](installation/060_INSTALL_PATCHMATCH.md)
|
||||
- [XFormers](installation/070_INSTALL_XFORMERS.md)
|
||||
- [CUDA and ROCm Drivers](installation/030_INSTALL_CUDA_AND_ROCM.md)
|
||||
- [Installing New Models](installation/050_INSTALLING_MODELS.md)
|
||||
|
||||
## :octicons-gift-24: InvokeAI Features
|
||||
|
||||
### The InvokeAI Web Interface
|
||||
- [WebUI overview](features/WEB.md)
|
||||
- [WebUI hotkey reference guide](features/WEBUIHOTKEYS.md)
|
||||
- [WebUI Unified Canvas for Img2Img, inpainting and outpainting](features/UNIFIED_CANVAS.md)
|
||||
|
||||
- [WebUI overview](features/WEB.md)
|
||||
- [WebUI hotkey reference guide](features/WEBUIHOTKEYS.md)
|
||||
- [WebUI Unified Canvas for Img2Img, inpainting and outpainting](features/UNIFIED_CANVAS.md)
|
||||
<!-- separator -->
|
||||
|
||||
### The InvokeAI Command Line Interface
|
||||
- [Command Line Interace Reference Guide](features/CLI.md)
|
||||
|
||||
- [Command Line Interace Reference Guide](features/CLI.md)
|
||||
<!-- separator -->
|
||||
|
||||
### Image Management
|
||||
- [Image2Image](features/IMG2IMG.md)
|
||||
- [Inpainting](features/INPAINTING.md)
|
||||
- [Outpainting](features/OUTPAINTING.md)
|
||||
- [Adding custom styles and subjects](features/CONCEPTS.md)
|
||||
- [Upscaling and Face Reconstruction](features/POSTPROCESS.md)
|
||||
- [Embiggen upscaling](features/EMBIGGEN.md)
|
||||
- [Other Features](features/OTHER.md)
|
||||
|
||||
- [Image2Image](features/IMG2IMG.md)
|
||||
- [Inpainting](features/INPAINTING.md)
|
||||
- [Outpainting](features/OUTPAINTING.md)
|
||||
- [Adding custom styles and subjects](features/CONCEPTS.md)
|
||||
- [Upscaling and Face Reconstruction](features/POSTPROCESS.md)
|
||||
- [Embiggen upscaling](features/EMBIGGEN.md)
|
||||
- [Other Features](features/OTHER.md)
|
||||
|
||||
<!-- separator -->
|
||||
|
||||
### Model Management
|
||||
- [Installing](installation/050_INSTALLING_MODELS.md)
|
||||
- [Model Merging](features/MODEL_MERGING.md)
|
||||
- [Style/Subject Concepts and Embeddings](features/CONCEPTS.md)
|
||||
- [Textual Inversion](features/TEXTUAL_INVERSION.md)
|
||||
- [Not Safe for Work (NSFW) Checker](features/NSFW.md)
|
||||
|
||||
- [Installing](installation/050_INSTALLING_MODELS.md)
|
||||
- [Model Merging](features/MODEL_MERGING.md)
|
||||
- [Style/Subject Concepts and Embeddings](features/CONCEPTS.md)
|
||||
- [Textual Inversion](features/TEXTUAL_INVERSION.md)
|
||||
- [Not Safe for Work (NSFW) Checker](features/NSFW.md)
|
||||
<!-- seperator -->
|
||||
|
||||
### Prompt Engineering
|
||||
- [Prompt Syntax](features/PROMPTS.md)
|
||||
- [Generating Variations](features/VARIATIONS.md)
|
||||
|
||||
- [Prompt Syntax](features/PROMPTS.md)
|
||||
- [Generating Variations](features/VARIATIONS.md)
|
||||
|
||||
## :octicons-log-16: Latest Changes
|
||||
|
||||
@ -162,84 +181,188 @@ This method is recommended for those familiar with running Docker containers
|
||||
|
||||
#### Migration to Stable Diffusion `diffusers` models
|
||||
|
||||
Previous versions of InvokeAI supported the original model file format introduced with Stable Diffusion 1.4. In the original format, known variously as "checkpoint", or "legacy" format, there is a single large weights file ending with `.ckpt` or `.safetensors`. Though this format has served the community well, it has a number of disadvantages, including file size, slow loading times, and a variety of non-standard variants that require special-case code to handle. In addition, because checkpoint files are actually a bundle of multiple machine learning sub-models, it is hard to swap different sub-models in and out, or to share common sub-models. A new format, introduced by the StabilityAI company in collaboration with HuggingFace, is called `diffusers` and consists of a directory of individual models. The most immediate benefit of `diffusers` is that they load from disk very quickly. A longer term benefit is that in the near future `diffusers` models will be able to share common sub-models, dramatically reducing disk space when you have multiple fine-tune models derived from the same base.
|
||||
Previous versions of InvokeAI supported the original model file format
|
||||
introduced with Stable Diffusion 1.4. In the original format, known variously as
|
||||
"checkpoint", or "legacy" format, there is a single large weights file ending
|
||||
with `.ckpt` or `.safetensors`. Though this format has served the community
|
||||
well, it has a number of disadvantages, including file size, slow loading times,
|
||||
and a variety of non-standard variants that require special-case code to handle.
|
||||
In addition, because checkpoint files are actually a bundle of multiple machine
|
||||
learning sub-models, it is hard to swap different sub-models in and out, or to
|
||||
share common sub-models. A new format, introduced by the StabilityAI company in
|
||||
collaboration with HuggingFace, is called `diffusers` and consists of a
|
||||
directory of individual models. The most immediate benefit of `diffusers` is
|
||||
that they load from disk very quickly. A longer term benefit is that in the near
|
||||
future `diffusers` models will be able to share common sub-models, dramatically
|
||||
reducing disk space when you have multiple fine-tune models derived from the
|
||||
same base.
|
||||
|
||||
When you perform a new install of version 2.3.0, you will be offered the option to install the `diffusers` versions of a number of popular SD models, including Stable Diffusion versions 1.5 and 2.1 (including the 768x768 pixel version of 2.1). These will act and work just like the checkpoint versions. Do not be concerned if you already have a lot of ".ckpt" or ".safetensors" models on disk! InvokeAI 2.3.0 can still load these and generate images from them without any extra intervention on your part.
|
||||
When you perform a new install of version 2.3.0, you will be offered the option
|
||||
to install the `diffusers` versions of a number of popular SD models, including
|
||||
Stable Diffusion versions 1.5 and 2.1 (including the 768x768 pixel version of
|
||||
2.1). These will act and work just like the checkpoint versions. Do not be
|
||||
concerned if you already have a lot of ".ckpt" or ".safetensors" models on disk!
|
||||
InvokeAI 2.3.0 can still load these and generate images from them without any
|
||||
extra intervention on your part.
|
||||
|
||||
To take advantage of the optimized loading times of `diffusers` models, InvokeAI offers options to convert legacy checkpoint models into optimized `diffusers` models. If you use the `invokeai` command line interface, the relevant commands are:
|
||||
To take advantage of the optimized loading times of `diffusers` models, InvokeAI
|
||||
offers options to convert legacy checkpoint models into optimized `diffusers`
|
||||
models. If you use the `invokeai` command line interface, the relevant commands
|
||||
are:
|
||||
|
||||
* `!convert_model` -- Take the path to a local checkpoint file or a URL that is pointing to one, convert it into a `diffusers` model, and import it into InvokeAI's models registry file.
|
||||
* `!optimize_model` -- If you already have a checkpoint model in your InvokeAI models file, this command will accept its short name and convert it into a like-named `diffusers` model, optionally deleting the original checkpoint file.
|
||||
* `!import_model` -- Take the local path of either a checkpoint file or a `diffusers` model directory and import it into InvokeAI's registry file. You may also provide the ID of any diffusers model that has been published on the [HuggingFace models repository](https://huggingface.co/models?pipeline_tag=text-to-image&sort=downloads) and it will be downloaded and installed automatically.
|
||||
- `!convert_model` -- Take the path to a local checkpoint file or a URL that
|
||||
is pointing to one, convert it into a `diffusers` model, and import it into
|
||||
InvokeAI's models registry file.
|
||||
- `!optimize_model` -- If you already have a checkpoint model in your InvokeAI
|
||||
models file, this command will accept its short name and convert it into a
|
||||
like-named `diffusers` model, optionally deleting the original checkpoint
|
||||
file.
|
||||
- `!import_model` -- Take the local path of either a checkpoint file or a
|
||||
`diffusers` model directory and import it into InvokeAI's registry file. You
|
||||
may also provide the ID of any diffusers model that has been published on
|
||||
the
|
||||
[HuggingFace models repository](https://huggingface.co/models?pipeline_tag=text-to-image&sort=downloads)
|
||||
and it will be downloaded and installed automatically.
|
||||
|
||||
The WebGUI offers similar functionality for model management.
|
||||
|
||||
For advanced users, new command-line options provide additional functionality. Launching `invokeai` with the argument `--autoconvert <path to directory>` takes the path to a directory of checkpoint files, automatically converts them into `diffusers` models and imports them. Each time the script is launched, the directory will be scanned for new checkpoint files to be loaded. Alternatively, the `--ckpt_convert` argument will cause any checkpoint or safetensors model that is already registered with InvokeAI to be converted into a `diffusers` model on the fly, allowing you to take advantage of future diffusers-only features without explicitly converting the model and saving it to disk.
|
||||
For advanced users, new command-line options provide additional functionality.
|
||||
Launching `invokeai` with the argument `--autoconvert <path to directory>` takes
|
||||
the path to a directory of checkpoint files, automatically converts them into
|
||||
`diffusers` models and imports them. Each time the script is launched, the
|
||||
directory will be scanned for new checkpoint files to be loaded. Alternatively,
|
||||
the `--ckpt_convert` argument will cause any checkpoint or safetensors model
|
||||
that is already registered with InvokeAI to be converted into a `diffusers`
|
||||
model on the fly, allowing you to take advantage of future diffusers-only
|
||||
features without explicitly converting the model and saving it to disk.
|
||||
|
||||
Please see [INSTALLING MODELS](https://invoke-ai.github.io/InvokeAI/installation/050_INSTALLING_MODELS/) for more information on model management in both the command-line and Web interfaces.
|
||||
Please see
|
||||
[INSTALLING MODELS](https://invoke-ai.github.io/InvokeAI/installation/050_INSTALLING_MODELS/)
|
||||
for more information on model management in both the command-line and Web
|
||||
interfaces.
|
||||
|
||||
#### Support for the `XFormers` Memory-Efficient Crossattention Package
|
||||
|
||||
On CUDA (Nvidia) systems, version 2.3.0 supports the `XFormers` library. Once installed, the`xformers` package dramatically reduces the memory footprint of loaded Stable Diffusion models files and modestly increases image generation speed. `xformers` will be installed and activated automatically if you specify a CUDA system at install time.
|
||||
On CUDA (Nvidia) systems, version 2.3.0 supports the `XFormers` library. Once
|
||||
installed, the`xformers` package dramatically reduces the memory footprint of
|
||||
loaded Stable Diffusion models files and modestly increases image generation
|
||||
speed. `xformers` will be installed and activated automatically if you specify a
|
||||
CUDA system at install time.
|
||||
|
||||
The caveat with using `xformers` is that it introduces slightly non-deterministic behavior, and images generated using the same seed and other settings will be subtly different between invocations. Generally the changes are unnoticeable unless you rapidly shift back and forth between images, but to disable `xformers` and restore fully deterministic behavior, you may launch InvokeAI using the `--no-xformers` option. This is most conveniently done by opening the file `invokeai/invokeai.init` with a text editor, and adding the line `--no-xformers` at the bottom.
|
||||
The caveat with using `xformers` is that it introduces slightly
|
||||
non-deterministic behavior, and images generated using the same seed and other
|
||||
settings will be subtly different between invocations. Generally the changes are
|
||||
unnoticeable unless you rapidly shift back and forth between images, but to
|
||||
disable `xformers` and restore fully deterministic behavior, you may launch
|
||||
InvokeAI using the `--no-xformers` option. This is most conveniently done by
|
||||
opening the file `invokeai/invokeai.init` with a text editor, and adding the
|
||||
line `--no-xformers` at the bottom.
|
||||
|
||||
#### A Negative Prompt Box in the WebUI
|
||||
|
||||
There is now a separate text input box for negative prompts in the WebUI. This is convenient for stashing frequently-used negative prompts ("mangled limbs, bad anatomy"). The `[negative prompt]` syntax continues to work in the main prompt box as well.
|
||||
There is now a separate text input box for negative prompts in the WebUI. This
|
||||
is convenient for stashing frequently-used negative prompts ("mangled limbs, bad
|
||||
anatomy"). The `[negative prompt]` syntax continues to work in the main prompt
|
||||
box as well.
|
||||
|
||||
To see exactly how your prompts are being parsed, launch `invokeai` with the `--log_tokenization` option. The console window will then display the tokenization process for both positive and negative prompts.
|
||||
To see exactly how your prompts are being parsed, launch `invokeai` with the
|
||||
`--log_tokenization` option. The console window will then display the
|
||||
tokenization process for both positive and negative prompts.
|
||||
|
||||
#### Model Merging
|
||||
|
||||
Version 2.3.0 offers an intuitive user interface for merging up to three Stable Diffusion models using an intuitive user interface. Model merging allows you to mix the behavior of models to achieve very interesting effects. To use this, each of the models must already be imported into InvokeAI and saved in `diffusers` format, then launch the merger using a new menu item in the InvokeAI launcher script (`invoke.sh`, `invoke.bat`) or directly from the command line with `invokeai-merge --gui`. You will be prompted to select the models to merge, the proportions in which to mix them, and the mixing algorithm. The script will create a new merged `diffusers` model and import it into InvokeAI for your use.
|
||||
Version 2.3.0 offers an intuitive user interface for merging up to three Stable
|
||||
Diffusion models using an intuitive user interface. Model merging allows you to
|
||||
mix the behavior of models to achieve very interesting effects. To use this,
|
||||
each of the models must already be imported into InvokeAI and saved in
|
||||
`diffusers` format, then launch the merger using a new menu item in the InvokeAI
|
||||
launcher script (`invoke.sh`, `invoke.bat`) or directly from the command line
|
||||
with `invokeai-merge --gui`. You will be prompted to select the models to merge,
|
||||
the proportions in which to mix them, and the mixing algorithm. The script will
|
||||
create a new merged `diffusers` model and import it into InvokeAI for your use.
|
||||
|
||||
See [MODEL MERGING](https://invoke-ai.github.io/InvokeAI/features/MODEL_MERGING/) for more details.
|
||||
See
|
||||
[MODEL MERGING](https://invoke-ai.github.io/InvokeAI/features/MODEL_MERGING/)
|
||||
for more details.
|
||||
|
||||
#### Textual Inversion Training
|
||||
|
||||
Textual Inversion (TI) is a technique for training a Stable Diffusion model to emit a particular subject or style when triggered by a keyword phrase. You can perform TI training by placing a small number of images of the subject or style in a directory, and choosing a distinctive trigger phrase, such as "pointillist-style". After successful training, The subject or style will be activated by including `<pointillist-style>` in your prompt.
|
||||
Textual Inversion (TI) is a technique for training a Stable Diffusion model to
|
||||
emit a particular subject or style when triggered by a keyword phrase. You can
|
||||
perform TI training by placing a small number of images of the subject or style
|
||||
in a directory, and choosing a distinctive trigger phrase, such as
|
||||
"pointillist-style". After successful training, The subject or style will be
|
||||
activated by including `<pointillist-style>` in your prompt.
|
||||
|
||||
Previous versions of InvokeAI were able to perform TI, but it required using a command-line script with dozens of obscure command-line arguments. Version 2.3.0 features an intuitive TI frontend that will build a TI model on top of any `diffusers` model. To access training you can launch from a new item in the launcher script or from the command line using `invokeai-ti --gui`.
|
||||
Previous versions of InvokeAI were able to perform TI, but it required using a
|
||||
command-line script with dozens of obscure command-line arguments. Version 2.3.0
|
||||
features an intuitive TI frontend that will build a TI model on top of any
|
||||
`diffusers` model. To access training you can launch from a new item in the
|
||||
launcher script or from the command line using `invokeai-ti --gui`.
|
||||
|
||||
See [TEXTUAL INVERSION](https://invoke-ai.github.io/InvokeAI/features/TEXTUAL_INVERSION/) for further details.
|
||||
See
|
||||
[TEXTUAL INVERSION](https://invoke-ai.github.io/InvokeAI/features/TEXTUAL_INVERSION/)
|
||||
for further details.
|
||||
|
||||
#### A New Installer Experience
|
||||
|
||||
The InvokeAI installer has been upgraded in order to provide a smoother and hopefully more glitch-free experience. In addition, InvokeAI is now packaged as a PyPi project, allowing developers and power-users to install InvokeAI with the command `pip install InvokeAI --use-pep517`. Please see [Installation](#installation) for details.
|
||||
The InvokeAI installer has been upgraded in order to provide a smoother and
|
||||
hopefully more glitch-free experience. In addition, InvokeAI is now packaged as
|
||||
a PyPi project, allowing developers and power-users to install InvokeAI with the
|
||||
command `pip install InvokeAI --use-pep517`. Please see
|
||||
[Installation](#installation) for details.
|
||||
|
||||
Developers should be aware that the `pip` installation procedure has been simplified and that the `conda` method is no longer supported at all. Accordingly, the `environments_and_requirements` directory has been deleted from the repository.
|
||||
Developers should be aware that the `pip` installation procedure has been
|
||||
simplified and that the `conda` method is no longer supported at all.
|
||||
Accordingly, the `environments_and_requirements` directory has been deleted from
|
||||
the repository.
|
||||
|
||||
#### Command-line name changes
|
||||
|
||||
All of InvokeAI's functionality, including the WebUI, command-line interface, textual inversion training and model merging, can all be accessed from the `invoke.sh` and `invoke.bat` launcher scripts. The menu of options has been expanded to add the new functionality. For the convenience of developers and power users, we have normalized the names of the InvokeAI command-line scripts:
|
||||
All of InvokeAI's functionality, including the WebUI, command-line interface,
|
||||
textual inversion training and model merging, can all be accessed from the
|
||||
`invoke.sh` and `invoke.bat` launcher scripts. The menu of options has been
|
||||
expanded to add the new functionality. For the convenience of developers and
|
||||
power users, we have normalized the names of the InvokeAI command-line scripts:
|
||||
|
||||
* `invokeai` -- Command-line client
|
||||
* `invokeai --web` -- Web GUI
|
||||
* `invokeai-merge --gui` -- Model merging script with graphical front end
|
||||
* `invokeai-ti --gui` -- Textual inversion script with graphical front end
|
||||
* `invokeai-configure` -- Configuration tool for initializing the `invokeai` directory and selecting popular starter models.
|
||||
- `invokeai` -- Command-line client
|
||||
- `invokeai --web` -- Web GUI
|
||||
- `invokeai-merge --gui` -- Model merging script with graphical front end
|
||||
- `invokeai-ti --gui` -- Textual inversion script with graphical front end
|
||||
- `invokeai-configure` -- Configuration tool for initializing the `invokeai`
|
||||
directory and selecting popular starter models.
|
||||
|
||||
For backward compatibility, the old command names are also recognized, including `invoke.py` and `configure-invokeai.py`. However, these are deprecated and will eventually be removed.
|
||||
For backward compatibility, the old command names are also recognized, including
|
||||
`invoke.py` and `configure-invokeai.py`. However, these are deprecated and will
|
||||
eventually be removed.
|
||||
|
||||
Developers should be aware that the locations of the script's source code has been moved. The new locations are:
|
||||
* `invokeai` => `ldm/invoke/CLI.py`
|
||||
* `invokeai-configure` => `ldm/invoke/config/configure_invokeai.py`
|
||||
* `invokeai-ti`=> `ldm/invoke/training/textual_inversion.py`
|
||||
* `invokeai-merge` => `ldm/invoke/merge_diffusers`
|
||||
Developers should be aware that the locations of the script's source code has
|
||||
been moved. The new locations are:
|
||||
|
||||
Developers are strongly encouraged to perform an "editable" install of InvokeAI using `pip install -e . --use-pep517` in the Git repository, and then to call the scripts using their 2.3.0 names, rather than executing the scripts directly. Developers should also be aware that the several important data files have been relocated into a new directory named `invokeai`. This includes the WebGUI's `frontend` and `backend` directories, and the `INITIAL_MODELS.yaml` files used by the installer to select starter models. Eventually all InvokeAI modules will be in subdirectories of `invokeai`.
|
||||
- `invokeai` => `ldm/invoke/CLI.py`
|
||||
- `invokeai-configure` => `ldm/invoke/config/configure_invokeai.py`
|
||||
- `invokeai-ti`=> `ldm/invoke/training/textual_inversion.py`
|
||||
- `invokeai-merge` => `ldm/invoke/merge_diffusers`
|
||||
|
||||
Please see [2.3.0 Release Notes](https://github.com/invoke-ai/InvokeAI/releases/tag/v2.3.0) for further details.
|
||||
For older changelogs, please visit the
|
||||
Developers are strongly encouraged to perform an "editable" install of InvokeAI
|
||||
using `pip install -e . --use-pep517` in the Git repository, and then to call
|
||||
the scripts using their 2.3.0 names, rather than executing the scripts directly.
|
||||
Developers should also be aware that the several important data files have been
|
||||
relocated into a new directory named `invokeai`. This includes the WebGUI's
|
||||
`frontend` and `backend` directories, and the `INITIAL_MODELS.yaml` files used
|
||||
by the installer to select starter models. Eventually all InvokeAI modules will
|
||||
be in subdirectories of `invokeai`.
|
||||
|
||||
Please see
|
||||
[2.3.0 Release Notes](https://github.com/invoke-ai/InvokeAI/releases/tag/v2.3.0)
|
||||
for further details. For older changelogs, please visit the
|
||||
**[CHANGELOG](CHANGELOG/#v223-2-december-2022)**.
|
||||
|
||||
## :material-target: Troubleshooting
|
||||
|
||||
Please check out our **[:material-frequently-asked-questions:
|
||||
Troubleshooting
|
||||
Guide](installation/010_INSTALL_AUTOMATED.md#troubleshooting)** to
|
||||
get solutions for common installation problems and other issues.
|
||||
Please check out our
|
||||
**[:material-frequently-asked-questions: Troubleshooting Guide](installation/010_INSTALL_AUTOMATED.md#troubleshooting)**
|
||||
to get solutions for common installation problems and other issues.
|
||||
|
||||
## :octicons-repo-push-24: Contributing
|
||||
|
||||
@ -265,8 +388,8 @@ thank them for their time, hard work and effort.
|
||||
For support, please use this repository's GitHub Issues tracking service. Feel
|
||||
free to send me an email if you use and like the script.
|
||||
|
||||
Original portions of the software are Copyright (c) 2022-23
|
||||
by [The InvokeAI Team](https://github.com/invoke-ai).
|
||||
Original portions of the software are Copyright (c) 2022-23 by
|
||||
[The InvokeAI Team](https://github.com/invoke-ai).
|
||||
|
||||
## :octicons-book-24: Further Reading
|
||||
|
||||
|
@ -417,7 +417,7 @@ Then type the following commands:
|
||||
|
||||
=== "AMD System"
|
||||
```bash
|
||||
pip install torch torchvision --force-reinstall --extra-index-url https://download.pytorch.org/whl/rocm5.2
|
||||
pip install torch torchvision --force-reinstall --extra-index-url https://download.pytorch.org/whl/rocm5.4.2
|
||||
```
|
||||
|
||||
### Corrupted configuration file
|
||||
|
@ -110,7 +110,7 @@ recipes are available
|
||||
|
||||
When installing torch and torchvision manually with `pip`, remember to provide
|
||||
the argument `--extra-index-url
|
||||
https://download.pytorch.org/whl/rocm5.2` as described in the [Manual
|
||||
https://download.pytorch.org/whl/rocm5.4.2` as described in the [Manual
|
||||
Installation Guide](020_INSTALL_MANUAL.md).
|
||||
|
||||
This will be done automatically for you if you use the installer
|
||||
|
@ -211,6 +211,26 @@ description for the model, whether to make this the default model that
|
||||
is loaded at InvokeAI startup time, and whether to replace its
|
||||
VAE. Generally the answer to the latter question is "no".
|
||||
|
||||
### Specifying a configuration file for legacy checkpoints
|
||||
|
||||
Some checkpoint files come with instructions to use a specific .yaml
|
||||
configuration file. For InvokeAI load this file correctly, please put
|
||||
the config file in the same directory as the corresponding `.ckpt` or
|
||||
`.safetensors` file and make sure the file has the same basename as
|
||||
the weights file. Here is an example:
|
||||
|
||||
```bash
|
||||
wonderful-model-v2.ckpt
|
||||
wonderful-model-v2.yaml
|
||||
```
|
||||
|
||||
Similarly, to use a custom VAE, name the VAE like this:
|
||||
|
||||
```bash
|
||||
wonderful-model-v2.vae.pt
|
||||
```
|
||||
|
||||
|
||||
### Converting legacy models into `diffusers`
|
||||
|
||||
The CLI `!convert_model` will convert a `.safetensors` or `.ckpt`
|
||||
|
@ -1,5 +0,0 @@
|
||||
mkdocs
|
||||
mkdocs-material>=8, <9
|
||||
mkdocs-git-revision-date-localized-plugin
|
||||
mkdocs-redirects==1.2.0
|
||||
|
@ -241,14 +241,18 @@ class InvokeAiInstance:
|
||||
|
||||
from plumbum import FG, local
|
||||
|
||||
# Note that we're installing pinned versions of torch and
|
||||
# torchvision here, which may not correspond to what is
|
||||
# in pyproject.toml. This is a hack to prevent torch 2.0 from
|
||||
# being installed and immediately uninstalled and replaced with 1.13
|
||||
pip = local[self.pip]
|
||||
|
||||
(
|
||||
pip[
|
||||
"install",
|
||||
"--require-virtualenv",
|
||||
"torch",
|
||||
"torchvision",
|
||||
"torch~=1.13.1",
|
||||
"torchvision>=0.14.1",
|
||||
"--force-reinstall",
|
||||
"--find-links" if find_links is not None else None,
|
||||
find_links,
|
||||
@ -379,6 +383,9 @@ class InvokeAiInstance:
|
||||
shutil.copy(src, dest)
|
||||
os.chmod(dest, 0o0755)
|
||||
|
||||
if OS == "Linux":
|
||||
shutil.copy(Path(__file__).parent / '..' / "templates" / "dialogrc", self.runtime / '.dialogrc')
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
|
27
installer/templates/dialogrc
Normal file
27
installer/templates/dialogrc
Normal file
@ -0,0 +1,27 @@
|
||||
# Screen
|
||||
use_shadow = OFF
|
||||
use_colors = ON
|
||||
screen_color = (BLACK, BLACK, ON)
|
||||
|
||||
# Box
|
||||
dialog_color = (YELLOW, BLACK , ON)
|
||||
title_color = (YELLOW, BLACK, ON)
|
||||
border_color = (YELLOW, BLACK, OFF)
|
||||
border2_color = (YELLOW, BLACK, OFF)
|
||||
|
||||
# Button
|
||||
button_active_color = (RED, BLACK, OFF)
|
||||
button_inactive_color = (YELLOW, BLACK, OFF)
|
||||
button_label_active_color = (YELLOW,BLACK,ON)
|
||||
button_label_inactive_color = (YELLOW,BLACK,ON)
|
||||
|
||||
# Menu box
|
||||
menubox_color = (BLACK, BLACK, ON)
|
||||
menubox_border_color = (YELLOW, BLACK, OFF)
|
||||
menubox_border2_color = (YELLOW, BLACK, OFF)
|
||||
|
||||
# Menu window
|
||||
item_color = (YELLOW, BLACK, OFF)
|
||||
item_selected_color = (BLACK, YELLOW, OFF)
|
||||
tag_key_color = (YELLOW, BLACK, OFF)
|
||||
tag_key_selected_color = (BLACK, YELLOW, OFF)
|
@ -1,5 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MIT License
|
||||
|
||||
# Coauthored by Lincoln Stein, Eugene Brodsky and Joshua Kimsey
|
||||
# Copyright 2023, The InvokeAI Development Team
|
||||
|
||||
####
|
||||
# This launch script assumes that:
|
||||
# 1. it is located in the runtime directory,
|
||||
@ -11,85 +16,168 @@
|
||||
|
||||
set -eu
|
||||
|
||||
# ensure we're in the correct folder in case user's CWD is somewhere else
|
||||
# Ensure we're in the correct folder in case user's CWD is somewhere else
|
||||
scriptdir=$(dirname "$0")
|
||||
cd "$scriptdir"
|
||||
|
||||
. .venv/bin/activate
|
||||
|
||||
export INVOKEAI_ROOT="$scriptdir"
|
||||
PARAMS=$@
|
||||
|
||||
# set required env var for torch on mac MPS
|
||||
# Check to see if dialog is installed (it seems to be fairly standard, but good to check regardless) and if the user has passed the --no-tui argument to disable the dialog TUI
|
||||
tui=true
|
||||
if command -v dialog &>/dev/null; then
|
||||
# This must use $@ to properly loop through the arguments passed by the user
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" == "--no-tui" ]; then
|
||||
tui=false
|
||||
# Remove the --no-tui argument to avoid errors later on when passing arguments to InvokeAI
|
||||
PARAMS=$(echo "$PARAMS" | sed 's/--no-tui//')
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
tui=false
|
||||
fi
|
||||
|
||||
# Set required env var for torch on mac MPS
|
||||
if [ "$(uname -s)" == "Darwin" ]; then
|
||||
export PYTORCH_ENABLE_MPS_FALLBACK=1
|
||||
fi
|
||||
|
||||
while true
|
||||
do
|
||||
if [ "$0" != "bash" ]; then
|
||||
echo "Do you want to generate images using the"
|
||||
echo "1. command-line interface"
|
||||
echo "2. browser-based UI"
|
||||
echo "3. run textual inversion training"
|
||||
echo "4. merge models (diffusers type only)"
|
||||
echo "5. download and install models"
|
||||
echo "6. change InvokeAI startup options"
|
||||
echo "7. re-run the configure script to fix a broken install"
|
||||
echo "8. open the developer console"
|
||||
echo "9. update InvokeAI"
|
||||
echo "10. command-line help"
|
||||
echo "Q - Quit"
|
||||
echo ""
|
||||
read -p "Please enter 1-10, Q: [2] " yn
|
||||
choice=${yn:='2'}
|
||||
case $choice in
|
||||
1)
|
||||
echo "Starting the InvokeAI command-line..."
|
||||
invokeai $@
|
||||
;;
|
||||
2)
|
||||
echo "Starting the InvokeAI browser-based UI..."
|
||||
invokeai --web $@
|
||||
;;
|
||||
3)
|
||||
echo "Starting Textual Inversion:"
|
||||
invokeai-ti --gui $@
|
||||
;;
|
||||
4)
|
||||
echo "Merging Models:"
|
||||
invokeai-merge --gui $@
|
||||
;;
|
||||
5)
|
||||
invokeai-model-install --root ${INVOKEAI_ROOT}
|
||||
;;
|
||||
6)
|
||||
invokeai-configure --root ${INVOKEAI_ROOT} --skip-sd-weights --skip-support-models
|
||||
;;
|
||||
7)
|
||||
invokeai-configure --root ${INVOKEAI_ROOT} --yes --default_only
|
||||
;;
|
||||
8)
|
||||
echo "Developer Console:"
|
||||
file_name=$(basename "${BASH_SOURCE[0]}")
|
||||
bash --init-file "$file_name"
|
||||
;;
|
||||
9)
|
||||
echo "Update:"
|
||||
invokeai-update
|
||||
;;
|
||||
10)
|
||||
invokeai --help
|
||||
;;
|
||||
[qQ])
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Invalid selection"
|
||||
exit;;
|
||||
# Primary function for the case statement to determine user input
|
||||
do_choice() {
|
||||
case $1 in
|
||||
1)
|
||||
clear
|
||||
printf "Generate images with a browser-based interface\n"
|
||||
invokeai --web $PARAMS
|
||||
;;
|
||||
2)
|
||||
clear
|
||||
printf "Generate images using a command-line interface\n"
|
||||
invokeai $PARAMS
|
||||
;;
|
||||
3)
|
||||
clear
|
||||
printf "Textual inversion training\n"
|
||||
invokeai-ti --gui $PARAMS
|
||||
;;
|
||||
4)
|
||||
clear
|
||||
printf "Merge models (diffusers type only)\n"
|
||||
invokeai-merge --gui $PARAMS
|
||||
;;
|
||||
5)
|
||||
clear
|
||||
printf "Download and install models\n"
|
||||
invokeai-model-install --root ${INVOKEAI_ROOT}
|
||||
;;
|
||||
6)
|
||||
clear
|
||||
printf "Change InvokeAI startup options\n"
|
||||
invokeai-configure --root ${INVOKEAI_ROOT} --skip-sd-weights --skip-support-models
|
||||
;;
|
||||
7)
|
||||
clear
|
||||
printf "Re-run the configure script to fix a broken install\n"
|
||||
invokeai-configure --root ${INVOKEAI_ROOT} --yes --default_only
|
||||
;;
|
||||
8)
|
||||
clear
|
||||
printf "Open the developer console\n"
|
||||
file_name=$(basename "${BASH_SOURCE[0]}")
|
||||
bash --init-file "$file_name"
|
||||
;;
|
||||
9)
|
||||
clear
|
||||
printf "Update InvokeAI\n"
|
||||
invokeai-update
|
||||
;;
|
||||
10)
|
||||
clear
|
||||
printf "Command-line help\n"
|
||||
invokeai --help
|
||||
;;
|
||||
"HELP 1")
|
||||
clear
|
||||
printf "Command-line help\n"
|
||||
invokeai --help
|
||||
;;
|
||||
*)
|
||||
clear
|
||||
printf "Exiting...\n"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
clear
|
||||
}
|
||||
|
||||
# Dialog-based TUI for launcing Invoke functions
|
||||
do_dialog() {
|
||||
options=(
|
||||
1 "Generate images with a browser-based interface"
|
||||
2 "Generate images using a command-line interface"
|
||||
3 "Textual inversion training"
|
||||
4 "Merge models (diffusers type only)"
|
||||
5 "Download and install models"
|
||||
6 "Change InvokeAI startup options"
|
||||
7 "Re-run the configure script to fix a broken install"
|
||||
8 "Open the developer console"
|
||||
9 "Update InvokeAI")
|
||||
|
||||
choice=$(dialog --clear \
|
||||
--backtitle "\Zb\Zu\Z3InvokeAI" \
|
||||
--colors \
|
||||
--title "What would you like to run?" \
|
||||
--ok-label "Run" \
|
||||
--cancel-label "Exit" \
|
||||
--help-button \
|
||||
--help-label "CLI Help" \
|
||||
--menu "Select an option:" \
|
||||
0 0 0 \
|
||||
"${options[@]}" \
|
||||
2>&1 >/dev/tty) || clear
|
||||
do_choice "$choice"
|
||||
clear
|
||||
}
|
||||
|
||||
# Command-line interface for launching Invoke functions
|
||||
do_line_input() {
|
||||
clear
|
||||
printf " ** For a more attractive experience, please install the 'dialog' utility using your package manager. **\n\n"
|
||||
printf "Do you want to generate images using the\n"
|
||||
printf "1: Browser-based UI\n"
|
||||
printf "2: Command-line interface\n"
|
||||
printf "3: Run textual inversion training\n"
|
||||
printf "4: Merge models (diffusers type only)\n"
|
||||
printf "5: Download and install models\n"
|
||||
printf "6: Change InvokeAI startup options\n"
|
||||
printf "7: Re-run the configure script to fix a broken install\n"
|
||||
printf "8: Open the developer console\n"
|
||||
printf "9: Update InvokeAI\n"
|
||||
printf "10: Command-line help\n"
|
||||
printf "Q: Quit\n\n"
|
||||
read -p "Please enter 1-10, Q: [1] " yn
|
||||
choice=${yn:='1'}
|
||||
do_choice $choice
|
||||
clear
|
||||
}
|
||||
|
||||
# Main IF statement for launching Invoke with either the TUI or CLI, and for checking if the user is in the developer console
|
||||
if [ "$0" != "bash" ]; then
|
||||
while true; do
|
||||
if $tui; then
|
||||
# .dialogrc must be located in the same directory as the invoke.sh script
|
||||
export DIALOGRC="./.dialogrc"
|
||||
do_dialog
|
||||
else
|
||||
do_line_input
|
||||
fi
|
||||
done
|
||||
else # in developer console
|
||||
python --version
|
||||
echo "Press ^D to exit"
|
||||
printf "Press ^D to exit\n"
|
||||
export PS1="(InvokeAI) \u@\h \w> "
|
||||
fi
|
||||
done
|
||||
|
@ -13,14 +13,19 @@ sd-inpainting-1.5:
|
||||
vae:
|
||||
repo_id: stabilityai/sd-vae-ft-mse
|
||||
recommended: True
|
||||
stable-diffusion-2.1:
|
||||
stable-diffusion-2.1-768:
|
||||
description: Stable Diffusion version 2.1 diffusers model, trained on 768 pixel images (5.21 GB)
|
||||
repo_id: stabilityai/stable-diffusion-2-1
|
||||
format: diffusers
|
||||
recommended: True
|
||||
stable-diffusion-2.1-base:
|
||||
description: Stable Diffusion version 2.1 diffusers model, trained on 512 pixel images (5.21 GB)
|
||||
repo_id: stabilityai/stable-diffusion-2-1-base
|
||||
format: diffusers
|
||||
recommended: False
|
||||
sd-inpainting-2.0:
|
||||
description: Stable Diffusion version 2.0 inpainting model (5.21 GB)
|
||||
repo_id: stabilityai/stable-diffusion-2-1
|
||||
repo_id: stabilityai/stable-diffusion-2-inpainting
|
||||
format: diffusers
|
||||
recommended: False
|
||||
analog-diffusion-1.0:
|
||||
|
67
invokeai/configs/stable-diffusion/v2-inference.yaml
Normal file
67
invokeai/configs/stable-diffusion/v2-inference.yaml
Normal file
@ -0,0 +1,67 @@
|
||||
model:
|
||||
base_learning_rate: 1.0e-4
|
||||
target: ldm.models.diffusion.ddpm.LatentDiffusion
|
||||
params:
|
||||
linear_start: 0.00085
|
||||
linear_end: 0.0120
|
||||
num_timesteps_cond: 1
|
||||
log_every_t: 200
|
||||
timesteps: 1000
|
||||
first_stage_key: "jpg"
|
||||
cond_stage_key: "txt"
|
||||
image_size: 64
|
||||
channels: 4
|
||||
cond_stage_trainable: false
|
||||
conditioning_key: crossattn
|
||||
monitor: val/loss_simple_ema
|
||||
scale_factor: 0.18215
|
||||
use_ema: False # we set this to false because this is an inference only config
|
||||
|
||||
unet_config:
|
||||
target: ldm.modules.diffusionmodules.openaimodel.UNetModel
|
||||
params:
|
||||
use_checkpoint: True
|
||||
use_fp16: True
|
||||
image_size: 32 # unused
|
||||
in_channels: 4
|
||||
out_channels: 4
|
||||
model_channels: 320
|
||||
attention_resolutions: [ 4, 2, 1 ]
|
||||
num_res_blocks: 2
|
||||
channel_mult: [ 1, 2, 4, 4 ]
|
||||
num_head_channels: 64 # need to fix for flash-attn
|
||||
use_spatial_transformer: True
|
||||
use_linear_in_transformer: True
|
||||
transformer_depth: 1
|
||||
context_dim: 1024
|
||||
legacy: False
|
||||
|
||||
first_stage_config:
|
||||
target: ldm.models.autoencoder.AutoencoderKL
|
||||
params:
|
||||
embed_dim: 4
|
||||
monitor: val/rec_loss
|
||||
ddconfig:
|
||||
#attn_type: "vanilla-xformers"
|
||||
double_z: true
|
||||
z_channels: 4
|
||||
resolution: 256
|
||||
in_channels: 3
|
||||
out_ch: 3
|
||||
ch: 128
|
||||
ch_mult:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
- 4
|
||||
num_res_blocks: 2
|
||||
attn_resolutions: []
|
||||
dropout: 0.0
|
||||
lossconfig:
|
||||
target: torch.nn.Identity
|
||||
|
||||
cond_stage_config:
|
||||
target: ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder
|
||||
params:
|
||||
freeze: True
|
||||
layer: "penultimate"
|
@ -1,6 +1,7 @@
|
||||
module.exports = {
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 2,
|
||||
endOfLine: 'auto',
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
overrides: [
|
||||
|
File diff suppressed because one or more lines are too long
2
invokeai/frontend/dist/index.html
vendored
2
invokeai/frontend/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
|
||||
<script type="module" crossorigin src="./assets/index-0e39fbc4.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-c09cf9ca.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index-14cb2922.css">
|
||||
</head>
|
||||
|
||||
|
10
invokeai/frontend/dist/locales/en.json
vendored
10
invokeai/frontend/dist/locales/en.json
vendored
@ -63,7 +63,8 @@
|
||||
"statusConvertingModel": "Converting Model",
|
||||
"statusModelConverted": "Model Converted",
|
||||
"statusMergingModels": "Merging Models",
|
||||
"statusMergedModels": "Models Merged"
|
||||
"statusMergedModels": "Models Merged",
|
||||
"pinOptionsPanel": "Pin Options Panel"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generations",
|
||||
@ -364,7 +365,8 @@
|
||||
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||
"convertToDiffusersSaveLocation": "Save Location",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"v2_base": "v2 (512px)",
|
||||
"v2_768": "v2 (768px)",
|
||||
"inpainting": "v1 Inpainting",
|
||||
"customConfig": "Custom Config",
|
||||
"pathToCustomConfig": "Path To Custom Config",
|
||||
@ -393,7 +395,9 @@
|
||||
"modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above.",
|
||||
"inverseSigmoid": "Inverse Sigmoid",
|
||||
"sigmoid": "Sigmoid",
|
||||
"weightedSum": "Weighted Sum"
|
||||
"weightedSum": "Weighted Sum",
|
||||
"none": "none",
|
||||
"addDifference": "Add Difference"
|
||||
},
|
||||
"parameters": {
|
||||
"general": "General",
|
||||
|
115
invokeai/frontend/dist/locales/es.json
vendored
115
invokeai/frontend/dist/locales/es.json
vendored
@ -15,7 +15,7 @@
|
||||
"langSpanish": "Español",
|
||||
"nodesDesc": "Un sistema de generación de imágenes basado en nodos, actualmente se encuentra en desarrollo. Mantente pendiente a nuestras actualizaciones acerca de esta fabulosa funcionalidad.",
|
||||
"postProcessing": "Post-procesamiento",
|
||||
"postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador",
|
||||
"postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador.",
|
||||
"postProcessDesc2": "Una interfaz de usuario dedicada se lanzará pronto para facilitar flujos de trabajo de postprocesamiento más avanzado.",
|
||||
"postProcessDesc3": "La Interfaz de Línea de Comandos de Invoke AI ofrece muchas otras características, incluyendo -Embiggen-.",
|
||||
"training": "Entrenamiento",
|
||||
@ -44,7 +44,26 @@
|
||||
"statusUpscaling": "Aumentando Tamaño",
|
||||
"statusUpscalingESRGAN": "Restaurando Rostros(ESRGAN)",
|
||||
"statusLoadingModel": "Cargando Modelo",
|
||||
"statusModelChanged": "Modelo cambiado"
|
||||
"statusModelChanged": "Modelo cambiado",
|
||||
"statusMergedModels": "Modelos combinados",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"langEnglish": "Inglés",
|
||||
"langDutch": "Holandés",
|
||||
"langFrench": "Francés",
|
||||
"langGerman": "Alemán",
|
||||
"langItalian": "Italiano",
|
||||
"langArabic": "Árabe",
|
||||
"langJapanese": "Japones",
|
||||
"langPolish": "Polaco",
|
||||
"langBrPortuguese": "Portugués brasileño",
|
||||
"langRussian": "Ruso",
|
||||
"langSimplifiedChinese": "Chino simplificado",
|
||||
"langUkranian": "Ucraniano",
|
||||
"back": "Atrás",
|
||||
"statusConvertingModel": "Convertir el modelo",
|
||||
"statusModelConverted": "Modelo adaptado",
|
||||
"statusMergingModels": "Fusionar modelos"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generaciones",
|
||||
@ -284,16 +303,16 @@
|
||||
"nameValidationMsg": "Introduce un nombre para tu modelo",
|
||||
"description": "Descripción",
|
||||
"descriptionValidationMsg": "Introduce una descripción para tu modelo",
|
||||
"config": "Config",
|
||||
"configValidationMsg": "Ruta del archivo de configuración del modelo",
|
||||
"config": "Configurar",
|
||||
"configValidationMsg": "Ruta del archivo de configuración del modelo.",
|
||||
"modelLocation": "Ubicación del Modelo",
|
||||
"modelLocationValidationMsg": "Ruta del archivo de modelo",
|
||||
"modelLocationValidationMsg": "Ruta del archivo de modelo.",
|
||||
"vaeLocation": "Ubicación VAE",
|
||||
"vaeLocationValidationMsg": "Ruta del archivo VAE",
|
||||
"vaeLocationValidationMsg": "Ruta del archivo VAE.",
|
||||
"width": "Ancho",
|
||||
"widthValidationMsg": "Ancho predeterminado de tu modelo",
|
||||
"widthValidationMsg": "Ancho predeterminado de tu modelo.",
|
||||
"height": "Alto",
|
||||
"heightValidationMsg": "Alto predeterminado de tu modelo",
|
||||
"heightValidationMsg": "Alto predeterminado de tu modelo.",
|
||||
"addModel": "Añadir Modelo",
|
||||
"updateModel": "Actualizar Modelo",
|
||||
"availableModels": "Modelos disponibles",
|
||||
@ -320,7 +339,61 @@
|
||||
"deleteModel": "Eliminar Modelo",
|
||||
"deleteConfig": "Eliminar Configuración",
|
||||
"deleteMsg1": "¿Estás seguro de querer eliminar esta entrada de modelo de InvokeAI?",
|
||||
"deleteMsg2": "El checkpoint del modelo no se eliminará de tu disco. Puedes volver a añadirlo si lo deseas."
|
||||
"deleteMsg2": "El checkpoint del modelo no se eliminará de tu disco. Puedes volver a añadirlo si lo deseas.",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"addDiffuserModel": "Añadir difusores",
|
||||
"inpainting": "v1 Repintado",
|
||||
"repoIDValidationMsg": "Repositorio en línea de tu modelo",
|
||||
"checkpointModels": "Puntos de control",
|
||||
"convertToDiffusersHelpText4": "Este proceso se realiza una sola vez. Puede tardar entre 30 y 60 segundos dependiendo de las especificaciones de tu ordenador.",
|
||||
"diffusersModels": "Difusores",
|
||||
"addCheckpointModel": "Agregar modelo de punto de control/Modelo Safetensor",
|
||||
"vaeRepoID": "Identificador del repositorio de VAE",
|
||||
"vaeRepoIDValidationMsg": "Repositorio en línea de tú VAE",
|
||||
"formMessageDiffusersModelLocation": "Difusores Modelo Ubicación",
|
||||
"formMessageDiffusersModelLocationDesc": "Por favor, introduzca al menos uno.",
|
||||
"formMessageDiffusersVAELocation": "Ubicación VAE",
|
||||
"formMessageDiffusersVAELocationDesc": "Si no se proporciona, InvokeAI buscará el archivo VAE dentro de la ubicación del modelo indicada anteriormente.",
|
||||
"convert": "Convertir",
|
||||
"convertToDiffusers": "Convertir en difusores",
|
||||
"convertToDiffusersHelpText1": "Este modelo se convertirá al formato 🧨 Difusores.",
|
||||
"convertToDiffusersHelpText2": "Este proceso sustituirá su entrada del Gestor de Modelos por la versión de Difusores del mismo modelo.",
|
||||
"convertToDiffusersHelpText3": "Su archivo de puntos de control en el disco NO será borrado ni modificado de ninguna manera. Puede volver a añadir su punto de control al Gestor de Modelos si lo desea.",
|
||||
"convertToDiffusersHelpText5": "Asegúrese de que dispone de suficiente espacio en disco. Los modelos suelen variar entre 4 GB y 7 GB de tamaño.",
|
||||
"convertToDiffusersHelpText6": "¿Desea transformar este modelo?",
|
||||
"convertToDiffusersSaveLocation": "Guardar ubicación",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"statusConverting": "Adaptar",
|
||||
"modelConverted": "Modelo adaptado",
|
||||
"sameFolder": "La misma carpeta",
|
||||
"invokeRoot": "Carpeta InvokeAI",
|
||||
"custom": "Personalizado",
|
||||
"customSaveLocation": "Ubicación personalizada para guardar",
|
||||
"merge": "Fusión",
|
||||
"modelsMerged": "Modelos fusionados",
|
||||
"mergeModels": "Combinar modelos",
|
||||
"modelOne": "Modelo 1",
|
||||
"modelTwo": "Modelo 2",
|
||||
"modelThree": "Modelo 3",
|
||||
"mergedModelName": "Nombre del modelo combinado",
|
||||
"alpha": "Alfa",
|
||||
"interpolationType": "Tipo de interpolación",
|
||||
"mergedModelSaveLocation": "Guardar ubicación",
|
||||
"mergedModelCustomSaveLocation": "Ruta personalizada",
|
||||
"invokeAIFolder": "Invocar carpeta de la inteligencia artificial",
|
||||
"modelMergeHeaderHelp2": "Sólo se pueden fusionar difusores. Si desea fusionar un modelo de punto de control, conviértalo primero en difusores.",
|
||||
"modelMergeAlphaHelp": "Alfa controla la fuerza de mezcla de los modelos. Los valores alfa más bajos reducen la influencia del segundo modelo.",
|
||||
"modelMergeInterpAddDifferenceHelp": "En este modo, el Modelo 3 se sustrae primero del Modelo 2. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente.",
|
||||
"ignoreMismatch": "Ignorar discrepancias entre modelos seleccionados",
|
||||
"modelMergeHeaderHelp1": "Puede combinar hasta tres modelos diferentes para crear una mezcla que se adapte a sus necesidades.",
|
||||
"inverseSigmoid": "Sigmoideo inverso",
|
||||
"weightedSum": "Modelo de suma ponderada",
|
||||
"sigmoid": "Función sigmoide",
|
||||
"allModels": "Todos los modelos",
|
||||
"repo_id": "Identificador del repositorio",
|
||||
"pathToCustomConfig": "Ruta a la configuración personalizada",
|
||||
"customConfig": "Configuración personalizada"
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Imágenes",
|
||||
@ -380,7 +453,22 @@
|
||||
"info": "Información",
|
||||
"deleteImage": "Eliminar Imagen",
|
||||
"initialImage": "Imagen Inicial",
|
||||
"showOptionsPanel": "Mostrar panel de opciones"
|
||||
"showOptionsPanel": "Mostrar panel de opciones",
|
||||
"symmetry": "Simetría",
|
||||
"vSymmetryStep": "Paso de simetría V",
|
||||
"hSymmetryStep": "Paso de simetría H",
|
||||
"cancel": {
|
||||
"immediate": "Cancelar inmediatamente",
|
||||
"schedule": "Cancelar tras la iteración actual",
|
||||
"isScheduled": "Cancelando",
|
||||
"setType": "Tipo de cancelación"
|
||||
},
|
||||
"copyImage": "Copiar la imagen",
|
||||
"general": "General",
|
||||
"negativePrompts": "Preguntas negativas",
|
||||
"imageToImage": "Imagen a imagen",
|
||||
"denoisingStrength": "Intensidad de la eliminación del ruido",
|
||||
"hiresStrength": "Alta resistencia"
|
||||
},
|
||||
"settings": {
|
||||
"models": "Modelos",
|
||||
@ -393,7 +481,8 @@
|
||||
"resetWebUI": "Restablecer interfaz web",
|
||||
"resetWebUIDesc1": "Al restablecer la interfaz web, solo se restablece la caché local del navegador de sus imágenes y la configuración guardada. No se elimina ninguna imagen de su disco duro.",
|
||||
"resetWebUIDesc2": "Si las imágenes no se muestran en la galería o algo más no funciona, intente restablecer antes de reportar un incidente en GitHub.",
|
||||
"resetComplete": "La interfaz web se ha restablecido. Actualice la página para recargarla."
|
||||
"resetComplete": "La interfaz web se ha restablecido. Actualice la página para recargarla.",
|
||||
"useSlidersForAll": "Utilice controles deslizantes para todas las opciones"
|
||||
},
|
||||
"toast": {
|
||||
"tempFoldersEmptied": "Directorio temporal vaciado",
|
||||
@ -431,12 +520,12 @@
|
||||
"feature": {
|
||||
"prompt": "Este campo tomará todo el texto de entrada, incluidos tanto los términos de contenido como los estilísticos. Si bien se pueden incluir pesos en la solicitud, los comandos/parámetros estándar de línea de comandos no funcionarán.",
|
||||
"gallery": "Conforme se generan nuevas invocaciones, los archivos del directorio de salida se mostrarán aquí. Las generaciones tienen opciones adicionales para configurar nuevas generaciones.",
|
||||
"other": "Estas opciones habilitarán modos de procesamiento alternativos para Invoke. El modo sin costuras funciona para generar patrones repetitivos en la salida. La optimización de alta resolución realiza un ciclo de generación de dos pasos y debe usarse en resoluciones más altas cuando desee una imagen/composición más coherente.",
|
||||
"other": "Estas opciones habilitarán modos de procesamiento alternativos para Invoke. 'Seamless mosaico' creará patrones repetitivos en la salida. 'Alta resolución' es la generación en dos pasos con img2img: use esta configuración cuando desee una imagen más grande y más coherente sin artefactos. tomar más tiempo de lo habitual txt2img.",
|
||||
"seed": "Los valores de semilla proporcionan un conjunto inicial de ruido que guían el proceso de eliminación de ruido y se pueden aleatorizar o rellenar con una semilla de una invocación anterior. La función Umbral se puede usar para mitigar resultados indeseables a valores CFG más altos (intente entre 0-10), y Perlin se puede usar para agregar ruido Perlin al proceso de eliminación de ruido. Ambos sirven para agregar variación a sus salidas.",
|
||||
"variations": "Pruebe una variación con una cantidad entre 0 y 1 para cambiar la imagen de salida para la semilla establecida. Se encuentran variaciones interesantes en la semilla entre 0.1 y 0.3.",
|
||||
"upscale": "Usando ESRGAN, puede aumentar la resolución de salida sin requerir un ancho/alto más alto en la generación inicial.",
|
||||
"faceCorrection": "Usando GFPGAN o Codeformer, la corrección de rostros intentará identificar rostros en las salidas y corregir cualquier defecto/anormalidad. Los valores de fuerza más altos aplicarán una presión correctiva más fuerte en las salidas, lo que resultará en rostros más atractivos. Con Codeformer, una mayor fidelidad intentará preservar la imagen original, a expensas de la fuerza de corrección de rostros.",
|
||||
"imageToImage": "Imagen a Imagen permite cargar una imagen inicial, que InvokeAI usará para guiar el proceso de generación, junto con una solicitud. Un valor más bajo para esta configuración se parecerá más a la imagen original. Se aceptan valores entre 0-1, y se recomienda un rango de .25-.75.",
|
||||
"imageToImage": "Imagen a Imagen permite cargar una imagen inicial, que InvokeAI usará para guiar el proceso de generación, junto con una solicitud. Un valor más bajo para esta configuración se parecerá más a la imagen original. Se aceptan valores entre 0-1, y se recomienda un rango de .25-.75",
|
||||
"boundingBox": "La caja delimitadora es análoga a las configuraciones de Ancho y Alto para Texto a Imagen o Imagen a Imagen. Solo se procesará el área en la caja.",
|
||||
"seamCorrection": "Controla el manejo de parches visibles que pueden ocurrir cuando se pega una imagen generada de nuevo en el lienzo.",
|
||||
"infillAndScaling": "Administra los métodos de relleno (utilizados en áreas enmascaradas o borradas del lienzo) y la escala (útil para tamaños de caja delimitadora pequeños)."
|
||||
|
76
invokeai/frontend/dist/locales/pt_BR.json
vendored
76
invokeai/frontend/dist/locales/pt_BR.json
vendored
@ -44,7 +44,26 @@
|
||||
"statusUpscaling": "Redimensinando",
|
||||
"statusUpscalingESRGAN": "Redimensinando (ESRGAN)",
|
||||
"statusLoadingModel": "Carregando Modelo",
|
||||
"statusModelChanged": "Modelo Alterado"
|
||||
"statusModelChanged": "Modelo Alterado",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"langArabic": "Árabe",
|
||||
"langEnglish": "Inglês",
|
||||
"langDutch": "Holandês",
|
||||
"langFrench": "Francês",
|
||||
"langGerman": "Alemão",
|
||||
"langItalian": "Italiano",
|
||||
"langJapanese": "Japonês",
|
||||
"langPolish": "Polonês",
|
||||
"langSimplifiedChinese": "Chinês",
|
||||
"langUkranian": "Ucraniano",
|
||||
"back": "Voltar",
|
||||
"statusConvertingModel": "Convertendo Modelo",
|
||||
"statusModelConverted": "Modelo Convertido",
|
||||
"statusMergingModels": "Mesclando Modelos",
|
||||
"statusMergedModels": "Modelos Mesclados",
|
||||
"langRussian": "Russo",
|
||||
"langSpanish": "Espanhol"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Gerações",
|
||||
@ -237,7 +256,7 @@
|
||||
"desc": "Salva a tela atual na galeria"
|
||||
},
|
||||
"copyToClipboard": {
|
||||
"title": "Copiar Para a Área de Transferência ",
|
||||
"title": "Copiar para a Área de Transferência",
|
||||
"desc": "Copia a tela atual para a área de transferência"
|
||||
},
|
||||
"downloadImage": {
|
||||
@ -284,7 +303,7 @@
|
||||
"nameValidationMsg": "Insira um nome para o seu modelo",
|
||||
"description": "Descrição",
|
||||
"descriptionValidationMsg": "Adicione uma descrição para o seu modelo",
|
||||
"config": "Config",
|
||||
"config": "Configuração",
|
||||
"configValidationMsg": "Caminho para o arquivo de configuração do seu modelo.",
|
||||
"modelLocation": "Localização do modelo",
|
||||
"modelLocationValidationMsg": "Caminho para onde seu modelo está localizado.",
|
||||
@ -317,7 +336,52 @@
|
||||
"deleteModel": "Excluir modelo",
|
||||
"deleteConfig": "Excluir Config",
|
||||
"deleteMsg1": "Tem certeza de que deseja excluir esta entrada do modelo de InvokeAI?",
|
||||
"deleteMsg2": "Isso não vai excluir o arquivo de modelo checkpoint do seu disco. Você pode lê-los, se desejar."
|
||||
"deleteMsg2": "Isso não vai excluir o arquivo de modelo checkpoint do seu disco. Você pode lê-los, se desejar.",
|
||||
"checkpointModels": "Checkpoints",
|
||||
"diffusersModels": "Diffusers",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"addCheckpointModel": "Adicionar Modelo de Checkpoint/Safetensor",
|
||||
"addDiffuserModel": "Adicionar Diffusers",
|
||||
"repo_id": "Repo ID",
|
||||
"vaeRepoID": "VAE Repo ID",
|
||||
"vaeRepoIDValidationMsg": "Repositório Online do seu VAE",
|
||||
"scanAgain": "Digitalize Novamente",
|
||||
"selectAndAdd": "Selecione e Adicione Modelos Listados Abaixo",
|
||||
"noModelsFound": "Nenhum Modelo Encontrado",
|
||||
"formMessageDiffusersModelLocation": "Localização dos Modelos Diffusers",
|
||||
"formMessageDiffusersModelLocationDesc": "Por favor entre com ao menos um.",
|
||||
"formMessageDiffusersVAELocation": "Localização do VAE",
|
||||
"formMessageDiffusersVAELocationDesc": "Se não provido, InvokeAI irá procurar pelo arquivo VAE dentro do local do modelo.",
|
||||
"convertToDiffusers": "Converter para Diffusers",
|
||||
"convertToDiffusersHelpText1": "Este modelo será convertido para o formato 🧨 Diffusers.",
|
||||
"convertToDiffusersHelpText5": "Por favor, certifique-se de que você tenha espaço suficiente em disco. Os modelos geralmente variam entre 4GB e 7GB de tamanho.",
|
||||
"convertToDiffusersHelpText6": "Você deseja converter este modelo?",
|
||||
"convertToDiffusersSaveLocation": "Local para Salvar",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"inpainting": "v1 Inpainting",
|
||||
"customConfig": "Configuração personalizada",
|
||||
"pathToCustomConfig": "Caminho para configuração personalizada",
|
||||
"convertToDiffusersHelpText3": "Seu arquivo de ponto de verificação no disco NÃO será excluído ou modificado de forma alguma. Você pode adicionar seu ponto de verificação ao Gerenciador de modelos novamente, se desejar.",
|
||||
"convertToDiffusersHelpText4": "Este é um processo único. Pode levar cerca de 30 a 60s, dependendo das especificações do seu computador.",
|
||||
"merge": "Mesclar",
|
||||
"modelsMerged": "Modelos mesclados",
|
||||
"mergeModels": "Mesclar modelos",
|
||||
"modelOne": "Modelo 1",
|
||||
"modelTwo": "Modelo 2",
|
||||
"modelThree": "Modelo 3",
|
||||
"statusConverting": "Convertendo",
|
||||
"modelConverted": "Modelo Convertido",
|
||||
"sameFolder": "Mesma pasta",
|
||||
"invokeRoot": "Pasta do InvokeAI",
|
||||
"custom": "Personalizado",
|
||||
"customSaveLocation": "Local de salvamento personalizado",
|
||||
"mergedModelName": "Nome do modelo mesclado",
|
||||
"alpha": "Alpha",
|
||||
"allModels": "Todos os Modelos",
|
||||
"repoIDValidationMsg": "Repositório Online do seu Modelo",
|
||||
"convert": "Converter",
|
||||
"convertToDiffusersHelpText2": "Este processo irá substituir sua entrada de Gerenciador de Modelos por uma versão Diffusers do mesmo modelo."
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Imagems",
|
||||
@ -442,14 +506,14 @@
|
||||
"move": "Mover",
|
||||
"resetView": "Resetar Visualização",
|
||||
"mergeVisible": "Fundir Visível",
|
||||
"saveToGallery": "Save To Gallery",
|
||||
"saveToGallery": "Salvar na Galeria",
|
||||
"copyToClipboard": "Copiar para a Área de Transferência",
|
||||
"downloadAsImage": "Baixar Como Imagem",
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"clearCanvas": "Limpar Tela",
|
||||
"canvasSettings": "Configurações de Tela",
|
||||
"showIntermediates": "Show Intermediates",
|
||||
"showIntermediates": "Mostrar Intermediários",
|
||||
"showGrid": "Mostrar Grade",
|
||||
"snapToGrid": "Encaixar na Grade",
|
||||
"darkenOutsideSelection": "Escurecer Seleção Externa",
|
||||
|
1
invokeai/frontend/dist/locales/ro.json
vendored
Normal file
1
invokeai/frontend/dist/locales/ro.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -63,7 +63,8 @@
|
||||
"statusConvertingModel": "Converting Model",
|
||||
"statusModelConverted": "Model Converted",
|
||||
"statusMergingModels": "Merging Models",
|
||||
"statusMergedModels": "Models Merged"
|
||||
"statusMergedModels": "Models Merged",
|
||||
"pinOptionsPanel": "Pin Options Panel"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generations",
|
||||
@ -364,7 +365,8 @@
|
||||
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||
"convertToDiffusersSaveLocation": "Save Location",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"v2_base": "v2 (512px)",
|
||||
"v2_768": "v2 (768px)",
|
||||
"inpainting": "v1 Inpainting",
|
||||
"customConfig": "Custom Config",
|
||||
"pathToCustomConfig": "Path To Custom Config",
|
||||
@ -393,7 +395,9 @@
|
||||
"modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above.",
|
||||
"inverseSigmoid": "Inverse Sigmoid",
|
||||
"sigmoid": "Sigmoid",
|
||||
"weightedSum": "Weighted Sum"
|
||||
"weightedSum": "Weighted Sum",
|
||||
"none": "none",
|
||||
"addDifference": "Add Difference"
|
||||
},
|
||||
"parameters": {
|
||||
"general": "General",
|
||||
|
@ -15,7 +15,7 @@
|
||||
"langSpanish": "Español",
|
||||
"nodesDesc": "Un sistema de generación de imágenes basado en nodos, actualmente se encuentra en desarrollo. Mantente pendiente a nuestras actualizaciones acerca de esta fabulosa funcionalidad.",
|
||||
"postProcessing": "Post-procesamiento",
|
||||
"postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador",
|
||||
"postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador.",
|
||||
"postProcessDesc2": "Una interfaz de usuario dedicada se lanzará pronto para facilitar flujos de trabajo de postprocesamiento más avanzado.",
|
||||
"postProcessDesc3": "La Interfaz de Línea de Comandos de Invoke AI ofrece muchas otras características, incluyendo -Embiggen-.",
|
||||
"training": "Entrenamiento",
|
||||
@ -44,7 +44,26 @@
|
||||
"statusUpscaling": "Aumentando Tamaño",
|
||||
"statusUpscalingESRGAN": "Restaurando Rostros(ESRGAN)",
|
||||
"statusLoadingModel": "Cargando Modelo",
|
||||
"statusModelChanged": "Modelo cambiado"
|
||||
"statusModelChanged": "Modelo cambiado",
|
||||
"statusMergedModels": "Modelos combinados",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"langEnglish": "Inglés",
|
||||
"langDutch": "Holandés",
|
||||
"langFrench": "Francés",
|
||||
"langGerman": "Alemán",
|
||||
"langItalian": "Italiano",
|
||||
"langArabic": "Árabe",
|
||||
"langJapanese": "Japones",
|
||||
"langPolish": "Polaco",
|
||||
"langBrPortuguese": "Portugués brasileño",
|
||||
"langRussian": "Ruso",
|
||||
"langSimplifiedChinese": "Chino simplificado",
|
||||
"langUkranian": "Ucraniano",
|
||||
"back": "Atrás",
|
||||
"statusConvertingModel": "Convertir el modelo",
|
||||
"statusModelConverted": "Modelo adaptado",
|
||||
"statusMergingModels": "Fusionar modelos"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generaciones",
|
||||
@ -284,16 +303,16 @@
|
||||
"nameValidationMsg": "Introduce un nombre para tu modelo",
|
||||
"description": "Descripción",
|
||||
"descriptionValidationMsg": "Introduce una descripción para tu modelo",
|
||||
"config": "Config",
|
||||
"configValidationMsg": "Ruta del archivo de configuración del modelo",
|
||||
"config": "Configurar",
|
||||
"configValidationMsg": "Ruta del archivo de configuración del modelo.",
|
||||
"modelLocation": "Ubicación del Modelo",
|
||||
"modelLocationValidationMsg": "Ruta del archivo de modelo",
|
||||
"modelLocationValidationMsg": "Ruta del archivo de modelo.",
|
||||
"vaeLocation": "Ubicación VAE",
|
||||
"vaeLocationValidationMsg": "Ruta del archivo VAE",
|
||||
"vaeLocationValidationMsg": "Ruta del archivo VAE.",
|
||||
"width": "Ancho",
|
||||
"widthValidationMsg": "Ancho predeterminado de tu modelo",
|
||||
"widthValidationMsg": "Ancho predeterminado de tu modelo.",
|
||||
"height": "Alto",
|
||||
"heightValidationMsg": "Alto predeterminado de tu modelo",
|
||||
"heightValidationMsg": "Alto predeterminado de tu modelo.",
|
||||
"addModel": "Añadir Modelo",
|
||||
"updateModel": "Actualizar Modelo",
|
||||
"availableModels": "Modelos disponibles",
|
||||
@ -320,7 +339,61 @@
|
||||
"deleteModel": "Eliminar Modelo",
|
||||
"deleteConfig": "Eliminar Configuración",
|
||||
"deleteMsg1": "¿Estás seguro de querer eliminar esta entrada de modelo de InvokeAI?",
|
||||
"deleteMsg2": "El checkpoint del modelo no se eliminará de tu disco. Puedes volver a añadirlo si lo deseas."
|
||||
"deleteMsg2": "El checkpoint del modelo no se eliminará de tu disco. Puedes volver a añadirlo si lo deseas.",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"addDiffuserModel": "Añadir difusores",
|
||||
"inpainting": "v1 Repintado",
|
||||
"repoIDValidationMsg": "Repositorio en línea de tu modelo",
|
||||
"checkpointModels": "Puntos de control",
|
||||
"convertToDiffusersHelpText4": "Este proceso se realiza una sola vez. Puede tardar entre 30 y 60 segundos dependiendo de las especificaciones de tu ordenador.",
|
||||
"diffusersModels": "Difusores",
|
||||
"addCheckpointModel": "Agregar modelo de punto de control/Modelo Safetensor",
|
||||
"vaeRepoID": "Identificador del repositorio de VAE",
|
||||
"vaeRepoIDValidationMsg": "Repositorio en línea de tú VAE",
|
||||
"formMessageDiffusersModelLocation": "Difusores Modelo Ubicación",
|
||||
"formMessageDiffusersModelLocationDesc": "Por favor, introduzca al menos uno.",
|
||||
"formMessageDiffusersVAELocation": "Ubicación VAE",
|
||||
"formMessageDiffusersVAELocationDesc": "Si no se proporciona, InvokeAI buscará el archivo VAE dentro de la ubicación del modelo indicada anteriormente.",
|
||||
"convert": "Convertir",
|
||||
"convertToDiffusers": "Convertir en difusores",
|
||||
"convertToDiffusersHelpText1": "Este modelo se convertirá al formato 🧨 Difusores.",
|
||||
"convertToDiffusersHelpText2": "Este proceso sustituirá su entrada del Gestor de Modelos por la versión de Difusores del mismo modelo.",
|
||||
"convertToDiffusersHelpText3": "Su archivo de puntos de control en el disco NO será borrado ni modificado de ninguna manera. Puede volver a añadir su punto de control al Gestor de Modelos si lo desea.",
|
||||
"convertToDiffusersHelpText5": "Asegúrese de que dispone de suficiente espacio en disco. Los modelos suelen variar entre 4 GB y 7 GB de tamaño.",
|
||||
"convertToDiffusersHelpText6": "¿Desea transformar este modelo?",
|
||||
"convertToDiffusersSaveLocation": "Guardar ubicación",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"statusConverting": "Adaptar",
|
||||
"modelConverted": "Modelo adaptado",
|
||||
"sameFolder": "La misma carpeta",
|
||||
"invokeRoot": "Carpeta InvokeAI",
|
||||
"custom": "Personalizado",
|
||||
"customSaveLocation": "Ubicación personalizada para guardar",
|
||||
"merge": "Fusión",
|
||||
"modelsMerged": "Modelos fusionados",
|
||||
"mergeModels": "Combinar modelos",
|
||||
"modelOne": "Modelo 1",
|
||||
"modelTwo": "Modelo 2",
|
||||
"modelThree": "Modelo 3",
|
||||
"mergedModelName": "Nombre del modelo combinado",
|
||||
"alpha": "Alfa",
|
||||
"interpolationType": "Tipo de interpolación",
|
||||
"mergedModelSaveLocation": "Guardar ubicación",
|
||||
"mergedModelCustomSaveLocation": "Ruta personalizada",
|
||||
"invokeAIFolder": "Invocar carpeta de la inteligencia artificial",
|
||||
"modelMergeHeaderHelp2": "Sólo se pueden fusionar difusores. Si desea fusionar un modelo de punto de control, conviértalo primero en difusores.",
|
||||
"modelMergeAlphaHelp": "Alfa controla la fuerza de mezcla de los modelos. Los valores alfa más bajos reducen la influencia del segundo modelo.",
|
||||
"modelMergeInterpAddDifferenceHelp": "En este modo, el Modelo 3 se sustrae primero del Modelo 2. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente.",
|
||||
"ignoreMismatch": "Ignorar discrepancias entre modelos seleccionados",
|
||||
"modelMergeHeaderHelp1": "Puede combinar hasta tres modelos diferentes para crear una mezcla que se adapte a sus necesidades.",
|
||||
"inverseSigmoid": "Sigmoideo inverso",
|
||||
"weightedSum": "Modelo de suma ponderada",
|
||||
"sigmoid": "Función sigmoide",
|
||||
"allModels": "Todos los modelos",
|
||||
"repo_id": "Identificador del repositorio",
|
||||
"pathToCustomConfig": "Ruta a la configuración personalizada",
|
||||
"customConfig": "Configuración personalizada"
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Imágenes",
|
||||
@ -380,7 +453,22 @@
|
||||
"info": "Información",
|
||||
"deleteImage": "Eliminar Imagen",
|
||||
"initialImage": "Imagen Inicial",
|
||||
"showOptionsPanel": "Mostrar panel de opciones"
|
||||
"showOptionsPanel": "Mostrar panel de opciones",
|
||||
"symmetry": "Simetría",
|
||||
"vSymmetryStep": "Paso de simetría V",
|
||||
"hSymmetryStep": "Paso de simetría H",
|
||||
"cancel": {
|
||||
"immediate": "Cancelar inmediatamente",
|
||||
"schedule": "Cancelar tras la iteración actual",
|
||||
"isScheduled": "Cancelando",
|
||||
"setType": "Tipo de cancelación"
|
||||
},
|
||||
"copyImage": "Copiar la imagen",
|
||||
"general": "General",
|
||||
"negativePrompts": "Preguntas negativas",
|
||||
"imageToImage": "Imagen a imagen",
|
||||
"denoisingStrength": "Intensidad de la eliminación del ruido",
|
||||
"hiresStrength": "Alta resistencia"
|
||||
},
|
||||
"settings": {
|
||||
"models": "Modelos",
|
||||
@ -393,7 +481,8 @@
|
||||
"resetWebUI": "Restablecer interfaz web",
|
||||
"resetWebUIDesc1": "Al restablecer la interfaz web, solo se restablece la caché local del navegador de sus imágenes y la configuración guardada. No se elimina ninguna imagen de su disco duro.",
|
||||
"resetWebUIDesc2": "Si las imágenes no se muestran en la galería o algo más no funciona, intente restablecer antes de reportar un incidente en GitHub.",
|
||||
"resetComplete": "La interfaz web se ha restablecido. Actualice la página para recargarla."
|
||||
"resetComplete": "La interfaz web se ha restablecido. Actualice la página para recargarla.",
|
||||
"useSlidersForAll": "Utilice controles deslizantes para todas las opciones"
|
||||
},
|
||||
"toast": {
|
||||
"tempFoldersEmptied": "Directorio temporal vaciado",
|
||||
@ -431,12 +520,12 @@
|
||||
"feature": {
|
||||
"prompt": "Este campo tomará todo el texto de entrada, incluidos tanto los términos de contenido como los estilísticos. Si bien se pueden incluir pesos en la solicitud, los comandos/parámetros estándar de línea de comandos no funcionarán.",
|
||||
"gallery": "Conforme se generan nuevas invocaciones, los archivos del directorio de salida se mostrarán aquí. Las generaciones tienen opciones adicionales para configurar nuevas generaciones.",
|
||||
"other": "Estas opciones habilitarán modos de procesamiento alternativos para Invoke. El modo sin costuras funciona para generar patrones repetitivos en la salida. La optimización de alta resolución realiza un ciclo de generación de dos pasos y debe usarse en resoluciones más altas cuando desee una imagen/composición más coherente.",
|
||||
"other": "Estas opciones habilitarán modos de procesamiento alternativos para Invoke. 'Seamless mosaico' creará patrones repetitivos en la salida. 'Alta resolución' es la generación en dos pasos con img2img: use esta configuración cuando desee una imagen más grande y más coherente sin artefactos. tomar más tiempo de lo habitual txt2img.",
|
||||
"seed": "Los valores de semilla proporcionan un conjunto inicial de ruido que guían el proceso de eliminación de ruido y se pueden aleatorizar o rellenar con una semilla de una invocación anterior. La función Umbral se puede usar para mitigar resultados indeseables a valores CFG más altos (intente entre 0-10), y Perlin se puede usar para agregar ruido Perlin al proceso de eliminación de ruido. Ambos sirven para agregar variación a sus salidas.",
|
||||
"variations": "Pruebe una variación con una cantidad entre 0 y 1 para cambiar la imagen de salida para la semilla establecida. Se encuentran variaciones interesantes en la semilla entre 0.1 y 0.3.",
|
||||
"upscale": "Usando ESRGAN, puede aumentar la resolución de salida sin requerir un ancho/alto más alto en la generación inicial.",
|
||||
"faceCorrection": "Usando GFPGAN o Codeformer, la corrección de rostros intentará identificar rostros en las salidas y corregir cualquier defecto/anormalidad. Los valores de fuerza más altos aplicarán una presión correctiva más fuerte en las salidas, lo que resultará en rostros más atractivos. Con Codeformer, una mayor fidelidad intentará preservar la imagen original, a expensas de la fuerza de corrección de rostros.",
|
||||
"imageToImage": "Imagen a Imagen permite cargar una imagen inicial, que InvokeAI usará para guiar el proceso de generación, junto con una solicitud. Un valor más bajo para esta configuración se parecerá más a la imagen original. Se aceptan valores entre 0-1, y se recomienda un rango de .25-.75.",
|
||||
"imageToImage": "Imagen a Imagen permite cargar una imagen inicial, que InvokeAI usará para guiar el proceso de generación, junto con una solicitud. Un valor más bajo para esta configuración se parecerá más a la imagen original. Se aceptan valores entre 0-1, y se recomienda un rango de .25-.75",
|
||||
"boundingBox": "La caja delimitadora es análoga a las configuraciones de Ancho y Alto para Texto a Imagen o Imagen a Imagen. Solo se procesará el área en la caja.",
|
||||
"seamCorrection": "Controla el manejo de parches visibles que pueden ocurrir cuando se pega una imagen generada de nuevo en el lienzo.",
|
||||
"infillAndScaling": "Administra los métodos de relleno (utilizados en áreas enmascaradas o borradas del lienzo) y la escala (útil para tamaños de caja delimitadora pequeños)."
|
||||
|
@ -44,7 +44,26 @@
|
||||
"statusUpscaling": "Redimensinando",
|
||||
"statusUpscalingESRGAN": "Redimensinando (ESRGAN)",
|
||||
"statusLoadingModel": "Carregando Modelo",
|
||||
"statusModelChanged": "Modelo Alterado"
|
||||
"statusModelChanged": "Modelo Alterado",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"langArabic": "Árabe",
|
||||
"langEnglish": "Inglês",
|
||||
"langDutch": "Holandês",
|
||||
"langFrench": "Francês",
|
||||
"langGerman": "Alemão",
|
||||
"langItalian": "Italiano",
|
||||
"langJapanese": "Japonês",
|
||||
"langPolish": "Polonês",
|
||||
"langSimplifiedChinese": "Chinês",
|
||||
"langUkranian": "Ucraniano",
|
||||
"back": "Voltar",
|
||||
"statusConvertingModel": "Convertendo Modelo",
|
||||
"statusModelConverted": "Modelo Convertido",
|
||||
"statusMergingModels": "Mesclando Modelos",
|
||||
"statusMergedModels": "Modelos Mesclados",
|
||||
"langRussian": "Russo",
|
||||
"langSpanish": "Espanhol"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Gerações",
|
||||
@ -237,7 +256,7 @@
|
||||
"desc": "Salva a tela atual na galeria"
|
||||
},
|
||||
"copyToClipboard": {
|
||||
"title": "Copiar Para a Área de Transferência ",
|
||||
"title": "Copiar para a Área de Transferência",
|
||||
"desc": "Copia a tela atual para a área de transferência"
|
||||
},
|
||||
"downloadImage": {
|
||||
@ -284,7 +303,7 @@
|
||||
"nameValidationMsg": "Insira um nome para o seu modelo",
|
||||
"description": "Descrição",
|
||||
"descriptionValidationMsg": "Adicione uma descrição para o seu modelo",
|
||||
"config": "Config",
|
||||
"config": "Configuração",
|
||||
"configValidationMsg": "Caminho para o arquivo de configuração do seu modelo.",
|
||||
"modelLocation": "Localização do modelo",
|
||||
"modelLocationValidationMsg": "Caminho para onde seu modelo está localizado.",
|
||||
@ -317,7 +336,52 @@
|
||||
"deleteModel": "Excluir modelo",
|
||||
"deleteConfig": "Excluir Config",
|
||||
"deleteMsg1": "Tem certeza de que deseja excluir esta entrada do modelo de InvokeAI?",
|
||||
"deleteMsg2": "Isso não vai excluir o arquivo de modelo checkpoint do seu disco. Você pode lê-los, se desejar."
|
||||
"deleteMsg2": "Isso não vai excluir o arquivo de modelo checkpoint do seu disco. Você pode lê-los, se desejar.",
|
||||
"checkpointModels": "Checkpoints",
|
||||
"diffusersModels": "Diffusers",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"addCheckpointModel": "Adicionar Modelo de Checkpoint/Safetensor",
|
||||
"addDiffuserModel": "Adicionar Diffusers",
|
||||
"repo_id": "Repo ID",
|
||||
"vaeRepoID": "VAE Repo ID",
|
||||
"vaeRepoIDValidationMsg": "Repositório Online do seu VAE",
|
||||
"scanAgain": "Digitalize Novamente",
|
||||
"selectAndAdd": "Selecione e Adicione Modelos Listados Abaixo",
|
||||
"noModelsFound": "Nenhum Modelo Encontrado",
|
||||
"formMessageDiffusersModelLocation": "Localização dos Modelos Diffusers",
|
||||
"formMessageDiffusersModelLocationDesc": "Por favor entre com ao menos um.",
|
||||
"formMessageDiffusersVAELocation": "Localização do VAE",
|
||||
"formMessageDiffusersVAELocationDesc": "Se não provido, InvokeAI irá procurar pelo arquivo VAE dentro do local do modelo.",
|
||||
"convertToDiffusers": "Converter para Diffusers",
|
||||
"convertToDiffusersHelpText1": "Este modelo será convertido para o formato 🧨 Diffusers.",
|
||||
"convertToDiffusersHelpText5": "Por favor, certifique-se de que você tenha espaço suficiente em disco. Os modelos geralmente variam entre 4GB e 7GB de tamanho.",
|
||||
"convertToDiffusersHelpText6": "Você deseja converter este modelo?",
|
||||
"convertToDiffusersSaveLocation": "Local para Salvar",
|
||||
"v1": "v1",
|
||||
"v2": "v2",
|
||||
"inpainting": "v1 Inpainting",
|
||||
"customConfig": "Configuração personalizada",
|
||||
"pathToCustomConfig": "Caminho para configuração personalizada",
|
||||
"convertToDiffusersHelpText3": "Seu arquivo de ponto de verificação no disco NÃO será excluído ou modificado de forma alguma. Você pode adicionar seu ponto de verificação ao Gerenciador de modelos novamente, se desejar.",
|
||||
"convertToDiffusersHelpText4": "Este é um processo único. Pode levar cerca de 30 a 60s, dependendo das especificações do seu computador.",
|
||||
"merge": "Mesclar",
|
||||
"modelsMerged": "Modelos mesclados",
|
||||
"mergeModels": "Mesclar modelos",
|
||||
"modelOne": "Modelo 1",
|
||||
"modelTwo": "Modelo 2",
|
||||
"modelThree": "Modelo 3",
|
||||
"statusConverting": "Convertendo",
|
||||
"modelConverted": "Modelo Convertido",
|
||||
"sameFolder": "Mesma pasta",
|
||||
"invokeRoot": "Pasta do InvokeAI",
|
||||
"custom": "Personalizado",
|
||||
"customSaveLocation": "Local de salvamento personalizado",
|
||||
"mergedModelName": "Nome do modelo mesclado",
|
||||
"alpha": "Alpha",
|
||||
"allModels": "Todos os Modelos",
|
||||
"repoIDValidationMsg": "Repositório Online do seu Modelo",
|
||||
"convert": "Converter",
|
||||
"convertToDiffusersHelpText2": "Este processo irá substituir sua entrada de Gerenciador de Modelos por uma versão Diffusers do mesmo modelo."
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Imagems",
|
||||
@ -442,14 +506,14 @@
|
||||
"move": "Mover",
|
||||
"resetView": "Resetar Visualização",
|
||||
"mergeVisible": "Fundir Visível",
|
||||
"saveToGallery": "Save To Gallery",
|
||||
"saveToGallery": "Salvar na Galeria",
|
||||
"copyToClipboard": "Copiar para a Área de Transferência",
|
||||
"downloadAsImage": "Baixar Como Imagem",
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"clearCanvas": "Limpar Tela",
|
||||
"canvasSettings": "Configurações de Tela",
|
||||
"showIntermediates": "Show Intermediates",
|
||||
"showIntermediates": "Mostrar Intermediários",
|
||||
"showGrid": "Mostrar Grade",
|
||||
"snapToGrid": "Encaixar na Grade",
|
||||
"darkenOutsideSelection": "Escurecer Seleção Externa",
|
||||
|
1
invokeai/frontend/public/locales/ro.json
Normal file
1
invokeai/frontend/public/locales/ro.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -392,7 +392,7 @@ const makeSocketIOListeners = (
|
||||
addLogEntry({
|
||||
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||
message: `${i18n.t(
|
||||
'modelmanager:modelAdded'
|
||||
'modelManager.modelAdded'
|
||||
)}: ${deleted_model_name}`,
|
||||
level: 'info',
|
||||
})
|
||||
@ -400,7 +400,7 @@ const makeSocketIOListeners = (
|
||||
dispatch(
|
||||
addToast({
|
||||
title: `${i18n.t(
|
||||
'modelmanager:modelEntryDeleted'
|
||||
'modelManager.modelEntryDeleted'
|
||||
)}: ${deleted_model_name}`,
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
@ -424,7 +424,7 @@ const makeSocketIOListeners = (
|
||||
dispatch(
|
||||
addToast({
|
||||
title: `${i18n.t(
|
||||
'modelmanager:modelConverted'
|
||||
'modelManager.modelConverted'
|
||||
)}: ${converted_model_name}`,
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
|
@ -144,8 +144,8 @@ export const frontendToBackendParameters = (
|
||||
variationAmount,
|
||||
width,
|
||||
shouldUseSymmetry,
|
||||
horizontalSymmetryTimePercentage,
|
||||
verticalSymmetryTimePercentage,
|
||||
horizontalSymmetrySteps,
|
||||
verticalSymmetrySteps,
|
||||
} = generationState;
|
||||
|
||||
const {
|
||||
@ -185,17 +185,17 @@ export const frontendToBackendParameters = (
|
||||
|
||||
// Symmetry Settings
|
||||
if (shouldUseSymmetry) {
|
||||
if (horizontalSymmetryTimePercentage > 0) {
|
||||
if (horizontalSymmetrySteps > 0) {
|
||||
generationParameters.h_symmetry_time_pct = Math.max(
|
||||
0,
|
||||
Math.min(1, horizontalSymmetryTimePercentage / steps)
|
||||
Math.min(1, horizontalSymmetrySteps / steps)
|
||||
);
|
||||
}
|
||||
|
||||
if (horizontalSymmetryTimePercentage > 0) {
|
||||
if (verticalSymmetrySteps > 0) {
|
||||
generationParameters.v_symmetry_time_pct = Math.max(
|
||||
0,
|
||||
Math.min(1, verticalSymmetryTimePercentage / steps)
|
||||
Math.min(1, verticalSymmetrySteps / steps)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ const IAICanvasStatusText = () => {
|
||||
color: boundingBoxColor,
|
||||
}}
|
||||
>{`${t(
|
||||
'unifiedcanvas:boundingBox'
|
||||
'unifiedCanvas.boundingBox'
|
||||
)}: ${boundingBoxDimensionsString}`}</div>
|
||||
)}
|
||||
{shouldShowScaledBoundingBox && (
|
||||
@ -118,19 +118,19 @@ const IAICanvasStatusText = () => {
|
||||
color: boundingBoxColor,
|
||||
}}
|
||||
>{`${t(
|
||||
'unifiedcanvas:scaledBoundingBox'
|
||||
'unifiedCanvas.scaledBoundingBox'
|
||||
)}: ${scaledBoundingBoxDimensionsString}`}</div>
|
||||
)}
|
||||
{shouldShowCanvasDebugInfo && (
|
||||
<>
|
||||
<div>{`${t(
|
||||
'unifiedcanvas:boundingBoxPosition'
|
||||
'unifiedCanvas.boundingBoxPosition'
|
||||
)}: ${boundingBoxCoordinatesString}`}</div>
|
||||
<div>{`${t(
|
||||
'unifiedcanvas:canvasDimensions'
|
||||
'unifiedCanvas.canvasDimensions'
|
||||
)}: ${canvasDimensionsString}`}</div>
|
||||
<div>{`${t(
|
||||
'unifiedcanvas:canvasPosition'
|
||||
'unifiedCanvas.canvasPosition'
|
||||
)}: ${canvasCoordinatesString}`}</div>
|
||||
<IAICanvasStatusTextCursorPos />
|
||||
</>
|
||||
|
@ -34,7 +34,7 @@ export default function IAICanvasStatusTextCursorPos() {
|
||||
|
||||
return (
|
||||
<div>{`${t(
|
||||
'unifiedcanvas:cursorPosition'
|
||||
'unifiedCanvas.cursorPosition'
|
||||
)}: ${cursorCoordinatesString}`}</div>
|
||||
);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
setInitialImage,
|
||||
setSeed,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { setAllPostProcessingParameters } from 'features/parameters/store/postprocessingSlice';
|
||||
import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { SystemState } from 'features/system/store/systemSlice';
|
||||
@ -189,11 +190,12 @@ const CurrentImageButtons = () => {
|
||||
);
|
||||
|
||||
const handleClickUseAllParameters = () => {
|
||||
if (!currentImage) return;
|
||||
currentImage.metadata && dispatch(setAllParameters(currentImage.metadata));
|
||||
if (currentImage.metadata?.image.type === 'img2img') {
|
||||
if (!currentImage?.metadata) return;
|
||||
dispatch(setAllParameters(currentImage.metadata));
|
||||
dispatch(setAllPostProcessingParameters(currentImage.metadata));
|
||||
if (currentImage.metadata.image.type === 'img2img') {
|
||||
dispatch(setActiveTab('img2img'));
|
||||
} else if (currentImage.metadata?.image.type === 'txt2img') {
|
||||
} else if (currentImage.metadata.image.type === 'txt2img') {
|
||||
dispatch(setActiveTab('txt2img'));
|
||||
}
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
setInitialImage,
|
||||
setSeed,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { setAllPostProcessingParameters } from 'features/parameters/store/postprocessingSlice';
|
||||
import { DragEvent, memo, useState } from 'react';
|
||||
import { FaCheck, FaTrashAlt } from 'react-icons/fa';
|
||||
import DeleteImageModal from './DeleteImageModal';
|
||||
@ -114,7 +115,10 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
};
|
||||
|
||||
const handleUseAllParameters = () => {
|
||||
metadata && dispatch(setAllParameters(metadata));
|
||||
if (metadata) {
|
||||
dispatch(setAllParameters(metadata));
|
||||
dispatch(setAllPostProcessingParameters(metadata));
|
||||
}
|
||||
toast({
|
||||
title: t('toast.parametersSet'),
|
||||
status: 'success',
|
||||
|
@ -2,18 +2,18 @@ import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import {
|
||||
setHorizontalSymmetryTimePercentage,
|
||||
setVerticalSymmetryTimePercentage,
|
||||
setHorizontalSymmetrySteps,
|
||||
setVerticalSymmetrySteps,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SymmetrySettings() {
|
||||
const horizontalSymmetryTimePercentage = useAppSelector(
|
||||
(state: RootState) => state.generation.horizontalSymmetryTimePercentage
|
||||
const horizontalSymmetrySteps = useAppSelector(
|
||||
(state: RootState) => state.generation.horizontalSymmetrySteps
|
||||
);
|
||||
|
||||
const verticalSymmetryTimePercentage = useAppSelector(
|
||||
(state: RootState) => state.generation.verticalSymmetryTimePercentage
|
||||
const verticalSymmetrySteps = useAppSelector(
|
||||
(state: RootState) => state.generation.verticalSymmetrySteps
|
||||
);
|
||||
|
||||
const steps = useAppSelector((state: RootState) => state.generation.steps);
|
||||
@ -26,28 +26,28 @@ export default function SymmetrySettings() {
|
||||
<>
|
||||
<IAISlider
|
||||
label={t('parameters.hSymmetryStep')}
|
||||
value={horizontalSymmetryTimePercentage}
|
||||
onChange={(v) => dispatch(setHorizontalSymmetryTimePercentage(v))}
|
||||
value={horizontalSymmetrySteps}
|
||||
onChange={(v) => dispatch(setHorizontalSymmetrySteps(v))}
|
||||
min={0}
|
||||
max={steps}
|
||||
step={1}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => dispatch(setHorizontalSymmetryTimePercentage(0))}
|
||||
handleReset={() => dispatch(setHorizontalSymmetrySteps(0))}
|
||||
sliderMarkRightOffset={-6}
|
||||
></IAISlider>
|
||||
<IAISlider
|
||||
label={t('parameters.vSymmetryStep')}
|
||||
value={verticalSymmetryTimePercentage}
|
||||
onChange={(v) => dispatch(setVerticalSymmetryTimePercentage(v))}
|
||||
value={verticalSymmetrySteps}
|
||||
onChange={(v) => dispatch(setVerticalSymmetrySteps(v))}
|
||||
min={0}
|
||||
max={steps}
|
||||
step={1}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => dispatch(setVerticalSymmetryTimePercentage(0))}
|
||||
handleReset={() => dispatch(setVerticalSymmetrySteps(0))}
|
||||
sliderMarkRightOffset={-6}
|
||||
></IAISlider>
|
||||
</>
|
||||
|
@ -3,7 +3,10 @@ import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSteps } from 'features/parameters/store/generationSlice';
|
||||
import {
|
||||
clampSymmetrySteps,
|
||||
setSteps,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function MainSteps() {
|
||||
@ -14,7 +17,13 @@ export default function MainSteps() {
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeSteps = (v: number) => dispatch(setSteps(v));
|
||||
const handleChangeSteps = (v: number) => {
|
||||
dispatch(setSteps(v));
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
dispatch(clampSymmetrySteps());
|
||||
};
|
||||
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
@ -41,6 +50,7 @@ export default function MainSteps() {
|
||||
width="auto"
|
||||
styleClass="main-settings-block"
|
||||
textAlign="center"
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import IAIButton, { IAIButtonProps } from 'common/components/IAIButton';
|
||||
import IAIIconButton, {
|
||||
IAIIconButtonProps,
|
||||
} from 'common/components/IAIIconButton';
|
||||
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -30,6 +31,7 @@ export default function InvokeButton(props: InvokeButton) {
|
||||
useHotkeys(
|
||||
['ctrl+enter', 'meta+enter'],
|
||||
() => {
|
||||
dispatch(clampSymmetrySteps());
|
||||
dispatch(generateImage(activeTabName));
|
||||
},
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ import * as InvokeAI from 'app/invokeai';
|
||||
import { getPromptAndNegative } from 'common/util/getPromptAndNegative';
|
||||
import promptToString from 'common/util/promptToString';
|
||||
import { seedWeightsToString } from 'common/util/seedWeightPairs';
|
||||
import { clamp } from 'lodash';
|
||||
|
||||
export interface GenerationState {
|
||||
cfgScale: number;
|
||||
@ -33,8 +34,8 @@ export interface GenerationState {
|
||||
variationAmount: number;
|
||||
width: number;
|
||||
shouldUseSymmetry: boolean;
|
||||
horizontalSymmetryTimePercentage: number;
|
||||
verticalSymmetryTimePercentage: number;
|
||||
horizontalSymmetrySteps: number;
|
||||
verticalSymmetrySteps: number;
|
||||
}
|
||||
|
||||
const initialGenerationState: GenerationState = {
|
||||
@ -64,8 +65,8 @@ const initialGenerationState: GenerationState = {
|
||||
variationAmount: 0.1,
|
||||
width: 512,
|
||||
shouldUseSymmetry: false,
|
||||
horizontalSymmetryTimePercentage: 0,
|
||||
verticalSymmetryTimePercentage: 0,
|
||||
horizontalSymmetrySteps: 0,
|
||||
verticalSymmetrySteps: 0,
|
||||
};
|
||||
|
||||
const initialState: GenerationState = initialGenerationState;
|
||||
@ -99,6 +100,18 @@ export const generationSlice = createSlice({
|
||||
setSteps: (state, action: PayloadAction<number>) => {
|
||||
state.steps = action.payload;
|
||||
},
|
||||
clampSymmetrySteps: (state) => {
|
||||
state.horizontalSymmetrySteps = clamp(
|
||||
state.horizontalSymmetrySteps,
|
||||
0,
|
||||
state.steps
|
||||
);
|
||||
state.verticalSymmetrySteps = clamp(
|
||||
state.verticalSymmetrySteps,
|
||||
0,
|
||||
state.steps
|
||||
);
|
||||
},
|
||||
setCfgScale: (state, action: PayloadAction<number>) => {
|
||||
state.cfgScale = action.payload;
|
||||
},
|
||||
@ -288,7 +301,6 @@ export const generationSlice = createSlice({
|
||||
state.perlin = perlin;
|
||||
}
|
||||
if (typeof seamless === 'boolean') state.seamless = seamless;
|
||||
// if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg
|
||||
if (width) state.width = width;
|
||||
if (height) state.height = height;
|
||||
|
||||
@ -334,22 +346,17 @@ export const generationSlice = createSlice({
|
||||
setShouldUseSymmetry: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldUseSymmetry = action.payload;
|
||||
},
|
||||
setHorizontalSymmetryTimePercentage: (
|
||||
state,
|
||||
action: PayloadAction<number>
|
||||
) => {
|
||||
state.horizontalSymmetryTimePercentage = action.payload;
|
||||
setHorizontalSymmetrySteps: (state, action: PayloadAction<number>) => {
|
||||
state.horizontalSymmetrySteps = action.payload;
|
||||
},
|
||||
setVerticalSymmetryTimePercentage: (
|
||||
state,
|
||||
action: PayloadAction<number>
|
||||
) => {
|
||||
state.verticalSymmetryTimePercentage = action.payload;
|
||||
setVerticalSymmetrySteps: (state, action: PayloadAction<number>) => {
|
||||
state.verticalSymmetrySteps = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
clampSymmetrySteps,
|
||||
clearInitialImage,
|
||||
resetParametersState,
|
||||
resetSeed,
|
||||
@ -384,8 +391,8 @@ export const {
|
||||
setVariationAmount,
|
||||
setWidth,
|
||||
setShouldUseSymmetry,
|
||||
setHorizontalSymmetryTimePercentage,
|
||||
setVerticalSymmetryTimePercentage,
|
||||
setHorizontalSymmetrySteps,
|
||||
setVerticalSymmetrySteps,
|
||||
} = generationSlice.actions;
|
||||
|
||||
export default generationSlice.reducer;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import * as InvokeAI from 'app/invokeai';
|
||||
import { FACETOOL_TYPES } from 'app/constants';
|
||||
|
||||
export type UpscalingLevel = 2 | 4;
|
||||
@ -40,6 +41,17 @@ export const postprocessingSlice = createSlice({
|
||||
name: 'postprocessing',
|
||||
initialState,
|
||||
reducers: {
|
||||
setAllPostProcessingParameters: (
|
||||
state,
|
||||
action: PayloadAction<InvokeAI.Metadata>
|
||||
) => {
|
||||
const { type, hires_fix } = action.payload.image;
|
||||
|
||||
if (type === 'txt2img') {
|
||||
state.hiresFix = Boolean(hires_fix);
|
||||
// Strength of img2img used in hires_fix is not currently exposed in the Metadata for the final image.
|
||||
}
|
||||
},
|
||||
setFacetoolStrength: (state, action: PayloadAction<number>) => {
|
||||
state.facetoolStrength = action.payload;
|
||||
},
|
||||
@ -83,6 +95,7 @@ export const postprocessingSlice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
setAllPostProcessingParameters,
|
||||
resetPostprocessingState,
|
||||
setCodeformerFidelity,
|
||||
setFacetoolStrength,
|
||||
|
@ -57,19 +57,19 @@ export default function MergeModels() {
|
||||
|
||||
const [modelMergeForce, setModelMergeForce] = useState<boolean>(false);
|
||||
|
||||
const modelOneList = Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelTwo && model !== modelThree) return model;
|
||||
});
|
||||
const modelOneList = Object.keys(diffusersModels).filter(
|
||||
(model) => model !== modelTwo && model !== modelThree
|
||||
);
|
||||
|
||||
const modelTwoList = Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelOne && model !== modelThree) return model;
|
||||
});
|
||||
const modelTwoList = Object.keys(diffusersModels).filter(
|
||||
(model) => model !== modelOne && model !== modelThree
|
||||
);
|
||||
|
||||
const modelThreeList = [
|
||||
'none',
|
||||
...Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelOne && model !== modelTwo) return model;
|
||||
}),
|
||||
{ key: t('modelManager.none'), value: 'none' },
|
||||
...Object.keys(diffusersModels)
|
||||
.filter((model) => model !== modelOne && model !== modelTwo)
|
||||
.map((model) => ({ key: model, value: model })),
|
||||
];
|
||||
|
||||
const isProcessing = useAppSelector(
|
||||
@ -209,18 +209,22 @@ export default function MergeModels() {
|
||||
<Flex columnGap={4}>
|
||||
{modelThree === 'none' ? (
|
||||
<>
|
||||
<Radio value="weighted_sum">weighted_sum</Radio>
|
||||
<Radio value="sigmoid">sigmoid</Radio>
|
||||
<Radio value="inv_sigmoid">inv_sigmoid</Radio>
|
||||
<Radio value="weighted_sum">
|
||||
{t('modelManager.weightedSum')}
|
||||
</Radio>
|
||||
<Radio value="sigmoid">{t('modelManager.sigmoid')}</Radio>
|
||||
<Radio value="inv_sigmoid">
|
||||
{t('modelManager.inverseSigmoid')}
|
||||
</Radio>
|
||||
</>
|
||||
) : (
|
||||
<Radio value="add_difference">
|
||||
<Tooltip
|
||||
label={t(
|
||||
'modelmanager:modelMergeInterpAddDifferenceHelp'
|
||||
'modelManager.modelMergeInterpAddDifferenceHelp'
|
||||
)}
|
||||
>
|
||||
add_difference
|
||||
{t('modelManager.addDifference')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
)}
|
||||
|
@ -181,7 +181,8 @@ export default function SearchModels() {
|
||||
|
||||
const configFiles = {
|
||||
v1: 'configs/stable-diffusion/v1-inference.yaml',
|
||||
v2: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||
v2_base: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||
v2_768: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||
inpainting: 'configs/stable-diffusion/v1-inpainting-inference.yaml',
|
||||
custom: pathToConfig,
|
||||
};
|
||||
@ -385,7 +386,8 @@ export default function SearchModels() {
|
||||
>
|
||||
<Flex gap={4}>
|
||||
<Radio value="v1">{t('modelManager.v1')}</Radio>
|
||||
<Radio value="v2">{t('modelManager.v2')}</Radio>
|
||||
<Radio value="v2_base">{t('modelManager.v2_base')}</Radio>
|
||||
<Radio value="v2_768">{t('modelManager.v2_768')}</Radio>
|
||||
<Radio value="inpainting">
|
||||
{t('modelManager.inpainting')}
|
||||
</Radio>
|
||||
|
@ -18,6 +18,7 @@ import { setParametersPanelScrollPosition } from 'features/ui/store/uiSlice';
|
||||
import InvokeAILogo from 'assets/images/logo.png';
|
||||
import { isEqual } from 'lodash';
|
||||
import { uiSelector } from '../store/uiSelectors';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = { children: ReactNode };
|
||||
|
||||
@ -60,6 +61,8 @@ const InvokeOptionsPanel = (props: Props) => {
|
||||
|
||||
const { children } = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Hotkeys
|
||||
useHotkeys(
|
||||
'o',
|
||||
@ -176,7 +179,7 @@ const InvokeOptionsPanel = (props: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Tooltip label="Pin Options Panel">
|
||||
<Tooltip label={t('common.pinOptionsPanel')}>
|
||||
<div
|
||||
className="parameters-panel-pin-button"
|
||||
data-selected={shouldPinParametersPanel}
|
||||
|
5
invokeai/frontend/src/i18.d.ts
vendored
5
invokeai/frontend/src/i18.d.ts
vendored
@ -1,11 +1,16 @@
|
||||
import 'i18next';
|
||||
|
||||
import en from '../public/locales/en.json';
|
||||
|
||||
declare module 'i18next' {
|
||||
// Extend CustomTypeOptions
|
||||
interface CustomTypeOptions {
|
||||
// Setting Default Namespace As English
|
||||
defaultNS: 'en';
|
||||
// Custom Types For Resources
|
||||
resources: {
|
||||
en: typeof en;
|
||||
};
|
||||
// Never Return Null
|
||||
returnNull: false;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -200,6 +200,8 @@ class Generate:
|
||||
# it wasn't actually doing anything. This logic could be reinstated.
|
||||
self.device = torch.device(choose_torch_device())
|
||||
print(f">> Using device_type {self.device.type}")
|
||||
if self.device.type == 'cuda':
|
||||
print(f">> CUDA device '{torch.cuda.get_device_name(torch.cuda.current_device())}' (GPU {os.environ.get('CUDA_VISIBLE_DEVICES') or 0})")
|
||||
if full_precision:
|
||||
if self.precision != "auto":
|
||||
raise ValueError("Remove --full_precision / -F if using --precision")
|
||||
|
@ -4,6 +4,7 @@ import shlex
|
||||
import sys
|
||||
import traceback
|
||||
from argparse import Namespace
|
||||
from packaging import version
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
@ -22,7 +23,7 @@ from ..generate import Generate
|
||||
from .args import (Args, dream_cmd_from_png, metadata_dumps,
|
||||
metadata_from_png)
|
||||
from .generator.diffusers_pipeline import PipelineIntermediateState
|
||||
from .globals import Globals
|
||||
from .globals import Globals, global_config_dir
|
||||
from .image_util import make_grid
|
||||
from .log import write_log
|
||||
from .model_manager import ModelManager
|
||||
@ -33,7 +34,6 @@ from ..util import url_attachment_name
|
||||
# global used in multiple functions (fix)
|
||||
infile = None
|
||||
|
||||
|
||||
def main():
|
||||
"""Initialize command-line parsers and the diffusion model"""
|
||||
global infile
|
||||
@ -66,6 +66,9 @@ def main():
|
||||
Globals.sequential_guidance = args.sequential_guidance
|
||||
Globals.ckpt_convert = args.ckpt_convert
|
||||
|
||||
# run any post-install patches needed
|
||||
run_patches()
|
||||
|
||||
print(f">> Internet connectivity is {Globals.internet_available}")
|
||||
|
||||
if not args.conf:
|
||||
@ -156,10 +159,16 @@ def main():
|
||||
except Exception as e:
|
||||
report_model_error(opt, e)
|
||||
|
||||
# completer is the readline object
|
||||
completer = get_completer(opt, models=gen.model_manager.list_models())
|
||||
|
||||
# try to autoconvert new models
|
||||
if path := opt.autoimport:
|
||||
gen.model_manager.heuristic_import(
|
||||
str(path), convert=False, commit_to_conf=opt.conf
|
||||
str(path),
|
||||
convert=False,
|
||||
commit_to_conf=opt.conf,
|
||||
config_file_callback=lambda x: _pick_configuration_file(completer,x),
|
||||
)
|
||||
|
||||
if path := opt.autoconvert:
|
||||
@ -178,7 +187,7 @@ def main():
|
||||
)
|
||||
|
||||
try:
|
||||
main_loop(gen, opt)
|
||||
main_loop(gen, opt, completer)
|
||||
except KeyboardInterrupt:
|
||||
print(
|
||||
f'\nGoodbye!\nYou can start InvokeAI again by running the "invoke.bat" (or "invoke.sh") script from {Globals.root}'
|
||||
@ -189,7 +198,7 @@ def main():
|
||||
|
||||
|
||||
# TODO: main_loop() has gotten busy. Needs to be refactored.
|
||||
def main_loop(gen, opt):
|
||||
def main_loop(gen, opt, completer):
|
||||
"""prompt/read/execute loop"""
|
||||
global infile
|
||||
done = False
|
||||
@ -200,7 +209,6 @@ def main_loop(gen, opt):
|
||||
# The readline completer reads history from the .dream_history file located in the
|
||||
# output directory specified at the time of script launch. We do not currently support
|
||||
# changing the history file midstream when the output directory is changed.
|
||||
completer = get_completer(opt, models=gen.model_manager.list_models())
|
||||
set_default_output_dir(opt, completer)
|
||||
if gen.model:
|
||||
add_embedding_terms(gen, completer)
|
||||
@ -389,6 +397,7 @@ def main_loop(gen, opt):
|
||||
prior_variations,
|
||||
postprocessed,
|
||||
first_seed,
|
||||
gen.model_name,
|
||||
)
|
||||
path = file_writer.save_image_and_prompt_to_png(
|
||||
image=image,
|
||||
@ -402,6 +411,7 @@ def main_loop(gen, opt):
|
||||
else first_seed
|
||||
],
|
||||
model_hash=gen.model_hash,
|
||||
model_id=gen.model_name,
|
||||
),
|
||||
name=filename,
|
||||
compress_level=opt.png_compression,
|
||||
@ -657,10 +667,10 @@ def import_model(model_path: str, gen, opt, completer, convert=False):
|
||||
model_name=model_name,
|
||||
description=model_desc,
|
||||
convert=convert,
|
||||
config_file_callback=lambda x: _pick_configuration_file(completer,x),
|
||||
)
|
||||
|
||||
if not imported_name:
|
||||
print("** Import failed or was skipped")
|
||||
print("** Aborting import.")
|
||||
return
|
||||
|
||||
if not _verify_load(imported_name, gen):
|
||||
@ -674,6 +684,48 @@ def import_model(model_path: str, gen, opt, completer, convert=False):
|
||||
completer.update_models(gen.model_manager.list_models())
|
||||
print(f">> {imported_name} successfully installed")
|
||||
|
||||
def _pick_configuration_file(completer, checkpoint_path: Path)->Path:
|
||||
print(
|
||||
f"""
|
||||
Please select the type of the model at checkpoint {checkpoint_path}:
|
||||
[1] A Stable Diffusion v1.x ckpt/safetensors model
|
||||
[2] A Stable Diffusion v1.x inpainting ckpt/safetensors model
|
||||
[3] A Stable Diffusion v2.x base model (512 pixels; there should be no 'parameterization:' line in its yaml file)
|
||||
[4] A Stable Diffusion v2.x v-predictive model (768 pixels; look for a 'parameterization: "v"' line in its yaml file)
|
||||
[5] Other (you will be prompted to enter the config file path)
|
||||
[Q] I have no idea! Skip the import.
|
||||
""")
|
||||
choices = [
|
||||
global_config_dir() / 'stable-diffusion' / x
|
||||
for x in [
|
||||
'v1-inference.yaml',
|
||||
'v1-inpainting-inference.yaml',
|
||||
'v2-inference.yaml',
|
||||
'v2-inference-v.yaml',
|
||||
]
|
||||
]
|
||||
|
||||
ok = False
|
||||
while not ok:
|
||||
try:
|
||||
choice = input('select 0-5, Q > ').strip()
|
||||
if choice.startswith(('q','Q')):
|
||||
return
|
||||
if choice == '5':
|
||||
completer.complete_extensions(('.yaml'))
|
||||
choice = Path(input('Select config file for this model> ').strip()).absolute()
|
||||
completer.complete_extensions(None)
|
||||
ok = choice.exists()
|
||||
else:
|
||||
choice = choices[int(choice)-1]
|
||||
ok = True
|
||||
except (ValueError, IndexError):
|
||||
print(f'{choice} is not a valid choice')
|
||||
except EOFError:
|
||||
return
|
||||
return choice
|
||||
|
||||
|
||||
def _verify_load(model_name: str, gen) -> bool:
|
||||
print(">> Verifying that new model loads...")
|
||||
current_model = gen.model_name
|
||||
@ -720,11 +772,11 @@ def convert_model(model_name_or_path: Union[Path, str], gen, opt, completer):
|
||||
original_config_file = Path(model_info["config"])
|
||||
model_name = model_name_or_path
|
||||
model_description = model_info["description"]
|
||||
vae = model_info["vae"]
|
||||
vae = model_info.get("vae")
|
||||
else:
|
||||
print(f"** {model_name_or_path} is not a legacy .ckpt weights file")
|
||||
return
|
||||
if vae_repo := ldm.invoke.model_manager.VAE_TO_REPO_ID.get(Path(vae).stem):
|
||||
if vae and (vae_repo := ldm.invoke.model_manager.VAE_TO_REPO_ID.get(Path(vae).stem)):
|
||||
vae_repo = dict(repo_id=vae_repo)
|
||||
else:
|
||||
vae_repo = None
|
||||
@ -744,8 +796,8 @@ def convert_model(model_name_or_path: Union[Path, str], gen, opt, completer):
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
manager.commit(opt.conf)
|
||||
if click.confirm(f"Delete the original .ckpt file at {ckpt_path}?", default=False):
|
||||
manager.commit(opt.conf)
|
||||
if ckpt_path and click.confirm(f"Delete the original .ckpt file at {ckpt_path}?", default=False):
|
||||
ckpt_path.unlink(missing_ok=True)
|
||||
print(f"{ckpt_path} deleted")
|
||||
|
||||
@ -941,13 +993,14 @@ def add_postprocessing_to_metadata(opt, original_file, new_file, tool, command):
|
||||
|
||||
|
||||
def prepare_image_metadata(
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation="generate",
|
||||
prior_variations=[],
|
||||
postprocessed=False,
|
||||
first_seed=None,
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation="generate",
|
||||
prior_variations=[],
|
||||
postprocessed=False,
|
||||
first_seed=None,
|
||||
model_id='unknown',
|
||||
):
|
||||
if postprocessed and opt.save_original:
|
||||
filename = choose_postprocess_name(opt, prefix, seed)
|
||||
@ -955,6 +1008,7 @@ def prepare_image_metadata(
|
||||
wildcards = dict(opt.__dict__)
|
||||
wildcards["prefix"] = prefix
|
||||
wildcards["seed"] = seed
|
||||
wildcards["model_id"] = model_id
|
||||
try:
|
||||
filename = opt.fnformat.format(**wildcards)
|
||||
except KeyError as e:
|
||||
@ -972,18 +1026,17 @@ def prepare_image_metadata(
|
||||
first_seed = first_seed or seed
|
||||
this_variation = [[seed, opt.variation_amount]]
|
||||
opt.with_variations = prior_variations + this_variation
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,model_id=model_id)
|
||||
elif len(prior_variations) > 0:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,model_id=model_id)
|
||||
elif operation == "postprocess":
|
||||
formatted_dream_prompt = "!fix " + opt.dream_prompt_str(
|
||||
seed=seed, prompt=opt.input_file_path
|
||||
seed=seed, prompt=opt.input_file_path, model_id=model_id,
|
||||
)
|
||||
else:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=seed,model_id=model_id)
|
||||
return filename, formatted_dream_prompt
|
||||
|
||||
|
||||
def choose_postprocess_name(opt, prefix, seed) -> str:
|
||||
match = re.search("postprocess:(\w+)", opt.last_operation)
|
||||
if match:
|
||||
@ -1234,6 +1287,60 @@ def check_internet() -> bool:
|
||||
except:
|
||||
return False
|
||||
|
||||
# This routine performs any patch-ups needed after installation
|
||||
def run_patches():
|
||||
install_missing_config_files()
|
||||
version_file = Path(Globals.root,'.version')
|
||||
if version_file.exists():
|
||||
with open(version_file,'r') as f:
|
||||
root_version = version.parse(f.readline() or 'v2.3.2')
|
||||
else:
|
||||
root_version = version.parse('v2.3.2')
|
||||
app_version = version.parse(ldm.invoke.__version__)
|
||||
if root_version < app_version:
|
||||
try:
|
||||
do_version_update(root_version, ldm.invoke.__version__)
|
||||
with open(version_file,'w') as f:
|
||||
f.write(ldm.invoke.__version__)
|
||||
except:
|
||||
print("** Update failed. Will try again on next launch")
|
||||
|
||||
def install_missing_config_files():
|
||||
"""
|
||||
install ckpt configuration files that may have been added to the
|
||||
distro after original root directory configuration
|
||||
"""
|
||||
import invokeai.configs as conf
|
||||
from shutil import copyfile
|
||||
|
||||
root_configs = Path(global_config_dir(), 'stable-diffusion')
|
||||
repo_configs = Path(conf.__path__[0], 'stable-diffusion')
|
||||
for src in repo_configs.iterdir():
|
||||
dest = root_configs / src.name
|
||||
if not dest.exists():
|
||||
copyfile(src,dest)
|
||||
|
||||
def do_version_update(root_version: version.Version, app_version: Union[str, version.Version]):
|
||||
"""
|
||||
Make any updates to the launcher .sh and .bat scripts that may be needed
|
||||
from release to release. This is not an elegant solution. Instead, the
|
||||
launcher should be moved into the source tree and installed using pip.
|
||||
"""
|
||||
if root_version < version.Version('v2.3.3'):
|
||||
if sys.platform == "linux":
|
||||
print('>> Downloading new version of launcher script and its config file')
|
||||
from ldm.util import download_with_progress_bar
|
||||
url_base = f'https://raw.githubusercontent.com/invoke-ai/InvokeAI/release/v{str(app_version)}/installer/templates/'
|
||||
|
||||
dest = Path(Globals.root,'invoke.sh.in')
|
||||
assert download_with_progress_bar(url_base+'invoke.sh.in',dest)
|
||||
dest.replace(Path(Globals.root,'invoke.sh'))
|
||||
os.chmod(Path(Globals.root,'invoke.sh'), 0o0755)
|
||||
|
||||
dest = Path(Globals.root,'dialogrc')
|
||||
assert download_with_progress_bar(url_base+'dialogrc',dest)
|
||||
dest.replace(Path(Globals.root,'.dialogrc'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
__version__='2.3.1'
|
||||
|
||||
__version__='2.3.3-rc2'
|
||||
|
@ -333,7 +333,7 @@ class Args(object):
|
||||
switches.append(f'-V {formatted_variations}')
|
||||
if 'variations' in a and len(a['variations'])>0:
|
||||
switches.append(f'-V {a["variations"]}')
|
||||
return ' '.join(switches)
|
||||
return ' '.join(switches) + f' # model_id={kwargs.get("model_id","unknown model")}'
|
||||
|
||||
def __getattribute__(self,name):
|
||||
'''
|
||||
@ -878,7 +878,7 @@ class Args(object):
|
||||
)
|
||||
render_group.add_argument(
|
||||
'--fnformat',
|
||||
default='{prefix}.{seed}.png',
|
||||
default=None,
|
||||
type=str,
|
||||
help='Overwrite the filename format. You can use any argument as wildcard enclosed in curly braces. Default is {prefix}.{seed}.png',
|
||||
)
|
||||
@ -1155,6 +1155,7 @@ def format_metadata(**kwargs):
|
||||
def metadata_dumps(opt,
|
||||
seeds=[],
|
||||
model_hash=None,
|
||||
model_id=None,
|
||||
postprocessing=None):
|
||||
'''
|
||||
Given an Args object, returns a dict containing the keys and
|
||||
@ -1167,7 +1168,7 @@ def metadata_dumps(opt,
|
||||
# top-level metadata minus `image` or `images`
|
||||
metadata = {
|
||||
'model' : 'stable diffusion',
|
||||
'model_id' : opt.model,
|
||||
'model_id' : model_id or opt.model,
|
||||
'model_hash' : model_hash,
|
||||
'app_id' : ldm.invoke.__app_id__,
|
||||
'app_version' : ldm.invoke.__version__,
|
||||
@ -1180,7 +1181,7 @@ def metadata_dumps(opt,
|
||||
)
|
||||
|
||||
# remove any image keys not mentioned in RFC #266
|
||||
rfc266_img_fields = ['type','postprocessing','sampler','prompt','seed','variations','steps',
|
||||
rfc266_img_fields = ['type','postprocessing','sampler','prompt','seed','variations','steps','hires_fix',
|
||||
'cfg_scale','threshold','perlin','step_number','width','height','extra','strength','seamless'
|
||||
'init_img','init_mask','facetool','facetool_strength','upscale','h_symmetry_time_pct',
|
||||
'v_symmetry_time_pct']
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ get_uc_and_c_and_ec() get the conditioned and unconditioned latent, an
|
||||
import re
|
||||
from typing import Union, Optional, Any
|
||||
|
||||
from transformers import CLIPTokenizer, CLIPTextModel
|
||||
from transformers import CLIPTokenizer
|
||||
|
||||
from compel import Compel
|
||||
from compel.prompt_parser import FlattenedPrompt, Blend, Fragment, CrossAttentionControlSubstitute, PromptParser
|
||||
@ -52,6 +52,8 @@ def get_uc_and_c_and_ec(prompt_string, model, log_tokens=False, skip_normalize_l
|
||||
textual_inversion_manager=model.textual_inversion_manager,
|
||||
dtype_for_device_getter=torch_dtype)
|
||||
|
||||
# get rid of any newline characters
|
||||
prompt_string = prompt_string.replace("\n", " ")
|
||||
positive_prompt_string, negative_prompt_string = split_prompt_to_positive_and_negative(prompt_string)
|
||||
legacy_blend = try_parse_legacy_blend(positive_prompt_string, skip_normalize_legacy_blend)
|
||||
positive_prompt: FlattenedPrompt|Blend
|
||||
@ -113,7 +115,7 @@ def get_tokens_for_prompt_object(tokenizer, parsed_prompt: FlattenedPrompt, trun
|
||||
return tokens
|
||||
|
||||
|
||||
def split_prompt_to_positive_and_negative(prompt_string_uncleaned):
|
||||
def split_prompt_to_positive_and_negative(prompt_string_uncleaned: str):
|
||||
unconditioned_words = ''
|
||||
unconditional_regex = r'\[(.*?)\]'
|
||||
unconditionals = re.findall(unconditional_regex, prompt_string_uncleaned)
|
||||
|
@ -290,7 +290,7 @@ def download_vaes():
|
||||
# first the diffusers version
|
||||
repo_id = "stabilityai/sd-vae-ft-mse"
|
||||
args = dict(
|
||||
cache_dir=global_cache_dir("diffusers"),
|
||||
cache_dir=global_cache_dir("hub"),
|
||||
)
|
||||
if not AutoencoderKL.from_pretrained(repo_id, **args):
|
||||
raise Exception(f"download of {repo_id} failed")
|
||||
@ -712,8 +712,8 @@ def write_opts(opts: Namespace, init_file: Path):
|
||||
out_file.write(line + "\n")
|
||||
out_file.write(
|
||||
f"""
|
||||
--outdir={opts.outdir}
|
||||
--embedding_path={opts.embedding_path}
|
||||
--outdir="{opts.outdir}"
|
||||
--embedding_path="{opts.embedding_path}"
|
||||
--precision={opts.precision}
|
||||
--max_loaded_models={int(opts.max_loaded_models)}
|
||||
--{'no-' if not opts.safety_checker else ''}nsfw_checker
|
||||
|
@ -72,7 +72,7 @@ def main():
|
||||
tag = Prompt.ask('Enter an InvokeAI tag or branch name')
|
||||
|
||||
print(f':crossed_fingers: Upgrading to [yellow]{tag}[/yellow]')
|
||||
cmd = f'pip install {INVOKE_AI_SRC}/{tag}.zip --use-pep517'
|
||||
cmd = f'pip install {INVOKE_AI_SRC}/{tag}.zip --use-pep517 --upgrade'
|
||||
print('')
|
||||
print('')
|
||||
if os.system(cmd)==0:
|
||||
|
@ -109,6 +109,7 @@ def install_requested_models(
|
||||
model_manager.heuristic_import(
|
||||
path_url_or_repo,
|
||||
convert=convert_to_diffusers,
|
||||
config_file_callback=_pick_configuration_file,
|
||||
commit_to_conf=config_file_path
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
@ -126,7 +127,7 @@ def install_requested_models(
|
||||
while line := input.readline():
|
||||
if not line.startswith(argument):
|
||||
output.writelines([line])
|
||||
output.writelines([f'{argument} {directory}'])
|
||||
output.writelines([f'{argument} "{directory}"'])
|
||||
os.replace(replacement,initfile)
|
||||
|
||||
# -------------------------------------
|
||||
@ -138,6 +139,45 @@ def yes_or_no(prompt: str, default_yes=True):
|
||||
else:
|
||||
return response[0] in ("y", "Y")
|
||||
|
||||
# -------------------------------------
|
||||
def _pick_configuration_file(checkpoint_path: Path)->Path:
|
||||
print(
|
||||
"""
|
||||
Please select the type of this model:
|
||||
[1] A Stable Diffusion v1.x ckpt/safetensors model
|
||||
[2] A Stable Diffusion v1.x inpainting ckpt/safetensors model
|
||||
[3] A Stable Diffusion v2.x base model (512 pixels; no 'parameterization:' in its yaml file)
|
||||
[4] A Stable Diffusion v2.x v-predictive model (768 pixels; look for 'parameterization: "v"' in its yaml file)
|
||||
[5] Other (you will be prompted to enter the config file path)
|
||||
[Q] I have no idea! Skip the import.
|
||||
""")
|
||||
choices = [
|
||||
global_config_dir() / 'stable-diffusion' / x
|
||||
for x in [
|
||||
'v1-inference.yaml',
|
||||
'v1-inpainting-inference.yaml',
|
||||
'v2-inference.yaml',
|
||||
'v2-inference-v.yaml',
|
||||
]
|
||||
]
|
||||
|
||||
ok = False
|
||||
while not ok:
|
||||
try:
|
||||
choice = input('select 0-5, Q > ').strip()
|
||||
if choice.startswith(('q','Q')):
|
||||
return
|
||||
if choice == '5':
|
||||
choice = Path(input('Select config file for this model> ').strip()).absolute()
|
||||
ok = choice.exists()
|
||||
else:
|
||||
choice = choices[int(choice)-1]
|
||||
ok = True
|
||||
except (ValueError, IndexError):
|
||||
print(f'{choice} is not a valid choice')
|
||||
except EOFError:
|
||||
return
|
||||
return choice
|
||||
|
||||
# -------------------------------------
|
||||
def get_root(root: str = None) -> str:
|
||||
@ -262,7 +302,6 @@ def _download_diffusion_weights(
|
||||
path = download_from_hf(
|
||||
model_class,
|
||||
repo_id,
|
||||
cache_subdir="diffusers",
|
||||
safety_checker=None,
|
||||
**extra_args,
|
||||
)
|
||||
|
535
ldm/invoke/dynamic_prompts.py
Executable file
535
ldm/invoke/dynamic_prompts.py
Executable file
@ -0,0 +1,535 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Simple script to generate a file of InvokeAI prompts and settings
|
||||
that scan across steps and other parameters.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import pydoc
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from contextlib import redirect_stderr
|
||||
from io import TextIOBase
|
||||
from itertools import product
|
||||
from multiprocessing import Process
|
||||
from multiprocessing.connection import Connection, Pipe
|
||||
from pathlib import Path
|
||||
from tempfile import gettempdir
|
||||
from typing import Callable, Iterable, List
|
||||
|
||||
import numpy as np
|
||||
import yaml
|
||||
from omegaconf import OmegaConf, dictconfig, listconfig
|
||||
|
||||
|
||||
def expand_prompts(
|
||||
template_file: Path,
|
||||
run_invoke: bool = False,
|
||||
invoke_model: str = None,
|
||||
invoke_outdir: Path = None,
|
||||
processes_per_gpu: int = 1,
|
||||
):
|
||||
"""
|
||||
:param template_file: A YAML file containing templated prompts and args
|
||||
:param run_invoke: A boolean which if True will pass expanded prompts to invokeai CLI
|
||||
:param invoke_model: Name of the model to load when run_invoke is true; otherwise uses default
|
||||
:param invoke_outdir: Directory for outputs when run_invoke is true; otherwise uses default
|
||||
"""
|
||||
if template_file.name.endswith(".json"):
|
||||
with open(template_file, "r") as file:
|
||||
with io.StringIO(yaml.dump(json.load(file))) as fh:
|
||||
conf = OmegaConf.load(fh)
|
||||
else:
|
||||
conf = OmegaConf.load(template_file)
|
||||
|
||||
# loading here to avoid long wait for help message
|
||||
import torch
|
||||
|
||||
torch.multiprocessing.set_start_method("spawn")
|
||||
gpu_count = torch.cuda.device_count() if torch.cuda.is_available() else 1
|
||||
commands = expanded_invokeai_commands(conf, run_invoke)
|
||||
children = list()
|
||||
|
||||
try:
|
||||
if run_invoke:
|
||||
invokeai_args = [shutil.which("invokeai"), "--from_file", "-"]
|
||||
if invoke_model:
|
||||
invokeai_args.extend(("--model", invoke_model))
|
||||
if invoke_outdir:
|
||||
outdir = os.path.expanduser(invoke_outdir)
|
||||
invokeai_args.extend(("--outdir", outdir))
|
||||
else:
|
||||
outdir = gettempdir()
|
||||
logdir = Path(outdir, "invokeai-batch-logs")
|
||||
|
||||
processes_to_launch = gpu_count * processes_per_gpu
|
||||
print(
|
||||
f">> Spawning {processes_to_launch} invokeai processes across {gpu_count} CUDA gpus",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(
|
||||
f'>> Outputs will be written into {invoke_outdir or "default InvokeAI outputs directory"}, and error logs will be written to {logdir}',
|
||||
file=sys.stderr,
|
||||
)
|
||||
import ldm.invoke.CLI
|
||||
|
||||
parent_conn, child_conn = Pipe()
|
||||
children = set()
|
||||
for i in range(processes_to_launch):
|
||||
p = Process(
|
||||
target=_run_invoke,
|
||||
kwargs=dict(
|
||||
entry_point=ldm.invoke.CLI.main,
|
||||
conn_in=child_conn,
|
||||
conn_out=parent_conn,
|
||||
args=invokeai_args,
|
||||
gpu=i % gpu_count,
|
||||
logdir=logdir,
|
||||
),
|
||||
)
|
||||
p.start()
|
||||
children.add(p)
|
||||
child_conn.close()
|
||||
sequence = 0
|
||||
for command in commands:
|
||||
sequence += 1
|
||||
parent_conn.send(
|
||||
command + f' --fnformat="dp.{sequence:04}.{{prompt}}.png"'
|
||||
)
|
||||
parent_conn.close()
|
||||
else:
|
||||
for command in commands:
|
||||
print(command)
|
||||
except KeyboardInterrupt:
|
||||
for p in children:
|
||||
p.terminate()
|
||||
|
||||
|
||||
class MessageToStdin(object):
|
||||
def __init__(self, connection: Connection):
|
||||
self.connection = connection
|
||||
self.linebuffer = list()
|
||||
|
||||
def readline(self) -> str:
|
||||
try:
|
||||
if len(self.linebuffer) == 0:
|
||||
message = self.connection.recv()
|
||||
self.linebuffer = message.split("\n")
|
||||
result = self.linebuffer.pop(0)
|
||||
return result
|
||||
except EOFError:
|
||||
return None
|
||||
|
||||
|
||||
class FilterStream(object):
|
||||
def __init__(
|
||||
self, stream: TextIOBase, include: re.Pattern = None, exclude: re.Pattern = None
|
||||
):
|
||||
self.stream = stream
|
||||
self.include = include
|
||||
self.exclude = exclude
|
||||
|
||||
def write(self, data: str):
|
||||
if self.include and self.include.match(data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
elif self.exclude and not self.exclude.match(data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
|
||||
def flush(self):
|
||||
self.stream.flush()
|
||||
|
||||
|
||||
def _run_invoke(
|
||||
entry_point: Callable,
|
||||
conn_in: Connection,
|
||||
conn_out: Connection,
|
||||
args: List[str],
|
||||
logdir: Path,
|
||||
gpu: int = 0,
|
||||
):
|
||||
pid = os.getpid()
|
||||
logdir.mkdir(parents=True, exist_ok=True)
|
||||
logfile = Path(logdir, f'{time.strftime("%Y-%m-%d_%H-%M-%S")}-pid={pid}.txt')
|
||||
print(
|
||||
f">> Process {pid} running on GPU {gpu}; logging to {logfile}", file=sys.stderr
|
||||
)
|
||||
conn_out.close()
|
||||
os.environ["CUDA_VISIBLE_DEVICES"] = f"{gpu}"
|
||||
sys.argv = args
|
||||
sys.stdin = MessageToStdin(conn_in)
|
||||
sys.stdout = FilterStream(sys.stdout, include=re.compile("^\[\d+\]"))
|
||||
with open(logfile, "w") as stderr, redirect_stderr(stderr):
|
||||
entry_point()
|
||||
|
||||
|
||||
def _filter_output(stream: TextIOBase):
|
||||
while line := stream.readline():
|
||||
if re.match("^\[\d+\]", line):
|
||||
print(line)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=HELP,
|
||||
)
|
||||
parser.add_argument(
|
||||
"template_file",
|
||||
type=Path,
|
||||
nargs="?",
|
||||
help="path to a template file, use --example to generate an example file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--example",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=f'Print an example template file in YAML format. Use "{sys.argv[0]} --example > example.yaml" to save output to a file',
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json-example",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=f'Print an example template file in json format. Use "{sys.argv[0]} --json-example > example.json" to save output to a file',
|
||||
)
|
||||
parser.add_argument(
|
||||
"--instructions",
|
||||
"-i",
|
||||
dest="instructions",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Print verbose instructions.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--invoke",
|
||||
action="store_true",
|
||||
help="Execute invokeai using specified optional --model, --processes_per_gpu and --outdir",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--model",
|
||||
help="Feed the generated prompts to the invokeai CLI using the indicated model. Will be overriden by a model: section in template file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--outdir", type=Path, help="Write images and log into indicated directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--processes_per_gpu",
|
||||
type=int,
|
||||
default=1,
|
||||
help="When executing invokeai, how many parallel processes to execute per CUDA GPU.",
|
||||
)
|
||||
opt = parser.parse_args()
|
||||
|
||||
if opt.example:
|
||||
print(EXAMPLE_TEMPLATE_FILE)
|
||||
sys.exit(0)
|
||||
|
||||
if opt.json_example:
|
||||
print(_yaml_to_json(EXAMPLE_TEMPLATE_FILE))
|
||||
sys.exit(0)
|
||||
|
||||
if opt.instructions:
|
||||
pydoc.pager(INSTRUCTIONS)
|
||||
sys.exit(0)
|
||||
|
||||
if not opt.template_file:
|
||||
parser.print_help()
|
||||
sys.exit(-1)
|
||||
|
||||
expand_prompts(
|
||||
template_file=opt.template_file,
|
||||
run_invoke=opt.invoke,
|
||||
invoke_model=opt.model,
|
||||
invoke_outdir=opt.outdir,
|
||||
processes_per_gpu=opt.processes_per_gpu,
|
||||
)
|
||||
|
||||
|
||||
def expanded_invokeai_commands(
|
||||
conf: OmegaConf, always_switch_models: bool = False
|
||||
) -> List[List[str]]:
|
||||
models = expand_values(conf.get("model"))
|
||||
steps = expand_values(conf.get("steps")) or [30]
|
||||
cfgs = expand_values(conf.get("cfg")) or [7.5]
|
||||
samplers = expand_values(conf.get("sampler")) or ["ddim"]
|
||||
seeds = expand_values(conf.get("seed")) or [0]
|
||||
dimensions = expand_values(conf.get("dimensions")) or ["512x512"]
|
||||
init_img = expand_values(conf.get("init_img")) or [""]
|
||||
perlin = expand_values(conf.get("perlin")) or [0]
|
||||
threshold = expand_values(conf.get("threshold")) or [0]
|
||||
strength = expand_values(conf.get("strength")) or [0.75]
|
||||
prompts = expand_prompt(conf.get("prompt")) or ["banana sushi"]
|
||||
|
||||
cross_product = product(
|
||||
*[
|
||||
models,
|
||||
seeds,
|
||||
prompts,
|
||||
samplers,
|
||||
cfgs,
|
||||
steps,
|
||||
perlin,
|
||||
threshold,
|
||||
init_img,
|
||||
strength,
|
||||
dimensions,
|
||||
]
|
||||
)
|
||||
previous_model = None
|
||||
|
||||
result = list()
|
||||
for p in cross_product:
|
||||
(
|
||||
model,
|
||||
seed,
|
||||
prompt,
|
||||
sampler,
|
||||
cfg,
|
||||
step,
|
||||
perlin,
|
||||
threshold,
|
||||
init_img,
|
||||
strength,
|
||||
dimensions,
|
||||
) = tuple(p)
|
||||
(width, height) = dimensions.split("x")
|
||||
switch_args = (
|
||||
f"!switch {model}\n"
|
||||
if always_switch_models or previous_model != model
|
||||
else ""
|
||||
)
|
||||
image_args = f"-I{init_img} -f{strength}" if init_img else ""
|
||||
command = f"{switch_args}{prompt} -S{seed} -A{sampler} -C{cfg} -s{step} {image_args} --perlin={perlin} --threshold={threshold} -W{width} -H{height}"
|
||||
result.append(command)
|
||||
previous_model = model
|
||||
return result
|
||||
|
||||
|
||||
def expand_prompt(
|
||||
stanza: str | dict | listconfig.ListConfig | dictconfig.DictConfig,
|
||||
) -> list | range:
|
||||
if not stanza:
|
||||
return None
|
||||
if isinstance(stanza, listconfig.ListConfig):
|
||||
return stanza
|
||||
if isinstance(stanza, str):
|
||||
return [stanza]
|
||||
if not isinstance(stanza, dictconfig.DictConfig):
|
||||
raise ValueError(f"Unrecognized template: {stanza}")
|
||||
|
||||
if not (template := stanza.get("template")):
|
||||
raise KeyError('"prompt" section must contain a "template" definition')
|
||||
|
||||
fragment_labels = re.findall("{([^{}]+?)}", template)
|
||||
if len(fragment_labels) == 0:
|
||||
return [template]
|
||||
fragments = [[{x: y} for y in stanza.get(x)] for x in fragment_labels]
|
||||
dicts = merge(product(*fragments))
|
||||
return [template.format(**x) for x in dicts]
|
||||
|
||||
|
||||
def merge(dicts: Iterable) -> List[dict]:
|
||||
result = list()
|
||||
for x in dicts:
|
||||
to_merge = dict()
|
||||
for item in x:
|
||||
to_merge = to_merge | item
|
||||
result.append(to_merge)
|
||||
return result
|
||||
|
||||
|
||||
def expand_values(stanza: str | dict | listconfig.ListConfig) -> list | range:
|
||||
if not stanza:
|
||||
return None
|
||||
if isinstance(stanza, listconfig.ListConfig):
|
||||
return stanza
|
||||
elif match := re.match("^(-?\d+);(-?\d+)(;(\d+))?", str(stanza)):
|
||||
(start, stop, step) = (
|
||||
int(match.group(1)),
|
||||
int(match.group(2)),
|
||||
int(match.group(4)) or 1,
|
||||
)
|
||||
return range(start, stop + step, step)
|
||||
elif match := re.match("^(-?[\d.]+);(-?[\d.]+)(;([\d.]+))?", str(stanza)):
|
||||
(start, stop, step) = (
|
||||
float(match.group(1)),
|
||||
float(match.group(2)),
|
||||
float(match.group(4)) or 1.0,
|
||||
)
|
||||
return np.arange(start, stop + step, step).tolist()
|
||||
else:
|
||||
return [stanza]
|
||||
|
||||
|
||||
def _yaml_to_json(yaml_input: str) -> str:
|
||||
"""
|
||||
Converts a yaml string into a json string. Used internally
|
||||
to generate the example template file.
|
||||
"""
|
||||
with io.StringIO(yaml_input) as yaml_in:
|
||||
data = yaml.safe_load(yaml_in)
|
||||
return json.dumps(data, indent=2)
|
||||
|
||||
|
||||
HELP = """
|
||||
This script takes a prompt template file that contains multiple
|
||||
alternative values for the prompt and its generation arguments (such
|
||||
as steps). It then expands out the prompts using all combinations of
|
||||
arguments and either prints them to the terminal's standard output, or
|
||||
feeds the prompts directly to the invokeai command-line interface.
|
||||
|
||||
Call this script again with --instructions (-i) for verbose instructions.
|
||||
"""
|
||||
|
||||
INSTRUCTIONS = f"""
|
||||
== INTRODUCTION ==
|
||||
This script takes a prompt template file that contains multiple
|
||||
alternative values for the prompt and its generation arguments (such
|
||||
as steps). It then expands out the prompts using all combinations of
|
||||
arguments and either prints them to the terminal's standard output, or
|
||||
feeds the prompts directly to the invokeai command-line interface.
|
||||
|
||||
If the optional --invoke argument is provided, then the generated
|
||||
prompts will be fed directly to invokeai for image generation. You
|
||||
will likely want to add the --outdir option in order to save the image
|
||||
files to their own folder.
|
||||
|
||||
{sys.argv[0]} --invoke --outdir=/tmp/outputs my_template.yaml
|
||||
|
||||
If --invoke isn't specified, the expanded prompts will be printed to
|
||||
output. You can capture them to a file for inspection and editing this
|
||||
way:
|
||||
|
||||
{sys.argv[0]} my_template.yaml > prompts.txt
|
||||
|
||||
And then feed them to invokeai this way:
|
||||
|
||||
invokeai --outdir=/tmp/outputs < prompts.txt
|
||||
|
||||
Note that after invokeai finishes processing the list of prompts, the
|
||||
output directory will contain a markdown file named `log.md`
|
||||
containing annotated images. You can open this file using an e-book
|
||||
reader such as the cross-platform Calibre eBook reader
|
||||
(https://calibre-ebook.com/).
|
||||
|
||||
== FORMAT OF THE TEMPLATES FILE ==
|
||||
|
||||
This will generate an example template file that you can get
|
||||
started with:
|
||||
|
||||
{sys.argv[0]} --example > example.yaml
|
||||
|
||||
An excerpt from the top of this file looks like this:
|
||||
|
||||
model:
|
||||
- stable-diffusion-1.5
|
||||
- stable-diffusion-2.1-base
|
||||
steps: 30;50;1 # start steps at 30 and go up to 50, incrementing by 1 each time
|
||||
seed: 50 # fixed constant, seed=50
|
||||
cfg: # list of CFG values to try
|
||||
- 7
|
||||
- 8
|
||||
- 12
|
||||
prompt: a walk in the park # constant value
|
||||
|
||||
In more detail, the template file can one or more of the
|
||||
following sections:
|
||||
- model:
|
||||
- steps:
|
||||
- seed:
|
||||
- cfg:
|
||||
- sampler:
|
||||
- prompt:
|
||||
- init_img:
|
||||
- perlin:
|
||||
- threshold:
|
||||
- strength
|
||||
|
||||
- Each section can have a constant value such as this:
|
||||
steps: 50
|
||||
- Or a range of numeric values in the format:
|
||||
steps: <start>;<stop>;<step> (note semicolon, not colon!)
|
||||
- Or a list of values in the format:
|
||||
- value1
|
||||
- value2
|
||||
- value3
|
||||
|
||||
The "prompt:" section is special. It can accept a constant value:
|
||||
|
||||
prompt: a walk in the woods in the style of donatello
|
||||
|
||||
Or it can accept a list of prompts:
|
||||
|
||||
prompt:
|
||||
- a walk in the woods
|
||||
- a walk on the beach
|
||||
|
||||
Or it can accept a templated list of prompts. These allow you to
|
||||
define a series of phrases, each of which is a list. You then combine
|
||||
them together into a prompt template in this way:
|
||||
|
||||
prompt:
|
||||
style:
|
||||
- oil painting
|
||||
- watercolor
|
||||
- comic book
|
||||
- studio photography
|
||||
subject:
|
||||
- sunny meadow in the mountains
|
||||
- gathering storm in the mountains
|
||||
template: a {{subject}} in the style of {{style}}
|
||||
|
||||
In the example above, the phrase names "style" and "subject" are
|
||||
examples only. You can use whatever you like. However, the "template:"
|
||||
field is required. The output will be:
|
||||
|
||||
"a sunny meadow in the mountains in the style of an oil painting"
|
||||
"a sunny meadow in the mountains in the style of watercolor masterpiece"
|
||||
...
|
||||
"a gathering storm in the mountains in the style of an ink sketch"
|
||||
|
||||
== SUPPORT FOR JSON FORMAT ==
|
||||
|
||||
For those who prefer the JSON format, this script will accept JSON
|
||||
template files as well. Please run "{sys.argv[0]} --json-example"
|
||||
to print out a version of the example template file in json format.
|
||||
You may save it to disk and use it as a starting point for your own
|
||||
template this way:
|
||||
|
||||
{sys.argv[0]} --json-example > template.json
|
||||
"""
|
||||
|
||||
EXAMPLE_TEMPLATE_FILE = """
|
||||
model: stable-diffusion-1.5
|
||||
steps: 30;50;10
|
||||
seed: 50
|
||||
dimensions: 512x512
|
||||
perlin: 0.0
|
||||
threshold: 0
|
||||
cfg:
|
||||
- 7
|
||||
- 12
|
||||
sampler:
|
||||
- k_euler_a
|
||||
- k_lms
|
||||
prompt:
|
||||
style:
|
||||
- oil painting
|
||||
- watercolor
|
||||
location:
|
||||
- the mountains
|
||||
- a desert
|
||||
object:
|
||||
- luxurious dwelling
|
||||
- crude tent
|
||||
template: a {object} in {location}, in the style of {style}
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -88,16 +88,13 @@ def global_cache_dir(subdir:Union[str,Path]='')->Path:
|
||||
'''
|
||||
Returns Path to the model cache directory. If a subdirectory
|
||||
is provided, it will be appended to the end of the path, allowing
|
||||
for huggingface-style conventions:
|
||||
global_cache_dir('diffusers')
|
||||
for Hugging Face-style conventions. Currently, Hugging Face has
|
||||
moved all models into the "hub" subfolder, so for any pretrained
|
||||
HF model, use:
|
||||
global_cache_dir('hub')
|
||||
Current HuggingFace documentation (mid-Jan 2023) indicates that
|
||||
transformers models will be cached into a "transformers" subdirectory,
|
||||
but in practice they seem to go into "hub". But if needed:
|
||||
global_cache_dir('transformers')
|
||||
One other caveat is that HuggingFace is moving some diffusers models
|
||||
into the "hub" subdirectory as well, so this will need to be revisited
|
||||
from time to time.
|
||||
|
||||
The legacy location for transformers used to be global_cache_dir('transformers')
|
||||
and global_cache_dir('diffusers') for diffusers.
|
||||
'''
|
||||
home: str = os.getenv('HF_HOME')
|
||||
|
||||
|
@ -437,10 +437,10 @@ def main():
|
||||
args = _parse_args()
|
||||
global_set_root(args.root_dir)
|
||||
|
||||
cache_dir = str(global_cache_dir("diffusers"))
|
||||
cache_dir = str(global_cache_dir("hub"))
|
||||
os.environ[
|
||||
"HF_HOME"
|
||||
] = cache_dir # because not clear the merge pipeline is honoring cache_dir
|
||||
] = str(global_cache_dir()) # because not clear the merge pipeline is honoring cache_dir
|
||||
args.cache_dir = cache_dir
|
||||
|
||||
try:
|
||||
|
@ -19,7 +19,7 @@ import warnings
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from shutil import move, rmtree
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
import safetensors
|
||||
import safetensors.torch
|
||||
@ -35,18 +35,15 @@ from picklescan.scanner import scan_file_path
|
||||
from ldm.invoke.devices import CPU_DEVICE
|
||||
from ldm.invoke.generator.diffusers_pipeline import StableDiffusionGeneratorPipeline
|
||||
from ldm.invoke.globals import Globals, global_cache_dir
|
||||
from ldm.util import (
|
||||
ask_user,
|
||||
download_with_resume,
|
||||
instantiate_from_config,
|
||||
url_attachment_name,
|
||||
)
|
||||
from ldm.util import ask_user, download_with_resume, instantiate_from_config, url_attachment_name
|
||||
|
||||
|
||||
class SDLegacyType(Enum):
|
||||
V1 = 1
|
||||
V1_INPAINT = 2
|
||||
V2 = 3
|
||||
V2_e = 4
|
||||
V2_v = 5
|
||||
UNKNOWN = 99
|
||||
|
||||
|
||||
@ -175,9 +172,9 @@ class ModelManager(object):
|
||||
"""
|
||||
# if we are converting legacy files automatically, then
|
||||
# there are no legacy ckpts!
|
||||
if Globals.ckpt_convert:
|
||||
return False
|
||||
info = self.model_info(model_name)
|
||||
if Globals.ckpt_convert or info.format=='diffusers' or self.is_v2_config(info.config):
|
||||
return False
|
||||
if "weights" in info and info["weights"].endswith((".ckpt", ".safetensors")):
|
||||
return True
|
||||
return False
|
||||
@ -280,13 +277,13 @@ class ModelManager(object):
|
||||
self.stack.remove(model_name)
|
||||
if delete_files:
|
||||
if weights:
|
||||
print(f"** deleting file {weights}")
|
||||
print(f"** Deleting file {weights}")
|
||||
Path(weights).unlink(missing_ok=True)
|
||||
elif path:
|
||||
print(f"** deleting directory {path}")
|
||||
print(f"** Deleting directory {path}")
|
||||
rmtree(path, ignore_errors=True)
|
||||
elif repo_id:
|
||||
print(f"** deleting the cached model directory for {repo_id}")
|
||||
print(f"** Deleting the cached model directory for {repo_id}")
|
||||
self._delete_model_from_cache(repo_id)
|
||||
|
||||
def add_model(
|
||||
@ -382,15 +379,16 @@ class ModelManager(object):
|
||||
if not os.path.isabs(weights):
|
||||
weights = os.path.normpath(os.path.join(Globals.root, weights))
|
||||
|
||||
# check whether this is a v2 file and force conversion
|
||||
convert = Globals.ckpt_convert or self.is_v2_config(config)
|
||||
|
||||
# if converting automatically to diffusers, then we do the conversion and return
|
||||
# a diffusers pipeline
|
||||
if Globals.ckpt_convert:
|
||||
if convert:
|
||||
print(
|
||||
f">> Converting legacy checkpoint {model_name} into a diffusers model..."
|
||||
)
|
||||
from ldm.invoke.ckpt_to_diffuser import (
|
||||
load_pipeline_from_original_stable_diffusion_ckpt,
|
||||
)
|
||||
from ldm.invoke.ckpt_to_diffuser import load_pipeline_from_original_stable_diffusion_ckpt
|
||||
|
||||
self.offload_model(self.current_model)
|
||||
if vae_config := self._choose_diffusers_vae(model_name):
|
||||
@ -418,11 +416,6 @@ class ModelManager(object):
|
||||
"NOHASH",
|
||||
)
|
||||
|
||||
# scan model
|
||||
self.scan_model(model_name, weights)
|
||||
|
||||
print(f">> Loading {model_name} from {weights}")
|
||||
|
||||
# for usage statistics
|
||||
if self._has_cuda():
|
||||
torch.cuda.reset_peak_memory_stats()
|
||||
@ -436,10 +429,13 @@ class ModelManager(object):
|
||||
weight_bytes = f.read()
|
||||
model_hash = self._cached_sha256(weights, weight_bytes)
|
||||
sd = None
|
||||
if weights.endswith(".safetensors"):
|
||||
sd = safetensors.torch.load(weight_bytes)
|
||||
else:
|
||||
|
||||
if weights.endswith(".ckpt"):
|
||||
self.scan_model(model_name, weights)
|
||||
sd = torch.load(io.BytesIO(weight_bytes), map_location="cpu")
|
||||
else:
|
||||
sd = safetensors.torch.load(weight_bytes)
|
||||
|
||||
del weight_bytes
|
||||
# merged models from auto11 merge board are flat for some reason
|
||||
if "state_dict" in sd:
|
||||
@ -462,18 +458,12 @@ class ModelManager(object):
|
||||
vae = os.path.normpath(os.path.join(Globals.root, vae))
|
||||
if os.path.exists(vae):
|
||||
print(f" | Loading VAE weights from: {vae}")
|
||||
vae_ckpt = None
|
||||
vae_dict = None
|
||||
if vae.endswith(".safetensors"):
|
||||
vae_ckpt = safetensors.torch.load_file(vae)
|
||||
vae_dict = {k: v for k, v in vae_ckpt.items() if k[0:4] != "loss"}
|
||||
else:
|
||||
if vae.endswith((".ckpt", ".pt")):
|
||||
self.scan_model(vae, vae)
|
||||
vae_ckpt = torch.load(vae, map_location="cpu")
|
||||
vae_dict = {
|
||||
k: v
|
||||
for k, v in vae_ckpt["state_dict"].items()
|
||||
if k[0:4] != "loss"
|
||||
}
|
||||
else:
|
||||
vae_ckpt = safetensors.torch.load_file(vae)
|
||||
vae_dict = {k: v for k, v in vae_ckpt.items() if k[0:4] != "loss"}
|
||||
model.first_stage_model.load_state_dict(vae_dict, strict=False)
|
||||
else:
|
||||
print(f" | VAE file {vae} not found. Skipping.")
|
||||
@ -495,9 +485,9 @@ class ModelManager(object):
|
||||
|
||||
print(f">> Loading diffusers model from {name_or_path}")
|
||||
if using_fp16:
|
||||
print(" | Using faster float16 precision")
|
||||
print(" | Using faster float16 precision")
|
||||
else:
|
||||
print(" | Using more accurate float32 precision")
|
||||
print(" | Using more accurate float32 precision")
|
||||
|
||||
# TODO: scan weights maybe?
|
||||
pipeline_args: dict[str, Any] = dict(
|
||||
@ -507,7 +497,7 @@ class ModelManager(object):
|
||||
if vae := self._load_vae(mconfig["vae"]):
|
||||
pipeline_args.update(vae=vae)
|
||||
if not isinstance(name_or_path, Path):
|
||||
pipeline_args.update(cache_dir=global_cache_dir("diffusers"))
|
||||
pipeline_args.update(cache_dir=global_cache_dir("hub"))
|
||||
if using_fp16:
|
||||
pipeline_args.update(torch_dtype=torch.float16)
|
||||
fp_args_list = [{"revision": "fp16"}, {}]
|
||||
@ -549,10 +539,21 @@ class ModelManager(object):
|
||||
width = pipeline.unet.config.sample_size * pipeline.vae_scale_factor
|
||||
height = width
|
||||
|
||||
print(f" | Default image dimensions = {width} x {height}")
|
||||
print(f" | Default image dimensions = {width} x {height}")
|
||||
|
||||
return pipeline, width, height, model_hash
|
||||
|
||||
def is_v2_config(self, config: Path) -> bool:
|
||||
if not os.path.isabs(config):
|
||||
config = os.path.join(Globals.root, config)
|
||||
try:
|
||||
mconfig = OmegaConf.load(config)
|
||||
return (
|
||||
mconfig["model"]["params"]["unet_config"]["params"]["context_dim"] > 768
|
||||
)
|
||||
except:
|
||||
return False
|
||||
|
||||
def model_name_or_path(self, model_name: Union[str, DictConfig]) -> str | Path:
|
||||
if isinstance(model_name, DictConfig) or isinstance(model_name, dict):
|
||||
mconfig = model_name
|
||||
@ -589,13 +590,14 @@ class ModelManager(object):
|
||||
if self._has_cuda():
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
@classmethod
|
||||
def scan_model(self, model_name, checkpoint):
|
||||
"""
|
||||
Apply picklescanner to the indicated checkpoint and issue a warning
|
||||
and option to exit if an infected file is identified.
|
||||
"""
|
||||
# scan model
|
||||
print(f">> Scanning Model: {model_name}")
|
||||
print(f" | Scanning Model: {model_name}")
|
||||
scan_result = scan_file_path(checkpoint)
|
||||
if scan_result.infected_files != 0:
|
||||
if scan_result.infected_files == 1:
|
||||
@ -618,13 +620,13 @@ class ModelManager(object):
|
||||
print("### Exiting InvokeAI")
|
||||
sys.exit()
|
||||
else:
|
||||
print(">> Model scanned ok")
|
||||
print(" | Model scanned ok")
|
||||
|
||||
def import_diffuser_model(
|
||||
self,
|
||||
repo_or_path: Union[str, Path],
|
||||
model_name: str = None,
|
||||
model_description: str = None,
|
||||
description: str = None,
|
||||
vae: dict = None,
|
||||
commit_to_conf: Path = None,
|
||||
) -> bool:
|
||||
@ -640,7 +642,7 @@ class ModelManager(object):
|
||||
models.yaml file.
|
||||
"""
|
||||
model_name = model_name or Path(repo_or_path).stem
|
||||
model_description = model_description or f"Imported diffusers model {model_name}"
|
||||
model_description = description or f"Imported diffusers model {model_name}"
|
||||
new_config = dict(
|
||||
description=model_description,
|
||||
vae=vae,
|
||||
@ -724,15 +726,25 @@ class ModelManager(object):
|
||||
format. Valid return values include:
|
||||
SDLegacyType.V1
|
||||
SDLegacyType.V1_INPAINT
|
||||
SDLegacyType.V2
|
||||
SDLegacyType.V2 (V2 prediction type unknown)
|
||||
SDLegacyType.V2_e (V2 using 'epsilon' prediction type)
|
||||
SDLegacyType.V2_v (V2 using 'v_prediction' prediction type)
|
||||
SDLegacyType.UNKNOWN
|
||||
"""
|
||||
key_name = "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_k.weight"
|
||||
if key_name in checkpoint and checkpoint[key_name].shape[-1] == 1024:
|
||||
return SDLegacyType.V2
|
||||
global_step = checkpoint.get("global_step")
|
||||
state_dict = checkpoint.get("state_dict") or checkpoint
|
||||
|
||||
try:
|
||||
state_dict = checkpoint.get("state_dict") or checkpoint
|
||||
key_name = "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_k.weight"
|
||||
if key_name in state_dict and state_dict[key_name].shape[-1] == 1024:
|
||||
if global_step == 220000:
|
||||
return SDLegacyType.V2_e
|
||||
elif global_step == 110000:
|
||||
return SDLegacyType.V2_v
|
||||
else:
|
||||
return SDLegacyType.V2
|
||||
# otherwise we assume a V1 file
|
||||
in_channels = state_dict[
|
||||
"model.diffusion_model.input_blocks.0.0.weight"
|
||||
].shape[1]
|
||||
@ -751,7 +763,9 @@ class ModelManager(object):
|
||||
convert: bool = False,
|
||||
model_name: str = None,
|
||||
description: str = None,
|
||||
model_config_file: Path = None,
|
||||
commit_to_conf: Path = None,
|
||||
config_file_callback: Callable[[Path], Path] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Accept a string which could be:
|
||||
@ -781,23 +795,25 @@ class ModelManager(object):
|
||||
"""
|
||||
model_path: Path = None
|
||||
thing = path_url_or_repo # to save typing
|
||||
is_temporary = False
|
||||
|
||||
print(f">> Probing {thing} for import")
|
||||
|
||||
if thing.startswith(("http:", "https:", "ftp:")):
|
||||
print(f" | {thing} appears to be a URL")
|
||||
print(f" | {thing} appears to be a URL")
|
||||
model_path = self._resolve_path(
|
||||
thing, "models/ldm/stable-diffusion-v1"
|
||||
) # _resolve_path does a download if needed
|
||||
is_temporary = True
|
||||
|
||||
elif Path(thing).is_file() and thing.endswith((".ckpt", ".safetensors")):
|
||||
if Path(thing).stem in ["model", "diffusion_pytorch_model"]:
|
||||
print(
|
||||
f" | {Path(thing).name} appears to be part of a diffusers model. Skipping import"
|
||||
f" | {Path(thing).name} appears to be part of a diffusers model. Skipping import"
|
||||
)
|
||||
return
|
||||
else:
|
||||
print(f" | {thing} appears to be a checkpoint file on disk")
|
||||
print(f" | {thing} appears to be a checkpoint file on disk")
|
||||
model_path = self._resolve_path(thing, "models/ldm/stable-diffusion-v1")
|
||||
|
||||
elif Path(thing).is_dir() and Path(thing, "model_index.json").exists():
|
||||
@ -824,7 +840,10 @@ class ModelManager(object):
|
||||
Path(thing).rglob("*.safetensors")
|
||||
):
|
||||
if model_name := self.heuristic_import(
|
||||
str(m), convert, commit_to_conf=commit_to_conf
|
||||
str(m),
|
||||
convert,
|
||||
commit_to_conf=commit_to_conf,
|
||||
config_file_callback=config_file_callback,
|
||||
):
|
||||
print(f" >> {model_name} successfully imported")
|
||||
return model_name
|
||||
@ -848,40 +867,70 @@ class ModelManager(object):
|
||||
|
||||
if model_path.stem in self.config: # already imported
|
||||
print(" | Already imported. Skipping")
|
||||
return
|
||||
return model_path.stem
|
||||
|
||||
# another round of heuristics to guess the correct config file.
|
||||
checkpoint = (
|
||||
safetensors.torch.load_file(model_path)
|
||||
if model_path.suffix == ".safetensors"
|
||||
else torch.load(model_path)
|
||||
)
|
||||
model_type = self.probe_model_type(checkpoint)
|
||||
|
||||
model_config_file = None
|
||||
if model_type == SDLegacyType.V1:
|
||||
print(" | SD-v1 model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v1-inference.yaml"
|
||||
)
|
||||
elif model_type == SDLegacyType.V1_INPAINT:
|
||||
print(" | SD-v1 inpainting model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v1-inpainting-inference.yaml"
|
||||
)
|
||||
elif model_type == SDLegacyType.V2:
|
||||
print(
|
||||
" | SD-v2 model detected; model will be converted to diffusers format"
|
||||
)
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v2-inference-v.yaml"
|
||||
)
|
||||
convert = True
|
||||
checkpoint = None
|
||||
if model_path.suffix.endswith((".ckpt", ".pt")):
|
||||
self.scan_model(model_path, model_path)
|
||||
checkpoint = torch.load(model_path)
|
||||
else:
|
||||
print(
|
||||
f"** {thing} is a legacy checkpoint file but not in a known Stable Diffusion model. Skipping import"
|
||||
)
|
||||
return
|
||||
checkpoint = safetensors.torch.load_file(model_path)
|
||||
# additional probing needed if no config file provided
|
||||
if model_config_file is None:
|
||||
# Is there a like-named .yaml file in the same directory as the
|
||||
# weights file? If so, we treat this as our model
|
||||
if model_path.with_suffix(".yaml").exists():
|
||||
model_config_file = model_path.with_suffix(".yaml")
|
||||
print(f" | Using config file {model_config_file.name}")
|
||||
else:
|
||||
model_type = self.probe_model_type(checkpoint)
|
||||
if model_type == SDLegacyType.V1:
|
||||
print(" | SD-v1 model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v1-inference.yaml"
|
||||
)
|
||||
elif model_type == SDLegacyType.V1_INPAINT:
|
||||
print(" | SD-v1 inpainting model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root,
|
||||
"configs/stable-diffusion/v1-inpainting-inference.yaml",
|
||||
)
|
||||
elif model_type == SDLegacyType.V2_v:
|
||||
print(" | SD-v2-v model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v2-inference-v.yaml"
|
||||
)
|
||||
elif model_type == SDLegacyType.V2_e:
|
||||
print(" | SD-v2-e model detected")
|
||||
model_config_file = Path(
|
||||
Globals.root, "configs/stable-diffusion/v2-inference.yaml"
|
||||
)
|
||||
elif model_type == SDLegacyType.V2:
|
||||
print(
|
||||
f"** {thing} is a V2 checkpoint file, but its parameterization cannot be determined. Please provide configuration file path."
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"** {thing} is a legacy checkpoint file but not a known Stable Diffusion model. Please provide configuration file path."
|
||||
)
|
||||
|
||||
if not model_config_file and config_file_callback:
|
||||
model_config_file = config_file_callback(model_path)
|
||||
if not model_config_file:
|
||||
return
|
||||
|
||||
if self.is_v2_config(model_config_file):
|
||||
convert = True
|
||||
print(" | This SD-v2 model will be converted to diffusers format for use")
|
||||
|
||||
# look for a custom vae
|
||||
vae_path = None
|
||||
for suffix in ["pt", "ckpt", "safetensors"]:
|
||||
if (model_path.with_suffix(f".vae.{suffix}")).exists():
|
||||
vae_path = model_path.with_suffix(f".vae.{suffix}")
|
||||
print(f" | Using VAE file {vae_path.name}")
|
||||
vae = None if vae_path else dict(repo_id="stabilityai/sd-vae-ft-mse")
|
||||
|
||||
if convert:
|
||||
diffuser_path = Path(
|
||||
@ -890,12 +939,18 @@ class ModelManager(object):
|
||||
model_name = self.convert_and_import(
|
||||
model_path,
|
||||
diffusers_path=diffuser_path,
|
||||
vae=dict(repo_id="stabilityai/sd-vae-ft-mse"),
|
||||
vae=vae,
|
||||
vae_path=vae_path,
|
||||
model_name=model_name,
|
||||
model_description=description,
|
||||
original_config_file=model_config_file,
|
||||
commit_to_conf=commit_to_conf,
|
||||
scan_needed=False,
|
||||
)
|
||||
# in the event that this file was downloaded automatically prior to conversion
|
||||
# we do not keep the original .ckpt/.safetensors around
|
||||
if is_temporary:
|
||||
model_path.unlink(missing_ok=True)
|
||||
else:
|
||||
model_name = self.import_ckpt_model(
|
||||
model_path,
|
||||
@ -903,7 +958,8 @@ class ModelManager(object):
|
||||
model_name=model_name,
|
||||
model_description=description,
|
||||
vae=str(
|
||||
Path(
|
||||
vae_path
|
||||
or Path(
|
||||
Globals.root,
|
||||
"models/ldm/stable-diffusion-v1/vae-ft-mse-840000-ema-pruned.ckpt",
|
||||
)
|
||||
@ -920,9 +976,11 @@ class ModelManager(object):
|
||||
diffusers_path: Path,
|
||||
model_name=None,
|
||||
model_description=None,
|
||||
vae=None,
|
||||
vae: dict = None,
|
||||
vae_path: Path = None,
|
||||
original_config_file: Path = None,
|
||||
commit_to_conf: Path = None,
|
||||
scan_needed: bool = True,
|
||||
) -> str:
|
||||
"""
|
||||
Convert a legacy ckpt weights file to diffuser model and import
|
||||
@ -936,7 +994,7 @@ class ModelManager(object):
|
||||
|
||||
new_config = None
|
||||
|
||||
from ldm.invoke.ckpt_to_diffuser import convert_ckpt_to_diffuser
|
||||
from ldm.invoke.ckpt_to_diffuser import convert_ckpt_to_diffusers
|
||||
|
||||
if diffusers_path.exists():
|
||||
print(
|
||||
@ -951,17 +1009,19 @@ class ModelManager(object):
|
||||
# By passing the specified VAE to the conversion function, the autoencoder
|
||||
# will be built into the model rather than tacked on afterward via the config file
|
||||
vae_model = self._load_vae(vae) if vae else None
|
||||
convert_ckpt_to_diffuser(
|
||||
convert_ckpt_to_diffusers(
|
||||
ckpt_path,
|
||||
diffusers_path,
|
||||
extract_ema=True,
|
||||
original_config_file=original_config_file,
|
||||
vae=vae_model,
|
||||
vae_path=str(vae_path) if vae_path else None,
|
||||
scan_needed=scan_needed,
|
||||
)
|
||||
print(
|
||||
f" | Success. Optimized model is now located at {str(diffusers_path)}"
|
||||
f" | Success. Optimized model is now located at {str(diffusers_path)}"
|
||||
)
|
||||
print(f" | Writing new config file entry for {model_name}")
|
||||
print(f" | Writing new config file entry for {model_name}")
|
||||
new_config = dict(
|
||||
path=str(diffusers_path),
|
||||
description=model_description,
|
||||
@ -1008,7 +1068,7 @@ class ModelManager(object):
|
||||
# In the event that the original entry is using a custom ckpt VAE, we try to
|
||||
# map that VAE onto a diffuser VAE using a hard-coded dictionary.
|
||||
# I would prefer to do this differently: We load the ckpt model into memory, swap the
|
||||
# VAE in memory, and then pass that to convert_ckpt_to_diffuser() so that the swapped
|
||||
# VAE in memory, and then pass that to convert_ckpt_to_diffusers() so that the swapped
|
||||
# VAE is built into the model. However, when I tried this I got obscure key errors.
|
||||
if vae:
|
||||
return vae
|
||||
@ -1088,27 +1148,39 @@ class ModelManager(object):
|
||||
to the 2.3.0 "diffusers" version. This should be a one-time operation, called at
|
||||
script startup time.
|
||||
"""
|
||||
# Three transformer models to check: bert, clip and safety checker
|
||||
# Three transformer models to check: bert, clip and safety checker, and
|
||||
# the diffusers as well
|
||||
models_dir = Path(Globals.root, "models")
|
||||
legacy_locations = [
|
||||
Path(
|
||||
"CompVis/stable-diffusion-safety-checker/models--CompVis--stable-diffusion-safety-checker"
|
||||
models_dir,
|
||||
"CompVis/stable-diffusion-safety-checker/models--CompVis--stable-diffusion-safety-checker",
|
||||
),
|
||||
Path("bert-base-uncased/models--bert-base-uncased"),
|
||||
Path(
|
||||
"openai/clip-vit-large-patch14/models--openai--clip-vit-large-patch14"
|
||||
),
|
||||
]
|
||||
models_dir = Path(Globals.root, "models")
|
||||
legacy_locations.extend(list(global_cache_dir("diffusers").glob("*")))
|
||||
legacy_layout = False
|
||||
for model in legacy_locations:
|
||||
legacy_layout = legacy_layout or Path(models_dir, model).exists()
|
||||
legacy_layout = legacy_layout or model.exists()
|
||||
if not legacy_layout:
|
||||
return
|
||||
|
||||
print(
|
||||
"** Legacy version <= 2.2.5 model directory layout detected. Reorganizing."
|
||||
"""
|
||||
>> ALERT:
|
||||
>> The location of your previously-installed diffusers models needs to move from
|
||||
>> invokeai/models/diffusers to invokeai/models/hub due to a change introduced by
|
||||
>> diffusers version 0.14. InvokeAI will now move all models from the "diffusers" directory
|
||||
>> into "hub" and then remove the diffusers directory. This is a quick, safe, one-time
|
||||
>> operation. However if you have customized either of these directories and need to
|
||||
>> make adjustments, please press ctrl-C now to abort and relaunch InvokeAI when you are ready.
|
||||
>> Otherwise press <enter> to continue."""
|
||||
)
|
||||
print("** This is a quick one-time operation.")
|
||||
input("continue> ")
|
||||
|
||||
# transformer files get moved into the hub directory
|
||||
if cls._is_huggingface_hub_directory_present():
|
||||
@ -1120,33 +1192,20 @@ class ModelManager(object):
|
||||
for model in legacy_locations:
|
||||
source = models_dir / model
|
||||
dest = hub / model.stem
|
||||
if dest.exists() and not source.exists():
|
||||
continue
|
||||
print(f"** {source} => {dest}")
|
||||
if source.exists():
|
||||
if dest.exists():
|
||||
rmtree(source)
|
||||
if dest.is_symlink():
|
||||
print(f"** Found symlink at {dest.name}. Not migrating.")
|
||||
elif dest.exists():
|
||||
if source.is_dir():
|
||||
rmtree(source)
|
||||
else:
|
||||
source.unlink()
|
||||
else:
|
||||
move(source, dest)
|
||||
|
||||
# anything else gets moved into the diffusers directory
|
||||
if cls._is_huggingface_hub_directory_present():
|
||||
diffusers = global_cache_dir("diffusers")
|
||||
else:
|
||||
diffusers = models_dir / "diffusers"
|
||||
|
||||
os.makedirs(diffusers, exist_ok=True)
|
||||
for root, dirs, _ in os.walk(models_dir, topdown=False):
|
||||
for dir in dirs:
|
||||
full_path = Path(root, dir)
|
||||
if full_path.is_relative_to(hub) or full_path.is_relative_to(diffusers):
|
||||
continue
|
||||
if Path(dir).match("models--*--*"):
|
||||
dest = diffusers / dir
|
||||
print(f"** {full_path} => {dest}")
|
||||
if dest.exists():
|
||||
rmtree(full_path)
|
||||
else:
|
||||
move(full_path, dest)
|
||||
|
||||
# now clean up by removing any empty directories
|
||||
empty = [
|
||||
root
|
||||
@ -1244,7 +1303,7 @@ class ModelManager(object):
|
||||
path = name_or_path
|
||||
else:
|
||||
owner, repo = name_or_path.split("/")
|
||||
path = Path(global_cache_dir("diffusers") / f"models--{owner}--{repo}")
|
||||
path = Path(global_cache_dir("hub") / f"models--{owner}--{repo}")
|
||||
if not path.exists():
|
||||
return None
|
||||
hashpath = path / "checksum.sha256"
|
||||
@ -1252,7 +1311,7 @@ class ModelManager(object):
|
||||
with open(hashpath) as f:
|
||||
hash = f.read()
|
||||
return hash
|
||||
print(" | Calculating sha256 hash of model files")
|
||||
print(" | Calculating sha256 hash of model files")
|
||||
tic = time.time()
|
||||
sha = hashlib.sha256()
|
||||
count = 0
|
||||
@ -1264,7 +1323,7 @@ class ModelManager(object):
|
||||
sha.update(chunk)
|
||||
hash = sha.hexdigest()
|
||||
toc = time.time()
|
||||
print(f" | sha256 = {hash} ({count} files hashed in", "%4.2fs)" % (toc - tic))
|
||||
print(f" | sha256 = {hash} ({count} files hashed in", "%4.2fs)" % (toc - tic))
|
||||
with open(hashpath, "w") as f:
|
||||
f.write(hash)
|
||||
return hash
|
||||
@ -1305,16 +1364,16 @@ class ModelManager(object):
|
||||
using_fp16 = self.precision == "float16"
|
||||
|
||||
vae_args.update(
|
||||
cache_dir=global_cache_dir("diffusers"),
|
||||
cache_dir=global_cache_dir("hug"),
|
||||
local_files_only=not Globals.internet_available,
|
||||
)
|
||||
|
||||
print(f" | Loading diffusers VAE from {name_or_path}")
|
||||
print(f" | Loading diffusers VAE from {name_or_path}")
|
||||
if using_fp16:
|
||||
vae_args.update(torch_dtype=torch.float16)
|
||||
fp_args_list = [{"revision": "fp16"}, {}]
|
||||
else:
|
||||
print(" | Using more accurate float32 precision")
|
||||
print(" | Using more accurate float32 precision")
|
||||
fp_args_list = [{}]
|
||||
|
||||
vae = None
|
||||
@ -1355,7 +1414,7 @@ class ModelManager(object):
|
||||
hashes_to_delete.add(revision.commit_hash)
|
||||
strategy = cache_info.delete_revisions(*hashes_to_delete)
|
||||
print(
|
||||
f"** deletion of this model is expected to free {strategy.expected_freed_size_str}"
|
||||
f"** Deletion of this model is expected to free {strategy.expected_freed_size_str}"
|
||||
)
|
||||
strategy.execute()
|
||||
|
||||
|
@ -9,6 +9,8 @@ Exports function retrieve_metadata(path)
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
from filelock import FileLock
|
||||
from PIL import PngImagePlugin, Image
|
||||
|
||||
# -------------------image generation utils-----
|
||||
@ -19,8 +21,26 @@ class PngWriter:
|
||||
self.outdir = outdir
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
|
||||
def unique_prefix(self)->str:
|
||||
next_prefix_file = Path(self.outdir,'.next_prefix')
|
||||
next_prefix_lock = Path(self.outdir,'.next_prefix.lock')
|
||||
prefix = 0
|
||||
with FileLock(next_prefix_lock):
|
||||
if not next_prefix_file.exists():
|
||||
prefix = self._unused_prefix()
|
||||
else:
|
||||
with open(next_prefix_file,'r') as file:
|
||||
prefix = 0
|
||||
try:
|
||||
prefix=int(file.readline())
|
||||
except (TypeError, ValueError):
|
||||
prefix=self._unused_prefix()
|
||||
with open(next_prefix_file,'w') as file:
|
||||
file.write(str(prefix+1))
|
||||
return f'{prefix:06}'
|
||||
|
||||
# gives the next unique prefix in outdir
|
||||
def unique_prefix(self):
|
||||
def _unused_prefix(self)->int:
|
||||
# sort reverse alphabetically until we find max+1
|
||||
dirlist = sorted(os.listdir(self.outdir), reverse=True)
|
||||
# find the first filename that matches our pattern or return 000000.0.png
|
||||
@ -28,8 +48,7 @@ class PngWriter:
|
||||
(f for f in dirlist if re.match('^(\d+)\..*\.png', f)),
|
||||
'0000000.0.png',
|
||||
)
|
||||
basecount = int(existing_name.split('.', 1)[0]) + 1
|
||||
return f'{basecount:06}'
|
||||
return int(existing_name.split('.', 1)[0]) + 1
|
||||
|
||||
# saves image named _image_ to outdir/name, writing metadata from prompt
|
||||
# returns full path of output
|
||||
@ -91,14 +110,12 @@ class PromptFormatter:
|
||||
switches.append(f'-H{opt.height or t2i.height}')
|
||||
switches.append(f'-C{opt.cfg_scale or t2i.cfg_scale}')
|
||||
switches.append(f'-A{opt.sampler_name or t2i.sampler_name}')
|
||||
# to do: put model name into the t2i object
|
||||
# switches.append(f'--model{t2i.model_name}')
|
||||
if opt.seamless or t2i.seamless:
|
||||
switches.append(f'--seamless')
|
||||
switches.append('--seamless')
|
||||
if opt.init_img:
|
||||
switches.append(f'-I{opt.init_img}')
|
||||
if opt.fit:
|
||||
switches.append(f'--fit')
|
||||
switches.append('--fit')
|
||||
if opt.strength and opt.init_img is not None:
|
||||
switches.append(f'-f{opt.strength or t2i.strength}')
|
||||
if opt.gfpgan_strength:
|
||||
|
@ -17,6 +17,7 @@ from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
|
||||
import npyscreen
|
||||
from diffusers.utils.import_utils import is_xformers_available
|
||||
from npyscreen import widget
|
||||
from omegaconf import OmegaConf
|
||||
|
||||
@ -29,7 +30,7 @@ from ldm.invoke.training.textual_inversion_training import (
|
||||
TRAINING_DATA = "text-inversion-training-data"
|
||||
TRAINING_DIR = "text-inversion-output"
|
||||
CONF_FILE = "preferences.conf"
|
||||
|
||||
XFORMERS_AVAILABLE = is_xformers_available()
|
||||
|
||||
class textualInversionForm(npyscreen.FormMultiPageAction):
|
||||
resolutions = [512, 768, 1024]
|
||||
@ -178,7 +179,7 @@ class textualInversionForm(npyscreen.FormMultiPageAction):
|
||||
out_of=10000,
|
||||
step=500,
|
||||
lowest=1,
|
||||
value=saved_args.get("max_train_steps", 3000),
|
||||
value=saved_args.get("max_train_steps", 2500),
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.train_batch_size = self.add_widget_intelligent(
|
||||
@ -187,7 +188,7 @@ class textualInversionForm(npyscreen.FormMultiPageAction):
|
||||
out_of=50,
|
||||
step=1,
|
||||
lowest=1,
|
||||
value=saved_args.get("train_batch_size", 8),
|
||||
value=saved_args.get("train_batch_size", 8 if XFORMERS_AVAILABLE else 3),
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.gradient_accumulation_steps = self.add_widget_intelligent(
|
||||
@ -225,7 +226,7 @@ class textualInversionForm(npyscreen.FormMultiPageAction):
|
||||
self.enable_xformers_memory_efficient_attention = self.add_widget_intelligent(
|
||||
npyscreen.Checkbox,
|
||||
name="Use xformers acceleration",
|
||||
value=saved_args.get("enable_xformers_memory_efficient_attention", False),
|
||||
value=saved_args.get("enable_xformers_memory_efficient_attention", XFORMERS_AVAILABLE),
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.lr_scheduler = self.add_widget_intelligent(
|
||||
@ -428,8 +429,7 @@ def do_front_end(args: Namespace):
|
||||
print(str(e))
|
||||
print("** DETAILS:")
|
||||
print(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
global_set_root(args.root_dir or Globals.root)
|
||||
|
@ -67,7 +67,7 @@ else:
|
||||
"nearest": PIL.Image.NEAREST,
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
XFORMERS_AVAILABLE = is_xformers_available
|
||||
|
||||
# Will error if the minimal version of diffusers is not installed. Remove at your own risks.
|
||||
check_min_version("0.10.0.dev0")
|
||||
@ -227,7 +227,7 @@ def parse_args():
|
||||
training_group.add_argument(
|
||||
"--train_batch_size",
|
||||
type=int,
|
||||
default=16,
|
||||
default=8 if XFORMERS_AVAILABLE else 3,
|
||||
help="Batch size (per device) for the training dataloader.",
|
||||
)
|
||||
training_group.add_argument("--num_train_epochs", type=int, default=100)
|
||||
@ -324,6 +324,7 @@ def parse_args():
|
||||
parser.add_argument(
|
||||
"--enable_xformers_memory_efficient_attention",
|
||||
action="store_true",
|
||||
default=XFORMERS_AVAILABLE,
|
||||
help="Whether or not to use xformers.",
|
||||
)
|
||||
|
||||
@ -536,7 +537,7 @@ def do_textual_inversion_training(
|
||||
seed: int = None,
|
||||
resolution: int = 512,
|
||||
center_crop: bool = False,
|
||||
train_batch_size: int = 16,
|
||||
train_batch_size: int = 4,
|
||||
num_train_epochs: int = 100,
|
||||
max_train_steps: int = 5000,
|
||||
gradient_accumulation_steps: int = 1,
|
||||
@ -634,7 +635,7 @@ def do_textual_inversion_training(
|
||||
assert (
|
||||
pretrained_model_name_or_path
|
||||
), f"models.yaml error: neither 'repo_id' nor 'path' is defined for {model}"
|
||||
pipeline_args = dict(cache_dir=global_cache_dir("diffusers"))
|
||||
pipeline_args = dict(cache_dir=global_cache_dir("hub"))
|
||||
|
||||
# Load tokenizer
|
||||
if tokenizer_name:
|
||||
|
@ -329,7 +329,7 @@ def download_with_resume(url: str, dest: Path, access_token: str = None) -> Path
|
||||
resp = requests.get(url, headers=header, stream=True) # new request with range
|
||||
|
||||
if exist_size > content_length:
|
||||
print('* corrupt existing file found. re-downloading')
|
||||
print(f'* corrupt existing file found (existing_size={exist_size}, content_length={content_length}). re-downloading')
|
||||
os.remove(dest)
|
||||
exist_size = 0
|
||||
|
||||
@ -341,15 +341,12 @@ def download_with_resume(url: str, dest: Path, access_token: str = None) -> Path
|
||||
elif resp.status_code == 206 or exist_size > 0:
|
||||
print(f"* {dest}: partial file found. Resuming...")
|
||||
elif resp.status_code != 200:
|
||||
print(f"** An error occurred during downloading {dest}: {resp.reason}")
|
||||
print(f"** An error occurred while downloading {url}: {resp.reason}")
|
||||
return None
|
||||
else:
|
||||
print(f"* {dest}: Downloading...")
|
||||
|
||||
try:
|
||||
if content_length < 2000:
|
||||
print(f"*** ERROR DOWNLOADING {url}: {resp.text}")
|
||||
return None
|
||||
|
||||
with open(dest, open_mode) as file, tqdm(
|
||||
desc=str(dest),
|
||||
initial=exist_size,
|
||||
|
28
mkdocs.yml
28
mkdocs.yml
@ -2,14 +2,14 @@
|
||||
|
||||
# General
|
||||
site_name: InvokeAI Stable Diffusion Toolkit Docs
|
||||
site_url: https://invoke-ai.github.io/InvokeAI
|
||||
site_url: !ENV [SITE_URL, 'https://invoke-ai.github.io/InvokeAI']
|
||||
site_author: mauwii
|
||||
dev_addr: '127.0.0.1:8080'
|
||||
|
||||
# Repository
|
||||
repo_name: 'invoke-ai/InvokeAI'
|
||||
repo_url: 'https://github.com/invoke-ai/InvokeAI'
|
||||
edit_uri: edit/main/docs/
|
||||
repo_name: !ENV [REPO_NAME, 'invoke-ai/InvokeAI']
|
||||
repo_url: !ENV [REPO_URL, 'https://github.com/invoke-ai/InvokeAI']
|
||||
edit_uri: blob/main/docs/
|
||||
|
||||
# Copyright
|
||||
copyright: Copyright © 2022 InvokeAI Team
|
||||
@ -19,7 +19,8 @@ theme:
|
||||
name: material
|
||||
icon:
|
||||
repo: fontawesome/brands/github
|
||||
edit: material/file-document-edit-outline
|
||||
edit: material/pencil
|
||||
view: material/eye
|
||||
palette:
|
||||
- media: '(prefers-color-scheme: light)'
|
||||
scheme: default
|
||||
@ -33,6 +34,11 @@ theme:
|
||||
icon: material/lightbulb-outline
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- content.action.edit
|
||||
- content.action.view
|
||||
- content.code.copy
|
||||
- content.tabs.link
|
||||
- navigation.indexes
|
||||
- navigation.instant
|
||||
- navigation.tabs
|
||||
- navigation.top
|
||||
@ -89,9 +95,9 @@ plugins:
|
||||
enable_creation_date: true
|
||||
- redirects:
|
||||
redirect_maps:
|
||||
'installation/INSTALL_AUTOMATED.md': 'installation/010_INSTALL_AUTOMATED.md'
|
||||
'installation/INSTALL_MANUAL.md': 'installation/020_INSTALL_MANUAL.md'
|
||||
'installation/INSTALL_SOURCE.md': 'installation/020_INSTALL_MANUAL.md'
|
||||
'installation/INSTALL_DOCKER.md': 'installation/040_INSTALL_DOCKER.md'
|
||||
'installation/INSTALLING_MODELS.md': 'installation/050_INSTALLING_MODELS.md'
|
||||
'installation/INSTALL_PATCHMATCH.md': 'installation/060_INSTALL_PATCHMATCH.md'
|
||||
'installation/INSTALL_AUTOMATED.md': 'installation/010_INSTALL_AUTOMATED.md'
|
||||
'installation/INSTALL_MANUAL.md': 'installation/020_INSTALL_MANUAL.md'
|
||||
'installation/INSTALL_SOURCE.md': 'installation/020_INSTALL_MANUAL.md'
|
||||
'installation/INSTALL_DOCKER.md': 'installation/040_INSTALL_DOCKER.md'
|
||||
'installation/INSTALLING_MODELS.md': 'installation/050_INSTALLING_MODELS.md'
|
||||
'installation/INSTALL_PATCHMATCH.md': 'installation/060_INSTALL_PATCHMATCH.md'
|
||||
|
160
pyproject.toml
160
pyproject.toml
@ -1,46 +1,40 @@
|
||||
[build-system]
|
||||
requires = ["setuptools~=65.5", "pip~=22.3", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
requires = ["setuptools ~= 67.1", "wheel"]
|
||||
|
||||
[project]
|
||||
name = "InvokeAI"
|
||||
description = "An implementation of Stable Diffusion which provides various new features and options to aid the image generation process"
|
||||
requires-python = ">=3.9, <3.11"
|
||||
readme = { content-type = "text/markdown", file = "README.md" }
|
||||
keywords = ["stable-diffusion", "AI"]
|
||||
dynamic = ["version"]
|
||||
license = { file = "LICENSE" }
|
||||
authors = [{ name = "The InvokeAI Project", email = "lincoln.stein@gmail.com" }]
|
||||
authors = [{name = "The InvokeAI Project", email = "lincoln.stein@gmail.com"}]
|
||||
classifiers = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: GPU',
|
||||
'Environment :: GPU :: NVIDIA CUDA',
|
||||
'Environment :: MacOS X',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: MacOS',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Topic :: Artistic Software',
|
||||
'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
|
||||
'Topic :: Internet :: WWW/HTTP :: WSGI :: Server',
|
||||
'Topic :: Multimedia :: Graphics',
|
||||
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
||||
'Topic :: Scientific/Engineering :: Image Processing',
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: GPU :: NVIDIA CUDA",
|
||||
"Environment :: GPU",
|
||||
"Environment :: MacOS X",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: End Users/Desktop",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python",
|
||||
"Topic :: Artistic Software",
|
||||
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
|
||||
"Topic :: Internet :: WWW/HTTP :: WSGI :: Server",
|
||||
"Topic :: Multimedia :: Graphics",
|
||||
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||
"Topic :: Scientific/Engineering :: Image Processing",
|
||||
]
|
||||
dependencies = [
|
||||
"accelerate",
|
||||
"accelerate~=0.16",
|
||||
"albumentations",
|
||||
"click",
|
||||
"clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip",
|
||||
"clip_anytorch",
|
||||
"compel==0.1.7",
|
||||
"datasets",
|
||||
"diffusers[torch]~=0.13",
|
||||
"diffusers[torch]~=0.14",
|
||||
"dnspython==2.2.1",
|
||||
"einops",
|
||||
"eventlet",
|
||||
@ -54,7 +48,7 @@ dependencies = [
|
||||
"huggingface-hub>=0.11.1",
|
||||
"imageio",
|
||||
"imageio-ffmpeg",
|
||||
"k-diffusion", # replacing "k-diffusion @ https://github.com/Birch-san/k-diffusion/archive/refs/heads/mps.zip",
|
||||
"k-diffusion",
|
||||
"kornia",
|
||||
"npyscreen",
|
||||
"numpy<1.24",
|
||||
@ -62,75 +56,133 @@ dependencies = [
|
||||
"opencv-python",
|
||||
"picklescan",
|
||||
"pillow",
|
||||
"pudb",
|
||||
"prompt-toolkit",
|
||||
"pudb",
|
||||
"packaging",
|
||||
"pypatchmatch",
|
||||
"pyreadline3",
|
||||
"pytorch-lightning==1.7.7",
|
||||
"realesrgan",
|
||||
"requests==2.28.2",
|
||||
"safetensors",
|
||||
"safetensors~=0.3.0",
|
||||
"scikit-image>=0.19",
|
||||
"send2trash",
|
||||
"streamlit",
|
||||
"taming-transformers-rom1504",
|
||||
"test-tube>=0.7.5",
|
||||
"torch>=1.13.1",
|
||||
"torch-fidelity",
|
||||
"torchvision>=0.14.1",
|
||||
"torch~=1.13.1",
|
||||
"torchmetrics",
|
||||
"transformers~=4.25",
|
||||
"torchvision>=0.14.1",
|
||||
"transformers~=4.26",
|
||||
"windows-curses; sys_platform=='win32'",
|
||||
]
|
||||
description = "An implementation of Stable Diffusion which provides various new features and options to aid the image generation process"
|
||||
dynamic = ["version"]
|
||||
keywords = ["AI", "stable-diffusion"]
|
||||
license = {text = "MIT"}
|
||||
name = "InvokeAI"
|
||||
readme = {content-type = "text/markdown", file = "README.md"}
|
||||
requires-python = ">=3.9, <3.11"
|
||||
|
||||
[project.optional-dependencies]
|
||||
"dev" = [
|
||||
"black[jupyter]",
|
||||
"flake8",
|
||||
"flake8-black",
|
||||
"flake8-bugbear",
|
||||
"isort",
|
||||
"pre-commit",
|
||||
]
|
||||
"dist" = ["pip-tools", "pipdeptree", "twine"]
|
||||
"docs" = [
|
||||
"mkdocs-material<9.0",
|
||||
"mkdocs-git-revision-date-localized-plugin",
|
||||
"mkdocs-material==9.*",
|
||||
"mkdocs-redirects==1.2.0",
|
||||
]
|
||||
"test" = ["pytest>6.0.0", "pytest-cov"]
|
||||
"test" = ["pytest-cov", "pytest>6.0.0"]
|
||||
"xformers" = [
|
||||
"xformers~=0.0.16; sys_platform!='darwin'",
|
||||
"triton; sys_platform=='linux'",
|
||||
"triton; sys_platform=='linux'",
|
||||
"xformers~=0.0.16; sys_platform!='darwin'",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
# legacy entrypoints; provided for backwards compatibility
|
||||
"invoke.py" = "ldm.invoke.CLI:main"
|
||||
"configure_invokeai.py" = "ldm.invoke.config.invokeai_configure:main"
|
||||
"textual_inversion.py" = "ldm.invoke.training.textual_inversion:main"
|
||||
"invoke.py" = "ldm.invoke.CLI:main"
|
||||
"merge_embeddings.py" = "ldm.invoke.merge_diffusers:main"
|
||||
"textual_inversion.py" = "ldm.invoke.training.textual_inversion:main"
|
||||
|
||||
# modern entrypoints
|
||||
"invokeai" = "ldm.invoke.CLI:main"
|
||||
"invokeai-configure" = "ldm.invoke.config.invokeai_configure:main"
|
||||
"invokeai-merge" = "ldm.invoke.merge_diffusers:main" # note name munging
|
||||
"invokeai-ti" = "ldm.invoke.training.textual_inversion:main"
|
||||
"invokeai-model-install" = "ldm.invoke.config.model_install:main"
|
||||
"invokeai-merge" = "ldm.invoke.merge_diffusers:main"
|
||||
"invokeai-ti" = "ldm.invoke.training.textual_inversion:main"
|
||||
"invokeai-update" = "ldm.invoke.config.invokeai_update:main"
|
||||
"invokeai-batch" = "ldm.invoke.dynamic_prompts:main"
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://invoke-ai.github.io/InvokeAI/"
|
||||
"Documentation" = "https://invoke-ai.github.io/InvokeAI/"
|
||||
"Source" = "https://github.com/invoke-ai/InvokeAI/"
|
||||
"Bug Reports" = "https://github.com/invoke-ai/InvokeAI/issues"
|
||||
"Discord" = "https://discord.gg/ZmtBAhwWhy"
|
||||
"Documentation" = "https://invoke-ai.github.io/InvokeAI/"
|
||||
"Homepage" = "https://invoke-ai.github.io/InvokeAI/"
|
||||
"Source" = "https://github.com/invoke-ai/InvokeAI/"
|
||||
|
||||
[tool.setuptools]
|
||||
license-files = ["LICENSE"]
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
version = { attr = "ldm.invoke.__version__" }
|
||||
version = {attr = "ldm.invoke.__version__"}
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
"include" = [
|
||||
"invokeai.assets.web",
|
||||
"invokeai.backend*",
|
||||
"invokeai.configs*",
|
||||
"invokeai.frontend.dist*",
|
||||
"ldm*",
|
||||
]
|
||||
"where" = ["."]
|
||||
"include" = ["invokeai.assets.web*", "invokeai.backend*", "invokeai.frontend.dist*", "invokeai.configs*", "ldm*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"invokeai.assets.web" = ["**.png"]
|
||||
"invokeai.backend" = ["**.png"]
|
||||
"invokeai.configs" = ["*.example", "**/*.yaml", "*.txt"]
|
||||
"invokeai.configs" = ["**.example", "**.txt", "**.yaml", "**/*.yaml"]
|
||||
"invokeai.frontend.dist" = ["**"]
|
||||
|
||||
[tool.black]
|
||||
extend-exclude = '''
|
||||
/(
|
||||
# skip legacy scripts
|
||||
| scripts/orig_scripts
|
||||
)/
|
||||
'''
|
||||
line-length = 88
|
||||
target-version = ['py39']
|
||||
|
||||
[tool.isort]
|
||||
atomic = true
|
||||
extend_skip_glob = ["scripts/orig_scripts/*"]
|
||||
filter_files = true
|
||||
line_length = 120
|
||||
profile = "black"
|
||||
py_version = 39
|
||||
remove_redundant_aliases = true
|
||||
skip_gitignore = true
|
||||
src_paths = ["installer", "invokeai", "ldm", "tests"]
|
||||
virtual_env = ".venv"
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
parallel = true
|
||||
|
||||
[tool.coverage.report]
|
||||
skip_covered = true
|
||||
skip_empty = true
|
||||
|
||||
[tool.coverage.paths]
|
||||
source = ["invokeai/backend", "ldm/invoke"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "-p pytest_cov --junitxml=junit/test-results.xml --cov-report=term:skip-covered --cov=ldm/invoke --cov=backend --cov-branch"
|
||||
addopts = ["--cov=invokeai/backend", "--cov=ldm/invoke"]
|
||||
|
9
scripts/dynamic_prompts.py
Executable file
9
scripts/dynamic_prompts.py
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Simple script to generate a file of InvokeAI prompts and settings
|
||||
that scan across steps and other parameters.
|
||||
"""
|
||||
|
||||
import ldm.invoke.dynamic_prompts
|
||||
ldm.invoke.dynamic_prompts.main()
|
Reference in New Issue
Block a user