mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-08-15 10:49:44 +02:00
Compare commits
55 Commits
revert-734
...
v2.5.14
Author | SHA1 | Date | |
---|---|---|---|
cbdb715918 | |||
5537102fd3 | |||
1ea294f15c | |||
4c8da67bb1 | |||
43a1c3901f | |||
a4c6f28a70 | |||
f8bca93170 | |||
19b05659b5 | |||
7e5c7ca1b7 | |||
1156c159f9 | |||
5c6c2303ba | |||
a0a58bcfa8 | |||
8a28b265a3 | |||
86dc08130b | |||
5cd8a732c7 | |||
fafbbf68a4 | |||
0cbb553564 | |||
f4512bb291 | |||
99205b4d03 | |||
d48e6554d5 | |||
d0c4e95de3 | |||
0b3a35c4b6 | |||
ded6a41f86 | |||
f4063e63d3 | |||
23ba912db0 | |||
368967fbcf | |||
a9d0fc9978 | |||
b6f3d2ec02 | |||
78e917a6fb | |||
96b45385e8 | |||
db47888a75 | |||
51443741b8 | |||
3e7f14af2c | |||
733439da07 | |||
efba81cb66 | |||
b2cc5dcf4b | |||
fab86ddf35 | |||
f3a90ce02d | |||
4886616c48 | |||
dcd8121009 | |||
59adaf6225 | |||
1da4b3d94a | |||
fb0c9405cf | |||
a17a9044ad | |||
64ced3b3f6 | |||
493526c478 | |||
8cedeb349d | |||
72b3598687 | |||
b1a2d36c2d | |||
e636dd3649 | |||
b87bc033f5 | |||
4e765a7948 | |||
6d08082693 | |||
00597879bc | |||
9d201f82f1 |
@ -19,6 +19,12 @@
|
|||||||
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.
|
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
|
### Detailed changelog
|
||||||
|
* 2.5.14 - 8 Feb 2023 - Fix broken auto-save settings. We renamed `sampler` to `sampler_name`, which caused old settings to fail.
|
||||||
|
* 2.5.14 - 6 Feb 2023 - Simplify the UI for merging models, and some other minor UI tweaks. Better error reporting if a model failed to load.
|
||||||
|
* 2.5.14 - 3 Feb 2023 - Fix the 'Make Similar Images' button, which was producing incorrect images (weren't very similar).
|
||||||
|
* 2.5.13 - 1 Feb 2023 - Fix the remaining GPU memory leaks, including a better fix (more comprehensive) for the change in 2.5.12 (27 Jan).
|
||||||
|
* 2.5.12 - 27 Jan 2023 - Fix a memory leak, which made the UI unresponsive after an out-of-memory error. The allocated memory is now freed-up after an error.
|
||||||
|
* 2.5.11 - 25 Jan 2023 - UI for Merging Models. Thanks @JeLuf. More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging
|
||||||
* 2.5.10 - 24 Jan 2023 - Reduce the VRAM usage for img2img in 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of this UI.
|
* 2.5.10 - 24 Jan 2023 - Reduce the VRAM usage for img2img in 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of this UI.
|
||||||
* 2.5.9 - 23 Jan 2023 - Fix a bug where img2img would produce poorer-quality images for the same settings, as compared to version 2.4 of this UI.
|
* 2.5.9 - 23 Jan 2023 - Fix a bug where img2img would produce poorer-quality images for the same settings, as compared to version 2.4 of this UI.
|
||||||
* 2.5.9 - 23 Jan 2023 - Reduce the VRAM usage for 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of the UI.
|
* 2.5.9 - 23 Jan 2023 - Reduce the VRAM usage for 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of the UI.
|
||||||
|
47
README.md
47
README.md
@ -1,14 +1,13 @@
|
|||||||
# Stable Diffusion UI
|
# Easy Diffusion 2.5
|
||||||
### The easiest way to install and use [Stable Diffusion](https://github.com/CompVis/stable-diffusion) on your own computer. Does not require technical knowledge, does not require pre-installed software. 1-click install, powerful features, friendly community.
|
### The easiest way to install and use [Stable Diffusion](https://github.com/CompVis/stable-diffusion) on your own computer.
|
||||||
|
|
||||||
[](https://discord.com/invite/u9yhsFmEkB) (for support, and development discussion) | [Troubleshooting guide for common problems](https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting)
|
Does not require technical knowledge, does not require pre-installed software. 1-click install, powerful features, friendly community.
|
||||||
|
|
||||||
### New:
|
[Installation guide](#step-1-download-and-extract-the-installer) | [Troubleshooting guide](https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting) | <sub>[](https://discord.com/invite/u9yhsFmEkB)</sub> <sup>(for support queries, and development discussions)</sup>
|
||||||
Experimental support for Stable Diffusion 2.0 is available in beta!
|
|
||||||
|
|
||||||
----
|

|
||||||
|
|
||||||
# Step 1: Download and prepare the installer
|
# Step 1: Download and extract the installer
|
||||||
Click the download button for your operating system:
|
Click the download button for your operating system:
|
||||||
|
|
||||||
<p float="left">
|
<p float="left">
|
||||||
@ -44,9 +43,18 @@ The installer will take care of whatever is needed. If you face any problems, yo
|
|||||||
### User experience
|
### User experience
|
||||||
- **Hassle-free installation**: Does not require technical knowledge, does not require pre-installed software. Just download and run!
|
- **Hassle-free installation**: Does not require technical knowledge, does not require pre-installed software. Just download and run!
|
||||||
- **Clutter-free UI**: A friendly and simple UI, while providing a lot of powerful features.
|
- **Clutter-free UI**: A friendly and simple UI, while providing a lot of powerful features.
|
||||||
|
- **Task Queue**: Queue up all your ideas, without waiting for the current task to finish.
|
||||||
|
- **Intelligent Model Detection**: Automatically figures out the YAML config file to use for the chosen model (via a models database).
|
||||||
|
- **Live Preview**: See the image as the AI is drawing it.
|
||||||
|
- **Image Modifiers**: A library of *modifier tags* like *"Realistic"*, *"Pencil Sketch"*, *"ArtStation"* etc. Experiment with various styles quickly.
|
||||||
|
- **Multiple Prompts File**: Queue multiple prompts by entering one prompt per line, or by running a text file.
|
||||||
|
- **Save generated images to disk**: Save your images to your PC!
|
||||||
|
- **UI Themes**: Customize the program to your liking.
|
||||||
|
- **Organize your models into sub-folders**
|
||||||
|
|
||||||
### Image generation
|
### Image generation
|
||||||
- **Supports**: "*Text to Image*" and "*Image to Image*".
|
- **Supports**: "*Text to Image*" and "*Image to Image*".
|
||||||
|
- **14 Samplers**: `ddim`, `plms`, `heun`, `euler`, `euler_a`, `dpm2`, `dpm2_a`, `lms`, `dpm_solver_stability`, `dpmpp_2s_a`, `dpmpp_2m`, `dpmpp_sde`, `dpm_fast`, `dpm_adaptive`
|
||||||
- **In-Painting**: Specify areas of your image to paint into.
|
- **In-Painting**: Specify areas of your image to paint into.
|
||||||
- **Simple Drawing Tool**: Draw basic images to guide the AI, without needing an external drawing program.
|
- **Simple Drawing Tool**: Draw basic images to guide the AI, without needing an external drawing program.
|
||||||
- **Face Correction (GFPGAN)**
|
- **Face Correction (GFPGAN)**
|
||||||
@ -56,7 +64,6 @@ The installer will take care of whatever is needed. If you face any problems, yo
|
|||||||
- **Attention/Emphasis**: () in the prompt increases the model's attention to enclosed words, and [] decreases it.
|
- **Attention/Emphasis**: () in the prompt increases the model's attention to enclosed words, and [] decreases it.
|
||||||
- **Weighted Prompts**: Use weights for specific words in your prompt to change their importance, e.g. `red:2.4 dragon:1.2`.
|
- **Weighted Prompts**: Use weights for specific words in your prompt to change their importance, e.g. `red:2.4 dragon:1.2`.
|
||||||
- **Prompt Matrix**: Quickly create multiple variations of your prompt, e.g. `a photograph of an astronaut riding a horse | illustration | cinematic lighting`.
|
- **Prompt Matrix**: Quickly create multiple variations of your prompt, e.g. `a photograph of an astronaut riding a horse | illustration | cinematic lighting`.
|
||||||
- **Lots of Samplers**: ddim, plms, heun, euler, euler_a, dpm2, dpm2_a, lms.
|
|
||||||
- **1-click Upscale/Face Correction**: Upscale or correct an image after it has been generated.
|
- **1-click Upscale/Face Correction**: Upscale or correct an image after it has been generated.
|
||||||
- **Make Similar Images**: Click to generate multiple variations of a generated image.
|
- **Make Similar Images**: Click to generate multiple variations of a generated image.
|
||||||
- **NSFW Setting**: A setting in the UI to control *NSFW content*.
|
- **NSFW Setting**: A setting in the UI to control *NSFW content*.
|
||||||
@ -64,13 +71,15 @@ The installer will take care of whatever is needed. If you face any problems, yo
|
|||||||
|
|
||||||
### Advanced features
|
### Advanced features
|
||||||
- **Custom Models**: Use your own `.ckpt` or `.safetensors` file, by placing it inside the `models/stable-diffusion` folder!
|
- **Custom Models**: Use your own `.ckpt` or `.safetensors` file, by placing it inside the `models/stable-diffusion` folder!
|
||||||
- **Stable Diffusion 2.0 support (experimental)**: available in beta channel.
|
- **Stable Diffusion 2.1 support**
|
||||||
|
- **Merge Models**
|
||||||
- **Use custom VAE models**
|
- **Use custom VAE models**
|
||||||
- **Use pre-trained Hypernetworks**
|
- **Use pre-trained Hypernetworks**
|
||||||
- **UI Plugins**: Choose from a growing list of [community-generated UI plugins](https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Plugins), or write your own plugin to add features to the project!
|
- **UI Plugins**: Choose from a growing list of [community-generated UI plugins](https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Plugins), or write your own plugin to add features to the project!
|
||||||
|
|
||||||
### Performance and security
|
### Performance and security
|
||||||
- **Low Memory Usage**: Creates 512x512 images with less than 4GB of GPU RAM!
|
- **Fast**: Creates a 512x512 image with euler_a in 5 seconds, on an NVIDIA 3060 12GB.
|
||||||
|
- **Low Memory Usage**: Create 512x512 images with less than 3 GB of GPU RAM, and 768x768 images with less than 4 GB of GPU RAM!
|
||||||
- **Use CPU setting**: If you don't have a compatible graphics card, but still want to run it on your CPU.
|
- **Use CPU setting**: If you don't have a compatible graphics card, but still want to run it on your CPU.
|
||||||
- **Multi-GPU support**: Automatically spreads your tasks across multiple GPUs (if available), for faster performance!
|
- **Multi-GPU support**: Automatically spreads your tasks across multiple GPUs (if available), for faster performance!
|
||||||
- **Auto scan for malicious models**: Uses picklescan to prevent malicious models.
|
- **Auto scan for malicious models**: Uses picklescan to prevent malicious models.
|
||||||
@ -78,23 +87,17 @@ The installer will take care of whatever is needed. If you face any problems, yo
|
|||||||
- **Auto-updater**: Gets you the latest improvements and bug-fixes to a rapidly evolving project.
|
- **Auto-updater**: Gets you the latest improvements and bug-fixes to a rapidly evolving project.
|
||||||
- **Developer Console**: A developer-mode for those who want to modify their Stable Diffusion code, and edit the conda environment.
|
- **Developer Console**: A developer-mode for those who want to modify their Stable Diffusion code, and edit the conda environment.
|
||||||
|
|
||||||
### Usability:
|
|
||||||
- **Live Preview**: See the image as the AI is drawing it.
|
|
||||||
- **Task Queue**: Queue up all your ideas, without waiting for the current task to finish.
|
|
||||||
- **Image Modifiers**: A library of *modifier tags* like *"Realistic"*, *"Pencil Sketch"*, *"ArtStation"* etc. Experiment with various styles quickly.
|
|
||||||
- **Multiple Prompts File**: Queue multiple prompts by entering one prompt per line, or by running a text file.
|
|
||||||
- **Save generated images to disk**: Save your images to your PC!
|
|
||||||
- **UI Themes**: Customize the program to your liking.
|
|
||||||
|
|
||||||
**(and a lot more)**
|
**(and a lot more)**
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Easy for new users:
|
## Easy for new users:
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Powerful features for advanced users:
|
## Powerful features for advanced users:
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Live Preview
|
## Live Preview
|
||||||
Useful for judging (and stopping) an image quickly, without waiting for it to finish rendering.
|
Useful for judging (and stopping) an image quickly, without waiting for it to finish rendering.
|
||||||
@ -102,7 +105,9 @@ Useful for judging (and stopping) an image quickly, without waiting for it to fi
|
|||||||

|

|
||||||
|
|
||||||
## Task Queue
|
## Task Queue
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# System Requirements
|
# System Requirements
|
||||||
1. Windows 10/11, or Linux. Experimental support for Mac is coming soon.
|
1. Windows 10/11, or Linux. Experimental support for Mac is coming soon.
|
||||||
|
@ -72,13 +72,15 @@ if "%ERRORLEVEL%" EQU "0" (
|
|||||||
set PYTHONNOUSERSITE=1
|
set PYTHONNOUSERSITE=1
|
||||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||||
|
|
||||||
call pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 || (
|
call python -m pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 || (
|
||||||
echo "Error installing torch. 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!"
|
echo "Error installing torch. 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
|
pause
|
||||||
exit /b
|
exit /b
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set PATH=C:\Windows\System32;%PATH%
|
||||||
|
|
||||||
@rem install/upgrade sdkit
|
@rem install/upgrade sdkit
|
||||||
call python ..\scripts\check_modules.py sdkit sdkit.models ldm transformers numpy antlr4 gfpgan realesrgan
|
call python ..\scripts\check_modules.py sdkit sdkit.models ldm transformers numpy antlr4 gfpgan realesrgan
|
||||||
if "%ERRORLEVEL%" EQU "0" (
|
if "%ERRORLEVEL%" EQU "0" (
|
||||||
@ -90,7 +92,7 @@ if "%ERRORLEVEL%" EQU "0" (
|
|||||||
set PYTHONNOUSERSITE=1
|
set PYTHONNOUSERSITE=1
|
||||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||||
|
|
||||||
call pip install --upgrade sdkit -q || (
|
call python -m pip install --upgrade sdkit -q || (
|
||||||
echo "Error updating sdkit"
|
echo "Error updating sdkit"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -101,7 +103,7 @@ if "%ERRORLEVEL%" EQU "0" (
|
|||||||
set PYTHONNOUSERSITE=1
|
set PYTHONNOUSERSITE=1
|
||||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||||
|
|
||||||
call pip install sdkit || (
|
call python -m pip install sdkit || (
|
||||||
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!"
|
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
|
pause
|
||||||
exit /b
|
exit /b
|
||||||
@ -111,7 +113,7 @@ if "%ERRORLEVEL%" EQU "0" (
|
|||||||
call python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
|
call python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
|
||||||
|
|
||||||
@rem upgrade stable-diffusion-sdkit
|
@rem upgrade stable-diffusion-sdkit
|
||||||
call pip install --upgrade stable-diffusion-sdkit -q || (
|
call python -m pip install --upgrade stable-diffusion-sdkit -q || (
|
||||||
echo "Error updating stable-diffusion-sdkit"
|
echo "Error updating stable-diffusion-sdkit"
|
||||||
)
|
)
|
||||||
call python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
|
call python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
|
||||||
@ -126,7 +128,7 @@ if "%ERRORLEVEL%" EQU "0" (
|
|||||||
set PYTHONNOUSERSITE=1
|
set PYTHONNOUSERSITE=1
|
||||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||||
|
|
||||||
call pip install rich || (
|
call python -m pip install rich || (
|
||||||
echo "Error installing rich. 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!"
|
echo "Error installing rich. 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
|
pause
|
||||||
exit /b
|
exit /b
|
||||||
|
@ -64,7 +64,7 @@ else
|
|||||||
export PYTHONNOUSERSITE=1
|
export PYTHONNOUSERSITE=1
|
||||||
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
||||||
|
|
||||||
if pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 ; then
|
if python -m pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 ; then
|
||||||
echo "Installed."
|
echo "Installed."
|
||||||
else
|
else
|
||||||
fail "torch install failed"
|
fail "torch install failed"
|
||||||
@ -80,7 +80,7 @@ if python ../scripts/check_modules.py sdkit sdkit.models ldm transformers numpy
|
|||||||
export PYTHONNOUSERSITE=1
|
export PYTHONNOUSERSITE=1
|
||||||
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
||||||
|
|
||||||
pip install --upgrade sdkit -q
|
python -m pip install --upgrade sdkit -q
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Installing sdkit: https://pypi.org/project/sdkit/"
|
echo "Installing sdkit: https://pypi.org/project/sdkit/"
|
||||||
@ -88,7 +88,7 @@ else
|
|||||||
export PYTHONNOUSERSITE=1
|
export PYTHONNOUSERSITE=1
|
||||||
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
||||||
|
|
||||||
if pip install sdkit ; then
|
if python -m pip install sdkit ; then
|
||||||
echo "Installed."
|
echo "Installed."
|
||||||
else
|
else
|
||||||
fail "sdkit install failed"
|
fail "sdkit install failed"
|
||||||
@ -98,7 +98,7 @@ fi
|
|||||||
python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
|
python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
|
||||||
|
|
||||||
# upgrade stable-diffusion-sdkit
|
# upgrade stable-diffusion-sdkit
|
||||||
pip install --upgrade stable-diffusion-sdkit -q
|
python -m pip install --upgrade stable-diffusion-sdkit -q
|
||||||
python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
|
python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
|
||||||
|
|
||||||
# install rich
|
# install rich
|
||||||
@ -110,7 +110,7 @@ else
|
|||||||
export PYTHONNOUSERSITE=1
|
export PYTHONNOUSERSITE=1
|
||||||
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
||||||
|
|
||||||
if pip install rich ; then
|
if python -m pip install rich ; then
|
||||||
echo "Installed."
|
echo "Installed."
|
||||||
else
|
else
|
||||||
fail "Install failed for rich"
|
fail "Install failed for rich"
|
||||||
|
@ -20,7 +20,7 @@ logging.basicConfig(
|
|||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format=LOG_FORMAT,
|
format=LOG_FORMAT,
|
||||||
datefmt="%X",
|
datefmt="%X",
|
||||||
handlers=[RichHandler(markup=True, rich_tracebacks=True, show_time=False, show_level=False)]
|
handlers=[RichHandler(markup=True, rich_tracebacks=False, show_time=False, show_level=False)],
|
||||||
)
|
)
|
||||||
|
|
||||||
SD_DIR = os.getcwd()
|
SD_DIR = os.getcwd()
|
||||||
|
@ -125,7 +125,7 @@ def needs_to_force_full_precision(context):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
device_name = context.device_name.lower()
|
device_name = context.device_name.lower()
|
||||||
return (('nvidia' in device_name or 'geforce' in device_name) and (' 1660' in device_name or ' 1650' in device_name or ' t400' in device_name or ' t550' in device_name or ' t1200' in device_name)) or ('Quadro T2000' in device_name)
|
return (('nvidia' in device_name or 'geforce' in device_name or 'quadro' in device_name) and (' 1660' in device_name or ' 1650' in device_name or ' t400' in device_name or ' t550' in device_name or ' t600' in device_name or ' t1000' in device_name or ' t1200' in device_name or ' t2000' in device_name))
|
||||||
|
|
||||||
def get_max_vram_usage_level(device):
|
def get_max_vram_usage_level(device):
|
||||||
if device != 'cpu':
|
if device != 'cpu':
|
||||||
|
@ -43,7 +43,7 @@ def load_default_models(context: Context):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f'[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]')
|
log.error(f'[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]')
|
||||||
log.error(f'[red]Error: {e}[/red]')
|
log.error(f'[red]Error: {e}[/red]')
|
||||||
log.error(f'[red]Consider to remove the model from the model folder.[red]')
|
log.error(f'[red]Consider removing the model from the model folder.[red]')
|
||||||
|
|
||||||
|
|
||||||
def unload_all(context: Context):
|
def unload_all(context: Context):
|
||||||
|
@ -65,6 +65,8 @@ def generate_images_internal(req: GenerateImageRequest, task_data: TaskData, dat
|
|||||||
callback = make_step_callback(req, task_data, data_queue, task_temp_images, step_callback, stream_image_progress)
|
callback = make_step_callback(req, task_data, data_queue, task_temp_images, step_callback, stream_image_progress)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if req.init_image is not None: req.sampler_name = 'ddim'
|
||||||
|
|
||||||
images = generate_images(context, callback=callback, **req.dict())
|
images = generate_images(context, callback=callback, **req.dict())
|
||||||
user_stopped = False
|
user_stopped = False
|
||||||
except UserInitiatedStop:
|
except UserInitiatedStop:
|
||||||
@ -72,9 +74,10 @@ def generate_images_internal(req: GenerateImageRequest, task_data: TaskData, dat
|
|||||||
user_stopped = True
|
user_stopped = True
|
||||||
if context.partial_x_samples is not None:
|
if context.partial_x_samples is not None:
|
||||||
images = latent_samples_to_images(context, context.partial_x_samples)
|
images = latent_samples_to_images(context, context.partial_x_samples)
|
||||||
context.partial_x_samples = None
|
|
||||||
finally:
|
finally:
|
||||||
gc(context)
|
if hasattr(context, 'partial_x_samples') and context.partial_x_samples is not None:
|
||||||
|
del context.partial_x_samples
|
||||||
|
context.partial_x_samples = None
|
||||||
|
|
||||||
return images, user_stopped
|
return images, user_stopped
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ from easydiffusion import device_manager
|
|||||||
from easydiffusion.types import TaskData, GenerateImageRequest
|
from easydiffusion.types import TaskData, GenerateImageRequest
|
||||||
from easydiffusion.utils import log
|
from easydiffusion.utils import log
|
||||||
|
|
||||||
|
from sdkit.utils import gc
|
||||||
|
|
||||||
THREAD_NAME_PREFIX = ''
|
THREAD_NAME_PREFIX = ''
|
||||||
ERR_LOCK_FAILED = ' failed to acquire lock within timeout.'
|
ERR_LOCK_FAILED = ' failed to acquire lock within timeout.'
|
||||||
LOCK_TIMEOUT = 15 # Maximum locking time in seconds before failing a task.
|
LOCK_TIMEOUT = 15 # Maximum locking time in seconds before failing a task.
|
||||||
@ -287,13 +289,12 @@ def thread_render(device):
|
|||||||
task_cache.keep(id(task), TASK_TTL)
|
task_cache.keep(id(task), TASK_TTL)
|
||||||
session_cache.keep(task.task_data.session_id, TASK_TTL)
|
session_cache.keep(task.task_data.session_id, TASK_TTL)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
task.error = e
|
task.error = str(e)
|
||||||
task.response = {"status": 'failed', "detail": str(task.error)}
|
task.response = {"status": 'failed', "detail": str(task.error)}
|
||||||
task.buffer_queue.put(json.dumps(task.response))
|
task.buffer_queue.put(json.dumps(task.response))
|
||||||
log.error(traceback.format_exc())
|
log.error(traceback.format_exc())
|
||||||
continue
|
|
||||||
finally:
|
finally:
|
||||||
# Task completed
|
gc(renderer.context)
|
||||||
task.lock.release()
|
task.lock.release()
|
||||||
task_cache.keep(id(task), TASK_TTL)
|
task_cache.keep(id(task), TASK_TTL)
|
||||||
session_cache.keep(task.task_data.session_id, TASK_TTL)
|
session_cache.keep(task.task_data.session_id, TASK_TTL)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<meta name="theme-color" content="#673AB6">
|
<meta name="theme-color" content="#673AB6">
|
||||||
<link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16">
|
<link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16">
|
||||||
<link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32">
|
<link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32">
|
||||||
|
<link rel="stylesheet" href="/media/css/jquery-confirm.min.css">
|
||||||
<link rel="stylesheet" href="/media/css/fonts.css">
|
<link rel="stylesheet" href="/media/css/fonts.css">
|
||||||
<link rel="stylesheet" href="/media/css/themes.css">
|
<link rel="stylesheet" href="/media/css/themes.css">
|
||||||
<link rel="stylesheet" href="/media/css/main.css">
|
<link rel="stylesheet" href="/media/css/main.css">
|
||||||
@ -13,7 +14,6 @@
|
|||||||
<link rel="stylesheet" href="/media/css/modifier-thumbnails.css">
|
<link rel="stylesheet" href="/media/css/modifier-thumbnails.css">
|
||||||
<link rel="stylesheet" href="/media/css/fontawesome-all.min.css">
|
<link rel="stylesheet" href="/media/css/fontawesome-all.min.css">
|
||||||
<link rel="stylesheet" href="/media/css/image-editor.css">
|
<link rel="stylesheet" href="/media/css/image-editor.css">
|
||||||
<link rel="stylesheet" href="/media/css/jquery-confirm.min.css">
|
|
||||||
<link rel="manifest" href="/media/manifest.webmanifest">
|
<link rel="manifest" href="/media/manifest.webmanifest">
|
||||||
<script src="/media/js/jquery-3.6.1.min.js"></script>
|
<script src="/media/js/jquery-3.6.1.min.js"></script>
|
||||||
<script src="/media/js/jquery-confirm.min.js"></script>
|
<script src="/media/js/jquery-confirm.min.js"></script>
|
||||||
@ -25,14 +25,14 @@
|
|||||||
<div id="logo">
|
<div id="logo">
|
||||||
<h1>
|
<h1>
|
||||||
Easy Diffusion
|
Easy Diffusion
|
||||||
<small>v2.5.10 <span id="updateBranchLabel"></span></small>
|
<small>v2.5.14 <span id="updateBranchLabel"></span></small>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="server-status">
|
<div id="server-status">
|
||||||
<div id="server-status-color">●</div>
|
<div id="server-status-color">●</div>
|
||||||
<span id="server-status-msg">Stable Diffusion is starting..</span>
|
<span id="server-status-msg">Stable Diffusion is starting..</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="tab-container">
|
<div id="tab-container" class="tab-container">
|
||||||
<span id="tab-main" class="tab active">
|
<span id="tab-main" class="tab active">
|
||||||
<span><i class="fa fa-image icon"></i> Generate</span>
|
<span><i class="fa fa-image icon"></i> Generate</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -107,6 +107,7 @@ code {
|
|||||||
.imgContainer {
|
.imgContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.imgItemInfo {
|
.imgItemInfo {
|
||||||
padding-bottom: 0.5em;
|
padding-bottom: 0.5em;
|
||||||
@ -114,16 +115,29 @@ code {
|
|||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 5px;
|
padding-right: 5pt;
|
||||||
|
padding-top: 6pt;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: 0.1s all;
|
transition: 0.1s all;
|
||||||
}
|
}
|
||||||
|
.imgPreviewItemClearBtn {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.imgPreviewItemClearBtn:hover {
|
||||||
|
background: rgb(177, 27, 0);
|
||||||
|
}
|
||||||
.imgContainer:hover > .imgItemInfo {
|
.imgContainer:hover > .imgItemInfo {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
.imgContainer:hover > .imgPreviewItemClearBtn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
.imgItemInfo * {
|
.imgItemInfo * {
|
||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
.imgItem .image_clear_btn {
|
||||||
|
transform: translate(40%, -50%);
|
||||||
|
}
|
||||||
#container {
|
#container {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -1029,7 +1043,7 @@ input::file-selector-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TABS */
|
/* TABS */
|
||||||
#tab-container {
|
.tab-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
@ -1182,3 +1196,10 @@ body.wait-pause {
|
|||||||
50% { border: solid 12px var(--background-color1); }
|
50% { border: solid 12px var(--background-color1); }
|
||||||
100% { border: solid 12px var(--accent-color); }
|
100% { border: solid 12px var(--accent-color); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c {
|
||||||
|
color: var(--button-text-color);
|
||||||
|
}
|
||||||
|
.jconfirm.jconfirm-modern .jconfirm-box {
|
||||||
|
background-color: var(--background-color1);
|
||||||
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 3.2 KiB |
BIN
ui/media/images/icon-512x512.png
Normal file
BIN
ui/media/images/icon-512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 KiB |
@ -262,10 +262,12 @@ function tryLoadOldSettings() {
|
|||||||
var saved_settings = JSON.parse(saved_settings_text)
|
var saved_settings = JSON.parse(saved_settings_text)
|
||||||
Object.keys(saved_settings.should_save).forEach(key => {
|
Object.keys(saved_settings.should_save).forEach(key => {
|
||||||
key = key in old_map ? old_map[key] : key
|
key = key in old_map ? old_map[key] : key
|
||||||
|
if (!(key in SETTINGS)) return
|
||||||
SETTINGS[key].ignore = !saved_settings.should_save[key]
|
SETTINGS[key].ignore = !saved_settings.should_save[key]
|
||||||
});
|
});
|
||||||
Object.keys(saved_settings.values).forEach(key => {
|
Object.keys(saved_settings.values).forEach(key => {
|
||||||
key = key in old_map ? old_map[key] : key
|
key = key in old_map ? old_map[key] : key
|
||||||
|
if (!(key in SETTINGS)) return
|
||||||
var setting = SETTINGS[key]
|
var setting = SETTINGS[key]
|
||||||
if (!setting.ignore) {
|
if (!setting.ignore) {
|
||||||
setting.value = saved_settings.values[key]
|
setting.value = saved_settings.values[key]
|
||||||
|
@ -718,7 +718,7 @@
|
|||||||
"height": 'number',
|
"height": 'number',
|
||||||
"seed": 'number',
|
"seed": 'number',
|
||||||
|
|
||||||
"sampler": 'string',
|
"sampler_name": 'string',
|
||||||
"use_stable_diffusion_model": 'string',
|
"use_stable_diffusion_model": 'string',
|
||||||
"num_inference_steps": 'number',
|
"num_inference_steps": 'number',
|
||||||
"guidance_scale": 'number',
|
"guidance_scale": 'number',
|
||||||
@ -731,7 +731,7 @@
|
|||||||
"output_quality": 'number',
|
"output_quality": 'number',
|
||||||
}
|
}
|
||||||
const TASK_DEFAULTS = {
|
const TASK_DEFAULTS = {
|
||||||
"sampler": "plms",
|
"sampler_name": "plms",
|
||||||
"use_stable_diffusion_model": "sd-v1-4",
|
"use_stable_diffusion_model": "sd-v1-4",
|
||||||
"num_inference_steps": 50,
|
"num_inference_steps": 50,
|
||||||
"guidance_scale": 7.5,
|
"guidance_scale": 7.5,
|
||||||
@ -835,11 +835,10 @@
|
|||||||
* @memberof Task
|
* @memberof Task
|
||||||
*/
|
*/
|
||||||
async post(timeout=-1) {
|
async post(timeout=-1) {
|
||||||
if (typeof performance == "object" && performance.mark && performance.measure) {
|
performance.mark('make-render-request')
|
||||||
performance.mark('make-render-request')
|
if (performance.getEntriesByName('click-makeImage', 'mark').length > 0) {
|
||||||
if (performance.getEntriesByName('click-makeImage', 'mark').length > 0) {
|
performance.measure('diff', 'click-makeImage', 'make-render-request')
|
||||||
console.log('delay between clicking and making the server request:', performance.measure('diff', 'click-makeImage', 'make-render-request').duration + ' ms')
|
console.log('delay between clicking and making the server request:', performance.getEntriesByName('diff', 'measure')[0].duration + ' ms')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let jsonResponse = await super.post('/render', timeout)
|
let jsonResponse = await super.post('/render', timeout)
|
||||||
|
@ -263,6 +263,7 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
<div class="imgItemInfo">
|
<div class="imgItemInfo">
|
||||||
<span class="imgSeedLabel"></span>
|
<span class="imgSeedLabel"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="imgPreviewItemClearBtn image_clear_btn"><i class="fa-solid fa-xmark"></i></button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
outputContainer.appendChild(imageItemElem)
|
outputContainer.appendChild(imageItemElem)
|
||||||
@ -275,6 +276,11 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
imageElem.setAttribute('data-steps', imageInferenceSteps)
|
imageElem.setAttribute('data-steps', imageInferenceSteps)
|
||||||
imageElem.setAttribute('data-guidance', imageGuidanceScale)
|
imageElem.setAttribute('data-guidance', imageGuidanceScale)
|
||||||
|
|
||||||
|
const imageRemoveBtn = imageItemElem.querySelector('.imgPreviewItemClearBtn')
|
||||||
|
imageRemoveBtn.addEventListener('click', (e) => {
|
||||||
|
console.log(e)
|
||||||
|
shiftOrConfirm(e, "Remove the image from the results?", () => { imageItemElem.style.display = 'none' })
|
||||||
|
})
|
||||||
|
|
||||||
const imageInfo = imageItemElem.querySelector('.imgItemInfo')
|
const imageInfo = imageItemElem.querySelector('.imgItemInfo')
|
||||||
imageInfo.style.visibility = (livePreview ? 'hidden' : 'visible')
|
imageInfo.style.visibility = (livePreview ? 'hidden' : 'visible')
|
||||||
@ -288,7 +294,6 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
imageSeedLabel.innerText = 'Seed: ' + req.seed
|
imageSeedLabel.innerText = 'Seed: ' + req.seed
|
||||||
|
|
||||||
let buttons = [
|
let buttons = [
|
||||||
{ text: 'Remove', on_click: onRemoveClick, class: 'secondaryButton' },
|
|
||||||
{ text: 'Use as Input', on_click: onUseAsInputClick },
|
{ text: 'Use as Input', on_click: onUseAsInputClick },
|
||||||
{ text: 'Download', on_click: onDownloadImageClick },
|
{ text: 'Download', on_click: onDownloadImageClick },
|
||||||
{ text: 'Make Similar Images', on_click: onMakeSimilarClick },
|
{ text: 'Make Similar Images', on_click: onMakeSimilarClick },
|
||||||
@ -325,10 +330,6 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRemoveClick(req, img, event) {
|
|
||||||
shiftOrConfirm(event, "Remove the image from the results?", () => { findClosestAncestor(img, '.imgItem').style.display='none' })
|
|
||||||
}
|
|
||||||
|
|
||||||
function onUseAsInputClick(req, img) {
|
function onUseAsInputClick(req, img) {
|
||||||
const imgData = img.src
|
const imgData = img.src
|
||||||
|
|
||||||
@ -658,7 +659,7 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
task.progressBar.classList.remove("active")
|
task.progressBar.classList.remove("active")
|
||||||
setStatus('request', 'done', 'success')
|
setStatus('request', 'done', 'success')
|
||||||
} else {
|
} else {
|
||||||
task.outputMsg.innerText += `Task ended after ${time}`
|
task.outputMsg.innerText += `. Task ended after ${time}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (randomSeedField.checked) {
|
if (randomSeedField.checked) {
|
||||||
@ -673,6 +674,9 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pauseClient) {
|
||||||
|
resumeBtn.click()
|
||||||
|
}
|
||||||
renderButtons.style.display = 'none'
|
renderButtons.style.display = 'none'
|
||||||
renameMakeImageButton()
|
renameMakeImageButton()
|
||||||
|
|
||||||
@ -1445,7 +1449,7 @@ function selectTab(tab_id) {
|
|||||||
let tabInfo = tabElements.find(t => t.tab.id == tab_id)
|
let tabInfo = tabElements.find(t => t.tab.id == tab_id)
|
||||||
if (!tabInfo.tab.classList.contains("active")) {
|
if (!tabInfo.tab.classList.contains("active")) {
|
||||||
tabElements.forEach(info => {
|
tabElements.forEach(info => {
|
||||||
if (info.tab.classList.contains("active")) {
|
if (info.tab.classList.contains("active") && info.tab.parentNode === tabInfo.tab.parentNode) {
|
||||||
info.tab.classList.toggle("active")
|
info.tab.classList.toggle("active")
|
||||||
info.content.classList.toggle("active")
|
info.content.classList.toggle("active")
|
||||||
}
|
}
|
||||||
@ -1466,6 +1470,9 @@ function linkTabContents(tab) {
|
|||||||
|
|
||||||
tab.addEventListener("click", event => selectTab(tab.id))
|
tab.addEventListener("click", event => selectTab(tab.id))
|
||||||
}
|
}
|
||||||
|
function isTabActive(tab) {
|
||||||
|
return tab.classList.contains("active")
|
||||||
|
}
|
||||||
|
|
||||||
let pauseClient = false
|
let pauseClient = false
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
// Scroll to the bottom of the log
|
// Scroll to the bottom of the log
|
||||||
logContainer.scrollTop = logContainer.scrollHeight;
|
logContainer.scrollTop = logContainer.scrollHeight;
|
||||||
|
|
||||||
|
document.querySelector('#merge-log-container').style.display = 'block'
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLogSeparator() {
|
function addLogSeparator() {
|
||||||
@ -46,8 +48,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function drawDiagram(fn) {
|
function drawDiagram(fn) {
|
||||||
|
const SIZE = 300
|
||||||
const canvas = document.getElementById('merge-canvas');
|
const canvas = document.getElementById('merge-canvas');
|
||||||
canvas.width=canvas.width
|
canvas.height = canvas.width = SIZE
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
// Draw coordinate system
|
// Draw coordinate system
|
||||||
@ -57,15 +60,16 @@
|
|||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
ctx.strokeStyle = 'white'
|
ctx.strokeStyle = 'white'
|
||||||
ctx.moveTo(0,0); ctx.lineTo(0,400); ctx.lineTo(400,400); ctx.lineTo(400,0); ctx.lineTo(0,0); ctx.lineTo(400,400);
|
ctx.moveTo(0,0); ctx.lineTo(0,SIZE); ctx.lineTo(SIZE,SIZE); ctx.lineTo(SIZE,0); ctx.lineTo(0,0); ctx.lineTo(SIZE,SIZE);
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.setLineDash([1,2])
|
ctx.setLineDash([1,2])
|
||||||
for (let i=40; i<400; i+=40) {
|
const n = SIZE / 10
|
||||||
|
for (let i=n; i<SIZE; i+=n) {
|
||||||
ctx.moveTo(0,i)
|
ctx.moveTo(0,i)
|
||||||
ctx.lineTo(400,i)
|
ctx.lineTo(SIZE,i)
|
||||||
ctx.moveTo(i,0)
|
ctx.moveTo(i,0)
|
||||||
ctx.lineTo(i,400)
|
ctx.lineTo(i,SIZE)
|
||||||
}
|
}
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
@ -79,8 +83,8 @@
|
|||||||
const x = i / numSamples;
|
const x = i / numSamples;
|
||||||
const y = fn(x);
|
const y = fn(x);
|
||||||
|
|
||||||
const canvasX = x * 400;
|
const canvasX = x * SIZE;
|
||||||
const canvasY = y * 400;
|
const canvasY = y * SIZE;
|
||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
ctx.moveTo(canvasX, canvasY);
|
ctx.moveTo(canvasX, canvasY);
|
||||||
@ -97,14 +101,14 @@
|
|||||||
ctx.fillStyle = "yellow"
|
ctx.fillStyle = "yellow"
|
||||||
for (let i=0; i< iterations; i++) {
|
for (let i=0; i< iterations; i++) {
|
||||||
const alpha = ( start + i * step ) / 100
|
const alpha = ( start + i * step ) / 100
|
||||||
const x = alpha*400
|
const x = alpha*SIZE
|
||||||
const y = fn(alpha) * 400
|
const y = fn(alpha) * SIZE
|
||||||
if (x <= 400) {
|
if (x <= SIZE) {
|
||||||
ctx.rect(x-3,y-3,6,6)
|
ctx.rect(x-3,y-3,6,6)
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
} else {
|
} else {
|
||||||
ctx.strokeStyle = 'red'
|
ctx.strokeStyle = 'red'
|
||||||
ctx.moveTo(0,0); ctx.lineTo(0,400); ctx.lineTo(400,400); ctx.lineTo(400,0); ctx.lineTo(0,0); ctx.lineTo(400,400);
|
ctx.moveTo(0,0); ctx.lineTo(0,SIZE); ctx.lineTo(SIZE,SIZE); ctx.lineTo(SIZE,0); ctx.lineTo(0,0); ctx.lineTo(SIZE,SIZE);
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
addLogMessage('<i>Warning: maximum ratio is ≥ 100%</i>')
|
addLogMessage('<i>Warning: maximum ratio is ≥ 100%</i>')
|
||||||
}
|
}
|
||||||
@ -128,9 +132,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////// Tab implementation
|
/////////////////////// Tab implementation
|
||||||
document.querySelector('#tab-container')?.insertAdjacentHTML('beforeend', `
|
document.querySelector('.tab-container')?.insertAdjacentHTML('beforeend', `
|
||||||
<span id="tab-merge" class="tab">
|
<span id="tab-merge" class="tab">
|
||||||
<span><i class="fa fa-code-merge icon"></i> Merge models</span>
|
<span><i class="fa fa-code-merge icon"></i> Merge models <small>(beta)</small></span>
|
||||||
</span>
|
</span>
|
||||||
`)
|
`)
|
||||||
|
|
||||||
@ -156,7 +160,6 @@
|
|||||||
<style>
|
<style>
|
||||||
#tab-content-merge .tab-content-inner {
|
#tab-content-merge .tab-content-inner {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
text-align: center;
|
|
||||||
padding: 10pt;
|
padding: 10pt;
|
||||||
}
|
}
|
||||||
.merge-container {
|
.merge-container {
|
||||||
@ -172,6 +175,17 @@
|
|||||||
"merge-input merge-config"
|
"merge-input merge-config"
|
||||||
"merge-buttons merge-buttons";
|
"merge-buttons merge-buttons";
|
||||||
}
|
}
|
||||||
|
.merge-container p {
|
||||||
|
margin-top: 3pt;
|
||||||
|
margin-bottom: 3pt;
|
||||||
|
}
|
||||||
|
.merge-config .tab-content {
|
||||||
|
background: var(--background-color1);
|
||||||
|
border-radius: 3pt;
|
||||||
|
}
|
||||||
|
.merge-config .tab-content-inner {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.merge-input {
|
.merge-input {
|
||||||
grid-area: merge-input;
|
grid-area: merge-input;
|
||||||
@ -201,6 +215,7 @@
|
|||||||
overflow-x:hidden;
|
overflow-x:hidden;
|
||||||
overflow-y:scroll;
|
overflow-y:scroll;
|
||||||
background:var(--background-color1);
|
background:var(--background-color1);
|
||||||
|
border-radius: 3pt;
|
||||||
}
|
}
|
||||||
div#merge-log i {
|
div#merge-log i {
|
||||||
color: hsl(var(--accent-hue), 100%, calc(2*var(--accent-lightness)));
|
color: hsl(var(--accent-hue), 100%, calc(2*var(--accent-lightness)));
|
||||||
@ -210,13 +225,21 @@
|
|||||||
background: var(--background-color4);
|
background: var(--background-color4);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
#merge-type-tabs {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
#merge-log-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.merge-container #merge-warning {
|
||||||
|
color: rgb(153, 153, 153);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
`)
|
`)
|
||||||
|
|
||||||
merge.innerHTML = `
|
merge.innerHTML = `
|
||||||
<div class="merge-container panel-box">
|
<div class="merge-container panel-box">
|
||||||
<div class="merge-input">
|
<div class="merge-input">
|
||||||
<h1>Batch merger</h1>
|
|
||||||
<p><label for="#mergeModelA">Select Model A:</label></p>
|
<p><label for="#mergeModelA">Select Model A:</label></p>
|
||||||
<select id="mergeModelA">
|
<select id="mergeModelA">
|
||||||
<option>A</option>
|
<option>A</option>
|
||||||
@ -225,50 +248,95 @@
|
|||||||
<select id="mergeModelB">
|
<select id="mergeModelB">
|
||||||
<option>A</option>
|
<option>A</option>
|
||||||
</select>
|
</select>
|
||||||
<p><label for="#merge-log">Log messages:</label></p>
|
<br/><br/>
|
||||||
<div id="merge-log"></div>
|
<p id="merge-warning"><small><b>Important:</b> Please merge models of similar type.<br/>For e.g. <code>SD 1.4</code> models with only <code>SD 1.4/1.5</code> models,<br/><code>SD 2.0</code> with <code>SD 2.0</code>-type, and <code>SD 2.1</code> with <code>SD 2.1</code>-type models.</small></p>
|
||||||
|
<br/>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><label for="#merge-filename">Output file name:</label></td>
|
||||||
|
<td><input id="merge-filename" size=24> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Base name of the output file.<br>Mix ratio and file suffix will be appended to this.</span></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="#merge-fp">Output precision:</label></td>
|
||||||
|
<td><select id="merge-fp">
|
||||||
|
<option value="fp16">fp16 (smaller file size)</option>
|
||||||
|
<option value="fp32">fp32 (larger file size)</option>
|
||||||
|
</select>
|
||||||
|
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Image generation uses fp16, so it's a good choice.<br>Use fp32 if you want to use the result models for more mixes</span></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="#merge-format">Output file format:</label></td>
|
||||||
|
<td><select id="merge-format">
|
||||||
|
<option value="safetensors">Safetensors (recommended)</option>
|
||||||
|
<option value="ckpt">CKPT/Pickle (legacy format)</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<br/>
|
||||||
|
<div id="merge-log-container">
|
||||||
|
<p><label for="#merge-log">Log messages:</label></p>
|
||||||
|
<div id="merge-log"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="merge-config">
|
<div class="merge-config">
|
||||||
<table>
|
<div class="tab-container">
|
||||||
<tr><td><label for="#merge-count">Step count:</label></td>
|
<span id="tab-merge-opts-single" class="tab active">
|
||||||
<td> <input id="merge-count" size=2 value="5"></td>
|
<span>Make a single file</small></span>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Number of models to create</span></i></td></tr>
|
</span>
|
||||||
<tr><td><label for="#merge-start">Start batch from:</label></td>
|
<span id="tab-merge-opts-batch" class="tab">
|
||||||
<td> <input id="merge-start" size=2 value="5">%</td>
|
<span>Make multiple variations</small></span>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Smallest share of model A in the mix</span></i></td></tr>
|
</span>
|
||||||
<tr><td><label for="#merge-step">Step size:</label></td>
|
</div>
|
||||||
<td> <input id="merge-step" size=2 value="10">%</td>
|
<div>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Share of model A added into the mix per step</span></i></td></tr>
|
<div id="tab-content-merge-opts-single" class="tab-content active">
|
||||||
<tr><td><label for="#merge-interpolation">Interpolation model:</label></td>
|
<div class="tab-content-inner">
|
||||||
<td> <select id="merge-interpolation">
|
<small>Saves a single merged model file, at the specified merge ratio.</small><br/><br/>
|
||||||
<option>Exact</option>
|
<label for="#single-merge-ratio-slider">Merge ratio:</label>
|
||||||
<option>SmoothStep</option>
|
<input id="single-merge-ratio-slider" name="single-merge-ratio-slider" class="editor-slider" value="50" type="range" min="1" max="1000">
|
||||||
<option>SmootherStep</option>
|
<input id="single-merge-ratio" size=2 value="5">%
|
||||||
<option>SmoothestStep</option>
|
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Model A's contribution to the mix. The rest will be from Model B.</span></i>
|
||||||
</select></td>
|
</div>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Sigmoid function to be applied to the model share before mixing</span></i></td></tr>
|
</div>
|
||||||
<tr><td><label for="#merge-fp">Float precision:</label></td><td> <select id="merge-fp">
|
<div id="tab-content-merge-opts-batch" class="tab-content">
|
||||||
<option value="fp16">fp16 - Half precision (compact file size)</option>
|
<div class="tab-content-inner">
|
||||||
<option value="fp32">fp32 - Full precision (larger file size)</option>
|
<small>Saves multiple variations of the model, at different merge ratios.<br/>Each variation will be saved as a separate file.</small><br/><br/>
|
||||||
</select></td>
|
<table>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Image generation uses fp16, so it's a good choice.<br>Use fp32 if you want to use the result models for more mixes</span></i></td></tr>
|
<tr><td><label for="#merge-count">Number of variations:</label></td>
|
||||||
<hr />
|
<td> <input id="merge-count" size=2 value="5"></td>
|
||||||
<tr><td><label for="#merge-filename">Output file name:</label></td>
|
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Number of models to create</span></i></td></tr>
|
||||||
<td> <input id="merge-filename" size=24></td>
|
<tr><td><label for="#merge-start">Starting merge ratio:</label></td>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Base name of the output file.<br>Mix ratio and file suffix will be appended to this.</span></i></td></tr>
|
<td> <input id="merge-start" size=2 value="5">%</td>
|
||||||
<tr><td><label for="#merge-format">File format:</label></td><td> <select id="merge-format">
|
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Smallest share of model A in the mix</span></i></td></tr>
|
||||||
<option value="safetensors">Safetensors (recommended)</option>
|
<tr><td><label for="#merge-step">Increment each step:</label></td>
|
||||||
<option value="ckpt">CKPT (legacy format)</option>
|
<td> <input id="merge-step" size=2 value="10">%</td>
|
||||||
</select></td>
|
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Share of model A added into the mix per step</span></i></td></tr>
|
||||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Use safetensors. It's the better format. Only use ckpt if you want to use<br>the models in legacy software not supporting saftensors.</span></i></td></tr>
|
<tr><td><label for="#merge-interpolation">Interpolation model:</label></td>
|
||||||
</table>
|
<td> <select id="merge-interpolation">
|
||||||
<canvas id="merge-canvas" width="400" height="400"></canvas>
|
<option>Exact</option>
|
||||||
|
<option>SmoothStep</option>
|
||||||
|
<option>SmootherStep</option>
|
||||||
|
<option>SmoothestStep</option>
|
||||||
|
</select></td>
|
||||||
|
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Sigmoid function to be applied to the model share before mixing</span></i></td></tr>
|
||||||
|
</table>
|
||||||
|
<br/>
|
||||||
|
<small>Preview of variation ratios:</small><br/>
|
||||||
|
<canvas id="merge-canvas" width="400" height="400"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="merge-buttons">
|
<div class="merge-buttons">
|
||||||
<button id="merge-button" class="primaryButton">Merge models</button>
|
<button id="merge-button" class="primaryButton">Merge models</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
|
const tabSettingsSingle = document.querySelector('#tab-merge-opts-single')
|
||||||
|
const tabSettingsBatch = document.querySelector('#tab-merge-opts-batch')
|
||||||
|
linkTabContents(tabSettingsSingle)
|
||||||
|
linkTabContents(tabSettingsBatch)
|
||||||
|
|
||||||
/////////////////////// Event Listener
|
/////////////////////// Event Listener
|
||||||
document.addEventListener('tabClick', (e) => {
|
document.addEventListener('tabClick', (e) => {
|
||||||
@ -276,16 +344,38 @@
|
|||||||
console.log('Activate')
|
console.log('Activate')
|
||||||
let modelList = stableDiffusionModelField.cloneNode(true)
|
let modelList = stableDiffusionModelField.cloneNode(true)
|
||||||
modelList.id = "mergeModelA"
|
modelList.id = "mergeModelA"
|
||||||
modelList.size = 8
|
|
||||||
document.querySelector("#mergeModelA").replaceWith(modelList)
|
document.querySelector("#mergeModelA").replaceWith(modelList)
|
||||||
modelList = stableDiffusionModelField.cloneNode(true)
|
modelList = stableDiffusionModelField.cloneNode(true)
|
||||||
modelList.id = "mergeModelB"
|
modelList.id = "mergeModelB"
|
||||||
modelList.size = 8
|
|
||||||
document.querySelector("#mergeModelB").replaceWith(modelList)
|
document.querySelector("#mergeModelB").replaceWith(modelList)
|
||||||
updateChart()
|
updateChart()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// slider
|
||||||
|
const singleMergeRatioField = document.querySelector('#single-merge-ratio')
|
||||||
|
const singleMergeRatioSlider = document.querySelector('#single-merge-ratio-slider')
|
||||||
|
|
||||||
|
function updateSingleMergeRatio() {
|
||||||
|
singleMergeRatioField.value = singleMergeRatioSlider.value / 10
|
||||||
|
singleMergeRatioField.dispatchEvent(new Event("change"))
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSingleMergeRatioSlider() {
|
||||||
|
if (singleMergeRatioField.value < 0) {
|
||||||
|
singleMergeRatioField.value = 0
|
||||||
|
} else if (singleMergeRatioField.value > 100) {
|
||||||
|
singleMergeRatioField.value = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
singleMergeRatioSlider.value = singleMergeRatioField.value * 10
|
||||||
|
singleMergeRatioSlider.dispatchEvent(new Event("change"))
|
||||||
|
}
|
||||||
|
|
||||||
|
singleMergeRatioSlider.addEventListener('input', updateSingleMergeRatio)
|
||||||
|
singleMergeRatioField.addEventListener('input', updateSingleMergeRatioSlider)
|
||||||
|
updateSingleMergeRatio()
|
||||||
|
|
||||||
document.querySelector('.merge-config').addEventListener('change', updateChart)
|
document.querySelector('.merge-config').addEventListener('change', updateChart)
|
||||||
|
|
||||||
document.querySelector('#merge-button').addEventListener('click', async function(e) {
|
document.querySelector('#merge-button').addEventListener('click', async function(e) {
|
||||||
@ -297,12 +387,20 @@
|
|||||||
let iterations = document.querySelector('#merge-count').value>>0
|
let iterations = document.querySelector('#merge-count').value>>0
|
||||||
let start = parseFloat( document.querySelector('#merge-start').value )
|
let start = parseFloat( document.querySelector('#merge-start').value )
|
||||||
let step = parseFloat( document.querySelector('#merge-step').value )
|
let step = parseFloat( document.querySelector('#merge-step').value )
|
||||||
addLogMessage(`start = ${start}%`)
|
|
||||||
addLogMessage(`step = ${step}%`)
|
|
||||||
|
|
||||||
if (start + iterations * (step-1) >= 100) {
|
if (isTabActive(tabSettingsSingle)) {
|
||||||
|
start = parseFloat(singleMergeRatioField.value)
|
||||||
|
step = 0
|
||||||
|
iterations = 1
|
||||||
|
addLogMessage(`merge ratio = ${start}%`)
|
||||||
|
} else {
|
||||||
|
addLogMessage(`start = ${start}%`)
|
||||||
|
addLogMessage(`step = ${step}%`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start + (iterations-1) * step >= 100) {
|
||||||
addLogMessage('<i>Aborting: maximum ratio is ≥ 100%</i>')
|
addLogMessage('<i>Aborting: maximum ratio is ≥ 100%</i>')
|
||||||
addLogMessage('Reduce the number of steps or the step size')
|
addLogMessage('Reduce the number of variations or the step size')
|
||||||
addLogSeparator()
|
addLogSeparator()
|
||||||
document.querySelector('#merge-count').focus()
|
document.querySelector('#merge-count').focus()
|
||||||
return
|
return
|
||||||
@ -330,12 +428,6 @@
|
|||||||
// Batch main loop
|
// Batch main loop
|
||||||
for (let i=0; i<iterations; i++) {
|
for (let i=0; i<iterations; i++) {
|
||||||
let alpha = ( start + i * step ) / 100
|
let alpha = ( start + i * step ) / 100
|
||||||
addLogMessage(`merging batch job ${i+1}/${iterations}, alpha = ${alpha}...`)
|
|
||||||
|
|
||||||
request['out_path'] = document.querySelector('#merge-filename').value
|
|
||||||
request['out_path'] += '-' +alpha+ '.' + document.querySelector('#merge-format').value
|
|
||||||
addLogMessage(` filename: ${request['out_path']}`)
|
|
||||||
|
|
||||||
switch (document.querySelector('#merge-interpolation').value) {
|
switch (document.querySelector('#merge-interpolation').value) {
|
||||||
case 'SmoothStep':
|
case 'SmoothStep':
|
||||||
alpha = smoothstep(alpha)
|
alpha = smoothstep(alpha)
|
||||||
@ -347,6 +439,12 @@
|
|||||||
alpha = smootheststep(alpha)
|
alpha = smootheststep(alpha)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
addLogMessage(`merging batch job ${i+1}/${iterations}, alpha = ${alpha.toFixed(5)}...`)
|
||||||
|
|
||||||
|
request['out_path'] = document.querySelector('#merge-filename').value
|
||||||
|
request['out_path'] += '-' + alpha.toFixed(5) + '.' + document.querySelector('#merge-format').value
|
||||||
|
addLogMessage(` filename: ${request['out_path']}`)
|
||||||
|
|
||||||
request['ratio'] = alpha
|
request['ratio'] = alpha
|
||||||
let res = await fetch('/model/merge', {
|
let res = await fetch('/model/merge', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector('#tab-container')?.insertAdjacentHTML('beforeend', `
|
document.querySelector('.tab-container')?.insertAdjacentHTML('beforeend', `
|
||||||
<span id="tab-news" class="tab">
|
<span id="tab-news" class="tab">
|
||||||
<span><i class="fa fa-bolt icon"></i> What's new?</span>
|
<span><i class="fa fa-bolt icon"></i> What's new?</span>
|
||||||
</span>
|
</span>
|
||||||
|
Reference in New Issue
Block a user