atikur-rabbi commited on
Commit
2b16701
1 Parent(s): a6ec9cb
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. developer_console.sh +0 -53
  2. scripts/check_modules.py +0 -13
  3. scripts/config.sh +0 -6
  4. scripts/functions.sh +1 -1
  5. scripts/install_status.txt +0 -1
  6. scripts/on_sd_start.sh +0 -323
  7. ui/__pycache__/main.cpython-38.pyc +0 -0
  8. ui/easydiffusion/__init__.py +0 -0
  9. ui/easydiffusion/__pycache__/__init__.cpython-38.pyc +0 -0
  10. ui/easydiffusion/__pycache__/app.cpython-38.pyc +0 -0
  11. ui/easydiffusion/__pycache__/device_manager.cpython-38.pyc +0 -0
  12. ui/easydiffusion/__pycache__/model_manager.cpython-38.pyc +0 -0
  13. ui/easydiffusion/__pycache__/renderer.cpython-38.pyc +0 -0
  14. ui/easydiffusion/__pycache__/server.cpython-38.pyc +0 -0
  15. ui/easydiffusion/__pycache__/task_manager.cpython-38.pyc +0 -0
  16. ui/easydiffusion/__pycache__/types.cpython-38.pyc +0 -0
  17. ui/easydiffusion/app.py +0 -328
  18. ui/easydiffusion/device_manager.py +0 -253
  19. ui/easydiffusion/model_manager.py +0 -255
  20. ui/easydiffusion/renderer.py +0 -180
  21. ui/easydiffusion/server.py +0 -304
  22. ui/easydiffusion/task_manager.py +0 -565
  23. ui/easydiffusion/types.py +0 -103
  24. ui/easydiffusion/utils/__init__.py +0 -8
  25. ui/easydiffusion/utils/__pycache__/__init__.cpython-38.pyc +0 -0
  26. ui/easydiffusion/utils/__pycache__/save_utils.cpython-38.pyc +0 -0
  27. ui/easydiffusion/utils/save_utils.py +0 -131
  28. ui/hotfix/9c24e6cd9f499d02c4f21a033736dabd365962dc80fe3aeb57a8f85ea45a20a3.26fead7ea4f0f843f6eb4055dfd25693f1a71f3c6871b184042d4b126244e142 +0 -171
  29. ui/index.html +0 -514
  30. ui/main.py +0 -10
  31. ui/media/css/auto-save.css +0 -81
  32. ui/media/css/fontawesome-all.min.css +0 -0
  33. ui/media/css/fonts.css +0 -40
  34. ui/media/css/image-editor.css +0 -228
  35. ui/media/css/image-modal.css +0 -84
  36. ui/media/css/jquery-confirm.min.css +0 -9
  37. ui/media/css/main.css +0 -1298
  38. ui/media/css/modifier-thumbnails.css +0 -223
  39. ui/media/css/searchable-models.css +0 -99
  40. ui/media/css/themes.css +0 -186
  41. ui/media/ding.mp3 +0 -0
  42. ui/media/fonts/fa-brands-400.ttf +0 -0
  43. ui/media/fonts/fa-brands-400.woff2 +0 -0
  44. ui/media/fonts/fa-regular-400.ttf +0 -0
  45. ui/media/fonts/fa-regular-400.woff2 +0 -0
  46. ui/media/fonts/fa-solid-900.ttf +0 -0
  47. ui/media/fonts/fa-solid-900.woff2 +0 -0
  48. ui/media/fonts/fa-v4compatibility.ttf +0 -0
  49. ui/media/fonts/fa-v4compatibility.woff2 +0 -0
  50. ui/media/fonts/work-sans-v18-latin-600.woff +0 -0
developer_console.sh DELETED
@@ -1,53 +0,0 @@
1
- #!/bin/bash
2
-
3
- cd "$(dirname "${BASH_SOURCE[0]}")"
4
-
5
- if [ "$0" == "bash" ]; then
6
- echo "Opening Stable Diffusion UI - Developer Console.."
7
- echo ""
8
-
9
- # set legacy and new installer's PATH, if they exist
10
- if [ -e "installer" ]; then export PATH="$(pwd)/installer/bin:$PATH"; fi
11
- if [ -e "installer_files/env" ]; then export PATH="$(pwd)/installer_files/env/bin:$PATH"; fi
12
-
13
- # activate the installer env
14
- CONDA_BASEPATH=$(conda info --base)
15
- source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # avoids the 'shell not initialized' error
16
-
17
- conda activate
18
-
19
- # test the environment
20
- echo "Environment Info:"
21
- which git
22
- git --version
23
-
24
- which conda
25
- conda --version
26
-
27
- echo ""
28
-
29
- # activate the legacy environment (if present) and set PYTHONPATH
30
- if [ -e "installer_files/env" ]; then
31
- export PYTHONPATH="$(pwd)/installer_files/env/lib/python3.8/site-packages"
32
- fi
33
- if [ -e "stable-diffusion/env" ]; then
34
- CONDA_BASEPATH=$(conda info --base)
35
- source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # otherwise conda complains about 'shell not initialized' (needed when running in a script)
36
-
37
- conda activate ./stable-diffusion/env
38
-
39
- export PYTHONPATH="$(pwd)/stable-diffusion/env/lib/python3.8/site-packages"
40
- fi
41
-
42
- which python
43
- python --version
44
-
45
- echo "PYTHONPATH=$PYTHONPATH"
46
-
47
- # done
48
-
49
- echo ""
50
- else
51
- file_name=$(basename "${BASH_SOURCE[0]}")
52
- bash --init-file "$file_name"
53
- fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/check_modules.py DELETED
@@ -1,13 +0,0 @@
1
- '''
2
- This script checks if the given modules exist
3
- '''
4
-
5
- import sys
6
- import pkgutil
7
-
8
- modules = sys.argv[1:]
9
- missing_modules = []
10
- for m in modules:
11
- if pkgutil.find_loader(m) is None:
12
- print('module', m, 'not found')
13
- exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/config.sh DELETED
@@ -1,6 +0,0 @@
1
- # get value from environment variable port
2
- # if not set, use default value 9990
3
- # export port to environment variable SD_UI_BIND_PORT
4
- # so that it can be used by other scripts
5
-
6
- # export SD_UI_BIND_PORT=${PORT:-9990}
 
 
 
 
 
 
 
scripts/functions.sh CHANGED
@@ -31,7 +31,7 @@ EOF
31
  filesize() {
32
  case "$(uname -s)" in
33
  Linux*) stat -c "%s" $1;;
34
- Darwin*) /usr/bin/stat -f "%z" $1;;
35
  *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
36
  esac
37
  }
 
31
  filesize() {
32
  case "$(uname -s)" in
33
  Linux*) stat -c "%s" $1;;
34
+ Darwin*) stat -f "%z" $1;;
35
  *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
36
  esac
37
  }
scripts/install_status.txt CHANGED
@@ -1,2 +1 @@
1
 
2
- sd_ui_git_cloned
 
1
 
 
scripts/on_sd_start.sh DELETED
@@ -1,323 +0,0 @@
1
- #!/bin/bash
2
-
3
- cp sd-ui-files/scripts/functions.sh scripts/
4
- cp sd-ui-files/scripts/on_env_start.sh scripts/
5
- cp sd-ui-files/scripts/bootstrap.sh scripts/
6
- cp sd-ui-files/scripts/check_modules.py scripts/
7
-
8
- source ./scripts/functions.sh
9
-
10
- # activate the installer env
11
- CONDA_BASEPATH=$(conda info --base)
12
- source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # avoids the 'shell not initialized' error
13
-
14
- conda activate || fail "Failed to activate conda"
15
-
16
- # remove the old version of the dev console script, if it's still present
17
- if [ -e "open_dev_console.sh" ]; then
18
- rm "open_dev_console.sh"
19
- fi
20
-
21
- python -c "import os; import shutil; frm = 'sd-ui-files/ui/hotfix/9c24e6cd9f499d02c4f21a033736dabd365962dc80fe3aeb57a8f85ea45a20a3.26fead7ea4f0f843f6eb4055dfd25693f1a71f3c6871b184042d4b126244e142'; dst = os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'transformers', '9c24e6cd9f499d02c4f21a033736dabd365962dc80fe3aeb57a8f85ea45a20a3.26fead7ea4f0f843f6eb4055dfd25693f1a71f3c6871b184042d4b126244e142'); shutil.copyfile(frm, dst) if os.path.exists(dst) else print(''); print('Hotfixed broken JSON file from OpenAI');"
22
-
23
- # Caution, this file will make your eyes and brain bleed. It's such an unholy mess.
24
- # Note to self: Please rewrite this in Python. For the sake of your own sanity.
25
-
26
- # set the correct installer path (current vs legacy)
27
- if [ -e "installer_files/env" ]; then
28
- export INSTALL_ENV_DIR="$(pwd)/installer_files/env"
29
- fi
30
- if [ -e "stable-diffusion/env" ]; then
31
- export INSTALL_ENV_DIR="$(pwd)/stable-diffusion/env"
32
- fi
33
-
34
- # create the stable-diffusion folder, to work with legacy installations
35
- if [ ! -e "stable-diffusion" ]; then mkdir stable-diffusion; fi
36
- cd stable-diffusion
37
-
38
- # activate the old stable-diffusion env, if it exists
39
- if [ -e "env" ]; then
40
- conda activate ./env || fail "conda activate failed"
41
- fi
42
-
43
- # disable the legacy src and ldm folder (otherwise this prevents installing gfpgan and realesrgan)
44
- if [ -e "src" ]; then mv src src-old; fi
45
- if [ -e "ldm" ]; then mv ldm ldm-old; fi
46
-
47
- mkdir -p "../models/stable-diffusion"
48
- mkdir -p "../models/gfpgan"
49
- mkdir -p "../models/realesrgan"
50
- mkdir -p "../models/vae"
51
-
52
- # migrate the legacy models to the correct path (if already downloaded)
53
- if [ -e "sd-v1-4.ckpt" ]; then mv sd-v1-4.ckpt ../models/stable-diffusion/; fi
54
- if [ -e "custom-model.ckpt" ]; then mv custom-model.ckpt ../models/stable-diffusion/; fi
55
- if [ -e "GFPGANv1.3.pth" ]; then mv GFPGANv1.3.pth ../models/gfpgan/; fi
56
- if [ -e "RealESRGAN_x4plus.pth" ]; then mv RealESRGAN_x4plus.pth ../models/realesrgan/; fi
57
- if [ -e "RealESRGAN_x4plus_anime_6B.pth" ]; then mv RealESRGAN_x4plus_anime_6B.pth ../models/realesrgan/; fi
58
-
59
- OS_NAME=$(uname -s)
60
- case "${OS_NAME}" in
61
- Linux*) OS_NAME="linux";;
62
- Darwin*) OS_NAME="macos";;
63
- *) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
64
- esac
65
-
66
- # install torch and torchvision
67
- if python ../scripts/check_modules.py torch torchvision; then
68
- # temp fix for installations that installed torch 2.0 by mistake
69
- if [ "$OS_NAME" == "linux" ]; then
70
- python -m pip install --upgrade torch==1.13.1+cu116 torchvision==0.14.1+cu116 --extra-index-url https://download.pytorch.org/whl/cu116 -q
71
- elif [ "$OS_NAME" == "macos" ]; then
72
- python -m pip install --upgrade torch==1.13.1 torchvision==0.14.1 -q
73
- fi
74
-
75
- echo "torch and torchvision have already been installed."
76
- else
77
- echo "Installing torch and torchvision.."
78
-
79
- export PYTHONNOUSERSITE=1
80
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
81
-
82
- if [ "$OS_NAME" == "linux" ]; then
83
- if python -m pip install --upgrade torch==1.13.1+cu116 torchvision==0.14.1+cu116 --extra-index-url https://download.pytorch.org/whl/cu116 ; then
84
- echo "Installed."
85
- else
86
- fail "torch install failed"
87
- fi
88
- elif [ "$OS_NAME" == "macos" ]; then
89
- if python -m pip install --upgrade torch==1.13.1 torchvision==0.14.1 ; then
90
- echo "Installed."
91
- else
92
- fail "torch install failed"
93
- fi
94
- fi
95
- fi
96
-
97
- # install/upgrade sdkit
98
- if python ../scripts/check_modules.py sdkit sdkit.models ldm transformers numpy antlr4 gfpgan realesrgan ; then
99
- echo "sdkit is already installed."
100
-
101
- # skip sdkit upgrade if in developer-mode
102
- if [ ! -e "../src/sdkit" ]; then
103
- export PYTHONNOUSERSITE=1
104
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
105
-
106
- python -m pip install --upgrade sdkit==1.0.48 -q
107
- fi
108
- else
109
- echo "Installing sdkit: https://pypi.org/project/sdkit/"
110
-
111
- export PYTHONNOUSERSITE=1
112
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
113
-
114
- if python -m pip install sdkit==1.0.48 ; then
115
- echo "Installed."
116
- else
117
- fail "sdkit install failed"
118
- fi
119
- fi
120
-
121
- python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
122
-
123
- # upgrade stable-diffusion-sdkit
124
- python -m pip install --upgrade stable-diffusion-sdkit==2.1.4 -q
125
- python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
126
-
127
- # install rich
128
- if python ../scripts/check_modules.py rich; then
129
- echo "rich has already been installed."
130
- else
131
- echo "Installing rich.."
132
-
133
- export PYTHONNOUSERSITE=1
134
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
135
-
136
- if python -m pip install rich ; then
137
- echo "Installed."
138
- else
139
- fail "Install failed for rich"
140
- fi
141
- fi
142
-
143
- if python ../scripts/check_modules.py uvicorn fastapi ; then
144
- echo "Packages necessary for Easy Diffusion were already installed"
145
- else
146
- printf "\n\nDownloading packages necessary for Easy Diffusion..\n\n"
147
-
148
- export PYTHONNOUSERSITE=1
149
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
150
-
151
- if conda install -c conda-forge -y uvicorn fastapi ; then
152
- echo "Installed. Testing.."
153
- else
154
- fail "'conda install uvicorn' failed"
155
- fi
156
-
157
- if ! command -v uvicorn &> /dev/null; then
158
- fail "UI packages not found!"
159
- fi
160
- fi
161
-
162
- if [ -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
163
- model_size=`filesize "../models/stable-diffusion/sd-v1-4.ckpt"`
164
-
165
- if [ "$model_size" -eq "4265380512" ] || [ "$model_size" -eq "7703807346" ] || [ "$model_size" -eq "7703810927" ]; then
166
- echo "Data files (weights) necessary for Stable Diffusion were already downloaded"
167
- else
168
- printf "\n\nThe model file present at models/stable-diffusion/sd-v1-4.ckpt is invalid. It is only $model_size bytes in size. Re-downloading.."
169
- rm ../models/stable-diffusion/sd-v1-4.ckpt
170
- fi
171
- fi
172
-
173
- if [ ! -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
174
- echo "Downloading data files (weights) for Stable Diffusion.."
175
-
176
- curl -L -k https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt > ../models/stable-diffusion/sd-v1-4.ckpt
177
-
178
- if [ -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
179
- model_size=`filesize "../models/stable-diffusion/sd-v1-4.ckpt"`
180
- if [ ! "$model_size" == "4265380512" ]; then
181
- fail "The downloaded model file was invalid! Bytes downloaded: $model_size"
182
- fi
183
- else
184
- fail "Error downloading the data files (weights) for Stable Diffusion"
185
- fi
186
- fi
187
-
188
-
189
- if [ -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
190
- model_size=`filesize "../models/gfpgan/GFPGANv1.3.pth"`
191
-
192
- if [ "$model_size" -eq "348632874" ]; then
193
- echo "Data files (weights) necessary for GFPGAN (Face Correction) were already downloaded"
194
- else
195
- printf "\n\nThe model file present at models/gfpgan/GFPGANv1.3.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
196
- rm ../models/gfpgan/GFPGANv1.3.pth
197
- fi
198
- fi
199
-
200
- if [ ! -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
201
- echo "Downloading data files (weights) for GFPGAN (Face Correction).."
202
-
203
- curl -L -k https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth > ../models/gfpgan/GFPGANv1.3.pth
204
-
205
- if [ -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
206
- model_size=`filesize "../models/gfpgan/GFPGANv1.3.pth"`
207
- if [ ! "$model_size" -eq "348632874" ]; then
208
- fail "The downloaded GFPGAN model file was invalid! Bytes downloaded: $model_size"
209
- fi
210
- else
211
- fail "Error downloading the data files (weights) for GFPGAN (Face Correction)."
212
- fi
213
- fi
214
-
215
-
216
- if [ -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
217
- model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus.pth"`
218
-
219
- if [ "$model_size" -eq "67040989" ]; then
220
- echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus were already downloaded"
221
- else
222
- printf "\n\nThe model file present at models/realesrgan/RealESRGAN_x4plus.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
223
- rm ../models/realesrgan/RealESRGAN_x4plus.pth
224
- fi
225
- fi
226
-
227
- if [ ! -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
228
- echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus.."
229
-
230
- curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth > ../models/realesrgan/RealESRGAN_x4plus.pth
231
-
232
- if [ -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
233
- model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus.pth"`
234
- if [ ! "$model_size" -eq "67040989" ]; then
235
- fail "The downloaded ESRGAN x4plus model file was invalid! Bytes downloaded: $model_size"
236
- fi
237
- else
238
- fail "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus"
239
- fi
240
- fi
241
-
242
-
243
- if [ -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
244
- model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth"`
245
-
246
- if [ "$model_size" -eq "17938799" ]; then
247
- echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus_anime were already downloaded"
248
- else
249
- printf "\n\nThe model file present at models/realesrgan/RealESRGAN_x4plus_anime_6B.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
250
- rm ../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth
251
- fi
252
- fi
253
-
254
- if [ ! -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
255
- echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime.."
256
-
257
- curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth > ../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth
258
-
259
- if [ -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
260
- model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth"`
261
- if [ ! "$model_size" -eq "17938799" ]; then
262
- fail "The downloaded ESRGAN x4plus_anime model file was invalid! Bytes downloaded: $model_size"
263
- fi
264
- else
265
- fail "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime."
266
- fi
267
- fi
268
-
269
-
270
- if [ -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
271
- model_size=`filesize "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt"`
272
-
273
- if [ "$model_size" -eq "334695179" ]; then
274
- echo "Data files (weights) necessary for the default VAE (sd-vae-ft-mse-original) were already downloaded"
275
- else
276
- printf "\n\nThe model file present at models/vae/vae-ft-mse-840000-ema-pruned.ckpt is invalid. It is only $model_size bytes in size. Re-downloading.."
277
- rm ../models/vae/vae-ft-mse-840000-ema-pruned.ckpt
278
- fi
279
- fi
280
-
281
- if [ ! -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
282
- echo "Downloading data files (weights) for the default VAE (sd-vae-ft-mse-original).."
283
-
284
- curl -L -k https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.ckpt > ../models/vae/vae-ft-mse-840000-ema-pruned.ckpt
285
-
286
- if [ -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
287
- model_size=`filesize "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt"`
288
- if [ ! "$model_size" -eq "334695179" ]; then
289
- printf "\n\nError: The downloaded default VAE (sd-vae-ft-mse-original) file was invalid! Bytes downloaded: $model_size\n\n"
290
- printf "\n\nError downloading the data files (weights) for the default VAE (sd-vae-ft-mse-original). Sorry about that, please try to:\n 1. Run this installer again.\n 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting\n 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\n 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues\nThanks!\n\n"
291
- read -p "Press any key to continue"
292
- exit
293
- fi
294
- else
295
- printf "\n\nError downloading the data files (weights) for the default VAE (sd-vae-ft-mse-original). Sorry about that, please try to:\n 1. Run this installer again.\n 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting\n 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\n 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues\nThanks!\n\n"
296
- read -p "Press any key to continue"
297
- exit
298
- fi
299
- fi
300
-
301
- if [ `grep -c sd_install_complete ../scripts/install_status.txt` -gt "0" ]; then
302
- echo sd_weights_downloaded >> ../scripts/install_status.txt
303
- echo sd_install_complete >> ../scripts/install_status.txt
304
- fi
305
-
306
- printf "\n\nEasy Diffusion installation complete, starting the server!\n\n"
307
-
308
- SD_PATH=`pwd`
309
-
310
- export PYTORCH_ENABLE_MPS_FALLBACK=1
311
- export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
312
- echo "PYTHONPATH=$PYTHONPATH"
313
-
314
- which python
315
- python --version
316
-
317
- cd ..
318
- export SD_UI_PATH=`pwd`/ui
319
- cd stable-diffusion
320
-
321
- uvicorn main:server_api --app-dir "$SD_UI_PATH" --port ${SD_UI_BIND_PORT:-9000} --host ${SD_UI_BIND_IP:-0.0.0.0} --log-level error
322
-
323
- read -p "Press any key to continue"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/__pycache__/main.cpython-38.pyc DELETED
Binary file (331 Bytes)
 
ui/easydiffusion/__init__.py DELETED
File without changes
ui/easydiffusion/__pycache__/__init__.cpython-38.pyc DELETED
Binary file (152 Bytes)
 
ui/easydiffusion/__pycache__/app.cpython-38.pyc DELETED
Binary file (9.25 kB)
 
ui/easydiffusion/__pycache__/device_manager.cpython-38.pyc DELETED
Binary file (6.7 kB)
 
ui/easydiffusion/__pycache__/model_manager.cpython-38.pyc DELETED
Binary file (7 kB)
 
ui/easydiffusion/__pycache__/renderer.cpython-38.pyc DELETED
Binary file (5.05 kB)
 
ui/easydiffusion/__pycache__/server.cpython-38.pyc DELETED
Binary file (10.4 kB)
 
ui/easydiffusion/__pycache__/task_manager.cpython-38.pyc DELETED
Binary file (15.5 kB)
 
ui/easydiffusion/__pycache__/types.cpython-38.pyc DELETED
Binary file (3.47 kB)
 
ui/easydiffusion/app.py DELETED
@@ -1,328 +0,0 @@
1
- import os
2
- import socket
3
- import sys
4
- import json
5
- import traceback
6
- import logging
7
- import shlex
8
- import urllib
9
- from rich.logging import RichHandler
10
-
11
- from sdkit.utils import log as sdkit_log # hack, so we can overwrite the log config
12
-
13
- from easydiffusion import task_manager
14
- from easydiffusion.utils import log
15
-
16
- # Remove all handlers associated with the root logger object.
17
- for handler in logging.root.handlers[:]:
18
- logging.root.removeHandler(handler)
19
-
20
- LOG_FORMAT = "%(asctime)s.%(msecs)03d %(levelname)s %(threadName)s %(message)s"
21
- logging.basicConfig(
22
- level=logging.INFO,
23
- format=LOG_FORMAT,
24
- datefmt="%X",
25
- handlers=[RichHandler(markup=True, rich_tracebacks=False, show_time=False, show_level=False)],
26
- )
27
-
28
- SD_DIR = os.getcwd()
29
-
30
- SD_UI_DIR = os.getenv("SD_UI_PATH", None)
31
-
32
- CONFIG_DIR = os.path.abspath(os.path.join(SD_UI_DIR, "..", "scripts"))
33
- MODELS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "models"))
34
-
35
- USER_PLUGINS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "plugins"))
36
- CORE_PLUGINS_DIR = os.path.abspath(os.path.join(SD_UI_DIR, "plugins"))
37
-
38
- USER_UI_PLUGINS_DIR = os.path.join(USER_PLUGINS_DIR, "ui")
39
- CORE_UI_PLUGINS_DIR = os.path.join(CORE_PLUGINS_DIR, "ui")
40
- USER_SERVER_PLUGINS_DIR = os.path.join(USER_PLUGINS_DIR, "server")
41
- UI_PLUGINS_SOURCES = ((CORE_UI_PLUGINS_DIR, "core"), (USER_UI_PLUGINS_DIR, "user"))
42
-
43
- sys.path.append(os.path.dirname(SD_UI_DIR))
44
- sys.path.append(USER_SERVER_PLUGINS_DIR)
45
-
46
- OUTPUT_DIRNAME = "Stable Diffusion UI" # in the user's home folder
47
- PRESERVE_CONFIG_VARS = ["FORCE_FULL_PRECISION"]
48
- TASK_TTL = 15 * 60 # Discard last session's task timeout
49
- APP_CONFIG_DEFAULTS = {
50
- # auto: selects the cuda device with the most free memory, cuda: use the currently active cuda device.
51
- "render_devices": "auto", # valid entries: 'auto', 'cpu' or 'cuda:N' (where N is a GPU index)
52
- "update_branch": "main",
53
- "ui": {
54
- "open_browser_on_start": True,
55
- },
56
- }
57
-
58
- IMAGE_EXTENSIONS = [".png", ".apng", ".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".jxl", ".gif", ".webp", ".avif", ".svg"]
59
- CUSTOM_MODIFIERS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "modifiers"))
60
- CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS=[".portrait", "_portrait", " portrait", "-portrait"]
61
- CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS=[".landscape", "_landscape", " landscape", "-landscape"]
62
-
63
- def init():
64
- os.makedirs(USER_UI_PLUGINS_DIR, exist_ok=True)
65
- os.makedirs(USER_SERVER_PLUGINS_DIR, exist_ok=True)
66
-
67
- load_server_plugins()
68
-
69
- update_render_threads()
70
-
71
-
72
- def getConfig(default_val=APP_CONFIG_DEFAULTS):
73
- try:
74
- config_json_path = os.path.join(CONFIG_DIR, "config.json")
75
- if not os.path.exists(config_json_path):
76
- config = default_val
77
- else:
78
- with open(config_json_path, "r", encoding="utf-8") as f:
79
- config = json.load(f)
80
- if "net" not in config:
81
- config["net"] = {}
82
- if os.getenv("SD_UI_BIND_PORT") is not None:
83
- config["net"]["listen_port"] = int(os.getenv("SD_UI_BIND_PORT"))
84
- else:
85
- config["net"]["listen_port"] = 9000
86
- if os.getenv("SD_UI_BIND_IP") is not None:
87
- config["net"]["listen_to_network"] = os.getenv("SD_UI_BIND_IP") == "0.0.0.0"
88
- else:
89
- config["net"]["listen_to_network"] = True
90
- return config
91
- except Exception as e:
92
- log.warn(traceback.format_exc())
93
- return default_val
94
-
95
-
96
- def setConfig(config):
97
- try: # config.json
98
- config_json_path = os.path.join(CONFIG_DIR, "config.json")
99
- with open(config_json_path, "w", encoding="utf-8") as f:
100
- json.dump(config, f)
101
- except:
102
- log.error(traceback.format_exc())
103
-
104
- try: # config.bat
105
- config_bat_path = os.path.join(CONFIG_DIR, "config.bat")
106
- config_bat = []
107
-
108
- if "update_branch" in config:
109
- config_bat.append(f"@set update_branch={config['update_branch']}")
110
-
111
- config_bat.append(f"@set SD_UI_BIND_PORT={config['net']['listen_port']}")
112
- bind_ip = "0.0.0.0" if config["net"]["listen_to_network"] else "127.0.0.1"
113
- config_bat.append(f"@set SD_UI_BIND_IP={bind_ip}")
114
-
115
- # Preserve these variables if they are set
116
- for var in PRESERVE_CONFIG_VARS:
117
- if os.getenv(var) is not None:
118
- config_bat.append(f"@set {var}={os.getenv(var)}")
119
-
120
- if len(config_bat) > 0:
121
- with open(config_bat_path, "w", encoding="utf-8") as f:
122
- f.write("\n".join(config_bat))
123
- except:
124
- log.error(traceback.format_exc())
125
-
126
- try: # config.sh
127
- config_sh_path = os.path.join(CONFIG_DIR, "config.sh")
128
- config_sh = ["#!/bin/bash"]
129
-
130
- if "update_branch" in config:
131
- config_sh.append(f"export update_branch={config['update_branch']}")
132
-
133
- config_sh.append(f"export SD_UI_BIND_PORT={config['net']['listen_port']}")
134
- bind_ip = "0.0.0.0" if config["net"]["listen_to_network"] else "127.0.0.1"
135
- config_sh.append(f"export SD_UI_BIND_IP={bind_ip}")
136
-
137
- # Preserve these variables if they are set
138
- for var in PRESERVE_CONFIG_VARS:
139
- if os.getenv(var) is not None:
140
- config_bat.append(f'export {var}="{shlex.quote(os.getenv(var))}"')
141
-
142
- if len(config_sh) > 1:
143
- with open(config_sh_path, "w", encoding="utf-8") as f:
144
- f.write("\n".join(config_sh))
145
- except:
146
- log.error(traceback.format_exc())
147
-
148
-
149
- def save_to_config(ckpt_model_name, vae_model_name, hypernetwork_model_name, vram_usage_level):
150
- config = getConfig()
151
- if "model" not in config:
152
- config["model"] = {}
153
-
154
- config["model"]["stable-diffusion"] = ckpt_model_name
155
- config["model"]["vae"] = vae_model_name
156
- config["model"]["hypernetwork"] = hypernetwork_model_name
157
-
158
- if vae_model_name is None or vae_model_name == "":
159
- del config["model"]["vae"]
160
- if hypernetwork_model_name is None or hypernetwork_model_name == "":
161
- del config["model"]["hypernetwork"]
162
-
163
- config["vram_usage_level"] = vram_usage_level
164
-
165
- setConfig(config)
166
-
167
-
168
- def update_render_threads():
169
- config = getConfig()
170
- render_devices = config.get("render_devices", "auto")
171
- active_devices = task_manager.get_devices()["active"].keys()
172
-
173
- log.debug(f"requesting for render_devices: {render_devices}")
174
- task_manager.update_render_threads(render_devices, active_devices)
175
-
176
-
177
- def getUIPlugins():
178
- plugins = []
179
-
180
- for plugins_dir, dir_prefix in UI_PLUGINS_SOURCES:
181
- for file in os.listdir(plugins_dir):
182
- if file.endswith(".plugin.js"):
183
- plugins.append(f"/plugins/{dir_prefix}/{file}")
184
-
185
- return plugins
186
-
187
-
188
- def load_server_plugins():
189
- if not os.path.exists(USER_SERVER_PLUGINS_DIR):
190
- return
191
-
192
- import importlib
193
-
194
- def load_plugin(file):
195
- mod_path = file.replace(".py", "")
196
- return importlib.import_module(mod_path)
197
-
198
- def apply_plugin(file, plugin):
199
- if hasattr(plugin, "get_cond_and_uncond"):
200
- import sdkit.generate.image_generator
201
-
202
- sdkit.generate.image_generator.get_cond_and_uncond = plugin.get_cond_and_uncond
203
- log.info(f"Overridden get_cond_and_uncond with the one in the server plugin: {file}")
204
-
205
- for file in os.listdir(USER_SERVER_PLUGINS_DIR):
206
- file_path = os.path.join(USER_SERVER_PLUGINS_DIR, file)
207
- if (not os.path.isdir(file_path) and not file_path.endswith("_plugin.py")) or (
208
- os.path.isdir(file_path) and not file_path.endswith("_plugin")
209
- ):
210
- continue
211
-
212
- try:
213
- log.info(f"Loading server plugin: {file}")
214
- mod = load_plugin(file)
215
-
216
- log.info(f"Applying server plugin: {file}")
217
- apply_plugin(file, mod)
218
- except:
219
- log.warn(f"Error while loading a server plugin")
220
- log.warn(traceback.format_exc())
221
-
222
-
223
- def getIPConfig():
224
- try:
225
- ips = socket.gethostbyname_ex(socket.gethostname())
226
- ips[2].append(ips[0])
227
- return ips[2]
228
- except Exception as e:
229
- log.exception(e)
230
- return []
231
-
232
-
233
- def open_browser():
234
- config = getConfig()
235
- ui = config.get("ui", {})
236
- net = config.get("net", {"listen_port": 9000})
237
- port = net.get("listen_port", 9000)
238
- if ui.get("open_browser_on_start", True):
239
- import webbrowser
240
-
241
- webbrowser.open(f"http://localhost:{port}")
242
-
243
- def get_image_modifiers():
244
- modifiers_json_path = os.path.join(SD_UI_DIR, "modifiers.json")
245
-
246
- modifier_categories = {}
247
- original_category_order=[]
248
- with open(modifiers_json_path, "r", encoding="utf-8") as f:
249
- modifiers_file = json.load(f)
250
-
251
- # The trailing slash is needed to support symlinks
252
- if not os.path.isdir(f"{CUSTOM_MODIFIERS_DIR}/"):
253
- return modifiers_file
254
-
255
- # convert modifiers from a list of objects to a dict of dicts
256
- for category_item in modifiers_file:
257
- category_name = category_item['category']
258
- original_category_order.append(category_name)
259
- category = {}
260
- for modifier_item in category_item['modifiers']:
261
- modifier = {}
262
- for preview_item in modifier_item['previews']:
263
- modifier[preview_item['name']] = preview_item['path']
264
- category[modifier_item['modifier']] = modifier
265
- modifier_categories[category_name] = category
266
-
267
- def scan_directory(directory_path: str, category_name="Modifiers"):
268
- for entry in os.scandir(directory_path):
269
- if entry.is_file():
270
- file_extension = list(filter(lambda e: entry.name.endswith(e), IMAGE_EXTENSIONS))
271
- if len(file_extension) == 0:
272
- continue
273
-
274
- modifier_name = entry.name[: -len(file_extension[0])]
275
- modifier_path = f"custom/{entry.path[len(CUSTOM_MODIFIERS_DIR) + 1:]}"
276
- # URL encode path segments
277
- modifier_path = "/".join(map(lambda segment: urllib.parse.quote(segment), modifier_path.split("/")))
278
- is_portrait = True
279
- is_landscape = True
280
-
281
- portrait_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS))
282
- landscape_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS))
283
-
284
- if len(portrait_extension) > 0:
285
- is_landscape = False
286
- modifier_name = modifier_name[: -len(portrait_extension[0])]
287
- elif len(landscape_extension) > 0:
288
- is_portrait = False
289
- modifier_name = modifier_name[: -len(landscape_extension[0])]
290
-
291
- if (category_name not in modifier_categories):
292
- modifier_categories[category_name] = {}
293
-
294
- category = modifier_categories[category_name]
295
-
296
- if (modifier_name not in category):
297
- category[modifier_name] = {}
298
-
299
- if (is_portrait or "portrait" not in category[modifier_name]):
300
- category[modifier_name]["portrait"] = modifier_path
301
-
302
- if (is_landscape or "landscape" not in category[modifier_name]):
303
- category[modifier_name]["landscape"] = modifier_path
304
- elif entry.is_dir():
305
- scan_directory(
306
- entry.path,
307
- entry.name if directory_path==CUSTOM_MODIFIERS_DIR else f"{category_name}/{entry.name}",
308
- )
309
-
310
- scan_directory(CUSTOM_MODIFIERS_DIR)
311
-
312
- custom_categories = sorted(
313
- [cn for cn in modifier_categories.keys() if cn not in original_category_order],
314
- key=str.casefold,
315
- )
316
-
317
- # convert the modifiers back into a list of objects
318
- modifier_categories_list = []
319
- for category_name in [*original_category_order, *custom_categories]:
320
- category = { 'category': category_name, 'modifiers': [] }
321
- for modifier_name in sorted(modifier_categories[category_name].keys(), key=str.casefold):
322
- modifier = { 'modifier': modifier_name, 'previews': [] }
323
- for preview_name, preview_path in modifier_categories[category_name][modifier_name].items():
324
- modifier['previews'].append({ 'name': preview_name, 'path': preview_path })
325
- category['modifiers'].append(modifier)
326
- modifier_categories_list.append(category)
327
-
328
- return modifier_categories_list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/device_manager.py DELETED
@@ -1,253 +0,0 @@
1
- import os
2
- import platform
3
- import torch
4
- import traceback
5
- import re
6
-
7
- from easydiffusion.utils import log
8
-
9
- """
10
- Set `FORCE_FULL_PRECISION` in the environment variables, or in `config.bat`/`config.sh` to set full precision (i.e. float32).
11
- Otherwise the models will load at half-precision (i.e. float16).
12
-
13
- Half-precision is fine most of the time. Full precision is only needed for working around GPU bugs (like NVIDIA 16xx GPUs).
14
- """
15
-
16
- COMPARABLE_GPU_PERCENTILE = (
17
- 0.65 # if a GPU's free_mem is within this % of the GPU with the most free_mem, it will be picked
18
- )
19
-
20
- mem_free_threshold = 0
21
-
22
-
23
- def get_device_delta(render_devices, active_devices):
24
- """
25
- render_devices: 'cpu', or 'auto', or 'mps' or ['cuda:N'...]
26
- active_devices: ['cpu', 'mps', 'cuda:N'...]
27
- """
28
-
29
- if render_devices in ("cpu", "auto", "mps"):
30
- render_devices = [render_devices]
31
- elif render_devices is not None:
32
- if isinstance(render_devices, str):
33
- render_devices = [render_devices]
34
- if isinstance(render_devices, list) and len(render_devices) > 0:
35
- render_devices = list(filter(lambda x: x.startswith("cuda:") or x == "mps", render_devices))
36
- if len(render_devices) == 0:
37
- raise Exception(
38
- '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"}'
39
- )
40
-
41
- render_devices = list(filter(lambda x: is_device_compatible(x), render_devices))
42
- if len(render_devices) == 0:
43
- raise Exception(
44
- "Sorry, none of the render_devices configured in config.json are compatible with Stable Diffusion"
45
- )
46
- else:
47
- raise Exception(
48
- 'Invalid render_devices value in config.json. Valid: {"render_devices": ["cuda:0", "cuda:1"...]}, or {"render_devices": "cpu"} or {"render_devices": "auto"}'
49
- )
50
- else:
51
- render_devices = ["auto"]
52
-
53
- if "auto" in render_devices:
54
- render_devices = auto_pick_devices(active_devices)
55
- if "cpu" in render_devices:
56
- log.warn("WARNING: Could not find a compatible GPU. Using the CPU, but this will be very slow!")
57
-
58
- active_devices = set(active_devices)
59
- render_devices = set(render_devices)
60
-
61
- devices_to_start = render_devices - active_devices
62
- devices_to_stop = active_devices - render_devices
63
-
64
- return devices_to_start, devices_to_stop
65
-
66
-
67
- def is_mps_available():
68
- return (
69
- platform.system() == "Darwin"
70
- and hasattr(torch.backends, "mps")
71
- and torch.backends.mps.is_available()
72
- and torch.backends.mps.is_built()
73
- )
74
-
75
-
76
- def is_cuda_available():
77
- return torch.cuda.is_available()
78
-
79
-
80
- def auto_pick_devices(currently_active_devices):
81
- global mem_free_threshold
82
-
83
- if is_mps_available():
84
- return ["mps"]
85
-
86
- if not is_cuda_available():
87
- return ["cpu"]
88
-
89
- device_count = torch.cuda.device_count()
90
- if device_count == 1:
91
- return ["cuda:0"] if is_device_compatible("cuda:0") else ["cpu"]
92
-
93
- log.debug("Autoselecting GPU. Using most free memory.")
94
- devices = []
95
- for device in range(device_count):
96
- device = f"cuda:{device}"
97
- if not is_device_compatible(device):
98
- continue
99
-
100
- mem_free, mem_total = torch.cuda.mem_get_info(device)
101
- mem_free /= float(10**9)
102
- mem_total /= float(10**9)
103
- device_name = torch.cuda.get_device_name(device)
104
- log.debug(
105
- f"{device} detected: {device_name} - Memory (free/total): {round(mem_free, 2)}Gb / {round(mem_total, 2)}Gb"
106
- )
107
- devices.append({"device": device, "device_name": device_name, "mem_free": mem_free})
108
-
109
- devices.sort(key=lambda x: x["mem_free"], reverse=True)
110
- max_mem_free = devices[0]["mem_free"]
111
- curr_mem_free_threshold = COMPARABLE_GPU_PERCENTILE * max_mem_free
112
- mem_free_threshold = max(curr_mem_free_threshold, mem_free_threshold)
113
-
114
- # Auto-pick algorithm:
115
- # 1. Pick the top 75 percentile of the GPUs, sorted by free_mem.
116
- # 2. Also include already-running devices (GPU-only), otherwise their free_mem will
117
- # always be very low (since their VRAM contains the model).
118
- # These already-running devices probably aren't terrible, since they were picked in the past.
119
- # Worst case, the user can restart the program and that'll get rid of them.
120
- devices = list(
121
- filter((lambda x: x["mem_free"] > mem_free_threshold or x["device"] in currently_active_devices), devices)
122
- )
123
- devices = list(map(lambda x: x["device"], devices))
124
- return devices
125
-
126
-
127
- def device_init(context, device):
128
- """
129
- This function assumes the 'device' has already been verified to be compatible.
130
- `get_device_delta()` has already filtered out incompatible devices.
131
- """
132
-
133
- validate_device_id(device, log_prefix="device_init")
134
-
135
- if "cuda" not in device:
136
- context.device = device
137
- context.device_name = get_processor_name()
138
- context.half_precision = False
139
- log.debug(f"Render device available as {context.device_name}")
140
- return
141
-
142
- context.device_name = torch.cuda.get_device_name(device)
143
- context.device = device
144
-
145
- # Force full precision on 1660 and 1650 NVIDIA cards to avoid creating green images
146
- if needs_to_force_full_precision(context):
147
- log.warn(f"forcing full precision on this GPU, to avoid green images. GPU detected: {context.device_name}")
148
- # Apply force_full_precision now before models are loaded.
149
- context.half_precision = False
150
-
151
- log.info(f'Setting {device} as active, with precision: {"half" if context.half_precision else "full"}')
152
- torch.cuda.device(device)
153
-
154
-
155
- def needs_to_force_full_precision(context):
156
- if "FORCE_FULL_PRECISION" in os.environ:
157
- return True
158
-
159
- device_name = context.device_name.lower()
160
- return (
161
- ("nvidia" in device_name or "geforce" in device_name or "quadro" in device_name)
162
- and (
163
- " 1660" in device_name
164
- or " 1650" in device_name
165
- or " t400" in device_name
166
- or " t550" in device_name
167
- or " t600" in device_name
168
- or " t1000" in device_name
169
- or " t1200" in device_name
170
- or " t2000" in device_name
171
- )
172
- ) or ("tesla k40m" in device_name)
173
-
174
-
175
- def get_max_vram_usage_level(device):
176
- if "cuda" in device:
177
- _, mem_total = torch.cuda.mem_get_info(device)
178
- else:
179
- return "high"
180
-
181
- mem_total /= float(10**9)
182
- if mem_total < 4.5:
183
- return "low"
184
- elif mem_total < 6.5:
185
- return "balanced"
186
-
187
- return "high"
188
-
189
-
190
- def validate_device_id(device, log_prefix=""):
191
- def is_valid():
192
- if not isinstance(device, str):
193
- return False
194
- if device == "cpu" or device == "mps":
195
- return True
196
- if not device.startswith("cuda:") or not device[5:].isnumeric():
197
- return False
198
- return True
199
-
200
- if not is_valid():
201
- raise EnvironmentError(
202
- f"{log_prefix}: device id should be 'cpu', 'mps', or 'cuda:N' (where N is an integer index for the GPU). Got: {device}"
203
- )
204
-
205
-
206
- def is_device_compatible(device):
207
- """
208
- Returns True/False, and prints any compatibility errors
209
- """
210
- # static variable "history".
211
- is_device_compatible.history = getattr(is_device_compatible, "history", {})
212
- try:
213
- validate_device_id(device, log_prefix="is_device_compatible")
214
- except:
215
- log.error(str(e))
216
- return False
217
-
218
- if device in ("cpu", "mps"):
219
- return True
220
- # Memory check
221
- try:
222
- _, mem_total = torch.cuda.mem_get_info(device)
223
- mem_total /= float(10**9)
224
- if mem_total < 3.0:
225
- if is_device_compatible.history.get(device) == None:
226
- log.warn(f"GPU {device} with less than 3 GB of VRAM is not compatible with Stable Diffusion")
227
- is_device_compatible.history[device] = 1
228
- return False
229
- except RuntimeError as e:
230
- log.error(str(e))
231
- return False
232
- return True
233
-
234
-
235
- def get_processor_name():
236
- try:
237
- import subprocess
238
-
239
- if platform.system() == "Windows":
240
- return platform.processor()
241
- elif platform.system() == "Darwin":
242
- os.environ["PATH"] = os.environ["PATH"] + os.pathsep + "/usr/sbin"
243
- command = "sysctl -n machdep.cpu.brand_string"
244
- return subprocess.check_output(command, shell=True).decode().strip()
245
- elif platform.system() == "Linux":
246
- command = "cat /proc/cpuinfo"
247
- all_info = subprocess.check_output(command, shell=True).decode().strip()
248
- for line in all_info.split("\n"):
249
- if "model name" in line:
250
- return re.sub(".*model name.*:", "", line, 1).strip()
251
- except:
252
- log.error(traceback.format_exc())
253
- return "cpu"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/model_manager.py DELETED
@@ -1,255 +0,0 @@
1
- import os
2
-
3
- from easydiffusion import app
4
- from easydiffusion.types import TaskData
5
- from easydiffusion.utils import log
6
-
7
- from sdkit import Context
8
- from sdkit.models import load_model, unload_model, scan_model
9
-
10
- KNOWN_MODEL_TYPES = ["stable-diffusion", "vae", "hypernetwork", "gfpgan", "realesrgan"]
11
- MODEL_EXTENSIONS = {
12
- "stable-diffusion": [".ckpt", ".safetensors"],
13
- "vae": [".vae.pt", ".ckpt", ".safetensors"],
14
- "hypernetwork": [".pt", ".safetensors"],
15
- "gfpgan": [".pth"],
16
- "realesrgan": [".pth"],
17
- }
18
- DEFAULT_MODELS = {
19
- "stable-diffusion": [ # needed to support the legacy installations
20
- "custom-model", # only one custom model file was supported initially, creatively named 'custom-model'
21
- "sd-v1-4", # Default fallback.
22
- ],
23
- "gfpgan": ["GFPGANv1.3"],
24
- "realesrgan": ["RealESRGAN_x4plus"],
25
- }
26
- MODELS_TO_LOAD_ON_START = ["stable-diffusion", "vae", "hypernetwork"]
27
-
28
- known_models = {}
29
-
30
-
31
- def init():
32
- make_model_folders()
33
- getModels() # run this once, to cache the picklescan results
34
-
35
-
36
- def load_default_models(context: Context):
37
- set_vram_optimizations(context)
38
-
39
- # init default model paths
40
- for model_type in MODELS_TO_LOAD_ON_START:
41
- context.model_paths[model_type] = resolve_model_to_use(model_type=model_type)
42
- try:
43
- load_model(context, model_type)
44
- except Exception as e:
45
- log.error(f"[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]")
46
- log.error(f"[red]Error: {e}[/red]")
47
- log.error(f"[red]Consider removing the model from the model folder.[red]")
48
-
49
-
50
- def unload_all(context: Context):
51
- for model_type in KNOWN_MODEL_TYPES:
52
- unload_model(context, model_type)
53
-
54
-
55
- def resolve_model_to_use(model_name: str = None, model_type: str = None):
56
- model_extensions = MODEL_EXTENSIONS.get(model_type, [])
57
- default_models = DEFAULT_MODELS.get(model_type, [])
58
- config = app.getConfig()
59
-
60
- model_dirs = [os.path.join(app.MODELS_DIR, model_type), app.SD_DIR]
61
- if not model_name: # When None try user configured model.
62
- # config = getConfig()
63
- if "model" in config and model_type in config["model"]:
64
- model_name = config["model"][model_type]
65
-
66
- if model_name:
67
- # Check models directory
68
- models_dir_path = os.path.join(app.MODELS_DIR, model_type, model_name)
69
- for model_extension in model_extensions:
70
- if os.path.exists(models_dir_path + model_extension):
71
- return models_dir_path + model_extension
72
- if os.path.exists(model_name + model_extension):
73
- return os.path.abspath(model_name + model_extension)
74
-
75
- # Default locations
76
- if model_name in default_models:
77
- default_model_path = os.path.join(app.SD_DIR, model_name)
78
- for model_extension in model_extensions:
79
- if os.path.exists(default_model_path + model_extension):
80
- return default_model_path + model_extension
81
-
82
- # Can't find requested model, check the default paths.
83
- for default_model in default_models:
84
- for model_dir in model_dirs:
85
- default_model_path = os.path.join(model_dir, default_model)
86
- for model_extension in model_extensions:
87
- if os.path.exists(default_model_path + model_extension):
88
- if model_name is not None:
89
- log.warn(
90
- f"Could not find the configured custom model {model_name}{model_extension}. Using the default one: {default_model_path}{model_extension}"
91
- )
92
- return default_model_path + model_extension
93
-
94
- return None
95
-
96
-
97
- def reload_models_if_necessary(context: Context, task_data: TaskData):
98
- model_paths_in_req = {
99
- "stable-diffusion": task_data.use_stable_diffusion_model,
100
- "vae": task_data.use_vae_model,
101
- "hypernetwork": task_data.use_hypernetwork_model,
102
- "gfpgan": task_data.use_face_correction,
103
- "realesrgan": task_data.use_upscale,
104
- "nsfw_checker": True if task_data.block_nsfw else None,
105
- }
106
- models_to_reload = {
107
- model_type: path
108
- for model_type, path in model_paths_in_req.items()
109
- if context.model_paths.get(model_type) != path
110
- }
111
-
112
- if set_vram_optimizations(context): # reload SD
113
- models_to_reload["stable-diffusion"] = model_paths_in_req["stable-diffusion"]
114
-
115
- for model_type, model_path_in_req in models_to_reload.items():
116
- context.model_paths[model_type] = model_path_in_req
117
-
118
- action_fn = unload_model if context.model_paths[model_type] is None else load_model
119
- action_fn(context, model_type, scan_model=False) # we've scanned them already
120
-
121
-
122
- def resolve_model_paths(task_data: TaskData):
123
- task_data.use_stable_diffusion_model = resolve_model_to_use(
124
- task_data.use_stable_diffusion_model, model_type="stable-diffusion"
125
- )
126
- task_data.use_vae_model = resolve_model_to_use(task_data.use_vae_model, model_type="vae")
127
- task_data.use_hypernetwork_model = resolve_model_to_use(task_data.use_hypernetwork_model, model_type="hypernetwork")
128
-
129
- if task_data.use_face_correction:
130
- task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, "gfpgan")
131
- if task_data.use_upscale:
132
- task_data.use_upscale = resolve_model_to_use(task_data.use_upscale, "realesrgan")
133
-
134
-
135
- def set_vram_optimizations(context: Context):
136
- config = app.getConfig()
137
- vram_usage_level = config.get("vram_usage_level", "balanced")
138
-
139
- if vram_usage_level != context.vram_usage_level:
140
- context.vram_usage_level = vram_usage_level
141
- return True
142
-
143
- return False
144
-
145
-
146
- def make_model_folders():
147
- for model_type in KNOWN_MODEL_TYPES:
148
- model_dir_path = os.path.join(app.MODELS_DIR, model_type)
149
-
150
- os.makedirs(model_dir_path, exist_ok=True)
151
-
152
- help_file_name = f"Place your {model_type} model files here.txt"
153
- help_file_contents = f'Supported extensions: {" or ".join(MODEL_EXTENSIONS.get(model_type))}'
154
-
155
- with open(os.path.join(model_dir_path, help_file_name), "w", encoding="utf-8") as f:
156
- f.write(help_file_contents)
157
-
158
-
159
- def is_malicious_model(file_path):
160
- try:
161
- if file_path.endswith(".safetensors"):
162
- return False
163
- scan_result = scan_model(file_path)
164
- if scan_result.issues_count > 0 or scan_result.infected_files > 0:
165
- log.warn(
166
- ":warning: [bold red]Scan %s: %d scanned, %d issue, %d infected.[/bold red]"
167
- % (file_path, scan_result.scanned_files, scan_result.issues_count, scan_result.infected_files)
168
- )
169
- return True
170
- else:
171
- log.debug(
172
- "Scan %s: [green]%d scanned, %d issue, %d infected.[/green]"
173
- % (file_path, scan_result.scanned_files, scan_result.issues_count, scan_result.infected_files)
174
- )
175
- return False
176
- except Exception as e:
177
- log.error(f"error while scanning: {file_path}, error: {e}")
178
- return False
179
-
180
-
181
- def getModels():
182
- models = {
183
- "active": {
184
- "stable-diffusion": "sd-v1-4",
185
- "vae": "",
186
- "hypernetwork": "",
187
- },
188
- "options": {
189
- "stable-diffusion": ["sd-v1-4"],
190
- "vae": [],
191
- "hypernetwork": [],
192
- },
193
- }
194
-
195
- models_scanned = 0
196
-
197
- class MaliciousModelException(Exception):
198
- "Raised when picklescan reports a problem with a model"
199
- pass
200
-
201
- def scan_directory(directory, suffixes, directoriesFirst: bool = True):
202
- nonlocal models_scanned
203
- tree = []
204
- for entry in sorted(
205
- os.scandir(directory), key=lambda entry: (entry.is_file() == directoriesFirst, entry.name.lower())
206
- ):
207
- if entry.is_file():
208
- matching_suffix = list(filter(lambda s: entry.name.endswith(s), suffixes))
209
- if len(matching_suffix) == 0:
210
- continue
211
- matching_suffix = matching_suffix[0]
212
-
213
- mtime = entry.stat().st_mtime
214
- mod_time = known_models[entry.path] if entry.path in known_models else -1
215
- if mod_time != mtime:
216
- models_scanned += 1
217
- if is_malicious_model(entry.path):
218
- raise MaliciousModelException(entry.path)
219
- known_models[entry.path] = mtime
220
- tree.append(entry.name[: -len(matching_suffix)])
221
- elif entry.is_dir():
222
- scan = scan_directory(entry.path, suffixes, directoriesFirst=False)
223
-
224
- if len(scan) != 0:
225
- tree.append((entry.name, scan))
226
- return tree
227
-
228
- def listModels(model_type):
229
- nonlocal models_scanned
230
-
231
- model_extensions = MODEL_EXTENSIONS.get(model_type, [])
232
- models_dir = os.path.join(app.MODELS_DIR, model_type)
233
- if not os.path.exists(models_dir):
234
- os.makedirs(models_dir)
235
-
236
- try:
237
- models["options"][model_type] = scan_directory(models_dir, model_extensions)
238
- except MaliciousModelException as e:
239
- models["scan-error"] = e
240
-
241
- # custom models
242
- listModels(model_type="stable-diffusion")
243
- listModels(model_type="vae")
244
- listModels(model_type="hypernetwork")
245
- listModels(model_type="gfpgan")
246
-
247
- if models_scanned > 0:
248
- log.info(f"[green]Scanned {models_scanned} models. Nothing infected[/]")
249
-
250
- # legacy
251
- custom_weight_path = os.path.join(app.SD_DIR, "custom-model.ckpt")
252
- if os.path.exists(custom_weight_path):
253
- models["options"]["stable-diffusion"].append("custom-model")
254
-
255
- return models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/renderer.py DELETED
@@ -1,180 +0,0 @@
1
- import queue
2
- import time
3
- import json
4
- import pprint
5
-
6
- from easydiffusion import device_manager
7
- from easydiffusion.types import TaskData, Response, Image as ResponseImage, UserInitiatedStop, GenerateImageRequest
8
- from easydiffusion.utils import get_printable_request, save_images_to_disk, log
9
-
10
- from sdkit import Context
11
- from sdkit.generate import generate_images
12
- from sdkit.filter import apply_filters
13
- from sdkit.utils import img_to_buffer, img_to_base64_str, latent_samples_to_images, gc
14
-
15
- context = Context() # thread-local
16
- """
17
- runtime data (bound locally to this thread), for e.g. device, references to loaded models, optimization flags etc
18
- """
19
-
20
-
21
- def init(device):
22
- """
23
- Initializes the fields that will be bound to this runtime's context, and sets the current torch device
24
- """
25
- context.stop_processing = False
26
- context.temp_images = {}
27
- context.partial_x_samples = None
28
-
29
- device_manager.device_init(context, device)
30
-
31
-
32
- def make_images(
33
- req: GenerateImageRequest, task_data: TaskData, data_queue: queue.Queue, task_temp_images: list, step_callback
34
- ):
35
- context.stop_processing = False
36
- print_task_info(req, task_data)
37
-
38
- images, seeds = make_images_internal(req, task_data, data_queue, task_temp_images, step_callback)
39
-
40
- res = Response(req, task_data, images=construct_response(images, seeds, task_data, base_seed=req.seed))
41
- res = res.json()
42
- data_queue.put(json.dumps(res))
43
- log.info("Task completed")
44
-
45
- return res
46
-
47
-
48
- def print_task_info(req: GenerateImageRequest, task_data: TaskData):
49
- req_str = pprint.pformat(get_printable_request(req)).replace("[", "\[")
50
- task_str = pprint.pformat(task_data.dict()).replace("[", "\[")
51
- log.info(f"request: {req_str}")
52
- log.info(f"task data: {task_str}")
53
-
54
-
55
- def make_images_internal(
56
- req: GenerateImageRequest, task_data: TaskData, data_queue: queue.Queue, task_temp_images: list, step_callback
57
- ):
58
-
59
- images, user_stopped = generate_images_internal(
60
- req, task_data, data_queue, task_temp_images, step_callback, task_data.stream_image_progress, task_data.stream_image_progress_interval
61
- )
62
- filtered_images = filter_images(task_data, images, user_stopped)
63
-
64
- if task_data.save_to_disk_path is not None:
65
- save_images_to_disk(images, filtered_images, req, task_data)
66
-
67
- seeds = [*range(req.seed, req.seed + len(images))]
68
- if task_data.show_only_filtered_image or filtered_images is images:
69
- return filtered_images, seeds
70
- else:
71
- return images + filtered_images, seeds + seeds
72
-
73
-
74
- def generate_images_internal(
75
- req: GenerateImageRequest,
76
- task_data: TaskData,
77
- data_queue: queue.Queue,
78
- task_temp_images: list,
79
- step_callback,
80
- stream_image_progress: bool,
81
- stream_image_progress_interval: int,
82
- ):
83
- context.temp_images.clear()
84
-
85
- callback = make_step_callback(req, task_data, data_queue, task_temp_images, step_callback, stream_image_progress, stream_image_progress_interval)
86
-
87
- try:
88
- if req.init_image is not None:
89
- req.sampler_name = "ddim"
90
-
91
- images = generate_images(context, callback=callback, **req.dict())
92
- user_stopped = False
93
- except UserInitiatedStop:
94
- images = []
95
- user_stopped = True
96
- if context.partial_x_samples is not None:
97
- images = latent_samples_to_images(context, context.partial_x_samples)
98
- finally:
99
- if hasattr(context, "partial_x_samples") and context.partial_x_samples is not None:
100
- del context.partial_x_samples
101
- context.partial_x_samples = None
102
-
103
- return images, user_stopped
104
-
105
-
106
- def filter_images(task_data: TaskData, images: list, user_stopped):
107
- if user_stopped:
108
- return images
109
-
110
- filters_to_apply = []
111
- if task_data.block_nsfw:
112
- filters_to_apply.append("nsfw_checker")
113
- if task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower():
114
- filters_to_apply.append("gfpgan")
115
- if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower():
116
- filters_to_apply.append("realesrgan")
117
-
118
- if len(filters_to_apply) == 0:
119
- return images
120
-
121
- return apply_filters(context, filters_to_apply, images, scale=task_data.upscale_amount)
122
-
123
-
124
- def construct_response(images: list, seeds: list, task_data: TaskData, base_seed: int):
125
- return [
126
- ResponseImage(
127
- data=img_to_base64_str(img, task_data.output_format, task_data.output_quality),
128
- seed=seed,
129
- )
130
- for img, seed in zip(images, seeds)
131
- ]
132
-
133
-
134
- def make_step_callback(
135
- req: GenerateImageRequest,
136
- task_data: TaskData,
137
- data_queue: queue.Queue,
138
- task_temp_images: list,
139
- step_callback,
140
- stream_image_progress: bool,
141
- stream_image_progress_interval: int,
142
- ):
143
- n_steps = req.num_inference_steps if req.init_image is None else int(req.num_inference_steps * req.prompt_strength)
144
- last_callback_time = -1
145
-
146
- def update_temp_img(x_samples, task_temp_images: list):
147
- partial_images = []
148
- images = latent_samples_to_images(context, x_samples)
149
- if task_data.block_nsfw:
150
- images = apply_filters(context, "nsfw_checker", images)
151
-
152
- for i, img in enumerate(images):
153
- buf = img_to_buffer(img, output_format="JPEG")
154
-
155
- context.temp_images[f"{task_data.request_id}/{i}"] = buf
156
- task_temp_images[i] = buf
157
- partial_images.append({"path": f"/image/tmp/{task_data.request_id}/{i}"})
158
- del images
159
- return partial_images
160
-
161
- def on_image_step(x_samples, i):
162
- nonlocal last_callback_time
163
-
164
- context.partial_x_samples = x_samples
165
- step_time = time.time() - last_callback_time if last_callback_time != -1 else -1
166
- last_callback_time = time.time()
167
-
168
- progress = {"step": i, "step_time": step_time, "total_steps": n_steps}
169
-
170
- if stream_image_progress and stream_image_progress_interval > 0 and i % stream_image_progress_interval == 0:
171
- progress["output"] = update_temp_img(x_samples, task_temp_images)
172
-
173
- data_queue.put(json.dumps(progress))
174
-
175
- step_callback()
176
-
177
- if context.stop_processing:
178
- raise UserInitiatedStop("User requested that we stop processing")
179
-
180
- return on_image_step
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/server.py DELETED
@@ -1,304 +0,0 @@
1
- """server.py: FastAPI SD-UI Web Host.
2
- Notes:
3
- async endpoints always run on the main thread. Without they run on the thread pool.
4
- """
5
- import os
6
- import traceback
7
- import datetime
8
- from typing import List, Union
9
-
10
- from fastapi import FastAPI, HTTPException
11
- from fastapi.staticfiles import StaticFiles
12
- from starlette.responses import FileResponse, JSONResponse, StreamingResponse
13
- from pydantic import BaseModel
14
-
15
- from easydiffusion import app, model_manager, task_manager
16
- from easydiffusion.types import TaskData, GenerateImageRequest, MergeRequest
17
- from easydiffusion.utils import log
18
-
19
- import mimetypes
20
-
21
- log.info(f"started in {app.SD_DIR}")
22
- log.info(f"started at {datetime.datetime.now():%x %X}")
23
-
24
- server_api = FastAPI()
25
-
26
- NOCACHE_HEADERS = {"Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0"}
27
-
28
-
29
- class NoCacheStaticFiles(StaticFiles):
30
- def __init__(self, directory: str):
31
- # follow_symlink is only available on fastapi >= 0.92.0
32
- if (os.path.islink(directory)):
33
- super().__init__(directory = os.path.realpath(directory))
34
- else:
35
- super().__init__(directory = directory)
36
-
37
- def is_not_modified(self, response_headers, request_headers) -> bool:
38
- if "content-type" in response_headers and (
39
- "javascript" in response_headers["content-type"] or "css" in response_headers["content-type"]
40
- ):
41
- response_headers.update(NOCACHE_HEADERS)
42
- return False
43
-
44
- return super().is_not_modified(response_headers, request_headers)
45
-
46
-
47
- class SetAppConfigRequest(BaseModel):
48
- update_branch: str = None
49
- render_devices: Union[List[str], List[int], str, int] = None
50
- model_vae: str = None
51
- ui_open_browser_on_start: bool = None
52
- listen_to_network: bool = None
53
- listen_port: int = None
54
-
55
-
56
- def init():
57
- mimetypes.init()
58
- mimetypes.add_type('text/css', '.css')
59
-
60
- if os.path.isdir(app.CUSTOM_MODIFIERS_DIR):
61
- server_api.mount(
62
- "/media/modifier-thumbnails/custom",
63
- NoCacheStaticFiles(directory=app.CUSTOM_MODIFIERS_DIR),
64
- name="custom-thumbnails",
65
- )
66
-
67
- server_api.mount("/media", NoCacheStaticFiles(directory=os.path.join(app.SD_UI_DIR, "media")), name="media")
68
-
69
- for plugins_dir, dir_prefix in app.UI_PLUGINS_SOURCES:
70
- server_api.mount(
71
- f"/plugins/{dir_prefix}", NoCacheStaticFiles(directory=plugins_dir), name=f"plugins-{dir_prefix}"
72
- )
73
-
74
- @server_api.post("/app_config")
75
- async def set_app_config(req: SetAppConfigRequest):
76
- return set_app_config_internal(req)
77
-
78
- @server_api.get("/get/{key:path}")
79
- def read_web_data(key: str = None):
80
- return read_web_data_internal(key)
81
-
82
- @server_api.get("/ping") # Get server and optionally session status.
83
- def ping(session_id: str = None):
84
- return ping_internal(session_id)
85
-
86
- @server_api.post("/render")
87
- def render(req: dict):
88
- return render_internal(req)
89
-
90
- @server_api.post("/model/merge")
91
- def model_merge(req: dict):
92
- print(req)
93
- return model_merge_internal(req)
94
-
95
- @server_api.get("/image/stream/{task_id:int}")
96
- def stream(task_id: int):
97
- return stream_internal(task_id)
98
-
99
- @server_api.get("/image/stop")
100
- def stop(task: int):
101
- return stop_internal(task)
102
-
103
- @server_api.get("/image/tmp/{task_id:int}/{img_id:int}")
104
- def get_image(task_id: int, img_id: int):
105
- return get_image_internal(task_id, img_id)
106
-
107
- @server_api.get("/")
108
- def read_root():
109
- return FileResponse(os.path.join(app.SD_UI_DIR, "index.html"), headers=NOCACHE_HEADERS)
110
-
111
- @server_api.on_event("shutdown")
112
- def shutdown_event(): # Signal render thread to close on shutdown
113
- task_manager.current_state_error = SystemExit("Application shutting down.")
114
-
115
-
116
- # API implementations
117
- def set_app_config_internal(req: SetAppConfigRequest):
118
- config = app.getConfig()
119
- if req.update_branch is not None:
120
- config["update_branch"] = req.update_branch
121
- if req.render_devices is not None:
122
- update_render_devices_in_config(config, req.render_devices)
123
- if req.ui_open_browser_on_start is not None:
124
- if "ui" not in config:
125
- config["ui"] = {}
126
- config["ui"]["open_browser_on_start"] = req.ui_open_browser_on_start
127
- if req.listen_to_network is not None:
128
- if "net" not in config:
129
- config["net"] = {}
130
- config["net"]["listen_to_network"] = bool(req.listen_to_network)
131
- if req.listen_port is not None:
132
- if "net" not in config:
133
- config["net"] = {}
134
- config["net"]["listen_port"] = int(req.listen_port)
135
- try:
136
- app.setConfig(config)
137
-
138
- if req.render_devices:
139
- app.update_render_threads()
140
-
141
- return JSONResponse({"status": "OK"}, headers=NOCACHE_HEADERS)
142
- except Exception as e:
143
- log.error(traceback.format_exc())
144
- raise HTTPException(status_code=500, detail=str(e))
145
-
146
-
147
- def update_render_devices_in_config(config, render_devices):
148
- if render_devices not in ("cpu", "auto") and not render_devices.startswith("cuda:"):
149
- raise HTTPException(status_code=400, detail=f"Invalid render device requested: {render_devices}")
150
-
151
- if render_devices.startswith("cuda:"):
152
- render_devices = render_devices.split(",")
153
-
154
- config["render_devices"] = render_devices
155
-
156
-
157
- def read_web_data_internal(key: str = None):
158
- if not key: # /get without parameters, stable-diffusion easter egg.
159
- raise HTTPException(status_code=418, detail="StableDiffusion is drawing a teapot!") # HTTP418 I'm a teapot
160
- elif key == "app_config":
161
- return JSONResponse(app.getConfig(), headers=NOCACHE_HEADERS)
162
- elif key == "system_info":
163
- config = app.getConfig()
164
-
165
- output_dir = config.get("force_save_path", os.path.join(os.path.expanduser("~"), app.OUTPUT_DIRNAME))
166
-
167
- system_info = {
168
- "devices": task_manager.get_devices(),
169
- "hosts": app.getIPConfig(),
170
- "default_output_dir": output_dir,
171
- "enforce_output_dir": ("force_save_path" in config),
172
- }
173
- system_info["devices"]["config"] = config.get("render_devices", "auto")
174
- return JSONResponse(system_info, headers=NOCACHE_HEADERS)
175
- elif key == "models":
176
- return JSONResponse(model_manager.getModels(), headers=NOCACHE_HEADERS)
177
- elif key == "modifiers":
178
- return JSONResponse(app.get_image_modifiers(), headers=NOCACHE_HEADERS)
179
- elif key == "ui_plugins":
180
- return JSONResponse(app.getUIPlugins(), headers=NOCACHE_HEADERS)
181
- else:
182
- raise HTTPException(status_code=404, detail=f"Request for unknown {key}") # HTTP404 Not Found
183
-
184
-
185
- def ping_internal(session_id: str = None):
186
- if task_manager.is_alive() <= 0: # Check that render threads are alive.
187
- if task_manager.current_state_error:
188
- raise HTTPException(status_code=500, detail=str(task_manager.current_state_error))
189
- raise HTTPException(status_code=500, detail="Render thread is dead.")
190
- if task_manager.current_state_error and not isinstance(task_manager.current_state_error, StopAsyncIteration):
191
- raise HTTPException(status_code=500, detail=str(task_manager.current_state_error))
192
- # Alive
193
- response = {"status": str(task_manager.current_state)}
194
- if session_id:
195
- session = task_manager.get_cached_session(session_id, update_ttl=True)
196
- response["tasks"] = {id(t): t.status for t in session.tasks}
197
- response["devices"] = task_manager.get_devices()
198
- return JSONResponse(response, headers=NOCACHE_HEADERS)
199
-
200
-
201
- def render_internal(req: dict):
202
- try:
203
- # separate out the request data into rendering and task-specific data
204
- render_req: GenerateImageRequest = GenerateImageRequest.parse_obj(req)
205
- task_data: TaskData = TaskData.parse_obj(req)
206
-
207
- # Overwrite user specified save path
208
- config = app.getConfig()
209
- if "force_save_path" in config:
210
- task_data.save_to_disk_path = config["force_save_path"]
211
-
212
- render_req.init_image_mask = req.get("mask") # hack: will rename this in the HTTP API in a future revision
213
-
214
- app.save_to_config(
215
- task_data.use_stable_diffusion_model,
216
- task_data.use_vae_model,
217
- task_data.use_hypernetwork_model,
218
- task_data.vram_usage_level,
219
- )
220
-
221
- # enqueue the task
222
- new_task = task_manager.render(render_req, task_data)
223
- response = {
224
- "status": str(task_manager.current_state),
225
- "queue": len(task_manager.tasks_queue),
226
- "stream": f"/image/stream/{id(new_task)}",
227
- "task": id(new_task),
228
- }
229
- return JSONResponse(response, headers=NOCACHE_HEADERS)
230
- except ChildProcessError as e: # Render thread is dead
231
- raise HTTPException(status_code=500, detail=f"Rendering thread has died.") # HTTP500 Internal Server Error
232
- except ConnectionRefusedError as e: # Unstarted task pending limit reached, deny queueing too many.
233
- raise HTTPException(status_code=503, detail=str(e)) # HTTP503 Service Unavailable
234
- except Exception as e:
235
- log.error(traceback.format_exc())
236
- raise HTTPException(status_code=500, detail=str(e))
237
-
238
-
239
- def model_merge_internal(req: dict):
240
- try:
241
- from sdkit.train import merge_models
242
- from easydiffusion.utils.save_utils import filename_regex
243
-
244
- mergeReq: MergeRequest = MergeRequest.parse_obj(req)
245
-
246
- merge_models(
247
- model_manager.resolve_model_to_use(mergeReq.model0, "stable-diffusion"),
248
- model_manager.resolve_model_to_use(mergeReq.model1, "stable-diffusion"),
249
- mergeReq.ratio,
250
- os.path.join(app.MODELS_DIR, "stable-diffusion", filename_regex.sub("_", mergeReq.out_path)),
251
- mergeReq.use_fp16,
252
- )
253
- return JSONResponse({"status": "OK"}, headers=NOCACHE_HEADERS)
254
- except Exception as e:
255
- log.error(traceback.format_exc())
256
- raise HTTPException(status_code=500, detail=str(e))
257
-
258
-
259
- def stream_internal(task_id: int):
260
- # TODO Move to WebSockets ??
261
- task = task_manager.get_cached_task(task_id, update_ttl=True)
262
- if not task:
263
- raise HTTPException(status_code=404, detail=f"Request {task_id} not found.") # HTTP404 NotFound
264
- # if (id(task) != task_id): raise HTTPException(status_code=409, detail=f'Wrong task id received. Expected:{id(task)}, Received:{task_id}') # HTTP409 Conflict
265
- if task.buffer_queue.empty() and not task.lock.locked():
266
- if task.response:
267
- # log.info(f'Session {session_id} sending cached response')
268
- return JSONResponse(task.response, headers=NOCACHE_HEADERS)
269
- raise HTTPException(status_code=425, detail="Too Early, task not started yet.") # HTTP425 Too Early
270
- # log.info(f'Session {session_id} opened live render stream {id(task.buffer_queue)}')
271
- return StreamingResponse(task.read_buffer_generator(), media_type="application/json")
272
-
273
-
274
- def stop_internal(task: int):
275
- if not task:
276
- if (
277
- task_manager.current_state == task_manager.ServerStates.Online
278
- or task_manager.current_state == task_manager.ServerStates.Unavailable
279
- ):
280
- raise HTTPException(status_code=409, detail="Not currently running any tasks.") # HTTP409 Conflict
281
- task_manager.current_state_error = StopAsyncIteration("")
282
- return {"OK"}
283
- task_id = task
284
- task = task_manager.get_cached_task(task_id, update_ttl=False)
285
- if not task:
286
- raise HTTPException(status_code=404, detail=f"Task {task_id} was not found.") # HTTP404 Not Found
287
- if isinstance(task.error, StopAsyncIteration):
288
- raise HTTPException(status_code=409, detail=f"Task {task_id} is already stopped.") # HTTP409 Conflict
289
- task.error = StopAsyncIteration(f"Task {task_id} stop requested.")
290
- return {"OK"}
291
-
292
-
293
- def get_image_internal(task_id: int, img_id: int):
294
- task = task_manager.get_cached_task(task_id, update_ttl=True)
295
- if not task:
296
- raise HTTPException(status_code=410, detail=f"Task {task_id} could not be found.") # HTTP404 NotFound
297
- if not task.temp_images[img_id]:
298
- raise HTTPException(status_code=425, detail="Too Early, task data is not available yet.") # HTTP425 Too Early
299
- try:
300
- img_data = task.temp_images[img_id]
301
- img_data.seek(0)
302
- return StreamingResponse(img_data, media_type="image/jpeg")
303
- except KeyError as e:
304
- raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/task_manager.py DELETED
@@ -1,565 +0,0 @@
1
- """task_manager.py: manage tasks dispatching and render threads.
2
- Notes:
3
- render_threads should be the only hard reference held by the manager to the threads.
4
- Use weak_thread_data to store all other data using weak keys.
5
- This will allow for garbage collection after the thread dies.
6
- """
7
- import json
8
- import traceback
9
-
10
- TASK_TTL = 15 * 60 # seconds, Discard last session's task timeout
11
-
12
- import torch
13
- import queue, threading, time, weakref
14
- from typing import Any, Hashable
15
-
16
- from easydiffusion import device_manager
17
- from easydiffusion.types import TaskData, GenerateImageRequest
18
- from easydiffusion.utils import log
19
-
20
- from sdkit.utils import gc
21
-
22
- THREAD_NAME_PREFIX = ""
23
- ERR_LOCK_FAILED = " failed to acquire lock within timeout."
24
- LOCK_TIMEOUT = 15 # Maximum locking time in seconds before failing a task.
25
- # It's better to get an exception than a deadlock... ALWAYS use timeout in critical paths.
26
-
27
- DEVICE_START_TIMEOUT = 60 # seconds - Maximum time to wait for a render device to init.
28
-
29
-
30
- class SymbolClass(type): # Print nicely formatted Symbol names.
31
- def __repr__(self):
32
- return self.__qualname__
33
-
34
- def __str__(self):
35
- return self.__name__
36
-
37
-
38
- class Symbol(metaclass=SymbolClass):
39
- pass
40
-
41
-
42
- class ServerStates:
43
- class Init(Symbol):
44
- pass
45
-
46
- class LoadingModel(Symbol):
47
- pass
48
-
49
- class Online(Symbol):
50
- pass
51
-
52
- class Rendering(Symbol):
53
- pass
54
-
55
- class Unavailable(Symbol):
56
- pass
57
-
58
-
59
- class RenderTask: # Task with output queue and completion lock.
60
- def __init__(self, req: GenerateImageRequest, task_data: TaskData):
61
- task_data.request_id = id(self)
62
- self.render_request: GenerateImageRequest = req # Initial Request
63
- self.task_data: TaskData = task_data
64
- self.response: Any = None # Copy of the last reponse
65
- self.render_device = None # Select the task affinity. (Not used to change active devices).
66
- self.temp_images: list = [None] * req.num_outputs * (1 if task_data.show_only_filtered_image else 2)
67
- self.error: Exception = None
68
- self.lock: threading.Lock = threading.Lock() # Locks at task start and unlocks when task is completed
69
- self.buffer_queue: queue.Queue = queue.Queue() # Queue of JSON string segments
70
-
71
- async def read_buffer_generator(self):
72
- try:
73
- while not self.buffer_queue.empty():
74
- res = self.buffer_queue.get(block=False)
75
- self.buffer_queue.task_done()
76
- yield res
77
- except queue.Empty as e:
78
- yield
79
-
80
- @property
81
- def status(self):
82
- if self.lock.locked():
83
- return "running"
84
- if isinstance(self.error, StopAsyncIteration):
85
- return "stopped"
86
- if self.error:
87
- return "error"
88
- if not self.buffer_queue.empty():
89
- return "buffer"
90
- if self.response:
91
- return "completed"
92
- return "pending"
93
-
94
- @property
95
- def is_pending(self):
96
- return bool(not self.response and not self.error)
97
-
98
-
99
- # Temporary cache to allow to query tasks results for a short time after they are completed.
100
- class DataCache:
101
- def __init__(self):
102
- self._base = dict()
103
- self._lock: threading.Lock = threading.Lock()
104
-
105
- def _get_ttl_time(self, ttl: int) -> int:
106
- return int(time.time()) + ttl
107
-
108
- def _is_expired(self, timestamp: int) -> bool:
109
- return int(time.time()) >= timestamp
110
-
111
- def clean(self) -> None:
112
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
113
- raise Exception("DataCache.clean" + ERR_LOCK_FAILED)
114
- try:
115
- # Create a list of expired keys to delete
116
- to_delete = []
117
- for key in self._base:
118
- ttl, _ = self._base[key]
119
- if self._is_expired(ttl):
120
- to_delete.append(key)
121
- # Remove Items
122
- for key in to_delete:
123
- (_, val) = self._base[key]
124
- if isinstance(val, RenderTask):
125
- log.debug(f"RenderTask {key} expired. Data removed.")
126
- elif isinstance(val, SessionState):
127
- log.debug(f"Session {key} expired. Data removed.")
128
- else:
129
- log.debug(f"Key {key} expired. Data removed.")
130
- del self._base[key]
131
- finally:
132
- self._lock.release()
133
-
134
- def clear(self) -> None:
135
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
136
- raise Exception("DataCache.clear" + ERR_LOCK_FAILED)
137
- try:
138
- self._base.clear()
139
- finally:
140
- self._lock.release()
141
-
142
- def delete(self, key: Hashable) -> bool:
143
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
144
- raise Exception("DataCache.delete" + ERR_LOCK_FAILED)
145
- try:
146
- if key not in self._base:
147
- return False
148
- del self._base[key]
149
- return True
150
- finally:
151
- self._lock.release()
152
-
153
- def keep(self, key: Hashable, ttl: int) -> bool:
154
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
155
- raise Exception("DataCache.keep" + ERR_LOCK_FAILED)
156
- try:
157
- if key in self._base:
158
- _, value = self._base.get(key)
159
- self._base[key] = (self._get_ttl_time(ttl), value)
160
- return True
161
- return False
162
- finally:
163
- self._lock.release()
164
-
165
- def put(self, key: Hashable, value: Any, ttl: int) -> bool:
166
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
167
- raise Exception("DataCache.put" + ERR_LOCK_FAILED)
168
- try:
169
- self._base[key] = (self._get_ttl_time(ttl), value)
170
- except Exception as e:
171
- log.error(traceback.format_exc())
172
- return False
173
- else:
174
- return True
175
- finally:
176
- self._lock.release()
177
-
178
- def tryGet(self, key: Hashable) -> Any:
179
- if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
180
- raise Exception("DataCache.tryGet" + ERR_LOCK_FAILED)
181
- try:
182
- ttl, value = self._base.get(key, (None, None))
183
- if ttl is not None and self._is_expired(ttl):
184
- log.debug(f"Session {key} expired. Discarding data.")
185
- del self._base[key]
186
- return None
187
- return value
188
- finally:
189
- self._lock.release()
190
-
191
-
192
- manager_lock = threading.RLock()
193
- render_threads = []
194
- current_state = ServerStates.Init
195
- current_state_error: Exception = None
196
- tasks_queue = []
197
- session_cache = DataCache()
198
- task_cache = DataCache()
199
- weak_thread_data = weakref.WeakKeyDictionary()
200
- idle_event: threading.Event = threading.Event()
201
-
202
-
203
- class SessionState:
204
- def __init__(self, id: str):
205
- self._id = id
206
- self._tasks_ids = []
207
-
208
- @property
209
- def id(self):
210
- return self._id
211
-
212
- @property
213
- def tasks(self):
214
- tasks = []
215
- for task_id in self._tasks_ids:
216
- task = task_cache.tryGet(task_id)
217
- if task:
218
- tasks.append(task)
219
- return tasks
220
-
221
- def put(self, task, ttl=TASK_TTL):
222
- task_id = id(task)
223
- self._tasks_ids.append(task_id)
224
- if not task_cache.put(task_id, task, ttl):
225
- return False
226
- while len(self._tasks_ids) > len(render_threads) * 2:
227
- self._tasks_ids.pop(0)
228
- return True
229
-
230
-
231
- def thread_get_next_task():
232
- from easydiffusion import renderer
233
-
234
- if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
235
- log.warn(f"Render thread on device: {renderer.context.device} failed to acquire manager lock.")
236
- return None
237
- if len(tasks_queue) <= 0:
238
- manager_lock.release()
239
- return None
240
- task = None
241
- try: # Select a render task.
242
- for queued_task in tasks_queue:
243
- if queued_task.render_device and renderer.context.device != queued_task.render_device:
244
- # Is asking for a specific render device.
245
- if is_alive(queued_task.render_device) > 0:
246
- continue # requested device alive, skip current one.
247
- else:
248
- # Requested device is not active, return error to UI.
249
- queued_task.error = Exception(queued_task.render_device + " is not currently active.")
250
- task = queued_task
251
- break
252
- if not queued_task.render_device and renderer.context.device == "cpu" and is_alive() > 1:
253
- # not asking for any specific devices, cpu want to grab task but other render devices are alive.
254
- continue # Skip Tasks, don't run on CPU unless there is nothing else or user asked for it.
255
- task = queued_task
256
- break
257
- if task is not None:
258
- del tasks_queue[tasks_queue.index(task)]
259
- return task
260
- finally:
261
- manager_lock.release()
262
-
263
-
264
- def thread_render(device):
265
- global current_state, current_state_error
266
-
267
- from easydiffusion import renderer, model_manager
268
-
269
- try:
270
- renderer.init(device)
271
-
272
- weak_thread_data[threading.current_thread()] = {
273
- "device": renderer.context.device,
274
- "device_name": renderer.context.device_name,
275
- "alive": True,
276
- }
277
-
278
- current_state = ServerStates.LoadingModel
279
- model_manager.load_default_models(renderer.context)
280
-
281
- current_state = ServerStates.Online
282
- except Exception as e:
283
- log.error(traceback.format_exc())
284
- weak_thread_data[threading.current_thread()] = {"error": e, "alive": False}
285
- return
286
-
287
- while True:
288
- session_cache.clean()
289
- task_cache.clean()
290
- if not weak_thread_data[threading.current_thread()]["alive"]:
291
- log.info(f"Shutting down thread for device {renderer.context.device}")
292
- model_manager.unload_all(renderer.context)
293
- return
294
- if isinstance(current_state_error, SystemExit):
295
- current_state = ServerStates.Unavailable
296
- return
297
- task = thread_get_next_task()
298
- if task is None:
299
- idle_event.clear()
300
- idle_event.wait(timeout=1)
301
- continue
302
- if task.error is not None:
303
- log.error(task.error)
304
- task.response = {"status": "failed", "detail": str(task.error)}
305
- task.buffer_queue.put(json.dumps(task.response))
306
- continue
307
- if current_state_error:
308
- task.error = current_state_error
309
- task.response = {"status": "failed", "detail": str(task.error)}
310
- task.buffer_queue.put(json.dumps(task.response))
311
- continue
312
- log.info(f"Session {task.task_data.session_id} starting task {id(task)} on {renderer.context.device_name}")
313
- if not task.lock.acquire(blocking=False):
314
- raise Exception("Got locked task from queue.")
315
- try:
316
-
317
- def step_callback():
318
- global current_state_error
319
-
320
- if (
321
- isinstance(current_state_error, SystemExit)
322
- or isinstance(current_state_error, StopAsyncIteration)
323
- or isinstance(task.error, StopAsyncIteration)
324
- ):
325
- renderer.context.stop_processing = True
326
- if isinstance(current_state_error, StopAsyncIteration):
327
- task.error = current_state_error
328
- current_state_error = None
329
- log.info(f"Session {task.task_data.session_id} sent cancel signal for task {id(task)}")
330
-
331
- current_state = ServerStates.LoadingModel
332
- model_manager.resolve_model_paths(task.task_data)
333
- model_manager.reload_models_if_necessary(renderer.context, task.task_data)
334
-
335
- current_state = ServerStates.Rendering
336
- task.response = renderer.make_images(
337
- task.render_request, task.task_data, task.buffer_queue, task.temp_images, step_callback
338
- )
339
- # Before looping back to the generator, mark cache as still alive.
340
- task_cache.keep(id(task), TASK_TTL)
341
- session_cache.keep(task.task_data.session_id, TASK_TTL)
342
- except Exception as e:
343
- task.error = str(e)
344
- task.response = {"status": "failed", "detail": str(task.error)}
345
- task.buffer_queue.put(json.dumps(task.response))
346
- log.error(traceback.format_exc())
347
- finally:
348
- gc(renderer.context)
349
- task.lock.release()
350
- task_cache.keep(id(task), TASK_TTL)
351
- session_cache.keep(task.task_data.session_id, TASK_TTL)
352
- if isinstance(task.error, StopAsyncIteration):
353
- log.info(f"Session {task.task_data.session_id} task {id(task)} cancelled!")
354
- elif task.error is not None:
355
- log.info(f"Session {task.task_data.session_id} task {id(task)} failed!")
356
- else:
357
- log.info(
358
- f"Session {task.task_data.session_id} task {id(task)} completed by {renderer.context.device_name}."
359
- )
360
- current_state = ServerStates.Online
361
-
362
-
363
- def get_cached_task(task_id: str, update_ttl: bool = False):
364
- # By calling keep before tryGet, wont discard if was expired.
365
- if update_ttl and not task_cache.keep(task_id, TASK_TTL):
366
- # Failed to keep task, already gone.
367
- return None
368
- return task_cache.tryGet(task_id)
369
-
370
-
371
- def get_cached_session(session_id: str, update_ttl: bool = False):
372
- if update_ttl:
373
- session_cache.keep(session_id, TASK_TTL)
374
- session = session_cache.tryGet(session_id)
375
- if not session:
376
- session = SessionState(session_id)
377
- session_cache.put(session_id, session, TASK_TTL)
378
- return session
379
-
380
-
381
- def get_devices():
382
- devices = {
383
- "all": {},
384
- "active": {},
385
- }
386
-
387
- def get_device_info(device):
388
- if device in ("cpu", "mps"):
389
- return {"name": device_manager.get_processor_name()}
390
-
391
- mem_free, mem_total = torch.cuda.mem_get_info(device)
392
- mem_free /= float(10**9)
393
- mem_total /= float(10**9)
394
-
395
- return {
396
- "name": torch.cuda.get_device_name(device),
397
- "mem_free": mem_free,
398
- "mem_total": mem_total,
399
- "max_vram_usage_level": device_manager.get_max_vram_usage_level(device),
400
- }
401
-
402
- # list the compatible devices
403
- cuda_count = torch.cuda.device_count()
404
- for device in range(cuda_count):
405
- device = f"cuda:{device}"
406
- if not device_manager.is_device_compatible(device):
407
- continue
408
-
409
- devices["all"].update({device: get_device_info(device)})
410
-
411
- if device_manager.is_mps_available():
412
- devices["all"].update({"mps": get_device_info("mps")})
413
-
414
- devices["all"].update({"cpu": get_device_info("cpu")})
415
-
416
- # list the activated devices
417
- if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
418
- raise Exception("get_devices" + ERR_LOCK_FAILED)
419
- try:
420
- for rthread in render_threads:
421
- if not rthread.is_alive():
422
- continue
423
- weak_data = weak_thread_data.get(rthread)
424
- if not weak_data or not "device" in weak_data or not "device_name" in weak_data:
425
- continue
426
- device = weak_data["device"]
427
- devices["active"].update({device: get_device_info(device)})
428
- finally:
429
- manager_lock.release()
430
-
431
- return devices
432
-
433
-
434
- def is_alive(device=None):
435
- if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
436
- raise Exception("is_alive" + ERR_LOCK_FAILED)
437
- nbr_alive = 0
438
- try:
439
- for rthread in render_threads:
440
- if device is not None:
441
- weak_data = weak_thread_data.get(rthread)
442
- if weak_data is None or not "device" in weak_data or weak_data["device"] is None:
443
- continue
444
- thread_device = weak_data["device"]
445
- if thread_device != device:
446
- continue
447
- if rthread.is_alive():
448
- nbr_alive += 1
449
- return nbr_alive
450
- finally:
451
- manager_lock.release()
452
-
453
-
454
- def start_render_thread(device):
455
- if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
456
- raise Exception("start_render_thread" + ERR_LOCK_FAILED)
457
- log.info(f"Start new Rendering Thread on device: {device}")
458
- try:
459
- rthread = threading.Thread(target=thread_render, kwargs={"device": device})
460
- rthread.daemon = True
461
- rthread.name = THREAD_NAME_PREFIX + device
462
- rthread.start()
463
- render_threads.append(rthread)
464
- finally:
465
- manager_lock.release()
466
- timeout = DEVICE_START_TIMEOUT
467
- while not rthread.is_alive() or not rthread in weak_thread_data or not "device" in weak_thread_data[rthread]:
468
- if rthread in weak_thread_data and "error" in weak_thread_data[rthread]:
469
- log.error(f"{rthread}, {device}, error: {weak_thread_data[rthread]['error']}")
470
- return False
471
- if timeout <= 0:
472
- return False
473
- timeout -= 1
474
- time.sleep(1)
475
- return True
476
-
477
-
478
- def stop_render_thread(device):
479
- try:
480
- device_manager.validate_device_id(device, log_prefix="stop_render_thread")
481
- except:
482
- log.error(traceback.format_exc())
483
- return False
484
-
485
- if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
486
- raise Exception("stop_render_thread" + ERR_LOCK_FAILED)
487
- log.info(f"Stopping Rendering Thread on device: {device}")
488
-
489
- try:
490
- thread_to_remove = None
491
- for rthread in render_threads:
492
- weak_data = weak_thread_data.get(rthread)
493
- if weak_data is None or not "device" in weak_data or weak_data["device"] is None:
494
- continue
495
- thread_device = weak_data["device"]
496
- if thread_device == device:
497
- weak_data["alive"] = False
498
- thread_to_remove = rthread
499
- break
500
- if thread_to_remove is not None:
501
- render_threads.remove(rthread)
502
- return True
503
- finally:
504
- manager_lock.release()
505
-
506
- return False
507
-
508
-
509
- def update_render_threads(render_devices, active_devices):
510
- devices_to_start, devices_to_stop = device_manager.get_device_delta(render_devices, active_devices)
511
- log.debug(f"devices_to_start: {devices_to_start}")
512
- log.debug(f"devices_to_stop: {devices_to_stop}")
513
-
514
- for device in devices_to_stop:
515
- if is_alive(device) <= 0:
516
- log.debug(f"{device} is not alive")
517
- continue
518
- if not stop_render_thread(device):
519
- log.warn(f"{device} could not stop render thread")
520
-
521
- for device in devices_to_start:
522
- if is_alive(device) >= 1:
523
- log.debug(f"{device} already registered.")
524
- continue
525
- if not start_render_thread(device):
526
- log.warn(f"{device} failed to start.")
527
-
528
- if is_alive() <= 0: # No running devices, probably invalid user config.
529
- raise EnvironmentError(
530
- 'ERROR: No active render devices! Please verify the "render_devices" value in config.json'
531
- )
532
-
533
- log.debug(f"active devices: {get_devices()['active']}")
534
-
535
-
536
- def shutdown_event(): # Signal render thread to close on shutdown
537
- global current_state_error
538
- current_state_error = SystemExit("Application shutting down.")
539
-
540
-
541
- def render(render_req: GenerateImageRequest, task_data: TaskData):
542
- current_thread_count = is_alive()
543
- if current_thread_count <= 0: # Render thread is dead
544
- raise ChildProcessError("Rendering thread has died.")
545
-
546
- # Alive, check if task in cache
547
- session = get_cached_session(task_data.session_id, update_ttl=True)
548
- pending_tasks = list(filter(lambda t: t.is_pending, session.tasks))
549
- if current_thread_count < len(pending_tasks):
550
- raise ConnectionRefusedError(
551
- f"Session {task_data.session_id} already has {len(pending_tasks)} pending tasks out of {current_thread_count}."
552
- )
553
-
554
- new_task = RenderTask(render_req, task_data)
555
- if session.put(new_task, TASK_TTL):
556
- # Use twice the normal timeout for adding user requests.
557
- # Tries to force session.put to fail before tasks_queue.put would.
558
- if manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT * 2):
559
- try:
560
- tasks_queue.append(new_task)
561
- idle_event.set()
562
- return new_task
563
- finally:
564
- manager_lock.release()
565
- raise RuntimeError("Failed to add task to cache.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/types.py DELETED
@@ -1,103 +0,0 @@
1
- from pydantic import BaseModel
2
- from typing import Any
3
-
4
-
5
- class GenerateImageRequest(BaseModel):
6
- prompt: str = ""
7
- negative_prompt: str = ""
8
-
9
- seed: int = 42
10
- width: int = 512
11
- height: int = 512
12
-
13
- num_outputs: int = 1
14
- num_inference_steps: int = 50
15
- guidance_scale: float = 7.5
16
-
17
- init_image: Any = None
18
- init_image_mask: Any = None
19
- prompt_strength: float = 0.8
20
- preserve_init_image_color_profile = False
21
-
22
- sampler_name: str = None # "ddim", "plms", "heun", "euler", "euler_a", "dpm2", "dpm2_a", "lms"
23
- hypernetwork_strength: float = 0
24
-
25
-
26
- class TaskData(BaseModel):
27
- request_id: str = None
28
- session_id: str = "session"
29
- save_to_disk_path: str = None
30
- vram_usage_level: str = "balanced" # or "low" or "medium"
31
-
32
- use_face_correction: str = None # or "GFPGANv1.3"
33
- use_upscale: str = None # or "RealESRGAN_x4plus" or "RealESRGAN_x4plus_anime_6B"
34
- upscale_amount: int = 4 # or 2
35
- use_stable_diffusion_model: str = "sd-v1-4"
36
- # use_stable_diffusion_config: str = "v1-inference"
37
- use_vae_model: str = None
38
- use_hypernetwork_model: str = None
39
-
40
- show_only_filtered_image: bool = False
41
- block_nsfw: bool = False
42
- output_format: str = "jpeg" # or "png" or "webp"
43
- output_quality: int = 75
44
- metadata_output_format: str = "txt" # or "json"
45
- stream_image_progress: bool = False
46
- stream_image_progress_interval: int = 5
47
-
48
-
49
- class MergeRequest(BaseModel):
50
- model0: str = None
51
- model1: str = None
52
- ratio: float = None
53
- out_path: str = "mix"
54
- use_fp16 = True
55
-
56
-
57
- class Image:
58
- data: str # base64
59
- seed: int
60
- is_nsfw: bool
61
- path_abs: str = None
62
-
63
- def __init__(self, data, seed):
64
- self.data = data
65
- self.seed = seed
66
-
67
- def json(self):
68
- return {
69
- "data": self.data,
70
- "seed": self.seed,
71
- "path_abs": self.path_abs,
72
- }
73
-
74
-
75
- class Response:
76
- render_request: GenerateImageRequest
77
- task_data: TaskData
78
- images: list
79
-
80
- def __init__(self, render_request: GenerateImageRequest, task_data: TaskData, images: list):
81
- self.render_request = render_request
82
- self.task_data = task_data
83
- self.images = images
84
-
85
- def json(self):
86
- del self.render_request.init_image
87
- del self.render_request.init_image_mask
88
-
89
- res = {
90
- "status": "succeeded",
91
- "render_request": self.render_request.dict(),
92
- "task_data": self.task_data.dict(),
93
- "output": [],
94
- }
95
-
96
- for image in self.images:
97
- res["output"].append(image.json())
98
-
99
- return res
100
-
101
-
102
- class UserInitiatedStop(Exception):
103
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/easydiffusion/utils/__init__.py DELETED
@@ -1,8 +0,0 @@
1
- import logging
2
-
3
- log = logging.getLogger("easydiffusion")
4
-
5
- from .save_utils import (
6
- save_images_to_disk,
7
- get_printable_request,
8
- )
 
 
 
 
 
 
 
 
 
ui/easydiffusion/utils/__pycache__/__init__.cpython-38.pyc DELETED
Binary file (311 Bytes)
 
ui/easydiffusion/utils/__pycache__/save_utils.cpython-38.pyc DELETED
Binary file (3.52 kB)
 
ui/easydiffusion/utils/save_utils.py DELETED
@@ -1,131 +0,0 @@
1
- import os
2
- import time
3
- import re
4
-
5
- from easydiffusion.types import TaskData, GenerateImageRequest
6
-
7
- from sdkit.utils import save_images, save_dicts
8
- from numpy import base_repr
9
-
10
- filename_regex = re.compile("[^a-zA-Z0-9._-]")
11
-
12
- # keep in sync with `ui/media/js/dnd.js`
13
- TASK_TEXT_MAPPING = {
14
- "prompt": "Prompt",
15
- "width": "Width",
16
- "height": "Height",
17
- "seed": "Seed",
18
- "num_inference_steps": "Steps",
19
- "guidance_scale": "Guidance Scale",
20
- "prompt_strength": "Prompt Strength",
21
- "use_face_correction": "Use Face Correction",
22
- "use_upscale": "Use Upscaling",
23
- "upscale_amount": "Upscale By",
24
- "sampler_name": "Sampler",
25
- "negative_prompt": "Negative Prompt",
26
- "use_stable_diffusion_model": "Stable Diffusion model",
27
- "use_vae_model": "VAE model",
28
- "use_hypernetwork_model": "Hypernetwork model",
29
- "hypernetwork_strength": "Hypernetwork Strength",
30
- }
31
-
32
-
33
- def save_images_to_disk(images: list, filtered_images: list, req: GenerateImageRequest, task_data: TaskData):
34
- now = time.time()
35
- save_dir_path = os.path.join(task_data.save_to_disk_path, filename_regex.sub("_", task_data.session_id))
36
- metadata_entries = get_metadata_entries_for_request(req, task_data)
37
- make_filename = make_filename_callback(req, now=now)
38
-
39
- if task_data.show_only_filtered_image or filtered_images is images:
40
- save_images(
41
- filtered_images,
42
- save_dir_path,
43
- file_name=make_filename,
44
- output_format=task_data.output_format,
45
- output_quality=task_data.output_quality,
46
- )
47
- if task_data.metadata_output_format.lower() in ["json", "txt", "embed"]:
48
- save_dicts(
49
- metadata_entries,
50
- save_dir_path,
51
- file_name=make_filename,
52
- output_format=task_data.metadata_output_format,
53
- file_format=task_data.output_format,
54
- )
55
- else:
56
- make_filter_filename = make_filename_callback(req, now=now, suffix="filtered")
57
-
58
- save_images(
59
- images,
60
- save_dir_path,
61
- file_name=make_filename,
62
- output_format=task_data.output_format,
63
- output_quality=task_data.output_quality,
64
- )
65
- save_images(
66
- filtered_images,
67
- save_dir_path,
68
- file_name=make_filter_filename,
69
- output_format=task_data.output_format,
70
- output_quality=task_data.output_quality,
71
- )
72
- if task_data.metadata_output_format.lower() in ["json", "txt", "embed"]:
73
- save_dicts(
74
- metadata_entries,
75
- save_dir_path,
76
- file_name=make_filter_filename,
77
- output_format=task_data.metadata_output_format,
78
- file_format=task_data.output_format,
79
- )
80
-
81
-
82
- def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskData):
83
- metadata = get_printable_request(req)
84
- metadata.update(
85
- {
86
- "use_stable_diffusion_model": task_data.use_stable_diffusion_model,
87
- "use_vae_model": task_data.use_vae_model,
88
- "use_hypernetwork_model": task_data.use_hypernetwork_model,
89
- "use_face_correction": task_data.use_face_correction,
90
- "use_upscale": task_data.use_upscale,
91
- }
92
- )
93
- if metadata["use_upscale"] is not None:
94
- metadata["upscale_amount"] = task_data.upscale_amount
95
- if task_data.use_hypernetwork_model is None:
96
- del metadata["hypernetwork_strength"]
97
-
98
- # if text, format it in the text format expected by the UI
99
- is_txt_format = task_data.metadata_output_format.lower() == "txt"
100
- if is_txt_format:
101
- metadata = {TASK_TEXT_MAPPING[key]: val for key, val in metadata.items() if key in TASK_TEXT_MAPPING}
102
-
103
- entries = [metadata.copy() for _ in range(req.num_outputs)]
104
- for i, entry in enumerate(entries):
105
- entry["Seed" if is_txt_format else "seed"] = req.seed + i
106
-
107
- return entries
108
-
109
-
110
- def get_printable_request(req: GenerateImageRequest):
111
- metadata = req.dict()
112
- del metadata["init_image"]
113
- del metadata["init_image_mask"]
114
- if req.init_image is None:
115
- del metadata["prompt_strength"]
116
- return metadata
117
-
118
-
119
- def make_filename_callback(req: GenerateImageRequest, suffix=None, now=None):
120
- if now is None:
121
- now = time.time()
122
-
123
- def make_filename(i):
124
- img_id = base_repr(int(now * 10000), 36)[-7:] + base_repr(int(i),36) # Base 36 conversion, 0-9, A-Z
125
-
126
- prompt_flattened = filename_regex.sub("_", req.prompt)[:50]
127
- name = f"{prompt_flattened}_{img_id}"
128
- name = name if suffix is None else f"{name}_{suffix}"
129
- return name
130
-
131
- return make_filename
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/hotfix/9c24e6cd9f499d02c4f21a033736dabd365962dc80fe3aeb57a8f85ea45a20a3.26fead7ea4f0f843f6eb4055dfd25693f1a71f3c6871b184042d4b126244e142 DELETED
@@ -1,171 +0,0 @@
1
- {
2
- "_name_or_path": "clip-vit-large-patch14/",
3
- "architectures": [
4
- "CLIPModel"
5
- ],
6
- "initializer_factor": 1.0,
7
- "logit_scale_init_value": 2.6592,
8
- "model_type": "clip",
9
- "projection_dim": 768,
10
- "text_config": {
11
- "_name_or_path": "",
12
- "add_cross_attention": false,
13
- "architectures": null,
14
- "attention_dropout": 0.0,
15
- "bad_words_ids": null,
16
- "bos_token_id": 0,
17
- "chunk_size_feed_forward": 0,
18
- "cross_attention_hidden_size": null,
19
- "decoder_start_token_id": null,
20
- "diversity_penalty": 0.0,
21
- "do_sample": false,
22
- "dropout": 0.0,
23
- "early_stopping": false,
24
- "encoder_no_repeat_ngram_size": 0,
25
- "eos_token_id": 2,
26
- "finetuning_task": null,
27
- "forced_bos_token_id": null,
28
- "forced_eos_token_id": null,
29
- "hidden_act": "quick_gelu",
30
- "hidden_size": 768,
31
- "id2label": {
32
- "0": "LABEL_0",
33
- "1": "LABEL_1"
34
- },
35
- "initializer_factor": 1.0,
36
- "initializer_range": 0.02,
37
- "intermediate_size": 3072,
38
- "is_decoder": false,
39
- "is_encoder_decoder": false,
40
- "label2id": {
41
- "LABEL_0": 0,
42
- "LABEL_1": 1
43
- },
44
- "layer_norm_eps": 1e-05,
45
- "length_penalty": 1.0,
46
- "max_length": 20,
47
- "max_position_embeddings": 77,
48
- "min_length": 0,
49
- "model_type": "clip_text_model",
50
- "no_repeat_ngram_size": 0,
51
- "num_attention_heads": 12,
52
- "num_beam_groups": 1,
53
- "num_beams": 1,
54
- "num_hidden_layers": 12,
55
- "num_return_sequences": 1,
56
- "output_attentions": false,
57
- "output_hidden_states": false,
58
- "output_scores": false,
59
- "pad_token_id": 1,
60
- "prefix": null,
61
- "problem_type": null,
62
- "projection_dim" : 768,
63
- "pruned_heads": {},
64
- "remove_invalid_values": false,
65
- "repetition_penalty": 1.0,
66
- "return_dict": true,
67
- "return_dict_in_generate": false,
68
- "sep_token_id": null,
69
- "task_specific_params": null,
70
- "temperature": 1.0,
71
- "tie_encoder_decoder": false,
72
- "tie_word_embeddings": true,
73
- "tokenizer_class": null,
74
- "top_k": 50,
75
- "top_p": 1.0,
76
- "torch_dtype": null,
77
- "torchscript": false,
78
- "transformers_version": "4.16.0.dev0",
79
- "use_bfloat16": false,
80
- "vocab_size": 49408
81
- },
82
- "text_config_dict": {
83
- "hidden_size": 768,
84
- "intermediate_size": 3072,
85
- "num_attention_heads": 12,
86
- "num_hidden_layers": 12,
87
- "projection_dim": 768
88
- },
89
- "torch_dtype": "float32",
90
- "transformers_version": null,
91
- "vision_config": {
92
- "_name_or_path": "",
93
- "add_cross_attention": false,
94
- "architectures": null,
95
- "attention_dropout": 0.0,
96
- "bad_words_ids": null,
97
- "bos_token_id": null,
98
- "chunk_size_feed_forward": 0,
99
- "cross_attention_hidden_size": null,
100
- "decoder_start_token_id": null,
101
- "diversity_penalty": 0.0,
102
- "do_sample": false,
103
- "dropout": 0.0,
104
- "early_stopping": false,
105
- "encoder_no_repeat_ngram_size": 0,
106
- "eos_token_id": null,
107
- "finetuning_task": null,
108
- "forced_bos_token_id": null,
109
- "forced_eos_token_id": null,
110
- "hidden_act": "quick_gelu",
111
- "hidden_size": 1024,
112
- "id2label": {
113
- "0": "LABEL_0",
114
- "1": "LABEL_1"
115
- },
116
- "image_size": 224,
117
- "initializer_factor": 1.0,
118
- "initializer_range": 0.02,
119
- "intermediate_size": 4096,
120
- "is_decoder": false,
121
- "is_encoder_decoder": false,
122
- "label2id": {
123
- "LABEL_0": 0,
124
- "LABEL_1": 1
125
- },
126
- "layer_norm_eps": 1e-05,
127
- "length_penalty": 1.0,
128
- "max_length": 20,
129
- "min_length": 0,
130
- "model_type": "clip_vision_model",
131
- "no_repeat_ngram_size": 0,
132
- "num_attention_heads": 16,
133
- "num_beam_groups": 1,
134
- "num_beams": 1,
135
- "num_hidden_layers": 24,
136
- "num_return_sequences": 1,
137
- "output_attentions": false,
138
- "output_hidden_states": false,
139
- "output_scores": false,
140
- "pad_token_id": null,
141
- "patch_size": 14,
142
- "prefix": null,
143
- "problem_type": null,
144
- "projection_dim" : 768,
145
- "pruned_heads": {},
146
- "remove_invalid_values": false,
147
- "repetition_penalty": 1.0,
148
- "return_dict": true,
149
- "return_dict_in_generate": false,
150
- "sep_token_id": null,
151
- "task_specific_params": null,
152
- "temperature": 1.0,
153
- "tie_encoder_decoder": false,
154
- "tie_word_embeddings": true,
155
- "tokenizer_class": null,
156
- "top_k": 50,
157
- "top_p": 1.0,
158
- "torch_dtype": null,
159
- "torchscript": false,
160
- "transformers_version": "4.16.0.dev0",
161
- "use_bfloat16": false
162
- },
163
- "vision_config_dict": {
164
- "hidden_size": 1024,
165
- "intermediate_size": 4096,
166
- "num_attention_heads": 16,
167
- "num_hidden_layers": 24,
168
- "patch_size": 14,
169
- "projection_dim": 768
170
- }
171
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/index.html DELETED
@@ -1,514 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Easy Diffusion</title>
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="theme-color" content="#673AB6">
7
- <link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16">
8
- <link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32">
9
- <link rel="stylesheet" href="/media/css/jquery-confirm.min.css">
10
- <link rel="stylesheet" href="/media/css/fonts.css">
11
- <link rel="stylesheet" href="/media/css/themes.css">
12
- <link rel="stylesheet" href="/media/css/main.css">
13
- <link rel="stylesheet" href="/media/css/auto-save.css">
14
- <link rel="stylesheet" href="/media/css/modifier-thumbnails.css">
15
- <link rel="stylesheet" href="/media/css/fontawesome-all.min.css">
16
- <link rel="stylesheet" href="/media/css/image-editor.css">
17
- <link rel="stylesheet" href="/media/css/searchable-models.css">
18
- <link rel="stylesheet" href="/media/css/image-modal.css">
19
- <link rel="manifest" href="/media/manifest.webmanifest">
20
- <script src="/media/js/jquery-3.6.1.min.js"></script>
21
- <script src="/media/js/jquery-confirm.min.js"></script>
22
- <script src="/media/js/jszip.min.js"></script>
23
- <script src="/media/js/FileSaver.min.js"></script>
24
- <script src="/media/js/marked.min.js"></script>
25
- </head>
26
- <body>
27
- <div id="container">
28
- <div id="top-nav">
29
- <div id="logo">
30
- <h1>
31
- <img id="logo_img" src="/media/images/icon-512x512.png" >
32
- Easy Diffusion
33
- <small>v2.5.26 <span id="updateBranchLabel"></span></small>
34
- </h1>
35
- </div>
36
- <div id="server-status">
37
- <div id="server-status-color">●</div>
38
- <span id="server-status-msg">Stable Diffusion is starting..</span>
39
- </div>
40
- <div id="tab-container" class="tab-container">
41
- <span id="tab-main" class="tab active">
42
- <span><i class="fa fa-image icon"></i> Generate</span>
43
- </span>
44
- <span id="tab-settings" class="tab">
45
- <span><i class="fa fa-gear icon"></i> Settings</span>
46
- </span>
47
- <span id="tab-about" class="tab">
48
- <span><i class="fa fa-comments icon"></i> Help & Community</span>
49
- </span>
50
- </div>
51
- </div>
52
-
53
- <div id="tab-content-wrapper">
54
- <div id="tab-content-main" class="tab-content active flex-container">
55
- <div id="editor">
56
- <div id="editor-inputs">
57
- <div id="editor-inputs-prompt" class="row">
58
- <label for="prompt"><b>Enter Prompt</b></label> <small>or</small> <button id="promptsFromFileBtn" class="tertiaryButton">Load from a file</button>
59
- <textarea id="prompt" class="col-free">a photograph of an astronaut riding a horse</textarea>
60
- <input id="prompt_from_file" name="prompt_from_file" type="file" /> <!-- hidden -->
61
- <label for="negative_prompt" class="collapsible" id="negative_prompt_handle">
62
- Negative Prompt
63
- <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Writing-prompts#negative-prompts" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top">Click to learn more about Negative Prompts</span></i></a>
64
- <small>(optional)</small>
65
- </label>
66
- <div class="collapsible-content">
67
- <textarea id="negative_prompt" name="negative_prompt" placeholder="list the things to remove from the image (e.g. fog, green)"></textarea>
68
- </div>
69
- </div>
70
-
71
- <div id="editor-inputs-init-image" class="row">
72
- <label for="init_image">Initial Image (img2img) <small>(optional)</small> </label>
73
-
74
- <div id="init_image_preview_container" class="image_preview_container">
75
- <div id="init_image_wrapper">
76
- <img id="init_image_preview" src="" />
77
- <span id="init_image_size_box" class="img_bottom_label"></span>
78
- <button class="init_image_clear image_clear_btn"><i class="fa-solid fa-xmark"></i></button>
79
- </div>
80
- <div id="init_image_buttons">
81
- <div class="button">
82
- <i class="fa-regular fa-folder-open"></i>
83
- Browse
84
- <input id="init_image" name="init_image" type="file" />
85
- </div>
86
- <div id="init_image_button_draw" class="button">
87
- <i class="fa-solid fa-pencil"></i>
88
- Draw
89
- </div>
90
- <div id="inpaint_button_container">
91
- <div id="init_image_button_inpaint" class="button">
92
- <i class="fa-solid fa-paintbrush"></i>
93
- Inpaint
94
- </div>
95
- <input id="enable_mask" name="enable_mask" type="checkbox">
96
- </div>
97
- </div>
98
- </div>
99
-
100
- <div id="apply_color_correction_setting" class="pl-5"><input id="apply_color_correction" name="apply_color_correction" type="checkbox"> <label for="apply_color_correction">Preserve color profile <small>(helps during inpainting)</small></label></div>
101
-
102
- </div>
103
-
104
- <div id="editor-inputs-tags-container" class="row">
105
- <label>Image Modifiers <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">click an Image Modifier to remove it, right-click to temporarily disable it, use Ctrl+Mouse Wheel to adjust its weight</span></i></label>
106
- <div id="editor-inputs-tags-list"></div>
107
- </div>
108
-
109
- <button id="makeImage" class="primaryButton">Make Image</button>
110
- <div id="render-buttons">
111
- <button id="stopImage" class="secondaryButton">Stop All</button>
112
- <button id="pause"><i class="fa-solid fa-pause"></i> Pause All</button>
113
- <button id="resume"><i class="fa-solid fa-play"></i> Resume</button>
114
- </div>
115
- </div>
116
-
117
- <span class="line-separator"></span>
118
-
119
- <div id="editor-settings" class="settings-box panel-box">
120
- <h4 class="collapsible">
121
- Image Settings
122
- <i id="reset-image-settings" class="fa-solid fa-arrow-rotate-left section-button">
123
- <span class="simple-tooltip top-left">
124
- Reset Image Settings
125
- </span>
126
- </i>
127
- </h4>
128
- <div id="editor-settings-entries" class="collapsible-content">
129
- <div><table>
130
- <tr><b class="settings-subheader">Image Settings</b></tr>
131
- <tr class="pl-5"><td><label for="seed">Seed:</label></td><td><input id="seed" name="seed" size="10" value="0" onkeypress="preventNonNumericalInput(event)"> <input id="random_seed" name="random_seed" type="checkbox" checked><label for="random_seed">Random</label></td></tr>
132
- <tr class="pl-5"><td><label for="num_outputs_total">Number of Images:</label></td><td><input id="num_outputs_total" name="num_outputs_total" value="1" size="1" onkeypress="preventNonNumericalInput(event)"> <label><small>(total)</small></label> <input id="num_outputs_parallel" name="num_outputs_parallel" value="1" size="1" onkeypress="preventNonNumericalInput(event)"> <label for="num_outputs_parallel"><small>(in parallel)</small></label></td></tr>
133
- <tr class="pl-5"><td><label for="stable_diffusion_model">Model:</label></td><td class="model-input">
134
- <input id="stable_diffusion_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
135
- <button id="reload-models" class="secondaryButton reloadModels"><i class='fa-solid fa-rotate'></i></button>
136
- <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Models" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about custom models</span></i></a>
137
- </td></tr>
138
- <!-- <tr id="modelConfigSelection" class="pl-5"><td><label for="model_config">Model Config:</i></label></td><td>
139
- <select id="model_config" name="model_config">
140
- </select>
141
- </td></tr> -->
142
- <tr class="pl-5"><td><label for="vae_model">Custom VAE:</i></label></td><td>
143
- <input id="vae_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
144
- <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about VAEs</span></i></a>
145
- </td></tr>
146
- <tr id="samplerSelection" class="pl-5"><td><label for="sampler_name">Sampler:</label></td><td>
147
- <select id="sampler_name" name="sampler_name">
148
- <option value="plms">PLMS</option>
149
- <option value="ddim">DDIM</option>
150
- <option value="heun">Heun</option>
151
- <option value="euler">Euler</option>
152
- <option value="euler_a" selected>Euler Ancestral</option>
153
- <option value="dpm2">DPM2</option>
154
- <option value="dpm2_a">DPM2 Ancestral</option>
155
- <option value="lms">LMS</option>
156
- <option value="dpm_solver_stability">DPM Solver (Stability AI)</option>
157
- <option value="dpmpp_2s_a">DPM++ 2s Ancestral (Karras)</option>
158
- <option value="dpmpp_2m">DPM++ 2m (Karras)</option>
159
- <option value="dpmpp_sde">DPM++ SDE (Karras)</option>
160
- <option value="dpm_fast">DPM Fast (Karras)</option>
161
- <option value="dpm_adaptive">DPM Adaptive (Karras)</option>
162
- <option value="unipc_snr">UniPC SNR</option>
163
- <option value="unipc_tu">UniPC TU</option>
164
- <option value="unipc_snr_2">UniPC SNR 2</option>
165
- <option value="unipc_tu_2">UniPC TC 2</option>
166
- <option value="unipc_tq">UniPC TQ</option>
167
- </select>
168
- <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/How-to-Use#samplers" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about samplers</span></i></a>
169
- </td></tr>
170
- <tr class="pl-5"><td><label>Image Size: </label></td><td>
171
- <select id="width" name="width" value="512">
172
- <option value="128">128 (*)</option>
173
- <option value="192">192</option>
174
- <option value="256">256 (*)</option>
175
- <option value="320">320</option>
176
- <option value="384">384</option>
177
- <option value="448">448</option>
178
- <option value="512" selected>512 (*)</option>
179
- <option value="576">576</option>
180
- <option value="640">640</option>
181
- <option value="704">704</option>
182
- <option value="768">768 (*)</option>
183
- <option value="832">832</option>
184
- <option value="896">896</option>
185
- <option value="960">960</option>
186
- <option value="1024">1024 (*)</option>
187
- <option value="1280">1280</option>
188
- <option value="1536">1536</option>
189
- <option value="1792">1792</option>
190
- <option value="2048">2048</option>
191
- </select>
192
- <label for="width"><small>(width)</small></label>
193
- <select id="height" name="height" value="512">
194
- <option value="128">128 (*)</option>
195
- <option value="192">192</option>
196
- <option value="256">256 (*)</option>
197
- <option value="320">320</option>
198
- <option value="384">384</option>
199
- <option value="448">448</option>
200
- <option value="512" selected>512 (*)</option>
201
- <option value="576">576</option>
202
- <option value="640">640</option>
203
- <option value="704">704</option>
204
- <option value="768">768 (*)</option>
205
- <option value="832">832</option>
206
- <option value="896">896</option>
207
- <option value="960">960</option>
208
- <option value="1024">1024 (*)</option>
209
- <option value="1280">1280</option>
210
- <option value="1536">1536</option>
211
- <option value="1792">1792</option>
212
- <option value="2048">2048</option>
213
- </select>
214
- <label for="height"><small>(height)</small></label>
215
- <div id="small_image_warning" class="displayNone">Small image sizes can cause bad image quality</div>
216
- </td></tr>
217
- <tr class="pl-5"><td><label for="num_inference_steps">Inference Steps:</label></td><td> <input id="num_inference_steps" name="num_inference_steps" size="4" value="25" onkeypress="preventNonNumericalInput(event)"></td></tr>
218
- <tr class="pl-5"><td><label for="guidance_scale_slider">Guidance Scale:</label></td><td> <input id="guidance_scale_slider" name="guidance_scale_slider" class="editor-slider" value="75" type="range" min="11" max="500"> <input id="guidance_scale" name="guidance_scale" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"></td></tr>
219
- <tr id="prompt_strength_container" class="pl-5"><td><label for="prompt_strength_slider">Prompt Strength:</label></td><td> <input id="prompt_strength_slider" name="prompt_strength_slider" class="editor-slider" value="80" type="range" min="0" max="99"> <input id="prompt_strength" name="prompt_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"><br/></td></tr>
220
- <tr class="pl-5"><td><label for="hypernetwork_model">Hypernetwork:</i></label></td><td>
221
- <input id="hypernetwork_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
222
- </td></tr>
223
- <tr id="hypernetwork_strength_container" class="pl-5">
224
- <td><label for="hypernetwork_strength_slider">Hypernetwork Strength:</label></td>
225
- <td> <input id="hypernetwork_strength_slider" name="hypernetwork_strength_slider" class="editor-slider" value="100" type="range" min="0" max="100"> <input id="hypernetwork_strength" name="hypernetwork_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"><br/></td>
226
- </tr>
227
- <tr class="pl-5"><td><label for="output_format">Output Format:</label></td><td>
228
- <select id="output_format" name="output_format">
229
- <option value="jpeg" selected>jpeg</option>
230
- <option value="png">png</option>
231
- <option value="webp">webp</option>
232
- </select>
233
- </td></tr>
234
- <tr class="pl-5" id="output_quality_row"><td><label for="output_quality">Image Quality:</label></td><td>
235
- <input id="output_quality_slider" name="output_quality" class="editor-slider" value="75" type="range" min="10" max="95"> <input id="output_quality" name="output_quality" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)">
236
- </td></tr>
237
- </table></div>
238
-
239
- <div><ul>
240
- <li><b class="settings-subheader">Render Settings</b></li>
241
- <li class="pl-5"><input id="stream_image_progress" name="stream_image_progress" type="checkbox"> <label for="stream_image_progress">Show a live preview <small>(uses more VRAM, slower images)</small></label></li>
242
- <li class="pl-5"><input id="use_face_correction" name="use_face_correction" type="checkbox"> <label for="use_face_correction">Fix incorrect faces and eyes</label> <div style="display:inline-block;"><input id="gfpgan_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" /></div></li>
243
- <li class="pl-5">
244
- <input id="use_upscale" name="use_upscale" type="checkbox"> <label for="use_upscale">Scale up by</label>
245
- <select id="upscale_amount" name="upscale_amount">
246
- <option value="2">2x</option>
247
- <option value="4" selected>4x</option>
248
- </select>
249
- with
250
- <select id="upscale_model" name="upscale_model">
251
- <option value="RealESRGAN_x4plus" selected>RealESRGAN_x4plus</option>
252
- <option value="RealESRGAN_x4plus_anime_6B">RealESRGAN_x4plus_anime_6B</option>
253
- </select>
254
- </li>
255
- <li class="pl-5"><input id="show_only_filtered_image" name="show_only_filtered_image" type="checkbox" checked> <label for="show_only_filtered_image">Show only the corrected/upscaled image</label></li>
256
- </ul></div>
257
- </div>
258
- </div>
259
-
260
- <div id="editor-modifiers" class="panel-box">
261
- <h4 class="collapsible">
262
- Image Modifiers (art styles, tags etc)
263
- <i id="modifier-settings-btn" class="fa-solid fa-gear section-button">
264
- <span class="simple-tooltip left">
265
- Add Custom Modifiers
266
- </span>
267
- </i>
268
- </h4>
269
- <div id="editor-modifiers-entries" class="collapsible-content">
270
- <div id="editor-modifiers-entries-toolbar">
271
- <label for="preview-image">Image Style:</label>
272
- <select id="preview-image" name="preview-image" value="portrait">
273
- <option value="portrait" selected="">Face</option>
274
- <option value="landscape">Landscape</option>
275
- </select>
276
- &nbsp;
277
- <label for="modifier-card-size-slider">Thumbnail Size:</label>
278
- <input id="modifier-card-size-slider" name="modifier-card-size-slider" value="0" type="range" min="-3" max="5">
279
- </div>
280
- </div>
281
- </div>
282
- </div>
283
-
284
- <div id="preview" class="col-free">
285
- <div id="initial-text">
286
- Type a prompt and press the "Make Image" button.<br/><br/>You can set an "Initial Image" if you want to guide the AI.<br/><br/>
287
- You can also add modifiers like "Realistic", "Pencil Sketch", "ArtStation" etc by browsing through the "Image Modifiers" section
288
- and selecting the desired modifiers.<br/><br/>
289
- Click "Image Settings" for additional settings like seed, image size, number of images to generate etc.<br/><br/>Enjoy! :)
290
- </div>
291
-
292
- <div id="preview-content">
293
- <div id="preview-tools">
294
- <button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can icon"></i> Clear All</button>
295
- <button class="tertiaryButton" id="show-download-popup"><i class="fa-solid fa-download"></i> Download images</button>
296
- <div class="display-settings">
297
- <span class="auto-scroll"></span> <!-- hack for Rabbit Hole update -->
298
- <button id="auto_scroll_btn" class="tertiaryButton">
299
- <i class="fa-solid fa-arrows-up-to-line icon"></i>
300
- <input id="auto_scroll" name="auto_scroll" type="checkbox" style="display: none">
301
- <span class="simple-tooltip left">
302
- Scroll to generated image (<span class="state">OFF</span>)
303
- </span>
304
- </button>
305
- <button class="dropdown tertiaryButton">
306
- <i class="fa-solid fa-magnifying-glass-plus icon dropbtn"></i>
307
- <span class="simple-tooltip left">
308
- Image Size
309
- </span>
310
- </button>
311
- <div class="dropdown-content">
312
- <div class="dropdown-item">
313
- <input id="thumbnail_size" name="thumbnail_size" class="editor-slider" type="range" value="70" min="5" max="200" oninput="sliderUpdate(event)">
314
- <input id="thumbnail_size-input" name="thumbnail_size-input" size="3" value="70" pattern="^[0-9.]+$" onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)">&nbsp;%
315
- </div>
316
- </div>
317
- </div>
318
- <div class="clearfix" style="clear: both;"></div>
319
- </div>
320
- </div>
321
- </div>
322
- </div>
323
-
324
- <div id="tab-content-settings" class="tab-content">
325
- <div id="system-settings" class="tab-content-inner">
326
- <h1>System Settings</h1>
327
- <div class="parameters-table"></div>
328
- <br/>
329
- <button id="save-system-settings-btn" class="primaryButton">Save</button>
330
- <br/><br/>
331
- <div>
332
- <h3><i class="fa fa-microchip icon"></i> System Info</h3>
333
- <div id="system-info">
334
- <table>
335
- <tr><td><label>Processor:</label></td><td id="system-info-cpu" class="value"></td></tr>
336
- <tr><td><label>Compatible Graphics Cards (all):</label></td><td id="system-info-gpus-all" class="value"></td></tr>
337
- <tr><td></td><td>&nbsp;</td></tr>
338
- <tr><td><label>Used for rendering 🔥:</label></td><td id="system-info-rendering-devices" class="value"></td></tr>
339
- <tr><td><label>Server Addresses <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">You can access Stable Diffusion UI from other devices using these addresses</span></i> :</label></td><td id="system-info-server-hosts" class="value"></td></tr>
340
- </table>
341
- </div>
342
- </div>
343
-
344
- </div>
345
- </div>
346
- <div id="tab-content-about" class="tab-content">
347
- <div class="tab-content-inner">
348
- <div class="float-container">
349
- <div class="float-child">
350
- <h1>Help</h1>
351
- <ul id="help-links">
352
- <li><span class="help-section">Using the software</span>
353
- <ul>
354
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/How-To-Use" target="_blank"><i class="fa-solid fa-book fa-fw"></i> How to use</a>
355
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Overview" target="_blank"><i class="fa-solid fa-list fa-fw"></i> UI Overview</a>
356
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Writing-Prompts" target="_blank"><i class="fa-solid fa-pen-to-square fa-fw"></i> Writing prompts</a>
357
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Inpainting" target="_blank"><i class="fa-solid fa-paintbrush fa-fw"></i> Inpainting</a>
358
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Run-on-Multiple-GPUs" target="_blank"><i class="fa-solid fa-paintbrush fa-fw"></i> Run on Multiple GPUs</a>
359
- </ul>
360
-
361
- <li><span class="help-section">Installation</span>
362
- <ul>
363
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" target="_blank"><i class="fa-solid fa-circle-question fa-fw"></i> Troubleshooting</a>
364
- </ul>
365
-
366
- <li><span class="help-section">Downloadable Content</span>
367
- <ul>
368
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Models" target="_blank"><i class="fa-solid fa-images fa-fw"></i> Custom Models</a>
369
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Plugins" target="_blank"><i class="fa-solid fa-puzzle-piece fa-fw"></i> UI Plugins</a>
370
- <li> <a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder" target="_blank"><i class="fa-solid fa-hand-sparkles fa-fw"></i> VAE Variational Auto Encoder</a>
371
- </ul>
372
- </ul>
373
- </div>
374
-
375
- <div class="float-child">
376
- <h1>Community</h1>
377
- <ul id="community-links">
378
- <li><a href="https://discord.com/invite/u9yhsFmEkB" target="_blank"><i class="fa-brands fa-discord fa-fw"></i> Discord user community</a></li>
379
- <li><a href="https://www.reddit.com/r/StableDiffusionUI/" target="_blank"><i class="fa-brands fa-reddit fa-fw"></i> Reddit community</a></li>
380
- <li><a href="https://github.com/cmdr2/stable-diffusion-ui" target="_blank"><i class="fa-brands fa-github fa-fw"></i> Source code on GitHub</a></li>
381
- </ul>
382
- </div>
383
- </div>
384
- </div>
385
- </div>
386
- </div>
387
-
388
-
389
- <div class="popup" id="download-images-popup">
390
- <div>
391
- <i class="close-button fa-solid fa-xmark"></i>
392
- <h1>Download all images</h1>
393
- <div class="parameters-table">
394
- <div>
395
- <div><i class="fa fa-file-zipper"></i></div>
396
- <div><label for="theme">Download as a ZIP file</label><small>Instead of downloading individual files, generate one zip file with all images</small></div>
397
- <div><div class="input-toggle"><input id="zip_toggle" name="zip_toggle" checked="" type="checkbox"><label for="zip_toggle"></label></div></div>
398
- </div>
399
- <div id="download-add-folders">
400
- <div><i class="fa fa-folder-tree"></i></div>
401
- <div><label for="theme">Add per-job folders</label><small>Place images into job folders</small></div>
402
- <div><div class="input-toggle"><input id="tree_toggle" name="tree_toggle" checked="" type="checkbox"><label for="tree_toggle"></label></div></div>
403
- </div>
404
- <div>
405
- <div><i class="fa fa-sliders"></i></div>
406
- <div><label for="theme">Add metadata files</label><small>For each image, also download a JSON file with all the settings used to generate the image</small></div>
407
- <div><div class="input-toggle"><input id="json_toggle" name="json_toggle" checked="" type="checkbox"><label for="json_toggle"></label></div></div>
408
- </div>
409
- </div>
410
- <br/>
411
- <button id="save-all-images" class="primaryButton"><i class="fa-solid fa-images"></i> Start download</button>
412
- </div>
413
- </div>
414
- <div id="save-settings-config" class="popup">
415
- <div>
416
- <i class="close-button fa-solid fa-xmark"></i>
417
- <h1>Save Settings Configuration</h1>
418
- <p>Select which settings should be remembered when restarting the browser</p>
419
- <table id="save-settings-config-table" class="form-table">
420
- </table>
421
- </div>
422
- </div>
423
-
424
- <div id="modifier-settings-config" class="popup" tabindex="0">
425
- <div>
426
- <i class="close-button fa-solid fa-xmark"></i>
427
- <h1>Modifier Settings</h1>
428
- <p>Set your custom modifiers (one per line)</p>
429
- <textarea id="custom-modifiers-input" placeholder="Enter your custom modifiers, one-per-line" spellcheck="false"></textarea>
430
- <p><small><b>Tip:</b> You can include special characters like {} () [] and |. You can also put multiple comma-separated phrases in a single line, to make a single modifier that combines all of those.</small></p>
431
- </div>
432
- </div>
433
-
434
- <div id="image-editor" class="popup image-editor-popup">
435
- <div>
436
- <i class="close-button fa-solid fa-xmark"></i>
437
- <h1>Image Editor</h1>
438
- <div class="flex-container">
439
- <div class="editor-controls-left"></div>
440
- <div class="editor-controls-center">
441
- <div></div>
442
- </div>
443
- <div class="editor-controls-right">
444
- <div></div>
445
- </div>
446
- </div>
447
- </div>
448
- </div>
449
-
450
- <div id="image-inpainter" class="popup image-editor-popup">
451
- <div>
452
- <i class="close-button fa-solid fa-xmark"></i>
453
- <h1>Inpainter</h1>
454
- <div class="flex-container">
455
- <div class="editor-controls-left"></div>
456
- <div class="editor-controls-center">
457
- <div></div>
458
- </div>
459
- <div class="editor-controls-right">
460
- <div></div>
461
- </div>
462
- </div>
463
- </div>
464
- </div>
465
-
466
- <div id="footer-spacer"></div>
467
- <div id="footer">
468
- <div class="line-separator">&nbsp;</div>
469
- <p>If you found this project useful and want to help keep it alive, please <a href="https://ko-fi.com/cmdr2_stablediffusion_ui" target="_blank"><img src="/media/images/kofi.png" id="coffeeButton"></a> to help cover the cost of development and maintenance! Thank you for your support!</p>
470
- <p>Please feel free to join the <a href="https://discord.com/invite/u9yhsFmEkB" target="_blank">discord community</a> or <a href="https://github.com/cmdr2/stable-diffusion-ui/issues" target="_blank">file an issue</a> if you have any problems or suggestions in using this interface.</p>
471
- <div id="footer-legal">
472
- <p><b>Disclaimer:</b> The authors of this project are not responsible for any content generated using this interface.</p>
473
- <p>This license of this software forbids you from sharing any content that violates any laws, produce any harm to a person, disseminate any personal information that would be meant for harm, <br/>spread misinformation and target vulnerable groups. For the full list of restrictions please read <a href="https://github.com/cmdr2/stable-diffusion-ui/blob/main/LICENSE" target="_blank">the license</a>.</p>
474
- <p>By using this software, you consent to the terms and conditions of the license.</p>
475
- </div>
476
- </div>
477
- </div>
478
- </body>
479
- <script src="media/js/utils.js"></script>
480
- <script src="media/js/engine.js"></script>
481
- <script src="media/js/parameters.js"></script>
482
- <script src="media/js/plugins.js"></script>
483
-
484
- <script src="media/js/image-modifiers.js"></script>
485
- <script src="media/js/auto-save.js"></script>
486
-
487
- <script src="media/js/searchable-models.js"></script>
488
- <script src="media/js/main.js"></script>
489
- <script src="media/js/themes.js"></script>
490
- <script src="media/js/dnd.js"></script>
491
- <script src="media/js/image-editor.js"></script>
492
- <script src="media/js/image-modal.js"></script>
493
- <script>
494
- async function init() {
495
- await initSettings()
496
- await getModels()
497
- await getAppConfig()
498
- await loadUIPlugins()
499
- await loadModifiers()
500
- await getSystemInfo()
501
-
502
- SD.init({
503
- events: {
504
- statusChange: setServerStatus,
505
- idle: onIdle
506
- }
507
- })
508
-
509
- playSound()
510
- }
511
-
512
- init()
513
- </script>
514
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/main.py DELETED
@@ -1,10 +0,0 @@
1
- from easydiffusion import model_manager, app, server
2
- from easydiffusion.server import server_api # required for uvicorn
3
-
4
- # Init the app
5
- model_manager.init()
6
- app.init()
7
- server.init()
8
-
9
- # start the browser ui
10
- app.open_browser()
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/auto-save.css DELETED
@@ -1,81 +0,0 @@
1
- /* Auto-Settings Styling */
2
- #auto_save_settings ~ button {
3
- margin: 5px;
4
- }
5
- #auto_save_settings:not(:checked) ~ button {
6
- display: none;
7
- }
8
-
9
- .form-table {
10
- margin: auto;
11
- }
12
-
13
- .form-table th {
14
- padding-top: 15px;
15
- padding-bottom: 5px;
16
- }
17
-
18
- .form-table td:first-child > *,
19
- .form-table th:first-child > * {
20
- float: right;
21
- white-space: nowrap;
22
- }
23
-
24
- .form-table td:last-child > *,
25
- .form-table th:last-child > * {
26
- float: left;
27
- }
28
-
29
-
30
- .parameters-table {
31
- display: flex;
32
- flex-direction: column;
33
- gap: 1px;
34
- }
35
-
36
- .parameters-table > div {
37
- background: var(--background-color2);
38
- display: flex;
39
- padding: 0px 4px;
40
- }
41
-
42
- .parameters-table > div > div {
43
- padding: 10px;
44
- display: flex;
45
- align-items: center;
46
- justify-content: center;
47
- }
48
-
49
- .parameters-table small {
50
- color: rgb(153, 153, 153);
51
- }
52
-
53
- .parameters-table > div > div:nth-child(1) {
54
- font-size: 20px;
55
- width: 45px;
56
- }
57
-
58
- .parameters-table > div > div:nth-child(2) {
59
- flex: 1;
60
- flex-direction: column;
61
- text-align: left;
62
- justify-content: center;
63
- align-items: start;
64
- gap: 4px;
65
- }
66
-
67
- .parameters-table > div > div:nth-child(3) {
68
- text-align: right;
69
- }
70
-
71
- .parameters-table > div:first-child {
72
- border-radius: 12px 12px 0px 0px;
73
- }
74
-
75
- .parameters-table > div:last-child {
76
- border-radius: 0px 0px 12px 12px;
77
- }
78
-
79
- .parameters-table .fa-fire {
80
- color: #F7630C;
81
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/fontawesome-all.min.css DELETED
The diff for this file is too large to render. See raw diff
 
ui/media/css/fonts.css DELETED
@@ -1,40 +0,0 @@
1
- /* work-sans-regular - latin */
2
- @font-face {
3
- font-family: 'Work Sans';
4
- font-style: normal;
5
- font-weight: 400;
6
- src: local(''),
7
- url('/media/fonts/work-sans-v18-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
8
- url('/media/fonts/work-sans-v18-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
9
- }
10
-
11
- /* work-sans-600 - latin */
12
- @font-face {
13
- font-family: 'Work Sans';
14
- font-style: normal;
15
- font-weight: 600;
16
- src: local(''),
17
- url('/media/fonts/work-sans-v18-latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
18
- url('/media/fonts/work-sans-v18-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
19
- }
20
-
21
- /* work-sans-700 - latin */
22
- @font-face {
23
- font-family: 'Work Sans';
24
- font-style: normal;
25
- font-weight: 700;
26
- src: local(''),
27
- url('/media/fonts/work-sans-v18-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
28
- url('/media/fonts/work-sans-v18-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
29
- }
30
-
31
- /* work-sans-800 - latin */
32
- @font-face {
33
- font-family: 'Work Sans';
34
- font-style: normal;
35
- font-weight: 800;
36
- src: local(''),
37
- url('/media/fonts/work-sans-v18-latin-800.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
38
- url('/media/fonts/work-sans-v18-latin-800.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
39
- }
40
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/image-editor.css DELETED
@@ -1,228 +0,0 @@
1
- .editor-controls-left {
2
- padding-left: 32px;
3
- text-align: left;
4
- padding-bottom: 20px;
5
- max-width: min-content;
6
- }
7
-
8
- .editor-options-container {
9
- display: flex;
10
- row-gap: 10px;
11
- }
12
-
13
- .editor-options-container > * {
14
- flex: 1;
15
- display: flex;
16
- justify-content: center;
17
- align-items: center;
18
- }
19
-
20
- .editor-options-container > * > * {
21
- position: inherit;
22
- width: 32px;
23
- height: 32px;
24
- border-radius: 16px;
25
- background: var(--background-color3);
26
- cursor: pointer;
27
- transition: opacity 0.25s;
28
- }
29
- .editor-options-container > * > *:hover {
30
- opacity: 0.75;
31
- }
32
-
33
- .editor-options-container > * > *.active {
34
- border: 1px solid #3584e4;
35
- }
36
-
37
- .image_editor_opacity .editor-options-container > * > *:not(.active) {
38
- border: 1px solid var(--background-color3);
39
- }
40
-
41
- .image_editor_color .editor-options-container {
42
- flex-wrap: wrap;
43
- }
44
- .image_editor_color .editor-options-container > * {
45
- flex: 20%;
46
- }
47
- .image_editor_color .editor-options-container > * > * {
48
- position: relative;
49
- }
50
- .image_editor_color .editor-options-container > * > *.active::before {
51
- content: "\f00c";
52
- display: var(--fa-display,inline-block);
53
- font-style: normal;
54
- font-variant: normal;
55
- line-height: 1;
56
- text-rendering: auto;
57
- font-family: var(--fa-style-family, "Font Awesome 6 Free");
58
- font-weight: var(--fa-style, 900);
59
- position: absolute;
60
- left: 50%;
61
- top: 50%;
62
- transform: translate(-50%, -50%) scale(125%);
63
- color: black;
64
- }
65
- .image_editor_color .editor-options-container > *:first-child {
66
- flex: 100%;
67
- }
68
- .image_editor_color .editor-options-container > *:first-child > * {
69
- width: 100%;
70
- }
71
- .image_editor_color .editor-options-container > *:first-child > * > input {
72
- width: 100%;
73
- height: 100%;
74
- opacity: 0;
75
- cursor: pointer;
76
- }
77
- .image_editor_color .editor-options-container > *:first-child > * > span {
78
- position: absolute;
79
- left: 50%;
80
- top: 50%;
81
- transform: translate(-50%, -50%);
82
- opacity: 0.5;
83
- }
84
- .image_editor_color .editor-options-container > *:first-child > *.active > span {
85
- opacity: 0;
86
- }
87
-
88
- .image_editor_tool .editor-options-container {
89
- flex-wrap: wrap;
90
- }
91
-
92
- .image_editor_tool .editor-options-container > * {
93
- padding: 2px;
94
- flex: 50%;
95
- }
96
-
97
- .editor-controls-center {
98
- /* background: var(--background-color2); */
99
- flex: 1;
100
- display: flex;
101
- justify-content: center;
102
- align-items: center;
103
- }
104
-
105
- .editor-controls-center > div {
106
- position: relative;
107
- background: black;
108
- }
109
-
110
- .editor-controls-center canvas {
111
- position: absolute;
112
- left: 0;
113
- top: 0;
114
- }
115
-
116
- .editor-controls-right {
117
- padding: 32px;
118
- display: flex;
119
- flex-direction: column;
120
- }
121
-
122
-
123
- .editor-controls-right > div:last-child {
124
- flex: 1;
125
- display: flex;
126
- flex-direction: column;
127
- min-width: 200px;
128
- gap: 5px;
129
- justify-content: end;
130
- }
131
-
132
- .image-editor-button {
133
- width: 100%;
134
- height: 32px;
135
- border-radius: 16px;
136
- background: var(--background-color3);
137
- }
138
-
139
- .editor-controls-right .image-editor-button {
140
- margin-bottom: 4px;
141
- }
142
-
143
- #init_image_button_inpaint .input-toggle {
144
- position: absolute;
145
- left: 16px;
146
- }
147
-
148
- #init_image_button_inpaint .input-toggle input:not(:checked) ~ label {
149
- pointer-events: none;
150
- }
151
-
152
- .image-editor-popup {
153
- --popup-margin: 16px;
154
- --popup-padding: 24px;
155
- }
156
-
157
- @media screen and (min-width: 700px) {
158
- .image-editor-popup {
159
- overflow-y: auto;
160
- }
161
- }
162
-
163
- .image-editor-popup > div {
164
- margin: var(--popup-margin);
165
- padding: var(--popup-padding);
166
- min-height: calc(99h - (2 * var(--popup-margin)));
167
- max-width: none;
168
- min-width: fit-content;
169
- }
170
-
171
- .image-editor-popup h1 {
172
- position: absolute;
173
- top: 32px;
174
- left: 50%;
175
- transform: translateX(-50%);
176
- }
177
-
178
-
179
- @media screen and (max-width: 700px) {
180
- .image-editor-popup > div {
181
- margin: 0px;
182
- padding: 0px;
183
- }
184
-
185
- .image-editor-popup h1 {
186
- position: relative;
187
- transform: none;
188
- left: auto;
189
- }
190
- }
191
-
192
-
193
- .image-editor-popup > div > div {
194
- min-height: calc(99vh - (2 * var(--popup-margin)) - (2 * var(--popup-padding)));
195
- }
196
-
197
- .inpainter .image_editor_color {
198
- display: none;
199
- }
200
-
201
- .inpainter .editor-canvas-background {
202
- opacity: 0.75;
203
- }
204
-
205
- #init_image_preview_container .button {
206
- display: flex;
207
- padding: 6px;
208
- height: 24px;
209
- box-shadow: 2px 2px 1px 1px #00000088;
210
- }
211
-
212
- #init_image_preview_container .button:hover {
213
- background: var(--background-color4)
214
- }
215
-
216
- .image-editor-popup .button {
217
- display: flex;
218
- }
219
- .image-editor-popup h4 {
220
- text-align: left;
221
- }
222
-
223
- .image-editor-popup .load_mask {
224
- display: none;
225
- }
226
- .inpainter .load_mask {
227
- display: flex;
228
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/image-modal.css DELETED
@@ -1,84 +0,0 @@
1
- #viewFullSizeImgModal {
2
- --popup-padding: 24px;
3
- position: sticky;
4
- padding: var(--popup-padding);
5
- pointer-events: none;
6
- width: 100vw;
7
- height: 100vh;
8
- box-sizing: border-box;
9
- display: flex;
10
- justify-content: center;
11
- align-items: center;
12
- overflow: hidden;
13
- z-index: 1001;
14
- }
15
-
16
- #viewFullSizeImgModal > * {
17
- pointer-events: auto;
18
- margin: 0;
19
- padding: 0;
20
- box-sizing: border-box;
21
- }
22
-
23
- #viewFullSizeImgModal .backdrop {
24
- max-width: unset;
25
- width: 100%;
26
- max-height: unset;
27
- height: 100%;
28
- inset: 0;
29
- position: absolute;
30
- top: 0;
31
- left: 0;
32
- z-index: 1001;
33
- opacity: .5;
34
- border: none;
35
- box-shadow: none;
36
- overflow: hidden;
37
- }
38
-
39
- #viewFullSizeImgModal .content {
40
- min-height: initial;
41
- max-height: calc(100vh - (var(--popup-padding) * 2));
42
- height: fit-content;
43
- min-width: initial;
44
- max-width: calc(100vw - (var(--popup-padding) * 2));
45
- width: fit-content;
46
- z-index: 1003;
47
- overflow: visible;
48
- }
49
-
50
- #viewFullSizeImgModal .image-wrapper {
51
- min-height: initial;
52
- max-height: calc(100vh - (var(--popup-padding) * 2));
53
- height: fit-content;
54
- min-width: initial;
55
- max-width: calc(100vw - (var(--popup-padding) * 2));
56
- width: fit-content;
57
- box-sizing: border-box;
58
- pointer-events: auto;
59
- margin: 0;
60
- padding: 0;
61
- overflow: auto;
62
- }
63
-
64
- #viewFullSizeImgModal img.natural-zoom {
65
- max-width: calc(100vh - (var(--popup-padding) * 2) - 4px);
66
- max-height: calc(100vh - (var(--popup-padding) * 2) - 4px);
67
- }
68
-
69
- #viewFullSizeImgModal .content > div::-webkit-scrollbar-track, #viewFullSizeImgModal .content > div::-webkit-scrollbar-corner {
70
- background: rgba(0, 0, 0, .5)
71
- }
72
-
73
- #viewFullSizeImgModal .menu-bar {
74
- position: absolute;
75
- top: 0;
76
- right: 0;
77
- padding-right: var(--scrollbar-width);
78
- }
79
-
80
- #viewFullSizeImgModal .menu-bar .tertiaryButton {
81
- font-size: 1.2em;
82
- margin: 12px 12px 0 0;
83
- cursor: pointer;
84
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/jquery-confirm.min.css DELETED
@@ -1,9 +0,0 @@
1
- /*!
2
- * jquery-confirm v3.3.2 (http://craftpip.github.io/jquery-confirm/)
3
- * Author: boniface pereira
4
- * Website: www.craftpip.com
5
- * Contact: [email protected]
6
- *
7
- * Copyright 2013-2017 jquery-confirm
8
- * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE)
9
- */@-webkit-keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}body[class*=jconfirm-no-scroll-]{overflow:hidden!important}.jconfirm{position:fixed;top:0;left:0;right:0;bottom:0;z-index:99999999;font-family:inherit;overflow:hidden}.jconfirm .jconfirm-bg{position:fixed;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .4s;transition:opacity .4s}.jconfirm .jconfirm-bg.jconfirm-bg-h{opacity:0!important}.jconfirm .jconfirm-scrollpane{-webkit-perspective:500px;perspective:500px;-webkit-perspective-origin:center;perspective-origin:center;display:table;width:100%;height:100%}.jconfirm .jconfirm-row{display:table-row;width:100%}.jconfirm .jconfirm-cell{display:table-cell;vertical-align:middle}.jconfirm .jconfirm-holder{max-height:100%;padding:50px 0}.jconfirm .jconfirm-box-container{-webkit-transition:-webkit-transform;transition:-webkit-transform;transition:transform;transition:transform,-webkit-transform}.jconfirm .jconfirm-box-container.jconfirm-no-transition{-webkit-transition:none!important;transition:none!important}.jconfirm .jconfirm-box{background:white;border-radius:4px;position:relative;outline:0;padding:15px 15px 0;overflow:hidden;margin-left:auto;margin-right:auto}@-webkit-keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@-webkit-keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@-webkit-keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@-webkit-keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@-webkit-keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@-webkit-keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}@keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}.jconfirm .jconfirm-box.jconfirm-type-animated{-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.jconfirm .jconfirm-box.jconfirm-type-blue{border-top:solid 7px #3498db;-webkit-animation-name:type-blue;animation-name:type-blue}.jconfirm .jconfirm-box.jconfirm-type-green{border-top:solid 7px #2ecc71;-webkit-animation-name:type-green;animation-name:type-green}.jconfirm .jconfirm-box.jconfirm-type-red{border-top:solid 7px #e74c3c;-webkit-animation-name:type-red;animation-name:type-red}.jconfirm .jconfirm-box.jconfirm-type-orange{border-top:solid 7px #f1c40f;-webkit-animation-name:type-orange;animation-name:type-orange}.jconfirm .jconfirm-box.jconfirm-type-purple{border-top:solid 7px #9b59b6;-webkit-animation-name:type-purple;animation-name:type-purple}.jconfirm .jconfirm-box.jconfirm-type-dark{border-top:solid 7px #34495e;-webkit-animation-name:type-dark;animation-name:type-dark}.jconfirm .jconfirm-box.loading{height:120px}.jconfirm .jconfirm-box.loading:before{content:'';position:absolute;left:0;background:white;right:0;top:0;bottom:0;border-radius:10px;z-index:1}.jconfirm .jconfirm-box.loading:after{opacity:.6;content:'';height:30px;width:30px;border:solid 3px transparent;position:absolute;left:50%;margin-left:-15px;border-radius:50%;-webkit-animation:jconfirm-spin 1s infinite linear;animation:jconfirm-spin 1s infinite linear;border-bottom-color:dodgerblue;top:50%;margin-top:-15px;z-index:2}.jconfirm .jconfirm-box div.jconfirm-closeIcon{height:20px;width:20px;position:absolute;top:10px;right:10px;cursor:pointer;opacity:.6;text-align:center;font-size:27px!important;line-height:14px!important;display:none;z-index:1}.jconfirm .jconfirm-box div.jconfirm-closeIcon:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-closeIcon .fa{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon:hover{opacity:1}.jconfirm .jconfirm-box div.jconfirm-title-c{display:block;font-size:22px;line-height:20px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;padding-bottom:15px}.jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand{cursor:move}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{font-size:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i{vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:inherit;font-family:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-content-pane{margin-bottom:15px;height:auto;-webkit-transition:height .4s ease-in;transition:height .4s ease-in;display:inline-block;width:100%;position:relative;overflow-x:hidden;overflow-y:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane.no-scroll{overflow-y:hidden}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar{width:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-track{background:rgba(0,0,0,0.1)}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-thumb{background:#666;border-radius:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content{overflow:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img{max-width:100%;height:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty{display:none}.jconfirm .jconfirm-box .jconfirm-buttons{padding-bottom:11px}.jconfirm .jconfirm-box .jconfirm-buttons>button{margin-bottom:4px;margin-left:2px;margin-right:2px}.jconfirm .jconfirm-box .jconfirm-buttons button{display:inline-block;padding:6px 12px;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;min-height:1em;-webkit-transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;-webkit-tap-highlight-color:transparent;border:0;background-image:none}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue{background-color:#3498db;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover{background-color:#2980b9;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green{background-color:#2ecc71;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover{background-color:#27ae60;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red{background-color:#e74c3c;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover{background-color:#c0392b;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange{background-color:#f1c40f;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover{background-color:#f39c12;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default{background-color:#ecf0f1;color:#000;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover{background-color:#bdc3c7;color:#000}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple{background-color:#9b59b6;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover{background-color:#8e44ad;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark{background-color:#34495e;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover{background-color:#2c3e50;color:#FFF}.jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c{color:#e74c3c!important}.jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c{color:#3498db!important}.jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c{color:#2ecc71!important}.jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c{color:#9b59b6!important}.jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c{color:#f1c40f!important}.jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c{color:#34495e!important}.jconfirm .jconfirm-clear{clear:both}.jconfirm.jconfirm-rtl{direction:rtl}.jconfirm.jconfirm-rtl div.jconfirm-closeIcon{left:5px;right:auto}.jconfirm.jconfirm-white .jconfirm-bg,.jconfirm.jconfirm-light .jconfirm-bg{background-color:#444;opacity:.2}.jconfirm.jconfirm-white .jconfirm-box,.jconfirm.jconfirm-light .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);border-radius:5px}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#333}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#ddd}.jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-black .jconfirm-bg,.jconfirm.jconfirm-dark .jconfirm-bg{background-color:darkslategray;opacity:.4}.jconfirm.jconfirm-black .jconfirm-box,.jconfirm.jconfirm-dark .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);background:#444;border-radius:5px;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button{border:0;background-image:none;text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none;-webkit-transition:background .1s;transition:background .1s;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#fff;background:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#666}.jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake{-webkit-animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow{-webkit-animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@-webkit-keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}@keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}.jconfirm{-webkit-perspective:400px;perspective:400px}.jconfirm .jconfirm-box{opacity:1;-webkit-transition-property:all;transition-property:all}.jconfirm .jconfirm-box.jconfirm-animation-top,.jconfirm .jconfirm-box.jconfirm-animation-left,.jconfirm .jconfirm-box.jconfirm-animation-right,.jconfirm .jconfirm-box.jconfirm-animation-bottom,.jconfirm .jconfirm-box.jconfirm-animation-opacity,.jconfirm .jconfirm-box.jconfirm-animation-zoom,.jconfirm .jconfirm-box.jconfirm-animation-scale,.jconfirm .jconfirm-box.jconfirm-animation-none,.jconfirm .jconfirm-box.jconfirm-animation-rotate,.jconfirm .jconfirm-box.jconfirm-animation-rotatex,.jconfirm .jconfirm-box.jconfirm-animation-rotatey,.jconfirm .jconfirm-box.jconfirm-animation-scaley,.jconfirm .jconfirm-box.jconfirm-animation-scalex{opacity:0}.jconfirm .jconfirm-box.jconfirm-animation-rotate{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.jconfirm .jconfirm-box.jconfirm-animation-rotatex{-webkit-transform:rotateX(90deg);transform:rotateX(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatexr{-webkit-transform:rotateX(-90deg);transform:rotateX(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatey{-webkit-transform:rotatey(90deg);transform:rotatey(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotateyr{-webkit-transform:rotatey(-90deg);transform:rotatey(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scaley{-webkit-transform:scaley(1.5);transform:scaley(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scalex{-webkit-transform:scalex(1.5);transform:scalex(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-top{-webkit-transform:translate(0px,-100px);transform:translate(0px,-100px)}.jconfirm .jconfirm-box.jconfirm-animation-left{-webkit-transform:translate(-100px,0px);transform:translate(-100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-right{-webkit-transform:translate(100px,0px);transform:translate(100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-bottom{-webkit-transform:translate(0px,100px);transform:translate(0px,100px)}.jconfirm .jconfirm-box.jconfirm-animation-zoom{-webkit-transform:scale(1.2);transform:scale(1.2)}.jconfirm .jconfirm-box.jconfirm-animation-scale{-webkit-transform:scale(0.5);transform:scale(0.5)}.jconfirm .jconfirm-box.jconfirm-animation-none{visibility:hidden}.jconfirm.jconfirm-supervan .jconfirm-bg{background-color:rgba(54,70,93,0.95)}.jconfirm.jconfirm-supervan .jconfirm-box{background-color:transparent}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark{border:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon{color:white}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c{text-align:center;color:white;font-size:28px;font-weight:normal}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c>*{padding-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane{margin-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content{text-align:center;color:white}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button{font-size:16px;border-radius:2px;background:#303f53;text-shadow:none;border:0;color:white;padding:10px;min-width:100px}.jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-material .jconfirm-bg{background-color:rgba(0,0,0,0.67)}.jconfirm.jconfirm-material .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 25px 10px 25px}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons{text-align:right}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-weight:500}.jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-bootstrap .jconfirm-bg{background-color:rgba(0,0,0,0.21)}.jconfirm.jconfirm-bootstrap .jconfirm-box{background-color:white;-webkit-box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);border:solid 1px rgba(0,0,0,0.4);padding:15px 0 0}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold;padding-left:15px;padding-right:15px}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87);padding:0 15px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons{text-align:right;padding:10px;margin:-5px 0 0;border-top:solid 1px #ddd;overflow:hidden;border-radius:0 0 4px 4px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button{font-weight:500}.jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-modern .jconfirm-bg{background-color:slategray;opacity:.6}.jconfirm.jconfirm-modern .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 30px 15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87);top:15px;right:15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:24px;font-weight:bold;text-align:center;margin-bottom:10px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{-webkit-transition:-webkit-transform .5s;transition:-webkit-transform .5s;transition:transform .5s;transition:transform .5s,-webkit-transform .5s;-webkit-transform:scale(0);transform:scale(0);display:block;margin-right:0;margin-left:0;margin-bottom:10px;font-size:69px;color:#aaa}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content{text-align:center;font-size:15px;color:#777;margin-bottom:25px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button{font-weight:bold;text-transform:uppercase;-webkit-transition:background .1s;transition:background .1s;padding:10px 20px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button+button{margin-left:4px}.jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{-webkit-transform:scale(1);transform:scale(1)}
 
 
 
 
 
 
 
 
 
 
ui/media/css/main.css DELETED
@@ -1,1298 +0,0 @@
1
- * {
2
- font-family: Work Sans, Verdana, Geneva, sans-serif;
3
- box-sizing: border-box;
4
- }
5
-
6
- html {
7
- position: relative;
8
- }
9
-
10
- body {
11
- margin: 0;
12
- font-size: 11pt;
13
- background-color: var(--background-color1);
14
- color: var(--text-color);
15
- }
16
- a {
17
- color: rgb(0, 102, 204);
18
- }
19
- a:visited {
20
- color: rgb(0, 102, 204);
21
- }
22
- label {
23
- font-size: 10pt;
24
- }
25
- code {
26
- background: var(--background-color4);
27
- padding: 2px 4px;
28
- border-radius: 4px;
29
- }
30
- #logo_img {
31
- width: 32px;
32
- height: 32px;
33
- transform: translateY(4px);
34
- }
35
- #prompt {
36
- width: 100%;
37
- height: 65pt;
38
- font-size: 14px;
39
- margin-bottom: 6px;
40
- margin-top: 5px;
41
- display: block;
42
- border: 2px solid var(--background-color2);
43
- }
44
- #negative_prompt {
45
- width: 100%;
46
- height: 50pt;
47
- font-size: 13px;
48
- margin-bottom: 5px;
49
- margin-top: 5px;
50
- display: block;
51
- }
52
- .image_clear_btn {
53
- position: absolute;
54
- transform: translate(30%, -30%);
55
- background: black;
56
- color: white;
57
- border: 2pt solid #ccc;
58
- padding: 0;
59
- cursor: pointer;
60
- outline: inherit;
61
- border-radius: 8pt;
62
- width: 16pt;
63
- height: 16pt;
64
- font-family: Verdana;
65
- font-size: 8pt;
66
- top: 0px;
67
- right: 0px;
68
- }
69
- .image_clear_btn:active {
70
- position: absolute;
71
- top: 0px;
72
- left: auto;
73
- }
74
- .settings-box ul {
75
- font-size: 9pt;
76
- margin-bottom: 5px;
77
- padding-left: 10px;
78
- list-style-type: none;
79
- }
80
- .settings-box li {
81
- padding-bottom: 4pt;
82
- }
83
- .editor-slider {
84
- vertical-align: middle;
85
- }
86
- .outputMsg {
87
- font-size: small;
88
- padding-bottom: 3pt;
89
- }
90
- #footer {
91
- font-size: small;
92
- padding: 10pt;
93
- background: none;
94
- }
95
- #footer-legal {
96
- font-size: 8pt;
97
- }
98
- #footer-spacer {
99
- flex: 0.7
100
- }
101
- .imgInfoLabel {
102
- font-size: 0.8em;
103
- background-color: var(--background-color2);
104
- }
105
- .imgSeedLabel {
106
- padding: 5px;
107
- border-radius: 0px 3px 3px 0px;
108
- }
109
- .imgExpandBtn {
110
- border-radius: 3px 0px 0px 3px;
111
- border-right: 1px solid var(--tertiary-border-color);
112
- padding: 5px 5px 5px;
113
- padding-left: 7px;
114
- cursor: pointer;
115
- }
116
- .imgExpandBtn:hover {
117
- background-color: var(--accent-color);
118
- }
119
- .imgItem {
120
- display: inline-block;
121
- margin-top: 1em;
122
- margin-right: 1em;
123
- }
124
- .imgContainer {
125
- display: flex;
126
- justify-content: flex-end;
127
- position: relative;
128
- }
129
- .imgItemInfo {
130
- padding-bottom: 0.5em;
131
- display: flex;
132
- align-items: flex-end;
133
- flex-direction: column;
134
- position: absolute;
135
- padding-right: 5pt;
136
- padding-top: 6pt;
137
- opacity: 0;
138
- transition: 0.1s all;
139
- }
140
- .imgPreviewItemClearBtn {
141
- opacity: 0;
142
- }
143
- .imgContainer .img_bottom_label {
144
- opacity: 0;
145
- }
146
- .imgPreviewItemClearBtn:hover {
147
- background: rgb(177, 27, 0);
148
- }
149
- .imgContainer:hover > .imgItemInfo {
150
- opacity: 1;
151
- }
152
- .imgContainer:hover > .imgPreviewItemClearBtn {
153
- opacity: 1;
154
- }
155
- .imgContainer:hover > .img_bottom_label {
156
- opacity: 60%;
157
- }
158
- .imgItemInfo > * {
159
- margin-bottom: 7px;
160
- }
161
- .imgItemInfo .tasksBtns {
162
- margin-left: 5pt;
163
- }
164
- .imgItem .image_clear_btn {
165
- transform: translate(40%, -50%);
166
- }
167
- #container {
168
- min-height: 100vh;
169
- width: 100%;
170
- margin: 0px;
171
- display: flex;
172
- flex-direction: column;
173
- }
174
- #logo small {
175
- font-size: 11pt;
176
- }
177
- #editor {
178
- background: var(--background-color1);
179
- padding: 16px;
180
- display: flex;
181
- flex-direction: column;
182
- flex: 0 0 380pt;
183
- }
184
- #editor label {
185
- font-weight: normal;
186
- }
187
- #editor h4 {
188
- margin: 0px;
189
- white-space: nowrap;
190
- }
191
- #editor .collapsible-content {
192
- width: 100%;
193
- }
194
- .settings-box label small {
195
- color: rgb(153, 153, 153);
196
- margin-right: 10px;
197
- }
198
- #preview {
199
- padding: 8px;
200
- background: var(--background-color1);
201
- }
202
- #preview .collapsible-content {
203
- padding: 0px 15px;
204
- }
205
- #editor-inputs-prompt {
206
- flex: 1;
207
- }
208
- #editor-inputs .row {
209
- padding-bottom: 10px;
210
- }
211
- #makeImage {
212
- border-radius: 6px;
213
- }
214
- #editor-modifiers h5 {
215
- padding: 5pt 0;
216
- margin: 0;
217
- }
218
- #makeImage {
219
- flex: 0 0 70px;
220
- background: var(--accent-color);
221
- border: var(--primary-button-border);
222
- color: var(--accent-text-color);
223
- width: 100%;
224
- height: 30pt;
225
- }
226
- #makeImage:hover {
227
- background: hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) + 6%));
228
- }
229
- #stopImage {
230
- flex: 0 0 70px;
231
- background: rgb(132, 8, 0);
232
- border: 2px solid rgb(122, 29, 0);
233
- color: rgb(255, 221, 255);
234
- height: 30pt;
235
- border-radius: 6px;
236
- flex-grow: 2;
237
- }
238
- #stopImage:hover {
239
- background: rgb(177, 27, 0);
240
- }
241
-
242
- div#render-buttons {
243
- gap: 3px;
244
- margin-top: 4px;
245
- display: none;
246
- }
247
- button#pause {
248
- flex-grow: 1;
249
- background: var(--accent-color);
250
- }
251
- button#resume {
252
- flex-grow: 1;
253
- background: var(--accent-color);
254
- display: none;
255
- }
256
-
257
- .flex-container {
258
- display: flex;
259
- width: 100%;
260
- }
261
- .col-free {
262
- flex: 1;
263
- }
264
- .collapsible {
265
- cursor: pointer;
266
- }
267
- .collapsible-content {
268
- display: block;
269
- padding-left: 10px;
270
- }
271
- .collapsible-content h5 {
272
- padding: 5pt 0pt;
273
- margin: 0;
274
- font-size: 10pt;
275
- }
276
- .collapsible-handle {
277
- color: white;
278
- padding-right: 5px;
279
- }
280
- .collapsible:not(.active) ~ .collapsible-content {
281
- display: none !important;
282
- }
283
- #editor-modifiers {
284
- overflow-y: auto;
285
- overflow-x: hidden;
286
- }
287
- #editor-modifiers .editor-modifiers-leaf {
288
- padding-top: 10pt;
289
- padding-bottom: 10pt;
290
- }
291
- img {
292
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15);
293
- }
294
- div.img-preview img {
295
- width:100%;
296
- height: 100%;
297
- max-height: 70vh;
298
- cursor: pointer;
299
- }
300
- .line-separator {
301
- background: var(--background-color3);
302
- height: 1pt;
303
- margin: 16px 0px;
304
- }
305
- #editor-inputs-tags-container {
306
- margin-top: 5pt;
307
- display: none;
308
- }
309
- #server-status {
310
- position: absolute;
311
- right: 16px;
312
- top: 50%;
313
- transform: translateY(-50%);
314
- text-align: right;
315
- }
316
- #server-status-color {
317
- font-size: 14pt;
318
- color: rgb(200, 139, 0);
319
- display: inline;
320
- }
321
- #server-status-msg {
322
- color: rgb(200, 139, 0);
323
- padding-left: 2pt;
324
- font-size: 10pt;
325
- }
326
- .preview-prompt {
327
- font-size: 13pt;
328
- display: inline;
329
- }
330
- #coffeeButton {
331
- height: 23px;
332
- transform: translateY(25%);
333
- }
334
-
335
- #top-nav {
336
- position: relative;
337
- background: var(--background-color4);
338
- display: flex;
339
- }
340
- .tab .icon {
341
- padding-right: 4pt;
342
- font-size: 14pt;
343
- transform: translateY(1pt);
344
- }
345
- #logo {
346
- display: inline;
347
- padding: 12px;
348
- padding-top: 8px;
349
- white-space: nowrap;
350
- }
351
- #logo h1 {
352
- display: inline;
353
- }
354
- #top-nav-items {
355
- list-style-type: none;
356
- display: inline;
357
- float: right;
358
- }
359
- #top-nav-items > li {
360
- float: left;
361
- display: inline;
362
- padding-left: 20pt;
363
- }
364
- #top-nav-items > li:first-child {
365
- cursor: default;
366
- }
367
- #initial-text {
368
- padding-top: 15pt;
369
- padding-left: 4pt;
370
- }
371
- .settings-subheader {
372
- font-size: 10pt;
373
- font-weight: bold;
374
- }
375
- .pl-5 {
376
- padding-left: 5pt;
377
- }
378
- #community-links {
379
- display: inline-block;
380
- list-style-type: none;
381
- text-align: left;
382
- margin: auto;
383
- padding: 0px;
384
- }
385
- #community-links li {
386
- padding-bottom: 12pt;
387
- display: block;
388
- font-size: 10pt;
389
- }
390
- #community-links li .fa-fw {
391
- padding-right: 2pt;
392
- }
393
- #community-links li a {
394
- color: var(--text-color);
395
- text-decoration: none;
396
- }
397
- .float-child h1 {
398
- border-bottom: var(--button-border);
399
- }
400
- #help-links {
401
- display: inline-block;
402
- list-style-type: none;
403
- text-align: left;
404
- margin: auto;
405
- padding: 0px;
406
- }
407
- #help-links li {
408
- padding-bottom: 12pt;
409
- display: block;
410
- font-size: 10pt;
411
- }
412
- #help-links li .fa-fw {
413
- padding-right: 2pt;
414
- }
415
- #help-links li a {
416
- color: var(--text-color);
417
- text-decoration: none;
418
- }
419
- #help-links li ul {
420
- padding-inline-start: 10px;
421
- margin-top: 8px;
422
- }
423
- .help-section {
424
- font-size: 130%;
425
- }
426
- .dropdown {
427
- overflow: hidden;
428
- }
429
- .dropdown-content {
430
- display: none;
431
- position: absolute;
432
- z-index: 2;
433
- border-radius: 7px;
434
- padding: 0px;
435
- margin-bottom: 15px;
436
- box-shadow: 0 20px 28px 0 rgba(0, 0, 0, 0.75), 0 6px 20px 0 rgba(0, 0, 0, 0.75);
437
- }
438
- .dropdown:hover .dropdown-content {
439
- display: block;
440
- }
441
- .dropdown:hover + .dropdown-content {
442
- display: block;
443
- }
444
- .dropdown-content:hover {
445
- display: block;
446
- }
447
-
448
- .display-settings {
449
- float: right;
450
- position: relative;
451
- }
452
-
453
- .display-settings .dropdown-content {
454
- right: 0px;
455
- top: 12pt;
456
- }
457
-
458
- .dropdown-item {
459
- padding: 4px;
460
- background: var(--background-color1);
461
- border: 2px solid var(--background-color4);
462
- }
463
-
464
- .dropdown-item:first-child {
465
- border-radius: 7px 7px 0px 0px;
466
- }
467
-
468
- .dropdown-item:last-child {
469
- border-radius: 0px 0px 7px 7px;
470
- }
471
-
472
- .imageTaskContainer {
473
- border: 1px solid var(--background-color2);
474
- margin-bottom: 10pt;
475
- padding: 5pt;
476
- border-radius: 5pt;
477
- box-shadow: 0 20px 28px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15);
478
- }
479
- .imageTaskContainer > div > .collapsible-handle {
480
- display: none;
481
- }
482
- .dropTargetBefore::before{
483
- content: "";
484
- border: 1px solid #fff;
485
- margin-bottom: -2px;
486
- display: block;
487
- box-shadow: 0 0 5px #fff;
488
- transform: translate(0px, -14px);
489
- }
490
- .dropTargetAfter::after{
491
- content: "";
492
- border: 1px solid #fff;
493
- margin-bottom: -2px;
494
- display: block;
495
- box-shadow: 0 0 5px #fff;
496
- transform: translate(0px, 14px);
497
- }
498
- .drag-handle {
499
- margin-right: 6px;
500
- cursor: move;
501
- }
502
- .taskStatusLabel {
503
- font-size: 8pt;
504
- background:var(--background-color2);
505
- border: 1px solid rgb(61, 62, 66);
506
- padding: 2pt 4pt;
507
- border-radius: 2pt;
508
- margin-right: 5pt;
509
- display: inline;
510
- }
511
- .activeTaskLabel {
512
- background:rgb(0, 90, 30);
513
- border: 1px solid rgb(0, 75, 19);
514
- color:rgb(222, 253, 230)
515
- }
516
- .waitingTaskLabel {
517
- background:rgb(128, 89, 0);
518
- border: 1px solid rgb(107, 75, 0);
519
- color:rgb(255, 242, 211)
520
- }
521
- .primaryButton {
522
- flex: 0 0 70px;
523
- background: var(--accent-color);
524
- border: var(--primary-button-border);
525
- color: rgb(255, 221, 255);
526
- padding: 3pt 6pt;
527
- }
528
- .secondaryButton {
529
- background: rgb(132, 8, 0);
530
- border: 1px solid rgb(122, 29, 0);
531
- color: rgb(255, 221, 255);
532
- padding: 3pt 6pt;
533
- border-radius: 5px;
534
- }
535
- .secondaryButton:hover {
536
- background: rgb(177, 27, 0);
537
- }
538
- .tertiaryButton {
539
- background: var(--tertiary-background-color);
540
- color: var(--tertiary-color);
541
- border: 1px solid var(--tertiary-border-color);
542
- padding: 3pt 6pt;
543
- border-radius: 5px;
544
- }
545
- .tertiaryButton:hover {
546
- background: hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) + 6%));
547
- color: var(--accent-text-color);
548
- }
549
- .tertiaryButton.pressed {
550
- border-style: inset;
551
- background: hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) + 6%));
552
- color: var(--accent-text-color);
553
- }
554
- .useSettings {
555
- margin-right: 6pt;
556
- float: right;
557
- }
558
- .stopTask {
559
- float: right;
560
- }
561
- #preview-tools {
562
- display: none;
563
- padding: 4pt;
564
- }
565
- #preview-tools .display-settings .dropdown-content {
566
- right: -6px;
567
- top: 20px;
568
- box-shadow: none;
569
- width: max-content;
570
- }
571
- .taskConfig {
572
- font-size: 10pt;
573
- color: #aaa;
574
- margin-bottom: 5pt;
575
- margin-top: 5pt;
576
- }
577
- .img-batch {
578
- display: inline;
579
- }
580
- #prompt_from_file {
581
- display: none;
582
- }
583
-
584
- #init_image_preview_container {
585
- display: flex;
586
- margin-top: 6px;
587
- margin-bottom: 8px;
588
- }
589
-
590
- #init_image_preview_container:not(.has-image) #init_image_wrapper,
591
- #init_image_preview_container:not(.has-image) #inpaint_button_container {
592
- display: none;
593
- }
594
-
595
-
596
- #init_image_buttons {
597
- display: flex;
598
- gap: 8px;
599
- }
600
-
601
- #init_image_preview_container.has-image #init_image_buttons {
602
- flex-direction: column;
603
- padding-left: 8px;
604
- }
605
-
606
- #init_image_buttons .button {
607
- position: relative;
608
- height: 32px;
609
- width: 150px;
610
- }
611
-
612
- #init_image_buttons .button > input {
613
- position: absolute;
614
- left: 0;
615
- top: 0;
616
- right: 0;
617
- bottom: 0;
618
- opacity: 0;
619
- }
620
-
621
- #inpaint_button_container {
622
- display: flex;
623
- align-items: center;
624
- gap: 8px;
625
- }
626
-
627
- #init_image_wrapper {
628
- grid-row: span 3;
629
- position: relative;
630
- width: fit-content;
631
- max-height: 150px;
632
- }
633
-
634
- #init_image_preview {
635
- max-height: 150px;
636
- height: 100%;
637
- width: 100%;
638
- object-fit: contain;
639
- border-radius: 6px;
640
- transition: all 1s ease-in-out;
641
- }
642
- /*
643
- #init_image_preview:hover {
644
- max-width: 500px;
645
- max-height: 1000px;
646
-
647
- transition: all 1s 0.5s ease-in-out;
648
- } */
649
-
650
- #init_image_size_box {
651
- border-radius: 6px 0px;
652
- }
653
- .img_bottom_label {
654
- position: absolute;
655
- right: 0px;
656
- bottom: 0px;
657
- padding: 3px;
658
- background: black;
659
- color: white;
660
- text-shadow: 0px 0px 4px black;
661
- opacity: 60%;
662
- font-size: 12px;
663
- }
664
-
665
- #editor-settings {
666
- min-width: 350px;
667
- }
668
-
669
- #editor-settings-entries {
670
- display: flex;
671
- flex-direction: column;
672
- }
673
-
674
- #editor-settings-entries > div {
675
- margin-top: 15px;
676
- }
677
-
678
- #editor-settings-entries ul {
679
- padding: 0px;
680
- }
681
-
682
- #editor-settings-entries table td {
683
- padding: 0px;
684
- line-height: 28px;
685
- }
686
-
687
- #editor-settings-entries table td:first-child {
688
- float: right;
689
- padding-right: 4px;
690
- white-space: nowrap;
691
- }
692
-
693
- #negative_prompt {
694
- width: 100%;
695
- }
696
-
697
- /* INPUTS STYLING */
698
- button,
699
- input[type="file"],
700
- input[type="checkbox"],
701
- select,
702
- option {
703
- cursor: pointer;
704
- }
705
-
706
- input[type="file"] * {
707
- cursor: pointer;
708
- }
709
-
710
- input,
711
- select,
712
- textarea {
713
- border-radius: var(--input-border-radius);
714
- padding: 4px;
715
- accent-color: var(--accent-color);
716
- background: var(--input-background-color);
717
- border: var(--input-border-size) solid var(--input-border-color);
718
- color: var(--input-text-color);
719
- font-size: 9pt;
720
- }
721
-
722
- input:hover {
723
- accent-color: var(--accent-color-hover);
724
- }
725
-
726
- input {
727
- padding: 4px 6px;
728
- }
729
-
730
- input:focus,
731
- select:focus,
732
- textarea:focus {
733
- outline: 2px solid var(--accent-color);
734
- }
735
-
736
- input[disabled],
737
- select[disabled],
738
- textarea[disabled] {
739
- opacity: 0.5;
740
- }
741
-
742
- input[type="file"] {
743
- width: 100%;
744
- padding: 2px;
745
- }
746
-
747
- button,
748
- input::file-selector-button,
749
- .button {
750
- padding: 2px 4px;
751
- border-radius: var(--input-border-radius);
752
- background: var(--button-color);
753
- color: var(--button-text-color);
754
- border: var(--button-border);
755
- align-items: center;
756
- justify-content: center;
757
- cursor: pointer;
758
- }
759
-
760
- .button i {
761
- margin-right: 8px;
762
- }
763
-
764
- button:hover,
765
- .button:hover {
766
- transition-duration: 0.1s;
767
- background: hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) + 6%));
768
- }
769
-
770
- input::file-selector-button {
771
- padding: 0px 4px;
772
- height: 19px;
773
- }
774
-
775
-
776
- .input-toggle {
777
- display: inline-block;
778
- position: relative;
779
- vertical-align: middle;
780
- width: calc(var(--input-height) * 2);
781
- user-select: none;
782
- -webkit-user-select: none;
783
- -moz-user-select: none;
784
- -ms-user-select: none;
785
- margin-right: 4px;
786
- }
787
- .input-toggle > input {
788
- position: absolute;
789
- opacity: 0;
790
- pointer-events: none;
791
- }
792
- .input-toggle > label {
793
- display: block;
794
- overflow: hidden;
795
- cursor: pointer;
796
- height: var(--input-height);
797
- padding: 0;
798
- line-height: var(--input-height);
799
- border: var(--input-border-size) solid var(--input-border-color);
800
- border-radius: var(--input-height);
801
- background: var(--input-background-color);
802
- transition: background 0.2s ease-in;
803
- }
804
- .input-toggle > label:before {
805
- content: "";
806
- display: block;
807
- width: calc(var(--input-height) - ((var(--input-border-size) + var(--input-switch-padding)) * 2));
808
- margin: 0px;
809
- background: var(--input-text-color);
810
- position: absolute;
811
- top: calc(var(--input-border-size) + var(--input-switch-padding));
812
- bottom: calc(var(--input-border-size) + var(--input-switch-padding));
813
- right: calc(var(--input-border-size) + var(--input-switch-padding) + var(--input-height));
814
- border-radius: calc(var(--input-height) - ((var(--input-border-size) + var(--input-switch-padding)) * 2));
815
- transition: all 0.2s ease-in 0s;
816
- opacity: 0.8;
817
- }
818
- .input-toggle > input:checked + label {
819
- background: var(--accent-color);
820
- }
821
- .input-toggle > input:checked + label:before {
822
- right: calc(var(--input-border-size) + var(--input-switch-padding));
823
- opacity: 1;
824
- }
825
- .model-filter {
826
- width: 90%;
827
- padding-right: 20px;
828
- white-space: nowrap;
829
- overflow: hidden;
830
- text-overflow: ellipsis;
831
- }
832
-
833
- /* Small screens */
834
- @media screen and (max-width: 1365px) {
835
- #top-nav {
836
- flex-direction: column;
837
- }
838
- }
839
-
840
- /* MOBILE SUPPORT */
841
- @media screen and (max-width: 700px) {
842
- body {
843
- margin: 0px;
844
- }
845
- #container {
846
- margin: 0px;
847
- }
848
- .flex-container {
849
- flex-direction: column;
850
- }
851
- #preview {
852
- margin: 0px;
853
- padding: 0px;
854
- }
855
- #preview .collapsible-content {
856
- padding: 0px;
857
- }
858
- #preview .collapsible-content {
859
- padding: 0px;
860
- }
861
- .imgItem {
862
- margin-right: 0px;
863
- }
864
- .imgItem img {
865
- height: 100%;
866
- width: 100%;
867
- object-fit: contain;
868
- }
869
- #editor {
870
- padding: 16px 8px;
871
- }
872
- #editor-settings {
873
- min-width: 0px;
874
- }
875
- .tab-content-inner {
876
- margin: 0px;
877
- }
878
- .tab {
879
- font-size: 0;
880
- }
881
- .tab .icon {
882
- padding-right: 0px;
883
- }
884
- #server-status {
885
- top: 75%;
886
- }
887
- .popup > div {
888
- padding-left: 5px !important;
889
- padding-right: 5px !important;
890
- }
891
- .popup > div input, .popup > div select {
892
- max-width: 40vw;
893
- }
894
- .popup .close-button {
895
- padding: 0px !important;
896
- margin: 24px !important;
897
- }
898
- .simple-tooltip {
899
- display: none;
900
- }
901
- #preview-tools button {
902
- font-size: 0px;
903
- }
904
- #preview-tools button .icon {
905
- font-size: 12pt;
906
- }
907
- }
908
-
909
- @media screen and (max-width: 500px) {
910
- #server-status #server-status-msg {
911
- display: none;
912
- }
913
- #server-status:hover #server-status-msg {
914
- display: inline;
915
- }
916
- }
917
-
918
- @media (min-width: 700px) {
919
- /* #editor {
920
- max-width: 480px;
921
- }*/
922
- .float-container {
923
- padding: 20px;
924
- }
925
- .float-child {
926
- width: 50%;
927
- float: left;
928
- padding: 20px;
929
- }
930
- }
931
-
932
- .help-btn {
933
- position: relative;
934
- }
935
-
936
- #promptsFromFileBtn {
937
- font-size: 9pt;
938
- display: inline;
939
- padding: 2pt;
940
- }
941
-
942
- .section-button {
943
- position: relative;
944
- transform: translateY(-13%);
945
- }
946
- .collapsible:not(.active) #copy-image-settings {
947
- display: none;
948
- }
949
-
950
- .section-button {
951
- cursor: pointer;
952
- float: right;
953
- padding: 8px;
954
- opacity: 1;
955
- transition: opacity 0.5;
956
- }
957
-
958
- .section-button {
959
- cursor: pointer;
960
- float: right;
961
- padding: 8px;
962
- opacity: 1;
963
- transition: opacity 0.5;
964
- }
965
-
966
- .collapsible:not(.active) .section-button {
967
- display: none;
968
- }
969
-
970
- /* SIMPLE TOOTIP */
971
- .simple-tooltip {
972
- border-radius: 3px;
973
- font-weight: bold;
974
- font-size: 12px;
975
- background-color: var(--background-color3);
976
-
977
- visibility: hidden;
978
- opacity: 0;
979
- position: absolute;
980
- width: max-content;
981
- max-width: 300px;
982
- padding: 8px 12px;
983
- transition: 0.3s all;
984
- z-index: 1000;
985
-
986
- pointer-events: none;
987
- }
988
-
989
- @media (hover: hover) {
990
- :hover > .simple-tooltip {
991
- opacity: 1;
992
- visibility: visible;
993
- }
994
- }
995
- .simple-tooltip.right {
996
- right: 0px;
997
- top: 50%;
998
- transform: translate(100%, -50%);
999
- }
1000
- :hover > .simple-tooltip.right {
1001
- transform: translate(100%, -50%);
1002
- }
1003
-
1004
- .simple-tooltip.top {
1005
- top: 0px;
1006
- left: 50%;
1007
- transform: translate(-50%, calc(-100% + 15%));
1008
- }
1009
- :hover > .simple-tooltip.top {
1010
- transform: translate(-50%, -100%);
1011
- }
1012
-
1013
- .simple-tooltip.left {
1014
- left: 0px;
1015
- top: 50%;
1016
- transform: translate(calc(-100% + 15%), -50%);
1017
- }
1018
- :hover > .simple-tooltip.left {
1019
- transform: translate(-100%, -50%);
1020
- }
1021
-
1022
- .simple-tooltip.bottom {
1023
- bottom: 0px;
1024
- left: 50%;
1025
- transform: translate(-50%, calc(100% - 15%));
1026
- }
1027
- :hover > .simple-tooltip.bottom {
1028
- transform: translate(-50%, 100%);
1029
- }
1030
-
1031
- .simple-tooltip.top-left {
1032
- top: 0px;
1033
- left: 0px;
1034
- transform: translate(calc(-100% + 15%), calc(-100% + 15%));
1035
- }
1036
- :hover > .simple-tooltip.top-left {
1037
- transform: translate(-80%, -100%);
1038
- }
1039
-
1040
- /* PROGRESS BAR */
1041
- .progress-bar {
1042
- background: var(--background-color3);
1043
- border-radius: 4px;
1044
- border: 2px solid var(--background-color3);
1045
- height: 16px;
1046
- position: relative;
1047
- transition: 0.25s 1s border, 0.25s 1s height;
1048
- clear: both;
1049
- }
1050
- .progress-bar > div {
1051
- background: var(--accent-color);
1052
- border-radius: 4px;
1053
- position: absolute;
1054
- left: 0;
1055
- top: 0;
1056
- bottom: 0;
1057
- width: 0%;
1058
- transition: width 1s ease-in-out;
1059
- }
1060
- .progress-bar.active {
1061
- background: repeating-linear-gradient(-65deg,
1062
- var(--background-color2),
1063
- var(--background-color2) 4px,
1064
- var(--background-color3) 5px,
1065
- var(--background-color3) 9px,
1066
- var(--background-color2) 10px);
1067
- background-size: 200% auto;
1068
- background-position: 0 100%;
1069
- animation: progress-anim 2s infinite;
1070
- animation-fill-mode: forwards;
1071
- animation-timing-function: linear;
1072
- }
1073
-
1074
- @keyframes progress-anim {
1075
- 0% { background-position: -55px 0; }
1076
- 100% { background-position: 0 0; }
1077
- }
1078
-
1079
- /* POPUPS */
1080
- .popup:not(.active) {
1081
- visibility: hidden;
1082
- opacity: 0;
1083
- }
1084
-
1085
- .popup {
1086
- position: absolute;
1087
- background: rgba(32, 33, 36, 50%);
1088
- top: 0px;
1089
- left: 0px;
1090
- right: 0px;
1091
- bottom: 0px;
1092
- z-index: 1000;
1093
- opacity: 1;
1094
- transition: 0s visibility, 0.3s opacity;
1095
- }
1096
-
1097
- @media only screen and (min-height: 1050px) {
1098
- .popup {
1099
- position: fixed;
1100
- }
1101
- }
1102
-
1103
- .popup > div {
1104
- position: relative;
1105
- background: var(--background-color2);
1106
- border: solid 1px var(--background-color3);
1107
- max-width: 700px;
1108
- margin: auto;
1109
- margin-top: 50px;
1110
- border-radius: 6px;
1111
- padding: 30px;
1112
- text-align: center;
1113
- box-shadow: 0px 0px 30px black;
1114
- }
1115
-
1116
- .popup .close-button {
1117
- position: absolute;
1118
- right: 0px;
1119
- top: 0px;
1120
- transform: scale(150%);
1121
- cursor: pointer;
1122
- padding: 24px;
1123
- }
1124
-
1125
- /* TABS */
1126
- .tab-container {
1127
- display: flex;
1128
- align-items: flex-end;
1129
- }
1130
-
1131
- .tab {
1132
- padding: 8px 16px;
1133
- border-radius: 4px 4px 0px 0px;
1134
- margin-left: 8px;
1135
- cursor: pointer;
1136
- background: var(--background-color1);
1137
- opacity: 50%;
1138
- transition: opacity 0.25s;
1139
- }
1140
-
1141
- .tab:hover {
1142
- opacity: 75%;
1143
- }
1144
-
1145
- .tab.active {
1146
- opacity: 100%;
1147
- }
1148
-
1149
- .tab-content:not(.active) {
1150
- display: none;
1151
- }
1152
-
1153
- #tab-content-wrapper > * {
1154
- padding-top: 8px;
1155
- }
1156
-
1157
- .tab-content-inner {
1158
- margin: auto;
1159
- max-width: 600px;
1160
- text-align: center;
1161
- padding: 20px 10px;
1162
- }
1163
-
1164
- .panel-box {
1165
- background: var(--background-color2);
1166
- border: 1px solid var(--background-color3);
1167
- border-radius: 7px;
1168
- padding: 7px;
1169
- margin-bottom: 15px;
1170
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15);
1171
- }
1172
-
1173
- i.active {
1174
- background: var(--accent-color);
1175
- }
1176
- .primaryButton.active {
1177
- background: hsl(var(--accent-hue), 100%, 50%);
1178
- }
1179
- #system-info {
1180
- max-width: 800px;
1181
- font-size: 10pt;
1182
- }
1183
- #system-info .value {
1184
- text-align: left;
1185
- padding-left: 10pt;
1186
- }
1187
- #system-info label {
1188
- float: right;
1189
- font-weight: bold;
1190
- }
1191
-
1192
- button:active {
1193
- transition-duration: 0.1s;
1194
- background-color: hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) + 24%));
1195
- position: relative;
1196
- top: 1px;
1197
- left: 1px;
1198
- }
1199
-
1200
- div.task-initimg > img {
1201
- margin-right: 6px;
1202
- display: block;
1203
- }
1204
- div.task-fs-initimage {
1205
- display: none;
1206
- position: absolute;
1207
- }
1208
- div.task-initimg:hover div.task-fs-initimage {
1209
- display: block;
1210
- position: absolute;
1211
- z-index: 9999;
1212
- box-shadow: 0 0 30px #000;
1213
- margin-top:-64px;
1214
- max-width: 75vw;
1215
- max-height: 75vh;
1216
- }
1217
- div.top-right {
1218
- position: absolute;
1219
- top: 8px;
1220
- right: 8px;
1221
- }
1222
-
1223
- #small_image_warning {
1224
- font-size: smaller;
1225
- color: var(--status-orange);
1226
- }
1227
-
1228
- button#save-system-settings-btn {
1229
- padding: 4pt 8pt;
1230
- }
1231
- #ip-info a {
1232
- color:var(--text-color)
1233
- }
1234
- #ip-info div {
1235
- line-height: 200%;
1236
- }
1237
-
1238
- #download-images-popup .parameters-table > div {
1239
- background: var(--background-color1);
1240
- }
1241
-
1242
- /* SCROLLBARS */
1243
- :root {
1244
- --scrollbar-width: 14px;
1245
- --scrollbar-radius: 10px;
1246
- }
1247
-
1248
- .scrollbar-editor::-webkit-scrollbar {
1249
- width: 8px;
1250
- }
1251
-
1252
- .scrollbar-editor::-webkit-scrollbar-track {
1253
- border-radius: 10px;
1254
- }
1255
-
1256
- .scrollbar-editor::-webkit-scrollbar-thumb {
1257
- background: --background-color2;
1258
- border-radius: 10px;
1259
- }
1260
-
1261
- ::-webkit-scrollbar {
1262
- width: var(--scrollbar-width);
1263
- }
1264
-
1265
- ::-webkit-scrollbar-track {
1266
- box-shadow: inset 0 0 5px var(--input-border-color);
1267
- border-radius: var(--input-border-radius);
1268
- }
1269
-
1270
- ::-webkit-scrollbar-thumb {
1271
- background: var(--background-color2);
1272
- border-radius: var(--scrollbar-radius);
1273
- }
1274
-
1275
- body.pause {
1276
- border: solid 12px var(--accent-color);
1277
- }
1278
-
1279
- body.wait-pause {
1280
- animation: blinker 2s linear infinite;
1281
- }
1282
-
1283
- @keyframes blinker {
1284
- 0% { border: solid 12px var(--accent-color); }
1285
- 50% { border: solid 12px var(--background-color1); }
1286
- 100% { border: solid 12px var(--accent-color); }
1287
- }
1288
-
1289
- .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c {
1290
- color: var(--button-text-color);
1291
- }
1292
- .jconfirm.jconfirm-modern .jconfirm-box {
1293
- background-color: var(--background-color1);
1294
- }
1295
-
1296
- .displayNone {
1297
- display:none !important;
1298
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/modifier-thumbnails.css DELETED
@@ -1,223 +0,0 @@
1
- .modifier-card {
2
- box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
3
- transition: 0.1s;
4
- border-radius: 7px;
5
- margin: 3pt 3pt;
6
- float: left;
7
- width: 8em;
8
- height: 11.5em;
9
- display: grid;
10
- grid-template-columns: 1fr;
11
- grid-template-rows: 8em 3.5em;
12
- gap: 0px 0px;
13
- grid-auto-flow: row;
14
- grid-template-areas:
15
- "modifier-card-image-container"
16
- "modifier-card-container";
17
- border: 2px solid rgba(255, 255, 255, .05);
18
- cursor: pointer;
19
- }
20
- .modifier-card-size_5 {
21
- width: 18em;
22
- grid-template-rows: 18em 3.5em;
23
- height: 21.5em;
24
- }
25
- .modifier-card-size_5 .modifier-card-image-overlay {
26
- font-size: 8em;
27
- }
28
- .modifier-card-size_4 {
29
- width: 14em;
30
- grid-template-rows: 14em 3.5em;
31
- height: 17.5em;
32
- }
33
- .modifier-card-size_4 .modifier-card-image-overlay {
34
- font-size: 7em;
35
- }
36
- .modifier-card-size_3 {
37
- width: 11em;
38
- grid-template-rows: 11em 3.5em;
39
- height: 14.5em;
40
- }
41
- .modifier-card-size_3 .modifier-card-image-overlay {
42
- font-size: 6em;
43
- }
44
- .modifier-card-size_2 {
45
- width: 10em;
46
- grid-template-rows: 10em 3.5em;
47
- height: 13.5em;
48
- }
49
- .modifier-card-size_2 .modifier-card-image-overlay {
50
- font-size: 6em;
51
- }
52
- .modifier-card-size_1 {
53
- width: 9em;
54
- grid-template-rows: 9em 3.5em;
55
- height: 12.5em;
56
- }
57
- .modifier-card-size_1 .modifier-card-image-overlay {
58
- font-size: 5em;
59
- }
60
- .modifier-card-size_-1 {
61
- width: 7em;
62
- grid-template-rows: 7em 3.5em;
63
- height: 10.5em;
64
- }
65
- .modifier-card-size_-1 .modifier-card-image-overlay {
66
- font-size: 4em;
67
- }
68
- .modifier-card-size_-2 {
69
- width: 6em;
70
- grid-template-rows: 6em 3.5em;
71
- height: 9.5em;
72
- }
73
- .modifier-card-size_-2 .modifier-card-image-overlay {
74
- font-size: 3em;
75
- }
76
- .modifier-card-size_-3 {
77
- width: 5em;
78
- grid-template-rows: 5em 3.5em;
79
- height: 8.5em;
80
- }
81
- .modifier-card-size_-3 .modifier-card-image-overlay {
82
- font-size: 3em;
83
- }
84
- .modifier-card-size_-3 .modifier-card-label {
85
- font-size: 0.8em;
86
- }
87
- .modifier-card-tiny {
88
- width: 6em;
89
- height: 9.5em;
90
- grid-template-rows: 6em 3.5em;
91
- }
92
- .modifier-card-tiny .modifier-card-image-overlay {
93
- font-size: 4em;
94
- }
95
- .modifier-card:hover {
96
- transform: scale(1.05);
97
- box-shadow: 0 5px 16px 5px rgba(0, 0, 0, 0.25);
98
- }
99
- .modifier-card-image-container {
100
- border-radius: 5px 5px 0 0;
101
- width: inherit;
102
- height: 100%;
103
- background-color: rgba(0, 0, 0, .2);
104
- grid-area: modifier-card-image-container;
105
- position: relative;
106
- display: flex;
107
- align-items: center;
108
- justify-content: center;
109
- color: rgb(255 255 255 / 8%);
110
- }
111
- .modifier-card-image-container img {
112
- width: inherit;
113
- height: 100%;
114
- border-radius: 5px 5px 0 0;
115
- }
116
- .modifier-card-image-container * {
117
- position: absolute;
118
- }
119
- .modifier-card-container {
120
- text-align: center;
121
- background-color: rgba(0,0,0,0.5);
122
- border-radius: 0 0 5px 5px;
123
- display: flex;
124
- justify-content: center;
125
- align-items: center;
126
- grid-area: modifier-card-container;
127
- font-weight: 100;
128
- font-size: .9em;
129
- width: inherit;
130
- }
131
- .modifier-card-label {
132
- padding: 4px;
133
- word-break: break-word;
134
- }
135
- .modifier-card-image-overlay {
136
- width: inherit;
137
- height: inherit;
138
- background-color: rgb(0 0 0 / 50%);
139
- z-index: 2;
140
- position: absolute;
141
- border-radius: 5px 5px 0 0;
142
- opacity: 0;
143
- font-size: 5em;
144
- font-weight: 900;
145
- color: rgb(255 255 255 / 50%);
146
- display: flex;
147
- align-items: center;
148
- justify-content: center;
149
- }
150
- .modifier-card-overlay {
151
- width: inherit;
152
- height: inherit;
153
- position: absolute;
154
- z-index: 3;
155
- }
156
- .modifier-card:hover > .modifier-card-image-container .modifier-card-image-overlay {
157
- opacity: 1;
158
- }
159
- .modifier-card:hover > .modifier-card-image-container img {
160
- filter: blur(.1em);
161
- }
162
- .modifier-card:active {
163
- transform: scale(0.95);
164
- box-shadow: 0 5px 16px 5px rgba(0, 0, 0, 0.5);
165
- }
166
- #preview-image {
167
- margin-top: 0.5em;
168
- margin-bottom: 0.5em;
169
- }
170
- .modifier-card-active {
171
- border: 2px solid rgb(179 82 255 / 94%);
172
- box-shadow: 0 0px 10px 0 rgb(170 0 229 / 58%);
173
- }
174
- .tooltip {
175
- position: relative;
176
- display: inline-block;
177
- }
178
- .tooltip .tooltip-text {
179
- visibility: hidden;
180
- width: 120px;
181
- background: rgb(101,97,181);
182
- background: linear-gradient(180deg, rgba(101,97,181,1) 0%, rgba(47,45,85,1) 100%);
183
- color: #fff;
184
- text-align: center;
185
- border-radius: 6px;
186
- padding: 5px;
187
- position: absolute;
188
- z-index: 1;
189
- top: 105%;
190
- left: 39%;
191
- margin-left: -60px;
192
- opacity: 0;
193
- transition: opacity 0.3s;
194
- border: 2px solid rgb(90 100 177 / 94%);
195
- box-shadow: 0px 10px 20px 5px rgb(11 0 58 / 55%);
196
- width: 10em;
197
- }
198
- .tooltip .tooltip-text::after {
199
- content: "";
200
- position: absolute;
201
- top: -0.9em;
202
- left: 50%;
203
- margin-left: -5px;
204
- border-width: 5px;
205
- border-style: solid;
206
- border-color: transparent transparent rgb(90 100 177 / 94%) transparent;
207
- }
208
- .tooltip:hover .tooltip-text {
209
- visibility: visible;
210
- opacity: 1;
211
- }
212
- #modifier-card-size-slider {
213
- width: 6em;
214
- margin-bottom: 0.5em;
215
- vertical-align: middle;
216
- }
217
- #modifier-settings-btn {
218
- float: right;
219
- }
220
- #modifier-settings-config textarea {
221
- width: 90%;
222
- height: 150px;
223
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/searchable-models.css DELETED
@@ -1,99 +0,0 @@
1
- .model-list {
2
- position: absolute;
3
- margin-block-start: 2px;
4
- display: none;
5
- padding-inline-start: 0;
6
- max-height: 200px;
7
- overflow: auto;
8
- background: var(--input-background-color);
9
- border: var(--input-border-size) solid var(--input-border-color);
10
- border-radius: var(--input-border-radius);
11
- color: var(--input-text-color);
12
- z-index: 1;
13
- line-height: normal;
14
- }
15
-
16
- .model-list ul {
17
- padding-right: 20px;
18
- padding-inline-start: 0;
19
- margin-top: 3pt;
20
- }
21
-
22
- .model-list li {
23
- padding-top: 3px;
24
- padding-bottom: 3px;
25
- }
26
-
27
- .model-list .icon {
28
- padding-right: 3pt;
29
- }
30
-
31
- .model-result {
32
- list-style: none;
33
- }
34
-
35
- .model-no-result {
36
- color: var(--text-color);
37
- list-style: none;
38
- padding: 3px 6px 3px 6px;
39
- font-size: 9pt;
40
- font-style: italic;
41
- display: none;
42
- }
43
-
44
- .model-list li.model-folder {
45
- color: var(--text-color);
46
- list-style: none;
47
- padding: 6px 6px 6px 6px;
48
- font-size: 9pt;
49
- font-weight: bold;
50
- border-top: 1px solid var(--background-color1);
51
- }
52
-
53
- .model-list li.model-file {
54
- color: var(--input-text-color);
55
- list-style: none;
56
- padding-left: 12px;
57
- padding-right:20px;
58
- font-size: 10pt;
59
- font-weight: normal;
60
- transition: none;
61
- transition:property: none;
62
- cursor: default;
63
- }
64
-
65
- .model-list li.model-file.in-root-folder {
66
- padding-left: 6px;
67
- }
68
-
69
- .model-list li.model-file.selected {
70
- background: grey;
71
- }
72
-
73
- .model-selector {
74
- cursor: pointer;
75
- }
76
-
77
- .model-selector-arrow {
78
- position: absolute;
79
- width: 17px;
80
- margin: 5px -17px;
81
- padding-top: 3px;
82
- cursor: pointer;
83
- font-size: 8pt;
84
- transition: none;
85
- }
86
-
87
- .model-input {
88
- white-space: nowrap;
89
- }
90
-
91
- .reloadModels {
92
- background: var(--background-color2);
93
- border: none;
94
- padding: 0px 0px;
95
- }
96
-
97
- #reload-models.secondaryButton:hover {
98
- background: var(--background-color2);
99
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/css/themes.css DELETED
@@ -1,186 +0,0 @@
1
- :root {
2
- --main-hue: 222;
3
- --main-saturation: 4%;
4
- --value-base: 13%;
5
- --value-step: 5%;
6
- --background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
7
- --background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1 * var(--value-step))));
8
- --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (0.5 * var(--value-step))));
9
- --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1.5 * var(--value-step))));
10
-
11
- --accent-hue: 267;
12
- --accent-lightness: 36%;
13
- --accent-lightness-hover: 40%;
14
-
15
- --text-color: #eee;
16
-
17
- --input-text-color: #eee;
18
- --input-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (0.7 * var(--value-step))));
19
- --input-border-color: var(--background-color4);
20
-
21
- --button-text-color: var(--input-text-color);
22
- --button-color: var(--input-background-color);
23
- --button-border: none;
24
-
25
- /* other */
26
- --input-border-radius: 4px;
27
- --input-border-size: 1px;
28
- --accent-color: hsl(var(--accent-hue), 100%, var(--accent-lightness));
29
- --accent-color-hover: hsl(var(--accent-hue), 100%, var(--accent-lightness-hover));
30
- --accent-text-color: rgb(255, 221, 255);
31
- --primary-button-border: none;
32
- --input-switch-padding: 1px;
33
- --input-height: 18px;
34
- --tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step))));
35
- --tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3 * var(--value-step))));
36
- --tertiary-color: var(--input-text-color)
37
-
38
- /* Main theme color, hex color fallback. */
39
- --theme-color-fallback: #673AB6;
40
- --status-orange: rgb(200, 139, 0);
41
- --status-green: green;
42
- --status-red: red;
43
- }
44
-
45
- .theme-light {
46
- --background-color1: white;
47
- --background-color2: #ececec;
48
- --background-color3: #e7e9eb;
49
- --background-color4: #cccccc;
50
-
51
- --text-color: black;
52
-
53
- --input-text-color: black;
54
- --input-background-color: #f8f9fa;
55
- --input-border-color: grey;
56
-
57
- --theme-color-fallback: #aaaaaa;
58
-
59
- --tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (16.8 * var(--value-step))));
60
- --tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (12 * var(--value-step))));
61
-
62
- --accent-text-color: white;
63
- }
64
-
65
- .theme-discord {
66
- --background-color1: #36393f;
67
- --background-color2: #2f3136;
68
- --background-color3: #292b2f;
69
- --background-color4: #202225;
70
-
71
- --accent-hue: 235;
72
- --accent-lightness: 65%;
73
-
74
- --input-border-size: 2px;
75
- --input-background-color: #202225;
76
- --input-border-color: var(--input-background-color);
77
-
78
- --theme-color-fallback: #202225;
79
-
80
- --tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
81
- --tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
82
- --accent-text-color: white;
83
- }
84
-
85
- .theme-cool-blue {
86
- --main-hue: 222;
87
- --main-saturation: 18%;
88
- --value-base: 18%;
89
- --value-step: 3%;
90
- --background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
91
- --background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
92
- --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
93
- --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
94
-
95
- --input-background-color: var(--background-color3);
96
-
97
- --accent-hue: 212;
98
-
99
- --theme-color-fallback: #0056b8;
100
-
101
- --tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
102
- --tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
103
- --accent-text-color: #f7fbff;
104
- }
105
-
106
-
107
- .theme-blurple {
108
- --main-hue: 235;
109
- --main-saturation: 18%;
110
- --value-base: 16%;
111
- --value-step: 3%;
112
- --background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
113
- --background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
114
- --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
115
- --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
116
-
117
- --input-background-color: var(--background-color3);
118
-
119
- --theme-color-fallback: #5300b8;
120
-
121
- --tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
122
- --tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
123
- }
124
-
125
- .theme-super-dark {
126
- --main-hue: 222;
127
- --main-saturation: 18%;
128
- --value-base: 5%;
129
- --value-step: 5%;
130
- --background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
131
- --background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1 * var(--value-step))));
132
- --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step))));
133
- --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1.4 * var(--value-step))));
134
-
135
- --input-background-color: var(--background-color3);
136
- --input-border-size: 0px;
137
-
138
- --theme-color-fallback: #000000;
139
- }
140
-
141
- .theme-wild {
142
- --main-hue: 128;
143
- --main-saturation: 18%;
144
- --value-base: 20%;
145
- --value-step: 5%;
146
- --background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
147
- --background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
148
- --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
149
- --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
150
-
151
- --accent-hue: 212;
152
-
153
- --input-border-size: 1px;
154
- --input-background-color: hsl(222, var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
155
- --input-text-color: #FF0000;
156
- --input-border-color: #005E05;
157
-
158
- --tertiary-color: white;
159
- --accent-text-color: #f7fbff;
160
- }
161
-
162
-
163
- .theme-gnomie {
164
- --background-color1: #242424;
165
- --background-color2: #353535;
166
- --background-color3: #494949;
167
- --background-color4: #000000;
168
-
169
- --accent-hue: 213;
170
- --accent-lightness: 55%;
171
- --accent-color: #2168bf;
172
-
173
- --input-border-radius: 6px;
174
- --input-text-color: #ffffff;
175
- --input-background-color: #2a2a2a;
176
- --input-border-size: 0px;
177
- --input-border-color: var(--input-background-color);
178
-
179
- --theme-color-fallback: #2168bf;
180
- }
181
-
182
- .theme-gnomie .panel-box {
183
- border: none;
184
- box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.25);
185
- border-radius: 10px;
186
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ui/media/ding.mp3 DELETED
Binary file (178 kB)
 
ui/media/fonts/fa-brands-400.ttf DELETED
Binary file (186 kB)
 
ui/media/fonts/fa-brands-400.woff2 DELETED
Binary file (107 kB)
 
ui/media/fonts/fa-regular-400.ttf DELETED
Binary file (62 kB)
 
ui/media/fonts/fa-regular-400.woff2 DELETED
Binary file (25.1 kB)
 
ui/media/fonts/fa-solid-900.ttf DELETED
Binary file (398 kB)
 
ui/media/fonts/fa-solid-900.woff2 DELETED
Binary file (150 kB)
 
ui/media/fonts/fa-v4compatibility.ttf DELETED
Binary file (10.1 kB)
 
ui/media/fonts/fa-v4compatibility.woff2 DELETED
Binary file (4.58 kB)
 
ui/media/fonts/work-sans-v18-latin-600.woff DELETED
Binary file (23.5 kB)