Update main with V2.3 fixes (#2774)

Until the nodes merge happens, we can continue to merge bugfixes from
the 2.3 branch into `main`. This will bring main into sync with
`v2.3.1+rc3`
This commit is contained in:
Lincoln Stein 2023-02-23 17:38:16 -05:00 committed by GitHub
commit ad6ea02c9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 229 additions and 155 deletions

View File

@ -28,7 +28,7 @@ jobs:
run: twine check dist/* run: twine check dist/*
- name: check PyPI versions - name: check PyPI versions
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2.3'
run: | run: |
pip install --upgrade requests pip install --upgrade requests
python -c "\ python -c "\

View File

@ -259,7 +259,7 @@ cleanup, testing, or code reviews, is very much encouraged to do so.
To join, just raise your hand on the InvokeAI Discord server (#dev-chat) or the GitHub discussion board. To join, just raise your hand on the InvokeAI Discord server (#dev-chat) or the GitHub discussion board.
If you'd like to help with localization, please register on [Weblate][translation status link]. If you want add a new language, please let us know which language and we will add it to the Weblate project. If you'd like to help with translation, please see our [translation guide](docs/other/TRANSLATION.md).
If you are unfamiliar with how If you are unfamiliar with how
to contribute to GitHub projects, here is a to contribute to GitHub projects, here is a

19
docs/other/TRANSLATION.md Normal file
View File

@ -0,0 +1,19 @@
# Translation
InvokeAI uses [Weblate](https://weblate.org) for translation. Weblate is a FOSS project providing a scalable translation service. Weblate automates the tedious parts of managing translation of a growing project, and the service is generously provided at no cost to FOSS projects like InvokeAI.
## Contributing
If you'd like to contribute by adding or updating a translation, please visit our [Weblate project](https://hosted.weblate.org/engage/invokeai/). You'll need to sign in with your GitHub account (a number of other accounts are supported, including Google).
Once signed in, select a language and then the Web UI component. From here you can Browse and Translate strings from English to your chosen language. Zen mode offers a simpler translation experience.
Your changes will be attributed to you in the automated PR process; you don't need to do anything else.
## Help & Questions
Please check Weblate's [documentation](https://docs.weblate.org/en/latest/index.html) or ping @psychedelicious or @blessedcoolant on Discord if you have any questions.
## Thanks
Thanks to the InvokeAI community for their efforts to translate the project!

View File

@ -20,10 +20,9 @@ echo Building installer for version $VERSION
echo "Be certain that you're in the 'installer' directory before continuing." echo "Be certain that you're in the 'installer' directory before continuing."
read -p "Press any key to continue, or CTRL-C to exit..." read -p "Press any key to continue, or CTRL-C to exit..."
read -e -p "Commit and tag this repo with '${VERSION}' and '${LATEST_TAG}'? [n]: " input read -e -p "Tag this repo with '${VERSION}' and '${LATEST_TAG}'? [n]: " input
RESPONSE=${input:='n'} RESPONSE=${input:='n'}
if [ "$RESPONSE" == 'y' ]; then if [ "$RESPONSE" == 'y' ]; then
git commit -a
if ! git tag $VERSION ; then if ! git tag $VERSION ; then
echo "Existing/invalid tag" echo "Existing/invalid tag"
@ -32,6 +31,8 @@ if [ "$RESPONSE" == 'y' ]; then
git push origin :refs/tags/$LATEST_TAG git push origin :refs/tags/$LATEST_TAG
git tag -fa $LATEST_TAG git tag -fa $LATEST_TAG
echo "remember to push --tags!"
fi fi
# ---------------------- # ----------------------

View File

@ -336,7 +336,8 @@ class InvokeAiInstance:
elif el in ['-y','--yes','--yes-to-all']: elif el in ['-y','--yes','--yes-to-all']:
new_argv.append(el) new_argv.append(el)
sys.argv = new_argv sys.argv = new_argv
import requests # to catch download exceptions
from messages import introduction from messages import introduction
introduction() introduction()
@ -346,7 +347,21 @@ class InvokeAiInstance:
# NOTE: currently the config script does its own arg parsing! this means the command-line switches # NOTE: currently the config script does its own arg parsing! this means the command-line switches
# from the installer will also automatically propagate down to the config script. # from the installer will also automatically propagate down to the config script.
# this may change in the future with config refactoring! # this may change in the future with config refactoring!
invokeai_configure.main() succeeded = False
try:
invokeai_configure.main()
succeeded = True
except requests.exceptions.ConnectionError as e:
print(f'\nA network error was encountered during configuration and download: {str(e)}')
except OSError as e:
print(f'\nAn OS error was encountered during configuration and download: {str(e)}')
except Exception as e:
print(f'\nA problem was encountered during the configuration and download steps: {str(e)}')
finally:
if not succeeded:
print('To try again, find the "invokeai" directory, run the script "invoke.sh" or "invoke.bat"')
print('and choose option 7 to fix a broken install, optionally followed by option 5 to install models.')
print('Alternatively you can relaunch the installer.')
def install_user_scripts(self): def install_user_scripts(self):
""" """

View File

@ -6,8 +6,9 @@ setlocal
call .venv\Scripts\activate.bat call .venv\Scripts\activate.bat
set INVOKEAI_ROOT=. set INVOKEAI_ROOT=.
:start
echo Do you want to generate images using the echo Do you want to generate images using the
echo 1. command-line echo 1. command-line interface
echo 2. browser-based UI echo 2. browser-based UI
echo 3. run textual inversion training echo 3. run textual inversion training
echo 4. merge models (diffusers type only) echo 4. merge models (diffusers type only)
@ -17,7 +18,8 @@ echo 7. re-run the configure script to fix a broken install
echo 8. open the developer console echo 8. open the developer console
echo 9. update InvokeAI echo 9. update InvokeAI
echo 10. command-line help echo 10. command-line help
set /P restore="Please enter 1-10: [2] " echo Q - quit
set /P restore="Please enter 1-10, Q: [2] "
if not defined restore set restore=2 if not defined restore set restore=2
IF /I "%restore%" == "1" ( IF /I "%restore%" == "1" (
echo Starting the InvokeAI command-line.. echo Starting the InvokeAI command-line..
@ -60,9 +62,19 @@ IF /I "%restore%" == "1" (
python .venv\Scripts\invokeai.exe --help %* python .venv\Scripts\invokeai.exe --help %*
pause pause
exit /b exit /b
) ELSE IF /I "%restore%" == "q" (
echo Goodbye!
goto ending
) ELSE ( ) ELSE (
echo Invalid selection echo Invalid selection
pause pause
exit /b exit /b
) )
goto start
endlocal endlocal
pause
:ending
exit /b

View File

@ -24,9 +24,11 @@ if [ "$(uname -s)" == "Darwin" ]; then
export PYTORCH_ENABLE_MPS_FALLBACK=1 export PYTORCH_ENABLE_MPS_FALLBACK=1
fi fi
while true
do
if [ "$0" != "bash" ]; then if [ "$0" != "bash" ]; then
echo "Do you want to generate images using the" echo "Do you want to generate images using the"
echo "1. command-line" echo "1. command-line interface"
echo "2. browser-based UI" echo "2. browser-based UI"
echo "3. run textual inversion training" echo "3. run textual inversion training"
echo "4. merge models (diffusers type only)" echo "4. merge models (diffusers type only)"
@ -35,35 +37,36 @@ if [ "$0" != "bash" ]; then
echo "7. re-run the configure script to fix a broken install" echo "7. re-run the configure script to fix a broken install"
echo "8. open the developer console" echo "8. open the developer console"
echo "9. update InvokeAI" echo "9. update InvokeAI"
echo "10. command-line help " echo "10. command-line help"
echo "Q - Quit"
echo "" echo ""
read -p "Please enter 1-10: [2] " yn read -p "Please enter 1-10, Q: [2] " yn
choice=${yn:='2'} choice=${yn:='2'}
case $choice in case $choice in
1) 1)
echo "Starting the InvokeAI command-line..." echo "Starting the InvokeAI command-line..."
exec invokeai $@ invokeai $@
;; ;;
2) 2)
echo "Starting the InvokeAI browser-based UI..." echo "Starting the InvokeAI browser-based UI..."
exec invokeai --web $@ invokeai --web $@
;; ;;
3) 3)
echo "Starting Textual Inversion:" echo "Starting Textual Inversion:"
exec invokeai-ti --gui $@ invokeai-ti --gui $@
;; ;;
4) 4)
echo "Merging Models:" echo "Merging Models:"
exec invokeai-merge --gui $@ invokeai-merge --gui $@
;; ;;
5) 5)
exec invokeai-model-install --root ${INVOKEAI_ROOT} invokeai-model-install --root ${INVOKEAI_ROOT}
;; ;;
6) 6)
exec invokeai-configure --root ${INVOKEAI_ROOT} --skip-sd-weights --skip-support-models invokeai-configure --root ${INVOKEAI_ROOT} --skip-sd-weights --skip-support-models
;; ;;
7) 7)
exec invokeai-configure --root ${INVOKEAI_ROOT} --yes --default_only invokeai-configure --root ${INVOKEAI_ROOT} --yes --default_only
;; ;;
8) 8)
echo "Developer Console:" echo "Developer Console:"
@ -72,10 +75,13 @@ if [ "$0" != "bash" ]; then
;; ;;
9) 9)
echo "Update:" echo "Update:"
exec invokeai-update invokeai-update
;; ;;
10) 10)
exec invokeai --help invokeai --help
;;
[qQ])
exit 0
;; ;;
*) *)
echo "Invalid selection" echo "Invalid selection"
@ -86,3 +92,4 @@ else # in developer console
echo "Press ^D to exit" echo "Press ^D to exit"
export PS1="(InvokeAI) \u@\h \w> " export PS1="(InvokeAI) \u@\h \w> "
fi fi
done

View File

@ -465,7 +465,10 @@
"isScheduled": "Annullamento", "isScheduled": "Annullamento",
"setType": "Imposta il tipo di annullamento", "setType": "Imposta il tipo di annullamento",
"immediate": "Annulla immediatamente" "immediate": "Annulla immediatamente"
} },
"hSymmetryStep": "Passi Simmetria Orizzontale",
"vSymmetryStep": "Passi Simmetria Verticale",
"symmetry": "Simmetria"
}, },
"settings": { "settings": {
"models": "Modelli", "models": "Modelli",

View File

@ -4,7 +4,7 @@
"themeLabel": "Тема", "themeLabel": "Тема",
"languagePickerLabel": "Язык", "languagePickerLabel": "Язык",
"reportBugLabel": "Сообщить об ошибке", "reportBugLabel": "Сообщить об ошибке",
"settingsLabel": "Настройка", "settingsLabel": "Настройки",
"darkTheme": "Темная", "darkTheme": "Темная",
"lightTheme": "Светлая", "lightTheme": "Светлая",
"greenTheme": "Зеленая", "greenTheme": "Зеленая",
@ -17,9 +17,9 @@
"postProcessing": "Постобработка", "postProcessing": "Постобработка",
"postProcessDesc1": "Invoke AI предлагает широкий спектр функций постобработки. Увеличение изображения (upscale) и восстановление лиц уже доступны в интерфейсе. Получите доступ к ним из меню 'Дополнительные параметры' на вкладках 'Текст в изображение' и 'Изображение в изображение'. Обрабатывайте изображения напрямую, используя кнопки действий с изображениями над текущим изображением или в режиме просмотра.", "postProcessDesc1": "Invoke AI предлагает широкий спектр функций постобработки. Увеличение изображения (upscale) и восстановление лиц уже доступны в интерфейсе. Получите доступ к ним из меню 'Дополнительные параметры' на вкладках 'Текст в изображение' и 'Изображение в изображение'. Обрабатывайте изображения напрямую, используя кнопки действий с изображениями над текущим изображением или в режиме просмотра.",
"postProcessDesc2": "В ближайшее время будет выпущен специальный интерфейс для более продвинутых процессов постобработки.", "postProcessDesc2": "В ближайшее время будет выпущен специальный интерфейс для более продвинутых процессов постобработки.",
"postProcessDesc3": "Интерфейс командной строки Invoke AI предлагает различные другие функции, включая увеличение Embiggen", "postProcessDesc3": "Интерфейс командной строки Invoke AI предлагает различные другие функции, включая Embiggen.",
"training": "Обучение", "training": "Обучение",
"trainingDesc1": "Специальный интерфейс для обучения собственных моделей с использованием Textual Inversion и Dreambooth", "trainingDesc1": "Специальный интерфейс для обучения собственных моделей с использованием Textual Inversion и Dreambooth.",
"trainingDesc2": "InvokeAI уже поддерживает обучение моделей с помощью TI, через интерфейс командной строки.", "trainingDesc2": "InvokeAI уже поддерживает обучение моделей с помощью TI, через интерфейс командной строки.",
"upload": "Загрузить", "upload": "Загрузить",
"close": "Закрыть", "close": "Закрыть",
@ -44,7 +44,9 @@
"statusUpscaling": "Увеличение", "statusUpscaling": "Увеличение",
"statusUpscalingESRGAN": "Увеличение (ESRGAN)", "statusUpscalingESRGAN": "Увеличение (ESRGAN)",
"statusLoadingModel": "Загрузка модели", "statusLoadingModel": "Загрузка модели",
"statusModelChanged": "Модель изменена" "statusModelChanged": "Модель изменена",
"githubLabel": "Github",
"discordLabel": "Discord"
}, },
"gallery": { "gallery": {
"generations": "Генерации", "generations": "Генерации",
@ -285,15 +287,15 @@
"description": "Описание", "description": "Описание",
"descriptionValidationMsg": "Введите описание модели", "descriptionValidationMsg": "Введите описание модели",
"config": "Файл конфигурации", "config": "Файл конфигурации",
"configValidationMsg": "Путь до файла конфигурации", "configValidationMsg": "Путь до файла конфигурации.",
"modelLocation": "Расположение модели", "modelLocation": "Расположение модели",
"modelLocationValidationMsg": "Путь до файла с моделью", "modelLocationValidationMsg": "Путь до файла с моделью.",
"vaeLocation": "Расположение VAE", "vaeLocation": "Расположение VAE",
"vaeLocationValidationMsg": "Путь до VAE", "vaeLocationValidationMsg": "Путь до файла VAE.",
"width": "Ширина", "width": "Ширина",
"widthValidationMsg": "Исходная ширина изображений", "widthValidationMsg": "Исходная ширина изображений модели.",
"height": "Высота", "height": "Высота",
"heightValidationMsg": "Исходная высота изображений", "heightValidationMsg": "Исходная высота изображений модели.",
"addModel": "Добавить модель", "addModel": "Добавить модель",
"updateModel": "Обновить модель", "updateModel": "Обновить модель",
"availableModels": "Доступные модели", "availableModels": "Доступные модели",
@ -320,7 +322,8 @@
"deleteModel": "Удалить модель", "deleteModel": "Удалить модель",
"deleteConfig": "Удалить конфигурацию", "deleteConfig": "Удалить конфигурацию",
"deleteMsg1": "Вы точно хотите удалить модель из InvokeAI?", "deleteMsg1": "Вы точно хотите удалить модель из InvokeAI?",
"deleteMsg2": "Это не удалит файл модели с диска. Позже вы можете добавить его снова." "deleteMsg2": "Это не удалит файл модели с диска. Позже вы можете добавить его снова.",
"repoIDValidationMsg": "Онлайн-репозиторий модели"
}, },
"parameters": { "parameters": {
"images": "Изображения", "images": "Изображения",
@ -411,15 +414,15 @@
"sentToUnifiedCanvas": "Отправить на холст", "sentToUnifiedCanvas": "Отправить на холст",
"parametersSet": "Параметры заданы", "parametersSet": "Параметры заданы",
"parametersNotSet": "Параметры не заданы", "parametersNotSet": "Параметры не заданы",
"parametersNotSetDesc": "Не найдены метаданные этого изображения", "parametersNotSetDesc": "Не найдены метаданные изображения.",
"parametersFailed": "Проблема с загрузкой параметров", "parametersFailed": "Проблема с загрузкой параметров",
"parametersFailedDesc": "Невозможно загрузить исходное изображение", "parametersFailedDesc": "Невозможно загрузить исходное изображение.",
"seedSet": "Сид задан", "seedSet": "Сид задан",
"seedNotSet": "Сид не задан", "seedNotSet": "Сид не задан",
"seedNotSetDesc": "Не удалось найти сид для изображения", "seedNotSetDesc": "Не удалось найти сид для изображения.",
"promptSet": "Запрос задан", "promptSet": "Запрос задан",
"promptNotSet": "Запрос не задан", "promptNotSet": "Запрос не задан",
"promptNotSetDesc": "Не удалось найти запрос для изображения", "promptNotSetDesc": "Не удалось найти запрос для изображения.",
"upscalingFailed": "Увеличение не удалось", "upscalingFailed": "Увеличение не удалось",
"faceRestoreFailed": "Восстановление лиц не удалось", "faceRestoreFailed": "Восстановление лиц не удалось",
"metadataLoadFailed": "Не удалось загрузить метаданные", "metadataLoadFailed": "Не удалось загрузить метаданные",
@ -477,7 +480,7 @@
"showCanvasDebugInfo": "Показать отладку холста", "showCanvasDebugInfo": "Показать отладку холста",
"clearCanvasHistory": "Очистить историю холста", "clearCanvasHistory": "Очистить историю холста",
"clearHistory": "Очистить историю", "clearHistory": "Очистить историю",
"clearCanvasHistoryMessage": "Очистка истории холста оставляет текущий холст нетронутым, но удаляет историю отмены и повтора", "clearCanvasHistoryMessage": "Очистка истории холста оставляет текущий холст нетронутым, но удаляет историю отмен и повторов.",
"clearCanvasHistoryConfirm": "Вы уверены, что хотите очистить историю холста?", "clearCanvasHistoryConfirm": "Вы уверены, что хотите очистить историю холста?",
"emptyTempImageFolder": "Очистить временную папку", "emptyTempImageFolder": "Очистить временную папку",
"emptyFolder": "Очистить папку", "emptyFolder": "Очистить папку",

View File

@ -465,7 +465,10 @@
"isScheduled": "Annullamento", "isScheduled": "Annullamento",
"setType": "Imposta il tipo di annullamento", "setType": "Imposta il tipo di annullamento",
"immediate": "Annulla immediatamente" "immediate": "Annulla immediatamente"
} },
"hSymmetryStep": "Passi Simmetria Orizzontale",
"vSymmetryStep": "Passi Simmetria Verticale",
"symmetry": "Simmetria"
}, },
"settings": { "settings": {
"models": "Modelli", "models": "Modelli",

View File

@ -4,7 +4,7 @@
"themeLabel": "Тема", "themeLabel": "Тема",
"languagePickerLabel": "Язык", "languagePickerLabel": "Язык",
"reportBugLabel": "Сообщить об ошибке", "reportBugLabel": "Сообщить об ошибке",
"settingsLabel": "Настройка", "settingsLabel": "Настройки",
"darkTheme": "Темная", "darkTheme": "Темная",
"lightTheme": "Светлая", "lightTheme": "Светлая",
"greenTheme": "Зеленая", "greenTheme": "Зеленая",
@ -17,9 +17,9 @@
"postProcessing": "Постобработка", "postProcessing": "Постобработка",
"postProcessDesc1": "Invoke AI предлагает широкий спектр функций постобработки. Увеличение изображения (upscale) и восстановление лиц уже доступны в интерфейсе. Получите доступ к ним из меню 'Дополнительные параметры' на вкладках 'Текст в изображение' и 'Изображение в изображение'. Обрабатывайте изображения напрямую, используя кнопки действий с изображениями над текущим изображением или в режиме просмотра.", "postProcessDesc1": "Invoke AI предлагает широкий спектр функций постобработки. Увеличение изображения (upscale) и восстановление лиц уже доступны в интерфейсе. Получите доступ к ним из меню 'Дополнительные параметры' на вкладках 'Текст в изображение' и 'Изображение в изображение'. Обрабатывайте изображения напрямую, используя кнопки действий с изображениями над текущим изображением или в режиме просмотра.",
"postProcessDesc2": "В ближайшее время будет выпущен специальный интерфейс для более продвинутых процессов постобработки.", "postProcessDesc2": "В ближайшее время будет выпущен специальный интерфейс для более продвинутых процессов постобработки.",
"postProcessDesc3": "Интерфейс командной строки Invoke AI предлагает различные другие функции, включая увеличение Embiggen", "postProcessDesc3": "Интерфейс командной строки Invoke AI предлагает различные другие функции, включая Embiggen.",
"training": "Обучение", "training": "Обучение",
"trainingDesc1": "Специальный интерфейс для обучения собственных моделей с использованием Textual Inversion и Dreambooth", "trainingDesc1": "Специальный интерфейс для обучения собственных моделей с использованием Textual Inversion и Dreambooth.",
"trainingDesc2": "InvokeAI уже поддерживает обучение моделей с помощью TI, через интерфейс командной строки.", "trainingDesc2": "InvokeAI уже поддерживает обучение моделей с помощью TI, через интерфейс командной строки.",
"upload": "Загрузить", "upload": "Загрузить",
"close": "Закрыть", "close": "Закрыть",
@ -44,7 +44,9 @@
"statusUpscaling": "Увеличение", "statusUpscaling": "Увеличение",
"statusUpscalingESRGAN": "Увеличение (ESRGAN)", "statusUpscalingESRGAN": "Увеличение (ESRGAN)",
"statusLoadingModel": "Загрузка модели", "statusLoadingModel": "Загрузка модели",
"statusModelChanged": "Модель изменена" "statusModelChanged": "Модель изменена",
"githubLabel": "Github",
"discordLabel": "Discord"
}, },
"gallery": { "gallery": {
"generations": "Генерации", "generations": "Генерации",
@ -285,15 +287,15 @@
"description": "Описание", "description": "Описание",
"descriptionValidationMsg": "Введите описание модели", "descriptionValidationMsg": "Введите описание модели",
"config": "Файл конфигурации", "config": "Файл конфигурации",
"configValidationMsg": "Путь до файла конфигурации", "configValidationMsg": "Путь до файла конфигурации.",
"modelLocation": "Расположение модели", "modelLocation": "Расположение модели",
"modelLocationValidationMsg": "Путь до файла с моделью", "modelLocationValidationMsg": "Путь до файла с моделью.",
"vaeLocation": "Расположение VAE", "vaeLocation": "Расположение VAE",
"vaeLocationValidationMsg": "Путь до VAE", "vaeLocationValidationMsg": "Путь до файла VAE.",
"width": "Ширина", "width": "Ширина",
"widthValidationMsg": "Исходная ширина изображений", "widthValidationMsg": "Исходная ширина изображений модели.",
"height": "Высота", "height": "Высота",
"heightValidationMsg": "Исходная высота изображений", "heightValidationMsg": "Исходная высота изображений модели.",
"addModel": "Добавить модель", "addModel": "Добавить модель",
"updateModel": "Обновить модель", "updateModel": "Обновить модель",
"availableModels": "Доступные модели", "availableModels": "Доступные модели",
@ -320,7 +322,8 @@
"deleteModel": "Удалить модель", "deleteModel": "Удалить модель",
"deleteConfig": "Удалить конфигурацию", "deleteConfig": "Удалить конфигурацию",
"deleteMsg1": "Вы точно хотите удалить модель из InvokeAI?", "deleteMsg1": "Вы точно хотите удалить модель из InvokeAI?",
"deleteMsg2": "Это не удалит файл модели с диска. Позже вы можете добавить его снова." "deleteMsg2": "Это не удалит файл модели с диска. Позже вы можете добавить его снова.",
"repoIDValidationMsg": "Онлайн-репозиторий модели"
}, },
"parameters": { "parameters": {
"images": "Изображения", "images": "Изображения",
@ -411,15 +414,15 @@
"sentToUnifiedCanvas": "Отправить на холст", "sentToUnifiedCanvas": "Отправить на холст",
"parametersSet": "Параметры заданы", "parametersSet": "Параметры заданы",
"parametersNotSet": "Параметры не заданы", "parametersNotSet": "Параметры не заданы",
"parametersNotSetDesc": "Не найдены метаданные этого изображения", "parametersNotSetDesc": "Не найдены метаданные изображения.",
"parametersFailed": "Проблема с загрузкой параметров", "parametersFailed": "Проблема с загрузкой параметров",
"parametersFailedDesc": "Невозможно загрузить исходное изображение", "parametersFailedDesc": "Невозможно загрузить исходное изображение.",
"seedSet": "Сид задан", "seedSet": "Сид задан",
"seedNotSet": "Сид не задан", "seedNotSet": "Сид не задан",
"seedNotSetDesc": "Не удалось найти сид для изображения", "seedNotSetDesc": "Не удалось найти сид для изображения.",
"promptSet": "Запрос задан", "promptSet": "Запрос задан",
"promptNotSet": "Запрос не задан", "promptNotSet": "Запрос не задан",
"promptNotSetDesc": "Не удалось найти запрос для изображения", "promptNotSetDesc": "Не удалось найти запрос для изображения.",
"upscalingFailed": "Увеличение не удалось", "upscalingFailed": "Увеличение не удалось",
"faceRestoreFailed": "Восстановление лиц не удалось", "faceRestoreFailed": "Восстановление лиц не удалось",
"metadataLoadFailed": "Не удалось загрузить метаданные", "metadataLoadFailed": "Не удалось загрузить метаданные",
@ -477,7 +480,7 @@
"showCanvasDebugInfo": "Показать отладку холста", "showCanvasDebugInfo": "Показать отладку холста",
"clearCanvasHistory": "Очистить историю холста", "clearCanvasHistory": "Очистить историю холста",
"clearHistory": "Очистить историю", "clearHistory": "Очистить историю",
"clearCanvasHistoryMessage": "Очистка истории холста оставляет текущий холст нетронутым, но удаляет историю отмены и повтора", "clearCanvasHistoryMessage": "Очистка истории холста оставляет текущий холст нетронутым, но удаляет историю отмен и повторов.",
"clearCanvasHistoryConfirm": "Вы уверены, что хотите очистить историю холста?", "clearCanvasHistoryConfirm": "Вы уверены, что хотите очистить историю холста?",
"emptyTempImageFolder": "Очистить временную папку", "emptyTempImageFolder": "Очистить временную папку",
"emptyFolder": "Очистить папку", "emptyFolder": "Очистить папку",

File diff suppressed because one or more lines are too long

View File

@ -496,6 +496,7 @@ def main_loop(gen, opt):
def do_command(command: str, gen, opt: Args, completer) -> tuple: def do_command(command: str, gen, opt: Args, completer) -> tuple:
global infile global infile
operation = "generate" # default operation, alternative is 'postprocess' operation = "generate" # default operation, alternative is 'postprocess'
command = command.replace('\\','/') # windows
if command.startswith( if command.startswith(
"!dream" "!dream"
@ -630,7 +631,6 @@ def import_model(model_path: str, gen, opt, completer, convert=False) -> str:
(3) a huggingface repository id; or (4) a local directory containing a (3) a huggingface repository id; or (4) a local directory containing a
diffusers model. diffusers model.
""" """
model_path = model_path.replace("\\", "/") # windows
default_name = Path(model_path).stem default_name = Path(model_path).stem
model_name = None model_name = None
model_desc = None model_desc = None
@ -672,7 +672,7 @@ def import_model(model_path: str, gen, opt, completer, convert=False) -> str:
gen.model_manager.commit(opt.conf) gen.model_manager.commit(opt.conf)
completer.update_models(gen.model_manager.list_models()) completer.update_models(gen.model_manager.list_models())
print(f">> {model_name} successfully installed") print(f">> {imported_name} successfully installed")
def _verify_load(model_name: str, gen) -> bool: def _verify_load(model_name: str, gen) -> bool:
print(">> Verifying that new model loads...") print(">> Verifying that new model loads...")

View File

@ -1 +1 @@
__version__='2.3.1+a0' __version__='2.3.1+rc3'

View File

@ -8,7 +8,6 @@
# #
print("Loading Python libraries...\n") print("Loading Python libraries...\n")
import argparse import argparse
import curses
import io import io
import os import os
import re import re
@ -19,6 +18,7 @@ import warnings
from argparse import Namespace from argparse import Namespace
from pathlib import Path from pathlib import Path
from urllib import request from urllib import request
from shutil import get_terminal_size
import npyscreen import npyscreen
import torch import torch
@ -46,7 +46,8 @@ from .model_install_backend import (
recommended_datasets, recommended_datasets,
hf_download_with_resume, hf_download_with_resume,
) )
from .widgets import IntTitleSlider, CenteredButtonPress from .widgets import IntTitleSlider, CenteredButtonPress, set_min_terminal_size
warnings.filterwarnings("ignore") warnings.filterwarnings("ignore")
@ -64,6 +65,10 @@ SD_Configs = Path(global_config_dir()) / "stable-diffusion"
Datasets = OmegaConf.load(Dataset_path) Datasets = OmegaConf.load(Dataset_path)
# minimum size for the UI
MIN_COLS = 135
MIN_LINES = 45
INIT_FILE_PREAMBLE = """# InvokeAI initialization file INIT_FILE_PREAMBLE = """# InvokeAI initialization file
# This is the InvokeAI initialization file, which contains command-line default values. # This is the InvokeAI initialization file, which contains command-line default values.
# Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting # Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting
@ -109,8 +114,6 @@ Add the '--help' argument to see all of the command-line switches available for
# --------------------------------------------- # ---------------------------------------------
def yes_or_no(prompt: str, default_yes=True): def yes_or_no(prompt: str, default_yes=True):
completer.set_options(["yes", "no"])
completer.complete_extensions(None) # turn off path-completion mode
default = "y" if default_yes else "n" default = "y" if default_yes else "n"
response = input(f"{prompt} [{default}] ") or default response = input(f"{prompt} [{default}] ") or default
if default_yes: if default_yes:
@ -162,7 +165,6 @@ def download_with_progress_bar(model_url: str, model_dest: str, label: str = "th
print(f"Installing {label} model file {model_url}...", end="", file=sys.stderr) print(f"Installing {label} model file {model_url}...", end="", file=sys.stderr)
if not os.path.exists(model_dest): if not os.path.exists(model_dest):
os.makedirs(os.path.dirname(model_dest), exist_ok=True) os.makedirs(os.path.dirname(model_dest), exist_ok=True)
print("", file=sys.stderr)
request.urlretrieve( request.urlretrieve(
model_url, model_dest, ProgressBar(os.path.basename(model_dest)) model_url, model_dest, ProgressBar(os.path.basename(model_dest))
) )
@ -180,26 +182,22 @@ def download_with_progress_bar(model_url: str, model_dest: str, label: str = "th
def download_bert(): def download_bert():
print( print(
"Installing bert tokenizer...", "Installing bert tokenizer...",
end="", file=sys.stderr
file=sys.stderr,
) )
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning) warnings.filterwarnings("ignore", category=DeprecationWarning)
from transformers import BertTokenizerFast from transformers import BertTokenizerFast
download_from_hf(BertTokenizerFast, "bert-base-uncased") download_from_hf(BertTokenizerFast, "bert-base-uncased")
print("...success", file=sys.stderr)
# --------------------------------------------- # ---------------------------------------------
def download_clip(): def download_clip():
print("Installing CLIP model...", file=sys.stderr) print("Installing CLIP model...", file=sys.stderr)
version = "openai/clip-vit-large-patch14" version = "openai/clip-vit-large-patch14"
print("Tokenizer...", file=sys.stderr, end="") print("Tokenizer...", file=sys.stderr)
download_from_hf(CLIPTokenizer, version) download_from_hf(CLIPTokenizer, version)
print("Text model...", file=sys.stderr, end="") print("Text model...", file=sys.stderr)
download_from_hf(CLIPTextModel, version) download_from_hf(CLIPTextModel, version)
print("...success", file=sys.stderr)
# --------------------------------------------- # ---------------------------------------------
@ -252,7 +250,7 @@ def download_codeformer():
# --------------------------------------------- # ---------------------------------------------
def download_clipseg(): def download_clipseg():
print("Installing clipseg model for text-based masking...", end="", file=sys.stderr) print("Installing clipseg model for text-based masking...", file=sys.stderr)
CLIPSEG_MODEL = "CIDAS/clipseg-rd64-refined" CLIPSEG_MODEL = "CIDAS/clipseg-rd64-refined"
try: try:
download_from_hf(AutoProcessor, CLIPSEG_MODEL) download_from_hf(AutoProcessor, CLIPSEG_MODEL)
@ -260,7 +258,6 @@ def download_clipseg():
except Exception: except Exception:
print("Error installing clipseg model:") print("Error installing clipseg model:")
print(traceback.format_exc()) print(traceback.format_exc())
print("...success", file=sys.stderr)
# ------------------------------------- # -------------------------------------
@ -276,15 +273,14 @@ def download_safety_checker():
print(traceback.format_exc()) print(traceback.format_exc())
return return
safety_model_id = "CompVis/stable-diffusion-safety-checker" safety_model_id = "CompVis/stable-diffusion-safety-checker"
print("AutoFeatureExtractor...", end="", file=sys.stderr) print("AutoFeatureExtractor...", file=sys.stderr)
download_from_hf(AutoFeatureExtractor, safety_model_id) download_from_hf(AutoFeatureExtractor, safety_model_id)
print("StableDiffusionSafetyChecker...", end="", file=sys.stderr) print("StableDiffusionSafetyChecker...", file=sys.stderr)
download_from_hf(StableDiffusionSafetyChecker, safety_model_id) download_from_hf(StableDiffusionSafetyChecker, safety_model_id)
print("...success", file=sys.stderr)
# ------------------------------------- # -------------------------------------
def download_vaes(precision: str): def download_vaes():
print("Installing stabilityai VAE...", file=sys.stderr) print("Installing stabilityai VAE...", file=sys.stderr)
try: try:
# first the diffusers version # first the diffusers version
@ -292,8 +288,6 @@ def download_vaes(precision: str):
args = dict( args = dict(
cache_dir=global_cache_dir("diffusers"), cache_dir=global_cache_dir("diffusers"),
) )
if precision == "float16":
args.update(torch_dtype=torch.float16, revision="fp16")
if not AutoencoderKL.from_pretrained(repo_id, **args): if not AutoencoderKL.from_pretrained(repo_id, **args):
raise Exception(f"download of {repo_id} failed") raise Exception(f"download of {repo_id} failed")
@ -306,7 +300,6 @@ def download_vaes(precision: str):
model_dir=str(Globals.root / Model_dir / Weights_dir), model_dir=str(Globals.root / Model_dir / Weights_dir),
): ):
raise Exception(f"download of {model_name} failed") raise Exception(f"download of {model_name} failed")
print("...downloaded successfully", file=sys.stderr)
except Exception as e: except Exception as e:
print(f"Error downloading StabilityAI standard VAE: {str(e)}", file=sys.stderr) print(f"Error downloading StabilityAI standard VAE: {str(e)}", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr) print(traceback.format_exc(), file=sys.stderr)
@ -332,8 +325,7 @@ class editOptsForm(npyscreen.FormMultiPage):
old_opts = self.parentApp.invokeai_opts old_opts = self.parentApp.invokeai_opts
first_time = not (Globals.root / Globals.initfile).exists() first_time = not (Globals.root / Globals.initfile).exists()
access_token = HfFolder.get_token() access_token = HfFolder.get_token()
window_width,window_height = get_terminal_size()
window_height, window_width = curses.initscr().getmaxyx()
for i in [ for i in [
"Configure startup settings. You can come back and change these later.", "Configure startup settings. You can come back and change these later.",
"Use ctrl-N and ctrl-P to move to the <N>ext and <P>revious fields.", "Use ctrl-N and ctrl-P to move to the <N>ext and <P>revious fields.",
@ -676,6 +668,8 @@ def run_console_ui(
) -> (Namespace, Namespace): ) -> (Namespace, Namespace):
# parse_args() will read from init file if present # parse_args() will read from init file if present
invokeai_opts = default_startup_options(initfile) invokeai_opts = default_startup_options(initfile)
set_min_terminal_size(MIN_COLS, MIN_LINES)
editApp = EditOptApplication(program_opts, invokeai_opts) editApp = EditOptApplication(program_opts, invokeai_opts)
editApp.run() editApp.run()
if editApp.user_cancelled: if editApp.user_cancelled:
@ -683,7 +677,6 @@ def run_console_ui(
else: else:
return (editApp.new_opts, editApp.user_selections) return (editApp.new_opts, editApp.user_selections)
# ------------------------------------- # -------------------------------------
def write_opts(opts: Namespace, init_file: Path): def write_opts(opts: Namespace, init_file: Path):
""" """
@ -703,6 +696,9 @@ def write_opts(opts: Namespace, init_file: Path):
args_to_skip = re.compile( args_to_skip = re.compile(
"^--?(o|out|no-xformer|xformer|no-ckpt|ckpt|free|no-nsfw|nsfw|prec|max_load|embed|always|ckpt|free_gpu)" "^--?(o|out|no-xformer|xformer|no-ckpt|ckpt|free|no-nsfw|nsfw|prec|max_load|embed|always|ckpt|free_gpu)"
) )
# fix windows paths
opts.outdir = opts.outdir.replace('\\','/')
opts.embedding_path = opts.embedding_path.replace('\\','/')
new_file = f"{init_file}.new" new_file = f"{init_file}.new"
try: try:
lines = [x.strip() for x in open(init_file, "r").readlines()] lines = [x.strip() for x in open(init_file, "r").readlines()]
@ -842,7 +838,7 @@ def main():
download_codeformer() download_codeformer()
download_clipseg() download_clipseg()
download_safety_checker() download_safety_checker()
download_vaes(init_options.precision) download_vaes()
if opt.skip_sd_weights: if opt.skip_sd_weights:
print("\n** SKIPPING DIFFUSION WEIGHTS DOWNLOAD PER USER REQUEST **") print("\n** SKIPPING DIFFUSION WEIGHTS DOWNLOAD PER USER REQUEST **")
@ -853,10 +849,6 @@ def main():
postscript(errors=errors) postscript(errors=errors)
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nGoodbye! Come back soon.") print("\nGoodbye! Come back soon.")
except Exception as e:
print(f'\nA problem occurred during initialization.\nThe error was: "{str(e)}"')
print(traceback.format_exc())
# ------------------------------------- # -------------------------------------
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,18 +2,16 @@
Minimalist updater script. Prompts user for the tag or branch to update to and runs Minimalist updater script. Prompts user for the tag or branch to update to and runs
pip install <path_to_git_source>. pip install <path_to_git_source>.
''' '''
import os
import platform import platform
import requests import requests
import subprocess
from rich import box, print from rich import box, print
from rich.console import Console, group from rich.console import Console, Group, group
from rich.panel import Panel from rich.panel import Panel
from rich.prompt import Prompt from rich.prompt import Prompt
from rich.style import Style from rich.style import Style
from rich.syntax import Syntax
from rich.text import Text from rich.text import Text
from rich.live import Live
from rich.table import Table
from ldm.invoke import __version__ from ldm.invoke import __version__
@ -23,19 +21,17 @@ INVOKE_AI_REL="https://api.github.com/repos/invoke-ai/InvokeAI/releases"
OS = platform.uname().system OS = platform.uname().system
ARCH = platform.uname().machine ARCH = platform.uname().machine
ORANGE_ON_DARK_GREY = Style(bgcolor="grey23", color="orange1")
if OS == "Windows": if OS == "Windows":
# Windows terminals look better without a background colour # Windows terminals look better without a background colour
console = Console(style=Style(color="grey74")) console = Console(style=Style(color="grey74"))
else: else:
console = Console(style=Style(color="grey74", bgcolor="grey23")) console = Console(style=Style(color="grey74", bgcolor="grey19"))
def get_versions()->dict: def get_versions()->dict:
return requests.get(url=INVOKE_AI_REL).json() return requests.get(url=INVOKE_AI_REL).json()
def welcome(versions: dict): def welcome(versions: dict):
@group() @group()
def text(): def text():
yield f'InvokeAI Version: [bold yellow]{__version__}' yield f'InvokeAI Version: [bold yellow]{__version__}'
@ -48,55 +44,45 @@ def welcome(versions: dict):
[3] Manually enter the tag or branch name you wish to update''' [3] Manually enter the tag or branch name you wish to update'''
console.rule() console.rule()
console.print( print(
Panel( Panel(
title="[bold wheat1]InvokeAI Updater", title="[bold wheat1]InvokeAI Updater",
renderable=text(), renderable=text(),
box=box.DOUBLE, box=box.DOUBLE,
expand=True, expand=True,
padding=(1, 2), padding=(1, 2),
style=ORANGE_ON_DARK_GREY, style=Style(bgcolor="grey23", color="orange1"),
subtitle=f"[bold grey39]{OS}-{ARCH}", subtitle=f"[bold grey39]{OS}-{ARCH}",
) )
) )
# console.rule is used instead of console.line to maintain dark background console.line()
# on terminals where light background is the default
console.rule(characters=" ")
def main(): def main():
versions = get_versions() versions = get_versions()
welcome(versions) welcome(versions)
tag = None tag = None
choice = Prompt.ask(Text.from_markup(('[grey74 on grey23]Choice:')),choices=['1','2','3'],default='1') choice = Prompt.ask('Choice:',choices=['1','2','3'],default='1')
if choice=='1': if choice=='1':
tag = versions[0]['tag_name'] tag = versions[0]['tag_name']
elif choice=='2': elif choice=='2':
tag = 'main' tag = 'main'
elif choice=='3': elif choice=='3':
tag = Prompt.ask('[grey74 on grey23]Enter an InvokeAI tag or branch name') tag = Prompt.ask('Enter an InvokeAI tag or branch name')
console.print(Panel(f':crossed_fingers: Upgrading to [yellow]{tag}[/yellow]', box=box.MINIMAL, style=ORANGE_ON_DARK_GREY))
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'
print('')
progress = Table.grid(expand=True) print('')
progress_panel = Panel(progress, box=box.MINIMAL, style=ORANGE_ON_DARK_GREY) if os.system(cmd)==0:
print(f':heavy_check_mark: Upgrade successful')
with subprocess.Popen(['bash', '-c', cmd], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: else:
progress.add_column() print(f':exclamation: [bold red]Upgrade failed[/red bold]')
with Live(progress_panel, console=console, vertical_overflow='visible'):
while proc.poll() is None:
for l in iter(proc.stdout.readline, b''):
progress.add_row(l.decode().strip(), style=ORANGE_ON_DARK_GREY)
if proc.returncode == 0:
console.rule(f':heavy_check_mark: Upgrade successful')
else:
console.rule(f':exclamation: [bold red]Upgrade failed[/red bold]')
if __name__ == "__main__": if __name__ == "__main__":
try: try:
main() main()
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -10,10 +10,8 @@ The work is actually done in backend code in model_install_backend.py.
""" """
import argparse import argparse
import curses
import os import os
import sys import sys
import traceback
from argparse import Namespace from argparse import Namespace
from pathlib import Path from pathlib import Path
from typing import List from typing import List
@ -22,15 +20,23 @@ import npyscreen
import torch import torch
from npyscreen import widget from npyscreen import widget
from omegaconf import OmegaConf from omegaconf import OmegaConf
from shutil import get_terminal_size
from ..devices import choose_precision, choose_torch_device from ..devices import choose_precision, choose_torch_device
from ..globals import Globals, global_config_dir from ..globals import Globals, global_config_dir
from .model_install_backend import (Dataset_path, default_config_file, from .model_install_backend import (Dataset_path, default_config_file,
default_dataset, get_root, default_dataset, get_root,
install_requested_models, install_requested_models,
recommended_datasets) recommended_datasets,
)
from .widgets import (MultiSelectColumns, TextBox, from .widgets import (MultiSelectColumns, TextBox,
OffsetButtonPress, CenteredTitleText) OffsetButtonPress, CenteredTitleText,
set_min_terminal_size,
)
# minimum size for the UI
MIN_COLS = 120
MIN_LINES = 45
class addModelsForm(npyscreen.FormMultiPage): class addModelsForm(npyscreen.FormMultiPage):
# for responsive resizing - disabled # for responsive resizing - disabled
@ -50,7 +56,7 @@ class addModelsForm(npyscreen.FormMultiPage):
super().__init__(parentApp=parentApp, name=name, *args, **keywords) super().__init__(parentApp=parentApp, name=name, *args, **keywords)
def create(self): def create(self):
window_height, window_width = curses.initscr().getmaxyx() window_width, window_height = get_terminal_size()
starter_model_labels = self._get_starter_model_labels() starter_model_labels = self._get_starter_model_labels()
recommended_models = [ recommended_models = [
x x
@ -249,7 +255,7 @@ class addModelsForm(npyscreen.FormMultiPage):
) )
def _get_starter_model_labels(self) -> List[str]: def _get_starter_model_labels(self) -> List[str]:
window_height, window_width = curses.initscr().getmaxyx() window_width, window_height = get_terminal_size()
label_width = 25 label_width = 25
checkbox_width = 4 checkbox_width = 4
spacing_width = 2 spacing_width = 2
@ -268,7 +274,7 @@ class addModelsForm(npyscreen.FormMultiPage):
] ]
def _get_columns(self) -> int: def _get_columns(self) -> int:
window_height, window_width = curses.initscr().getmaxyx() window_width, window_height = get_terminal_size()
cols = ( cols = (
4 4
if window_width > 240 if window_width > 240
@ -362,7 +368,6 @@ class AddModelApplication(npyscreen.NPSAppManaged):
"MAIN", addModelsForm, name="Install Stable Diffusion Models" "MAIN", addModelsForm, name="Install Stable Diffusion Models"
) )
# -------------------------------------------------------- # --------------------------------------------------------
def process_and_execute(opt: Namespace, selections: Namespace): def process_and_execute(opt: Namespace, selections: Namespace):
models_to_remove = [ models_to_remove = [
@ -409,6 +414,7 @@ def select_and_download_models(opt: Namespace):
precision=precision, precision=precision,
) )
else: else:
set_min_terminal_size(MIN_COLS, MIN_LINES)
installApp = AddModelApplication() installApp = AddModelApplication()
installApp.run() installApp.run()
@ -475,7 +481,7 @@ def main():
sys.exit(-1) sys.exit(-1)
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nGoodbye! Come back soon.") print("\nGoodbye! Come back soon.")
except (widget.NotEnoughSpaceForWidget, Exception) as e: except widget.NotEnoughSpaceForWidget as e:
if str(e).startswith("Height of 1 allocated"): if str(e).startswith("Height of 1 allocated"):
print( print(
"** Insufficient vertical space for the interface. Please make your window taller and try again" "** Insufficient vertical space for the interface. Please make your window taller and try again"
@ -484,11 +490,6 @@ def main():
print( print(
"** Insufficient horizontal space for the interface. Please make your window wider and try again." "** Insufficient horizontal space for the interface. Please make your window wider and try again."
) )
else:
print(f"** An error has occurred: {str(e)}")
traceback.print_exc()
sys.exit(-1)
# ------------------------------------- # -------------------------------------
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -67,6 +67,9 @@ def install_requested_models(
purge_deleted: bool = False, purge_deleted: bool = False,
config_file_path: Path = None, config_file_path: Path = None,
): ):
'''
Entry point for installing/deleting starter models, or installing external models.
'''
config_file_path=config_file_path or default_config_file() config_file_path=config_file_path or default_config_file()
if not config_file_path.exists(): if not config_file_path.exists():
open(config_file_path,'w') open(config_file_path,'w')
@ -117,14 +120,15 @@ def install_requested_models(
argument = '--autoconvert' if convert_to_diffusers else '--autoimport' argument = '--autoconvert' if convert_to_diffusers else '--autoimport'
initfile = Path(Globals.root, Globals.initfile) initfile = Path(Globals.root, Globals.initfile)
replacement = Path(Globals.root, f'{Globals.initfile}.new') replacement = Path(Globals.root, f'{Globals.initfile}.new')
directory = str(scan_directory).replace('\\','/')
with open(initfile,'r') as input: with open(initfile,'r') as input:
with open(replacement,'w') as output: with open(replacement,'w') as output:
while line := input.readline(): while line := input.readline():
if not line.startswith(argument): if not line.startswith(argument):
output.writelines([line]) output.writelines([line])
output.writelines([f'{argument} {str(scan_directory)}']) output.writelines([f'{argument} {directory}'])
os.replace(replacement,initfile) os.replace(replacement,initfile)
# ------------------------------------- # -------------------------------------
def yes_or_no(prompt: str, default_yes=True): def yes_or_no(prompt: str, default_yes=True):
default = "y" if default_yes else "n" default = "y" if default_yes else "n"
@ -231,7 +235,6 @@ def _download_ckpt_weights(mconfig: DictConfig, access_token: str) -> Path:
def download_from_hf( def download_from_hf(
model_class: object, model_name: str, cache_subdir: Path = Path("hub"), **kwargs model_class: object, model_name: str, cache_subdir: Path = Path("hub"), **kwargs
): ):
print("", file=sys.stderr) # to prevent tqdm from overwriting
path = global_cache_dir(cache_subdir) path = global_cache_dir(cache_subdir)
model = model_class.from_pretrained( model = model_class.from_pretrained(
model_name, model_name,

View File

@ -2,8 +2,34 @@
Widget class definitions used by model_select.py, merge_diffusers.py and textual_inversion.py Widget class definitions used by model_select.py, merge_diffusers.py and textual_inversion.py
''' '''
import math import math
import platform
import npyscreen import npyscreen
import os
import sys
import curses import curses
import struct
from shutil import get_terminal_size
# -------------------------------------
def set_terminal_size(columns: int, lines: int):
OS = platform.uname().system
if OS=="Windows":
os.system(f'mode con: cols={columns} lines={lines}')
elif OS in ['Darwin', 'Linux']:
import termios
import fcntl
winsize = struct.pack("HHHH", lines, columns, 0, 0)
fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSWINSZ, winsize)
sys.stdout.write("\x1b[8;{rows};{cols}t".format(rows=lines, cols=columns))
sys.stdout.flush()
def set_min_terminal_size(min_cols: int, min_lines: int):
# make sure there's enough room for the ui
term_cols, term_lines = get_terminal_size()
cols = max(term_cols, min_cols)
lines = max(term_lines, min_lines)
set_terminal_size(cols,lines)
class IntSlider(npyscreen.Slider): class IntSlider(npyscreen.Slider):
def translate_value(self): def translate_value(self):
@ -23,7 +49,6 @@ class CenteredTitleText(npyscreen.TitleText):
maxy, maxx = self.parent.curses_pad.getmaxyx() maxy, maxx = self.parent.curses_pad.getmaxyx()
label = self.name label = self.name
self.relx = (maxx - len(label)) // 2 self.relx = (maxx - len(label)) // 2
begin_entry_at = -self.relx + 2
# ------------------------------------- # -------------------------------------
class CenteredButtonPress(npyscreen.ButtonPress): class CenteredButtonPress(npyscreen.ButtonPress):

View File

@ -19,15 +19,7 @@ from typing import Union
Globals = Namespace() Globals = Namespace()
# This is usually overwritten by the command line and/or environment variables # Where to look for the initialization file and other key components
if os.environ.get('INVOKEAI_ROOT'):
Globals.root = osp.abspath(os.environ.get('INVOKEAI_ROOT'))
elif os.environ.get('VIRTUAL_ENV'):
Globals.root = osp.abspath(osp.join(os.environ.get('VIRTUAL_ENV'), '..'))
else:
Globals.root = osp.abspath(osp.expanduser('~/invokeai'))
# Where to look for the initialization file
Globals.initfile = 'invokeai.init' Globals.initfile = 'invokeai.init'
Globals.models_file = 'models.yaml' Globals.models_file = 'models.yaml'
Globals.models_dir = 'models' Globals.models_dir = 'models'
@ -35,6 +27,20 @@ Globals.config_dir = 'configs'
Globals.autoscan_dir = 'weights' Globals.autoscan_dir = 'weights'
Globals.converted_ckpts_dir = 'converted_ckpts' Globals.converted_ckpts_dir = 'converted_ckpts'
# Set the default root directory. This can be overwritten by explicitly
# passing the `--root <directory>` argument on the command line.
# logic is:
# 1) use INVOKEAI_ROOT environment variable (no check for this being a valid directory)
# 2) use VIRTUAL_ENV environment variable, with a check for initfile being there
# 3) use ~/invokeai
if os.environ.get('INVOKEAI_ROOT'):
Globals.root = osp.abspath(os.environ.get('INVOKEAI_ROOT'))
elif os.environ.get('VIRTUAL_ENV') and Path(os.environ.get('VIRTUAL_ENV'),'..',Globals.initfile).exists():
Globals.root = osp.abspath(osp.join(os.environ.get('VIRTUAL_ENV'), '..'))
else:
Globals.root = osp.abspath(osp.expanduser('~/invokeai'))
# Try loading patchmatch # Try loading patchmatch
Globals.try_patchmatch = True Globals.try_patchmatch = True

View File

@ -428,8 +428,6 @@ class ModelManager(object):
torch.cuda.reset_peak_memory_stats() torch.cuda.reset_peak_memory_stats()
torch.cuda.empty_cache() torch.cuda.empty_cache()
tic = time.time()
# this does the work # this does the work
if not os.path.isabs(config): if not os.path.isabs(config):
config = os.path.join(Globals.root, config) config = os.path.join(Globals.root, config)
@ -642,21 +640,18 @@ class ModelManager(object):
models.yaml file. models.yaml file.
""" """
model_name = model_name or Path(repo_or_path).stem model_name = model_name or Path(repo_or_path).stem
description = model_description or f"imported diffusers model {model_name}" model_description = model_description or f"Imported diffusers model {model_name}"
new_config = dict( new_config = dict(
description=model_description, description=model_description,
vae=vae, vae=vae,
format="diffusers", format="diffusers",
) )
print(f"DEBUG: here i am 1")
if isinstance(repo_or_path, Path) and repo_or_path.exists(): if isinstance(repo_or_path, Path) and repo_or_path.exists():
new_config.update(path=str(repo_or_path)) new_config.update(path=str(repo_or_path))
else: else:
new_config.update(repo_id=repo_or_path) new_config.update(repo_id=repo_or_path)
print(f"DEBUG: here i am 2")
self.add_model(model_name, new_config, True) self.add_model(model_name, new_config, True)
print(f"DEBUG: config = {self.config}")
if commit_to_conf: if commit_to_conf:
self.commit(commit_to_conf) self.commit(commit_to_conf)
return model_name return model_name
@ -704,7 +699,7 @@ class ModelManager(object):
model_name or Path(weights).stem model_name or Path(weights).stem
) # note this gives ugly pathnames if used on a URL without a Content-Disposition header ) # note this gives ugly pathnames if used on a URL without a Content-Disposition header
model_description = ( model_description = (
model_description or f"imported stable diffusion weights file {model_name}" model_description or f"Imported stable diffusion weights file {model_name}"
) )
new_config = dict( new_config = dict(
weights=str(weights_path), weights=str(weights_path),
@ -840,7 +835,7 @@ class ModelManager(object):
thing, commit_to_conf=commit_to_conf thing, commit_to_conf=commit_to_conf
) )
pipeline, _, _, _ = self._load_diffusers_model(self.config[model_name]) pipeline, _, _, _ = self._load_diffusers_model(self.config[model_name])
return model_name
else: else:
print( print(
f"** {thing}: Unknown thing. Please provide a URL, file path, directory or HuggingFace repo_id" f"** {thing}: Unknown thing. Please provide a URL, file path, directory or HuggingFace repo_id"

View File

@ -38,7 +38,7 @@ dependencies = [
"albumentations", "albumentations",
"click", "click",
"clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip", "clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip",
"compel>=0.1.6", "compel==0.1.7",
"datasets", "datasets",
"diffusers[torch]~=0.13", "diffusers[torch]~=0.13",
"dnspython==2.2.1", "dnspython==2.2.1",