Compare commits

...

37 Commits

Author SHA1 Message Date
1010837cfd Merge pull request #999 from cmdr2/beta
Beta
2023-03-12 09:57:17 +05:30
aec7e6d32e changelog 2023-03-11 12:38:25 +05:30
bb0f7cd1cd Load mask from file 2023-03-11 12:37:51 +05:30
5dd92b1d3f sdkit 1.0.47 - mps buffer fix 2023-03-11 10:40:45 +05:30
7548f7cdbb revert mps buffer fix 2023-03-11 10:27:57 +05:30
44da3d26f3 sdkit 1.0.45 - fix buffers used for mac mps 2023-03-11 10:24:01 +05:30
7c01c48297 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-03-11 09:27:36 +05:30
7826870d99 Logo change 2023-03-11 09:27:04 +05:30
bdb6649722 Merge pull request #995 from cmdr2/beta
Beta
2023-03-11 09:08:01 +05:30
31ee73c5eb Merge pull request #994 from cmdr2/main
Main
2023-03-11 09:06:26 +05:30
0fd706f392 Bring back the ability to run on CPU on PCs with CUDA-compatible GPUs 2023-03-10 10:19:55 +05:30
8907dabd4c Merge pull request #987 from michaelgallacher/beta
Hotfix rollup
2023-03-10 10:16:21 +05:30
1496d6ec51 Hotfix rollup
* Reverts the recent 'torch.mps' changes since .mps is only available in torch v2.0, which isn't yet released.
* Includes Hotfitx 984
* Enables 'cpu-only' option when running on Apple silicon.
2023-03-09 14:10:29 -07:00
d1a45ed9ac Report the device GPU memory (and existence) correctly for mps (mac) 2023-03-09 21:15:00 +05:30
f73d28ac10 changelog 2023-03-09 18:26:03 +05:30
1b7af75d4e Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-03-09 18:21:47 +05:30
ed0d78bf73 changelog 2023-03-09 18:21:37 +05:30
046e2acae1 Merge pull request #982 from cmdr2/beta
Beta
2023-03-09 17:58:41 +05:30
b6efa71efc Merge pull request #981 from cmdr2/main
Main
2023-03-09 17:57:37 +05:30
3bb835b5e1 Support custom modifiers with images (#912)
* Support custom modifiers with images

* Add dash support

* Avoid needing to upgrade fastapi

* Revert gitignore
2023-03-08 20:52:31 +05:30
fbeecda38c Merge pull request #963 from JeLuF/patch-18
Remove AVX check
2023-03-08 13:37:59 +05:30
942904186a changelog 2023-03-08 10:02:05 +05:30
737a81570a Merge pull request #975 from michaelgallacher/beta
Add support for MPS when running on Apple silicon
2023-03-08 10:00:10 +05:30
3691aeb8e1 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-03-08 09:58:01 +05:30
32d8f4d24b sdkit 1.0.44 - mps support for mac 2023-03-08 09:57:45 +05:30
30ccd35dd3 Merge pull request #976 from cmdr2/beta
Don't need to use bootstrap.bat after installation
2023-03-08 09:19:13 +05:30
11265c4034 Add support for MPS when running on Apple silicon
Changes:

* autodetect if MPS is available and the pytorch version has MPS support.
* change logic from "is the device CPU?" to "is the device not CUDA?".
* set PYTORCH_ENABLE_MPS_FALLBACK=1

Known issues:

* Some samplers (eg DDIM) will fail on MPS unless forced to CPU-only mode
2023-03-07 14:57:37 -07:00
8acff43028 Merge pull request #973 from cmdr2/main
Main
2023-03-07 22:06:06 +05:30
660aa4f4ab Don't include bootstrap.bat in the new installer, since we don't need micromamba, and we don't need to download and install conda/git separately 2023-03-07 21:33:38 +05:30
1384c2f1bc Keep bootstrap.bat in the repo, until the new installer releases. However it won't be copied or used after installation. 2023-03-07 21:17:04 +05:30
459b9428d4 Remove bootstrap.bat, since it's only needed during installation (and the current installer contains it, and this installer will soon be phased out) 2023-03-07 21:16:05 +05:30
a82f16958b Project name changes in NSIS installer 2023-03-07 19:43:04 +05:30
b9f436812b Download the default CLIP model during NSIS installation; Allow setting the path to an existing installation, which will be used for creating the installer executable 2023-03-07 19:40:58 +05:30
88e3831bc6 Remove AVX check
https://discord.com/channels/1014774730907209781/1064237509913084087/1064237509913084087
2023-03-05 00:13:07 +01:00
2a597fcad7 Single-file installer - Include all the dependencies from an installed folder; Download the default models using the NSCurl plugin 2023-03-04 18:02:30 +05:30
6158f49400 Workaround to fix the broken Rabbit Hole plugin 2023-03-02 13:56:39 +05:30
9dd819e193 Workaround to fix the broken Rabbit Hole plugin 2023-03-02 13:55:53 +05:30
25 changed files with 273 additions and 62 deletions

View File

@ -3,22 +3,28 @@
## v2.5
### Major Changes
- **Nearly twice as fast** - significantly faster speed of image generation. We're now pretty close to automatic1111's speed. Code contributions are welcome to make our project even faster: https://github.com/easydiffusion/sdkit/#is-it-fast
- **Mac M1/M2 support** - Experimental support for Mac M1/M2. Thanks @michaelgallacher, @JeLuf and vishae.
- **Full support for Stable Diffusion 2.1 (including CPU)** - supports loading v1.4 or v2.0 or v2.1 models seamlessly. No need to enable "Test SD2", and no need to add `sd2_` to your SD 2.0 model file names. Works on CPU as well.
- **Memory optimized Stable Diffusion 2.1** - you can now use Stable Diffusion 2.1 models, with the same low VRAM optimizations that we've always had for SD 1.4. Please note, the SD 2.0 and 2.1 models require more GPU and System RAM, as compared to the SD 1.4 and 1.5 models.
- **11 new samplers!** - explore the new samplers, some of which can generate great images in less than 10 inference steps! We've added the Karras and UniPC samplers.
- **Model Merging** - You can now merge two models (`.ckpt` or `.safetensors`) and output `.ckpt` or `.safetensors` models, optionally in `fp16` precision. Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging
- **11 new samplers!** - explore the new samplers, some of which can generate great images in less than 10 inference steps! We've added the Karras and UniPC samplers. Thanks @Schorny for the UniPC samplers.
- **Model Merging** - You can now merge two models (`.ckpt` or `.safetensors`) and output `.ckpt` or `.safetensors` models, optionally in `fp16` precision. Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging . Thanks @JeLuf.
- **Fast loading/unloading of VAEs** - No longer needs to reload the entire Stable Diffusion model, each time you change the VAE
- **Database of known models** - automatically picks the right configuration for known models. E.g. we automatically detect and apply "v" parameterization (required for some SD 2.0 models), and "fp32" attention precision (required for some SD 2.1 models).
- **Color correction for img2img** - an option to preserve the color profile (histogram) of the initial image. This is especially useful if you're getting red-tinted images after inpainting/masking.
- **Three GPU Memory Usage Settings** - `High` (fastest, maximum VRAM usage), `Balanced` (default - almost as fast, significantly lower VRAM usage), `Low` (slowest, very low VRAM usage). The `Low` setting is applied automatically for GPUs with less than 4 GB of VRAM.
- **Find models in sub-folders** - This allows you to organize your models into sub-folders inside `models/stable-diffusion`, instead of keeping them all in a single folder.
- **Save metadata as JSON** - You can now save the metadata files as either text or json files (choose in the Settings tab).
- **Find models in sub-folders** - This allows you to organize your models into sub-folders inside `models/stable-diffusion`, instead of keeping them all in a single folder. Thanks @patriceac and @ogmaresca.
- **Custom Modifier Categories** - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca.
- **Embed metadata, or save as TXT/JSON** - You can now embed the metadata directly into the images, or save them as text or json files (choose in the Settings tab). Thanks @patriceac.
- **Major rewrite of the code** - Most of the codebase has been reorganized and rewritten, to make it more manageable and easier for new developers to contribute features. We've separated our core engine into a new project called `sdkit`, which allows anyone to easily integrate Stable Diffusion (and related modules like GFPGAN etc) into their programming projects (via a simple `pip install sdkit`): https://github.com/easydiffusion/sdkit/
- **Name change** - Last, and probably the least, the UI is now called "Easy Diffusion". It indicates the focus of this project - an easy way for people to play with Stable Diffusion.
Our focus continues to remain on an easy installation experience, and an easy user-interface. While still remaining pretty powerful, in terms of features and speed.
### Detailed changelog
* 2.5.24 - 11 Mar 2023 - Button to load an image mask from a file.
* 2.5.24 - 10 Mar 2023 - Logo change. Image credit: @lazlo_vii.
* 2.5.23 - 8 Mar 2023 - Experimental support for Mac M1/M2. Thanks @michaelgallacher, @JeLuf and vishae!
* 2.5.23 - 8 Mar 2023 - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). More details - https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca.
* 2.5.22 - 28 Feb 2023 - Minor styling changes to UI buttons, and the models dropdown.
* 2.5.22 - 28 Feb 2023 - Lots of UI-related bug fixes. Thanks @patriceac.
* 2.5.21 - 22 Feb 2023 - An option to control the size of the image thumbnails. You can use the `Display options` in the top-right corner to change this. Thanks @JeLuf.

1
NSIS/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.exe

BIN
NSIS/cyborg_flower_girl.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

BIN
NSIS/cyborg_flower_girl.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

1
NSIS/nsisconf.nsh Normal file
View File

@ -0,0 +1 @@
!define EXISTING_INSTALLATION_DIR "D:\path\to\installed\easy-diffusion"

View File

@ -1,20 +1,24 @@
; Script generated by the HM NIS Edit Script Wizard.
Target x86-unicode
Target amd64-unicode
Unicode True
!AddPluginDir /x86-unicode "."
SetCompressor /FINAL lzma
RequestExecutionLevel user
!AddPluginDir /amd64-unicode "."
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "Stable Diffusion UI"
!define PRODUCT_VERSION "Installer 2.35"
!define PRODUCT_NAME "Easy Diffusion"
!define PRODUCT_VERSION "2.5"
!define PRODUCT_PUBLISHER "cmdr2 and contributors"
!define PRODUCT_WEB_SITE "https://stable-diffusion-ui.github.io"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Cmdr2\App Paths\installer.exe"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Easy Diffusion\App Paths\installer.exe"
; MUI 1.67 compatible ------
!include "MUI.nsh"
!include "LogicLib.nsh"
!include "nsDialogs.nsh"
!include "nsisconf.nsh"
Var Dialog
Var Label
Var Button
@ -106,7 +110,7 @@ Function DirectoryLeave
StrCpy $5 $INSTDIR 3
System::Call 'Kernel32::GetVolumeInformation(t "$5",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r1,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
${AndIf} $1 == "NTFS"
${AndIf} $1 != "NTFS"
MessageBox mb_ok "$5 has filesystem type '$1'.$\nOnly NTFS filesystems are supported.$\nPlease choose a different drive."
Abort
${EndIf}
@ -140,7 +144,7 @@ Function MediaPackDialog
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 48u "The Windows Media Feature Pack is missing on this computer. It is required for the Stable Diffusion UI.$\nYou can continue the installation after installing the Windows Media Feature Pack."
${NSD_CreateLabel} 0 0 100% 48u "The Windows Media Feature Pack is missing on this computer. It is required for Easy Diffusion.$\nYou can continue the installation after installing the Windows Media Feature Pack."
Pop $Label
${NSD_CreateButton} 10% 49u 80% 12u "Download Meda Feature Pack from Microsoft"
@ -157,12 +161,12 @@ FunctionEnd
; MUI Settings
;---------------------------------------------------------------------------------------------------------
!define MUI_ABORTWARNING
!define MUI_ICON "sd.ico"
!define MUI_ICON "cyborg_flower_girl.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "astro.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP "cyborg_flower_girl.bmp"
; Welcome page
!define MUI_WELCOMEPAGE_TEXT "This installer will guide you through the installation of Stable Diffusion UI.$\n$\n\
!define MUI_WELCOMEPAGE_TEXT "This installer will guide you through the installation of Easy Diffusion.$\n$\n\
Click Next to continue."
!insertmacro MUI_PAGE_WELCOME
Page custom MediaPackDialog
@ -188,8 +192,8 @@ Page custom MediaPackDialog
;---------------------------------------------------------------------------------------------------------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "Install Stable Diffusion UI.exe"
InstallDir "C:\Stable-Diffusion-UI\"
OutFile "Install Easy Diffusion.exe"
InstallDir "C:\EasyDiffusion\"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
@ -200,15 +204,40 @@ Section "MainSection" SEC01
File "..\CreativeML Open RAIL-M License"
File "..\How to install and run.txt"
File "..\LICENSE"
File "..\Start Stable Diffusion UI.cmd"
File "..\scripts\Start Stable Diffusion UI.cmd"
File /r "${EXISTING_INSTALLATION_DIR}\installer_files"
File /r "${EXISTING_INSTALLATION_DIR}\profile"
File /r "${EXISTING_INSTALLATION_DIR}\sd-ui-files"
SetOutPath "$INSTDIR\scripts"
File "..\scripts\bootstrap.bat"
File "..\scripts\install_status.txt"
File "${EXISTING_INSTALLATION_DIR}\scripts\install_status.txt"
File "..\scripts\on_env_start.bat"
File "C:\windows\system32\curl.exe"
CreateDirectory "$INSTDIR\profile"
CreateDirectory "$SMPROGRAMS\Stable Diffusion UI"
CreateShortCut "$SMPROGRAMS\Stable Diffusion UI\Start Stable Diffusion UI.lnk" "$INSTDIR\Start Stable Diffusion UI.cmd"
CreateDirectory "$INSTDIR\models"
CreateDirectory "$INSTDIR\models\stable-diffusion"
CreateDirectory "$INSTDIR\models\gfpgan"
CreateDirectory "$INSTDIR\models\realesrgan"
CreateDirectory "$INSTDIR\models\vae"
CreateDirectory "$SMPROGRAMS\Easy Diffusion"
CreateShortCut "$SMPROGRAMS\Easy Diffusion\Easy Diffusion.lnk" "$INSTDIR\Start Stable Diffusion UI.cmd"
DetailPrint 'Downloading the Stable Diffusion 1.4 model...'
NScurl::http get "https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt" "$INSTDIR\models\stable-diffusion\sd-v1-4.ckpt" /CANCEL /INSIST /END
DetailPrint 'Downloading the GFPGAN model...'
NScurl::http get "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth" "$INSTDIR\models\gfpgan\GFPGANv1.3.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the RealESRGAN_x4plus model...'
NScurl::http get "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth" "$INSTDIR\models\realesrgan\RealESRGAN_x4plus.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the RealESRGAN_x4plus_anime model...'
NScurl::http get "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth" "$INSTDIR\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the default VAE (sd-vae-ft-mse-original) model...'
NScurl::http get "https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.ckpt" "$INSTDIR\models\vae\vae-ft-mse-840000-ema-pruned.ckpt" /CANCEL /INSIST /END
DetailPrint 'Downloading the CLIP model (clip-vit-large-patch14)...'
NScurl::http get "https://huggingface.co/openai/clip-vit-large-patch14/resolve/8d052a0f05efbaefbc9e8786ba291cfdf93e5bff/pytorch_model.bin" "$INSTDIR\profile\.cache\huggingface\hub\models--openai--clip-vit-large-patch14\snapshots\8d052a0f05efbaefbc9e8786ba291cfdf93e5bff\pytorch_model.bin" /CANCEL /INSIST /END
SectionEnd
;---------------------------------------------------------------------------------------------------------
@ -254,7 +283,7 @@ Function .onInit
${If} $4 < "8000"
MessageBox MB_OK|MB_ICONEXCLAMATION "Warning!$\n$\nYour system has less than 8GB of memory (RAM).$\n$\n\
You can still try to install Stable Diffusion UI,$\nbut it might have problems to start, or run$\nvery slowly."
You can still try to install Easy Diffusion,$\nbut it might have problems to start, or run$\nvery slowly."
${EndIf}
FunctionEnd

View File

@ -25,15 +25,12 @@ if exist "on_sd_start.bat" (
@rem set legacy installer's PATH, if it exists
if exist "installer" set PATH=%cd%\installer;%cd%\installer\Library\bin;%cd%\installer\Scripts;%cd%\installer\Library\usr\bin;%PATH%
@rem Setup the packages required for the installer
call scripts\bootstrap.bat
@rem set new installer's PATH, if it downloaded any packages
if exist "installer_files\env" set PATH=%cd%\installer_files\env;%cd%\installer_files\env\Library\bin;%cd%\installer_files\env\Scripts;%cd%\installer_files\Library\usr\bin;%PATH%
set PYTHONPATH=%cd%\installer;%cd%\installer_files\env
@rem Test the bootstrap
@rem Test the core requirements
call where git
call git --version

View File

@ -30,9 +30,6 @@ if ! which tar; then fail "'tar' not found. Please install tar."; fi
if ! which bzip2; then fail "'bzip2' not found. Please install bzip2."; fi
if pwd | grep ' '; then fail "The installation directory's path contains a space character. Conda will fail to install. Please change the directory."; fi
if [ -f /proc/cpuinfo ]; then
if ! cat /proc/cpuinfo | grep avx | uniq; then fail "Your CPU doesn't support AVX."; fi
fi
# https://mamba.readthedocs.io/en/latest/installation.html
if [ "$OS_NAME" == "linux" ] && [ "$OS_ARCH" == "arm64" ]; then OS_ARCH="aarch64"; fi

View File

View File

@ -52,7 +52,6 @@ if "%update_branch%"=="" (
@xcopy sd-ui-files\ui ui /s /i /Y /q
@copy sd-ui-files\scripts\on_sd_start.bat scripts\ /Y
@copy sd-ui-files\scripts\bootstrap.bat scripts\ /Y
@copy sd-ui-files\scripts\check_modules.py scripts\ /Y
@copy "sd-ui-files\scripts\Start Stable Diffusion UI.cmd" . /Y
@copy "sd-ui-files\scripts\Developer Console.cmd" . /Y

View File

@ -95,7 +95,7 @@ if "%ERRORLEVEL%" EQU "0" (
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
call python -m pip install --upgrade sdkit==1.0.43 -q || (
call python -m pip install --upgrade sdkit==1.0.47 -q || (
echo "Error updating sdkit"
)
)
@ -106,7 +106,7 @@ if "%ERRORLEVEL%" EQU "0" (
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
call python -m pip install sdkit==1.0.43 || (
call python -m pip install sdkit==1.0.47 || (
echo "Error installing sdkit. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
exit /b

View File

@ -81,7 +81,7 @@ if python ../scripts/check_modules.py sdkit sdkit.models ldm transformers numpy
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
python -m pip install --upgrade sdkit==1.0.43 -q
python -m pip install --upgrade sdkit==1.0.47 -q
fi
else
echo "Installing sdkit: https://pypi.org/project/sdkit/"
@ -89,7 +89,7 @@ else
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
if python -m pip install sdkit==1.0.43 ; then
if python -m pip install sdkit==1.0.47 ; then
echo "Installed."
else
fail "sdkit install failed"
@ -285,6 +285,7 @@ printf "\n\nEasy Diffusion installation complete, starting the server!\n\n"
SD_PATH=`pwd`
export PYTORCH_ENABLE_MPS_FALLBACK=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
echo "PYTHONPATH=$PYTHONPATH"

View File

@ -5,6 +5,7 @@ import json
import traceback
import logging
import shlex
import urllib
from rich.logging import RichHandler
from sdkit.utils import log as sdkit_log # hack, so we can overwrite the log config
@ -54,6 +55,10 @@ APP_CONFIG_DEFAULTS = {
},
}
IMAGE_EXTENSIONS = [".png", ".apng", ".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".jxl", ".gif", ".webp", ".avif", ".svg"]
CUSTOM_MODIFIERS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "modifiers"))
CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS=[".portrait", "_portrait", " portrait", "-portrait"]
CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS=[".landscape", "_landscape", " landscape", "-landscape"]
def init():
os.makedirs(USER_UI_PLUGINS_DIR, exist_ok=True)
@ -234,3 +239,90 @@ def open_browser():
import webbrowser
webbrowser.open(f"http://localhost:{port}")
def get_image_modifiers():
modifiers_json_path = os.path.join(SD_UI_DIR, "modifiers.json")
modifier_categories = {}
original_category_order=[]
with open(modifiers_json_path, "r", encoding="utf-8") as f:
modifiers_file = json.load(f)
# The trailing slash is needed to support symlinks
if not os.path.isdir(f"{CUSTOM_MODIFIERS_DIR}/"):
return modifiers_file
# convert modifiers from a list of objects to a dict of dicts
for category_item in modifiers_file:
category_name = category_item['category']
original_category_order.append(category_name)
category = {}
for modifier_item in category_item['modifiers']:
modifier = {}
for preview_item in modifier_item['previews']:
modifier[preview_item['name']] = preview_item['path']
category[modifier_item['modifier']] = modifier
modifier_categories[category_name] = category
def scan_directory(directory_path: str, category_name="Modifiers"):
for entry in os.scandir(directory_path):
if entry.is_file():
file_extension = list(filter(lambda e: entry.name.endswith(e), IMAGE_EXTENSIONS))
if len(file_extension) == 0:
continue
modifier_name = entry.name[: -len(file_extension[0])]
modifier_path = f"custom/{entry.path[len(CUSTOM_MODIFIERS_DIR) + 1:]}"
# URL encode path segments
modifier_path = "/".join(map(lambda segment: urllib.parse.quote(segment), modifier_path.split("/")))
is_portrait = True
is_landscape = True
portrait_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS))
landscape_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS))
if len(portrait_extension) > 0:
is_landscape = False
modifier_name = modifier_name[: -len(portrait_extension[0])]
elif len(landscape_extension) > 0:
is_portrait = False
modifier_name = modifier_name[: -len(landscape_extension[0])]
if (category_name not in modifier_categories):
modifier_categories[category_name] = {}
category = modifier_categories[category_name]
if (modifier_name not in category):
category[modifier_name] = {}
if (is_portrait or "portrait" not in category[modifier_name]):
category[modifier_name]["portrait"] = modifier_path
if (is_landscape or "landscape" not in category[modifier_name]):
category[modifier_name]["landscape"] = modifier_path
elif entry.is_dir():
scan_directory(
entry.path,
entry.name if directory_path==CUSTOM_MODIFIERS_DIR else f"{category_name}/{entry.name}",
)
scan_directory(CUSTOM_MODIFIERS_DIR)
custom_categories = sorted(
[cn for cn in modifier_categories.keys() if cn not in original_category_order],
key=str.casefold,
)
# convert the modifiers back into a list of objects
modifier_categories_list = []
for category_name in [*original_category_order, *custom_categories]:
category = { 'category': category_name, 'modifiers': [] }
for modifier_name in sorted(modifier_categories[category_name].keys(), key=str.casefold):
modifier = { 'modifier': modifier_name, 'previews': [] }
for preview_name, preview_path in modifier_categories[category_name][modifier_name].items():
modifier['previews'].append({ 'name': preview_name, 'path': preview_path })
category['modifiers'].append(modifier)
modifier_categories_list.append(category)
return modifier_categories_list

View File

@ -1,4 +1,5 @@
import os
import platform
import torch
import traceback
import re
@ -21,20 +22,20 @@ mem_free_threshold = 0
def get_device_delta(render_devices, active_devices):
"""
render_devices: 'cpu', or 'auto' or ['cuda:N'...]
active_devices: ['cpu', 'cuda:N'...]
render_devices: 'cpu', or 'auto', or 'mps' or ['cuda:N'...]
active_devices: ['cpu', 'mps', 'cuda:N'...]
"""
if render_devices in ("cpu", "auto"):
if render_devices in ("cpu", "auto", "mps"):
render_devices = [render_devices]
elif render_devices is not None:
if isinstance(render_devices, str):
render_devices = [render_devices]
if isinstance(render_devices, list) and len(render_devices) > 0:
render_devices = list(filter(lambda x: x.startswith("cuda:"), render_devices))
render_devices = list(filter(lambda x: x.startswith("cuda:") or x == "mps", render_devices))
if len(render_devices) == 0:
raise Exception(
'Invalid render_devices value in config.json. Valid: {"render_devices": ["cuda:0", "cuda:1"...]}, or {"render_devices": "cpu"} or {"render_devices": "auto"}'
'Invalid render_devices value in config.json. Valid: {"render_devices": ["cuda:0", "cuda:1"...]}, or {"render_devices": "cpu"} or {"render_devices": "mps"} or {"render_devices": "auto"}'
)
render_devices = list(filter(lambda x: is_device_compatible(x), render_devices))
@ -63,10 +64,26 @@ def get_device_delta(render_devices, active_devices):
return devices_to_start, devices_to_stop
def is_mps_available():
return (
platform.system() == "Darwin"
and hasattr(torch.backends, "mps")
and torch.backends.mps.is_available()
and torch.backends.mps.is_built()
)
def is_cuda_available():
return torch.cuda.is_available()
def auto_pick_devices(currently_active_devices):
global mem_free_threshold
if not torch.cuda.is_available():
if is_mps_available():
return ["mps"]
if not is_cuda_available():
return ["cpu"]
device_count = torch.cuda.device_count()
@ -115,11 +132,11 @@ def device_init(context, device):
validate_device_id(device, log_prefix="device_init")
if device == "cpu":
context.device = "cpu"
if "cuda" not in device:
context.device = device
context.device_name = get_processor_name()
context.half_precision = False
log.debug(f"Render device CPU available as {context.device_name}")
log.debug(f"Render device available as {context.device_name}")
return
context.device_name = torch.cuda.get_device_name(device)
@ -134,8 +151,6 @@ def device_init(context, device):
log.info(f'Setting {device} as active, with precision: {"half" if context.half_precision else "full"}')
torch.cuda.device(device)
return
def needs_to_force_full_precision(context):
if "FORCE_FULL_PRECISION" in os.environ:
@ -158,14 +173,16 @@ def needs_to_force_full_precision(context):
def get_max_vram_usage_level(device):
if device != "cpu":
if "cuda" in device:
_, mem_total = torch.cuda.mem_get_info(device)
mem_total /= float(10**9)
else:
return "high"
if mem_total < 4.5:
return "low"
elif mem_total < 6.5:
return "balanced"
mem_total /= float(10**9)
if mem_total < 4.5:
return "low"
elif mem_total < 6.5:
return "balanced"
return "high"
@ -174,7 +191,7 @@ def validate_device_id(device, log_prefix=""):
def is_valid():
if not isinstance(device, str):
return False
if device == "cpu":
if device == "cpu" or device == "mps":
return True
if not device.startswith("cuda:") or not device[5:].isnumeric():
return False
@ -182,7 +199,7 @@ def validate_device_id(device, log_prefix=""):
if not is_valid():
raise EnvironmentError(
f"{log_prefix}: device id should be 'cpu', or 'cuda:N' (where N is an integer index for the GPU). Got: {device}"
f"{log_prefix}: device id should be 'cpu', 'mps', or 'cuda:N' (where N is an integer index for the GPU). Got: {device}"
)
@ -198,7 +215,7 @@ def is_device_compatible(device):
log.error(str(e))
return False
if device == "cpu":
if device in ("cpu", "mps"):
return True
# Memory check
try:
@ -217,14 +234,14 @@ def is_device_compatible(device):
def get_processor_name():
try:
import platform, subprocess
import subprocess
if platform.system() == "Windows":
return platform.processor()
elif platform.system() == "Darwin":
os.environ["PATH"] = os.environ["PATH"] + os.pathsep + "/usr/sbin"
command = "sysctl -n machdep.cpu.brand_string"
return subprocess.check_output(command).strip()
return subprocess.check_output(command, shell=True).decode().strip()
elif platform.system() == "Linux":
command = "cat /proc/cpuinfo"
all_info = subprocess.check_output(command, shell=True).decode().strip()

View File

@ -25,6 +25,13 @@ NOCACHE_HEADERS = {"Cache-Control": "no-cache, no-store, must-revalidate", "Prag
class NoCacheStaticFiles(StaticFiles):
def __init__(self, directory: str):
# follow_symlink is only available on fastapi >= 0.92.0
if (os.path.islink(directory)):
super().__init__(directory = os.path.realpath(directory))
else:
super().__init__(directory = directory)
def is_not_modified(self, response_headers, request_headers) -> bool:
if "content-type" in response_headers and (
"javascript" in response_headers["content-type"] or "css" in response_headers["content-type"]
@ -45,6 +52,13 @@ class SetAppConfigRequest(BaseModel):
def init():
if os.path.isdir(app.CUSTOM_MODIFIERS_DIR):
server_api.mount(
"/media/modifier-thumbnails/custom",
NoCacheStaticFiles(directory=app.CUSTOM_MODIFIERS_DIR),
name="custom-thumbnails",
)
server_api.mount("/media", NoCacheStaticFiles(directory=os.path.join(app.SD_UI_DIR, "media")), name="media")
for plugins_dir, dir_prefix in app.UI_PLUGINS_SOURCES:
@ -156,7 +170,7 @@ def read_web_data_internal(key: str = None):
elif key == "models":
return JSONResponse(model_manager.getModels(), headers=NOCACHE_HEADERS)
elif key == "modifiers":
return FileResponse(os.path.join(app.SD_UI_DIR, "modifiers.json"), headers=NOCACHE_HEADERS)
return JSONResponse(app.get_image_modifiers(), headers=NOCACHE_HEADERS)
elif key == "ui_plugins":
return JSONResponse(app.getUIPlugins(), headers=NOCACHE_HEADERS)
else:

View File

@ -385,7 +385,7 @@ def get_devices():
}
def get_device_info(device):
if device == "cpu":
if device in ("cpu", "mps"):
return {"name": device_manager.get_processor_name()}
mem_free, mem_total = torch.cuda.mem_get_info(device)
@ -400,14 +400,17 @@ def get_devices():
}
# list the compatible devices
gpu_count = torch.cuda.device_count()
for device in range(gpu_count):
cuda_count = torch.cuda.device_count()
for device in range(cuda_count):
device = f"cuda:{device}"
if not device_manager.is_device_compatible(device):
continue
devices["all"].update({device: get_device_info(device)})
if device_manager.is_mps_available():
devices["all"].update({"mps": get_device_info("mps")})
devices["all"].update({"cpu": get_device_info("cpu")})
# list the activated devices

View File

@ -25,8 +25,9 @@
<div id="top-nav">
<div id="logo">
<h1>
<img id="logo_img" src="/media/images/icon-512x512.png" >
Easy Diffusion
<small>v2.5.22 <span id="updateBranchLabel"></span></small>
<small>v2.5.24 <span id="updateBranchLabel"></span></small>
</h1>
</div>
<div id="server-status">
@ -289,6 +290,7 @@
<button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can icon"></i> Clear All</button>
<button id="save-all-images" class="tertiaryButton"><i class="fa-solid fa-download icon"></i> Download All Images</button>
<div class="display-settings">
<span class="auto-scroll"></span> <!-- hack for Rabbit Hole update -->
<button id="auto_scroll_btn" class="tertiaryButton">
<i class="fa-solid fa-arrows-up-to-line icon"></i>
<input id="auto_scroll" name="auto_scroll" type="checkbox" style="display: none">

View File

@ -214,3 +214,10 @@
.image-editor-popup h4 {
text-align: left;
}
.image-editor-popup .load_mask {
display: none;
}
.inpainter .load_mask {
display: flex;
}

View File

@ -27,6 +27,11 @@ code {
padding: 2px 4px;
border-radius: 4px;
}
#logo_img {
width: 32px;
height: 32px;
transform: translateY(4px);
}
#prompt {
width: 100%;
height: 65pt;
@ -324,6 +329,7 @@ div.img-preview img {
#logo {
display: inline;
padding: 12px;
padding-top: 8px;
white-space: nowrap;
}
#logo h1 {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 352 KiB

View File

@ -117,6 +117,42 @@ const IMAGE_EDITOR_TOOLS = [
]
const IMAGE_EDITOR_ACTIONS = [
{
id: "load_mask",
name: "Load mask from file",
className: "load_mask",
icon: "fa-regular fa-folder-open",
handler: (editor) => {
let el = document.createElement('input')
el.setAttribute("type", "file")
el.addEventListener("change", function() {
if (this.files.length === 0) {
return
}
let reader = new FileReader()
let file = this.files[0]
reader.addEventListener('load', function(event) {
let maskData = reader.result
editor.layers.drawing.ctx.clearRect(0, 0, editor.width, editor.height)
var image = new Image()
image.onload = () => {
editor.layers.drawing.ctx.drawImage(image, 0, 0, editor.width, editor.height)
}
image.src = maskData
})
if (file) {
reader.readAsDataURL(file)
}
})
el.click()
},
trackHistory: true
},
{
id: "fill_all",
name: "Fill all",
@ -457,6 +493,9 @@ class ImageEditor {
var element = document.createElement("div")
var icon = document.createElement("i")
element.className = "image-editor-button button"
if (action.className) {
element.className += " " + action.className
}
icon.className = action.icon
element.appendChild(icon)
element.append(action.name)