Compare commits

...

1798 Commits

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

* Add dash support

* Avoid needing to upgrade fastapi

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

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

Known issues:

* Some samplers (eg DDIM) will fail on MPS unless forced to CPU-only mode
2023-03-07 14:57:37 -07:00
8acff43028 Merge pull request #973 from cmdr2/main
Main
2023-03-07 22:06:06 +05:30
660aa4f4ab Don't include bootstrap.bat in the new installer, since we don't need micromamba, and we don't need to download and install conda/git separately 2023-03-07 21:33:38 +05:30
1384c2f1bc Keep bootstrap.bat in the repo, until the new installer releases. However it won't be copied or used after installation. 2023-03-07 21:17:04 +05:30
459b9428d4 Remove bootstrap.bat, since it's only needed during installation (and the current installer contains it, and this installer will soon be phased out) 2023-03-07 21:16:05 +05:30
a82f16958b Project name changes in NSIS installer 2023-03-07 19:43:04 +05:30
b9f436812b Download the default CLIP model during NSIS installation; Allow setting the path to an existing installation, which will be used for creating the installer executable 2023-03-07 19:40:58 +05:30
88e3831bc6 Remove AVX check
https://discord.com/channels/1014774730907209781/1064237509913084087/1064237509913084087
2023-03-05 00:13:07 +01:00
2a597fcad7 Single-file installer - Include all the dependencies from an installed folder; Download the default models using the NSCurl plugin 2023-03-04 18:02:30 +05:30
6158f49400 Workaround to fix the broken Rabbit Hole plugin 2023-03-02 13:56:39 +05:30
9dd819e193 Workaround to fix the broken Rabbit Hole plugin 2023-03-02 13:55:53 +05:30
e706fae648 Update README.md 2023-03-02 10:31:23 +05:30
118a4862ab Merge pull request #954 from cmdr2/beta
Beta
2023-03-02 10:26:25 +05:30
5e2f31e3bf Merge branch 'main' into beta 2023-03-02 10:15:51 +05:30
f78b31b1bc Less jittery dropdown 2023-03-01 18:41:21 +05:30
8d698cb997 reword 2023-03-01 18:35:41 +05:30
8945aac319 Merge models is no longer in beta 2023-03-01 18:28:58 +05:30
f2a960136e Move zoom and 'scroll to generated image' into a flat icon strip, with a press-toggle button for the 'scroll to' button; Tweaked the behavior of the on-scroll dropdown CSS class 2023-03-01 18:27:48 +05:30
7a1170f1dd Use naturalWidth, to show the actual image width (especially for upscaled images) 2023-03-01 15:22:38 +05:30
24cce08580 Show the image dimensions on mouse over 2023-03-01 15:17:27 +05:30
b425b43d3e changelog 2023-02-28 15:38:53 +05:30
353fe88226 Set tertiary colors on buttons that don't need to be visible in a very dominant manner 2023-02-28 15:37:38 +05:30
1a3086230e Set the dropdown width only when the dropdown is opened, to fix a bug where it would get set before the DOM element actually rendered. The settings field is collapsed by default (on new installations), so the computed DOM width would be invalid 2023-02-28 15:37:06 +05:30
0e57487774 Preserve full names for shortened modifiers (#945)
* Preserve full names for shortened modifiers

The PR https://github.com/cmdr2/stable-diffusion-ui/pull/779/files added code to preserve the full names of truncated image modifiers, but only in the "short image modifiers" code path. This PR fixes that by preserving the full car name for truncated modifier names too.

* Pick the full modifier name

The previous code selected the entire innerText from the modifier-car-label element, but for truncated modifiers this would also include the tooltip text. This modification fixes that by only picking specifically the full modifier name.

* Only pick the full modifier name

Previous code would pick up the tooltip text too, causing a mismatch of strings in the comparison.

* Display the truncated image modifier names

What we process and compare is always the full image modifier string, but we still want to display a shortened string when applicable.
2023-02-28 14:42:24 +05:30
3024465086 Merge pull request #932 from patriceac/patch-42
DOM tweaking to identify modifier categories
2023-02-28 14:41:46 +05:30
c95b43253a Merge pull request #933 from patriceac/patch-43
Cleanup logging
2023-02-28 14:41:04 +05:30
aedf7856e5 Merge pull request #940 from patriceac/patch-47
Select model by clicking on the file icon itself
2023-02-28 11:59:32 +05:30
d83e034d5e Select model by clicking on the file icon itself
Currently one has to click on the model name to select a model. Clicking on the file icon won't work and doesn't do anything. This change fixes that behavior by allowing the user to click on either the model name or the file icon to select a model.
2023-02-26 17:26:22 -08:00
b9676b51cb Cleanup logging
Is it okay for you if I comment this in Beta?
2023-02-24 17:46:53 -08:00
5698473891 Renaming custom-modifier-category to modifier-category 2023-02-24 13:55:18 -08:00
de1d1ad961 Shrink the preview tools buttons to icons-only on a small screen 2023-02-24 21:50:21 +05:30
bd82480fa3 Keep the min-width of a dropdown equal to the width of the input element 2023-02-24 20:08:19 +05:30
fce8b96d3b Tweaks to the styling of the models dropdown 2023-02-24 19:29:25 +05:30
37b47e7f05 Show root-level models at the top 2023-02-24 18:55:57 +05:30
a6f94959fe DOM tweaking to identify custom categories
This is purely a DOM update to be able to identify the custom category a given custom image modifier is part of, e.g. using .closest() from a custom modifier plugin. No UI change.
2023-02-24 01:16:14 -08:00
45a2c9f7ef Show icons next to the model folder and files in the dropdown, styling tweaks to increase padding 2023-02-23 22:11:53 +05:30
c49ac6880d Merge pull request #931 from patriceac/patch-41
Fix the restoration of the inpainting toggle
2023-02-23 19:29:40 +05:30
e0258d9e7b Merge pull request #930 from patriceac/patch-40
Fix the display of the Preview options button
2023-02-23 19:29:00 +05:30
e3ff6f183b Merge pull request #928 from ogmaresca/fix-models-up-down-arrow-keys
Fix up/down arrow keys on model selects
2023-02-23 19:28:16 +05:30
e6ec7393c6 Fix the restoration of the inpainting toggle
The Inpainting toggle doesn't get restored at the very first attempt.

Repro steps:
1. Create a task with a source image and enable the inpainting toggle.
2. Copy the task to the clipboard
3. Refresh the page (F5)
4. Paste the task from the clipboard

Expected result:
The task gets restored and the toggle is ON.

Actual result:
The task is restored, but the toggle is OFF.

To fix that, we have to restore the toggle's state after loading the source image.
2023-02-22 23:46:07 -08:00
f733b53c25 Merge pull request #927 from rbertus2000/fixthumbnailsize
fix for thumbnail slider to support seamless resize
2023-02-23 09:19:07 +05:30
204a68b17d Fix the display of the Preview options button
The preview options button overlaps the image task container when the window is reduced because of the float:right property of the button. This technique makes the parent div grow as needed when it contains a floated element, resulting in cleaner display.
2023-02-22 19:11:18 -08:00
1379dde1a7 Fix up/down arrow keys on model selects 2023-02-22 18:18:06 -05:00
79eee62d42 fix for thumbnail slider 2023-02-22 22:05:16 +01:00
7c1f18b6cd reword test 2 2023-02-22 20:16:52 +05:30
b59371988d Minor styling tweak 2023-02-22 20:15:33 +05:30
30dbadb2ab Focus the prompt textbox on start 2023-02-22 20:11:19 +05:30
a342de0207 Rename dropdown to 'View options' 2023-02-22 20:08:17 +05:30
6e6d236819 Change the image zoom size if the textbox is edited next to the slider 2023-02-22 19:56:45 +05:30
0e41483564 version 2023-02-22 19:35:13 +05:30
1023f5f7cc Slider for preview image size (#767)
* Slider for preview image size
Add a slider to the system settings so that users can configure the max size of thumbnails

* Remove debug output

* Fix var definition

* Move slider to 'display settings' menu

* thumbnail slider CSS
2023-02-22 19:32:00 +05:30
4bc7bca60d Merge pull request #924 from patriceac/patch-37
Allow modifier images to be passed as base64 images
2023-02-22 19:28:47 +05:30
de7dbd27c0 Merge pull request #925 from patriceac/patch-39
Fix reloading of image tags with weight modifiers
2023-02-22 19:26:19 +05:30
14118f142c Update image-modifiers.js
Reloading of image tags with ((weight modifiers)) doesn't reuse the modifier card even if it exists, which means images are not restored either. This change fixes that behavior by ensuring proper matching of the tags with existing modifiers.
2023-02-22 00:57:03 -08:00
9b99be4c1d Allow modifiers to be passed as base64 images
No change in existing UI behavior, this change allows image modifier plugins to (optionally) pass the card image as a base64-encoded image rather than a source file.
2023-02-22 00:06:07 -08:00
91c4b5865c Pin the sdkit version during fresh installs 2023-02-21 10:40:17 +05:30
1b4c14af71 Merge pull request #920 from patriceac/patch-36
Fix the active selection's display
2023-02-21 08:42:10 +05:30
7b85e50604 Merge pull request #918 from JeLuF/downloadall
Download all: Fix to download more than 10 images
2023-02-21 08:41:50 +05:30
d64b2d8fbe Merge pull request #917 from JeLuF/NoSSLmodule
Copy SSL DLLs
2023-02-21 08:41:09 +05:30
f1a7aed1b6 Merge pull request #916 from JeLuF/skipst
Don't scan safetensors files
2023-02-21 08:39:52 +05:30
75f758e792 Bugfix for enforce autosave (#909)
* show saveToDisk as checked and enable metadata format selection

* spaces instead of tabs

* check if force = true
2023-02-21 08:39:16 +05:30
e25e1bfe10 Make stream_image_progress accept an integer for the rate the progress frames should be generated. (#889)
* Make stream_image_progress accept an integer

for the rate the progress frames should be generated.

* Use a different field for the progress interval.
2023-02-21 08:38:21 +05:30
09deaefab0 Fix the active selection's display
Yesterday's PR caused a regression on the active brush display, specifically for Sharpness, which is treated differently from the other brushes in the code. This is the fix.
2023-02-20 18:25:57 -08:00
f80ecbde71 Download all: Fix to download more than 10 images
https://discord.com/channels/1014774730907209781/1021695193499582494/1077218966205902860
2023-02-21 00:49:04 +01:00
5e1e198a1f Copy SSL DLLs
Prevent the 'SSL module is not available' error message
2023-02-20 23:02:27 +01:00
bdbb741716 Don't scan safetensors files
In newer versions of the picklescanner, scanning of .safetensors files creates an error:

21:28:01.067 ERROR MainThread ERROR: parsing pickle in D:\2.35\dev\models\stable-diffusion\dantionrealmix_10.safetensors: at position 1, opcode b'\xce' unknown

To avoid these entries in the logs, skip scanning of safetensors files.
2023-02-20 22:44:10 +01:00
2f0e8a8a4a Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-20 19:31:57 +05:30
4f8424c544 sdkit 1.0.43 - unipc samplers on any device, not just cuda 2023-02-20 19:31:47 +05:30
ce3355d6aa Merge pull request #902 from patriceac/patch-32
Select but don't empty the search box upon selection
2023-02-20 19:14:02 +05:30
fb67ef2df0 Merge pull request #908 from JeLuF/png
Download all: Fix file name suffix
2023-02-20 18:57:24 +05:30
380e9aaf13 Merge pull request #903 from patriceac/patch-33
Fix autoscroll behavior for the first image
2023-02-20 18:56:52 +05:30
255e90d125 Merge pull request #910 from patriceac/patch-34
Fix the centering of sharpness brushes
2023-02-20 18:54:22 +05:30
504f7f3799 Merge pull request #913 from patriceac/patch-35
Fix the toggling of image modifiers
2023-02-20 18:49:52 +05:30
9970e505de sdkit version 1.0.42 - WEBP format support 2023-02-20 18:43:39 +05:30
0ccacd5eca 🔥 Installer: Fix ESRGAN anime model's path
The size check fails on every installation. The path name of the check wasn't changed when the model was moved to the models directory.
2023-02-20 18:40:13 +05:30
50e4683492 Merge pull request #907 from ogmaresca/webp-support
Support WEBP image formats
2023-02-20 18:36:40 +05:30
bc14bdc010 Merge pull request #900 from patriceac/patch-31
Fix filename parsing issue
2023-02-20 18:30:45 +05:30
14b0dabfdf Merge pull request #904 from JeLuF/patch-16
🔥 Installer: Fix ESRGAN anime model's path
2023-02-20 18:28:31 +05:30
e140acd2a4 Merge branch 'beta' into webp-support 2023-02-19 23:30:38 -05:00
facfed07fe sdkit 1.0.41 - NSFW filter 2023-02-20 08:44:26 +05:30
41a3309cbe Fix the toggling of image modifiers
The toggling of image modifiers doesn't get properly applied if weights are changed after restoring the image modifiers.
2023-02-19 15:59:20 -08:00
4df9a22dd6 Fix the centering of sharpness brushes
Fixing a visual glitch that becomes visible when a plugin adds borders to the brushes to make them more visible.

See this for context; https://discord.com/channels/1014774730907209781/1058857864954904607/1076694770845487155
2023-02-19 12:08:06 -08:00
31a1c4b2b2 Download all: Fix file name suffix 2023-02-19 12:44:10 +01:00
c2c33b7df1 Support WEBP outputs 2023-02-18 22:37:34 -05:00
6a2c2152e2 🔥 Installer: Fix ESRGAN anime model's path
The size check fails on every installation. The path name of the check wasn't changed when the model was moved to the models directory.
2023-02-18 14:05:55 +01:00
37f2755611 changelog 2023-02-18 15:01:52 +05:30
aa70f2849b NSFW filter setting 2023-02-18 15:01:13 +05:30
e7a2dfa57f changelog 2023-02-18 14:31:39 +05:30
b43f9fc4ee Upgrade stable-diffusion-sdkit to 2.1.3, to use transformers 4.26.1 2023-02-18 14:30:37 +05:30
51b6a2fd2a Pin the version of stable-diffusion-sdkit used, to avoid untested releases from getting used 2023-02-18 14:21:24 +05:30
5fffb82b16 Pin the version of stable-diffusion-sdkit used, to avoid untested releases from getting used 2023-02-18 14:17:28 +05:30
e051dbc2c7 Fix autoscroll behavior for the first image
When the first image is generated, the autoscroll triggers before the image is fully displayed by the browser. This causes it to not be positioned properly.
The fix is to listen for the "load" event on the IMG element before triggering the scrolling event. Once the image fully loaded and rendered, the browser correctly detects the size of the viewport and renders properly.
2023-02-18 00:00:00 -08:00
c2fba39cc7 Select but don't empty the search box upon selection
As per your request.
2023-02-17 23:26:17 -08:00
1050b13bbb Merge pull request #899 from patriceac/patch-30
Fix the chevron enabled state upon refresh
2023-02-18 12:30:54 +05:30
92d3d9cd33 Fix filename parsing issue
Here is a more robust fix for task restoration in dnd.js. Task restoration will fail if the JSON contains "use_face_correction": false, which can happen under some circumstances.

The fix checks if the filename passed to getModelPath is actually a string, which covers both the previous scenario (filename === null) and this new one (filename === false).
2023-02-17 18:49:51 -08:00
d8dec3e56a Fix the chevron enabled state upon refresh
Fix for my previous PR. Apologies for this silly copy/paste mistake.

https://discord.com/channels/1014774730907209781/1014780368890630164/1075782233970970704
2023-02-17 16:40:16 -08:00
130f9678b2 Merge pull request #896 from JeLuF/0x0a0d
Remove superfluous CarriageReturn
2023-02-17 16:06:29 +05:30
29d13cb06d Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-17 15:29:43 +05:30
620f521e0c changelog 2023-02-17 15:25:49 +05:30
a36fb55b05 Remove superfluous CarriageReturn
\r\n creates CR CR LF in python, which confuses the Windows batch processor.
With only \n, adding the config line for FP32 works as expected:

10:50:43.659 WARNING cuda:0 forcing full precision on this GPU, to avoid green images. GPU detected: NVIDIA GeForce GTX 1060 6GB
2023-02-17 10:53:51 +01:00
23f9bcb38b Upgrade sdkit, moving the experimental parser into a plugin 2023-02-17 15:22:59 +05:30
e73e820237 Support server-side plugins. Currently supports overriding the get_cond_and_uncond function 2023-02-17 15:22:42 +05:30
7e4735ae0f Merge pull request #893 from JeLuF/oneclick
Only confirm image deletion once
2023-02-17 11:17:53 +05:30
66ffcbbee6 Merge pull request #894 from ogmaresca/fix-model-folders-broken-up
Fix model folders being split up by child folders
2023-02-17 11:08:16 +05:30
4754743c84 5 new samplers - UniPC 2023-02-17 10:24:59 +05:30
09c1dfd92b Remove leading slash from data-path attributes 2023-02-16 23:29:32 -05:00
7fc46f3672 sdkit 1.0.39 - unipc samplers 2023-02-17 09:36:10 +05:30
df93fee034 Fix model dropdown icon 2023-02-16 21:16:19 -05:00
fc2cf742c8 Remove trailing slash 2023-02-16 21:08:41 -05:00
9bec441e94 Fix model folders being split up by child folders 2023-02-16 21:03:02 -05:00
1caab1da85 Only confirm image deletion once
The previous code added an event listener per preview image (if live preview is enabled), so
that multiple confirmations were required.
2023-02-17 00:54:41 +01:00
d612d7ab53 changelog 2023-02-16 21:10:51 +05:30
3d3994bbad sdkit 1.0.38 - experimental parser, requires the prompt to start with an exclamation mark 2023-02-16 21:01:33 +05:30
d643ae0299 temp fix for broken dropdowns 2023-02-16 19:46:06 +05:30
0a099434a3 Merge pull request #885 from patriceac/patch-28
Cleaning up event listener that's no longer needed
2023-02-16 19:31:19 +05:30
16905a8999 Merge pull request #888 from JeLuF/macos2
No /proc/cpuinfo on MacOS
2023-02-16 19:29:42 +05:30
282c4cca82 Add support for disabled state to model dropdown (#886)
* Add support for disabled state to model dropdown

As per https://discord.com/channels/1014774730907209781/1021695193499582494/1075068193753804831

The only limitation is that we cannot visually gray out the chevron itself because the corresponding font-awesome icon is a Pro icon (https://fontawesome.com/icons/angle-down?s=duotone&f=classic).

* Gray out the chevron when the control is disabled

* Remove empty line

* Disable the transition on the chevron

Apply effect immediately when the dropdown is enabled/disabled.
2023-02-16 19:29:08 +05:30
f36b7ce016 Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2023-02-16 19:22:04 +05:30
9fb5cac5d4 Bypass incorrect ERRORLEVEL values in nested code blocks by using something called delayedexpansion. Ugh 2023-02-16 19:21:51 +05:30
9f5f213cd3 Fix for dropdown widths (#883)
* Fix dropdown location

* change width
2023-02-16 10:35:46 +05:30
5d3b59b94e No /proc/cpuinfo on MacOS
Check whether /proc/cpuinfo exists before checking for AVX support
2023-02-15 21:15:55 +01:00
744c6e4725 sdkit 1.0.37 2023-02-15 21:40:02 +05:30
c59745d346 Cleaning up event listener that's no longer needed
The event listener instantiates two objects every time the user clicks on the Merge tab. This is no longer needed after AssassinJN's CSS fixes from yesterday.
2023-02-15 00:10:02 -08:00
9d1dd09a07 'Download all images' button (#765)
* Use standard DOM function

* Add 'download all images' button

---------

Co-authored-by: cmdr2 <secondary.cmdr2@gmail.com>
2023-02-14 19:33:25 +05:30
2eb317c6b6 Format code, PEP8 using Black 2023-02-14 18:47:50 +05:30
0ad08c609d Merge pull request #878 from patriceac/patch-26
Removing the 'None' option for face correction
2023-02-14 16:44:39 +05:30
85f6f8b31d Merge pull request #881 from patriceac/patch-27
Fix reloading of tasks with no file path
2023-02-14 16:44:01 +05:30
9799309db9 Fix reloading of tasks with no file path
In some conditions tasks may be reloaded with an empty file path (e.g. no face correction)
2023-02-14 02:31:13 -08:00
fa205f483a Merge pull request #880 from JeLuF/instfix
Fix functions.sh upgrade, change messages to Easy Diffusion
2023-02-14 15:08:06 +05:30
2df4286256 Change SDUI to Easy Diffusion 2023-02-14 09:05:23 +01:00
b89f689ea3 Fix functions.sh upgrade, change messages to Easy Diffusion 2023-02-14 09:00:02 +01:00
f58b21746e Removing the 'None' option for face correction
As per conversation : https://discord.com/channels/1014774730907209781/1014780368890630164/1074802779471757405
2023-02-13 17:42:36 -08:00
6971f9dcf1 Merge pull request #873 from AssassinJN/patch-1
remove js based sizing
2023-02-13 21:12:45 +05:30
3454a47f67 Merge pull request #872 from AssassinJN/patch-2
Fix for searchable model width
2023-02-13 21:12:15 +05:30
5922fd39c5 Fix for searchable model width 2023-02-13 09:31:53 -05:00
cdbddbae3b remove js based sizing 2023-02-13 09:20:11 -05:00
af4a26c1d0 Merge pull request #871 from JeLuF/patch-15
Fix typo in `cp functions.sh`
2023-02-13 19:12:18 +05:30
d3f42e47a7 Fix typo in cp functions.sh 2023-02-13 14:33:34 +01:00
8821e471b5 Merge pull request #870 from patriceac/Fix-autocomplete
Fix autocomplete in GFPGAN and Merge
2023-02-13 15:26:51 +05:30
d34aed0b14 Fix autocomplete in GFPGAN and Merge 2023-02-13 01:54:55 -08:00
b7391652ca Merge pull request #869 from patriceac/searchable-models-fixes
Model search bug fixes
2023-02-13 15:16:22 +05:30
074a14f056 Second batch of fixes for search models
Addresses the issues reported by JeLuf:
- - gfpgan: the list with models doesn't appear under the <input> box
- merge models: As long as no models are selected, the <input> box is very short.
- When searching for models by name, the width of the model list shrinks and is smaller than the <input> element.
2023-02-13 01:37:00 -08:00
b1db708af1 Model search bug fixes
First batch of bug fixes for model search:
- fix navigation issues with arrow keys when filtering models
- fix the issue with arrow keys jumping several entries after model reloading
- disable autocomplete in search box
2023-02-12 23:23:26 -08:00
b2a66709b0 Merge pull request #868 from JeLuF/modelselect
Use new model selector for merging and gfpgan
2023-02-13 09:03:13 +05:30
e3e43913ab Linux Installer fixes (#867)
Copy functions.sh from git repo as well
Remove duplicate 'Press any key' call
2023-02-13 09:02:31 +05:30
c7fed0a42a typo 2023-02-13 08:56:43 +05:30
c6c5e0734a typo 2023-02-13 08:55:35 +05:30
73cbc58a50 typo 2023-02-13 08:54:29 +05:30
8431395326 Fix model merger tab initialization 2023-02-13 00:30:06 +01:00
dd21c07d4a Use new model selector for merging and gfpgan 2023-02-13 00:13:13 +01:00
ce9591428e hotfix for broken model dropdown. thanks @patrice 2023-02-12 18:46:09 +05:30
a801a5d8b6 Searchable models (#786)
* Searchable models

Creates searchable dropdowns for SD, VAE, or HN models. Also adds a reload models button (placed next to SD models, reloads everything including VAE and HN models).

* Fixing the editor pane display

* Revert "Fixing the editor pane display"

This reverts commit de902a6340.

* Move formatting to the CSS file

* Rewritten the siblings functions

I like these much better, and I imagine you will too. :)

* Code cleanup

* Minor tweak in list ordering

Minor tweak to move the root folder's content at the end of the list (similar to the current version).
2023-02-12 14:48:09 +05:30
04e8458ce2 Merge pull request #862 from JeLuF/dragfix
Fix task reordering
2023-02-12 14:40:21 +05:30
4b4fa84879 Merge pull request #856 from JeLuF/mac
Changes to make things work on MacOS/x64
2023-02-12 14:39:32 +05:30
1b3df8c4de Merge pull request #864 from patriceac/patch-25
Fix the inpainter and image editor display
2023-02-12 14:38:34 +05:30
7ce223771d Add k40m to list of FP32 cards (#863)
https://discord.com/channels/1014774730907209781/1073819636329631754
2023-02-12 14:37:53 +05:30
ccf71ed445 Fix the inpainter and image editor display 2023-02-11 21:57:56 -08:00
aa7c031e8a Fix task reordering 2023-02-12 01:02:27 +01:00
8465bc1bc9 Changes to make things work on MacOS/x64 2023-02-10 22:34:52 +01:00
f2f3ed71d4 Hide Image buttons hides task (#854)
* hide task when all images are hidden

* Update main.css

* remove console logs

* remove another console log

* Update main.js

* Update main.js
2023-02-10 22:58:07 +05:30
ab7ba35639 Revert "sdkit message"
This reverts commit 6ab3133b33.
2023-02-10 22:54:45 +05:30
1cc09cbe5f Revert "sdkit message"
This reverts commit 6ab3133b33.
2023-02-10 22:54:02 +05:30
fe7e398eb4 sdkit message 2023-02-10 19:01:27 +05:30
6ab3133b33 sdkit message 2023-02-10 19:01:03 +05:30
ef77c37a7e changelog 2023-02-10 18:43:06 +05:30
1dd165a9c9 Keep txt as the default metadata format, and write metadata files by default, if saving to disk 2023-02-10 18:13:08 +05:30
3c74540615 Merge pull request #794 from patriceac/Embed-Metadata
Embed metadata
2023-02-10 18:11:56 +05:30
ad249c4651 sdkit 1.0.36, for the image metadata embedding change 2023-02-10 18:09:23 +05:30
071a4d6f37 Use a fixed sdkit version, to avoid bumping to the latest sdkit version in the main branch 2023-02-10 18:05:17 +05:30
5f2fb19d71 Use a fixed sdkit version, to avoid bumping to the latest sdkit version in the main branch 2023-02-10 18:04:43 +05:30
ce61657f7a typo 2023-02-10 17:46:50 +05:30
dc54e5bdce version 2023-02-10 17:44:16 +05:30
f7b8e000c5 Merge pull request #830 from ogmaresca/sort-models
Sort models alphabetically
2023-02-10 17:42:24 +05:30
73abf131a6 Merge pull request #771 from patriceac/patch-19
Fix restoration of models with subfolders
2023-02-10 17:32:56 +05:30
5741af2aba Merge pull request #777 from patriceac/preview-content-container
Group image containers (DOM tweak)
2023-02-10 17:28:08 +05:30
159af669f6 Merge pull request #769 from JeLuF/counter
Fix number on the "Make X images" button
2023-02-10 17:22:24 +05:30
a517255653 Merge pull request #784 from JeLuF/no-src
Warn when running installer from git checkout
2023-02-10 17:20:10 +05:30
573154633b Merge pull request #793 from patriceac/patch-20
Fix the tooltip display over image modifier cards
2023-02-10 17:18:46 +05:30
baa8afd9eb Merge pull request #843 from JeLuF/prompthook
Add hook to implement custom prompt preprocessors
2023-02-10 17:18:06 +05:30
9e718da70e Merge pull request #789 from JeLuF/gfpgan-chooser
Support multiple GFPGAN models
2023-02-10 17:16:49 +05:30
4df442f169 Merge pull request #736 from JeLuF/enfdir
Enforce an autosave directory
2023-02-10 16:55:23 +05:30
1dc93c7a39 Merge pull request #829 from Schorny/beta
add random_seed flag to reqBody
2023-02-10 16:52:41 +05:30
3d124986d3 renamed random_seed to used_random_seed 2023-02-10 11:59:34 +01:00
a589d98cd4 Merge pull request #850 from JeLuF/patch-13
Link to LINUX.zip
2023-02-10 10:51:12 +05:30
ed9f18e22c Trim lines 2023-02-09 17:56:54 -05:00
14fb115fc8 Link to LINUX.zip 2023-02-09 20:25:27 +01:00
c35a731a60 Update README.md 2023-02-09 19:56:18 +05:30
4f3d2bd120 Merge pull request #779 from patriceac/Fix-card-names-and-toggling
Fix card names and toggling
2023-02-09 19:43:57 +05:30
69c8fc3236 Merge pull request #811 from patriceac/patch-23
Removing the ':' after the tooltip icon
2023-02-09 19:31:10 +05:30
840ff5c363 Merge branch 'main' into patch-23 2023-02-09 19:30:55 +05:30
8386cd5cf7 Merge pull request #817 from fernandoisnaldo/patch-1
Fix aarch64 (arm64) verification
2023-02-09 19:24:13 +05:30
666c2f8771 Merge pull request #831 from ogmaresca/remove-promt-strength-txt2img
Restore VAE model in metadata files and remove prompt strength in txt2img generations
2023-02-09 19:23:54 +05:30
b342fa9661 Merge pull request #837 from patriceac/patch-24
Fix the behavior of the use as input button
2023-02-09 19:09:09 +05:30
63bf84fdd5 Merge pull request #845 from cmdr2/beta
Changelog
2023-02-09 19:01:53 +05:30
070e51fcab Changelog 2023-02-09 19:01:25 +05:30
50fd64150e Merge pull request #844 from JeLuF/patch-12
Add T500 to list of full precision cards
2023-02-09 09:56:51 +05:30
63c5de2612 Add T500 to list of full precision cards 2023-02-09 01:46:32 +01:00
c576d582e2 Add hook to implement custom prompt preprocessors 2023-02-08 17:26:55 +01:00
026a4b6c76 Merge pull request #842 from cmdr2/beta
Don't force a user to 'low' VRAM usage, if their GPU has 4 GB or less VRAM
2023-02-08 19:46:57 +05:30
7bc95b68c8 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-08 19:43:31 +05:30
0332cc8cb3 Don't force the user to 'low' VRAM usage automatically, if their GPU is less than 4 GB of VRAM. We need a better way to set 'low' as the default in the UI, but the user should be able to override it if they want 2023-02-08 19:41:55 +05:30
ce192f4ad7 Merge pull request #839 from cmdr2/main
Merge from main
2023-02-08 11:44:51 +05:30
cbdb715918 Merge pull request #838 from cmdr2/beta
Beta
2023-02-08 11:19:59 +05:30
5537102fd3 changelog 2023-02-08 11:19:16 +05:30
1ea294f15c Fix broken auto-save settings. We renamed sampler to sampler_name, which causes old settings to fail 2023-02-08 11:18:28 +05:30
e7bf2ee58b Show models above folders in child folders to avoid models from appearing to belong the grandchild folder, prevent creating empty <optgroup />s 2023-02-07 21:13:06 -05:00
a931aa59a3 Fix the behavior of the use as input button
Clicking the button toggles the task container behind it.
2023-02-07 18:02:42 -08:00
4c8da67bb1 Use "python -m pip" instead of "pip" (#835)
* Use "python -m pip" instead of "pip"

https://discord.com/channels/1014774730907209781/1072423234676461619

* Use "python -m" instead of "pip" (Linux=
2023-02-07 15:39:02 +05:30
a0178e15b3 More robust relative path calculation 2023-02-06 22:19:57 -08:00
43a1c3901f ED favicon (#832) 2023-02-07 11:32:55 +05:30
a4c6f28a70 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-07 11:32:06 +05:30
f8bca93170 ED favicon 2023-02-07 11:31:56 +05:30
f07d05a490 Also remove Hypernetwork Strength if not using a hypernetwork 2023-02-06 23:35:23 -05:00
b3a988bc0b Restore VAE model in metadata files and remove prompt strength in txt2img generations 2023-02-06 23:07:23 -05:00
e0f22d29e8 Sort models alphabetically 2023-02-06 19:03:03 -05:00
07ee97b862 add random_seed flag to reqBody (#1)
expose if the user requested a random seed or used a fixed seed
2023-02-06 23:13:00 +01:00
19b05659b5 Update README.md 2023-02-06 23:07:11 +05:30
7e5c7ca1b7 Easy Diffusion 2.5 2023-02-06 22:50:18 +05:30
1156c159f9 Merge pull request #827 from cmdr2/beta
v2.5
2023-02-06 20:11:18 +05:30
5c6c2303ba Why does this script file keep losing exec permission? 2023-02-06 20:05:40 +05:30
a0a58bcfa8 Merge branch 'main' into beta 2023-02-06 19:42:24 +05:30
8a28b265a3 Preserve the id of the top-level tabs container, to avoid breaking plugins that rely on it 2023-02-06 19:09:39 +05:30
86dc08130b typo 2023-02-06 16:47:48 +05:30
5cd8a732c7 grammar 2023-02-06 16:29:46 +05:30
fafbbf68a4 changelog 2023-02-06 16:20:38 +05:30
0cbb553564 Follow the theme in the popup dialog box 2023-02-06 15:32:54 +05:30
f4512bb291 Color of close button 2023-02-06 15:19:10 +05:30
99205b4d03 Show an X over an image, instead of a remove button in image options 2023-02-06 15:14:47 +05:30
d48e6554d5 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-06 13:49:38 +05:30
d0c4e95de3 Simplify the UI of the model merge tab; Allows a user to merge a single model, or a batch of variations; Also fixes a few logging bugs in the model merge tab 2023-02-06 13:49:15 +05:30
0b3a35c4b6 Make the tabs container a class, to make it reusable for other tab groups 2023-02-06 13:48:18 +05:30
ded6a41f86 Only disable the sibling tabs when a particular tab is selected. This allows the 'tab' management code to be reused for nested tabs 2023-02-06 13:46:40 +05:30
f4063e63d3 Merge pull request #824 from JeLuF/pause2
Fix 'Pause All' function
2023-02-06 10:18:51 +05:30
23ba912db0 Fix 'Pause All' function
If 'pause all' is clicked during the last scheduled job, the 'resume all' button gets hidden when the jobs terminates, making it
impossible to unpause the engine.
https://discord.com/channels/1014774730907209781/1014780368890630164/1071584183417323602
2023-02-05 17:33:43 +01:00
b99d9db8f9 Create exactly 'total' images even if 'in parallel' is no factor of 'total' 2023-02-05 17:09:56 +01:00
b7047dafb2 Fix aarch64 (arm64) verification 2023-02-03 16:36:49 -03:00
368967fbcf Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-02-03 21:41:23 +05:30
a9d0fc9978 changelog 2023-02-03 21:41:12 +05:30
b6f3d2ec02 Formatting 2023-02-03 21:40:08 +05:30
78e917a6fb Fix the broken 'Make Similar Images' button 2023-02-03 21:40:03 +05:30
96b45385e8 Merge pull request #803 from JeLuF/patch-10
Add T600 to list of FP only GPUs
2023-02-03 19:56:54 +05:30
db47888a75 changelog 2023-02-01 11:54:05 +05:30
51443741b8 Proactively delete the partial samples from the callbacks 2023-02-01 11:50:50 +05:30
3e7f14af2c Don't use Rich Tracebacks, can cause a memory leak. It keeps a reference to the Exception object (which in turn keeps references to any torch Tensors in the stack, preventing their garbage-collection) 2023-02-01 11:50:27 +05:30
733439da07 Fix a memory leak. Apparently the Exception object keeps references to torch Tensors in the stack, so keeping a reference to the Exception object prevents those Tensors from getting garbage-collected. 2023-02-01 11:49:18 +05:30
6bff97d6fa Removing the ':' after the tooltip icon
This colon after the tooltip icon just feels out of place.
2023-01-30 23:09:36 -08:00
efba81cb66 Add T1000, make Quadro equivalent to nvidia or geforce 2023-01-28 20:51:01 +01:00
b2cc5dcf4b Add T600 to list of FP only GPUs
https://discord.com/channels/1014774730907209781/1068948110304354314
2023-01-28 20:18:07 +01:00
fab86ddf35 changelog 2023-01-27 09:46:50 +05:30
f3a90ce02d Formatting tweaks and tip about merging similar type of models 2023-01-25 20:05:27 +05:30
4886616c48 changelog 2023-01-25 19:52:28 +05:30
dcd8121009 Revert "Temporarily disable the Merge Models UI"
This reverts commit 59adaf6225.
2023-01-25 19:51:12 +05:30
59adaf6225 Temporarily disable the Merge Models UI 2023-01-25 19:46:55 +05:30
0055cd9b2e Merge pull request #734 from JeLuF/mrguipi
Frontend of the batch merger
2023-01-25 19:39:19 +05:30
fe89d487f6 Merge pull request #733 from JeLuF/mrgui
Backend side merge API
2023-01-25 19:38:21 +05:30
01368ac496 Add support for Windows path names 2023-01-25 02:47:50 -08:00
495064985e Reduce VRAM usage of img2img in balanced mode, without reducing the speed of rendering 2023-01-24 18:58:15 +05:30
200f8fd245 Code cleanup 2023-01-24 01:53:22 -08:00
64bf4356b4 Update save_utils.py 2023-01-24 01:48:16 -08:00
8d4d409cd6 Add 'embed' and 'none' to metadata saving options
*** Please merge https://github.com/easydiffusion/sdkit/pull/9 before merging this one. ***

This is the ED client part of metadata embedding. It adds 'embed' and 'none' options to the metadata setting and makes none the default (if never set before) because (1) it feels weird to create metadata files by default and (2) embedding by default could cause be problematic if users don't realize it's happening.

Also fixes the disabling of the dropdown in the settings when Save images to disk is toggled off.
2023-01-24 01:47:48 -08:00
dd4937178f Fix the tooltip display over image modifier cards 2023-01-24 01:37:37 -08:00
e12387a377 changelog 2023-01-23 21:40:50 +05:30
5d3fb9091a Reduce the VRAM usage for balanced mode, without sacrificing the rendering speed 2023-01-23 19:36:00 +05:30
b044bc1791 Support multiple GFPGAN models
Add scanning for models and a dropdown to choose different models from
2023-01-19 20:49:54 +01:00
409ec61be2 Fail fatally, add same check on Linux, add some extra checks on Linux
Linux: Check that curl, bzip2, tar are available, check whether there's a space character in the install path, check whether the CPU supports AVX.
2023-01-19 00:40:20 +01:00
e2ae2715a3 Revert "Revert "Don't set the specific vram optimizations to use, instead use the new sdkit API for setting the vram usage level directly""
This reverts commit 52458ae273.
2023-01-18 17:03:14 +05:30
52458ae273 Revert "Don't set the specific vram optimizations to use, instead use the new sdkit API for setting the vram usage level directly"
This reverts commit 42f9abdfe3.
2023-01-18 10:30:56 +05:30
79d112ca7b Warn when running installer from git checkout 2023-01-18 00:11:23 +01:00
9b1a9cc7c8 changelog 2023-01-17 21:34:41 +05:30
42f9abdfe3 Don't set the specific vram optimizations to use, instead use the new sdkit API for setting the vram usage level directly 2023-01-17 21:33:15 +05:30
66d311258a Fix card names and toggling
Fix names and toggling for cards starting  with "By ", e.g. "By the ocean".
2023-01-16 23:56:44 -08:00
0a1197055c changelog 2023-01-16 18:32:09 +05:30
649cbf07e3 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-01-16 18:30:46 +05:30
5089ac5ad1 Fix a bug where the .vae.pt extension wouldn't get picked up. Thanks Madrang, rbertus2000 and JeLuf 2023-01-16 18:30:22 +05:30
d99e3f7974 Merge pull request #776 from JeLuF/patch-8
Add NVIDIA T1200 to the list of FP GPUs
2023-01-16 18:09:06 +05:30
3d5133209b Group image containers (DOM tweak)
Move image containers in their own container to create a clear delineation in the DOM. Purely DOM structural adjustment meant to make a sticky footer possible in the preview pane (for plugins).
2023-01-15 23:34:56 -08:00
b5d1912c94 Add NVIDIA T1200 to the list of FP GPUs
Fixes https://discord.com/channels/1014774730907209781/1014774732018683926/1064269949339697163
2023-01-16 00:42:02 +01:00
a8fba8f3fb Fix restoration of models with subfolders
In dnd.js, when models are restored in the UI, there is code that strips the path from the model file name. Now that we allow models to be hosted in subfolders, this code break the task restoration (e.g. use settings, D&D, copy/paste) because "/my models/model.ckpt" becomes "model.ckpt", which won't be found.

https://discord.com/channels/1014774730907209781/1014780368890630164/1063726724573052948
2023-01-14 23:54:09 -08:00
9d9fc1683a Fix number on the "Make X images" button
With this change, the number of prompt variants is taken into account when computing the number of images that will be generated.
X = getPrompts().length * numOutputsTotalField.value
2023-01-13 22:05:25 +01:00
8ee4364065 Merge pull request #768 from rbertus2000/beta
bugfix for FP GPUs
2023-01-13 17:39:49 +05:30
152aa7de09 bugfix for FP GPUs 2023-01-13 12:54:11 +01:00
85c90cbee1 Merge pull request #764 from JeLuF/patch-7
Add NVIDIA T550 to list of FP GPUs #755
2023-01-13 10:18:24 +05:30
7302927e4c Add NVIDIA T550 to list of FP GPUs #755
The Nvidia T550 needs full precision to work correctly.
2023-01-12 14:16:35 +01:00
df3d00ef94 Merge pull request #763 from patriceac/patch-18
Another fix for high res images
2023-01-12 10:23:01 +05:30
bb47835256 Another fix for high res images
This time to address the height.
2023-01-11 17:25:54 -08:00
037512ca5c Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2023-01-11 18:25:16 +05:30
a13713adaf Don't search for a yaml config file next to the model, since sdkit now does this automatically 2023-01-11 18:23:56 +05:30
ad073252e7 Merge pull request #762 from patriceac/patch-17
Fix the restoring of the previous nested model
2023-01-11 14:58:25 +05:30
d24a7a5c5e Fix the restoring of the last selected model 2023-01-10 19:00:19 -08:00
192fd223b4 use config.json instead of config.bat 2023-01-10 23:40:35 +01:00
a671dd8e00 Fix import, remove debug output 2023-01-10 20:34:17 +01:00
8b764a8fd3 changelog 2023-01-10 21:58:29 +05:30
aa576e68e3 Bring back the default opacity of 0.4 for inpainting mask, even though it leads to some other bugs. It's not a good UX to have an inpainting mask with full opacity 2023-01-10 21:56:26 +05:30
ad5508a14d Fix typo 2023-01-10 21:54:31 +05:30
4fafc8aa67 Merge pull request #685 from mdiller/mdiller_bugfixes
Mdiller bugfixes
2023-01-10 21:44:40 +05:30
0aab3d0f12 Merge pull request #744 from AssassinJN/patch-2
return taskEntry.id on createTask
2023-01-10 21:41:56 +05:30
a5d88bdfcc changelog 2023-01-10 21:09:08 +05:30
5173957368 Minor refactor of save file 2023-01-10 20:13:39 +05:30
4b3e3d900d Merge pull request #745 from JeLuF/sync-fn
Synchronize .img and .txt autosave file names
2023-01-10 20:07:17 +05:30
9ea51b174a Merge branch 'beta' into sync-fn 2023-01-10 20:06:58 +05:30
80e265e547 Merge pull request #746 from JeLuF/modelload
Don't crash on unsupported models
2023-01-10 20:01:24 +05:30
c3e6e63023 Merge pull request #754 from patriceac/patch-15
Fix display of very large images
2023-01-10 20:00:00 +05:30
9b5a262d63 Merge pull request #758 from patriceac/patch-16
Fix image editor display
2023-01-10 19:56:18 +05:30
1309f1480c Tabs to spaces 2023-01-10 19:48:36 +05:30
12ba5b8096 Merge pull request #753 from JeLuF/modeldir
Recursive scanning for models
2023-01-10 19:29:27 +05:30
156c5f4792 Fix incorrect seeds returned when no filters were applied. Fixes https://github.com/cmdr2/stable-diffusion-ui/pull/748 2023-01-10 19:23:17 +05:30
1da4b3d94a Not all browsers return the PerformanceEntry object on performance.measure(). Fix credit @JeLuf 2023-01-10 10:01:24 +05:30
18aca98e41 Fix image editor display
Fix for the cut off controls
2023-01-09 09:29:31 -08:00
a88afb0956 Add paths to the value field 2023-01-09 18:24:04 +01:00
bfa1f57930 Fix rendering of very large images
See comments for screenshots.
2023-01-09 09:21:16 -08:00
a5350eb3cc changelog 2023-01-09 19:42:06 +05:30
3ed4d792b3 Check whether the browser supports performance.measure/mark before calling them. Fixes https://github.com/cmdr2/stable-diffusion-ui/pull/757 2023-01-09 19:41:10 +05:30
fb0c9405cf changelog 2023-01-09 19:40:17 +05:30
a17a9044ad Check whether the browser supports performance.measure/mark before calling them. Fixes https://github.com/cmdr2/stable-diffusion-ui/pull/757 2023-01-09 19:33:23 +05:30
73af7f5481 Use a boolean .includes() instead of a regex match() for checking string contains 2023-01-09 19:19:30 +05:30
57ead7f0c0 Merge pull request #752 from patriceac/patch-14
Fix parsing of text file tasks
2023-01-09 19:16:36 +05:30
bf490c910a changelog 2023-01-09 18:48:15 +05:30
40f806efa8 Merge pull request #742 from JeLuF/noise
Prevent flooding the log with warnings for GPU<3GB
2023-01-09 18:47:20 +05:30
226ba8b06e Bump version 2023-01-09 18:39:24 +05:30
b11aa4833d Merge pull request #724 from patriceac/img2img-settings-restoration
Img2img settings restoration
2023-01-09 18:36:32 +05:30
8d9cd0e30b Fix display of very large images 2023-01-07 15:04:07 -08:00
9532928998 Recursive scanning for models 2023-01-07 19:04:15 +01:00
420f7549a2 Fix parsing of text file tasks
parseContent(text) doesn't check the text content being passed actually described a task, which causes some corner case scenarios to break (image task settings are incorrectly cleared because an empty image task is created).
2023-01-07 00:47:30 -08:00
ed64b9bfed Don't crash on unsupported models 2023-01-06 01:41:55 +01:00
5d5ebfdef6 Synchronize .img and .txt autosave file names 2023-01-04 16:51:18 +01:00
567c02bf5d return taskEntry.id on createTask
I would like to have createTask return the taskEntry.id in order to allow for watchers or callbacks to be able to reference tasks by id more easily.
2023-01-04 10:04:52 -05:00
60f7c73c8a prevent flooding the log with warnings for GPU<3GB 2023-01-04 02:45:51 +01:00
ac4c5003f1 also empty VAE and hypernetwork fields 2023-01-03 08:23:42 +01:00
d5e76e662f Enforce a autosave directory 2022-12-30 21:05:25 +01:00
23d5f85d17 Frontend batch merger 2022-12-30 10:13:34 +01:00
f75adc1e22 added fill tool and updated as requested in pull request 2022-12-30 01:07:46 -08:00
15a1436c8b Backend side merge API 2022-12-30 10:07:23 +01:00
813edec808 Removing one more unnecessary custom event 2022-12-29 09:43:12 -08:00
21e3299b7a Applying changes from latest CR
- Replaced custom event with load event
- Removed the custom event dispatch
2022-12-29 09:26:32 -08:00
f7193966fb Addressing Cmdr2's comments and more
Only triggers events when there actually was a state  change. Also opportunistically removed the hardcoded delay in favor of an even-driven flow, which makes the whole thing more robust and much more reactive.
2022-12-29 01:16:44 -08:00
2d9853f1f4 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-29 13:25:25 +05:30
ced79a187d changelog 2022-12-29 13:25:13 +05:30
7832524963 Merge pull request #729 from patriceac/patch-12
ESC keyboard shortcut to close the image editor
2022-12-29 13:23:00 +05:30
58c7f3ba15 ESC keyboard shortcut to close the image editor 2022-12-28 23:50:56 -08:00
90ec8f0575 changelog 2022-12-29 13:17:26 +05:30
64ced3b3f6 Tag v2.4.23, to be able to revert back incase of an emergency 2022-12-29 13:04:44 +05:30
493526c478 If downgrading to 2.4 (from 2.5), move the default models back to the legacy location 2022-12-29 13:00:57 +05:30
b86617e3af Merge pull request #720 from patriceac/restore-inactive-modifiers
Proper restoration of inactive image modifiers
2022-12-29 10:28:28 +05:30
f3db6d84fb Merge pull request #721 from patriceac/patch-8
Fix restoration of hypernetwork dropdown
2022-12-29 10:26:54 +05:30
f9b9ecf754 Merge branch 'beta' into patch-8 2022-12-29 10:26:48 +05:30
af43a92a2f Merge pull request #725 from patriceac/patch-9
Limit the size of zoomed-in source images
2022-12-29 10:18:17 +05:30
4dbdc642f9 Merge pull request #726 from patriceac/patch-10
Persist the processing order toggle across sessions
2022-12-29 10:17:24 +05:30
8f2c87ce94 Merge pull request #717 from jsuelwald/patch-1
Restore download link for Linux in beta, ...
2022-12-29 10:16:59 +05:30
5149040496 Merge pull request #727 from patriceac/patch-11
Restore the original prompt if provided
2022-12-29 10:15:22 +05:30
5b1078e0db Merge pull request #719 from patriceac/fix-duplicate-image
Fix for duplicate images
2022-12-29 10:13:51 +05:30
ae31813239 Restore the original prompt if provided
Restore the original prompt if provided... including if it's empty now that empty prompts are allowed if there are modifiers.
2022-12-28 18:52:18 -08:00
f6b3cde286 Persist the process order toggle across sessions
🤷
2022-12-28 17:50:18 -08:00
0f05f9c32c Limit the size of zoomed-in source images
If the source image has a high enough resolution it won't fit on the screen when hovering over it. This simple fix limits the max size so the user always has a chance to see the full image.
2022-12-28 17:30:59 -08:00
89170af721 Proper source image unloading 2022-12-28 17:00:38 -08:00
5fddae589b Reverting duplicate hypernetwork fix 2022-12-28 16:54:36 -08:00
19c16af5fa Fix img2img task restoration
Fix source image, mask, and color profile restoration for use settings, copy/paste, and d&d.
2022-12-28 16:43:35 -08:00
019f8f69f4 Fix restoration of hypernetwork dropdown
Fix for https://discord.com/channels/1014774730907209781/1014774732018683928/1055508538228748368
2022-12-28 15:55:59 -08:00
ad8d1f77df Proper restoration of inactive image modifiers
Inactive image modifiers (right click on image tag) are not properly restored by Use Settings and Copy/Paste settings. This PR fixes that.
2022-12-28 13:41:36 -08:00
e82a8a7f3d Fix for duplicate images
When eye correction, upscaling, and only show filtered image are ALL disabled, the UI still generates two of the same image, and increments the second's seed by 1 (although it's the same image). It doesn't perform an additional process, but the item is shown twice.
2022-12-28 12:06:36 -08:00
ad07aeb041 Restore download link for Linux in beta, ...
and make shellscripts in scripts/ executable
2022-12-28 17:52:49 +01:00
451ab7e84c Create the folders before moving to them 2022-12-28 19:40:08 +05:30
083390da83 Fix a bug where the task and req data needed to print with a backslash 2022-12-28 19:23:36 +05:30
dc6d48580b Merge pull request #715 from jsuelwald/beta
Convert [ to \[ so the logging backend...
2022-12-28 19:20:28 +05:30
27d69e2ac3 Upgrade stable-diffusion-sdkit during startup 2022-12-28 19:19:53 +05:30
91274a4df8 Move the mandatory models to the models folder, instead of the legacy location inside the stable-diffusion folder 2022-12-28 19:08:39 +05:30
6eafcdfafd Update renderer.py
Use .replace on pformat in both lines
2022-12-28 14:27:07 +01:00
5e44744ff7 Update renderer.py
Updated (replace doesn't work on sets)
2022-12-28 13:49:52 +01:00
37b293fe74 Force full precision on NVIDIA T400 2022-12-28 17:46:24 +05:30
280f0be690 Disable symlink warnings on Windows for huggingface cache 2022-12-28 16:48:12 +05:30
183bc8321c Convert [ to \[ so the logging backend...
doesn't interpret that as a colour or other command
2022-12-28 10:43:39 +01:00
a973e4d1ef version 2022-12-28 14:30:01 +05:30
eed1066967 Merge pull request #714 from patriceac/patch-7
Default to 4x in taskConfig when factor not present in task
2022-12-28 13:09:27 +05:30
2859c94fea Applying Madrang's suggestion 2022-12-27 23:36:43 -08:00
dbcce2ee5d Default to 4x in taskConfig 2022-12-27 23:27:25 -08:00
25071c238c Remove the width for better formatting (uses what Bonsi suggested in the first place) 2022-12-27 21:14:31 +05:30
9995ffb5f3 Merge pull request #711 from jsuelwald/patch-1
Update renderer.py for better readable console output
2022-12-27 21:11:44 +05:30
c867c35e45 Update renderer.py 2022-12-27 16:23:36 +01:00
6f60e88ca6 Update renderer.py for better readable console output 2022-12-27 15:41:10 +01:00
11730dcbe4 changelog 2022-12-27 17:07:43 +05:30
e155bac445 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-27 17:06:55 +05:30
15a4682665 Fix broken drag-and-drop for text files and clipboard paste 2022-12-27 17:06:46 +05:30
08675b39f7 Merge pull request #710 from patriceac/image-modifiers-events
Adding image modifier events to core plugins
2022-12-27 16:39:11 +05:30
2c7d5adb80 Adding image modifier events to core plugins
Sorry, forgot these in the first PR.
2022-12-27 02:58:46 -08:00
51c7faee3c Changelog 2022-12-27 16:23:57 +05:30
852e129f9c Support upscaling by 2x or 4x (previously only supported 4x) 2022-12-27 16:20:16 +05:30
6eb2d800fa Tweak low GPU wording 2022-12-27 14:58:08 +05:30
0a2c70595d Turbo be gone 2022-12-27 14:51:03 +05:30
f13e16af15 Disable unused config for now 2022-12-27 12:21:51 +05:30
f364958c13 Merge pull request #705 from patriceac/fix-cut-off-tooltips-display
Fix cut off tooltips display
2022-12-27 10:26:46 +05:30
e65150647d Merge pull request #708 from patriceac/patch-6
Add icon to "Process newest jobs first" setting
2022-12-27 10:25:45 +05:30
3c435b9593 Merge pull request #707 from patriceac/image-modifiers-events
Adding image modifiers events
2022-12-27 10:25:20 +05:30
871b96a450 Add icon to "Process newest jobs first" setting 2022-12-26 19:10:37 -08:00
48a3254ad2 Adding image modifiers events
Adding events to allow plugins to listen for image modifiers loaded and refreshed events respectively.
2022-12-26 12:16:36 -08:00
2c0bdd6377 Fix cut off tooltips display 2022-12-26 10:04:36 -08:00
8cedeb349d Changes to allow rolling back from the upcoming sdkit-based system 2022-12-26 23:04:45 +05:30
e241ef25e5 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-26 21:00:57 +05:30
5e553dd958 Skip sdkit upgrade if in developer mode 2022-12-26 21:00:46 +05:30
19ee87d2cd Merge pull request #692 from JeLuF/remove-result
Add "Remove" button to each image's hover menu (Fixes #682)
2022-12-26 17:38:00 +05:30
72b3598687 Merge pull request #703 from JeLuF/patch-5
Bring back Linux download link
2022-12-26 17:36:43 +05:30
33b120f6cd Merge pull request #702 from patriceac/fix-copy-to-clipboard
Fix copy image settings to clipboard
2022-12-26 16:25:44 +05:30
0bfb9d00c8 Fix copy image settings to clipboard
Regression was caused by the processing of the legacy turbo field, which I understand to now be obsolete.
2022-12-26 02:10:36 -08:00
b1a2d36c2d Bring back Linux download link 2022-12-26 10:16:43 +01:00
517ddca22d Changelog 2022-12-26 13:12:56 +05:30
41c7b08418 Keep euler_a as the default 2022-12-26 11:59:44 +05:30
c7c1b5a570 changelog 2022-12-25 17:18:31 +05:30
87b6dfb1a9 Changelog 2022-12-25 17:17:10 +05:30
46c56f3706 Use a model config yaml file if placed next to the model (with the same name). This can override a known model as well 2022-12-25 17:07:00 +05:30
32bab80508 Show sdkit version during startup 2022-12-25 16:38:37 +05:30
b6f1194c93 Typo 2022-12-25 00:23:51 +05:30
206f9b97bb Merge pull request #695 from cmdr2/refactor
v2.5 - move to sdkit
2022-12-24 23:28:10 +05:30
13721f160e changelog grammar 2022-12-24 23:22:47 +05:30
102e5623f7 Merge branch 'beta' into refactor 2022-12-24 23:14:02 +05:30
9a975321db v2.5 changelog 2022-12-24 23:11:13 +05:30
6743ec14f1 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-24 22:17:31 +05:30
daec5e5426 Changes to allow rolling back from the upcoming sdkit-based system 2022-12-24 22:17:16 +05:30
a2b55c0df7 Report precision 2022-12-24 21:44:42 +05:30
01320ac735 Rename project to Easy Diffusion 2022-12-24 21:36:47 +05:30
84bddee2ce Treat none as a boolean false in drag-and-drop 2022-12-24 19:41:36 +05:30
e636dd3649 Merge pull request #694 from cmdr2/beta
Beta
2022-12-24 19:18:28 +05:30
5f6b798e35 Stop printing annoying ok messages 2022-12-24 19:13:17 +05:30
9137f3793e Merge pull request #693 from madrang/mobile-fixes
Add a debounce delay to allow mobile to bouble tap.
2022-12-24 15:53:31 +05:30
73e92a688f color logging 2 2022-12-24 15:43:06 +05:30
7a9f219037 color logging 2022-12-24 15:41:19 +05:30
a4728190c0 Refactor server.py 2022-12-24 15:29:49 +05:30
04d67a24b6 Don't allow the results to be collapsed when clicking draghandle 2022-12-24 04:55:28 -05:00
55049ba9d2 Add a debounce delay to allow mobile to bouble tap. 2022-12-24 04:42:43 -05:00
e0b33a4feb Install rich 2022-12-24 15:10:46 +05:30
fb5c0a3db7 Install python 3.8.5 during installation. Torch isn't available for 3.11 2022-12-24 14:57:57 +05:30
8154a5709b disable the legacy src and ldm folder (otherwise this prevents installing gfpgan and realesrgan) 2022-12-24 14:01:33 +05:30
3a6780bd50 Copy check_modules.py the first time an existing user runs the new version 2022-12-24 13:56:05 +05:30
b7a76d4212 Merge branch 'beta' into refactor 2022-12-24 13:45:53 +05:30
ba7cae683a Bump to 2.5 2022-12-24 13:39:28 +05:30
243556656e Temporarily disable the model config dropdown in the UI 2022-12-24 13:38:55 +05:30
6662dc66d5 Updated scripts to install sdkit into existing installations, while still working with new installations 2022-12-24 13:37:50 +05:30
107112d1c4 Integration bugs 2022-12-24 12:37:20 +05:30
4eae540086 Add "Remove" button to each image's hover menu 2022-12-24 01:02:38 +01:00
21108650f7 add findClosestAncestor
Function to find the closest ancestor of an element that matches the selection criterion
2022-12-24 00:58:52 +01:00
c5d343750c Merge pull request #691 from JeLuF/patch-4
Avoid guidance scale "1.0"
2022-12-23 17:55:41 +05:30
09b76dcd93 Avoid guidance scale "1.0"
Using a guidance scale of 1.0 will cause an exception in the renderer and return a very confusing error message.
https://discord.com/channels/1014774730907209781/1028195513377509376
2022-12-23 13:18:08 +01:00
b87bc033f5 Merge pull request #690 from cmdr2/beta
Update CHANGES.md
2022-12-23 11:26:42 +05:30
fb95d76e34 Update CHANGES.md 2022-12-23 11:26:14 +05:30
4e765a7948 Merge pull request #689 from cmdr2/beta
Speed up image creation, by removing a delay (regression) of 4-5 seconds between clicking Make Image and calling the server
2022-12-23 11:25:14 +05:30
cf2408013e Measure the click-to-render-request latency, only if the click button was used 2022-12-23 10:54:40 +05:30
d8543d1358 Use the sdkit model scan; Disable scan-per-load since we scan them before allowing them to be invoked 2022-12-22 16:47:59 +05:30
d8b79d8b5c Don't crash if IP listing fails. Thanks @JeLuf 2022-12-22 15:43:52 +05:30
c2bcf89f9a Merge branch 'beta' into refactor 2022-12-22 15:42:04 +05:30
5cb24f992c Bump version 2022-12-22 15:23:07 +05:30
21394b7d45 Reduce the delay between clicking 'Make Image' and making the render call to the server. Was nearly 4-5 seconds, now it's about 250-300ms. This is a hacky workaround until a better solution is found 2022-12-22 15:22:25 +05:30
6d08082693 Merge branch 'beta' 2022-12-22 13:43:50 +05:30
768fb2583a Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-22 13:43:09 +05:30
6e07b2354f Fix an unnecessary error when a task header is clicked 2022-12-22 13:42:47 +05:30
00597879bc Merge pull request #688 from cmdr2/beta
Update CHANGES.md
2022-12-22 13:26:15 +05:30
0cd0d6aadf Update CHANGES.md 2022-12-22 13:25:57 +05:30
9d201f82f1 Merge pull request #687 from cmdr2/beta
Undo/redo buttons in the image editor, Drag handle to reorder tasks, Pause button to pause all the tasks
2022-12-22 13:23:50 +05:30
d6c535c45c Merge branch 'main' into beta 2022-12-22 13:23:07 +05:30
babdb5b718 Prompt Matrix is in main 2022-12-22 12:26:32 +05:30
0ea8d038be Merge pull request #679 from SpecificKnot/main
Changes to Front Docs
2022-12-22 12:25:48 +05:30
c804a9971e Work-in-progress code for adding a model config dropdown in the UI. Doesn't work yet 2022-12-22 11:54:00 +05:30
4d7f6e4236 Change version number in beta 2022-12-22 10:32:40 +05:30
5474d1786f updated inpainter to not auto-clear itself whenever you draw etc 2022-12-21 16:35:03 -08:00
7f36473544 added a fill action 2022-12-21 16:20:07 -08:00
9d19698bf3 fixed opacity on inpainter to be 100% by default so no weird erasing 2022-12-21 16:09:56 -08:00
582b2d936f fixed theme css properties not being updated properly 2022-12-21 16:03:52 -08:00
6036ccdc1c Style Adjustments
Made a few adjustments to fit the needs of the project for new users.
2022-12-20 12:44:48 +00:00
5eeef41d8c Update to use the latest sdkit API 2022-12-20 15:16:47 +05:30
bacf266f0d Merge pull request #651 from madrang/release-notes
Update 'release-notes' to use loadScript
2022-12-20 10:21:07 +05:30
ba5c54043b Merge pull request #680 from AssassinJN/beta
Drag and Drop Styles
2022-12-20 10:19:30 +05:30
e33c858829 Merge pull request #1 from JeLuF/AJNdrag
Only activate the dragOver event listener when dragging tasks
2022-12-19 14:39:27 -05:00
e47e54de3f Only activate the dragOver event listener when dragging tasks 2022-12-19 20:34:06 +01:00
54f9e9bfe9 adding drag and drop styles
Add functions required for adding styles to imageTaskContainer to show where images will be dropped.
2022-12-19 13:45:42 -05:00
e1875c872c classes for drag and drop
Added classes for drag and drop.
2022-12-19 13:44:15 -05:00
27b8e173e8 Changes to Front Docs 2022-12-19 14:28:05 +00:00
47e3884994 Rename the python package name to easydiffusion (from sd_internal) 2022-12-19 19:39:15 +05:30
e483071894 Rename diffusionkit to sdkit; Delete runtime.py (historic moment) 2022-12-19 19:27:28 +05:30
af090cb289 Update README.md 2022-12-19 12:24:19 +05:30
9bbb25f16c Update README.md 2022-12-19 12:23:32 +05:30
3007f00c9b Update README.md 2022-12-19 12:22:27 +05:30
352dcfbe30 Update README.md 2022-12-19 12:20:46 +05:30
60b181a545 Update README.md 2022-12-19 12:11:01 +05:30
600482e2d7 Update README.md 2022-12-19 12:10:15 +05:30
39ccbbd72e Update README.md 2022-12-19 12:09:13 +05:30
6e69cbcdaf Merge pull request #674 from SpecificKnot/main
Simplified README
2022-12-19 11:55:04 +05:30
bf6c222a3b Merge pull request #641 from JeLuF/pause
Pause button
2022-12-19 11:52:55 +05:30
6afcf7570a Merge pull request #671 from patriceac/allow-empty-prompts
Allow empty prompts (image modifiers only)
2022-12-19 11:50:18 +05:30
c3126f7b4d Merge pull request #673 from jsuelwald/patch-1
Change time display on job
2022-12-19 11:48:38 +05:30
cb3b542363 Merge pull request #675 from JeLuF/drag
Add drag handle
2022-12-19 09:36:44 +05:30
1a5e15608c Merge pull request #676 from JeLuF/ipfix
Return empty list if hostname lookup fails
2022-12-19 09:14:40 +05:30
64a751ad79 Merge branch 'beta' into pause 2022-12-19 00:55:56 +01:00
57efe31959 Return empty list if hostname lookup fails 2022-12-19 00:42:48 +01:00
39350d554b Remove old code 2022-12-19 00:32:13 +01:00
8f4e03550c Add drag handle 2022-12-19 00:14:57 +01:00
d03823fb20 Last minute changes 2022-12-18 21:16:32 +00:00
00ec2b9d6f README Updates
Updates to README to make it easier to follow along.
2022-12-18 21:13:12 +00:00
70e4bc4582 Update README.md 2022-12-18 20:52:38 +00:00
5e56a437ef Update README.md 2022-12-18 20:48:19 +00:00
22ffd25619 Change time display on job
Change "Processed 1 image in 150.65 seconds" to "Processed 1 Image in 2 minutes 30 seconds" to be consistent with the approx. time remaining while rendering
2022-12-18 07:20:42 +01:00
127949c56b Allow empty prompts (image modifiers only)
Allows empty prompts as long as there are image modifiers. This allows the user to craft prompts just by using image modifiers if they so wish.
2022-12-17 17:06:07 -08:00
cdfef16a0e Merge pull request #670 from patriceac/collapsible-toggle-event
Fire an event when a collapsible is toggled
2022-12-17 16:49:51 +05:30
1595f1ed05 Add 6 new samplers; Fix a bug where new tasks wouldn't started if a previous task was stopped 2022-12-17 16:45:43 +05:30
1cae39b105 Fire an event when a collapsible is toggled
Need an event to know that a collapsible got toggled to be able to resize the panels accordingly. Thanks!
2022-12-17 03:05:43 -08:00
8189b38e6e Typo in decoding live preview images 2022-12-17 15:59:09 +05:30
c240d6932a Update CHANGES.md 2022-12-17 10:13:23 +05:30
c4548d9396 Merge pull request #669 from JeLuF/hover
CSS only initimg hover, 'use as input' button
2022-12-17 09:50:46 +05:30
aea70e3dd4 Merge pull request #668 from JeLuF/imgedit
Fix img resize issues, add redo/undo buttons
2022-12-17 09:50:07 +05:30
3b01e65e11 CSS only initimg hover, 'use as input' button 2022-12-17 01:30:30 +01:00
341c810bbb Fix img resize issues, add redo/undo buttons 2022-12-17 00:29:54 +01:00
85fd2dfaaa Merge pull request #664 from patriceac/tab-change-trigger
Fire an event upon tab change
2022-12-16 18:24:10 +05:30
bf4bc38c6c Merge pull request #662 from JeLuF/patch-7
Linux uses .zip, not .tar.xz (Fixes #657)
2022-12-16 18:23:44 +05:30
aa8b50280b Remove the test_sd2 flag, the code now works with SD 2.0 2022-12-16 15:31:55 +05:30
62553dc0fa Fire an event upon tab change
Fire an event upon tab change.
2022-12-16 01:45:58 -08:00
25639cc3f8 Tweak Memory Usage setting text; Fix a bug with the memory usage setting comparison 2022-12-16 14:11:55 +05:30
7982a9ae25 Change the performance field to GPU Memory Usage instead, and use the 'balanced' profile by default, since it's just 5% slower than 'high', and uses nearly 50% less VRAM 2022-12-16 11:34:49 +05:30
aa01fd058e Set performance level (low, medium, high) instead of a Turbo field. The previous Turbo field is equivalent to 'Medium' performance now 2022-12-15 23:30:06 +05:30
ef7e1575bd Linux uses .zip, not .tar.xz (Fixes #657) 2022-12-15 16:44:43 +01:00
fb075a0013 Fix whitespace 2022-12-14 16:53:50 +05:30
d1738baf44 Merge branch 'beta' into refactor 2022-12-14 16:53:23 +05:30
7eb29fa91b Fix: errors were overwritten by the time taken in the UI 2022-12-14 16:52:46 +05:30
34c00fb77f Fix: errors were overwritten by the time taken in the UI 2022-12-14 16:51:30 +05:30
7965318d9f Update task_manager.py 2022-12-14 16:49:59 +05:30
e73a514e29 Revert a recent change to task error reporting, seems unstable 2022-12-14 16:37:45 +05:30
35ff4f439e Refactor save_to_disk 2022-12-14 16:30:19 +05:30
12e0194c7f Allow None as the value type in dnd parsing 2022-12-14 16:30:08 +05:30
d1ac90e16d [metadata parsing] Support loading the flat JSON format saved by the next backend; Set the dropdown to None if the value is undefined or null in the metadata 2022-12-14 15:43:24 +05:30
7dc7f70582 Allow parsing .safetensors stable diffusion model path in the metadata parser 2022-12-14 10:34:36 +05:30
84d606408a Prompt is now a keyword in the new metadata format generated from diffusionkit 2022-12-14 10:31:19 +05:30
d103693811 Bug in the metadata generation - made an array of None 2022-12-14 10:22:24 +05:30
0dbce101ac sampler -> sampler_name 2022-12-14 10:21:44 +05:30
cb81e2aacd Fix a bug where the metadata output format wouldn't get sent to the backend 2022-12-14 10:18:01 +05:30
6cd0b530c5 Simplify the code for VAE loading, and make it faster to load VAEs (because we don't reload the entire SD model each time a VAE changes); Record the error and end the thread if the SD model fails to load during startup 2022-12-13 15:46:04 +05:30
35571eb14d Don't hang the task if something other than the renderer fails (e.g. model loading) 2022-12-13 12:03:34 +05:30
8e6102ad9a removeTask() 2022-12-13 12:03:30 +05:30
80bc80dc2c removeTask() 2022-12-13 12:02:43 +05:30
a483bd0800 No need to catch and report exceptions separately in the renderer now 2022-12-13 11:46:13 +05:30
47a39569bc Merge branch 'beta' into refactor 2022-12-13 11:45:43 +05:30
f00e1a92d8 Don't hang the task if something other than the renderer fails (e.g. model loading) 2022-12-13 11:44:20 +05:30
a289945e8e Merge pull request #654 from jsuelwald/beta
The exception should also mention dpm2
2022-12-12 21:05:03 +05:30
b750c0d7c3 The exception should also mention dpm2 2022-12-12 16:24:03 +01:00
a244a6873a Use the new 'diffusionkit' package name 2022-12-12 20:46:11 +05:30
ceff4f06c1 Merge branch 'beta' into refactor 2022-12-12 20:43:29 +05:30
0307114c8e Merge pull request #653 from cmdr2/beta
Don't collapse the task entry if 'Stop Task' is pressed
2022-12-12 19:56:49 +05:30
92030a3917 Don't collapse the task entry if 'Stop Task' is pressed 2022-12-12 19:56:27 +05:30
73ace121a4 Merge pull request #652 from cmdr2/beta
Beta
2022-12-12 19:49:21 +05:30
44d5809e46 Changelog 2022-12-12 19:46:13 +05:30
5c4e6f7e96 Tweak editor width 2022-12-12 19:42:43 +05:30
8c032579b8 Hide the hypernetwork strength slider if no hypernetwork model is selected; Support drag-n-drop for hypernetwork models 2022-12-12 19:31:59 +05:30
b53935bfd4 Revert "Scrolling panes (#632)"
This reverts commit e3184622e8.
2022-12-12 19:03:16 +05:30
d4db027cfa Move the hypernetwork options below the sampler settings; Whitespace fixes 2022-12-12 19:02:34 +05:30
27963decc9 Use the multi-filters API 2022-12-12 18:12:55 +05:30
25f488c6e1 Merge branch 'beta' into refactor 2022-12-12 15:47:13 +05:30
07bd580050 Typos 2022-12-12 15:44:22 +05:30
fb32a38d96 Rename sampler to sampler_name in the API 2022-12-12 15:21:02 +05:30
ac0961d7d4 Typos from the refactor 2022-12-12 15:18:56 +05:30
6b943f88d1 Set uvicorn log level to 'error' 2022-12-12 15:18:30 +05:30
4bbf683d15 Minor refactor 2022-12-12 14:41:36 +05:30
d0e50584ea Expose the metadata format option in the UI 2022-12-12 14:06:20 +05:30
b57649828d Refactor the save-to-disk code, moving parts of it to diffusionkit 2022-12-12 14:01:47 +05:30
1f44a283b3 Update 'release-notes' to use loadScript 2022-12-12 02:47:42 -05:00
9947c3bcfb Start timer to IDLE_COOLDOWN before idleEventPromise completes. (#649) 2022-12-12 11:12:11 +05:30
8faf6b9f52 Don't allow to make zero images, make at least one. (#647) 2022-12-12 11:11:33 +05:30
e45cbbf1ca Use the turbo setting if requested 2022-12-11 20:42:31 +05:30
1a5b6ef260 Rename runtime2.py to renderer.py; Will remove the old runtime soon 2022-12-11 20:21:25 +05:30
096556d8c9 Move away the remaining model-related code to the model_manager 2022-12-11 20:13:44 +05:30
97919c7e87 Simplify the runtime code 2022-12-11 19:58:12 +05:30
0aa7968503 Move color correction to diffusionkit; Rename color correction to 'Preserve color profile' 2022-12-11 19:34:07 +05:30
bd1bc78953 Use onIdle(), move pause button, quick resume without using the promise 2022-12-11 14:57:01 +01:00
6ce6dc3ff6 Get rid of the ugly copying around (and maintaining) of multiple request-related fields. Split into two objects: task-related fields, and render-related fields. Also remove the ability for request-defined full-precision. Full-precision can now be forced by using a USE_FULL_PRECISION environment variable 2022-12-11 18:16:29 +05:30
e6346775e7 Merge branch 'beta' into pause 2022-12-11 11:19:48 +01:00
d03eed3859 Simplify the logic for reloading gfpgan and realesrgan models (based on the request), using the code path used for the other model types 2022-12-11 14:14:59 +05:30
afb88616d8 Load the models after the device init, to let the UI load before the models finish loading 2022-12-11 13:30:16 +05:30
543f13f9a3 Tweak logging to increase the space available by 3 characters 2022-12-11 13:19:22 +05:30
af5c68051a Fix for the tooltips being cutoff (#636) 2022-12-11 12:59:23 +05:30
5b7cd11de8 Added support for Async events (#643)
* Added support for async events callbacks

* Don't fire IDLE event if the first callback hasn't completed execution.
2022-12-11 11:22:52 +05:30
d3c3496e55 Merge pull request #639 from madrang/newEngine
Check if window is defined. Not all JS execution environments have it.
2022-12-11 11:19:11 +05:30
c08c8b2789 Merge pull request #638 from JeLuF/initimg
show initimg in task list
2022-12-11 11:18:10 +05:30
069315e434 Merge pull request #642 from patriceac/patch-5
Fixing a typo
2022-12-11 11:16:24 +05:30
7e4ad83a1c Merge pull request #637 from madrang/mainjs_fixes
Fix (typeof stepUpdate !== 'object') not completing the task on stop.
2022-12-11 11:15:31 +05:30
400f9fd680 Merge pull request #635 from patriceac/patch-4
Store the auto-scroll checkbox setting in localStorage instead of using the auto-save framework
2022-12-11 11:06:19 +05:30
38951f5581 Pause button - check whether function is defined before calling it 2022-12-11 02:49:49 +01:00
b5329ee93d Fixing a typo
Yeah, I know... What can I say? I have my OCD too. 👀
2022-12-10 17:45:14 -08:00
c568bca69e Pause button 2022-12-11 02:31:23 +01:00
7b2be12587 Check if window is defined. Not all JS execution environments have it. 2022-12-10 18:26:48 -05:00
099fde2652 show initimg in task list 2022-12-10 17:17:37 +01:00
83e5410945 Fix (typeof stepUpdate !== 'object') not completing the task on stop. 2022-12-10 00:52:27 -05:00
b330c34b29 Fix auto-scroll setting management
After thinking about it, the auto-save toggle is meant for the *Editor* fields listed behind the Configure button. The auto-scroll toggle is not part of the Editor, and is more akin to a system setting, although it's placed in the main UI for convenience reasons related to its nature. As such, and especially considering it's a plugin, I lean towards decoupling auto-scroll from the auto-save settings, and just storing it independently.
2022-12-09 19:34:41 -08:00
e3184622e8 Scrolling panes (#632)
Decouple the editor and the preview panes. Scrollbars color updated as well as requested.
2022-12-09 23:11:39 +05:30
28f822afe0 Fix tags not being properly applied to prompt matrix (#610)
There is an issue on the beta where if you use pipe ( | ) in the prompt to make a prompt matrix, the optional prompts are only applied when the last prompt in the matrix is used.
2022-12-09 23:04:25 +05:30
a2af811ad2 Disable uvicorn access logging in favor of cleaner server-side logging, we already get all that info; Print the request metadata 2022-12-09 22:47:34 +05:30
cde8c2d3bd Use a logger 2022-12-09 21:30:18 +05:30
79cc84b611 Option to apply color correction (balances the histogram) during inpainting; Refactor the runtime to use a general-purpose dict 2022-12-09 19:39:56 +05:30
f1de0be679 Fix integration issues after the refactor 2022-12-09 17:50:33 +05:30
854e3d3576 Fix reading value from undefined. (#631) 2022-12-09 16:34:59 +05:30
dbac2655f5 Typo 2022-12-09 16:14:04 +05:30
0f656dbf2f Typo 2022-12-09 16:11:08 +05:30
3fbb3f6773 Use const 2022-12-09 16:09:10 +05:30
8820814002 Simplify the API for resolving model paths; Code cleanup 2022-12-09 15:45:36 +05:30
b40fb3a422 Model readme file write flag 2022-12-09 15:27:40 +05:30
aa59575df3 Remove unused patch files 2022-12-09 15:24:55 +05:30
accfec9007 Space 2022-12-09 15:22:56 +05:30
16410d90b8 Use the simplified model loading API in diffusion-kit; Catch and report exceptions while generating images 2022-12-09 15:21:49 +05:30
27c6113287 Support hypernetworks; moves the hypernetwork module to diffusion-kit 2022-12-09 13:29:06 +05:30
f4a6910ab4 Work-in-progress: refactored the end-to-end codebase. Missing: hypernetworks, turbo config, and SD 2. Not tested yet 2022-12-08 21:39:09 +05:30
bad89160cc Work-in-progress model loading 2022-12-08 13:50:46 +05:30
5782966d63 Merge branch 'beta' into refactor 2022-12-08 11:58:09 +05:30
ba2c966329 First draft of multi-task in a single session. (#622) 2022-12-08 11:12:46 +05:30
f8dee7e25f Add test sample to one of the plugin. (#626)
* Added test example from a plugin.

* Only load style if #news was created.
2022-12-08 10:57:50 +05:30
a8151176d7 SD 2.1 2022-12-08 10:04:33 +05:30
9ee0b7fe2e SD 2.1 2022-12-08 10:04:14 +05:30
fb6a7e04f5 Work-in-progress refactor of the backend, to move most of the logic to diffusion-kit and keeping this as a UI around that engine. Does not work yet. 2022-12-07 22:15:35 +05:30
bfdf487d52 SD2 models no longer need to be prefixed with 'sd2_' . The model loader now checks for a key that only SD2 models seem to have, to deduce which config file to use 2022-12-07 16:19:46 +05:30
b7aac1501d Don't show prompt strength when the app starts 2022-12-07 13:12:35 +05:30
273525e6f9 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-07 13:12:02 +05:30
064a4938c1 Don't show prompt strength when the app starts 2022-12-07 13:11:49 +05:30
182236e742 Hypernets mergefixes (#625)
* Add hypernetwork args definition in the engine.

* Add the values to reqBody

* Don't load hypernetwork.py with SD2 until it's compatible.
2022-12-07 12:35:36 +05:30
75cb052cca Paint editor - translucent mask, more brush size options 2022-12-07 12:28:28 +05:30
d4a378827f Paint editor - translucent mask, more brush size options 2022-12-07 12:27:40 +05:30
592d5e8c40 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-07 11:41:52 +05:30
733150111d Changelog 2022-12-07 11:41:36 +05:30
cbe91251ac Hypernetwork support (#619)
* Update README.md

* Update README.md

* Make on_sd_start.sh executable

* Merge pull request #542 from patriceac/patch-1

Fix restoration of model and VAE

* Merge pull request #541 from patriceac/patch-2

Fix restoration of parallel output setting

* Hypernetwork support

Adds support for hypernetworks. Hypernetworks are stored in /models/hypernetworks

* forgot to remove unused code

Co-authored-by: cmdr2 <secondary.cmdr2@gmail.com>
2022-12-07 11:24:16 +05:30
1283c6483d Use the reqBody exposed to events to allow plugins to change the request. (#620) 2022-12-07 09:34:04 +05:30
f24d3d69af Fix download pictures (#616)
Old link was broken. Apparently the "develop" branch was deleted.
2022-12-07 09:33:11 +05:30
7984327d81 Fixed tasks buttons by replacing the error with a warning when setting properties to undefined. (#618) 2022-12-06 21:49:05 +05:30
ef90832aea engine.js (#615)
* New engine.js first draft.

* Small fixes...

* Bump version for cache...

* Improved cancellation code.

* Cleaning

* Wrong argument used in Task.waitUntil

* session_id needs to always match SD.sessionId

* Removed passing explicit Session ID from UI.
Use SD.sessionID to replace.

* Cleaning... Removed a disabled line and a hardcoded value.

* Fix return if tasks are still waiting.

* Added checkbox to reverse processing order.

* Fixed progress not displaying properly.

* Renamed reverse label.

* Only hide progress bar inside onCompleted.

* Thanks to rbertus2000 for helping testing and debugging!

* Resolve async promises when used optionally.

* when removed var should have used let, not const.

* Renamed getTaskErrorHandler to onTaskErrorHandler to better reflect actual implementation.

* Switched to the unsafer and less git friendly end of lines comma as requested in review.

* Raised SERVER_STATE_VALIDITY_DURATION to 90 seconds to match the changes to Beta.

* Added logging.

* Added one more hook before those inside the SD engine.

* Added selftest.plugin.js as part of core.

* Removed a tests that wasn't yet implemented...

* Groupped task stopping and abort in single function.

* Added optional test for plugins.

* Allow prompt text to be selected.

* Added comment.

* Improved isServerAvailable for better mobile usage and added comments for easier debugging.

* Comments...

* Normalized EVENT_STATUS_CHANGED to follow the same pattern as the other events.

* Disable plugins if editorModifierTagsList is not defined.

* Adds a new ServiceContainer to register IOC handlers.

* Added expect test for a missing dependency in a ServiceContainer

* Moved all event code in it's own sub class for easier reuse.

* Removed forgotten unused var...

* Allow getPrompts to be reused be plugins.

* Renamed EventSource to GenericEventSource to avoid redefining an existing class name.

* Added missing time argument to debounce

* Added output_quality to engine.js

* output_quality need to be an int.

* Fixed typo.

* Replaced the default euler_a by dpm2 to work with both SD1.# and SD2

* Remove generic completed tasks from plugins on generator complete.

* dpm2 starts at step 2, replaced with plms to start at step 1.

* Merge error

* Merge error

* changelog

Co-authored-by: Marc-Andre Ferland <madrang@gmail.com>
2022-12-06 17:04:08 +05:30
9571b8addc Merge pull request #614 from cmdr2/beta
Beta
2022-12-06 16:18:24 +05:30
9601f304a5 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-12-06 16:17:55 +05:30
ff43dac2a7 Open the color box when the custom label is clicked 2022-12-06 16:17:45 +05:30
0a43305455 Merge pull request #613 from cmdr2/beta
Beta
2022-12-06 16:11:38 +05:30
54d8224de2 Update CHANGES.md 2022-12-06 16:09:58 +05:30
c9e34457cd Tweak text in editor 2022-12-06 15:39:27 +05:30
47c8eb304f Revert the button styling 2022-12-06 15:36:52 +05:30
2dd39fa218 Disable auto-save for the auto-scroll toggle, until a better way to save it is figured out. It currently breaks a few UI fields, since it calls initSettings() a second time 2022-12-06 15:20:31 +05:30
cb618efb98 Image Editor Updates (#612)
* fixed tools for image editor to be more modular and made cursor an actual cursor change

* fixed eraser cursor positioning

* updated opacity to not have a 100 option

* separated clear into an actions section

* added history support for image editor. ctrl-z and ctrl-y both work now

* removed extra console log debugging stuff

* updated buttons style

* updated the button ui on the main page as requested

* updated with a bunch of bugfixes
2022-12-06 13:56:51 +05:30
e7ca8090fd Make JPEG Output quality user controllable (#607)
Add a slider to the image options for the JPEG quality
For PNG images, the slider is hidden.
2022-12-05 11:02:33 +05:30
7861c57317 Safetensor support (Fixes #599) (#608)
* safetensors support
Add support for checkpoints in safetensors format: https://github.com/huggingface/safetensors

This format shall be safer than pickle files

* pip install safetensors
2022-12-05 10:59:48 +05:30
f701b8dc29 Simplify onUpscaleClick (#602)
* Simplified onUpscaleClick code.

* Updated fix with comment as to what it's fixing.

* Move the fix to enqueueImageVariationTask
2022-12-05 10:46:10 +05:30
bd10a850fa Fix upscaling when a source image is set (#593)
* Fix upscaling when a source image is set

If you have an image selected (img2img) then clicking Upscale on another unrelated image, the image for img2img is used and you get something very unexpected.

* Fix for img2img and mask gens
2022-12-03 22:25:14 +05:30
0f96688a54 Highlight artist modifiers when clicked (#596)
Artist modifiers, with the exception of Artstation (the first one), don't have the outline when selected. All the other modifiers, above or below, seem to work as intended

https://discord.com/channels/1014774730907209781/1014774732018683927/1048343258775949322
2022-12-03 22:18:57 +05:30
8eeca90d55 Fix weird scrolling when using a pen (#588)
With a pen, typing on a browser page, waiting a short moment, and then moving the pen scrolls the page.
Call event.preventDefault() to disable this default behaviour for events in the canvas area.
2022-12-02 14:40:21 +05:30
367e7f7065 Add dpm2 (#592)
* Move cond_stage_model to the right device

* Removed unused vars.

* Added 'dpm2'
2022-12-02 12:58:00 +05:30
ee19eaae62 Fix for RuntimeError, missing lines. (#591)
* Move cond_stage_model to the right device

* Removed unused vars.
2022-12-02 12:57:26 +05:30
8eb3a3536b Update on_sd_start.bat 2022-12-02 12:06:41 +05:30
cfd50231e1 Update on_sd_start.sh 2022-12-02 12:06:39 +05:30
1c8ab9e1b4 Temporarily set the display: flex style only on the image editor buttons 2022-12-01 16:59:12 +05:30
6094cd8578 Fix the 'load from file' button that had moved to the next line' 2022-12-01 16:10:20 +05:30
353c49a40b Bump version 2022-12-01 16:05:35 +05:30
277140f218 Image Editor (#574)
* started implementing hamunii's image editor, and added a hamunii theme

* fixed so active tab is main tab

* added some testing stuff for image ediotr

* re-implemented canvas drawing myself. just need to add layer stuff now

* moved everything to an image editor class and implement it so it actually works nicely now

* fixed a couple weird bugs and cleaned up the background image and sharpness stuff

* cleaned up a lot of stuff about the editor, added tools, buttons, made it mostly work in the current ui

* added inpainting support

* updated with more nice changes/updates to the inpainting and drawing editor

* made some more fixes and touchups to the image editor

* removed a bunch of semicolons

* remove old image inpainting system

* updated to work properly on mobile

* made a minor bugfix

* fixed img_size_box alignment

* Update index.html

Co-authored-by: cmdr2 <secondary.cmdr2@gmail.com>
Co-authored-by: cmdr2 <shashank.shekhar.global@gmail.com>
2022-12-01 16:01:09 +05:30
ca9413ccf4 Toggle image modifiers plugin (#558)
* Toggle image modifiers plugin

Right-click on image modifiers to temporarily turn them off without removing them. To quickly iterate and experiment with various combinations.

Please note this plugin required a minor tweak in getPrompts() to add support for image modifier inactive state.

* Fix tag matching

Co-authored-by: cmdr2 <secondary.cmdr2@gmail.com>
2022-12-01 15:10:36 +05:30
c9a0d090cb Merge pull request #569 from patriceac/Fix-seed-behavior
Tweak the seed behavior
2022-12-01 15:03:21 +05:30
1cd783d3a3 Merge pull request #534 from patriceac/Custom-modifiers-as-a-plugin
Custom modifiers as a plugin
2022-12-01 14:59:29 +05:30
1ead764a02 Merge branch 'beta' into Custom-modifiers-as-a-plugin 2022-12-01 14:57:39 +05:30
45f7b35954 Merge pull request #581 from patriceac/Hotfix-for-repeat-image-modifiers-handling
Hotfix for repeat image modifiers
2022-12-01 14:47:15 +05:30
6a41540749 Remove unused scripts from the previous installer 2022-12-01 14:44:20 +05:30
5b47da67f6 Merge pull request #582 from cmdr2/beta
Beta
2022-12-01 13:59:13 +05:30
292f68ff97 Typo in css path 2022-12-01 13:57:38 +05:30
3b554d881a Styling changes for the confirm dialog 2022-12-01 13:54:49 +05:30
40ebf468d3 Hotfix for repeat image modifiers
As per Discord conversation, this PR fixed the image modifiers behavior when a modifier appears more than once, and also fixes a regression introduced by ((weighted modifiers)).
2022-11-30 22:13:13 -08:00
4bc6e51862 Merge pull request #580 from JeLuF/patch-5
Add Quadro T2000 to force_full_precision list.
2022-12-01 10:35:32 +05:30
427861cf13 Add Quadro T2000 to force_full_precision list. 2022-12-01 00:59:12 +01:00
da3e7a2eb8 Fix the broken image close button 2022-11-30 21:14:18 +05:30
2979f04c82 Use socket.gethostname() instead of socket.getfqdn() 2022-11-30 20:17:18 +05:30
1949d8a50c Tweak modifiers help msg 2022-11-30 16:32:43 +05:30
ee66c799e0 Merge pull request #563 from patriceac/Mouse-wheel-behavior-fixes
Improved Mouse Wheel UX with Image Modifiers
2022-11-30 16:24:05 +05:30
7c50b8bf94 Merge branch 'beta' into Mouse-wheel-behavior-fixes 2022-11-30 16:22:45 +05:30
141ff74ece Merge pull request #557 from madrang/webmanifest
Added web manifest to allow installing the Url as a web app.
2022-11-30 16:19:04 +05:30
321e5f1ed6 Merge pull request #564 from patriceac/Fix-UI-display-when-removing-the-last-task
Fix UI display when removing the last task
2022-11-30 16:14:59 +05:30
6d131d9d8e Merge branch 'beta' into Fix-UI-display-when-removing-the-last-task 2022-11-30 16:14:28 +05:30
7e69b8eb31 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-30 16:11:22 +05:30
4e0b33e6a4 Merge pull request #566 from patriceac/Visual-feedback-on-buttons
Visual feedback on button click
2022-11-30 16:11:08 +05:30
54f7e6fcb8 SD2 fix - register buffer on the correct device 2022-11-30 16:05:06 +05:30
529169c4da Merge pull request #541 from patriceac/patch-2
Fix restoration of parallel output setting
2022-11-30 15:54:04 +05:30
a2c8c99215 Merge pull request #541 from patriceac/patch-2
Fix restoration of parallel output setting
2022-11-30 15:53:30 +05:30
e8bf3fd009 Merge pull request #542 from patriceac/patch-1
Fix restoration of model and VAE
2022-11-30 15:52:26 +05:30
465676e9ea Merge pull request #542 from patriceac/patch-1
Fix restoration of model and VAE
2022-11-30 15:51:31 +05:30
af53b57047 Changelog 2022-11-30 15:49:47 +05:30
54b5f75905 Rename auto-scroll to reflect its purpose 2022-11-30 15:47:24 +05:30
4348333497 Don't register listeners for an autosave setting, if they've already been registered 2022-11-30 15:45:30 +05:30
cc31110bcf Merge pull request #537 from patriceac/Generate-screen-layout
Auto-scroll plugin
2022-11-30 15:44:31 +05:30
f7c04bf7a6 bump version 2022-11-30 14:34:42 +05:30
029509ebad Unify IP info with devices, into a system_info table 2022-11-30 14:34:24 +05:30
65102bb64d Merge pull request #536 from JeLuF/serverip
Show network addresses in system settings
2022-11-30 14:00:18 +05:30
b96b55c5ce Merge branch 'beta' into serverip 2022-11-30 14:00:12 +05:30
1f5aba010e Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into webmanifest
# Conflicts:
#	ui/index.html
2022-11-30 03:29:46 -05:00
f0b3bea4e3 Also confirm before the 'Stop All' button acts; Tweak wording of confirm dialog 2022-11-30 13:54:42 +05:30
84fae2d9e0 Merge pull request #531 from JeLuF/confirm
Confirm 'Clear All' and 'Stop Task'
2022-11-30 13:48:14 +05:30
0b96fa112d Merge branch 'beta' into confirm 2022-11-30 13:47:08 +05:30
c64bcd23d3 Picklescanner is mandatory 2022-11-30 13:38:22 +05:30
efd9a22bb5 Merge pull request #530 from madrang/list-models
Scan model once as start, then only if changed.
2022-11-30 13:37:27 +05:30
159c3edfe3 Simplify the logic for toggling modifier cards, no need to loop through the cards, since we already have the card object in hand 2022-11-30 13:33:20 +05:30
f74fa8657b Merge pull request #518 from patriceac/patch-6
Fix duplicate custom modifiers activation states
2022-11-30 13:27:14 +05:30
648b142a4b Merge pull request #571 from madrang/tabs-css
Add a new css rule for screens smaller than 500px.
2022-11-30 13:24:38 +05:30
426f92595e Merge pull request #520 from madrang/fix-gfpgan
Fix the gfpgan fix for multi-gpu
2022-11-30 13:08:10 +05:30
82a8d9b644 Merge pull request #577 from cmdr2/beta
Beta
2022-11-30 12:19:44 +05:30
ff9430b8a2 Tabs to 4 spaces 2022-11-30 12:18:34 +05:30
2e69ffcb5e Merge pull request #576 from cmdr2/beta
v2.4.16 - Remove the use of git-apply
2022-11-30 12:12:17 +05:30
0ea38db7ef Show the SD 2.0 setting only to beta users 2022-11-30 12:05:46 +05:30
a69d4c279e Make seed field behavior deterministic
Copying the image settings while 'Random' is enabled would cause the seed to be randomized. This was misleading as what I see wasn't what I would get.
2022-11-29 19:04:42 -08:00
2706149399 Tweak left padding of editor panel 2022-11-29 15:27:13 +05:30
3d0cdc1cb6 Bump version 2022-11-29 13:32:29 +05:30
ac605e9352 Typos and minor fixes for sd 2 2022-11-29 13:30:08 +05:30
5432297691 Default to sd-v1-4 when trying to use a SD2 model with SD 1.4, and warn the user. This will eventually be unnecessary 2022-11-29 13:14:58 +05:30
e37be0f954 Remove the need to use yield in the core loop for streaming results. This removes the need to patch the Stable Diffusion code, which can be fragile 2022-11-29 13:03:57 +05:30
a99209b674 Add a new css rule for screens smaller than 500px. 2022-11-28 20:23:17 -05:00
cb02b5ba18 Merge pull request #567 from madrang/tabs-css
Improved tabs flow on small screens.
2022-11-28 18:27:29 +05:30
69f14edd80 Tweak the seed behavior
Update the seed *before* starting the processing, so interrupting the processing retains the seed being used for the batch being currently processed.

The idea behind that is that if I like the gen I'm currently seeing and want to build on top of it, I can create a new task with the same seed without having to wait for the current task to complete.
2022-11-28 01:19:31 -08:00
14714b950d Slight improvement of detection logic 2022-11-28 00:14:12 -08:00
13654cb8c0 Make on_sd_start.sh executable 2022-11-28 13:00:02 +05:30
00276228cf Make on_sd_start.sh executable 2022-11-28 12:59:33 +05:30
8583bb8d7b Improved tabs flow on small screens. 2022-11-27 20:37:20 -05:00
d48951fe00 Visual feedback on button click
When there are too many tasks and the top of the list is not visible, there is no visual feedback that a task has been successfully added to the queue.

Adding a subtle visual feedback on buttons upon click to reflect that the mouse event was taken into account.
2022-11-27 16:26:01 -08:00
99bdcfa0a5 Set theme-color from the current selected theme. 2022-11-27 15:49:54 -05:00
e64e1a92e6 Fix UI display when removing the last task
Clear All button properly shows the "welcome message", but Remove the last task would just result in a blank Preview pane.
2022-11-27 12:42:51 -08:00
e278e639a3 Fix removal of image modifiers with non-zero weights
Properly handles removal of image modifiers that had (((modifiers))) or [[[modifiers]]] updated at runtime.
2022-11-27 03:00:19 -08:00
c4bad5c454 Conciseness
Shortening the sentence.
2022-11-27 01:42:39 -08:00
da41a74efc Require Ctrl+Mouse Wheel for modifier weight adjustment
The current behavior is just too annoying, and scrolling the page is a much more frequent activity than tweaking the weights.
2022-11-27 01:35:47 -08:00
0dc970562a Reverting this unnecessary change 2022-11-26 18:27:04 -08:00
2d8401473d Revert "Update custom-modifiers.plugin.js"
This reverts commit e5c11ea214.
2022-11-26 16:57:54 -08:00
9c91f57b19 Added web manifest to allow installing the Url as a web app. 2022-11-26 15:51:26 -05:00
f14afcd129 Update README.md 2022-11-26 12:44:19 +05:30
5c1a3d82d7 Update README.md 2022-11-26 12:23:03 +05:30
e02a917569 Improved logic for auto-scroll toggle insertion
Updating the insertion logic to prepare for future UI improvements.
2022-11-25 22:51:49 -08:00
347fa0fda1 Update on_sd_start.bat 2022-11-26 01:50:30 +05:30
6510d4cb02 Merge pull request #553 from cmdr2/revert-552-beta
Revert "Patching patch again"
2022-11-26 01:45:57 +05:30
91e4ccf6f8 Update on_sd_start.bat 2022-11-26 01:43:41 +05:30
36249874bc Revert "Patching patch again" 2022-11-26 01:42:16 +05:30
d2b5d6cce9 Merge pull request #552 from jsuelwald/beta
Patching patch again
2022-11-26 01:40:02 +05:30
b2922741c9 Patching patch again 2022-11-25 21:06:19 +01:00
300f3e27db Merge pull request #551 from cmdr2/revert-549-patch-2
Revert "Update ddim_callback_sd2.patch"
2022-11-26 01:25:17 +05:30
d7330b80a9 Revert "Update ddim_callback_sd2.patch" 2022-11-26 01:22:35 +05:30
acdd7667b7 Merge pull request #549 from jsuelwald/patch-2
Update ddim_callback_sd2.patch
2022-11-26 01:19:08 +05:30
8114fa3f5d Update ddim_callback_sd2.patch 2022-11-25 20:46:24 +01:00
4bc5508f38 Rollback 2022-11-26 01:07:55 +05:30
e503c6092e Ddim decode for img2img 2022-11-26 00:55:39 +05:30
6a8985d8dd Update ddim_callback_sd2.patch 2022-11-26 00:49:15 +05:30
bee67fd883 Shape 2022-11-25 23:54:08 +05:30
a1d75d40aa Update runtime.py 2022-11-25 23:36:43 +05:30
29484867ca Typo 2022-11-25 23:32:56 +05:30
7fa983b971 Img2img sd2 attempt 2 2022-11-25 23:28:31 +05:30
617a8b2814 Fix for make_schedule error in sd2 2022-11-25 23:15:22 +05:30
b924d323d4 img2img attempt for sd2 2022-11-25 22:36:02 +05:30
a2efda41d3 Cleaning up the code 2022-11-25 03:50:47 -08:00
642c114501 Working txt2img 2022-11-25 14:29:24 +05:30
02dd3e457d Tweaks to load sd1 models in sd2 code, typos 2022-11-25 13:57:15 +05:30
ea7b28c9d5 Placeholder changes for SD 2.0 support, haven't tested yet 2022-11-25 12:17:44 +05:30
472ab4a9ce Fix restoration of parallel output setting 2022-11-24 14:15:27 -08:00
fca84e3edf Fix restoration of model and VAE
😅
2022-11-24 13:47:35 -08:00
b70235ff92 Set the PYTHONPATH in the developer console, before the prompt shows up 2022-11-24 11:48:27 +05:30
6eff591df7 System settings to disable the 'Are you sure?'-dialogs 2022-11-23 23:05:30 +01:00
d0b2bf736e Auto-scroll off by default 2022-11-23 03:23:51 -08:00
e5c11ea214 Update custom-modifiers.plugin.js
Removing the redundant initialization of the array.
2022-11-23 03:00:19 -08:00
6b6443406d Create Autoscroll.plugin.js 2022-11-23 02:57:07 -08:00
3452d7852a Merge branch 'beta' into serverip 2022-11-23 11:28:05 +01:00
f1fa10badd Show network addresses in system settings
Users sometimes struggle to get the IP address of their PC. This PR adds a button to the system settings pane that will list the server's IP
addresses.
2022-11-23 11:25:36 +01:00
1267621424 Merge pull request #535 from cmdr2/beta
Switch to new custom backend
2022-11-23 15:09:09 +05:30
8a0ec95fe1 Merge branch 'main' into beta 2022-11-23 15:08:34 +05:30
ba30a63407 Update custom-modifiers.plugin.js
Add a carriage return at the end
2022-11-22 23:07:44 -08:00
c56a2adbcb Custom modifiers as a plugin 2022-11-22 19:04:20 -08:00
2de96d4dc9 Scan model once as start, then only if changed. 2022-11-22 20:41:08 -05:00
a486f20892 Merge branch 'beta' into confirm 2022-11-22 21:33:18 +01:00
49535deb2e Confirm 'Clear All' and 'Stop Task'
Ask for a confimation before clearing the results pane or stopping a render task. The dialog can be skipped by holding down the shift key while clicking on the button.
2022-11-22 21:27:36 +01:00
7cbf62cf12 Revert whitespace fix 2022-11-22 23:30:03 +05:30
3b0ace3410 Revert whitespace fix 2022-11-22 23:27:46 +05:30
5a9c8e1d87 Warn but don't fix whitespaces in a patch 2022-11-22 23:21:11 +05:30
daaa65dc0a Warn but don't fix whitespaces in a patch 2022-11-22 23:20:24 +05:30
ab4e371524 Fix whitespace during git apply 2022-11-22 22:25:36 +05:30
927fd304b0 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-22 22:22:07 +05:30
5af84b8e90 Fix whitespace during git apply 2022-11-22 22:21:54 +05:30
d425dac499 Merge pull request #529 from madrang/dragNdrop
Fixing file drag and drop.
2022-11-22 21:57:34 +05:30
d056459e76 Merge pull request #529 from madrang/dragNdrop
Fixing file drag and drop.
2022-11-22 21:56:07 +05:30
3169485f33 Fixing file drag and drop. 2022-11-22 11:11:06 -05:00
d9b9f80a93 diffusion-kit upgrade 2022-11-22 17:39:51 +05:30
d429505b71 Update version of diffusion-kit 2022-11-22 17:14:20 +05:30
72ee708917 Remove the need to install realesrgan, gfpgan and certain specific package versions, since the new backend should install them directly 2022-11-22 16:50:10 +05:30
93bbfac29a Change the backend to a custom fork of SD, since basujindal's fork is no longer under development. This fork is intended to include the common models/tools used like RealESRGAN, GFPGAN, Codeformer etc, and is meant to be a community-developed project 2022-11-22 16:38:39 +05:30
040d7a6563 Merge pull request #528 from patriceac/patch-1
Add support for custom modifiers to d&d and clipboard
2022-11-22 16:06:26 +05:30
e8dd930a50 Add support for custom modifiers to d&d and clipboard
Add support for custom modifiers to d&d and clipboard and remove now-redundant code in restoreTaskToUI.
2022-11-22 00:06:43 -08:00
31c049ebfe Version css 2022-11-22 11:09:01 +05:30
d343a37fb2 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-22 11:08:07 +05:30
7097175c6f CSS tweak for logo and version 2022-11-22 11:07:50 +05:30
8e57c49043 Merge pull request #527 from cmdr2/beta
Beta
2022-11-22 11:00:25 +05:30
9f036ceefd Merge branch 'main' into beta 2022-11-22 10:59:51 +05:30
ff3ca8b36b link to new downloads 2022-11-22 10:48:43 +05:30
87a7b70a27 Shell error code check 2022-11-22 10:40:20 +05:30
9c71c966ca Shell error code check 2022-11-22 10:39:47 +05:30
6dc99e676e Reduce the width of the editor sidebar, regression 2022-11-21 18:45:37 +05:30
80ecb82cc2 Reduce the width of the editor sidebar, regression 2022-11-21 18:42:07 +05:30
7fc9509d4d Nowarn for fresh installation (git apply whitespace) 2022-11-21 17:20:09 +05:30
3bf5e11f94 Nowarn for fresh installation (git apply whitespace) 2022-11-21 17:19:55 +05:30
eef9af2266 Typo 2022-11-21 17:14:54 +05:30
fabdf5fe30 Typo 2022-11-21 17:14:34 +05:30
1cc27e524b Don't warn about whitespace in the git patch application 2022-11-21 17:11:57 +05:30
8316a002da Don't warn about whitespace in the git patch application 2022-11-21 17:11:38 +05:30
888c637f71 Merge pull request #432 from JeLuF/JeLuF-nsis
NSIS Installer
2022-11-21 16:30:49 +05:30
48b7d2587e bump version 2022-11-21 16:21:22 +05:30
923c889de8 Merge pull request #495 from madrang/pasteFix
Fix pasting in Firefox.
2022-11-21 16:15:24 +05:30
8ae575d67a Merge pull request #508 from patriceac/patch-4
Modifier weight via mouse wheel plugin
2022-11-21 16:10:23 +05:30
b51407486a Merge pull request #517 from patriceac/patch-5
Fix duplicate custom modifiers restoration
2022-11-21 16:05:17 +05:30
a689b34ed1 Merge pull request #506 from patriceac/patch-2
VAE support in Use Settings
2022-11-21 16:02:51 +05:30
aa98e60243 Merge pull request #507 from patriceac/patch-3
Modifier drag-and-drop plugin
2022-11-21 16:02:04 +05:30
c3bf767024 Merge pull request #525 from cmdr2/beta
Beta
2022-11-21 14:08:47 +05:30
b641f1a230 Bump version 2022-11-21 14:08:12 +05:30
9499685dda Check for enqueued tasks more frequently 2022-11-21 14:06:26 +05:30
80d23cbbbf Merge pull request #523 from cmdr2/main
Merge main
2022-11-21 12:43:23 +05:30
efa684c5e8 Merge pull request #522 from cmdr2/beta
v2.4.11 updates
2022-11-21 12:43:03 +05:30
2edf64985d Update CHANGES.md 2022-11-21 12:41:53 +05:30
5fe7807462 ERRORLEVEL is unreliable when conda is run 2022-11-21 12:38:46 +05:30
e96b9005ca Merge pull request #514 from JeLuF/checkinput
Prevent empty fields in make image request
2022-11-21 12:36:23 +05:30
8c29e735e7 Merge pull request #513 from JeLuF/ipconfig
CHANGE.md change for IP config
2022-11-21 12:35:15 +05:30
497e073a8c Merge pull request #480 from JeLuF/patch-3
Handle %TMP% and %TEMP%
2022-11-21 12:34:31 +05:30
d4ce54a3c2 Merge pull request #521 from JeLuF/patch-4
Add --whitespace=fix to git apply
2022-11-21 12:33:04 +05:30
de37a81902 Merge pull request #519 from JeLuF/relocate2
Rewrite easy_install.pth on each start
2022-11-21 12:15:15 +05:30
d6b8cb718a Merge pull request #519 from JeLuF/relocate2
Rewrite easy_install.pth on each start
2022-11-21 12:13:43 +05:30
ed435d2b72 Add --whitespace=fix also on Linux 2022-11-20 23:09:27 +01:00
2b1f8533b0 Add --whitespace=fix to git apply
For some users who have git preinstalled, `git apply` fails due to whitespace errors.

Aracon found that applying `--whitespace=fix` to the `git apply` invocation fixes the problem.
https://discord.com/channels/1014774730907209781/1036679816713359471/1037025435491516548

ryz confirmed that `--reject` wasn't needed for him to make it work, and this explanation from the "git apply" manpage suggests 
that we shouldn't include `--reject`:

> For atomicity, git apply by default fails the whole patch and does not touch the working tree when some 
> of the hunks do not apply. This option makes it apply the parts of the patch that are applicable, and leave 
> the rejected hunks in corresponding *.rej files.

After having a look at https://github.com/git/git/blob/master/apply.c, I think that they only check for `correct_ws_error` if they couldn't apply the patch. It doesn't impact 'normal' patching. If the patch can be applied, it will be done, and only if the apply fails, they'll check whether adding or removing WS might help. It should thus be save to be added and didn't produce any errors on my installation using SDUI-provided git.
2022-11-20 23:07:44 +01:00
0a21a69a9f Updated facexlib fix for usage on multi-gpu. 2022-11-20 13:04:22 -05:00
5ebc6b698c Rewrite easy_install.pth on each start
Fixes GFPGANer errors when the env has been moved.
2022-11-20 18:48:48 +01:00
cbc48e31e1 Fix duplicate custom modifiers activation states
Fixing activation state for custom modifier cards sharing the same tag where only one of the cards gets (de)activated.
2022-11-19 19:25:28 -08:00
577dd9048f Fix duplicate custom modifiers restoration
Fix for duplicate image modifiers when restoring a task in which several custom modifier cards share the same tag.
2022-11-19 19:21:36 -08:00
ae409dd0ec Prevent empty fields in make image request
Prevent render jobs to fail with HTTP 422 due to empty fields in the image settings.
https://discord.com/channels/1014774730907209781/1043481789706031215/1043481789706031215
https://discord.com/channels/1014774730907209781/1014774732018683927/1042768986871443516

minor change, no CHANGE.md entry
2022-11-19 21:00:41 +01:00
cde855e1dc Change note 2022-11-19 20:31:36 +01:00
adcd4368e7 Merge pull request #510 from JeLuF/ipconfig
Add network settings to the UI
2022-11-20 00:55:42 +05:30
8bcdb205ed Merge pull request #512 from cmdr2/beta
Use the correct device name when moving the model to cpu
2022-11-20 00:50:58 +05:30
2cf8b2a453 Use the correct device name when moving the model to cpu 2022-11-20 00:43:38 +05:30
6c156380f9 Add network settings to the UI
Allow users to choose the uvicorn port
Allow users to restrict uvicorn to only listen on localhost
2022-11-19 17:10:45 +01:00
369d0ee502 Modifier weight via mouse wheel plugin 2022-11-19 01:17:24 -08:00
4971a212e9 Modifier drag-and-drop plugin 2022-11-19 01:09:59 -08:00
2111a81d18 Proper PR for VAE support in Use Settings 2022-11-19 00:56:44 -08:00
6799b3d7da Merge pull request #505 from cmdr2/beta
v2.4.11
2022-11-19 13:54:55 +05:30
a3463274ee changelog 2022-11-19 12:02:52 +05:30
c10e773401 Speed up the model move, by using the earlier function to move modelCS and modelFS to the cpu 2022-11-19 11:53:33 +05:30
f7af259576 Scan only the model files (check by extension), minor refactoring of the
scanning code
2022-11-19 10:44:32 +05:30
87c6a54634 changelog 2022-11-18 21:11:59 +05:30
d03521bf12 Use as Input -> Use these settings 2022-11-18 21:11:34 +05:30
3eb1919c81 Fix the missing (beta) label next to the version number 2022-11-18 19:38:16 +05:30
e53d6dbd5c changelog 2022-11-18 19:33:34 +05:30
01d2db8e96 Changelog 2022-11-18 17:36:23 +05:30
b18c2aea05 Don't cache css and js files, it's really annoying after merging every PR to have to update the version number in index.html. Disabling this until we figure out a better way 2022-11-18 17:31:20 +05:30
a6e3c272e2 Tweak CSS for button press color 2022-11-18 17:14:58 +05:30
4000f98ba4 Merge pull request #490 from JeLuF/ui1
Visual feedback for the save button in the system settings
2022-11-18 17:10:04 +05:30
d06fd404ae Font size of negative prompt textbox 2022-11-18 17:09:42 +05:30
c6f0e19e2f Merge pull request #493 from JeLuF/negative
Textarea for negative prompts
2022-11-18 17:07:37 +05:30
462af9989a Merge pull request #491 from JeLuF/inst1
Fix typo in the installer's error messages
2022-11-18 17:07:06 +05:30
eedea2fdcd Bump version 2022-11-18 17:06:43 +05:30
9c3d946de0 Theme tweaks 2022-11-18 17:01:20 +05:30
ace3102601 Reduce the size of the toggle switches 2022-11-18 16:24:49 +05:30
48946100e9 Bump version 2022-11-18 16:21:12 +05:30
0067e46192 Merge pull request #501 from mdiller/mdiller_fancyswitches
Better Toggle Inputs & Updated Settings UI
2022-11-18 16:17:54 +05:30
921711a679 Don't crash if an invalid model file is beign scanned 2022-11-18 16:12:45 +05:30
32dfb765dd Bump JS version 2022-11-18 16:04:26 +05:30
8482f12909 Bump version 2022-11-18 16:03:15 +05:30
306a56124c Merge pull request #492 from JeLuF/scanner
Picklescan of model files
2022-11-18 16:02:23 +05:30
1f815d7562 Merge branch 'beta' into scanner 2022-11-18 16:01:50 +05:30
f25d35fad8 changelog 2022-11-18 15:55:53 +05:30
f74c57449e Cosmetic changes to Use Settings 2022-11-18 15:54:47 +05:30
a697bd935a Refactor the Use Settings code, and move that to the common restoreTask() function 2022-11-18 15:38:17 +05:30
ec294227bd Bump version 2022-11-18 15:14:35 +05:30
f67758eaf3 Bring back some styling that was removed accidentally by the PR merge 2022-11-18 14:58:21 +05:30
f7ed65d749 Bump version 2022-11-18 14:51:05 +05:30
7ffeb3964b Merge pull request #463 from patriceac/beta
Adding Use Settings
2022-11-18 14:40:04 +05:30
025d4df774 Don't crash if a VAE file fails to load 2022-11-18 13:11:48 +05:30
45086a4b6e updated hamunii theme name to gnomie 2022-11-17 22:25:55 -08:00
2db0023653 updated themes to work nicely with the new stuff 2022-11-17 20:15:39 -08:00
bfc21220a7 added hamunii theme 2022-11-17 18:13:08 -08:00
507491fbec added fancy switches and updated the ui of the settings tab 2022-11-17 17:58:09 -08:00
c890ef6917 Merge pull request #497 from cmdr2/beta
Beta
2022-11-17 13:40:26 +05:30
6756fb4fe7 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-17 13:39:40 +05:30
6c089c0a78 Link to Multi GPU wiki page 2022-11-17 13:39:29 +05:30
b2ab3f987c Merge pull request #496 from cmdr2/beta
v2.4.7
2022-11-17 13:20:20 +05:30
c99b2edf98 Update CHANGES.md 2022-11-17 13:17:20 +05:30
e052610184 Removed debugging log calls. 2022-11-17 02:45:09 -05:00
13f1725105 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-17 13:13:12 +05:30
f2367932e1 Style code tags in the What's New markdown 2022-11-17 13:13:01 +05:30
7e94ec986e Update CHANGES.md 2022-11-17 13:07:35 +05:30
7bda3e6994 Release summary and detailed changelog 2022-11-17 13:06:36 +05:30
3a18606385 Disable when targeting input elements. 2022-11-17 02:36:14 -05:00
e25a94e815 Bug fix, forgot to await promise. 2022-11-17 02:20:01 -05:00
c13f662e2d Use the document paste event for pasting json and text data. 2022-11-17 02:16:20 -05:00
97ee085f30 Fix a bug where Face Correction (GFPGAN) would fail on cuda:N (i.e. GPUs other than cuda:0), as well as fail on CPU if the system had an incompatible GPU. 2022-11-17 12:27:06 +05:30
1364fd5c45 Fix pasting in Firefox.
Should not display button.
https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText#browser_compatibility
2022-11-17 01:44:11 -05:00
cc3186a683 Highlight the Save settings button when pressed 2022-11-17 11:01:10 +05:30
0c93c4754d Tabs to spaces 2022-11-17 10:49:22 +05:30
7b4cfbeeaa Update CHANGES.md 2022-11-16 23:47:24 +01:00
8cebb53147 Textarea for negative prompts 2022-11-16 23:35:27 +01:00
3e18f2f09c Picklescan of model files
During getModel(), the server picklescans the model files for potential
malicious code in the pickled python objects. If a malicious file is
found, the web UI will show a big red error message, the makeImage
button will be disabled, and the user must remove the malicious file
and reload the UI page.
2022-11-16 22:34:02 +01:00
add09e52ef Fix typo in the installer's error messages 2022-11-16 20:56:11 +01:00
5429a509c6 Visual feedback for the save button in the system settings 2022-11-16 20:52:40 +01:00
3555fa36aa Update CHANGES.md 2022-11-16 19:40:33 +05:30
ee31519552 Merge pull request #489 from cmdr2/main
v2.4.6 - merge hotfix from main - bring back the VRAM usage (during startup) to what it was in the previous main version (v2.3.5)
2022-11-16 19:36:49 +05:30
06b41aee58 Fix - reduce the amount of VRAM occupied when the program starts up, this caused a regression and failures on GPUs with 4 gb or less of VRAM 2022-11-16 19:29:04 +05:30
cd19d50e1d Update CHANGES.md 2022-11-16 17:00:31 +05:30
a5e4eea5ca Smaller version numbers in CHANGES 2022-11-16 16:56:35 +05:30
c6a6270e16 Typo 2022-11-16 16:55:11 +05:30
18d9d2602a Add a 'What's New?' tab as a core plugin, which fetches the contents of CHANGES.md from the app's release branch 2022-11-16 16:54:28 +05:30
f7ec9f2073 Merge pull request #488 from JeLuF/beta
Add Change history
2022-11-16 16:05:24 +05:30
4c5f66185d Add Change history 2022-11-16 10:44:56 +01:00
105c1893cb Merge branch 'beta' of https://github.com/patriceac/stable-diffusion-ui into beta 2022-11-16 00:40:00 -08:00
061cee207f Delete modifiers-dnd.plugin.js 2022-11-16 00:39:41 -08:00
af4a925b54 Delete modifiers-dnd.plugin.js 2022-11-16 00:38:17 -08:00
a6f3e87921 Image modifiers drag-and-drop plugin 2022-11-16 00:35:02 -08:00
9764d9109f Merge remote-tracking branch 'upstream/main' into beta 2022-11-16 00:29:52 -08:00
46dfa57ee0 Allow the core project to ship UI plugins 2022-11-16 13:30:40 +05:30
2c861c65d4 Merge pull request #485 from cmdr2/beta
UI setting for preventing browser autostart
2022-11-16 12:45:51 +05:30
a59bac4b40 UI setting for preventing browser autostart 2022-11-16 12:43:46 +05:30
cf214bf367 Merge pull request #484 from cmdr2/main
Merge main
2022-11-16 12:29:09 +05:30
75724797f7 Don't show a 500 error when the config json file doesn't exist 2022-11-16 12:20:25 +05:30
d04aeb55ad Fix default render device 2022-11-16 12:16:46 +05:30
47bd6dc6b8 Fix render devices auto 2022-11-16 12:14:06 +05:30
5e0f525932 Merge pull request #483 from cmdr2/beta
v2.4.4
2022-11-16 12:10:01 +05:30
1f66daf2f3 Write the config script files only if necessary 2022-11-16 11:40:51 +05:30
ded9cb0358 Check if config contains update_branch before trying to write it to a script file 2022-11-16 11:36:04 +05:30
04f201933b space apart the stop button 2022-11-16 11:33:05 +05:30
f5ec1cb3a4 Don't show the list of files that have been copied on startup 2022-11-16 11:31:16 +05:30
6c23e3f534 Bump version 2022-11-16 11:19:42 +05:30
e99d54d1f6 Merge main 2022-11-16 11:19:10 +05:30
7f436061b8 RFC: how to handle %TMP% and %TEMP% - UNTESTED
`conda activate` fails if %TMP% or %TEMP% contains spaces. So instead of setting the temp variables in the installer steps, we need to set it at the beginning of the script. 

Would this break anything? 
https://discord.com/channels/1014774730907209781/1042190192049668106/1042190192049668106
2022-11-15 23:29:32 +01:00
3c71200eb4 Update index.html 2022-11-15 16:06:50 +05:30
f124cf8318 Make the task config summary labels bold 2022-11-15 16:06:35 +05:30
9d2b944063 Remove unused variable 2022-11-15 13:18:00 +05:30
8e1ec5903b Don't throw an exception when an invalid device is being checked for compatibility. Report and return false 2022-11-15 12:41:10 +05:30
5cf763d51f Add a 'Save' button in settings, to avoid starting/stopping threads while a user is still modifying their GPU settings 2022-11-15 12:22:55 +05:30
3546859fe5 Bump version 2022-11-15 11:05:39 +05:30
6530e45178 Merge pull request #478 from madrang/beta
Changed update_render_threads to use SetAppConfigRequest.
2022-11-15 11:04:52 +05:30
07f0036b2b Merge pull request #476 from JeLuF/patch-2
Incr. Server State Validtiy to 90s
2022-11-15 10:19:45 +05:30
5237f55a71 Removed extra line, use only save_render_devices_to_config 2022-11-14 22:29:55 -05:00
a108e5067d Typos in comments. 2022-11-14 22:20:21 -05:00
a4a24b1a1a Fixed calling get_device_delta with a single cuda device inside config.json at boot. 2022-11-14 22:14:03 -05:00
ffe0eb1544 Changed update_render_threads to use SetAppConfigRequest to set which devices are active.
Keep ImageRequest.render_device for affinity only. (Send a task to an already active device.)
2022-11-14 21:54:24 -05:00
288e8a65f3 Incr. Server State Validtiy to 90s
By default, healthCheck() is run every 5s. On background tabs, this may get extended. My tests have shown pings every 60s. The ping was older than 10s, so the condition in line 490 evaluates to `false` and the client tries to access the stream before the server is ready. By increasing the validity this can be avoided - at least until the browser runs the healthcheck even less often.

See https://discord.com/channels/1014774730907209781/1041811939380178964/1041812021018120262 for the analysis.
2022-11-14 23:18:03 +01:00
0ebfbca93e Merge pull request #475 from JeLuF/beta
🔥Fix system info for CPU mode
2022-11-14 22:41:38 +05:30
f22f57495e Fix system info for CPU mode 2022-11-14 17:55:36 +01:00
8786a9d21d Fix border color of the image task container 2022-11-14 21:25:57 +05:30
f06a97d30b Move system info into settings 2022-11-14 21:21:48 +05:30
2329c47faf Bump version 2022-11-14 21:13:38 +05:30
2967261acb Ensure that we only pick better GPUs than the current one, during the subsequent tasks 2022-11-14 21:13:24 +05:30
64ff1ecbb6 Formatting for mem free 2022-11-14 21:02:17 +05:30
8707f88c07 Show mem free info 2022-11-14 20:35:47 +05:30
36846618ec Allow configuring whether the browser is opened by default 2022-11-14 20:15:54 +05:30
0cb2f19e29 Mark multi GPU as experimental in the UI 2022-11-14 20:06:20 +05:30
125a50ae87 Include the gpu id in the gpu list and system info 2022-11-14 20:01:57 +05:30
9d37ea23f8 Bump version 2022-11-14 19:53:55 +05:30
31617ae340 Show a system info tab, which shows the active GPUs 2022-11-14 19:53:40 +05:30
950614fb81 Bump version 2022-11-14 19:42:57 +05:30
14bbd7b7ae Merge pull request #474 from JeLuF/beta
Add paste button next to copy button
2022-11-14 19:06:52 +05:30
257cd34101 Merge branch 'beta' into beta 2022-11-14 19:06:35 +05:30
ab6ec3a9b7 Fix - setting can be null sometimes (autosave) 2022-11-14 18:10:23 +05:30
39814a89b6 Fix - setting can be null sometimes (autosave) 2022-11-14 18:09:25 +05:30
24fbbf8aa8 Remove unused variables 2022-11-14 16:26:16 +05:30
338ceffa6d Use 'auto' as the default render_device 2022-11-14 15:14:58 +05:30
371e104b00 Pick the device id 2022-11-14 13:43:37 +05:30
d5aba8eaf1 Show free/total mem while starting up 2022-11-14 13:40:55 +05:30
1d2b3a4ed8 Hide/show the GPUs list depending on whether auto is selected 2022-11-14 13:14:33 +05:30
f904945d40 Disable the GPU list if auto is enabled 2022-11-14 13:02:36 +05:30
027b2e1b88 Use the 65 percentile of free_mem for GPU selection, instead of 75 percentile 2022-11-14 12:26:21 +05:30
d79eb5e1a6 Typo 2022-11-14 11:51:56 +05:30
f6651b03b5 Workaround to run gfpgan on cuda:0 even if it's not enabled in the multi-gpu setup 2022-11-14 11:51:18 +05:30
5f880a179c Remove idle CPU unloading (when GPUs are active), because now a CPU can never be used along with GPUs 2022-11-14 11:24:30 +05:30
ea03fd22db Start on multiple GPUs by default (top 75 percentile by free_mem); UI selection for 'cpu' or 'auto' or a list of specific GPUs, which is now linked to the backend; Dynamically start/stop render threads for the devices, without requiring a full program restart 2022-11-14 11:23:22 +05:30
e252c9ac05 Only set the userprofile if in a new micromamba installation 2022-11-14 10:11:28 +05:30
a212fb35c1 Merge pull request #469 from JeLuF/patch-1
set USERPROFILE to local profile (fixes #468)
2022-11-14 10:07:17 +05:30
e561e4de0b Visual feedback for the copy and paste icons 2022-11-14 01:58:24 +01:00
1c3d5cd851 Add paste button next to copy button 2022-11-14 01:23:04 +01:00
e59fbac761 set USERPROFILE to local profile (fixes #468)
According to this analysis: https://discord.com/channels/1014774730907209781/1040225028828057620/1040324719074889779
the USERPROFILE variable must not contain unicode characters as well. Only setting APPDATA is not sufficient.
2022-11-13 09:19:01 +01:00
332f2b0678 Hotfix for CSS layout regression 2022-11-12 19:04:23 -08:00
745ea5fb05 Update index.html 2022-11-12 17:39:29 +05:30
fa16ca4eec Update auto-save.js 2022-11-12 17:39:26 +05:30
d7757b8b03 Update index.html 2022-11-12 17:25:07 +05:30
98aefad249 Skip if a setting isn't present 2022-11-12 17:24:48 +05:30
a19ba40672 Typo 2022-11-12 13:31:59 +05:30
3983cb001f Save the VAE model to the metadata text file 2022-11-12 13:29:24 +05:30
c17222dbe4 The error level is unreliable on Windows when testing a command. My cmd.exe shell hooks are broken, and this condition always fails for me 2022-11-12 13:08:46 +05:30
abd8c69395 Bypass a bug in micromamba, where it fails silently if the APPDATA env variable has special characters like öäü 2022-11-12 13:07:29 +05:30
a7fde73df4 Tabs to spaces in bootstrap scripts 2022-11-12 12:47:39 +05:30
78b464b404 Merge pull request #464 from madrang/beta
Always return a byte buffer. Sending the picture as URL text fails in some browsers.
2022-11-12 11:51:52 +05:30
aa21115e26 Always return a byte buffer. Sending the picture as URL text fails in some browsers. 2022-11-11 20:44:39 -05:00
a39f845835 current_vae_path needs to be global 2022-11-11 19:30:33 +05:30
3fdd8d91e2 Handle device init failures and record that as an error, if the GPU has less than 3 gb of VRAM 2022-11-11 16:13:27 +05:30
c13bccc7ae Fix the error where a device named 'None' would get assigned for incompatible GPUs 2022-11-11 15:43:20 +05:30
b4f7d6bf25 Bump js version 2022-11-11 15:12:04 +05:30
fa0c2f7138 Temp change to get beta working and use a single GPU until the rest of the changes come through 2022-11-11 15:09:25 +05:30
453cc2a951 Bump version 2022-11-11 14:46:27 +05:30
bd56795c62 Switch to using cuda:N instead of N (integer device ids) 2022-11-11 14:46:05 +05:30
2c54b7f289 Remove the WIP line for render devices 2022-11-11 14:43:14 +05:30
cd5f847b55 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-11 12:03:14 +05:30
a25544baea Fix the editor width on Chrome 2022-11-11 12:02:58 +05:30
39b6c5d6f4 Merge remote-tracking branch 'upstream/beta' into beta 2022-11-10 22:30:28 -08:00
d1c9db874f Set the PYTHONPATH right at the start, to prevent it from picking up a system-wide python 2022-11-11 11:37:15 +05:30
f954542dda Merge pull request #461 from JeLuF/dontleave
Add event listener beforeunload
2022-11-11 10:58:15 +05:30
9fec7d236c Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-11 10:48:47 +05:30
67656accf8 Bump css version. This is annoying 2022-11-11 10:48:30 +05:30
64952a536c Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-11 10:47:52 +05:30
65e0d5f511 Attempt to fix horizontal resizing of the prompt textbox, thanks @Bilbo 2022-11-11 10:44:52 +05:30
903acff924 Adding Use Settings 2022-11-10 18:36:39 -08:00
5a06946469 Add event listener beforeunload
When closing the window, a warning is shown if there are any render results.
2022-11-10 23:23:20 +01:00
baef31b2c7 Send 'auto' as the render_device from the UI
, if no GPU is selected and CPU is unchecked)
2022-11-10 22:23:15 +05:30
b9a12d1562 Restrict device selection id to 'cpu' or integers (and 'auto' in the initial device selection functions) 2022-11-10 20:03:11 +05:30
3f26d03166 Show GPU list in the UI only if the PC has more than 1 GPU 2022-11-10 16:34:01 +05:30
1fed3ad532 Don't propagate events in the Stop Task button 2022-11-10 15:33:39 +05:30
929b245f5f Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-11-10 14:59:11 +05:30
0da6354825 Press Ctrl+Enter to start a task 2022-11-10 14:59:01 +05:30
716a28891d Merge pull request #460 from JeLuF/helppage
Add Wiki TOC to the Help&Community tab
2022-11-10 13:17:26 +05:30
93a2e91694 Use theme variable for bottom border design 2022-11-10 00:44:42 +01:00
4913dc1aad Replace hr by border-bottom 2022-11-09 23:57:48 +01:00
087df18fea Add Wiki links to help&community page 2022-11-09 23:42:56 +01:00
058ce6fe82 UI-side changes for selecting multiple GPUs, and keeping the Use CPU option synchronized with the backend. This change isn't ready to be shipped, it still needs python-side changes to support the req.render_device config 2022-11-09 19:17:44 +05:30
087c10d52d Sort models by name 2022-11-09 17:35:55 +05:30
18292e447c Make the models dir if required 2022-11-09 16:28:58 +05:30
6c1dda47c0 Don't change the page when something other than an image or text file is dropped into the page (or an image is dropped outside the init image box) 2022-11-09 15:21:41 +05:30
ad1fc8f3d8 Bump version 2022-11-09 13:47:21 +05:30
bca98269bb Fix a bug where the custom image modifiers button would close the modifiers panel 2022-11-09 13:46:50 +05:30
1bebaf933d Bring back the old style panels for image settings and modifiers 2022-11-09 13:43:43 +05:30
166eb996a9 Bump versions 2022-11-09 12:26:27 +05:30
10fae34754 Bump js/css versions 2022-11-09 12:25:16 +05:30
aa4d97e8df Merge pull request #458 from mdiller/mdiller_ui_reorganize
UI Reorganization & Adding Tabs
2022-11-09 12:22:38 +05:30
dbbb9d7877 Temporarily remove the default-on behavior for GFPGAN, until the CPU version is fixed 2022-11-09 11:25:50 +05:30
82fda5cb03 Temporarily remove the default-on behavior for GFPGAN, until the CPU version is fixed 2022-11-09 11:24:14 +05:30
3ff213b3e8 removed status on mobile 2022-11-08 21:51:12 -08:00
65587536ab Fix typo in binding of host/ip 2022-11-09 11:08:25 +05:30
ad31be8344 Fix 2022-11-09 11:05:07 +05:30
25815c81bf Bring back the configurable host/port 2022-11-09 11:03:03 +05:30
852a22f86d temporary rollback of configurable host/port 2022-11-09 10:58:25 +05:30
69c7f22053 Merge branch 'beta' into mdiller_ui_reorganize 2022-11-08 21:22:22 -08:00
75a964167a hid the now shown collapsible handle 2022-11-08 21:00:56 -08:00
c5768c81e1 Merge pull request #453 from patriceac/beta
Fix modifier and system settings popup position
2022-11-09 10:23:12 +05:30
4eb2b818e7 shrank system settings a bit so it fits on monible 2022-11-08 20:47:55 -08:00
f742aad810 Merge pull request #446 from JeLuF/sd-ui-bind
Protect SD_UI_BIND_PORT and SD_UI_BIND_IP in config files
2022-11-09 10:09:28 +05:30
e22b171b7b Merge pull request #445 from JeLuF/err-handle
Improve error handling
2022-11-09 10:08:55 +05:30
d061eb2c64 updated to work decently for mobile 2022-11-08 20:37:49 -08:00
69aa115178 updated the about tab to be help and community, and fixed footer to act nicely 2022-11-08 20:19:31 -08:00
e175b87384 updated so tabs work now, and we have a settings tab and an about tab 2022-11-08 19:54:41 -08:00
f216ee739a updated with latest updates for this support 2022-11-08 19:22:14 -08:00
16d6644573 Merge pull request #455 from JeLuF/util-js
Fix: Uncaught TypeError: Cannot set properties of null
2022-11-09 08:22:46 +05:30
38afc6e6f8 Fix: Uncaught TypeError: Cannot set properties of null 2022-11-08 19:05:28 +01:00
8f1d214b12 Bring back CPU unloading of models when idle for a while (applies only when GPUs are present) 2022-11-08 19:23:35 +05:30
51fb1a43de Temporarily disable the idle CPU unloading behavior, since it's not clear whether it'll reload the model if a future request for the CPU is received after it has unloaded the model 2022-11-08 19:02:21 +05:30
a86b6bfbd6 Fix a bug with drag-and-drop where the upscale dropdown would not get enabled/disabled based on the setting 2022-11-08 18:46:55 +05:30
1176ddcc85 Fix a bug in drag-and-drop where an empty Negative Prompt line would result in the next line getting assigned to negative prompts; Simplify the drag-and-drop text file parsing logic to use a single algorithm, the files are small enough that we don't need over-optimization and confuse new developers 2022-11-08 18:44:11 +05:30
fa080e380c Fix a bug where images could no longer be dragged and dropped onto the initial image box 2022-11-08 18:14:26 +05:30
57c3acd9d8 Single line comment for Live Preview 2022-11-08 17:51:51 +05:30
302cf5b10b Show a tooltip over the ? help buttons 2022-11-08 17:49:46 +05:30
e2a9e81dbc Show tooltips on 'Copy Image Settings' 2022-11-08 17:40:47 +05:30
b1cf7391ce Add links to help docs for certain UI elements 2022-11-08 17:19:20 +05:30
9bc7521de0 Make custom VAE an Image Setting, rather than a System Setting; Don't load a VAE into memory by default 2022-11-08 16:54:15 +05:30
a68ebd2b76 Fixing the popup position on larger screens
Fixing the popup position on larger screens; Smaller screens still get the current rendering experience.
2022-11-08 02:17:26 -08:00
47f7c938ae Update main.css 2022-11-07 23:15:59 -08:00
842e7e559e Update bootstrap.bat 2022-11-08 10:30:26 +05:30
bd5a6e6fb3 FS check, CV2.DLL fix, cleanup
- Only install on NTFS (FAT installations fail)
- Ask the user to install the Media Feature Pack on Windows 10 N (fixes python cv2 errors)
- Code cleanup
2022-11-08 00:20:36 +01:00
67cca3bc00 Print the devices for which rendering threads have started; Prettier print of the model data 2022-11-07 18:26:10 +05:30
90b1609d4e device_selection is already a string, since we've used string functions before this line 2022-11-07 18:08:43 +05:30
abbfae2fc0 Simplify the logic used for displaying the GFPGAN warning 2022-11-07 17:55:27 +05:30
b52b854270 Merge pull request #444 from madrang/beta
Remove prompt_strength and init_image when not using in-painting
2022-11-07 14:43:48 +05:30
58b759f652 Fix tabs to spaces 2022-11-06 16:50:23 +01:00
74ca756a53 Protect SD_UI_BIND_PORT and SD_UI_BIND_IP in config files 2022-11-06 00:27:11 +01:00
a62ee7850b Merge branch 'err-handle' of github.com:JeLuF/stable-diffusion-ui into err-handle 2022-11-05 23:31:19 +01:00
d3a90ccc0d Windows error handling
- cd to the script location on start of 'Start Stable Diffusion UI.cmd'
- Bail out when downloading micromamba fails
- add env variables SD_UI_BIND_IP and SD_UI_BIND_PORT to configure uvicorn
2022-11-05 23:30:40 +01:00
46b13ee664 Merge branch 'cmdr2:main' into err-handle 2022-11-05 20:49:19 +01:00
cfa6dc7836 Add blank lines to error message 2022-11-05 19:02:19 +01:00
f969bfa7be More error handling, central error function 2022-11-05 18:59:59 +01:00
3576214920 Remove prompt_strength and init_image when not using in-painting 2022-11-05 13:39:19 -04:00
f964fe3750 Add on/off support for parsing boolean. 2022-11-05 13:33:38 -04:00
e86a883d0a Merge pull request #439 from JeLuF/patch-9
Add a link to the wiki to the "Help & Community" dropdown.
2022-11-05 11:01:49 +05:30
82d764000a Fix https://github.com/cmdr2/stable-diffusion-ui/issues/441 - numerical validation 2022-11-04 19:54:59 +05:30
749c72e6a6 Fix https://github.com/cmdr2/stable-diffusion-ui/issues/441 - numerical validation 2022-11-04 19:48:34 +05:30
c3129a40f1 Merge pull request #440 from madrang/dragNdrop
Drag&Drop Fixes
2022-11-04 09:13:14 +05:30
d04aa89812 Fix 'Use Upscaling' dropdown getting blank on False. 2022-11-03 20:34:51 -04:00
d5f854d376 Fix use_face_correction not disabling on false 2022-11-03 20:34:12 -04:00
63dcb8cfe1 Add a link to the wiki to the "Help & Community" dropdown. 2022-11-03 20:39:08 +01:00
6c57fa078b Merge pull request #437 from madrang/dragNdrop
Requested fixes for Drag&Drop
2022-11-03 13:13:41 +05:30
c3cc75feff Adds a list of properties to not export by default. 2022-11-03 03:16:20 -04:00
d2e6011089 Windows paths... 2022-11-03 03:12:11 -04:00
5a18144366 Enable/disable seedField when updating randomSeedField.checked 2022-11-03 03:11:58 -04:00
8a0a22bfb0 Merge pull request #427 from madrang/dragNdrop
Add support for drag&drop for the text files made by the backend
2022-11-03 11:41:21 +05:30
950b226374 Moved copy icon css to main.css 2022-11-03 02:09:42 -04:00
74e64a4387 Merge pull request #435 from JeLuF/sanitize
Sanitize session id's before using them as path components
2022-11-03 10:57:12 +05:30
59e4c1cf79 Sanitize session id's before using them as path components 2022-11-03 00:43:44 +01:00
9b89ede9c4 Only require 8GB instead of 80GB
80GB was a leftover from the code test
2022-11-03 00:28:47 +01:00
bf205de3a1 NSIS script enhancements
- Enable Unicode support
- Activate LongPathsEnabled if the user tries to install into a directory 
  with more than 30 characters length
- Change welcome text page. No need to close other programs during our setup
- Warn if the user has less than 8GB of RAM
- Formatting, comments
2022-11-02 21:12:20 +01:00
045ad78bb9 Added calls to update sliders. 2022-11-02 10:53:48 -04:00
c0350e5be7 Moved file ext to a var. 2022-11-02 10:45:51 -04:00
ea7006eec4 Set the PYTHONPATH before installation to prevent conda from knowing about any system-wide python installations (and skipping package installs due to that) 2022-11-02 19:45:49 +05:30
2b3e38f77e Merge pull request #421 from madrang/beta
Fix plugins needing to specify many params or they would be missing in the render request.
2022-11-02 12:34:45 +05:30
d04fe5d582 Increase CSS version 2022-11-02 12:23:36 +05:30
17ab4caa5e Merge pull request #426 from ayunami2000/beta
Improve UI on mobile devices
2022-11-02 12:22:18 +05:30
976bc727dd Merge pull request #422 from madrang/device-select
Implement complete device selection in the backend.
2022-11-02 12:05:59 +05:30
484e53cc08 made first large swathe of changes for ui reorganization 2022-11-01 23:03:05 -07:00
b09b80933d Print device name on task start and complete to avoid doubt from users on what device selected the task. 2022-11-01 22:28:10 -04:00
8165086d02 NSIS scripts 2022-11-02 01:07:52 +01:00
82f14b087a NSIS Readme 2022-11-02 01:07:23 +01:00
93b3419737 Better human formatted JSON 2022-11-01 04:54:38 -04:00
19290fe467 Merge pull request #431 from JeLuF/patch-8
Copy CUDA_VISIBLE_DEVICES to config.*, it it has been set
2022-11-01 13:40:11 +05:30
d2f679030b Don't put CUDA_VISIBLE_DEVICES hints if it's already set 2022-11-01 01:16:29 +01:00
053bce7a8e Set the correct mimetype in the base64 image 2022-10-31 19:05:57 +05:30
2f208832a9 Merge pull request #424 from patriceac/patch-1
Fixing the parsing of Set and Permute operators in custom tags
2022-10-31 18:25:30 +05:30
268d7495cc Naming... 2022-10-31 01:13:04 -04:00
ce16e61e63 Adds a copy as JSON button. 2022-10-31 01:02:23 -04:00
f92bca58fa Lines endings... 2022-10-31 01:01:56 -04:00
83d541b60d Fixed model parsing... 2022-10-30 23:41:26 -04:00
965efc3a13 Restore old values if invalid values for the dropdown was used. 2022-10-30 23:35:42 -04:00
d656c34bd4 Add support for drag&drop for the text files made by the backend and also supports JSON. 2022-10-30 23:21:39 -04:00
7f151cbeba Copy CUDA_VISIBLE_DEVICES to config.*, it it has been set
Don't delete CUDA_VISIBLE_DEVICES settings when generating a new config file
2022-10-31 00:48:18 +01:00
bc2f9204e9 Improve UI on mobile devices 2022-10-30 18:16:31 -04:00
a922a93016 Can work with one or more params, don't need a minimum of two.
Still works just the same.
2022-10-30 14:09:12 -04:00
eb596ba866 Allow start_render_thread to proceed faster in case of failure. 2022-10-30 06:04:06 -04:00
2208545612 Don't display this warning if on CPU. 2022-10-30 05:39:45 -04:00
f08a875cd2 Update main.js
Fix parsing of Set and Permute operators in custom tags.
2022-10-30 00:26:53 -07:00
d492d3f738 Update main.js
Fixing the parsing of Set and Permute operators in custom tags.
2022-10-30 00:22:01 -07:00
c687091ce9 Only return valid data for alive threads. 2022-10-30 01:38:32 -04:00
eb994716e6 Indentation... 2022-10-30 01:33:17 -04:00
70acc8a7c0 Syntax... 2022-10-29 19:02:07 -04:00
bf97781232 Don't let users register the same device twice. 2022-10-29 18:57:31 -04:00
099727d671 Added auto unload to CPU if GPUs are active. 2022-10-29 18:57:10 -04:00
6229cdb1ba Added a missing device_name 2022-10-29 17:47:45 -04:00
b7a663ed20 Implement complete device selection in the backend. 2022-10-29 17:34:53 -04:00
3bd97352ba Don't reset reqBody, only replace using req as we use a new task object created from UI inputs.
Fix plugins needing to specify many params or they would be missing in the render request.
2022-10-29 14:47:58 -04:00
33e25d9241 Deduce the filename in developer_console.sh instead of hardcoding it 2022-10-29 20:25:11 +05:30
fc11018158 Re-download micromamba if necessary 2022-10-29 19:41:52 +05:30
5e22360cb1 Change the JS/CSS version 2022-10-29 18:10:23 +05:30
840348b4eb fix: change to the correct working directory
changes to the directory containing `start.sh` prior to activating the conda environment

this allows you to run the program without first changing to the correct directory, eg: `$ ~/bin/stable-diffusion-ui/start.sh`
2022-10-29 15:09:04 +05:30
450fb2553c fix: change to the correct working directory
changes to the directory containing `start.sh` prior to activating the conda environment

this allows you to run the program without first changing to the correct directory, eg: `$ ~/bin/stable-diffusion-ui/start.sh`
2022-10-29 15:08:25 +05:30
cf04738594 Merge pull request #420 from madrang/beta
Missing .lower() cause CUDA:0 to fail check where cuda:0 works.
2022-10-29 15:01:13 +05:30
03757632cf Missing .lower() cause CUDA:0 to fail check where cuda:0 works. 2022-10-29 04:33:14 -04:00
e818f5a93f Bump version 2022-10-29 12:29:28 +05:30
ab9b08770a Merge pull request #417 from mdiller/mdiller_parameters
Moved System Settings & Reworked into "Parameters"
2022-10-29 12:04:21 +05:30
40df8b68ad Merge pull request #418 from madrang/beta
Changed failure in start_render_thread to return false instead of throwing exception
2022-10-29 11:33:36 +05:30
9f5202fee3 Improved readability and comments. 2022-10-29 00:43:02 -04:00
902ccbd203 Don't try to start cuda:0 if auto used cpu mode. 2022-10-29 00:36:26 -04:00
4675da4d16 Display warning on start failure.
Removes spam from exception and continue starting other devices.
2022-10-28 22:53:55 -04:00
86da27a7a1 Moved wait outside lock and now returns false on failure. 2022-10-28 22:52:00 -04:00
fc2a6567da Moved import before use of runtime.thread_data.device 2022-10-28 22:51:04 -04:00
7c611d9b62 added some shadow and animation to popups 2022-10-28 18:41:41 -07:00
784c7465d1 updated settings labels 2022-10-28 18:31:46 -07:00
301af7bd7a added parameters 2022-10-28 18:25:54 -07:00
09c11a385d normalized popups 2022-10-28 16:48:32 -07:00
ef6f491d94 Write lines, please 2022-10-28 22:42:11 +05:30
9dcef00fbb New lines for config.sh 2022-10-28 22:35:04 +05:30
e781e5dd43 Need to wrap the filter() output in a list 2022-10-28 22:30:05 +05:30
d3e672d811 Replace os-specific newlines with writelines() 2022-10-28 22:23:52 +05:30
dad1554ec2 Fix a bug where config.bat would not get written properly 2022-10-28 21:07:18 +05:30
30bf96c6cd Fix a bug where beta wouldn't switch properly because the config.bat/sh files weren't being written 2022-10-28 21:00:25 +05:30
a8c16e39b8 Support custom VAE files; Use vae-ft-mse-840000-ema-pruned as the default VAE, which can be overridden by putting a .vae.pt file inside models/stable-diffusion with the same name as the ckpt model file. The UI / System Settings allows setting the default VAE model to use 2022-10-28 20:06:44 +05:30
79a7cd2938 Merge pull request #414 from madrang/beta
Set online after preload. Move ident to include in if check.
2022-10-28 13:54:44 +05:30
26562e445f Set online after preload. Move ident to include in if check. 2022-10-28 04:09:34 -04:00
0b678b1f16 Merge pull request #413 from JeLuF/patch-7
Change "Advanced Settings" to "Image settings"
2022-10-28 13:10:04 +05:30
79b5e85b15 Change "Advanced Settings" to "Image settings"
The menu has been renamed, so the welcome text should reflect this.
2022-10-28 09:21:31 +02:00
2432491bfc Merge pull request #411 from madrang/beta
Apply force_full_precision if was set on device_select.
2022-10-28 11:50:16 +05:30
a09ce3e026 Merge pull request #412 from mdiller/mdiller_progressbar
Quick Fix for Progressbar Behavior
2022-10-28 11:49:42 +05:30
c52fc843f6 Comment... 2022-10-28 02:09:11 -04:00
02240bda25 Moved up to not duplicate if statement. 2022-10-28 02:05:48 -04:00
0185ef7c83 Apply force_full_precision if was set on device_select. 2022-10-28 02:02:09 -04:00
7d29b9901c updated progressbar to end more consistently 2022-10-27 22:47:08 -07:00
ae553dfed3 Merge pull request #410 from madrang/beta
Only default to cpu on auto or current when cuda not available.
2022-10-28 10:43:28 +05:30
71c6beadb4 Only default to cpu on auto or current.
Not when a specific device was requested.
2022-10-28 01:09:38 -04:00
d939629c09 Bump version 2022-10-28 10:39:23 +05:30
0a569146a8 Merge pull request #406 from mdiller/mdiller_progressbar
Fixed/Implemented Progressbar
2022-10-28 10:34:03 +05:30
d5a012d49f Merge pull request #407 from madrang/beta
Wait until device is fully ready before proceeding.
2022-10-28 10:28:16 +05:30
22a11769fa Enable preload on cpu when no other devices are alive. 2022-10-27 21:57:50 -04:00
7dc7ba9977 Removed old comments. 2022-10-27 21:47:44 -04:00
fa4059a4b9 Removed all async code since now start_render_thread wait for init to complete making this useless. 2022-10-27 21:40:16 -04:00
7f4786f9dd Wait until device is fully ready before proceding. 2022-10-27 20:27:21 -04:00
5a6e7a46d1 added progressbar 2022-10-27 17:03:09 -07:00
9f90749f99 Merge pull request #405 from JeLuF/patch-6
Add disk space requirements
2022-10-28 00:22:08 +05:30
0dfaf9159d Put back the check to only preload on GPU 2022-10-28 00:04:33 +05:30
5d8bda1178 Merge pull request #404 from cmdr2/multi-gpu
Support for multiple GPUs, and improvements to RAM and VRAM usage
2022-10-27 23:52:11 +05:30
9ad1e0d529 Allow the user to specify any disk path to the model, in the config 2022-10-27 23:39:29 +05:30
389e3397ec Preload the model even in the CPU mode 2022-10-27 23:17:41 +05:30
284b95213e Fix a bug where the device wouldn't get set if no cuda-compatible hardware was found 2022-10-27 22:59:55 +05:30
952854f64e Revert 554650c18d 2022-10-27 22:59:17 +05:30
554650c18d Fix a bug where the device wouldn't get set if no cuda-compatible hardware was found 2022-10-27 22:51:45 +05:30
01a2fa7c2d Fix a bug where the default model would not load if the user hadn't already configured a custom model (e.g. in a fresh installation); Check for the model in the models/stable-diffusion folder first, before checking in the direct folder 2022-10-27 22:34:23 +05:30
1257e34487 Add disk space requirements 2022-10-27 17:39:54 +02:00
a45743f443 Update CONTRIBUTING.md 2022-10-27 20:56:49 +05:30
7d03719816 Merge pull request #403 from cmdr2/main
Merge main
2022-10-27 20:50:09 +05:30
7c5bbca2fa Bump version 2022-10-27 20:49:05 +05:30
cf313939aa Merge pull request #402 from cmdr2/beta
Retry micromamba download on windows
2022-10-27 19:50:12 +05:30
873d4bd3f2 Retry micromamba download on windows 2022-10-27 19:47:20 +05:30
f43f3fc84b Merge pull request #401 from cmdr2/beta
Download micromamba again if it failed to download the first time
2022-10-27 16:07:10 +05:30
0e1fed86ba Download micromamba again if it failed to download the first time 2022-10-27 16:06:16 +05:30
3fb5d886dc Merge pull request #398 from madrang/mGpu-crashHandling
mGpu crash handling
2022-10-27 13:44:26 +05:30
b57cd8d5c2 Merge pull request #397 from madrang/mGpu-fixtype
Fix TypeError: string indices must be integers
2022-10-27 13:44:19 +05:30
5c1bbc08ca Merge pull request #399 from JeLuF/patch-5
Undo curl change
2022-10-27 07:37:15 +05:30
6ba32b95f3 Undo curl change
#392 Resume Downloads
The retry options also don't work on some windows machines:
https://discord.com/channels/1014774730907209781/1014774732018683926/1034935751332347922
2022-10-27 00:26:24 +02:00
d3df113fb0 When reduced_memory is True, on crash only move model back to Cpu. 2022-10-26 16:52:31 -04:00
06c2ab045a Fix TypeError: string indices must be integers 2022-10-26 16:14:29 -04:00
6d43e0951c Update on_sd_start.sh 2022-10-27 00:49:32 +05:30
ec14429238 Merge pull request #348 from madrang/multi-gpu
Multi gpu
2022-10-26 19:33:44 +05:30
1dc2c6f183 Update README.md 2022-10-26 18:31:39 +05:30
984b8f7e6f No need to generate arch-specific installers 2022-10-26 18:28:21 +05:30
0f8448b2c0 Merge pull request #396 from cmdr2/main
Merge main
2022-10-26 18:11:53 +05:30
088c546bee Merge pull request #394 from JeLuF/patch-4
Retry downloads on flaky internet connections
2022-10-26 17:36:46 +05:30
20fff378f0 Merge pull request #395 from cmdr2/beta
Use micromamba to install git and conda, instead of bundling a copy of git and conda in the installer. This will not affect existing installations, they'll continue using the previously bundled git and conda that came with the old installer
2022-10-26 17:35:30 +05:30
4994a7ac85 Update on_sd_start.sh 2022-10-26 13:27:49 +02:00
a959c69d32 Retry downloads for flaky internet connections
See issue #392
2022-10-26 13:26:19 +02:00
39244568be Merge pull request #391 from cmdr2/installer_umamba
Remove the extra python version print
2022-10-26 16:02:25 +05:30
c8fc0bb4f5 Remove the extra python version print 2022-10-26 16:02:00 +05:30
654ad5c71f Merge pull request #390 from cmdr2/installer_umamba
Report the python version after activating the SD environment, that l…
2022-10-26 16:00:56 +05:30
7b9d18caea Report the python version after activating the SD environment, that log is not very useful otherwise 2022-10-26 16:00:21 +05:30
8d347efec2 Merge pull request #389 from cmdr2/installer_umamba
Use micromamba to install git and conda, instead of bundling a copy of git and conda in the installer. This will not affect existing installations, they'll continue using the previously bundled git and conda that came with the old installer
2022-10-26 13:06:43 +05:30
85de6dd52e Merge branch 'beta' into installer_umamba 2022-10-26 13:01:22 +05:30
c024b39c8b Get ready for installer_umamba 2022-10-26 12:55:39 +05:30
1f0db48487 Bump version 2022-10-26 12:53:22 +05:30
2bc5f475f4 Merge pull request #386 from cmdr2/beta
Refactor the previously saved settings into the new auto-save system
2022-10-26 12:48:15 +05:30
5abf4c99de Merge pull request #385 from cmdr2/main
Merge from main
2022-10-26 12:45:47 +05:30
137e519b66 Move the installer activation to on_sd_start 2022-10-26 12:15:58 +05:30
dcb27e7de8 Build the win installer on windows, and linux/mac installer on linux/mac 2022-10-26 11:45:43 +05:30
d4d5b5a75c Fix the echo script 2022-10-26 11:40:27 +05:30
a83b3f8408 typo in the help copy script 2022-10-26 11:28:45 +05:30
da9af8673f Create the scripts folder in the installers 2022-10-26 11:27:34 +05:30
1b4ba3b396 Update the build scripts for generating the installers 2022-10-26 11:26:10 +05:30
eb2f1cbc9e Update README.md 2022-10-26 11:03:12 +05:30
28f58f72dd Update README.md 2022-10-26 11:02:53 +05:30
81389401df Update README.md 2022-10-26 11:02:06 +05:30
c618c5c5f0 Update README.md 2022-10-26 10:55:25 +05:30
0eaff4c626 Update README.md 2022-10-26 10:55:00 +05:30
9783c1052d Update README.md 2022-10-25 22:58:44 +05:30
f732fa9736 Use call to start the conda script; activate the installer env first even in the developer console 2022-10-25 20:26:46 +05:30
0c2d227da1 Activate the installer env while starting up, like the previous installer did in the start script 2022-10-25 19:21:26 +05:30
a281efef04 deactivate any pre-activated conda environments, by returning to (base) and then deactivating that. On Windows and Linux 2022-10-25 18:07:29 +05:30
538dcec348 deactivate any pre-activated conda environments before installing 2022-10-25 17:26:33 +05:30
0d38c8ae8f Bring back the post-installation test for torch 2022-10-25 16:38:08 +05:30
967c1a2da9 No need for conda 4.14, disable the broken test for torch 2022-10-25 15:42:22 +05:30
f3da326b77 Remove debug logging 2022-10-25 14:36:57 +05:30
153a6e2cb0 Temporarily disable sd_start for linux 2022-10-25 14:30:08 +05:30
95f37b9d36 Use conda 4.14 in the new installer as well (like the previous installer did) 2022-10-25 13:00:57 +05:30
60c37a1fc7 Set the PYTHONPATH before testing the SD installation 2022-10-25 12:48:56 +05:30
615c61e230 Fix a broken PYTHONPATH export in the linux script, used ; instead of : 2022-10-25 12:44:05 +05:30
ae40b6ba8c Missed a is_alive check in the conversion. 2022-10-25 03:00:50 -04:00
d482427e0d Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-25 02:51:31 -04:00
c41baf3aeb Moved img_id creation inside save image loop. 2022-10-25 02:10:52 -04:00
dd7cb74edc Tweak reset-image-settin
gs button some more
2022-10-25 11:12:34 +05:30
4eed2c7582 Tweak the position of the reset-image-settings button 2022-10-25 11:11:37 +05:30
100e830e04 Bust the cache for included media 2022-10-25 11:03:07 +05:30
af28d82ebc Merge pull request #377 from madrang/beta
Missing '?' in case renderRequest is ever undefined.
2022-10-25 10:46:17 +05:30
6285980f98 Merge pull request #377 from madrang/beta
Missing '?' in case renderRequest is ever undefined.
2022-10-25 10:44:37 +05:30
a5d19cd31f Update index.html 2022-10-25 10:32:55 +05:30
9c9998b468 Merge pull request #364 from mdiller/mdiller_settings
Settings Refactor
2022-10-25 10:32:38 +05:30
011eb55a53 Merge pull request #383 from cmdr2/main
Merge from main
2022-10-25 10:32:17 +05:30
189d31cc29 Specify update_ttl on all get_cached_task calls. 2022-10-24 05:12:08 -04:00
d178f3d1b9 Missing 'e' 2022-10-23 15:01:11 -04:00
6e9d73ec64 Fixe forgotten current_state_error, is now in task_manager 2022-10-23 15:00:36 -04:00
8d1adf4f80 Fix the incorrect command used for downloading and extracting micromamba on linux/osx 2022-10-23 15:13:24 +05:30
d0b7f58e7c Fix a bug in the new linux installer's legacy path 2022-10-23 15:02:03 +05:30
19d24e5644 Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-10-23 14:38:11 +05:30
461f618b8a Replace grep with findstr on Windows 2022-10-23 14:37:59 +05:30
fc875651d3 Removed unused vars 2022-10-23 05:00:21 -04:00
5ff14d1fed Install conda only if it's not present in the legacy and new installer dir 2022-10-23 11:57:23 +05:30
80c9c1bb05 Install a new conda only if not already present locally 2022-10-23 11:36:31 +05:30
a111d9b18a Supress detached head warning 2022-10-23 11:28:08 +05:30
df14913c67 Always install conda, don't use the system's version 2022-10-23 11:16:28 +05:30
b6c6fef770 Use findstr instead of grep on windows 2022-10-23 10:47:44 +05:30
1a2f37b0ec Make the micromamba binary executable after download on linux 2022-10-23 10:38:01 +05:30
6f3c662783 Bump version 2022-10-23 10:28:27 +05:30
3772137c8f Include usr/bin in the installer PATH; newlines at the end of all files 2022-10-23 10:23:43 +05:30
0d62123a0b Replaced missing gpu_name by device_name 2022-10-22 21:28:12 -04:00
28fed6281f Merge branch 'beta' into multi-gpu 2022-10-22 21:20:02 -04:00
1ec95d42ba Missing '?' in case renderRequest is ever undefined. 2022-10-22 21:19:42 -04:00
8adf965d0b Formatting changes. 2022-10-22 19:02:02 -04:00
026dd38480 Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-22 18:07:22 -04:00
338c2243e3 Newline after printing env info in developer scripts 2022-10-22 23:28:43 +05:30
e8d61225f5 Make the linux installer executable 2022-10-22 23:26:59 +05:30
cc356ce67d Initial commit of the new micromamba-based installer; This should work seamlessly for new and existing users; Also allows the installer to run on mac (but the installation will fail because the mac-specific environment.yaml hasn't been added yet) 2022-10-22 23:24:13 +05:30
364e364429 Added get_cached_task to replace task_cache.tryGet in server.py
Now updated cache TTL on /stream and temp images endpoints.
Keep images alive longer when browser keeps reading the endpoints.
2022-10-22 13:52:13 -04:00
46a46877ed Missing model_path replaced by model_name 2022-10-22 13:49:23 -04:00
5ee05e3aaa Merge pull request #376 from cmdr2/beta
Custom Modifiers; Try to fix the 503 error bug; Show the number of images being created in the Make Image button
2022-10-22 22:27:05 +05:30
5568a09f49 Merge pull request #375 from madrang/beta
Improved render response checks
2022-10-22 22:23:05 +05:30
1199c431ff Removed a new line by mistake. Formatting... 2022-10-22 12:51:43 -04:00
2c1a897c4e Missing newline. 2022-10-22 12:50:53 -04:00
305f2fa448 In case of failure, display error in renderRequest.detail 2022-10-22 12:32:41 -04:00
b051685727 More logging for each state and improved handling. 2022-10-22 12:31:14 -04:00
344dd92c85 Improved checks on '/render' requests 2022-10-22 12:29:01 -04:00
4167c65acf Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-22 12:17:12 -04:00
cd6d49860f Missing a 'r' in progress 2022-10-22 01:23:39 -04:00
8a10fcf7ea updated print statement. 2022-10-22 00:34:33 -04:00
7580bb21c3 Fix upscale multiple images bug 2022-10-22 08:38:19 +05:30
62102236a2 Merge pull request #372 from rbertus2000/beta
fix multiple images with upscale/fix face button
2022-10-22 08:34:34 +05:30
3b5f96a133 Fixed stopping tasks and more cleaning. 2022-10-21 22:45:19 -04:00
ce2b711b1f Newlines... 2022-10-21 21:44:15 -04:00
667fb438cb Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu
# Conflicts:
#	ui/media/js/main.js
2022-10-21 21:10:02 -04:00
7befa94e6d More comments and cleanup. 2022-10-21 20:56:24 -04:00
32d7835119 added a simple tooltip to the reset button 2022-10-21 17:44:04 -07:00
726abf6e65 removed some extra comment stuff 2022-10-21 17:31:57 -07:00
c154a4bdc8 removed second auto-savecss reference 2022-10-21 17:30:09 -07:00
88ef1a3c5b Moved time before model.to 2022-10-21 20:22:34 -04:00
5453925e26 Merge branch 'beta' into mdiller_settings 2022-10-21 17:16:50 -07:00
537e314b49 updated to consume the old settings nicely 2022-10-21 17:13:13 -07:00
ccb7a553c2 Memory improvements 2022-10-21 19:34:29 -04:00
1696a5c8e1 modifyCurrentRequest with rest parameters 2022-10-21 23:04:42 +02:00
816cf8f702 fix multiple images with upscale/fix face button 2022-10-21 22:40:26 +02:00
e8167541af Show a tip regarding custom modifiers 2022-10-21 21:35:20 +05:30
329360aa5b Show the number of images it'll make in the Make Image button 2022-10-21 15:18:05 +05:30
eb1a276e60 Move the image modifers toolbar back to the top 2022-10-21 14:54:45 +05:30
a53bac1a94 Fix a bug where a null value for custom modifiers would break 2022-10-21 14:43:32 +05:30
93bf93d3a1 Fix a bug where a null value for custom modifiers would break 2022-10-21 14:42:02 +05:30
4174c8c25c Increase version 2022-10-21 14:36:51 +05:30
48a88a8624 Custom modifiers 2022-10-21 14:08:16 +05:30
1442748f58 When starting with profiler cuda devices are slower to init. 2022-10-21 03:53:26 -04:00
d17e216f91 Replace the thumbnail image for glass caustics image modifier 2022-10-21 13:08:23 +05:30
56ed4fe6f2 Fix VisualStudio Type Warning. 2022-10-21 01:30:49 -04:00
9a71e9ba86 Merge pull request #369 from cmdr2/main
Merge main
2022-10-21 09:57:53 +05:30
ef478a4a9e Remove the message about system-related settings 2022-10-21 09:41:31 +05:30
1bd7d40716 Merge pull request #368 from madrang/HTTP503-Fix
Fix HTTP503 Error.
2022-10-21 07:35:52 +05:30
807e9573fb Check result status, not json object. 2022-10-20 20:36:45 -04:00
849d1d7ebd Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu
# Conflicts:
#	ui/media/js/main.js
#	ui/sd_internal/runtime.py
#	ui/server.py
2022-10-20 20:08:23 -04:00
3fe2545228 Merge pull request #367 from cmdr2/beta
Refactor the time delays into constants and mention the units
2022-10-20 17:25:38 +05:30
090dfff730 Refactor the time delays into constants and mention the units 2022-10-20 17:22:01 +05:30
f94e9449d5 Merge pull request #366 from cmdr2/beta
Specify multiple word options in a prompt; UI Plugins system
2022-10-20 16:07:25 +05:30
d8753adc4e Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-10-20 16:05:28 +05:30
2e17ea99e2 Don't cache ui plugins in the browser 2022-10-20 16:05:18 +05:30
c4daf8524e Merge pull request #365 from cmdr2/merge
Merge main
2022-10-20 15:58:03 +05:30
9d16898926 Merge branch 'beta' into merge 2022-10-20 15:57:46 +05:30
f4bcc1f2e5 Bug fix - autosave wasn't saving the changes in the textboxes next to guidance scale and prompt strength sliders 2022-10-20 15:26:18 +05:30
63e8614ace Refactor the image button code 2022-10-20 15:10:34 +05:30
5d686b146d Remove the new label from Upscale 2022-10-20 12:14:09 +05:30
e85758dc5f Merge pull request #361 from rbertus2000/beta
fix seed for parallel renders with filters applied
2022-10-20 12:03:00 +05:30
d08f090800 Merge branch 'beta' into mdiller_settings 2022-10-19 21:17:56 -07:00
8554473c21 the rest of the fking owl 2022-10-19 21:12:01 -07:00
01fb1bde8b fix seed for parallel renders with filters applied 2022-10-19 23:16:51 +02:00
29e32ffc42 Mark the new upscale button as new 2022-10-19 22:08:58 +05:30
88bd60a083 Button to draw another 25 steps 2022-10-19 22:08:42 +05:30
48b7b725b0 Add a button to fix faces on generated images 2022-10-19 22:02:59 +05:30
8d8c932d8c Bump version 2022-10-19 21:59:15 +05:30
253d355bd2 New upscale button for images; Fix a bug where the string seed would get appended with numbers 2022-10-19 21:58:51 +05:30
e287df1320 Allow loading UI plugins from a /plugins/ URL path, which loads files ending with .plugin.js inside the plugins/ui folder 2022-10-19 21:34:40 +05:30
bae0bec1cc Change the image buttons plugins to a list instead of a dict 2022-10-19 21:21:19 +05:30
602686a5d2 Move the current implementation of upscale/redo/double size into a custom plugin 2022-10-19 20:27:06 +05:30
af05d94198 Allow plugin buttons for image overlay to decide whether they should be displayed or not 2022-10-19 20:10:45 +05:30
5fa3a7ca44 UI-side plugin system; Use PLUGINS['IMAGE_INFO_BUTTONS'] to add additional buttons on the generated images 2022-10-19 19:50:05 +05:30
9609350789 Rework the API for image buttons 2022-10-19 18:23:34 +05:30
9c1e73ffff Fix missing auto-save.css include 2022-10-19 18:10:22 +05:30
50741c70c0 Add a 'Make Similar Images' button 2022-10-19 17:26:35 +05:30
fc8660df78 Faster response on invalid settings when CPU was specified with GFPGANer. 2022-10-19 05:19:16 -04:00
4e5ddca3bd Display the failure detail when there is one at that step.
Was checking the json object, not the server response.
2022-10-19 05:10:37 -04:00
3bdc90451a Dont preload on cpu. 2022-10-19 04:34:54 -04:00
a036b2981a Removed forgotten mention of CPU in message to user. 2022-10-19 04:31:57 -04:00
8fae83dab7 Print value to console for better debug from logs. 2022-10-19 04:26:09 -04:00
083f9dd29b Bump version 2022-10-19 13:50:36 +05:30
7d5fabbd25 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-10-19 13:50:17 +05:30
105f071847 Expand curly braces in prompts, for e.g. 'hello {foo,bar}' => 'hello foo' and 'hello bar' 2022-10-19 13:50:05 +05:30
ef68e5b13d Added warning about validating config. 2022-10-19 04:16:46 -04:00
21afe077d7 Removed Cpu from the devices allowed to run GFPGANer.
Added clear error for the user.
2022-10-19 03:02:26 -04:00
48222ce44c updated to make autosaving on by default and updated some of the new logic 2022-10-18 22:13:45 -07:00
0922ba938c Remove unnecessary tabs 2022-10-19 09:59:18 +05:30
3fc66ec525 Removed empty lines left over from merge. 2022-10-19 00:27:51 -04:00
44191cd908 Merge pull request #357 from rbertus2000/beta
fixed img_id for parallel renders
2022-10-19 09:57:05 +05:30
0da0c6bd77 Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-19 00:26:09 -04:00
b5f6e9d01b Merge pull request #357 from rbertus2000/beta
fixed img_id for parallel renders
2022-10-19 09:52:58 +05:30
6098b196dc Text header, comments and better validations. 2022-10-18 23:58:55 -04:00
0922349344 made some updates and moved some stuff to auto-save js 2022-10-18 20:49:58 -07:00
53cdeeff03 More fixes to devices changing names. 2022-10-18 21:08:04 -04:00
fcdb086daf Fixed is_alive to work with devices that can change name after init. 2022-10-18 20:33:37 -04:00
d2d9c2dd0f fixed corresponding txt file id 2022-10-19 01:17:44 +02:00
4241fb9386 fixed img_id for parallel renders 2022-10-18 22:38:37 +02:00
cfd6751777 Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-18 13:21:26 -04:00
5e461e9b6b Fixed is_alive with render_threads that can update the device name after starting. 2022-10-18 13:21:15 -04:00
946dfdf7b8 Bring back the upscale/double/redo buttons 2022-10-18 22:29:15 +05:30
4da9843479 Move image modifiers JS to a separate file 2022-10-18 22:28:04 +05:30
eccb3c643d Separate the inpainting editor JS into a separate file 2022-10-18 22:09:11 +05:30
bfa5a51ce8 Use a local copy of fontawesome, to allow working offline 2022-10-18 21:40:17 +05:30
9066ad6cdf Use locally hosted fonts, to be able to work offline 2022-10-18 21:06:56 +05:30
f7b513dff2 Refactor the CSS and JS into separate files, attempt 1 2022-10-18 20:18:56 +05:30
3de5f10d52 Merge pull request #356 from cmdr2/beta
Task Manager (support multiple tabs and user agents), Themes, Auto-save settings, Prompt Matrix (one prompt per line), Load Prompts from a file, UI theme tweaks
2022-10-18 19:16:58 +05:30
07429a862c Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-10-18 19:02:52 +05:30
2f2bddf020 Allow empty prompts; Allow collapsing a results box for an empty prompt 2022-10-18 19:02:34 +05:30
ad03adaebf Merge pull request #355 from cmdr2/main
Merge main
2022-10-18 18:51:30 +05:30
ac7a5488ee Disable the upscale/redo/double size buttons temporarily, so that the release can proceed to main 2022-10-18 18:50:47 +05:30
6de93d4fbb Reduce the padding around the screen edges 2022-10-18 16:28:18 +05:30
8a312f76c5 Merge pull request #352 from madrang/HTTPException-fix
Replaced 'return HTTPException' by 'raise HTTPException'
2022-10-18 16:23:31 +05:30
4a956b5a55 Make the label 10pt 2022-10-18 16:20:35 +05:30
83d6c3ba88 Fix the broken 'time remaining' counter 2022-10-18 16:12:17 +05:30
52daf6b864 Revert "Use python 3.9"
This reverts commit c8420e152f.
2022-10-18 15:37:02 +05:30
c8420e152f Use python 3.9 2022-10-18 15:34:37 +05:30
1dff19af26 Revert "Use python 3.10"
This reverts commit a1e2eca802.
2022-10-18 15:15:12 +05:30
a1e2eca802 Use python 3.10 2022-10-18 15:11:28 +05:30
48b63a26c8 Don't disable the random field when the output image is used as the new init image 2022-10-18 14:51:23 +05:30
b23bc4a5b6 Don't disable the random field when the output image is used as the new init image 2022-10-18 14:49:39 +05:30
940236b4a4 Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-18 03:23:42 -04:00
b6ef18b0d8 Merge pull request #354 from madrang/beta
Fixed theme loading with extensions.
2022-10-18 12:52:48 +05:30
372484f976 Fixed theme loading with extensions. 2022-10-18 03:21:59 -04:00
086cf67e93 Remove commented-out script copying line 2022-10-18 12:48:20 +05:30
3c8692d06c Merge branch 'beta' of https://github.com/cmdr2/stable-diffusion-ui.git into multi-gpu 2022-10-18 02:52:50 -04:00
efffca83fe Merge pull request #353 from mdiller/mdiller_themes
Theme Selection
2022-10-18 12:11:19 +05:30
04fe81e001 Merge branch 'HTTPException-fix' into multi-gpu
# Conflicts:
#	ui/server.py
2022-10-18 02:36:57 -04:00
d2215c2ba9 removed accent hue in a couple places where it didnt need to be specified 2022-10-17 23:36:05 -07:00
89b1b6e242 Replaced 'return HTTPException' by 'raise HTTPException' 2022-10-18 02:30:30 -04:00
e476d68848 fixed a couple things and added some more themes 2022-10-17 23:19:22 -07:00
da8835bc77 updated to behave better and apply variables that are dependant 2022-10-17 23:00:08 -07:00
f170c2611c Merge branch 'beta' into mdiller_themes 2022-10-17 22:23:02 -07:00
351b17d1d9 added a theme dropdown box 2022-10-17 22:22:27 -07:00
14e88706df Set and use a local profile directory for new installations - does not affect existing installations 2022-10-18 09:46:25 +05:30
926e3e2712 Merge pull request #351 from madrang/fix-bug332
Force encoding to utf-8 on text file operations Fixes #332
2022-10-18 09:40:54 +05:30
c39043fb9d Merge pull request #350 from madrang/beta
Fixed file path bugs introduced by mistake and made img_id sequential.
2022-10-18 09:21:46 +05:30
578b3ba4f4 Force encoding to utf-8 on text file operations Fixes #332
# Conflicts:
#	ui/server.py
2022-10-17 23:15:36 -04:00
5b0b582039 Force encoding to utf-8 on text file operations Fixes #332 2022-10-17 22:38:29 -04:00
e24be913e5 Merge branch 'beta' into multi-gpu 2022-10-17 21:35:24 -04:00
4d3358ba66 Fixed file path bugs introduced by mistake and made img_id sequential based on time for better sorting of renders. 2022-10-17 21:29:14 -04:00
ffe40fa3a3 Fixed file path bugs introduced by mistake and made img_id sequential based on time for better sorting of renders. 2022-10-17 21:27:15 -04:00
87f93b34a3 Fixed a typo when adding a comment. 2022-10-17 14:44:53 -04:00
03bd9a5731 Temporary fix for lagging progress updates check 2022-10-17 21:53:46 +05:30
cb82170187 Fix the bug where custom models weren't getting picked up 2022-10-17 21:22:05 +05:30
5b9e16af83 Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-10-17 18:40:14 +05:30
7b1b2a4bef Enable auto-save of settings by default 2022-10-17 18:40:04 +05:30
1f1a0b7b53 Merge pull request #347 from cmdr2/task_manager
Cosmetic tweaks to loading status
2022-10-17 18:05:29 +05:30
320acfae89 Cosmetic tweaks to loading status 2022-10-17 18:04:46 +05:30
1c171d0f12 Merge pull request #346 from cmdr2/task_manager
Allow multiple tabs and computers to generate tasks without throwing errors (by @madrang)
2022-10-17 17:57:10 +05:30
22bf3618ea Bump version 2022-10-17 17:56:52 +05:30
5f1593f4d0 Style the busy and waiting colors 2022-10-17 17:52:55 +05:30
9af75bf9b2 Don't throw an error if a task was stopped before it started processing 2022-10-17 17:41:27 +05:30
344fa729a5 Don't stop another session's task when the 'Stop All Tasks' button is pressed 2022-10-17 17:36:20 +05:30
33d3d90a93 Merge pull request #329 from madrang/task-queue-rendering
Task queue rendering
2022-10-17 16:59:10 +05:30
24dfc09f35 Merge branch 'beta' into task-queue-rendering 2022-10-17 15:22:54 +05:30
e533bc0847 Merge pull request #330 from madrang/use_cpu_fix
Update use_cpu on Redo and Double Size to move renders to/from cpu and gpu after starting.
2022-10-17 15:22:13 +05:30
306333ceba Merge pull request #345 from cmdr2/main
Update the troubleshooting link to the new wiki page
2022-10-17 15:17:05 +05:30
e96312b470 Update the troubleshooting link to the new wiki page 2022-10-17 15:16:31 +05:30
fb60b4bca7 Merge pull request #344 from cmdr2/main
Update Troubleshooting.md
2022-10-17 15:13:11 +05:30
0612e4429d Update Troubleshooting.md 2022-10-17 15:12:47 +05:30
ee80aa26db Lighter color on hover for input elements 2022-10-17 14:34:48 +05:30
a45e667e9c Fix a bug (after merge) where the image info wouldn't get set 2022-10-17 14:19:16 +05:30
1b4a2369bb Don't save prompts by default 2022-10-17 13:48:06 +05:30
224483f6ac Rearrange the prompts box - move the prompt load button to the top, hide negative prompts behind a collapsible 2022-10-17 13:45:08 +05:30
c61574b782 Fix typo while merging b1dd4069db to beta 2022-10-17 13:04:33 +05:30
c92129ac63 Improved detection of missing cuda:0 and added warning to console about how to fix. 2022-10-17 03:32:23 -04:00
6c71d95932 Bump version 2022-10-17 13:01:31 +05:30
e859f5c7a1 Merge pull request #343 from cmdr2/main
Merge main
2022-10-17 12:59:21 +05:30
dc402f5f0e Downloaded images named with their correct prompt and settings 2022-10-17 12:57:45 +05:30
188894c837 Push back the auto-save settings change by @mdiller 2022-10-17 12:44:05 +05:30
70f99a70a5 Merge pull request #342 from cmdr2/revert-335-mdiller_beta
Revert "Auto-saving Settings"
2022-10-17 11:40:12 +05:30
fb4fbd23d8 Revert "Auto-saving Settings" 2022-10-17 11:40:01 +05:30
f58b2383b9 Revert "Fix typo while merging"
This reverts commit 05caf1fe28.
2022-10-17 11:39:51 +05:30
05caf1fe28 Fix typo while merging 2022-10-17 11:36:02 +05:30
704486abc2 Merge pull request #335 from mdiller/mdiller_beta
Auto-saving Settings
2022-10-17 11:35:03 +05:30
1ec023b435 Merge branch 'beta' into mdiller_beta 2022-10-17 11:34:50 +05:30
fd21eeb477 Uncomment the git reset 2022-10-17 11:26:02 +05:30
edf2b2df6f Bump version; Shrink the size of the editor panel and font size 2022-10-17 11:21:35 +05:30
9ce338622c Merge pull request #340 from mdiller/mdiller_styling
Updated/Fixed CSS Styling
2022-10-17 10:50:10 +05:30
2b35529cbd Merge pull request #338 from JeLuF/patch-3
Add: ModuleNotFoundError: No module named 'gfpgan'
2022-10-17 10:36:26 +05:30
554b67a2f0 Fixing bug in is_alive. 2022-10-17 01:05:51 -04:00
012243a880 Process GPU tasks on CPU when there are no cuda devices at all. 2022-10-17 01:05:27 -04:00
d4a348a2b2 Process GFPGANer on cuda:0 when possible, otherwise use cpu. 2022-10-16 23:12:46 -04:00
1d4c5cc96f Added clear error response when submitting tasks that requires GFPGANer if cuda:0 and cpu rendering is disabled. 2022-10-16 23:07:55 -04:00
41bfb96b6b Fixed bug in task_manager.is_alive and added way to check for first device. 2022-10-16 23:06:41 -04:00
994d62ac65 Added a clear error message when targeting CPU if not enabled in config. 2022-10-16 22:26:05 -04:00
7c72608e1c First draft for Multi-GPU support 2022-10-16 21:41:39 -04:00
2edc06c662 Forgot to update UI if failed to get new server state 2022-10-16 21:32:59 -04:00
cb4d66d6fe removed temporary thing from env start script 2022-10-15 21:15:11 -07:00
f80602b51a tweaked styling of the size hint for the image 2022-10-15 18:39:56 -07:00
58d8a5ce46 added support for theming buttons 2022-10-15 18:34:59 -07:00
72a65218be updated some of the styling and positioning of some stuff 2022-10-15 18:04:41 -07:00
1b0d5b710e fixed styling to work properly for mobile 2022-10-15 17:26:52 -07:00
2a25ac0847 reorganized colors to make them themeable 2022-10-15 16:41:38 -07:00
9aefdf35a1 fixed bug with prompt strength showing up during non-img2img stuff 2022-10-15 15:30:04 -07:00
231961c017 removed newline from end of mainjs file 2022-10-15 15:25:36 -07:00
ee621fa091 pruned out all the auto-settings saving stuff 2022-10-15 15:23:48 -07:00
a69a04cfb6 reorganized and fixed the auto-save settings stuff so its all in its own file 2022-10-15 15:10:42 -07:00
b1aed344c7 moved auto-save settings stuff to new file and removed ui changes from main.js. this not done, just first step 2022-10-15 14:54:34 -07:00
3e08d665c7 removed non-settings related stuff from html 2022-10-15 14:46:18 -07:00
4a94c86433 removed stuff from styling that wasnt settings-related 2022-10-15 14:41:57 -07:00
d4878f6ed3 temporarily removed git reset and checkouts 2022-10-15 14:35:39 -07:00
d94719ea02 Add: ModuleNotFoundError: No module named 'gfpgan'
Common error
2022-10-15 20:11:39 +02:00
982b5221b1 Improved serverState tracking 2022-10-15 05:48:12 -04:00
cbdf03450d Added timeout to critical locking tasks with matching exception 2022-10-15 05:31:17 -04:00
7625e591fe Fixed output_dir not liking the move to JSONResponse 2022-10-15 04:47:12 -04:00
8fdb1e7ec9 Improved locking and logging when cleaning old cached sessions. 2022-10-15 04:39:45 -04:00
d3b28c42e6 Better error handling with cache.put 2022-10-15 04:08:17 -04:00
1b32423881 Renamed a missing ServerStates to task_manager.ServerStates 2022-10-15 03:32:00 -04:00
7de699c7fa Moved a lot of code into task_manager.py 2022-10-15 03:28:20 -04:00
e9f9670eb5 Changed '/get' from a query to a path parameter 2022-10-15 01:32:53 -04:00
3d4e961320 time.time() is in seconds not ms. 2022-10-15 00:51:06 -04:00
db2fb33d53 Merge pull request #336 from ZacTheHac/main
Downloaded images named with their correct prompt and settings
2022-10-15 10:14:38 +05:30
ff3db04ab7 temp_images needs twice the size if show_only_filtered_image is false 2022-10-14 23:21:44 -04:00
c7f6763c48 Runtime cleanup and moved apply_filters to it's own function 2022-10-14 23:20:57 -04:00
b1dd4069db Downloaded images named with their correct prompt and settings 2022-10-14 19:46:31 -07:00
58c647d433 updated to fix the formatting to make for a cleaner diff in the pull request 2022-10-14 17:30:54 -07:00
333ea4aa53 added a bunch of changes including cleaning up styling and inputs and adding auto-saving settings. see PR for more info. 2022-10-14 17:30:54 -07:00
3ad59da2a9 Move negative prompt box next to the main prompt box 2022-10-14 23:01:23 +05:30
2d9b211eeb Reduce the size of the prompt header in the task list 2022-10-14 22:58:36 +05:30
4f5a352985 Update use_cpu using UI on Redo and Double Size 2022-10-14 12:08:22 -04:00
6ae3b77c2f LoadingModel detection 2022-10-14 06:03:18 -04:00
4a7260b1be StopAsyncIteration should not trigger HTTP500.
Now returns faster into the ready state.
2022-10-14 05:20:44 -04:00
f91c77bdc6 Failed task go immediately into the buffer state with the error. 2022-10-14 04:47:13 -04:00
476e938d23 Forgot a color change for batched tasks. taskStatusLabel could have class activeTaskLabel replace by waitingTaskLabel again. 2022-10-14 04:18:34 -04:00
1ec9d986bb Render queue first draft 2022-10-14 03:47:25 -04:00
4b88cfa51a More simple time check 2022-10-14 03:43:33 -04:00
bc56226a28 Grouped many endpoints into one 2022-10-14 03:42:43 -04:00
a6e5474fdb CSS waitingTaskLabel for task waiting to start 2022-10-14 00:56:04 -04:00
8c7ca2c34d Executable permission 2022-10-13 10:40:24 +05:30
91fccc6691 Executable permission 2022-10-13 10:39:34 +05:30
93d1737357 Merge pull request #322 from madrang/prompt-fix
Remove trailing coma in promptMatrix when activeTags is empty
2022-10-13 10:36:27 +05:30
5ba1ae9ae4 Remove trailing coma in promptMatrix when activeTags is empty 2022-10-13 00:45:29 -04:00
8cb408bc6e Merge pull request #312 from madrang/guided-upscale
Added Upscale Button
2022-10-12 15:17:40 +05:30
197a89a37a Only comments changes to better describe buffering cases. 2022-10-12 03:08:25 -04:00
d336ead3b1 Updated old comments of doMakeImage to better reflect the updated reading process. 2022-10-12 02:57:09 -04:00
662644663e Improved redo when used with in-pictures editor 2022-10-12 02:32:00 -04:00
4c7819effb Corrected an issue when resuming background page on mobile and added comments to stream reader. 2022-10-12 00:33:00 -04:00
8b5b9ee8f1 Fix error on stopping tasks. 2022-10-11 23:15:06 -04:00
89b911a9dc Original code was missing a check on 'success' to abort failed tasks. 2022-10-11 22:04:41 -04:00
b673e216b6 In a batched task, keep all error messages.
If there are other batches in the task sent,
it should not remove previous errors.
2022-10-11 21:53:08 -04:00
a1b2f0ccf1 Reordered error checks to first check task status,
If none use connection status and the last step is now the generic message.
2022-10-11 20:10:40 -04:00
f269facf9d Stop hiding exceptions after read is complete. 2022-10-11 20:08:44 -04:00
5a36d280d7 Improve error display to always have some debug informations present. 2022-10-11 18:40:05 -04:00
c39563b123 Track read complete to read buffer until the end. 2022-10-11 18:38:23 -04:00
548149de8e Removed a nested try/catch that wasn't displaying all the informations.
Kept the outside try/catch that had better logging.
2022-10-11 16:42:27 -04:00
d6d4ce0ac4 Moved done check after data read in 'doMakeImage'. 2022-10-11 16:19:34 -04:00
83b0239791 Fixed an old hidden parsing crash that was there but hidden by the old try/catch block. 2022-10-11 15:32:06 -04:00
d1fa13d67a e.message wont start with 'JSON.parse' on mobile.
Removed message check but made the try/catch more narrow to not hide other errors.
2022-10-11 13:52:18 -04:00
3abd570678 Enable strict mode to throw errors on any undeclared variables. 2022-10-10 22:31:47 -04:00
b0b0781bd7 Use requestIdleCallback if available 2022-10-10 22:30:17 -04:00
1aa28ddee1 Improved Redo and DoubleSize 2022-10-10 22:29:15 -04:00
09b50badb1 Fix removing old tasks stopping the current render. 2022-10-10 22:28:34 -04:00
7060108a8b Don't hide errors if they are unexpected. 2022-10-10 22:27:49 -04:00
e6f0d5bf44 Fixed a few undeclared variables I found. 2022-10-10 22:27:15 -04:00
399642f958 Fix the broken linux developer console script 2022-10-10 19:37:05 +05:30
781effc34e Splitted ImgX2 into Redo and Double Size. 2022-10-10 04:06:15 -04:00
324c8f8146 Fixed showImages to clone batched reqBody and not reuse same objects. 2022-10-10 02:32:27 -04:00
27e372e38f Clone the complete task object instead of only reqBody.
Avoids altering already completed tasks for reruns.
2022-10-10 02:31:02 -04:00
87122ce211 Each output render need it own instance of reqBody to avoid altering the other runs after they are completed. 2022-10-09 21:18:27 -04:00
c0c6675423 Removed dead code 2022-10-09 21:16:42 -04:00
fa4aeb5261 Only replace existing seeds when needed. 2022-10-09 21:16:24 -04:00
4e51eeb998 Bug fixes for createTask, use task object, not UI infos. 2022-10-09 19:59:34 -04:00
a27c3f09b3 Renamed getStartUpscaleHandler to getStartNewTaskHandler and added new tasks types. 2022-10-09 19:58:16 -04:00
3e5f117066 Cleaned up button creation for new tasks 2022-10-09 19:56:51 -04:00
3753fb3ea4 Added upscale button with matching 'getStartUpscaleHandler' function. 2022-10-09 07:19:00 -04:00
d3e49cf1e9 Cleanup of 'createTask' 2022-10-09 07:17:43 -04:00
ffcf46a371 Set the custom temp variable only while installing 2022-10-09 10:02:59 +05:30
fc5eedbef5 Update on_sd_start.bat 2022-10-09 09:56:44 +05:30
d78b6c4445 Revert "Revert "Revert "Disable the uvicorn check, seems to be failing incorrectly for some reason"""
This reverts commit 6e056bb337.
2022-10-08 22:45:43 +05:30
6e056bb337 Revert "Revert "Disable the uvicorn check, seems to be failing incorrectly for some reason""
This reverts commit b5c2c1009c.
2022-10-08 22:43:37 +05:30
b5c2c1009c Revert "Disable the uvicorn check, seems to be failing incorrectly for some reason"
This reverts commit e30aca7531.
2022-10-08 22:37:44 +05:30
b54029a04a Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-10-08 22:26:23 +05:30
e30aca7531 Disable the uvicorn check, seems to be failing incorrectly for some reason 2022-10-08 22:26:14 +05:30
866722b68f Update README.md 2022-10-08 19:53:45 +05:30
d93f3468d3 Merge pull request #303 from madrang/resize-inpainting-disable
Resize in-painting disable
2022-10-08 19:48:43 +05:30
83032e858a Merge branch 'beta' of github.com:cmdr2/stable-diffusion-ui into beta 2022-10-08 18:22:13 +05:30
6855e314b3 Store the output format setting in localStorage 2022-10-08 18:22:01 +05:30
2c4a8619a8 Only 'resizeInpaintingEditor' if 'aspectRatio' has changed. 2022-10-08 08:42:25 -04:00
3247d83252 Refactored the readme, to make it more readable and highlight the features better 2022-10-08 18:08:06 +05:30
109ff2d8a5 Task queue screenshot 2022-10-08 18:00:23 +05:30
48797d12eb Simple screenshot 2022-10-08 17:56:50 +05:30
abe66d8af0 Updated settings screenshot 2022-10-08 17:49:14 +05:30
58c9b70b26 Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-10-08 17:38:09 +05:30
996643bde8 Update main screenshot 2022-10-08 17:37:59 +05:30
68dd9a29e8 Run 'resizeInpaintingEditor' once when 'maskSetting' is changed. 2022-10-08 07:56:01 -04:00
68c4b55945 Disable 'resizeInpaintingEditor' when 'maskSetting' is unchecked. 2022-10-08 07:55:24 -04:00
bab86c9ce2 Merge pull request #302 from cmdr2/canvas-resize
Follow the output aspect ratio in the inpainting editor
2022-10-08 16:55:36 +05:30
5f24e4d705 Increased the inpainting editor size; Fix a bug with the brush size not resetting 2022-10-08 16:53:47 +05:30
66c7b3fcb2 Don't use setAttribute to overwrite the style 2022-10-08 16:47:15 +05:30
1ffe29c657 Merge pull request #301 from madrang/resizeCanvas
Resize canvas following selected aspect ratio
2022-10-08 16:37:11 +05:30
6b7d4877e6 Initial implementation of prompt matrix - creates multiple task entries for the different permutations 2022-10-08 15:56:56 +05:30
80826eb500 Add min-width to .drawing-board-controls to keep the in-painting controls on one line. 2022-10-08 05:54:53 -04:00
11962facde resize 'inpaintingEditor' on change from 'widthField' and 'heightField' 2022-10-08 05:53:44 -04:00
c7eccfd804 Update Troubleshooting.md 2022-10-08 14:02:57 +05:30
ad617e0deb Merge pull request #300 from cmdr2/beta
Don't delete the model variables twice
2022-10-08 13:59:06 +05:30
7ae70d5a4d Don't delete the model variables twice 2022-10-08 13:58:44 +05:30
62d1a0291e Merge pull request #299 from cmdr2/beta
Unload the previous model while reloading
2022-10-08 13:19:58 +05:30
883dc72fc6 Unload the previous model while reloading 2022-10-08 13:19:18 +05:30
65b2e9633c Merge pull request #298 from cmdr2/beta
Didn't fix the ckpt bug properly
2022-10-08 12:49:09 +05:30
3b923e0d37 Didn't fix the ckpt bug properly 2022-10-08 12:48:37 +05:30
4938cb9bbc Merge pull request #297 from cmdr2/beta
Load prompts from a file; Bugfix - model load failure would incorrectly set the global state
2022-10-08 12:37:15 +05:30
a208564f06 Wait for the model to load before changing the global 'model loaded' state 2022-10-08 12:35:23 +05:30
6c6ca4daf4 Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-10-08 12:06:22 +05:30
1024da601d Set a custom temp path to workaround the pip bug 2022-10-08 12:06:11 +05:30
55d05ee590 Use euler_a and num_inference_steps 25 as the default 2022-10-07 23:54:42 +05:30
66f39e070b Read prompts from a text file; Allow specifying multiple prompts in the textbox by separating them by new lines 2022-10-07 23:46:56 +05:30
252681001e Update README.md 2022-10-07 20:09:04 +05:30
a39014b3b1 Update README.md 2022-10-07 20:08:48 +05:30
10bcfdd6b2 Revert "Merge branch 'react' into main"
This reverts commit 41ea9814e8, reversing
changes made to 06c8a004d8.
2022-10-07 20:01:15 +05:30
41ea9814e8 Merge branch 'react' into main 2022-10-07 20:00:27 +05:30
bccf7e3f69 Merge pull request #293 from cmdr2/main
Merge from main
2022-10-07 19:58:49 +05:30
06c8a004d8 Remove the old dev console scripts 2022-10-07 19:52:31 +05:30
4ab90fb14d Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-10-07 19:48:40 +05:30
54d8feeaf0 Rename dev console script 2022-10-07 19:48:24 +05:30
23d20c918f Merge pull request #292 from cmdr2/beta
Custom Models; Reduce RAM usage; JPG/PNG option
2022-10-07 19:45:17 +05:30
10012d7125 Merge branch 'main' into beta 2022-10-07 19:38:53 +05:30
d70ea854b1 Create the custom model instruction file even on existing installations 2022-10-07 19:36:18 +05:30
8c576ece28 Instructions for where to place the custom ckpt file 2022-10-07 19:33:52 +05:30
e0c0935d3a Merge pull request #275 from caranicas/react-base-tag-upgrade
React base Big Update
2022-10-07 19:14:24 +05:30
ab987e73c6 Copy the dev console script for linux on the first restart 2022-10-07 18:50:07 +05:30
cec203a6db Allow saving in jpeg or png format; Default to saving in jpeg 2022-10-06 15:05:34 +05:30
cf8bb9efb0 Don't reload the model when using an initial image; Work in half-precision for txt2img as well, no change in the output image noticed 2022-10-06 14:42:47 +05:30
201a053025 Support an arbitrary number of custom models, placed in the models/stable-diffusion folder. Shows an option in the UI to select which model to use 2022-10-06 14:28:02 +05:30
703f987825 Copy the dev console script on the first update. Temporary until enough people have this update 2022-10-06 11:58:32 +05:30
4e3d677d8e Developer console, to enter the activated conda environment easily for debugging and fixing the environnment 2022-10-06 11:58:27 +05:30
aab90130d2 Copy the dev console script on the first update. Temporary until enough people have this update 2022-10-06 11:25:14 +05:30
9321dfdd89 Developer console, to enter the activated conda environment easily for debugging and fixing the environnment 2022-10-06 10:37:41 +05:30
2607ef5fe0 working positive and negative prompts 2022-10-02 18:18:35 -04:00
84b291a57a built 2022-10-01 20:30:46 -04:00
3271c5a60b react-base-history-tab 2022-10-01 20:25:27 -04:00
79bb66f535 better layout grid 2022-10-01 18:46:22 -04:00
1616885e7f hide history 2022-10-01 17:01:20 -04:00
85045c3e9c wip 2022-10-01 08:19:24 -04:00
4710d18e33 slight adjustment 2022-09-30 19:07:16 -04:00
3da75494b0 type fixes and build 2022-09-30 17:17:22 -04:00
ac021f38da build 2022-09-30 16:51:03 -04:00
d0a2c36f6c tightened up themeing and cards more and more 2022-09-30 16:48:20 -04:00
9facc9379f getting the cards and tabs sorted out 2022-09-30 14:52:21 -04:00
a0f4e2659b working on cards and backgrounds 2022-09-30 12:54:23 -04:00
4dfa3d8372 cleaned and built 2022-09-30 12:29:42 -04:00
30563ee04c all buttons are a recipe now 2022-09-30 12:23:18 -04:00
3fa7594fcc move to hsl color system 2022-09-30 11:33:39 -04:00
ccfa32ce93 Report the error in the UI. Regression after switching to the task queue 2022-09-30 10:53:30 +05:30
fcb41e30dc Fix a bug with the linux script, where the file size check would fail if the group name had spaces 2022-09-30 10:45:08 +05:30
5ed6bba412 clean build 2022-09-29 14:26:06 -04:00
50e929eb0c working queue 2022-09-29 14:23:12 -04:00
129839ce21 decent queue display 2022-09-29 12:54:13 -04:00
fd2961ecb9 Merge branch 'react-base' into react-base-queue 2022-09-29 09:03:52 -04:00
e506d988e2 wip 2022-09-29 09:02:43 -04:00
196649c0e9 Use the correct seed from the response 2022-09-29 13:55:09 +05:30
12182ee04f Newer images go on top 2022-09-29 13:52:48 +05:30
5db64526cc Fix a bug where batches would overwrite the previous images inside a task 2022-09-29 13:43:25 +05:30
5c2ec70eb4 Hide the sampler field when an output image is used as the new input 2022-09-29 13:12:01 +05:30
24a2c6251f Remove log statement 2022-09-29 13:08:58 +05:30
0d035d9ae9 Remove unnecessary semicolons 2022-09-29 13:08:42 +05:30
a28f1294e2 Integrate with beta; Use the outputContainer for the task; Don't show the info while a live preview is generating; Use the local task container reference instead of a seed-based identifier (will fail if the seed is same across two tasks) 2022-09-29 13:01:18 +05:30
a3b0cde59d Merge pull request #242 from Hakorr/main
Image item refactor
2022-09-29 12:03:45 +05:30
c2dec9eac4 Merge branch 'haka-fix' into main 2022-09-29 12:00:44 +05:30
0fdb49f168 Merge pull request #260 from caranicas/react-base-nav
React base - Nav, Audio, Display,
2022-09-29 11:58:04 +05:30
e86d02765f properly styled buttons 2022-09-28 18:38:47 -04:00
6e877aea02 added stop and queue clear 2022-09-28 18:14:18 -04:00
330f1577fd tightened up center display 2022-09-28 16:29:11 -04:00
ff980591c3 tightened up center display 2022-09-28 15:40:43 -04:00
60992ae492 fix up types, and display id 2022-09-28 13:34:00 -04:00
1b439c15f6 added audio ding 2022-09-28 12:54:15 -04:00
f58c16ab03 commented 2022-09-28 12:23:33 -04:00
b560d2953f updated nav and removed ts comments 2022-09-28 12:19:44 -04:00
2c52c8efb7 better nav 2022-09-28 11:58:47 -04:00
5375166f04 moved the settings 2022-09-28 11:22:17 -04:00
5e85cae9ce Merge branch 'react-base' into react-base-nav 2022-09-28 09:14:28 -04:00
0ae449fd44 Merge pull request #257 from caranicas/react-base-inpainting
React base inpainting
2022-09-28 18:39:50 +05:30
4f5b4f387a Merge pull request #258 from cmdr2/main
Merge main
2022-09-28 18:39:37 +05:30
a8d3d613b0 Merge branch 'react-base' into react-base-inpainting 2022-09-28 09:01:21 -04:00
c680fbe834 clean 2022-09-28 08:52:12 -04:00
286c77778f Merge pull request #247 from caranicas/react-base-streaming-test
React base streaming test
2022-09-28 11:10:48 +05:30
10c4bee1e5 Fix for show all images 2022-09-28 00:05:34 +03:00
f26b8ee224 build 2022-09-27 14:51:51 -04:00
1961567ebd got the inpainting mask sent to the server 2022-09-27 14:50:05 -04:00
094687717d external changes 2022-09-27 13:45:29 -04:00
e5844c926b tags working 2022-09-27 13:37:28 -04:00
96ad8c823a wokring checkmark, cleaner time adn translation 2022-09-27 11:02:58 -04:00
de2977284c fixed time remaining and progress display 2022-09-27 10:45:36 -04:00
c1dea44fa6 Fix for live preview 2022-09-27 17:23:19 +03:00
5a105eb2b3 fix timestamp 2022-09-27 09:46:32 -04:00
7a076f7304 clean ups 2022-09-27 09:28:04 -04:00
986b303f2f reselct and delete working 2022-09-26 17:36:21 -04:00
afd8717c21 poc streaming image response 2022-09-26 17:06:42 -04:00
6effd783c0 wip 2022-09-26 16:53:13 -04:00
b8f47545ed fix ordering 2022-09-26 16:50:34 -04:00
a6394b2dce history displaying 2022-09-26 11:15:13 -04:00
5ba802dc68 Overlaid info 2022-09-26 17:50:27 +03:00
76c72c1a7f get a bit closer, and add some notes 2022-09-25 19:21:09 -04:00
1c1cf58409 fix shift 2022-09-25 11:00:53 -04:00
8155e3ef7a actual displaying 2022-09-25 10:57:37 -04:00
62048c68f0 Image item refactor and redesign 2022-09-25 02:55:11 +03:00
f32df2ac9c Merge branch 'react-base' into react-base-streaming-test 2022-09-24 13:50:20 -04:00
22a0b3be45 workable plan 2022-09-24 13:47:30 -04:00
3490d0d743 Merge pull request #239 from cmdr2/main
Merge main
2022-09-24 22:51:06 +05:30
fbe829def7 Merge from main 2022-09-24 18:55:53 +05:30
161eea3e9e Merge pull request #232 from caranicas/react-base-sampler
sampler fix
2022-09-24 11:19:12 +05:30
d1e792686e added some options to test 2022-09-23 13:31:56 -04:00
62fe380520 add default values to false 2022-09-23 13:20:15 -04:00
319f08c4c9 sampler fix 2022-09-23 12:49:37 -04:00
0d13fe67b0 Merge pull request #227 from cmdr2/beta
Merge beta
2022-09-23 17:59:31 +05:30
a0c6e9e490 Merge branch 'beta' into react 2022-09-22 23:04:48 +05:30
56960d6da9 Merge branch 'beta' into react 2022-09-22 22:56:45 +05:30
2590dc690e Merge pull request #191 from caranicas/beta-react
Beta react
2022-09-21 23:18:00 +05:30
e2545b3d34 Merge branch 'react' into beta-react 2022-09-21 23:17:33 +05:30
bf4d920fb4 Merge pull request #33 from caranicas/beta-react-linting-pt2
Beta react linting pt2
2022-09-20 14:22:17 -04:00
d84fb244d3 fix all the linting errors i can 2022-09-20 14:21:21 -04:00
f04b5244fa cleaning up type issues 2022-09-20 12:35:44 -04:00
6f3829fa91 remove debug 2022-09-20 09:55:33 -04:00
a5ae3545d5 Merge pull request #32 from caranicas/react-beta-linting-clean
React beta linting clean
2022-09-20 09:52:02 -04:00
63b658ac50 linting and some type fixes 2022-09-20 09:50:50 -04:00
e8544be30a hide inert ui for now 2022-09-20 09:49:50 -04:00
39090451f0 fix the linting issue and index error 2022-09-20 09:36:12 -04:00
12fc6e6354 Merge pull request #31 from mrbusysky/beta-react
Updates for translations
2022-09-20 09:09:12 -04:00
154326061d Translation update part 2 2022-09-19 18:39:44 -07:00
0bbfd574b3 pretty fixes 2022-09-19 17:52:01 -07:00
eff3887f35 updates for static words part 1 2022-09-19 17:49:03 -07:00
34cb532e6b adjust footer to center 2022-09-19 19:02:01 -04:00
cf1d1a97f3 Merge pull request #30 from caranicas/beta-react-translation
language switcher
2022-09-19 15:57:18 -04:00
e0a4f0bc4c language switcher 2022-09-19 15:52:51 -04:00
1ac8eba1b8 clean and pretty 2022-09-19 15:40:34 -04:00
82f8c31b81 fix some linting issues 2022-09-19 15:37:21 -04:00
9f2ae75fa2 Merge pull request #29 from caranicas/beta-react-loading-and-cache
Beta react loading and cache
2022-09-19 15:08:37 -04:00
9d220c482d loading and cache are better 2022-09-19 15:07:47 -04:00
c4718bd302 add basic loading 2022-09-19 14:05:01 -04:00
e1e2a90498 fix build 2022-09-19 13:40:17 -04:00
40a48954c3 Merge pull request #28 from caranicas/beta-react-style-clean-pt2
Beta react style clean pt2
2022-09-19 13:34:39 -04:00
e81068f528 footer looking better 2022-09-19 13:32:20 -04:00
0591487cfd creation ui is better 2022-09-19 13:19:19 -04:00
737ed7ba5d clean up font ambiguity 2022-09-19 12:47:55 -04:00
27fd1f39f0 css clean 2022-09-19 12:04:14 -04:00
1210313e7f Merge pull request #27 from caranicas/beta-react-i18n-lint
Beta react i18n lint
2022-09-19 11:37:56 -04:00
4733c8fb75 add linting rules to help out with i18n 2022-09-19 11:36:56 -04:00
8777e65996 work on identical keys 2022-09-19 10:57:31 -04:00
330fa10935 i18n linting 2022-09-19 10:30:33 -04:00
1bd4a0f4ee basic linting 2022-09-19 10:14:50 -04:00
bea8ae55de remove space 2022-09-19 10:05:52 -04:00
b99cd49091 lf line endings 2022-09-19 10:03:08 -04:00
35f3b70968 Merge pull request #26 from mrbusysky/beta-react
Translation added
2022-09-19 09:07:27 -04:00
e33f3231d0 matching pre merge issue translation 2022-09-18 18:57:17 -07:00
b6cf6ee94a Translation Update
Still need to replace all the static words in pages.
2022-09-18 18:40:34 -07:00
6118518b1b Updating to match
there was to many merge conflicts
2022-09-18 18:33:03 -07:00
f77d5ebfd2 fix cache time 2022-09-18 20:53:18 -04:00
fcf5c41709 fix undefined bug 2022-09-18 20:40:17 -04:00
7f3279f20f Merge pull request #25 from caranicas/beta-react-filter-fix
fix filter and some styling
2022-09-18 19:25:42 -04:00
c23de50f3e fix filter and some styling 2022-09-18 19:24:35 -04:00
51f1759323 Merge pull request #24 from caranicas/beta-react-display-loading
Beta react display loading
2022-09-18 15:44:31 -04:00
cedc634933 display clean 2022-09-18 15:21:39 -04:00
c7b89a1126 current and cache history 2022-09-18 15:19:31 -04:00
bad015de9a Merge pull request #23 from caranicas/beta-react-prompt-and-beta
Beta react prompt gate, beta checkmark, styling iteration
2022-09-18 11:18:51 -04:00
21057759de remove logs 2022-09-18 11:16:09 -04:00
d027352d79 disabled beta check for now 2022-09-18 11:14:17 -04:00
fd8c568d75 working beta 2022-09-18 11:12:41 -04:00
85292ca1b4 adding recipe 2022-09-17 20:26:24 -04:00
1ab90e76d1 solidifed the styles 2022-09-17 17:23:14 -04:00
1e9e9daeb3 wip 2022-09-17 16:30:47 -04:00
65682a8130 Merge pull request #21 from caranicas/beta-react-theme
theme scaffold
2022-09-17 14:18:51 -04:00
bca225e692 theme scaffold 2022-09-17 14:18:05 -04:00
4fbc46b3b3 Merge pull request #20 from caranicas/beta-react-draw
Beta react draw
2022-09-17 12:47:00 -04:00
4b3806fb9a clean 2022-09-17 12:38:19 -04:00
5abbec94c4 working 2022-09-17 12:23:50 -04:00
346d1dddba decent drawing tools 2022-09-17 11:58:21 -04:00
8b48ad77e8 organize the inpainting display 2022-09-16 21:07:42 -04:00
64d97a3232 build and pretty 2022-09-16 18:35:48 -04:00
94a208bd91 drawing basics 2022-09-16 18:32:48 -04:00
b15ac8b13e wip 2022-09-16 16:58:05 -04:00
0ddff9d551 organized draw image 2022-09-16 16:41:30 -04:00
7c31dbb3d6 Merge pull request #19 from caranicas/beta-react-app-config
new config route and tighter header
2022-09-16 15:25:58 -04:00
6ee995afaa new config route and tighter header 2022-09-16 14:34:10 -04:00
691acb647e Merge pull request #18 from caranicas/beta-react-display
Beta react display
2022-09-16 13:31:11 -04:00
80d9d88de1 persistent state and reduced unneeded boolean logic 2022-09-16 13:29:32 -04:00
cf12abfc7f better store and disabling 2022-09-16 12:56:57 -04:00
b21ec7a302 patching cors issue with modifcations 2022-09-16 11:32:36 -04:00
972473f1af drawing in progress 2022-09-15 20:25:48 -04:00
ee8e0b46a2 letter box image 2022-09-15 19:48:12 -04:00
1c3d270402 Merge pull request #15 from caranicas/beta-react-router
basic routing
2022-09-15 16:39:38 -04:00
9d09d2042a properly installed and clean 2022-09-15 16:36:08 -04:00
b8823ade29 basic routing 2022-09-15 16:25:02 -04:00
0e5b01f897 Merge pull request #13 from caranicas/beta-react-advanced-settings
Beta react advanced settings
2022-09-15 15:38:46 -04:00
87f221290f pretty and build 2022-09-15 15:37:36 -04:00
fd3b0c20b6 advanced panels 2022-09-15 15:35:41 -04:00
93e71027fd advanced settings organaized and dropdowns 2022-09-15 15:16:42 -04:00
c6852c70fd new build 2022-09-15 13:45:23 -04:00
953773aaa8 pretty 2022-09-15 13:44:08 -04:00
e0a139d083 Merge pull request #12 from caranicas/beta-react-ui
Beta react UI
2022-09-15 13:37:22 -04:00
867140df30 creation ui soldified 2022-09-15 13:34:54 -04:00
8a354e6187 using vanilla extract for main and app 2022-09-15 10:19:09 -04:00
6afd4b0dc7 Merge pull request #11 from caranicas/beta-react-style-cleanup
working display panel
2022-09-14 19:03:48 -04:00
e2517ef50e remove unneeded 2022-09-14 19:03:26 -04:00
ad6798eaad fixed most of the big css issues 2022-09-14 19:00:51 -04:00
2a5fcc0846 working display panel 2022-09-14 18:38:31 -04:00
37592a876e fix the image preview display 2022-09-14 17:56:38 -04:00
4979e176c7 updated dist 2022-09-14 17:25:50 -04:00
f3fdac2762 tidy and pretty 2022-09-14 17:24:18 -04:00
9a67617cef Merge pull request #10 from caranicas/beta-react-audio
Beta react audio
2022-09-14 17:20:14 -04:00
96e43cbb65 audio component and gated 2022-09-14 17:19:40 -04:00
458dc5b232 Merge branch 'beta-react' into beta-react-audio 2022-09-14 16:59:36 -04:00
28a7c6d3aa wip 2022-09-14 16:59:14 -04:00
d3c241d283 Merge pull request #9 from caranicas/beta-react-creation-options
Beta react creation options
2022-09-14 16:50:17 -04:00
445959abbd fix issue with upsclaing checkbox 2022-09-14 16:49:27 -04:00
62842968cb upscaling and face fixing passing thru 2022-09-14 16:45:12 -04:00
2dda683aa6 face correctiona and scaling passing thru properly 2022-09-14 16:33:56 -04:00
616167e08c Merge pull request #8 from caranicas/beta-react-asset-fix
moved assets
2022-09-14 15:42:29 -04:00
acd74c60c8 moved assets 2022-09-14 15:35:39 -04:00
c1c4a2933e make pretty 2022-09-14 14:49:23 -04:00
8158ead1a2 fix testing values 2022-09-14 14:32:01 -04:00
fcc196f452 Merge pull request #7 from caranicas/beta-react-file-responses
file metadata and saveing
2022-09-14 14:28:10 -04:00
d55e2492d4 file metadata and saveing 2022-09-14 14:23:55 -04:00
45e05b0891 Merge pull request #6 from caranicas/beta-react-parallel-logic
updated parallel logic
2022-09-14 13:25:53 -04:00
eb53739c95 fix modifiers path 2022-09-14 13:20:19 -04:00
4a35059711 comments 2022-09-14 13:07:27 -04:00
a1ad1147e6 adjust server 2022-09-14 12:57:03 -04:00
eefa7d53c5 updated parallel logic 2022-09-14 12:53:28 -04:00
716491a68e clean build, and moved assets 2022-09-14 11:16:36 -04:00
29e5263fcc add a comment 2022-09-14 11:05:50 -04:00
4df61d7efc hide original dom 2022-09-14 10:52:19 -04:00
34aa60d47b inital push 2022-09-14 10:48:46 -04:00
129 changed files with 26120 additions and 3853 deletions

27
3rd-PARTY-LICENSES Normal file
View File

@ -0,0 +1,27 @@
jquery-confirm
==============
https://craftpip.github.io/jquery-confirm/
jquery-confirm is licensed under the MIT license:
The MIT License (MIT)
Copyright (c) 2019 Boniface Pereira
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

140
CHANGES.md Normal file
View File

@ -0,0 +1,140 @@
# What's new?
## v2.5
### Major Changes
- **Nearly twice as fast** - significantly faster speed of image generation. We're now pretty close to automatic1111's speed. Code contributions are welcome to make our project even faster: https://github.com/easydiffusion/sdkit/#is-it-fast
- **Mac M1/M2 support** - Experimental support for Mac M1/M2. Thanks @michaelgallacher, @JeLuf and vishae.
- **Full support for Stable Diffusion 2.1 (including CPU)** - supports loading v1.4 or v2.0 or v2.1 models seamlessly. No need to enable "Test SD2", and no need to add `sd2_` to your SD 2.0 model file names. Works on CPU as well.
- **Memory optimized Stable Diffusion 2.1** - you can now use Stable Diffusion 2.1 models, with the same low VRAM optimizations that we've always had for SD 1.4. Please note, the SD 2.0 and 2.1 models require more GPU and System RAM, as compared to the SD 1.4 and 1.5 models.
- **11 new samplers!** - explore the new samplers, some of which can generate great images in less than 10 inference steps! We've added the Karras and UniPC samplers. Thanks @Schorny for the UniPC samplers.
- **Model Merging** - You can now merge two models (`.ckpt` or `.safetensors`) and output `.ckpt` or `.safetensors` models, optionally in `fp16` precision. Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging . Thanks @JeLuf.
- **Fast loading/unloading of VAEs** - No longer needs to reload the entire Stable Diffusion model, each time you change the VAE
- **Database of known models** - automatically picks the right configuration for known models. E.g. we automatically detect and apply "v" parameterization (required for some SD 2.0 models), and "fp32" attention precision (required for some SD 2.1 models).
- **Color correction for img2img** - an option to preserve the color profile (histogram) of the initial image. This is especially useful if you're getting red-tinted images after inpainting/masking.
- **Three GPU Memory Usage Settings** - `High` (fastest, maximum VRAM usage), `Balanced` (default - almost as fast, significantly lower VRAM usage), `Low` (slowest, very low VRAM usage). The `Low` setting is applied automatically for GPUs with less than 4 GB of VRAM.
- **Find models in sub-folders** - This allows you to organize your models into sub-folders inside `models/stable-diffusion`, instead of keeping them all in a single folder. Thanks @patriceac and @ogmaresca.
- **Custom Modifier Categories** - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca.
- **Embed metadata, or save as TXT/JSON** - You can now embed the metadata directly into the images, or save them as text or json files (choose in the Settings tab). Thanks @patriceac.
- **Major rewrite of the code** - Most of the codebase has been reorganized and rewritten, to make it more manageable and easier for new developers to contribute features. We've separated our core engine into a new project called `sdkit`, which allows anyone to easily integrate Stable Diffusion (and related modules like GFPGAN etc) into their programming projects (via a simple `pip install sdkit`): https://github.com/easydiffusion/sdkit/
- **Name change** - Last, and probably the least, the UI is now called "Easy Diffusion". It indicates the focus of this project - an easy way for people to play with Stable Diffusion.
Our focus continues to remain on an easy installation experience, and an easy user-interface. While still remaining pretty powerful, in terms of features and speed.
### Detailed changelog
* 2.5.24 - 11 Mar 2023 - Button to load an image mask from a file.
* 2.5.24 - 10 Mar 2023 - Logo change. Image credit: @lazlo_vii.
* 2.5.23 - 8 Mar 2023 - Experimental support for Mac M1/M2. Thanks @michaelgallacher, @JeLuf and vishae!
* 2.5.23 - 8 Mar 2023 - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). More details - https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca.
* 2.5.22 - 28 Feb 2023 - Minor styling changes to UI buttons, and the models dropdown.
* 2.5.22 - 28 Feb 2023 - Lots of UI-related bug fixes. Thanks @patriceac.
* 2.5.21 - 22 Feb 2023 - An option to control the size of the image thumbnails. You can use the `Display options` in the top-right corner to change this. Thanks @JeLuf.
* 2.5.20 - 20 Feb 2023 - Support saving images in WEBP format (which consumes less disk space, with similar quality). Thanks @ogmaresca.
* 2.5.20 - 18 Feb 2023 - A setting to block NSFW images from being generated. You can enable this setting in the Settings tab.
* 2.5.19 - 17 Feb 2023 - Initial support for server-side plugins. Currently supports overriding the `get_cond_and_uncond()` function.
* 2.5.18 - 17 Feb 2023 - 5 new samplers! UniPC samplers, some of which produce images in less than 15 steps. Thanks @Schorny.
* 2.5.16 - 13 Feb 2023 - Searchable dropdown for models. This is useful if you have a LOT of models. You can type part of the model name, to auto-search through your models. Thanks @patriceac for the feature, and @AssassinJN for help in UI tweaks!
* 2.5.16 - 13 Feb 2023 - Lots of fixes and improvements to the installer. First round of changes to add Mac support. Thanks @JeLuf.
* 2.5.16 - 13 Feb 2023 - UI bug fixes for the inpainter editor. Thanks @patriceac.
* 2.5.16 - 13 Feb 2023 - Fix broken task reorder. Thanks @JeLuf.
* 2.5.16 - 13 Feb 2023 - Remove a task if all the images inside it have been removed. Thanks @AssassinJN.
* 2.5.16 - 10 Feb 2023 - Embed metadata into the JPG/PNG images, if selected in the "Settings" tab (under "Metadata format"). Thanks @patriceac.
* 2.5.16 - 10 Feb 2023 - Sort models alphabetically in the models dropdown. Thanks @ogmaresca.
* 2.5.16 - 10 Feb 2023 - Support multiple GFPGAN models. Download new GFPGAN models into the `models/gfpgan` folder, and refresh the UI to use it. Thanks @JeLuf.
* 2.5.16 - 10 Feb 2023 - Allow a server to enforce a fixed directory path to save images. This is useful if the server is exposed to a lot of users. This can be set in the `config.json` file as `force_save_path: "/path/to/fixed/save/dir"`. E.g. `force_save_path: "D:/user_images"`. Thanks @JeLuf.
* 2.5.16 - 10 Feb 2023 - The "Make Images" button now shows the correct amount of images it'll create when using operators like `{}` or `|`. For e.g. if the prompt is `Photo of a {woman, man}`, then the button will say `Make 2 Images`. Thanks @JeLuf.
* 2.5.16 - 10 Feb 2023 - A bunch of UI-related bug fixes. Thanks @patriceac.
* 2.5.15 - 8 Feb 2023 - Allow using 'balanced' VRAM usage mode on GPUs with 4 GB or less of VRAM. This mode used to be called 'Turbo' in the previous version.
* 2.5.14 - 8 Feb 2023 - Fix broken auto-save settings. We renamed `sampler` to `sampler_name`, which caused old settings to fail.
* 2.5.14 - 6 Feb 2023 - Simplify the UI for merging models, and some other minor UI tweaks. Better error reporting if a model failed to load.
* 2.5.14 - 3 Feb 2023 - Fix the 'Make Similar Images' button, which was producing incorrect images (weren't very similar).
* 2.5.13 - 1 Feb 2023 - Fix the remaining GPU memory leaks, including a better fix (more comprehensive) for the change in 2.5.12 (27 Jan).
* 2.5.12 - 27 Jan 2023 - Fix a memory leak, which made the UI unresponsive after an out-of-memory error. The allocated memory is now freed-up after an error.
* 2.5.11 - 25 Jan 2023 - UI for Merging Models. Thanks @JeLuf. More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging
* 2.5.10 - 24 Jan 2023 - Reduce the VRAM usage for img2img in 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of this UI.
* 2.5.9 - 23 Jan 2023 - Fix a bug where img2img would produce poorer-quality images for the same settings, as compared to version 2.4 of this UI.
* 2.5.9 - 23 Jan 2023 - Reduce the VRAM usage for 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of the UI.
* 2.5.8 - 17 Jan 2023 - Fix a bug where 'Low' VRAM usage would consume a LOT of VRAM (on higher-end GPUs). Also fixed a bug that caused out-of-memory errors on SD 2.1-768 models, on 'high' VRAM usage setting.
* 2.5.7 - 16 Jan 2023 - Fix a bug where VAE files ending with .vae.pt weren't getting displayed. Thanks Madrang, rbertus2000 and JeLuf.
* 2.5.6 - 10 Jan 2023 - `Fill` tool for the Image Editor, to allow filling areas with color (or the entire image). And some bug fixes to the Image Editor. Thanks @mdiller.
* 2.5.6 - 10 Jan 2023 - Find Stable Diffusion models in sub-folders inside `models/stable-diffusion`. This allows you to organize your models into sub-folders, instead of keeping them all in a single folder. Thanks @JeLuf.
* 2.5.5 - 9 Jan 2023 - Lots of bug fixes. Thanks @patriceac and @JeLuf.
* 2.5.4 - 29 Dec 2022 - Press Esc key on the keyboard to close the Image Editor. Thanks @patriceac.
* 2.5.4 - 29 Dec 2022 - Lots of bug fixes in the UI. Thanks @patriceac.
* 2.5.4 - 28 Dec 2022 - Full support for running tasks in parallel on multiple GPUs. Warning: 'Euler Ancestral', 'DPM2 Ancestral' and 'DPM++ 2s Ancestral' may produce slight variations in the image (if run in parallel), so we recommend using the other samplers.
* 2.5.3 - 27 Dec 2022 - Fix broken drag-and-drop for text metadata files (as well as paste in clipboard).
* 2.5.3 - 27 Dec 2022 - Allow upscaling by 2x as well as 4x.
* 2.5.3 - 27 Dec 2022 - Fix broken renders on a second GPU.
* 2.5.3 - 26 Dec 2022 - Add a `Remove` button on each image. Thanks @JeLuf.
* 2.5.2 - 26 Dec 2022 - Fix broken inpainting if using non-square target images.
* 2.5.2 - 26 Dec 2022 - Fix a bug where an incorrect model config would get used for some SD 2.1 models.
* 2.5.2 - 26 Dec 2022 - Slight performance and memory improvement while rendering using SD 2.1 models.
* 2.5.1 - 25 Dec 2022 - Allow custom config yaml files for models. You can put a config file (`.yaml`) next to the model file, with the same name as the model. For e.g. if you put `robo-diffusion-v2-base.yaml` next to `robo-diffusion-v2-base.ckpt`, it'll automatically use that config file.
* 2.5.1 - 25 Dec 2022 - Fix broken rendering for SD 2.1-768 models. Fix broken rendering SD 2.0 safetensor models.
* 2.5.0 - 25 Dec 2022 - Major new release! Nearly twice as fast, Full support for SD 2.1 (including low GPU RAM optimizations), 6 new samplers, Model Merging, Fast loading/unloading of VAEs, Database of known models, Color correction for img2img, Three GPU Memory Usage Settings, Save metadata as JSON, Major rewrite of the code, Name change.
## v2.4
### Major Changes
- **Allow reordering the task queue** (by dragging and dropping tasks). Thanks @madrang
- **Automatic scanning for malicious model files** - using `picklescan`, and support for `safetensor` model format. Thanks @JeLuf
- **Image Editor** - for drawing simple images for guiding the AI. Thanks @mdiller
- **Use pre-trained hypernetworks** - for improving the quality of images. Thanks @C0bra5
- **Support for custom VAE models**. You can place your VAE files in the `models/vae` folder, and refresh the browser page to use them. More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder
- **Experimental support for multiple GPUs!** It should work automatically. Just open one browser tab per GPU, and spread your tasks across your GPUs. For e.g. open our UI in two browser tabs if you have two GPUs. You can customize which GPUs it should use in the "Settings" tab, otherwise let it automatically pick the best GPUs. Thanks @madrang . More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/Run-on-Multiple-GPUs
- **Cleaner UI design** - Show settings and help in new tabs, instead of dropdown popups (which were buggy). Thanks @mdiller
- **Progress bar.** Thanks @mdiller
- **Custom Image Modifiers** - You can now save your custom image modifiers! Your saved modifiers can include special characters like `{}, (), [], |`
- Drag and Drop **text files generated from previously saved images**, and copy settings to clipboard. Thanks @madrang
- Paste settings from clipboard. Thanks @JeLuf
- Bug fixes to reduce the chances of tasks crashing during long multi-hour runs (chrome can put long-running background tabs to sleep). Thanks @JeLuf and @madrang
- **Improved documentation.** Thanks @JeLuf and @jsuelwald
- Improved the codebase for dealing with system settings and UI settings. Thanks @mdiller
- Help instructions next to some setttings, and in the tab
- Show system info in the settings tab
- Keyboard shortcut: Ctrl+Enter to start a task
- Configuration to prevent the browser from opening on startup
- Lots of minor bug fixes
- A `What's New?` tab in the UI
- Ask for a confimation before clearing the results pane or stopping a render task. The dialog can be skipped by holding down the shift key while clicking on the button.
- Show the network addresses of the server in the systems setting dialog
- Support loading models in the safetensor format, for improved safety
### Detailed changelog
* 2.4.24 - 9 Jan 2022 - Urgent fix for failures on old/long-term-support browsers. Thanks @JeLuf.
* 2.4.23/22 - 29 Dec 2022 - Allow rolling back from the upcoming v2.5 change (in beta).
* 2.4.21 - 23 Dec 2022 - Speed up image creation, by removing a delay (regression) of 4-5 seconds between clicking the `Make Image` button and calling the server.
* 2.4.20 - 22 Dec 2022 - `Pause All` button to pause all the pending tasks. Thanks @JeLuf
* 2.4.20 - 22 Dec 2022 - `Undo`/`Redo` buttons in the image editor. Thanks @JeLuf
* 2.4.20 - 22 Dec 2022 - Drag handle to reorder the tasks. This fixed a bug where the metadata was no longer selectable (for copying). Thanks @JeLuf
* 2.4.19 - 17 Dec 2022 - Add Undo/Redo buttons in the Image Editor. Thanks @JeLuf
* 2.4.19 - 10 Dec 2022 - Show init img in task list
* 2.4.19 - 7 Dec 2022 - Use pre-trained hypernetworks while generating images. Thanks @C0bra5
* 2.4.19 - 6 Dec 2022 - Allow processing new tasks first. Thanks @madrang
* 2.4.19 - 6 Dec 2022 - Allow reordering the task queue (by dragging tasks). Thanks @madrang
* 2.4.19 - 6 Dec 2022 - Re-organize the code, to make it easier to write user plugins. Thanks @madrang
* 2.4.18 - 5 Dec 2022 - Make JPEG Output quality user controllable. Thanks @JeLuf
* 2.4.18 - 5 Dec 2022 - Support loading models in the safetensor format, for improved safety. Thanks @JeLuf
* 2.4.18 - 1 Dec 2022 - Image Editor, for drawing simple images for guiding the AI. Thanks @mdiller
* 2.4.18 - 1 Dec 2022 - Disable an image modifier temporarily by right-clicking it. Thanks @patriceac
* 2.4.17 - 30 Nov 2022 - Scroll to generated image. Thanks @patriceac
* 2.4.17 - 30 Nov 2022 - Show the network addresses of the server in the systems setting dialog. Thanks @JeLuf
* 2.4.17 - 30 Nov 2022 - Fix a bug where GFPGAN wouldn't work properly when multiple GPUs tried to run it at the same time. Thanks @madrang
* 2.4.17 - 30 Nov 2022 - Confirm before stopping or clearing all the tasks. Thanks @JeLuf
* 2.4.16 - 29 Nov 2022 - Bug fixes for SD 2.0 - remove the need for patching, default to SD 1.4 model if trying to load an SD2 model in SD1.4.
* 2.4.15 - 25 Nov 2022 - Experimental support for SD 2.0. Uses lots of memory, not optimized, probably GPU-only.
* 2.4.14 - 22 Nov 2022 - Change the backend to a custom fork of Stable Diffusion
* 2.4.13 - 21 Nov 2022 - Change the modifier weight via mouse wheel, drag to reorder selected modifiers, and some more modifier-related fixes. Thanks @patriceac
* 2.4.12 - 21 Nov 2022 - Another fix for improving how long images take to generate. Reduces the time taken for an enqueued task to start processing.
* 2.4.11 - 21 Nov 2022 - Installer improvements: avoid crashing if the username contains a space or special characters, allow moving/renaming the folder after installation on Windows, whitespace fix on git apply
* 2.4.11 - 21 Nov 2022 - Validate inputs before submitting the Image request
* 2.4.11 - 19 Nov 2022 - New system settings to manage the network config (port number and whether to only listen on localhost)
* 2.4.11 - 19 Nov 2022 - Address a regression in how long images take to generate. Use the previous code for moving a model to CPU. This improves things by a second or two per image, but we still have a regression (investigating).
* 2.4.10 - 18 Nov 2022 - Textarea for negative prompts. Thanks @JeLuf
* 2.4.10 - 18 Nov 2022 - Improved design for Settings, and rounded toggle buttons instead of checkboxes for a more modern look. Thanks @mdiller
* 2.4.9 - 18 Nov 2022 - Add Picklescan - a scanner for malicious model files. If it finds a malicious file, it will halt the web application and alert the user. Thanks @JeLuf
* 2.4.8 - 18 Nov 2022 - A `Use these settings` button to use the settings from a previously generated image task. Thanks @patriceac
* 2.4.7 - 18 Nov 2022 - Don't crash if a VAE file fails to load
* 2.4.7 - 17 Nov 2022 - Fix a bug where Face Correction (GFPGAN) would fail on cuda:N (i.e. GPUs other than cuda:0), as well as fail on CPU if the system had an incompatible GPU.
* 2.4.6 - 16 Nov 2022 - Fix a regression in VRAM usage during startup, which caused 'Out of Memory' errors when starting on GPUs with 4gb (or less) VRAM
* 2.4.5 - 16 Nov 2022 - Add checkbox for "Open browser on startup".
* 2.4.5 - 16 Nov 2022 - Add a directory for core plugins that ship with Stable Diffusion UI by default.
* 2.4.5 - 16 Nov 2022 - Add a "What's New?" tab as a core plugin, which fetches the contents of CHANGES.md from the app's release branch.

View File

@ -6,19 +6,18 @@ Thanks
# For developers:
If you would like to contribute to this project, there is a discord for dicussion:
If you would like to contribute to this project, there is a discord for discussion:
[![Discord Server](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.com/invite/u9yhsFmEkB)
## Development environment for UI (frontend and server) changes
This is in-flux, but one way to get a development environment running for editing the UI of this project is:
(swap `.sh` or `.bat` in instructions depending on your environment, and be sure to adjust any paths to match where you're working)
1) `git clone` the repository, e.g. to `/projects/stable-diffusion-ui-repo`
2) Download the pre-built end user archive from the link on github, and extract it, e.g. to `/projects/stable-diffusion-ui-archive`
3) `cd /projects/stable-diffusion-ui-archive` and run the script to set up and start the project, e.g. `start.sh`
4) Check you can view and generate images on `localhost:9000`
5) Close the server, and edit `/projects/stable-diffusion-ui-archive/scripts/on_env_start.sh`
6) Comment out the lines near the bottom that copies the `files/ui` folder, e.g:
1) Install the project to a new location using the [usual installation process](https://github.com/cmdr2/stable-diffusion-ui#installation), e.g. to `/projects/stable-diffusion-ui-archive`
2) Start the newly installed project, and check that you can view and generate images on `localhost:9000`
3) Next, please clone the project repository using `git clone` (e.g. to `/projects/stable-diffusion-ui-repo`)
4) Close the server (started in step 2), and edit `/projects/stable-diffusion-ui-archive/scripts/on_env_start.sh` (or `on_env_start.bat`)
5) Comment out the lines near the bottom that copies the `files/ui` folder, e.g:
for `.sh`
```
@ -33,23 +32,20 @@ REM @xcopy sd-ui-files\ui ui /s /i /Y
REM @copy sd-ui-files\scripts\on_sd_start.bat scripts\ /Y
REM @copy "sd-ui-files\scripts\Start Stable Diffusion UI.cmd" . /Y
```
7) Comment out the line at the top of `/projects/stable-diffusion-ui-archive/scripts/on_sd_start.sh` that copies `on_env_start`. For e.g. `@copy sd-ui-files\scripts\on_env_start.bat scripts\ /Y`
6) Next, comment out the line at the top of `/projects/stable-diffusion-ui-archive/scripts/on_sd_start.sh` (or `on_sd_start.bat`) that copies `on_env_start`. For e.g. `@rem @copy sd-ui-files\scripts\on_env_start.bat scripts\ /Y`
8) Delete the current `ui` folder at `/projects/stable-diffusion-ui-archive/ui`
9) Now make a symlink between the repository clone (where you will be making changes) and this archive (where you will be running stable diffusion):
`ln -s /projects/stable-diffusion-ui-repo/ui /projects/stable-diffusion-ui-archive/ui`
or for Windows
`mklink /D \projects\stable-diffusion-ui-archive\ui \projects\stable-diffusion-ui-repo\ui` (link name first, source repo dir second)
9) Run the archive again `start.sh` and ensure you can still use the UI.
`mklink /J \projects\stable-diffusion-ui-archive\ui \projects\stable-diffusion-ui-repo\ui` (link name first, source repo dir second)
9) Run the project again (like in step 2) and ensure you can still use the UI.
10) Congrats, now any changes you make in your repo `ui` folder are linked to this running archive of the app and can be previewed in the browser.
11) Please update CHANGES.md in your pull requests.
Check the `ui/frontend/build/README.md` for instructions on running and building the React code.
## Development environment for Installer changes
Build the Windows installer using Windows, and the Linux installer using Linux. Don't mix the two, and don't use WSL. An Ubuntu VM is fine for building the Linux installer on a Windows host.
1. Install Miniconda 3 or Anaconda.
2. Install `conda install -c conda-forge -y conda-pack`
3. Open the Anaconda Prompt. Do not use WSL if you're building for Windows.
4. Run `build.bat` or `./build.sh` depending on whether you're in Windows or Linux.
5. Compress the `stable-diffusion-ui` folder created inside the `dist` folder. Make a `zip` for Windows, and `tar.xz` for Linux (smaller files, and Linux users already have tar).
6. Make a new GitHub release and upload the Windows and Linux installer builds.
1. Run `build.bat` or `./build.sh` depending on whether you're in Windows or Linux.
2. Make a new GitHub release and upload the Windows and Linux installer builds created inside the `dist` folder.

1
NSIS/.gitignore vendored Normal file
View File

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

1
NSIS/README.md Normal file
View File

@ -0,0 +1 @@
Scripts to be used with the Nullsoft Scriptable Installation System

BIN
NSIS/astro.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

BIN
NSIS/cyborg_flower_girl.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

BIN
NSIS/cyborg_flower_girl.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

1
NSIS/nsisconf.nsh Normal file
View File

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

BIN
NSIS/sd.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

294
NSIS/sdui.nsi Normal file
View File

@ -0,0 +1,294 @@
; Script generated by the HM NIS Edit Script Wizard.
Target amd64-unicode
Unicode True
SetCompressor /FINAL lzma
RequestExecutionLevel user
!AddPluginDir /amd64-unicode "."
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "Easy Diffusion"
!define PRODUCT_VERSION "2.5"
!define PRODUCT_PUBLISHER "cmdr2 and contributors"
!define PRODUCT_WEB_SITE "https://stable-diffusion-ui.github.io"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Easy Diffusion\App Paths\installer.exe"
; MUI 1.67 compatible ------
!include "MUI.nsh"
!include "LogicLib.nsh"
!include "nsDialogs.nsh"
!include "nsisconf.nsh"
Var Dialog
Var Label
Var Button
Var InstDirLen
Var LongPathsEnabled
Var AccountType
;---------------------------------------------------------------------------------------------------------
; This function returns the number of spaces in a string.
; The string is passed on the stack (using Push $STRING)
; The result is also returned on the stack and can be consumed with Pop $var
; https://nsis.sourceforge.io/Check_for_spaces_in_a_directory_path
Function CheckForSpaces
Exch $R0
Push $R1
Push $R2
Push $R3
StrCpy $R1 -1
StrCpy $R3 $R0
StrCpy $R0 0
loop:
StrCpy $R2 $R3 1 $R1
IntOp $R1 $R1 - 1
StrCmp $R2 "" done
StrCmp $R2 " " 0 loop
IntOp $R0 $R0 + 1
Goto loop
done:
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
;---------------------------------------------------------------------------------------------------------
; The function DirectoryLeave is called after the user chose the installation directory.
; If it calls "abort", the user is sent back to choose a different directory.
Function DirectoryLeave
; check whether the installation directory path is longer than 30 characters.
; If yes, we suggest to the user to enable long filename support
;----------------------------------------------------------------------------
StrLen $InstDirLen "$INSTDIR"
; Check whether the registry key that allows for >260 characters in a path name is set
ReadRegStr $LongPathsEnabled HKLM "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled"
${If} $InstDirLen > 30
${AndIf} $LongPathsEnabled == "0"
; Check whether we're in the Admin group
UserInfo::GetAccountType
Pop $AccountType
${If} $AccountType == "Admin"
${AndIf} ${Cmd} `MessageBox MB_YESNO|MB_ICONQUESTION 'The path name is too long. $\n$\nYou can either enable long file name support in Windows,$\nor you can go back and choose a different path.$\n$\nFor details see: shorturl.at/auBD1$\n$\nEnable long path name support in Windows?' IDYES`
; Enable long path names
WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1
${Else}
MessageBox MB_OK|MB_ICONEXCLAMATION "Installation path name too long. The installation path must not have more than 30 characters."
abort
${EndIf}
${EndIf}
; Check for spaces in the installation directory path.
; ----------------------------------------------------
; $R0 = CheckForSpaces( $INSTDIR )
Push $INSTDIR # Input string (install path).
Call CheckForSpaces
Pop $R0 # The function returns the number of spaces found in the input string.
; Check if any spaces exist in $INSTDIR.
${If} $R0 != 0
; Plural if more than 1 space in $INSTDIR.
; If $R0 == 1: $R1 = ""; else: $R1 = "s"
StrCmp $R0 1 0 +3
StrCpy $R1 ""
Goto +2
StrCpy $R1 "s"
; Show message box then take the user back to the Directory page.
MessageBox MB_OK|MB_ICONEXCLAMATION "Error: The Installaton directory \
has $R0 space character$R1.$\nPlease choose an installation directory without space characters."
Abort
${EndIf}
; Check for NTFS filesystem. Installations on FAT fail.
; -----------------------------------------------------
StrCpy $5 $INSTDIR 3
System::Call 'Kernel32::GetVolumeInformation(t "$5",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r1,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
${AndIf} $1 != "NTFS"
MessageBox mb_ok "$5 has filesystem type '$1'.$\nOnly NTFS filesystems are supported.$\nPlease choose a different drive."
Abort
${EndIf}
FunctionEnd
;---------------------------------------------------------------------------------------------------------
; Open the MS download page in a browser and enable the [Next] button
Function MSMediaFeaturepack
ExecShell "open" "https://www.microsoft.com/en-us/software-download/mediafeaturepack"
GetDlgItem $0 $HWNDPARENT 1
EnableWindow $0 1
FunctionEnd
;---------------------------------------------------------------------------------------------------------
; Install the MS Media Feature Pack, if it is missing (e.g. on Windows 10 N)
Function MediaPackDialog
!insertmacro MUI_HEADER_TEXT "Windows Media Feature Pack" "Required software module is missing"
; Skip this dialog if mf.dll is installed
${If} ${FileExists} "$WINDIR\system32\mf.dll"
Abort
${EndIf}
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 48u "The Windows Media Feature Pack is missing on this computer. It is required for Easy Diffusion.$\nYou can continue the installation after installing the Windows Media Feature Pack."
Pop $Label
${NSD_CreateButton} 10% 49u 80% 12u "Download Meda Feature Pack from Microsoft"
Pop $Button
GetFunctionAddress $0 MSMediaFeaturePack
nsDialogs::OnClick $Button $0
GetDlgItem $0 $HWNDPARENT 1
EnableWindow $0 0
nsDialogs::Show
FunctionEnd
;---------------------------------------------------------------------------------------------------------
; MUI Settings
;---------------------------------------------------------------------------------------------------------
!define MUI_ABORTWARNING
!define MUI_ICON "cyborg_flower_girl.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "cyborg_flower_girl.bmp"
; Welcome page
!define MUI_WELCOMEPAGE_TEXT "This installer will guide you through the installation of Easy Diffusion.$\n$\n\
Click Next to continue."
!insertmacro MUI_PAGE_WELCOME
Page custom MediaPackDialog
; License page
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
!insertmacro MUI_PAGE_LICENSE "..\CreativeML Open RAIL-M License"
; Directory page
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "DirectoryLeave"
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!define MUI_FINISHPAGE_RUN "$INSTDIR\Start Stable Diffusion UI.cmd"
!insertmacro MUI_PAGE_FINISH
; Language files
!insertmacro MUI_LANGUAGE "English"
;---------------------------------------------------------------------------------------------------------
; MUI end
;---------------------------------------------------------------------------------------------------------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "Install Easy Diffusion.exe"
InstallDir "C:\EasyDiffusion\"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
;---------------------------------------------------------------------------------------------------------
; List of files to be installed
Section "MainSection" SEC01
SetOutPath "$INSTDIR"
File "..\CreativeML Open RAIL-M License"
File "..\How to install and run.txt"
File "..\LICENSE"
File "..\scripts\Start Stable Diffusion UI.cmd"
File /r "${EXISTING_INSTALLATION_DIR}\installer_files"
File /r "${EXISTING_INSTALLATION_DIR}\profile"
File /r "${EXISTING_INSTALLATION_DIR}\sd-ui-files"
SetOutPath "$INSTDIR\scripts"
File "${EXISTING_INSTALLATION_DIR}\scripts\install_status.txt"
File "..\scripts\on_env_start.bat"
File "C:\windows\system32\curl.exe"
CreateDirectory "$INSTDIR\models"
CreateDirectory "$INSTDIR\models\stable-diffusion"
CreateDirectory "$INSTDIR\models\gfpgan"
CreateDirectory "$INSTDIR\models\realesrgan"
CreateDirectory "$INSTDIR\models\vae"
CreateDirectory "$SMPROGRAMS\Easy Diffusion"
CreateShortCut "$SMPROGRAMS\Easy Diffusion\Easy Diffusion.lnk" "$INSTDIR\Start Stable Diffusion UI.cmd"
DetailPrint 'Downloading the Stable Diffusion 1.4 model...'
NScurl::http get "https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt" "$INSTDIR\models\stable-diffusion\sd-v1-4.ckpt" /CANCEL /INSIST /END
DetailPrint 'Downloading the GFPGAN model...'
NScurl::http get "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth" "$INSTDIR\models\gfpgan\GFPGANv1.3.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the RealESRGAN_x4plus model...'
NScurl::http get "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth" "$INSTDIR\models\realesrgan\RealESRGAN_x4plus.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the RealESRGAN_x4plus_anime model...'
NScurl::http get "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth" "$INSTDIR\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth" /CANCEL /INSIST /END
DetailPrint 'Downloading the default VAE (sd-vae-ft-mse-original) model...'
NScurl::http get "https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.ckpt" "$INSTDIR\models\vae\vae-ft-mse-840000-ema-pruned.ckpt" /CANCEL /INSIST /END
DetailPrint 'Downloading the CLIP model (clip-vit-large-patch14)...'
NScurl::http get "https://huggingface.co/openai/clip-vit-large-patch14/resolve/8d052a0f05efbaefbc9e8786ba291cfdf93e5bff/pytorch_model.bin" "$INSTDIR\profile\.cache\huggingface\hub\models--openai--clip-vit-large-patch14\snapshots\8d052a0f05efbaefbc9e8786ba291cfdf93e5bff\pytorch_model.bin" /CANCEL /INSIST /END
SectionEnd
;---------------------------------------------------------------------------------------------------------
; Our installer only needs 25 KB, but once it has run, we need 25 GB
; So we need to overwrite the automatically detected space requirements.
; https://nsis.sourceforge.io/Docs/Chapter4.html#4.9.13.7
; The example in section 4.9.13.7 seems to be wrong: the number
; needs to be provided in Kilobytes.
Function .onInit
; Set required size of section 'SEC01' to 25 Gigabytes
SectionSetSize ${SEC01} 26214400
; Check system meory size. We need at least 8GB
; ----------------------------------------------------
; allocate a few bytes of memory
System::Alloc 64
Pop $1
; Retrieve HW info from the Windows Kernel
System::Call "*$1(i64)"
System::Call "Kernel32::GlobalMemoryStatusEx(i r1)"
; unpack the data into $R2 - $R10
System::Call "*$1(i.r2, i.r3, l.r4, l.r5, l.r6, l.r7, l.r8, l.r9, l.r10)"
# free up the memory
System::Free $1
; Result mapping:
; "Structure size: $2 bytes"
; "Memory load: $3%"
; "Total physical memory: $4 bytes"
; "Free physical memory: $5 bytes"
; "Total page file: $6 bytes"
; "Free page file: $7 bytes"
; "Total virtual: $8 bytes"
; "Free virtual: $9 bytes"
; Mem size in MB
System::Int64Op $4 / 1048576
Pop $4
${If} $4 < "8000"
MessageBox MB_OK|MB_ICONEXCLAMATION "Warning!$\n$\nYour system has less than 8GB of memory (RAM).$\n$\n\
You can still try to install Easy Diffusion,$\nbut it might have problems to start, or run$\nvery slowly."
${EndIf}
FunctionEnd
;Section -Post
; WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\installer.exe"
;SectionEnd

199
README.md
View File

@ -1,107 +1,146 @@
# Stable Diffusion UI v2
### A simple 1-click way to install and use [Stable Diffusion](https://github.com/CompVis/stable-diffusion) on your own computer. No dependencies or technical knowledge required.
# Easy Diffusion 2.5
### The easiest way to install and use [Stable Diffusion](https://github.com/CompVis/stable-diffusion) on your own computer.
Does not require technical knowledge, does not require pre-installed software. 1-click install, powerful features, friendly community.
[Installation guide](#step-1-download-and-extract-the-installer) | [Troubleshooting guide](https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting) | <sub>[![Discord Server](https://img.shields.io/discord/1014774730907209781?label=Discord)](https://discord.com/invite/u9yhsFmEkB)</sub> <sup>(for support queries, and development discussions)</sup>
![t2i](https://raw.githubusercontent.com/Stability-AI/stablediffusion/main/assets/stable-samples/txt2img/768/merged-0006.png)
# Step 1: Download and extract the installer
Click the download button for your operating system:
<p float="left">
<a href="#installation"><img src="https://github.com/cmdr2/stable-diffusion-ui/raw/develop/media/download-win.png" width="200" /></a>
<a href="#installation"><img src="https://github.com/cmdr2/stable-diffusion-ui/raw/develop/media/download-linux.png" width="200" /></a>
<a href="https://github.com/cmdr2/stable-diffusion-ui/releases/download/v2.5.15/stable-diffusion-ui-windows.zip"><img src="https://github.com/cmdr2/stable-diffusion-ui/raw/main/media/download-win.png" width="200" /></a>
<a href="https://github.com/cmdr2/stable-diffusion-ui/releases/download/v2.5.15/stable-diffusion-ui-linux.zip"><img src="https://github.com/cmdr2/stable-diffusion-ui/raw/main/media/download-linux.png" width="200" /></a>
</p>
[![Discord Server](https://img.shields.io/discord/1014774730907209781?label=Discord)](https://discord.com/invite/u9yhsFmEkB) (for support, and development discussion) | [Troubleshooting guide for common problems](Troubleshooting.md)
## On Windows:
1. Unzip/extract the folder `stable-diffusion-ui` which should be in your downloads folder, unless you changed your default downloads destination.
2. Move the `stable-diffusion-ui` folder to your `C:` drive (or any other drive like `D:`, at the top root level). `C:\stable-diffusion-ui` or `D:\stable-diffusion-ui` as examples. This will avoid a common problem with Windows (file path length limits).
## On Linux:
1. Unzip/extract the folder `stable-diffusion-ui` which should be in your downloads folder, unless you changed your default downloads destination.
2. Open a terminal window, and navigate to the `stable-diffusion-ui` directory.
️‍🔥🎉 **New!** Use Custom Weights, Task Queue, Negative Prompt, Live Preview, More Samplers, In-Painting, Face Correction (GFPGAN) and Upscaling (RealESRGAN) have been added!
# Step 2: Run the program
## On Windows:
Double-click `Start Stable Diffusion UI.cmd`.
If Windows SmartScreen prevents you from running the program click `More info` and then `Run anyway`.
## On Linux:
Run `./start.sh` (or `bash start.sh`) in a terminal.
This distribution currently uses Stable Diffusion 1.4. Once the model for 1.5 becomes publicly available, the model in this distribution will be updated.
The installer will take care of whatever is needed. If you face any problems, you can join the friendly [Discord community](https://discord.com/invite/u9yhsFmEkB) and ask for assistance.
# Features in the new v2 Version:
- **No Dependencies or Technical Knowledge Required**: 1-click install for Windows 10/11 and Linux. *No dependencies*, no need for WSL or Docker or Conda or technical setup. Just download and run!
- **Face Correction (GFPGAN) and Upscaling (RealESRGAN)**
- **In-Painting**
- **Live Preview**: See the image as the AI is drawing it
- **Task Queue**: Queue up all your ideas, without waiting for the current task to finish
- **Custom Weights**: Use your own `.ckpt` file, by placing it inside the `stable-diffusion` folder (rename it to `custom-model.ckpt`)
- **Negative Prompt**: Specify aspects of the image to *remove*.
- **Lots of Samplers:** ddim, plms, heun, euler, euler_a, dpm2, dpm2_a, lms
# Step 3: There is no Step 3. It's that simple!
**To Uninstall:** Just delete the `stable-diffusion-ui` folder to uninstall all the downloaded packages.
----
# Easy for new users, powerful features for advanced users
## Features:
### User experience
- **Hassle-free installation**: Does not require technical knowledge, does not require pre-installed software. Just download and run!
- **Clutter-free UI**: A friendly and simple UI, while providing a lot of powerful features.
- **Task Queue**: Queue up all your ideas, without waiting for the current task to finish.
- **Intelligent Model Detection**: Automatically figures out the YAML config file to use for the chosen model (via a models database).
- **Live Preview**: See the image as the AI is drawing it.
- **Image Modifiers**: A library of *modifier tags* like *"Realistic"*, *"Pencil Sketch"*, *"ArtStation"* etc. Experiment with various styles quickly.
- **New UI**: with cleaner design
- **Waifu Model Support**: Just replace the `stable-diffusion\sd-v1-4.ckpt` file after installation with the Waifu model
- Supports "*Text to Image*" and "*Image to Image*"
- **NSFW Setting**: A setting in the UI to control *NSFW content*
- **Use CPU setting**: If you don't have a compatible graphics card, but still want to run it on your CPU.
- **Auto-updater**: Gets you the latest improvements and bug-fixes to a rapidly evolving project.
- **Low Memory Usage**: Creates 512x512 images with less than 4GB of VRAM!
- **Multiple Prompts File**: Queue multiple prompts by entering one prompt per line, or by running a text file.
- **Save generated images to disk**: Save your images to your PC!
- **UI Themes**: Customize the program to your liking.
- **Searchable models dropdown**: organize your models into sub-folders, and search through them in the UI.
### Image generation
- **Supports**: "*Text to Image*" and "*Image to Image*".
- **19 Samplers**: `ddim`, `plms`, `heun`, `euler`, `euler_a`, `dpm2`, `dpm2_a`, `lms`, `dpm_solver_stability`, `dpmpp_2s_a`, `dpmpp_2m`, `dpmpp_sde`, `dpm_fast`, `dpm_adaptive`, `unipc_snr`, `unipc_tu`, `unipc_tq`, `unipc_snr_2`, `unipc_tu_2`.
- **In-Painting**: Specify areas of your image to paint into.
- **Simple Drawing Tool**: Draw basic images to guide the AI, without needing an external drawing program.
- **Face Correction (GFPGAN)**
- **Upscaling (RealESRGAN)**
- **Loopback**: Use the output image as the input image for the next img2img task.
- **Negative Prompt**: Specify aspects of the image to *remove*.
- **Attention/Emphasis**: () in the prompt increases the model's attention to enclosed words, and [] decreases it.
- **Weighted Prompts**: Use weights for specific words in your prompt to change their importance, e.g. `red:2.4 dragon:1.2`.
- **Prompt Matrix**: Quickly create multiple variations of your prompt, e.g. `a photograph of an astronaut riding a horse | illustration | cinematic lighting`.
- **1-click Upscale/Face Correction**: Upscale or correct an image after it has been generated.
- **Make Similar Images**: Click to generate multiple variations of a generated image.
- **NSFW Setting**: A setting in the UI to control *NSFW content*.
- **JPEG/PNG/WEBP output**: Multiple file formats.
### Advanced features
- **Custom Models**: Use your own `.ckpt` or `.safetensors` file, by placing it inside the `models/stable-diffusion` folder!
- **Stable Diffusion 2.1 support**
- **Merge Models**
- **Use custom VAE models**
- **Use pre-trained Hypernetworks**
- **Use custom GFPGAN models**
- **UI Plugins**: Choose from a growing list of [community-generated UI plugins](https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Plugins), or write your own plugin to add features to the project!
### Performance and security
- **Fast**: Creates a 512x512 image with euler_a in 5 seconds, on an NVIDIA 3060 12GB.
- **Low Memory Usage**: Create 512x512 images with less than 3 GB of GPU RAM, and 768x768 images with less than 4 GB of GPU RAM!
- **Use CPU setting**: If you don't have a compatible graphics card, but still want to run it on your CPU.
- **Multi-GPU support**: Automatically spreads your tasks across multiple GPUs (if available), for faster performance!
- **Auto scan for malicious models**: Uses picklescan to prevent malicious models.
- **Safetensors support**: Support loading models in the safetensor format, for improved safety.
- **Auto-updater**: Gets you the latest improvements and bug-fixes to a rapidly evolving project.
- **Developer Console**: A developer-mode for those who want to modify their Stable Diffusion code, and edit the conda environment.
**(and a lot more)**
----
## Easy for new users:
![Screenshot of the initial UI](https://user-images.githubusercontent.com/844287/217043152-29454d15-0387-4228-b70d-9a4b84aeb8ba.png)
## Powerful features for advanced users:
![Screenshot of advanced settings](https://user-images.githubusercontent.com/844287/217042588-fc53c975-bacd-4a9c-af88-37408734ade3.png)
![Screenshot of advanced settings](media/shot-v9.jpg?raw=true)
## Live Preview
Useful for judging (and stopping) an image quickly, without waiting for it to finish rendering.
![live-512](https://user-images.githubusercontent.com/844287/192097249-729a0a1e-a677-485e-9ccc-16a9e848fabe.gif)
## Task Queue
![Screenshot of task queue](https://user-images.githubusercontent.com/844287/217043984-0b35f73b-1318-47cb-9eed-a2a91b430490.png)
# System Requirements
1. Windows 10/11, or Linux. Experimental support for Mac is coming soon.
2. An NVIDIA graphics card, preferably with 4GB or more of VRAM. But if you don't have a compatible graphics card, you can still use it with a "Use CPU" setting. It'll be very slow, but it should still work.
2. An NVIDIA graphics card, preferably with 4GB or more of VRAM. If you don't have a compatible graphics card, it'll automatically run in the slower "CPU Mode".
3. Minimum 8 GB of RAM and 25GB of disk space.
You do not need anything else. You do not need WSL, Docker or Conda. The installer will take care of it.
You don't need to install or struggle with Python, Anaconda, Docker etc. The installer will take care of whatever is needed.
# Installation
1. **Download** [for Windows](https://github.com/cmdr2/stable-diffusion-ui/releases/download/v2.16/stable-diffusion-ui-win64.zip) or [for Linux](https://github.com/cmdr2/stable-diffusion-ui/releases/download/v2.16/stable-diffusion-ui-linux.tar.xz).
----
2. **Extract**:
- For Windows: After unzipping the file, please move the `stable-diffusion-ui` folder to your `C:` (or any drive like D:, at the top root level), e.g. `C:\stable-diffusion-ui`. This will avoid a common problem with Windows (file path length limits).
- For Linux: After extracting the .tar.xz file, please open a terminal, and go to the `stable-diffusion-ui` directory.
3. **Run**:
- For Windows: `Start Stable Diffusion UI.cmd` by double-clicking it.
- For Linux: In the terminal, run `./start.sh` (or `bash start.sh`)
This will automatically install Stable Diffusion, set it up, and start the interface. No additional steps are needed.
**To Uninstall:** Just delete the `stable-diffusion-ui` folder to uninstall all the downloaded packages.
# Usage
Open http://localhost:9000 in your browser (after running step 3 previously). It may take a few moments for the back-end to be ready.
## With a text description
1. Enter a text prompt, like `a photograph of an astronaut riding a horse` in the textbox.
2. Press `Make Image`. This will take some time, depending on your system's processing power.
3. See the image generated using your prompt.
## With an image
1. Click `Browse..` next to `Initial Image`. Select your desired image.
2. An optional text prompt can help you further describe the kind of image you want to generate.
3. Press `Make Image`. See the image generated using your prompt.
You can use Face Correction or Upscaling to improve the image further.
**Pro tip:** You can also click `Use as Input` on a generated image, to use it as the input image for your next generation. This can be useful for sequentially refining the generated image with a single click.
**Another tip:** Images with the same aspect ratio of your generated image work best. E.g. 1:1 if you're generating images sized 512x512.
## Problems? Troubleshooting
Please try the common [troubleshooting](Troubleshooting.md) steps. If that doesn't fix it, please ask on the [discord server](https://discord.com/invite/u9yhsFmEkB), or [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues).
# Image Settings
You can also set the configuration like `seed`, `width`, `height`, `num_outputs`, `num_inference_steps` and `guidance_scale` using the 'show' button next to 'Image settings'.
Use the same `seed` number to get the same image for a certain prompt. This is useful for refining a prompt without losing the basic image design. Enable the `random images` checkbox to get random images.
![Screenshot of advanced settings](media/config-v6.jpg?raw=true)
# System Settings
The system settings are reachable via the cogwheel symbol on the top right. It can be used to configure whether all generated images should
saved be automically, or to tune the Stable Diffusion image generation.
![Screenshot of advanced settings](media/system-settings-v2.jpg?raw=true)
# Image Modifiers
![Screenshot of advanced settings](media/modifiers-v1.jpg?raw=true)
# How to use?
Please refer to our [guide](https://github.com/cmdr2/stable-diffusion-ui/wiki/How-to-Use) to understand how to use the features in this UI.
# Bugs reports and code contributions welcome
If there are any problems or suggestions, please feel free to ask on the [discord server](https://discord.com/invite/u9yhsFmEkB) or [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues).
Also, please feel free to submit a pull request, if you have any code contributions in mind. Join the [discord server](https://discord.com/invite/u9yhsFmEkB) for development-related discussions, and for helping other users.
We could really use help on these aspects (click to view tasks that need your help):
* [User Interface](https://github.com/users/cmdr2/projects/1/views/1)
* [Engine](https://github.com/users/cmdr2/projects/3/views/1)
* [Installer](https://github.com/users/cmdr2/projects/4/views/1)
* [Documentation](https://github.com/users/cmdr2/projects/5/views/1)
If you have any code contributions in mind, please feel free to say Hi to us on the [discord server](https://discord.com/invite/u9yhsFmEkB). We use the Discord server for development-related discussions, and for helping users.
# Disclaimer
The authors of this project are not responsible for any content generated using this interface.
The 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, spread misinformation, or target vulnerable groups. For the full list of restrictions please read [the license](LICENSE). You agree to these terms by using this software.
The license of this software forbids you from sharing any content that:
- Violates any laws.
- Produces any harm to a person or persons.
- Disseminates (spreads) any personal information that would be meant for harm.
- Spreads misinformation.
- Target vulnerable groups.
For the full list of restrictions please read [the License](LICENSE). You agree to these terms by using this software.

View File

@ -1,75 +0,0 @@
Common issues and their solutions. If these solutions don't work, please feel free to ask at the [discord server](https://discord.com/invite/u9yhsFmEkB) or [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues).
## RuntimeError: CUDA out of memory
This can happen if your PC has less than 6GB of VRAM.
Try disabling the "Turbo mode" setting under "Advanced Settings", since that takes an additional 1 GB of VRAM (to increase the speed).
Additionally, a common reason for this error is that you're using an initial image larger than 768x768 pixels. Try using a smaller initial image.
Also try generating smaller sized images.
## basicsr module not found
For Windows: Please download and extract basicsr from [here](https://github.com/cmdr2/stable-diffusion-ui/releases/download/v2.16/basicsr-win64.zip), and place the `basicsr` folder inside the `stable-diffusion-ui\stable-diffusion\env\lib\site-packages` folder. Then run the `Start Stable Diffusion UI.cmd` file again.
For Linux: Please contact on the [discord server](https://discord.com/invite/u9yhsFmEkB).
## No ldm found, or antlr4 or any other missing module, or ClobberError: This transaction has incompatible packages due to a shared path
On Windows, please ensure that you had placed the `stable-diffusion-ui` folder after unzipping to the root of C: or D: (or any drive). For e.g. `C:\stable-diffusion-ui`. **Note:** This has to be done **before** you start the installation process. If you have already installed (and are facing this error), please delete the installed folder, and start fresh by unzipping and placing the folder at the top of your drive.
This error can also be caused if you already have conda/miniconda/anaconda installed, due to package conflicts. Please open your Anaconda Prompt, and run `conda clean --all` to clean up unused packages.
If nothing works, this could be due to a corrupted installation. Please try reinstalling this, by deleting the installed folder, and unzipping from the downloaded zip file.
## Killed uvicorn server:app --app-dir ... --port 9000 --host 0.0.0.0
This happens if your PC ran out of RAM. Stable Diffusion requires a lot of RAM, and requires atleast 10 GB of RAM to work well. You can also try closing all other applications before running Stable Diffusion UI.
## Green image generated
This usually happens if you're running NVIDIA 1650 or 1660 Super. To solve this, please close and run the Stable Diffusion command on your computer. If you're using the older Docker-based solution (v1), please upgrade to v2: https://github.com/cmdr2/stable-diffusion-ui/tree/v2#installation
If you're still seeing this error, please try enabling "Full Precision" under "Advanced Settings" in the Stable Diffusion UI.
## './docker-compose.yml' is invalid:
> ERROR: The Compose file './docker-compose.yml' is invalid because:
> services.stability-ai.deploy.resources.reservations value Additional properties are not allowed ('devices' was unexpected)
Please ensure you have `docker-compose` version 1.29 or higher. Check `docker-compose --version`, and if required [update it to 1.29](https://docs.docker.com/compose/install/). (Thanks [HVRyan](https://github.com/HVRyan))
## RuntimeError: Found no NVIDIA driver on your system:
If you have an NVIDIA GPU and the latest [NVIDIA driver](http://www.nvidia.com/Download/index.aspx), please ensure that you've installed [nvidia-container-toolkit](https://stackoverflow.com/a/58432877). (Thanks [u/exintrovert420](https://www.reddit.com/user/exintrovert420/))
## Some other process is already running at port 9000 / port 9000 could not be bound
You can override the port used. Please change `docker-compose.yml` inside the project directory, and update the line `9000:9000` to `1337:9000` (where 1337 is whichever port number you want).
After doing this, please restart your server, by running `./server restart`.
After this, you can access the server at `http://localhost:1337` (where 1337 is the new port you specified earlier).
## RuntimeError: CUDA error: unknown error
Please ensure that you have an NVIDIA GPU and the latest [NVIDIA driver](http://www.nvidia.com/Download/index.aspx), and that you've installed [nvidia-container-toolkit](https://stackoverflow.com/a/58432877).
Also, if you are using WSL (Windows), please ensure you have the latest WSL kernel by running `wsl --shutdown` and then `wsl --update`. (Thanks [AndrWeisR](https://github.com/AndrWeisR))
# For support queries
## Entering a conda environment in an existing installation
This will give you an activated conda environment in the terminal, so you can run commands and force-install any packages, if required.
Users don't need to have the Anaconda Prompt installed to do this anymore, since the installer bundles a portable version of conda inside it. Just follow these steps.
**Windows:**
1. Open the terminal: Press Win+R, type "cmd", and press "Run"
2. Type `cd C:\stable-diffusion-ui` and press enter (or wherever you've installed it)
3. Type `installer\Scripts\activate.bat` and press enter
4. Type `cd stable-diffusion` and press enter
5. Type `conda activate .\env` and press enter
6. Type `python --version` and press enter. You should see 3.8.5.
**Linux:**
1. Open the terminal
2. Type `cd /path/to/stable-diffusion-ui` and press enter
3. Type `installer/bin/activate` and press enter
4. Type `cd stable-diffusion` and press enter
5. Type `conda activate ./env` and press enter
6. Type `python --version` and press enter. You should see 3.8.5.
This will give you an activated conda environment. To confirm, type `python --version` and press enter. You should see 3.8.5.

View File

@ -8,40 +8,40 @@
set /p answer=Are you a developer of this project (Y/N)?
if /i "%answer:~,1%" NEQ "Y" exit /b
@set PYTHONNOUSERSITE=1
mkdir dist\win\stable-diffusion-ui\scripts
@REM mkdir dist\linux-mac\stable-diffusion-ui\scripts
@mkdir dist\stable-diffusion-ui
@rem copy the installer files for Windows
@echo "Downloading components for the installer.."
copy scripts\on_env_start.bat dist\win\stable-diffusion-ui\scripts\
copy scripts\bootstrap.bat dist\win\stable-diffusion-ui\scripts\
copy "scripts\Start Stable Diffusion UI.cmd" dist\win\stable-diffusion-ui\
copy LICENSE dist\win\stable-diffusion-ui\
copy "CreativeML Open RAIL-M License" dist\win\stable-diffusion-ui\
copy "How to install and run.txt" dist\win\stable-diffusion-ui\
echo. > dist\win\stable-diffusion-ui\scripts\install_status.txt
@call conda env create --prefix installer -f environment.yaml
@call conda activate .\installer
@rem copy the installer files for Linux and Mac
@echo "Creating a distributable package.."
@REM copy scripts\on_env_start.sh dist\linux-mac\stable-diffusion-ui\scripts\
@REM copy scripts\bootstrap.sh dist\linux-mac\stable-diffusion-ui\scripts\
@REM copy scripts\start.sh dist\linux-mac\stable-diffusion-ui\
@REM copy LICENSE dist\linux-mac\stable-diffusion-ui\
@REM copy "CreativeML Open RAIL-M License" dist\linux-mac\stable-diffusion-ui\
@REM copy "How to install and run.txt" dist\linux-mac\stable-diffusion-ui\
@REM echo. > dist\linux-mac\stable-diffusion-ui\scripts\install_status.txt
@call conda install -c conda-forge -y conda-pack
@call conda pack --n-threads -1 --prefix installer --format tar
@rem make the zip
@cd dist\stable-diffusion-ui
@mkdir installer
cd dist\win
call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-windows.zip
cd ..\..
@call tar -xf ..\..\installer.tar -C installer
@REM cd dist\linux-mac
@REM call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-linux.zip
@REM call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-mac.zip
@REM cd ..\..
@mkdir scripts
echo "Build ready. Upload the zip files inside the 'dist' folder."
@copy ..\..\scripts\on_env_start.bat scripts\
@copy "..\..\scripts\Start Stable Diffusion UI.cmd" .
@copy ..\..\LICENSE .
@copy "..\..\CreativeML Open RAIL-M License" .
@copy "..\..\How to install and run.txt" .
@echo. > scripts\install_status.txt
@echo "Build ready. Zip the 'dist\stable-diffusion-ui' folder."
@echo "Cleaning up.."
@cd ..\..
@rmdir /s /q installer
@del installer.tar
pause

View File

@ -11,45 +11,39 @@ case $yn in
* ) exit;;
esac
export PYTHONNOUSERSITE=1
# mkdir -p dist/win/stable-diffusion-ui/scripts
mkdir -p dist/linux-mac/stable-diffusion-ui/scripts
mkdir -p dist/stable-diffusion-ui
# copy the installer files for Windows
echo "Downloading components for the installer.."
# cp scripts/on_env_start.bat dist/win/stable-diffusion-ui/scripts/
# cp scripts/bootstrap.bat dist/win/stable-diffusion-ui/scripts/
# cp "scripts/Start Stable Diffusion UI.cmd" dist/win/stable-diffusion-ui/
# cp LICENSE dist/win/stable-diffusion-ui/
# cp "CreativeML Open RAIL-M License" dist/win/stable-diffusion-ui/
# cp "How to install and run.txt" dist/win/stable-diffusion-ui/
# echo "" > dist/win/stable-diffusion-ui/scripts/install_status.txt
source ~/miniconda3/etc/profile.d/conda.sh
# copy the installer files for Linux and Mac
conda install -c conda-forge -y conda-pack
cp scripts/on_env_start.sh dist/linux-mac/stable-diffusion-ui/scripts/
cp scripts/bootstrap.sh dist/linux-mac/stable-diffusion-ui/scripts/
cp scripts/functions.sh dist/linux-mac/stable-diffusion-ui/scripts/
cp scripts/start.sh dist/linux-mac/stable-diffusion-ui/
cp LICENSE dist/linux-mac/stable-diffusion-ui/
cp "CreativeML Open RAIL-M License" dist/linux-mac/stable-diffusion-ui/
cp "How to install and run.txt" dist/linux-mac/stable-diffusion-ui/
echo "" > dist/linux-mac/stable-diffusion-ui/scripts/install_status.txt
conda env create --prefix installer -f environment.yaml
conda activate ./installer
# make the zip
echo "Creating a distributable package.."
conda pack --n-threads -1 --prefix installer --format tar
cd dist/stable-diffusion-ui
mkdir installer
tar -xf ../../installer.tar -C installer
mkdir scripts
cp ../../scripts/on_env_start.sh scripts/
cp ../../scripts/start.sh .
cp ../../LICENSE .
cp "../../CreativeML Open RAIL-M License" .
cp "../../How to install and run.txt" .
echo "" > scripts/install_status.txt
chmod u+x start.sh
echo "Build ready. Zip the 'dist/stable-diffusion-ui' folder."
echo "Cleaning up.."
# cd dist/win
# zip -r ../stable-diffusion-ui-windows.zip stable-diffusion-ui
# cd ../..
cd dist/linux-mac
zip -r ../stable-diffusion-ui-linux.zip stable-diffusion-ui
zip -r ../stable-diffusion-ui-mac.zip stable-diffusion-ui
cd ../..
rm -rf installer
rm installer.tar
echo "Build ready. Upload the zip files inside the 'dist' folder."

BIN
media/config-v7.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
media/shot-v10-simple.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
media/shot-v10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
media/task-queue-v1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -0,0 +1,43 @@
@echo off
echo "Opening Stable Diffusion UI - Developer Console.." & echo.
set PATH=C:\Windows\System32;%PATH%
@rem set legacy and new installer's PATH, if they exist
if exist "installer" set PATH=%cd%\installer;%cd%\installer\Library\bin;%cd%\installer\Scripts;%cd%\installer\Library\usr\bin;%PATH%
if exist "installer_files\env" set PATH=%cd%\installer_files\env;%cd%\installer_files\env\Library\bin;%cd%\installer_files\env\Scripts;%cd%\installer_files\Library\usr\bin;%PATH%
set PYTHONPATH=%cd%\installer;%cd%\installer_files\env
@rem activate the installer env
call conda activate
@rem Test the environment
echo "Environment Info:"
call where git
call git --version
call where conda
call conda --version
echo.
@rem activate the legacy environment (if present) and set PYTHONPATH
if exist "installer_files\env" (
set PYTHONPATH=%cd%\installer_files\env\lib\site-packages
)
if exist "stable-diffusion\env" (
call conda activate .\stable-diffusion\env
set PYTHONPATH=%cd%\stable-diffusion\env\lib\site-packages
)
call where python
call python --version
echo PYTHONPATH=%PYTHONPATH%
@rem done
echo.
cmd /k

View File

@ -1,19 +1,43 @@
@echo off
@REM Delete the post-activate hook from the old installer
if exist "installer\etc\conda\activate.d\post_activate.bat" (
echo. > installer\etc\conda\activate.d\post_activate.bat
)
cd /d %~dp0
echo Install dir: %~dp0
@call installer\Scripts\activate.bat
set PATH=C:\Windows\System32;%PATH%
@call conda-unpack
if exist "on_sd_start.bat" (
echo ================================================================================
echo.
echo !!!! WARNING !!!!
echo.
echo It looks like you're trying to run the installation script from a source code
echo download. This will not work.
echo.
echo Recommended: Please close this window and download the installer from
echo https://stable-diffusion-ui.github.io/docs/installation/
echo.
echo ================================================================================
echo.
pause
exit /b
)
@call conda --version
@call git --version
@rem set legacy installer's PATH, if it exists
if exist "installer" set PATH=%cd%\installer;%cd%\installer\Library\bin;%cd%\installer\Scripts;%cd%\installer\Library\usr\bin;%PATH%
@cd installer
@rem set new installer's PATH, if it downloaded any packages
if exist "installer_files\env" set PATH=%cd%\installer_files\env;%cd%\installer_files\env\Library\bin;%cd%\installer_files\env\Scripts;%cd%\installer_files\Library\usr\bin;%PATH%
@call ..\scripts\on_env_start.bat
set PYTHONPATH=%cd%\installer;%cd%\installer_files\env
@rem Test the core requirements
call where git
call git --version
call where conda
call conda --version
@rem Download the rest of the installer and UI
call scripts\on_env_start.bat
@pause

78
scripts/bootstrap.bat Normal file
View File

@ -0,0 +1,78 @@
@echo off
setlocal enabledelayedexpansion
@rem This script will install git and conda (if not found on the PATH variable)
@rem using micromamba (an 8mb static-linked single-file binary, conda replacement).
@rem For users who already have git and conda, this step will be skipped.
@rem This enables a user to install this project without manually installing conda and git.
@rem config
set MAMBA_ROOT_PREFIX=%cd%\installer_files\mamba
set INSTALL_ENV_DIR=%cd%\installer_files\env
set LEGACY_INSTALL_ENV_DIR=%cd%\installer
set MICROMAMBA_DOWNLOAD_URL=https://github.com/cmdr2/stable-diffusion-ui/releases/download/v1.1/micromamba.exe
set umamba_exists=F
set OLD_APPDATA=%APPDATA%
set OLD_USERPROFILE=%USERPROFILE%
set APPDATA=%cd%\installer_files\appdata
set USERPROFILE=%cd%\profile
@rem figure out whether git and conda needs to be installed
if exist "%INSTALL_ENV_DIR%" set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH%
set PACKAGES_TO_INSTALL=
if not exist "%LEGACY_INSTALL_ENV_DIR%\etc\profile.d\conda.sh" (
if not exist "%INSTALL_ENV_DIR%\etc\profile.d\conda.sh" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% conda python=3.8.5
)
call git --version >.tmp1 2>.tmp2
if "!ERRORLEVEL!" NEQ "0" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% git
call "%MAMBA_ROOT_PREFIX%\micromamba.exe" --version >.tmp1 2>.tmp2
if "!ERRORLEVEL!" EQU "0" set umamba_exists=T
@rem (if necessary) install git and conda into a contained environment
if "%PACKAGES_TO_INSTALL%" NEQ "" (
@rem download micromamba
if "%umamba_exists%" == "F" (
echo "Downloading micromamba from %MICROMAMBA_DOWNLOAD_URL% to %MAMBA_ROOT_PREFIX%\micromamba.exe"
mkdir "%MAMBA_ROOT_PREFIX%"
call curl -Lk "%MICROMAMBA_DOWNLOAD_URL%" > "%MAMBA_ROOT_PREFIX%\micromamba.exe"
if "!ERRORLEVEL!" NEQ "0" (
echo "There was a problem downloading micromamba. Cannot continue."
pause
exit /b
)
mkdir "%APPDATA%"
mkdir "%USERPROFILE%"
@rem test the mamba binary
echo Micromamba version:
call "%MAMBA_ROOT_PREFIX%\micromamba.exe" --version
)
@rem create the installer env
if not exist "%INSTALL_ENV_DIR%" (
call "%MAMBA_ROOT_PREFIX%\micromamba.exe" create -y --prefix "%INSTALL_ENV_DIR%"
)
echo "Packages to install:%PACKAGES_TO_INSTALL%"
call "%MAMBA_ROOT_PREFIX%\micromamba.exe" install -y --prefix "%INSTALL_ENV_DIR%" -c conda-forge %PACKAGES_TO_INSTALL%
if not exist "%INSTALL_ENV_DIR%" (
echo "There was a problem while installing%PACKAGES_TO_INSTALL% using micromamba. Cannot continue."
pause
exit /b
)
)
@rem revert to the old APPDATA. only needed it for bypassing a bug in micromamba (with special characters)
set APPDATA=%OLD_APPDATA%
set USERPROFILE=%OLD_USERPROFILE%

93
scripts/bootstrap.sh Executable file
View File

@ -0,0 +1,93 @@
#!/bin/bash
# This script will install git and conda (if not found on the PATH variable)
# using micromamba (an 8mb static-linked single-file binary, conda replacement).
# For users who already have git and conda, this step will be skipped.
# This enables a user to install this project without manually installing conda and git.
source ./scripts/functions.sh
set -o pipefail
OS_NAME=$(uname -s)
case "${OS_NAME}" in
Linux*) OS_NAME="linux";;
Darwin*) OS_NAME="osx";;
*) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
esac
OS_ARCH=$(uname -m)
case "${OS_ARCH}" in
x86_64*) OS_ARCH="64";;
arm64*) OS_ARCH="arm64";;
aarch64*) OS_ARCH="arm64";;
*) echo "Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64" && exit
esac
if ! which curl; then fail "'curl' not found. Please install curl."; fi
if ! which tar; then fail "'tar' not found. Please install tar."; fi
if ! which bzip2; then fail "'bzip2' not found. Please install bzip2."; fi
if pwd | grep ' '; then fail "The installation directory's path contains a space character. Conda will fail to install. Please change the directory."; fi
# https://mamba.readthedocs.io/en/latest/installation.html
if [ "$OS_NAME" == "linux" ] && [ "$OS_ARCH" == "arm64" ]; then OS_ARCH="aarch64"; fi
# config
export MAMBA_ROOT_PREFIX="$(pwd)/installer_files/mamba"
INSTALL_ENV_DIR="$(pwd)/installer_files/env"
LEGACY_INSTALL_ENV_DIR="$(pwd)/installer"
MICROMAMBA_DOWNLOAD_URL="https://micro.mamba.pm/api/micromamba/${OS_NAME}-${OS_ARCH}/latest"
umamba_exists="F"
# figure out whether git and conda needs to be installed
if [ -e "$INSTALL_ENV_DIR" ]; then export PATH="$INSTALL_ENV_DIR/bin:$PATH"; fi
PACKAGES_TO_INSTALL=""
if [ ! -e "$LEGACY_INSTALL_ENV_DIR/etc/profile.d/conda.sh" ] && [ ! -e "$INSTALL_ENV_DIR/etc/profile.d/conda.sh" ]; then PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL conda python=3.8.5"; fi
if ! hash "git" &>/dev/null; then PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL git"; fi
if "$MAMBA_ROOT_PREFIX/micromamba" --version &>/dev/null; then umamba_exists="T"; fi
# (if necessary) install git and conda into a contained environment
if [ "$PACKAGES_TO_INSTALL" != "" ]; then
# download micromamba
if [ "$umamba_exists" == "F" ]; then
echo "Downloading micromamba from $MICROMAMBA_DOWNLOAD_URL to $MAMBA_ROOT_PREFIX/micromamba"
mkdir -p "$MAMBA_ROOT_PREFIX"
curl -L "$MICROMAMBA_DOWNLOAD_URL" | tar -xvj -O bin/micromamba > "$MAMBA_ROOT_PREFIX/micromamba"
if [ "$?" != "0" ]; then
echo
echo "EE micromamba download failed"
echo "EE If the lines above contain 'bzip2: Cannot exec', your system doesn't have bzip2 installed"
echo "EE If there are network errors, please check your internet setup"
fail "micromamba download failed"
fi
chmod u+x "$MAMBA_ROOT_PREFIX/micromamba"
# test the mamba binary
echo "Micromamba version:"
"$MAMBA_ROOT_PREFIX/micromamba" --version
fi
# create the installer env
if [ ! -e "$INSTALL_ENV_DIR" ]; then
"$MAMBA_ROOT_PREFIX/micromamba" create -y --prefix "$INSTALL_ENV_DIR" || fail "unable to create the install environment"
fi
if [ ! -e "$INSTALL_ENV_DIR" ]; then
fail "There was a problem while installing$PACKAGES_TO_INSTALL using micromamba. Cannot continue."
fi
echo "Packages to install:$PACKAGES_TO_INSTALL"
"$MAMBA_ROOT_PREFIX/micromamba" install -y --prefix "$INSTALL_ENV_DIR" -c conda-forge $PACKAGES_TO_INSTALL
if [ "$?" != "0" ]; then
fail "Installation of the packages '$PACKAGES_TO_INSTALL' failed."
fi
fi

13
scripts/check_modules.py Normal file
View File

@ -0,0 +1,13 @@
'''
This script checks if the given modules exist
'''
import sys
import pkgutil
modules = sys.argv[1:]
missing_modules = []
for m in modules:
if pkgutil.find_loader(m) is None:
print('module', m, 'not found')
exit(1)

53
scripts/developer_console.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
cd "$(dirname "${BASH_SOURCE[0]}")"
if [ "$0" == "bash" ]; then
echo "Opening Stable Diffusion UI - Developer Console.."
echo ""
# set legacy and new installer's PATH, if they exist
if [ -e "installer" ]; then export PATH="$(pwd)/installer/bin:$PATH"; fi
if [ -e "installer_files/env" ]; then export PATH="$(pwd)/installer_files/env/bin:$PATH"; fi
# activate the installer env
CONDA_BASEPATH=$(conda info --base)
source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # avoids the 'shell not initialized' error
conda activate
# test the environment
echo "Environment Info:"
which git
git --version
which conda
conda --version
echo ""
# activate the legacy environment (if present) and set PYTHONPATH
if [ -e "installer_files/env" ]; then
export PYTHONPATH="$(pwd)/installer_files/env/lib/python3.8/site-packages"
fi
if [ -e "stable-diffusion/env" ]; then
CONDA_BASEPATH=$(conda info --base)
source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # otherwise conda complains about 'shell not initialized' (needed when running in a script)
conda activate ./stable-diffusion/env
export PYTHONPATH="$(pwd)/stable-diffusion/env/lib/python3.8/site-packages"
fi
which python
python --version
echo "PYTHONPATH=$PYTHONPATH"
# done
echo ""
else
file_name=$(basename "${BASH_SOURCE[0]}")
bash --init-file "$file_name"
fi

39
scripts/functions.sh Normal file
View File

@ -0,0 +1,39 @@
#
# utility functions for all scripts
#
fail() {
echo
echo "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
echo
if [ "$1" != "" ]; then
echo ERROR: $1
else
echo An error occurred.
fi
cat <<EOF
Error downloading Stable Diffusion UI. Sorry about that, please try to:
1. Run this installer again.
2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting
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
4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues
Thanks!
EOF
read -p "Press any key to continue"
exit 1
}
filesize() {
case "$(uname -s)" in
Linux*) stat -c "%s" $1;;
Darwin*) stat -f "%z" $1;;
*) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
esac
}

View File

View File

@ -1,11 +1,9 @@
@echo off
@echo. & echo "Stable Diffusion UI - v2" & echo.
@echo. & echo "Easy Diffusion - v2" & echo.
set PATH=C:\Windows\System32;%PATH%
@cd ..
if exist "scripts\config.bat" (
@call scripts\config.bat
)
@ -14,7 +12,7 @@ if "%update_branch%"=="" (
set update_branch=main
)
@>nul grep -c "conda_sd_ui_deps_installed" scripts\install_status.txt
@>nul findstr /m "conda_sd_ui_deps_installed" scripts\install_status.txt
@if "%ERRORLEVEL%" NEQ "0" (
for /f "tokens=*" %%a in ('python -c "import os; parts = os.getcwd().split(os.path.sep); print(len(parts))"') do if "%%a" NEQ "2" (
echo. & echo "!!!! WARNING !!!!" & echo.
@ -28,34 +26,36 @@ if "%update_branch%"=="" (
)
)
@>nul grep -c "sd_ui_git_cloned" scripts\install_status.txt
@>nul findstr /m "sd_ui_git_cloned" scripts\install_status.txt
@if "%ERRORLEVEL%" EQU "0" (
@echo "Stable Diffusion UI's git repository was already installed. Updating from %update_branch%.."
@echo "Easy Diffusion's git repository was already installed. Updating from %update_branch%.."
@cd sd-ui-files
@call git reset --hard
@call git checkout "%update_branch%"
@call git -c advice.detachedHead=false checkout "%update_branch%"
@call git pull
@cd ..
) else (
@echo. & echo "Downloading Stable Diffusion UI.." & echo.
@echo. & echo "Downloading Easy Diffusion..." & echo.
@echo "Using the %update_branch% channel" & echo.
@call git clone -b "%update_branch%" https://github.com/cmdr2/stable-diffusion-ui.git sd-ui-files && (
@echo sd_ui_git_cloned >> scripts\install_status.txt
) || (
@echo "Error downloading Stable Diffusion UI. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
@echo "Error downloading Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
@exit /b
)
)
@xcopy sd-ui-files\ui ui /s /i /Y
@xcopy sd-ui-files\ui ui /s /i /Y /q
@copy sd-ui-files\scripts\on_sd_start.bat scripts\ /Y
@copy sd-ui-files\scripts\check_modules.py scripts\ /Y
@copy "sd-ui-files\scripts\Start Stable Diffusion UI.cmd" . /Y
@copy "sd-ui-files\scripts\Developer Console.cmd" . /Y
@call scripts\on_sd_start.bat
@pause
@pause

View File

@ -1,6 +1,8 @@
#!/bin/bash
printf "\n\nStable Diffusion UI\n\n"
source ./scripts/functions.sh
printf "\n\nEasy Diffusion\n\n"
if [ -f "scripts/config.sh" ]; then
source scripts/config.sh
@ -11,33 +13,33 @@ if [ "$update_branch" == "" ]; then
fi
if [ -f "scripts/install_status.txt" ] && [ `grep -c sd_ui_git_cloned scripts/install_status.txt` -gt "0" ]; then
echo "Stable Diffusion UI's git repository was already installed. Updating from $update_branch.."
echo "Easy Diffusion's git repository was already installed. Updating from $update_branch.."
cd sd-ui-files
git reset --hard
git checkout "$update_branch"
git -c advice.detachedHead=false checkout "$update_branch"
git pull
cd ..
else
printf "\n\nDownloading Stable Diffusion UI..\n\n"
printf "\n\nDownloading Easy Diffusion..\n\n"
printf "Using the $update_branch channel\n\n"
if git clone -b "$update_branch" https://github.com/cmdr2/stable-diffusion-ui.git sd-ui-files ; then
echo sd_ui_git_cloned >> scripts/install_status.txt
else
printf "\n\nError downloading Stable Diffusion UI. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "git clone failed"
fi
fi
rm -rf ui
cp -Rf sd-ui-files/ui .
cp sd-ui-files/scripts/on_sd_start.sh scripts/
cp sd-ui-files/scripts/bootstrap.sh scripts/
cp sd-ui-files/scripts/check_modules.py scripts/
cp sd-ui-files/scripts/start.sh .
cp sd-ui-files/scripts/developer_console.sh .
cp sd-ui-files/scripts/functions.sh scripts/
./scripts/on_sd_start.sh
read -p "Press any key to continue"
exec ./scripts/on_sd_start.sh

View File

@ -1,199 +1,205 @@
@echo off
@copy sd-ui-files\scripts\on_env_start.bat scripts\ /Y
@REM Caution, this file will make your eyes and brain bleed. It's such an unholy mess.
@REM Note to self: Please rewrite this in Python. For the sake of your own sanity.
@call 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');"
@copy sd-ui-files\scripts\on_env_start.bat scripts\ /Y
@copy sd-ui-files\scripts\bootstrap.bat scripts\ /Y
@copy sd-ui-files\scripts\check_modules.py scripts\ /Y
@>nul grep -c "sd_git_cloned" scripts\install_status.txt
@if "%ERRORLEVEL%" EQU "0" (
@echo "Stable Diffusion's git repository was already installed. Updating.."
@cd stable-diffusion
@call git reset --hard
@call git pull
@call git checkout f6cfebffa752ee11a7b07497b8529d5971de916c
@call git apply ..\ui\sd_internal\ddim_callback.patch
@call git apply ..\ui\sd_internal\env_yaml.patch
@cd ..
) else (
@echo. & echo "Downloading Stable Diffusion.." & echo.
@call git clone https://github.com/basujindal/stable-diffusion.git && (
@echo sd_git_cloned >> scripts\install_status.txt
) || (
@echo "Error downloading Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
@exit /b
)
@cd stable-diffusion
@call git checkout f6cfebffa752ee11a7b07497b8529d5971de916c
@call git apply ..\ui\sd_internal\ddim_callback.patch
@call git apply ..\ui\sd_internal\env_yaml.patch
@cd ..
if exist "%cd%\profile" (
set USERPROFILE=%cd%\profile
)
@cd stable-diffusion
@rem set the correct installer path (current vs legacy)
if exist "%cd%\installer_files\env" (
set INSTALL_ENV_DIR=%cd%\installer_files\env
)
if exist "%cd%\stable-diffusion\env" (
set INSTALL_ENV_DIR=%cd%\stable-diffusion\env
)
@>nul grep -c "conda_sd_env_created" ..\scripts\install_status.txt
@if "%ERRORLEVEL%" EQU "0" (
@echo "Packages necessary for Stable Diffusion were already installed"
@mkdir tmp
@set TMP=%cd%\tmp
@set TEMP=%cd%\tmp
@call conda activate .\env
@rem activate the installer env
call conda activate
@if "%ERRORLEVEL%" NEQ "0" (
@echo. & echo "Error activating conda for Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@REM remove the old version of the dev console script, if it's still present
if exist "Open Developer Console.cmd" del "Open Developer Console.cmd"
@call 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');"
@rem create the stable-diffusion folder, to work with legacy installations
if not exist "stable-diffusion" mkdir stable-diffusion
cd stable-diffusion
@rem activate the old stable-diffusion env, if it exists
if exist "env" (
call conda activate .\env
)
@rem disable the legacy src and ldm folder (otherwise this prevents installing gfpgan and realesrgan)
if exist src rename src src-old
if exist ldm rename ldm ldm-old
if not exist "..\models\stable-diffusion" mkdir "..\models\stable-diffusion"
if not exist "..\models\gfpgan" mkdir "..\models\gfpgan"
if not exist "..\models\realesrgan" mkdir "..\models\realesrgan"
if not exist "..\models\vae" mkdir "..\models\vae"
@rem migrate the legacy models to the correct path (if already downloaded)
if exist "sd-v1-4.ckpt" move sd-v1-4.ckpt ..\models\stable-diffusion\
if exist "custom-model.ckpt" move custom-model.ckpt ..\models\stable-diffusion\
if exist "GFPGANv1.3.pth" move GFPGANv1.3.pth ..\models\gfpgan\
if exist "RealESRGAN_x4plus.pth" move RealESRGAN_x4plus.pth ..\models\realesrgan\
if exist "RealESRGAN_x4plus_anime_6B.pth" move RealESRGAN_x4plus_anime_6B.pth ..\models\realesrgan\
if not exist "%INSTALL_ENV_DIR%\DLLs\libssl-1_1-x64.dll" copy "%INSTALL_ENV_DIR%\Library\bin\libssl-1_1-x64.dll" "%INSTALL_ENV_DIR%\DLLs\"
if not exist "%INSTALL_ENV_DIR%\DLLs\libcrypto-1_1-x64.dll" copy "%INSTALL_ENV_DIR%\Library\bin\libcrypto-1_1-x64.dll" "%INSTALL_ENV_DIR%\DLLs\"
@rem install torch and torchvision
call python ..\scripts\check_modules.py torch torchvision
if "%ERRORLEVEL%" EQU "0" (
echo "torch and torchvision have already been installed."
) else (
@echo. & echo "Downloading packages necessary for Stable Diffusion.." & echo. & echo "***** This will take some time (depending on the speed of the Internet connection) and may appear to be stuck, but please be patient ***** .." & echo.
echo "Installing torch and torchvision.."
@rmdir /s /q .\env
@REM prevent from using packages from the user's home directory, to avoid conflicts
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
@REM prevent conda from using packages from the user's home directory, to avoid conflicts
@set PYTHONNOUSERSITE=1
@call conda env create --prefix env -f environment.yaml || (
@echo. & echo "Error installing the packages necessary for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
call python -m pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 || (
echo "Error installing torch. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
exit /b
)
@call conda activate .\env
@call conda install -c conda-forge -y --prefix env antlr4-python3-runtime=4.8 || (
@echo. & echo "Error installing antlr4-python3-runtime for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
for /f "tokens=*" %%a in ('python -c "import torch; import ldm; import transformers; import numpy; import antlr4; print(42)"') do if "%%a" NEQ "42" (
@echo. & echo "Dependency test failed! Error installing the packages necessary for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@echo conda_sd_env_created >> ..\scripts\install_status.txt
)
set PATH=C:\Windows\System32;%PATH%
@>nul grep -c "conda_sd_gfpgan_deps_installed" ..\scripts\install_status.txt
@if "%ERRORLEVEL%" EQU "0" (
@echo "Packages necessary for GFPGAN (Face Correction) were already installed"
@rem install/upgrade sdkit
call python ..\scripts\check_modules.py sdkit sdkit.models ldm transformers numpy antlr4 gfpgan realesrgan
if "%ERRORLEVEL%" EQU "0" (
echo "sdkit is already installed."
@rem skip sdkit upgrade if in developer-mode
if not exist "..\src\sdkit" (
@REM prevent from using packages from the user's home directory, to avoid conflicts
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
call python -m pip install --upgrade sdkit==1.0.47 -q || (
echo "Error updating sdkit"
)
)
) else (
@echo. & echo "Downloading packages necessary for GFPGAN (Face Correction).." & echo.
echo "Installing sdkit: https://pypi.org/project/sdkit/"
@set PYTHONNOUSERSITE=1
@REM prevent from using packages from the user's home directory, to avoid conflicts
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
@call pip install -e git+https://github.com/TencentARC/GFPGAN#egg=GFPGAN || (
@echo. & echo "Error installing the packages necessary for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
call python -m pip install sdkit==1.0.47 || (
echo "Error installing sdkit. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
exit /b
)
@call pip install basicsr==1.4.2 || (
@echo. & echo "Error installing the basicsr package necessary for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
for /f "tokens=*" %%a in ('python -c "from gfpgan import GFPGANer; print(42)"') do if "%%a" NEQ "42" (
@echo. & echo "Dependency test failed! Error installing the packages necessary for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@echo conda_sd_gfpgan_deps_installed >> ..\scripts\install_status.txt
)
@>nul grep -c "conda_sd_esrgan_deps_installed" ..\scripts\install_status.txt
@if "%ERRORLEVEL%" EQU "0" (
@echo "Packages necessary for ESRGAN (Resolution Upscaling) were already installed"
call python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
@rem upgrade stable-diffusion-sdkit
call python -m pip install --upgrade stable-diffusion-sdkit==2.1.3 -q || (
echo "Error updating stable-diffusion-sdkit"
)
call python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
@rem install rich
call python ..\scripts\check_modules.py rich
if "%ERRORLEVEL%" EQU "0" (
echo "rich has already been installed."
) else (
@echo. & echo "Downloading packages necessary for ESRGAN (Resolution Upscaling).." & echo.
echo "Installing rich.."
@set PYTHONNOUSERSITE=1
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
@call pip install -e git+https://github.com/xinntao/Real-ESRGAN#egg=realesrgan || (
@echo. & echo "Error installing the packages necessary for ESRGAN (Resolution Upscaling). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
call python -m pip install rich || (
echo "Error installing rich. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
exit /b
)
for /f "tokens=*" %%a in ('python -c "from basicsr.archs.rrdbnet_arch import RRDBNet; from realesrgan import RealESRGANer; print(42)"') do if "%%a" NEQ "42" (
@echo. & echo "Dependency test failed! Error installing the packages necessary for ESRGAN (Resolution Upscaling). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@echo conda_sd_esrgan_deps_installed >> ..\scripts\install_status.txt
)
@>nul grep -c "conda_sd_ui_deps_installed" ..\scripts\install_status.txt
set PATH=C:\Windows\System32;%PATH%
call python ..\scripts\check_modules.py uvicorn fastapi
@if "%ERRORLEVEL%" EQU "0" (
echo "Packages necessary for Stable Diffusion UI were already installed"
echo "Packages necessary for Easy Diffusion were already installed"
) else (
@echo. & echo "Downloading packages necessary for Stable Diffusion UI.." & echo.
@echo. & echo "Downloading packages necessary for Easy Diffusion..." & echo.
@set PYTHONNOUSERSITE=1
set PYTHONNOUSERSITE=1
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
@call conda install -c conda-forge -y --prefix env uvicorn fastapi || (
echo "Error installing the packages necessary for Stable Diffusion UI. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
@call conda install -c conda-forge -y uvicorn fastapi || (
echo "Error installing the packages necessary for Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!"
pause
exit /b
)
)
call WHERE uvicorn > .tmp
@>nul grep -c "uvicorn" .tmp
@>nul findstr /m "uvicorn" .tmp
@if "%ERRORLEVEL%" NEQ "0" (
@echo. & echo "UI packages not found! Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
@echo. & echo "UI packages not found! Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@>nul grep -c "conda_sd_ui_deps_installed" ..\scripts\install_status.txt
@>nul findstr /m "conda_sd_ui_deps_installed" ..\scripts\install_status.txt
@if "%ERRORLEVEL%" NEQ "0" (
@echo conda_sd_ui_deps_installed >> ..\scripts\install_status.txt
)
@if exist "sd-v1-4.ckpt" (
for %%I in ("sd-v1-4.ckpt") do if "%%~zI" EQU "4265380512" (
@if exist "..\models\stable-diffusion\sd-v1-4.ckpt" (
for %%I in ("..\models\stable-diffusion\sd-v1-4.ckpt") do if "%%~zI" EQU "4265380512" (
echo "Data files (weights) necessary for Stable Diffusion were already downloaded. Using the HuggingFace 4 GB Model."
) else (
for %%J in ("sd-v1-4.ckpt") do if "%%~zJ" EQU "7703807346" (
for %%J in ("..\models\stable-diffusion\sd-v1-4.ckpt") do if "%%~zJ" EQU "7703807346" (
echo "Data files (weights) necessary for Stable Diffusion were already downloaded. Using the HuggingFace 7 GB Model."
) else (
for %%K in ("sd-v1-4.ckpt") do if "%%~zK" EQU "7703810927" (
for %%K in ("..\models\stable-diffusion\sd-v1-4.ckpt") do if "%%~zK" EQU "7703810927" (
echo "Data files (weights) necessary for Stable Diffusion were already downloaded. Using the Waifu Model."
) else (
echo. & echo "The model file present at %cd%\sd-v1-4.ckpt is invalid. It is only %%~zK bytes in size. Re-downloading.." & echo.
del "sd-v1-4.ckpt"
echo. & echo "The model file present at models\stable-diffusion\sd-v1-4.ckpt is invalid. It is only %%~zK bytes in size. Re-downloading.." & echo.
del "..\models\stable-diffusion\sd-v1-4.ckpt"
)
)
)
)
@if not exist "sd-v1-4.ckpt" (
@if not exist "..\models\stable-diffusion\sd-v1-4.ckpt" (
@echo. & echo "Downloading data files (weights) for Stable Diffusion.." & echo.
@call curl -L -k https://me.cmdr2.org/stable-diffusion-ui/sd-v1-4.ckpt > sd-v1-4.ckpt
@call 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
@if exist "sd-v1-4.ckpt" (
for %%I in ("sd-v1-4.ckpt") do if "%%~zI" NEQ "4265380512" (
@if exist "..\models\stable-diffusion\sd-v1-4.ckpt" (
for %%I in ("..\models\stable-diffusion\sd-v1-4.ckpt") do if "%%~zI" NEQ "4265380512" (
echo. & echo "Error: The downloaded model file was invalid! Bytes downloaded: %%~zI" & echo.
echo. & echo "Error downloading the data files (weights) for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
echo. & echo "Error downloading the data files (weights) for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
) else (
@echo. & echo "Error downloading the data files (weights) for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
@echo. & echo "Error downloading the data files (weights) for Stable Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@ -201,29 +207,29 @@ call WHERE uvicorn > .tmp
@if exist "GFPGANv1.3.pth" (
for %%I in ("GFPGANv1.3.pth") do if "%%~zI" EQU "348632874" (
@if exist "..\models\gfpgan\GFPGANv1.3.pth" (
for %%I in ("..\models\gfpgan\GFPGANv1.3.pth") do if "%%~zI" EQU "348632874" (
echo "Data files (weights) necessary for GFPGAN (Face Correction) were already downloaded"
) else (
echo. & echo "The GFPGAN model file present at %cd%\GFPGANv1.3.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "GFPGANv1.3.pth"
echo. & echo "The GFPGAN model file present at models\gfpgan\GFPGANv1.3.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "..\models\gfpgan\GFPGANv1.3.pth"
)
)
@if not exist "GFPGANv1.3.pth" (
@if not exist "..\models\gfpgan\GFPGANv1.3.pth" (
@echo. & echo "Downloading data files (weights) for GFPGAN (Face Correction).." & echo.
@call curl -L -k https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth > GFPGANv1.3.pth
@call curl -L -k https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth > ..\models\gfpgan\GFPGANv1.3.pth
@if exist "GFPGANv1.3.pth" (
for %%I in ("GFPGANv1.3.pth") do if "%%~zI" NEQ "348632874" (
@if exist "..\models\gfpgan\GFPGANv1.3.pth" (
for %%I in ("..\models\gfpgan\GFPGANv1.3.pth") do if "%%~zI" NEQ "348632874" (
echo. & echo "Error: The downloaded GFPGAN model file was invalid! Bytes downloaded: %%~zI" & echo.
echo. & echo "Error downloading the data files (weights) for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
echo. & echo "Error downloading the data files (weights) for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
) else (
@echo. & echo "Error downloading the data files (weights) for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
@echo. & echo "Error downloading the data files (weights) for GFPGAN (Face Correction). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@ -231,29 +237,29 @@ call WHERE uvicorn > .tmp
@if exist "RealESRGAN_x4plus.pth" (
for %%I in ("RealESRGAN_x4plus.pth") do if "%%~zI" EQU "67040989" (
@if exist "..\models\realesrgan\RealESRGAN_x4plus.pth" (
for %%I in ("..\models\realesrgan\RealESRGAN_x4plus.pth") do if "%%~zI" EQU "67040989" (
echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus were already downloaded"
) else (
echo. & echo "The GFPGAN model file present at %cd%\RealESRGAN_x4plus.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "RealESRGAN_x4plus.pth"
echo. & echo "The RealESRGAN model file present at models\realesrgan\RealESRGAN_x4plus.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "..\models\realesrgan\RealESRGAN_x4plus.pth"
)
)
@if not exist "RealESRGAN_x4plus.pth" (
@if not exist "..\models\realesrgan\RealESRGAN_x4plus.pth" (
@echo. & echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus.." & echo.
@call curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth > RealESRGAN_x4plus.pth
@call curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth > ..\models\realesrgan\RealESRGAN_x4plus.pth
@if exist "RealESRGAN_x4plus.pth" (
for %%I in ("RealESRGAN_x4plus.pth") do if "%%~zI" NEQ "67040989" (
@if exist "..\models\realesrgan\RealESRGAN_x4plus.pth" (
for %%I in ("..\models\realesrgan\RealESRGAN_x4plus.pth") do if "%%~zI" NEQ "67040989" (
echo. & echo "Error: The downloaded ESRGAN x4plus model file was invalid! Bytes downloaded: %%~zI" & echo.
echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
) else (
@echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
@echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@ -261,29 +267,29 @@ call WHERE uvicorn > .tmp
@if exist "RealESRGAN_x4plus_anime_6B.pth" (
for %%I in ("RealESRGAN_x4plus_anime_6B.pth") do if "%%~zI" EQU "17938799" (
@if exist "..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth" (
for %%I in ("..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth") do if "%%~zI" EQU "17938799" (
echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus_anime were already downloaded"
) else (
echo. & echo "The GFPGAN model file present at %cd%\RealESRGAN_x4plus_anime_6B.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "RealESRGAN_x4plus_anime_6B.pth"
echo. & echo "The RealESRGAN model file present at models\realesrgan\RealESRGAN_x4plus_anime_6B.pth is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth"
)
)
@if not exist "RealESRGAN_x4plus_anime_6B.pth" (
@if not exist "..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth" (
@echo. & echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime.." & echo.
@call curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth > RealESRGAN_x4plus_anime_6B.pth
@call 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
@if exist "RealESRGAN_x4plus_anime_6B.pth" (
for %%I in ("RealESRGAN_x4plus_anime_6B.pth") do if "%%~zI" NEQ "17938799" (
@if exist "..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth" (
for %%I in ("..\models\realesrgan\RealESRGAN_x4plus_anime_6B.pth") do if "%%~zI" NEQ "17938799" (
echo. & echo "Error: The downloaded ESRGAN x4plus_anime model file was invalid! Bytes downloaded: %%~zI" & echo.
echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
) else (
@echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
@echo. & echo "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
@ -291,27 +297,60 @@ call WHERE uvicorn > .tmp
@>nul grep -c "sd_install_complete" ..\scripts\install_status.txt
@if exist "..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt" (
for %%I in ("..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt") do if "%%~zI" EQU "334695179" (
echo "Data files (weights) necessary for the default VAE (sd-vae-ft-mse-original) were already downloaded"
) else (
echo. & echo "The default VAE (sd-vae-ft-mse-original) file present at models\vae\vae-ft-mse-840000-ema-pruned.ckpt is invalid. It is only %%~zI bytes in size. Re-downloading.." & echo.
del "..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt"
)
)
@if not exist "..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt" (
@echo. & echo "Downloading data files (weights) for the default VAE (sd-vae-ft-mse-original).." & echo.
@call 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
@if exist "..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt" (
for %%I in ("..\models\vae\vae-ft-mse-840000-ema-pruned.ckpt") do if "%%~zI" NEQ "334695179" (
echo. & echo "Error: The downloaded default VAE (sd-vae-ft-mse-original) file was invalid! Bytes downloaded: %%~zI" & echo.
echo. & echo "Error downloading the data files (weights) for the default VAE (sd-vae-ft-mse-original). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
) else (
@echo. & echo "Error downloading the data files (weights) for the default VAE (sd-vae-ft-mse-original). Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo.
pause
exit /b
)
)
@>nul findstr /m "sd_install_complete" ..\scripts\install_status.txt
@if "%ERRORLEVEL%" NEQ "0" (
@echo sd_weights_downloaded >> ..\scripts\install_status.txt
@echo sd_install_complete >> ..\scripts\install_status.txt
)
@echo. & echo "Stable Diffusion is ready!" & echo.
@echo. & echo "Easy Diffusion installation complete! Starting the server!" & echo.
@set SD_DIR=%cd%
@cd env\lib\site-packages
@set PYTHONPATH=%SD_DIR%;%cd%
@cd ..\..\..
@echo PYTHONPATH=%PYTHONPATH%
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
echo PYTHONPATH=%PYTHONPATH%
call where python
call python --version
@cd ..
@set SD_UI_PATH=%cd%\ui
@cd stable-diffusion
@call python --version
@rem set any overrides
set HF_HUB_DISABLE_SYMLINKS_WARNING=true
@uvicorn server:app --app-dir "%SD_UI_PATH%" --port 9000 --host 0.0.0.0
@if NOT DEFINED SD_UI_BIND_PORT set SD_UI_BIND_PORT=9000
@if NOT DEFINED SD_UI_BIND_IP set SD_UI_BIND_IP=0.0.0.0
@uvicorn main:server_api --app-dir "%SD_UI_PATH%" --port %SD_UI_BIND_PORT% --host %SD_UI_BIND_IP% --log-level error
@pause
@pause

View File

@ -1,309 +1,301 @@
#!/bin/bash
cp sd-ui-files/scripts/functions.sh scripts/
cp sd-ui-files/scripts/on_env_start.sh scripts/
cp sd-ui-files/scripts/bootstrap.sh scripts/
cp sd-ui-files/scripts/check_modules.py scripts/
source installer/etc/profile.d/conda.sh
source ./scripts/functions.sh
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');"
# activate the installer env
CONDA_BASEPATH=$(conda info --base)
source "$CONDA_BASEPATH/etc/profile.d/conda.sh" # avoids the 'shell not initialized' error
conda activate || fail "Failed to activate conda"
# remove the old version of the dev console script, if it's still present
if [ -e "open_dev_console.sh" ]; then
rm "open_dev_console.sh"
fi
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');"
# Caution, this file will make your eyes and brain bleed. It's such an unholy mess.
# Note to self: Please rewrite this in Python. For the sake of your own sanity.
if [ -e "scripts/install_status.txt" ] && [ `grep -c sd_git_cloned scripts/install_status.txt` -gt "0" ]; then
echo "Stable Diffusion's git repository was already installed. Updating.."
cd stable-diffusion
git reset --hard
git pull
git checkout f6cfebffa752ee11a7b07497b8529d5971de916c
git apply ../ui/sd_internal/ddim_callback.patch
git apply ../ui/sd_internal/env_yaml.patch
cd ..
else
printf "\n\nDownloading Stable Diffusion..\n\n"
if git clone https://github.com/basujindal/stable-diffusion.git ; then
echo sd_git_cloned >> scripts/install_status.txt
else
printf "\n\nError downloading Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
cd stable-diffusion
git checkout f6cfebffa752ee11a7b07497b8529d5971de916c
git apply ../ui/sd_internal/ddim_callback.patch
git apply ../ui/sd_internal/env_yaml.patch
cd ..
# set the correct installer path (current vs legacy)
if [ -e "installer_files/env" ]; then
export INSTALL_ENV_DIR="$(pwd)/installer_files/env"
fi
if [ -e "stable-diffusion/env" ]; then
export INSTALL_ENV_DIR="$(pwd)/stable-diffusion/env"
fi
# create the stable-diffusion folder, to work with legacy installations
if [ ! -e "stable-diffusion" ]; then mkdir stable-diffusion; fi
cd stable-diffusion
if [ `grep -c conda_sd_env_created ../scripts/install_status.txt` -gt "0" ]; then
echo "Packages necessary for Stable Diffusion were already installed"
conda activate ./env
else
printf "\n\nDownloading packages necessary for Stable Diffusion..\n"
printf "\n\n***** This will take some time (depending on the speed of the Internet connection) and may appear to be stuck, but please be patient ***** ..\n\n"
# prevent conda from using packages from the user's home directory, to avoid conflicts
export PYTHONNOUSERSITE=1
if conda env create --prefix env --force -f environment.yaml ; then
echo "Installed. Testing.."
else
printf "\n\nError installing the packages necessary for Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
conda activate ./env
if conda install -c conda-forge --prefix ./env -y antlr4-python3-runtime=4.8 ; then
echo "Installed. Testing.."
else
printf "\n\nError installing antlr4-python3-runtime for Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
out_test=`python -c "import torch; import ldm; import transformers; import numpy; import antlr4; print(42)"`
if [ "$out_test" != "42" ]; then
printf "\n\nDependency test failed! Error installing the packages necessary for Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
echo conda_sd_env_created >> ../scripts/install_status.txt
# activate the old stable-diffusion env, if it exists
if [ -e "env" ]; then
conda activate ./env || fail "conda activate failed"
fi
if [ `grep -c conda_sd_gfpgan_deps_installed ../scripts/install_status.txt` -gt "0" ]; then
echo "Packages necessary for GFPGAN (Face Correction) were already installed"
# disable the legacy src and ldm folder (otherwise this prevents installing gfpgan and realesrgan)
if [ -e "src" ]; then mv src src-old; fi
if [ -e "ldm" ]; then mv ldm ldm-old; fi
mkdir -p "../models/stable-diffusion"
mkdir -p "../models/gfpgan"
mkdir -p "../models/realesrgan"
mkdir -p "../models/vae"
# migrate the legacy models to the correct path (if already downloaded)
if [ -e "sd-v1-4.ckpt" ]; then mv sd-v1-4.ckpt ../models/stable-diffusion/; fi
if [ -e "custom-model.ckpt" ]; then mv custom-model.ckpt ../models/stable-diffusion/; fi
if [ -e "GFPGANv1.3.pth" ]; then mv GFPGANv1.3.pth ../models/gfpgan/; fi
if [ -e "RealESRGAN_x4plus.pth" ]; then mv RealESRGAN_x4plus.pth ../models/realesrgan/; fi
if [ -e "RealESRGAN_x4plus_anime_6B.pth" ]; then mv RealESRGAN_x4plus_anime_6B.pth ../models/realesrgan/; fi
# install torch and torchvision
if python ../scripts/check_modules.py torch torchvision; then
echo "torch and torchvision have already been installed."
else
printf "\n\nDownloading packages necessary for GFPGAN (Face Correction)..\n"
echo "Installing torch and torchvision.."
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
if pip install -e git+https://github.com/TencentARC/GFPGAN#egg=GFPGAN ; then
echo "Installed. Testing.."
if python -m pip install --upgrade torch torchvision --extra-index-url https://download.pytorch.org/whl/cu116 ; then
echo "Installed."
else
printf "\n\nError installing the packages necessary for GFPGAN (Face Correction). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "torch install failed"
fi
out_test=`python -c "from gfpgan import GFPGANer; print(42)"`
if [ "$out_test" != "42" ]; then
printf "\n\nDependency test failed! Error installing the packages necessary for GFPGAN (Face Correction). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
echo conda_sd_gfpgan_deps_installed >> ../scripts/install_status.txt
fi
if [ `grep -c conda_sd_esrgan_deps_installed ../scripts/install_status.txt` -gt "0" ]; then
echo "Packages necessary for ESRGAN (Resolution Upscaling) were already installed"
# install/upgrade sdkit
if python ../scripts/check_modules.py sdkit sdkit.models ldm transformers numpy antlr4 gfpgan realesrgan ; then
echo "sdkit is already installed."
# skip sdkit upgrade if in developer-mode
if [ ! -e "../src/sdkit" ]; then
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
python -m pip install --upgrade sdkit==1.0.47 -q
fi
else
printf "\n\nDownloading packages necessary for ESRGAN (Resolution Upscaling)..\n"
echo "Installing sdkit: https://pypi.org/project/sdkit/"
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
if pip install -e git+https://github.com/xinntao/Real-ESRGAN#egg=realesrgan ; then
echo "Installed. Testing.."
if python -m pip install sdkit==1.0.47 ; then
echo "Installed."
else
printf "\n\nError installing the packages necessary for ESRGAN (Resolution Upscaling). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "sdkit install failed"
fi
out_test=`python -c "from basicsr.archs.rrdbnet_arch import RRDBNet; from realesrgan import RealESRGANer; print(42)"`
if [ "$out_test" != "42" ]; then
printf "\n\nDependency test failed! Error installing the packages necessary for ESRGAN (Resolution Upscaling). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fi
echo conda_sd_esrgan_deps_installed >> ../scripts/install_status.txt
fi
if [ `grep -c conda_sd_ui_deps_installed ../scripts/install_status.txt` -gt "0" ]; then
echo "Packages necessary for Stable Diffusion UI were already installed"
python -c "from importlib.metadata import version; print('sdkit version:', version('sdkit'))"
# upgrade stable-diffusion-sdkit
python -m pip install --upgrade stable-diffusion-sdkit==2.1.3 -q
python -c "from importlib.metadata import version; print('stable-diffusion version:', version('stable-diffusion-sdkit'))"
# install rich
if python ../scripts/check_modules.py rich; then
echo "rich has already been installed."
else
printf "\n\nDownloading packages necessary for Stable Diffusion UI..\n\n"
echo "Installing rich.."
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
if conda install -c conda-forge --prefix ./env -y uvicorn fastapi ; then
if python -m pip install rich ; then
echo "Installed."
else
fail "Install failed for rich"
fi
fi
if python ../scripts/check_modules.py uvicorn fastapi ; then
echo "Packages necessary for Easy Diffusion were already installed"
else
printf "\n\nDownloading packages necessary for Easy Diffusion..\n\n"
export PYTHONNOUSERSITE=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
if conda install -c conda-forge -y uvicorn fastapi ; then
echo "Installed. Testing.."
else
printf "\n\nError installing the packages necessary for Stable Diffusion UI. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "'conda install uvicorn' failed"
fi
if ! command -v uvicorn &> /dev/null; then
printf "\n\nUI packages not found! Error installing the packages necessary for Stable Diffusion UI. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "UI packages not found!"
fi
echo conda_sd_ui_deps_installed >> ../scripts/install_status.txt
fi
if [ -f "sd-v1-4.ckpt" ]; then
model_size=`find "sd-v1-4.ckpt" -printf "%s"`
if [ -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
model_size=`filesize "../models/stable-diffusion/sd-v1-4.ckpt"`
if [ "$model_size" -eq "4265380512" ] || [ "$model_size" -eq "7703807346" ] || [ "$model_size" -eq "7703810927" ]; then
echo "Data files (weights) necessary for Stable Diffusion were already downloaded"
else
printf "\n\nThe model file present at $PWD/sd-v1-4.ckpt is invalid. It is only $model_size bytes in size. Re-downloading.."
rm sd-v1-4.ckpt
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.."
rm ../models/stable-diffusion/sd-v1-4.ckpt
fi
fi
if [ ! -f "sd-v1-4.ckpt" ]; then
if [ ! -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
echo "Downloading data files (weights) for Stable Diffusion.."
curl -L -k https://me.cmdr2.org/stable-diffusion-ui/sd-v1-4.ckpt > sd-v1-4.ckpt
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
if [ -f "sd-v1-4.ckpt" ]; then
model_size=`find "sd-v1-4.ckpt" -printf "%s"`
if [ -f "../models/stable-diffusion/sd-v1-4.ckpt" ]; then
model_size=`filesize "../models/stable-diffusion/sd-v1-4.ckpt"`
if [ ! "$model_size" == "4265380512" ]; then
printf "\n\nError: The downloaded model file was invalid! Bytes downloaded: $model_size\n\n"
printf "\n\nError downloading the data files (weights) for Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "The downloaded model file was invalid! Bytes downloaded: $model_size"
fi
else
printf "\n\nError downloading the data files (weights) for Stable Diffusion. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "Error downloading the data files (weights) for Stable Diffusion"
fi
fi
if [ -f "GFPGANv1.3.pth" ]; then
model_size=`find "GFPGANv1.3.pth" -printf "%s"`
if [ -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
model_size=`filesize "../models/gfpgan/GFPGANv1.3.pth"`
if [ "$model_size" -eq "348632874" ]; then
echo "Data files (weights) necessary for GFPGAN (Face Correction) were already downloaded"
else
printf "\n\nThe model file present at $PWD/GFPGANv1.3.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
rm GFPGANv1.3.pth
printf "\n\nThe model file present at models/gfpgan/GFPGANv1.3.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
rm ../models/gfpgan/GFPGANv1.3.pth
fi
fi
if [ ! -f "GFPGANv1.3.pth" ]; then
if [ ! -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
echo "Downloading data files (weights) for GFPGAN (Face Correction).."
curl -L -k https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth > GFPGANv1.3.pth
curl -L -k https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth > ../models/gfpgan/GFPGANv1.3.pth
if [ -f "GFPGANv1.3.pth" ]; then
model_size=`find "GFPGANv1.3.pth" -printf "%s"`
if [ -f "../models/gfpgan/GFPGANv1.3.pth" ]; then
model_size=`filesize "../models/gfpgan/GFPGANv1.3.pth"`
if [ ! "$model_size" -eq "348632874" ]; then
printf "\n\nError: The downloaded GFPGAN model file was invalid! Bytes downloaded: $model_size\n\n"
printf "\n\nError downloading the data files (weights) for GFPGAN (Face Correction). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "The downloaded GFPGAN model file was invalid! Bytes downloaded: $model_size"
fi
else
printf "\n\nError downloading the data files (weights) for GFPGAN (Face Correction). 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "Error downloading the data files (weights) for GFPGAN (Face Correction)."
fi
fi
if [ -f "RealESRGAN_x4plus.pth" ]; then
model_size=`find "RealESRGAN_x4plus.pth" -printf "%s"`
if [ -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus.pth"`
if [ "$model_size" -eq "67040989" ]; then
echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus were already downloaded"
else
printf "\n\nThe model file present at $PWD/RealESRGAN_x4plus.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
rm RealESRGAN_x4plus.pth
printf "\n\nThe model file present at models/realesrgan/RealESRGAN_x4plus.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
rm ../models/realesrgan/RealESRGAN_x4plus.pth
fi
fi
if [ ! -f "RealESRGAN_x4plus.pth" ]; then
if [ ! -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus.."
curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth > RealESRGAN_x4plus.pth
curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth > ../models/realesrgan/RealESRGAN_x4plus.pth
if [ -f "RealESRGAN_x4plus.pth" ]; then
model_size=`find "RealESRGAN_x4plus.pth" -printf "%s"`
if [ -f "../models/realesrgan/RealESRGAN_x4plus.pth" ]; then
model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus.pth"`
if [ ! "$model_size" -eq "67040989" ]; then
printf "\n\nError: The downloaded ESRGAN x4plus model file was invalid! Bytes downloaded: $model_size\n\n"
printf "\n\nError downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "The downloaded ESRGAN x4plus model file was invalid! Bytes downloaded: $model_size"
fi
else
printf "\n\nError downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus. 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/blob/main/Troubleshooting.md\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"
read -p "Press any key to continue"
exit
fail "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus"
fi
fi
if [ -f "RealESRGAN_x4plus_anime_6B.pth" ]; then
model_size=`find "RealESRGAN_x4plus_anime_6B.pth" -printf "%s"`
if [ -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth"`
if [ "$model_size" -eq "17938799" ]; then
echo "Data files (weights) necessary for ESRGAN (Resolution Upscaling) x4plus_anime were already downloaded"
else
printf "\n\nThe model file present at $PWD/RealESRGAN_x4plus_anime_6B.pth is invalid. It is only $model_size bytes in size. Re-downloading.."
rm RealESRGAN_x4plus_anime_6B.pth
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.."
rm ../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth
fi
fi
if [ ! -f "RealESRGAN_x4plus_anime_6B.pth" ]; then
if [ ! -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
echo "Downloading data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime.."
curl -L -k https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth > RealESRGAN_x4plus_anime_6B.pth
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
if [ -f "RealESRGAN_x4plus_anime_6B.pth" ]; then
model_size=`find "RealESRGAN_x4plus_anime_6B.pth" -printf "%s"`
if [ -f "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth" ]; then
model_size=`filesize "../models/realesrgan/RealESRGAN_x4plus_anime_6B.pth"`
if [ ! "$model_size" -eq "17938799" ]; then
printf "\n\nError: The downloaded ESRGAN x4plus_anime model file was invalid! Bytes downloaded: $model_size\n\n"
printf "\n\nError downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. 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/blob/main/Troubleshooting.md\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"
fail "The downloaded ESRGAN x4plus_anime model file was invalid! Bytes downloaded: $model_size"
fi
else
fail "Error downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime."
fi
fi
if [ -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
model_size=`filesize "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt"`
if [ "$model_size" -eq "334695179" ]; then
echo "Data files (weights) necessary for the default VAE (sd-vae-ft-mse-original) were already downloaded"
else
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.."
rm ../models/vae/vae-ft-mse-840000-ema-pruned.ckpt
fi
fi
if [ ! -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
echo "Downloading data files (weights) for the default VAE (sd-vae-ft-mse-original).."
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
if [ -f "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt" ]; then
model_size=`filesize "../models/vae/vae-ft-mse-840000-ema-pruned.ckpt"`
if [ ! "$model_size" -eq "334695179" ]; then
printf "\n\nError: The downloaded default VAE (sd-vae-ft-mse-original) file was invalid! Bytes downloaded: $model_size\n\n"
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"
read -p "Press any key to continue"
exit
fi
else
printf "\n\nError downloading the data files (weights) for ESRGAN (Resolution Upscaling) x4plus_anime. 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/blob/main/Troubleshooting.md\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"
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"
read -p "Press any key to continue"
exit
fi
fi
if [ `grep -c sd_install_complete ../scripts/install_status.txt` -gt "0" ]; then
echo sd_weights_downloaded >> ../scripts/install_status.txt
echo sd_install_complete >> ../scripts/install_status.txt
fi
printf "\n\nStable Diffusion is ready!\n\n"
printf "\n\nEasy Diffusion installation complete, starting the server!\n\n"
SD_PATH=`pwd`
export PYTHONPATH="$SD_PATH;$SD_PATH/env/lib/python3.8/site-packages"
export PYTORCH_ENABLE_MPS_FALLBACK=1
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
echo "PYTHONPATH=$PYTHONPATH"
which python
python --version
cd ..
export SD_UI_PATH=`pwd`/ui
cd stable-diffusion
python --version
uvicorn server:app --app-dir "$SD_UI_PATH" --port 9000 --host 0.0.0.0
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
read -p "Press any key to continue"

View File

@ -1,6 +0,0 @@
@call conda --version
@call git --version
cd %CONDA_PREFIX%\..\scripts
on_env_start.bat

View File

@ -1,12 +0,0 @@
#!/bin/bash
conda-unpack
source $CONDA_PREFIX/etc/profile.d/conda.sh
conda --version
git --version
cd $CONDA_PREFIX/../scripts
./on_env_start.sh

39
scripts/start.sh Normal file → Executable file
View File

@ -1,10 +1,41 @@
#!/bin/bash
source installer/bin/activate
cd "$(dirname "${BASH_SOURCE[0]}")"
conda-unpack
if [ -f "on_sd_start.bat" ]; then
echo ================================================================================
echo
echo !!!! WARNING !!!!
echo
echo It looks like you\'re trying to run the installation script from a source code
echo download. This will not work.
echo
echo Recommended: Please close this window and download the installer from
echo https://stable-diffusion-ui.github.io/docs/installation/
echo
echo ================================================================================
echo
read
exit 1
fi
conda --version
git --version
# set legacy installer's PATH, if it exists
if [ -e "installer" ]; then export PATH="$(pwd)/installer/bin:$PATH"; fi
# Setup the packages required for the installer
scripts/bootstrap.sh || exit 1
# set new installer's PATH, if it downloaded any packages
if [ -e "installer_files/env" ]; then export PATH="$(pwd)/installer_files/env/bin:$PATH"; fi
# Test the bootstrap
which git
git --version || exit 1
which conda
conda --version || exit 1
# Download the rest of the installer and UI
chmod +x scripts/*.sh
scripts/on_env_start.sh

View File

328
ui/easydiffusion/app.py Normal file
View File

@ -0,0 +1,328 @@
import os
import socket
import sys
import json
import traceback
import logging
import shlex
import urllib
from rich.logging import RichHandler
from sdkit.utils import log as sdkit_log # hack, so we can overwrite the log config
from easydiffusion import task_manager
from easydiffusion.utils import log
# Remove all handlers associated with the root logger object.
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
LOG_FORMAT = "%(asctime)s.%(msecs)03d %(levelname)s %(threadName)s %(message)s"
logging.basicConfig(
level=logging.INFO,
format=LOG_FORMAT,
datefmt="%X",
handlers=[RichHandler(markup=True, rich_tracebacks=False, show_time=False, show_level=False)],
)
SD_DIR = os.getcwd()
SD_UI_DIR = os.getenv("SD_UI_PATH", None)
CONFIG_DIR = os.path.abspath(os.path.join(SD_UI_DIR, "..", "scripts"))
MODELS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "models"))
USER_PLUGINS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "plugins"))
CORE_PLUGINS_DIR = os.path.abspath(os.path.join(SD_UI_DIR, "plugins"))
USER_UI_PLUGINS_DIR = os.path.join(USER_PLUGINS_DIR, "ui")
CORE_UI_PLUGINS_DIR = os.path.join(CORE_PLUGINS_DIR, "ui")
USER_SERVER_PLUGINS_DIR = os.path.join(USER_PLUGINS_DIR, "server")
UI_PLUGINS_SOURCES = ((CORE_UI_PLUGINS_DIR, "core"), (USER_UI_PLUGINS_DIR, "user"))
sys.path.append(os.path.dirname(SD_UI_DIR))
sys.path.append(USER_SERVER_PLUGINS_DIR)
OUTPUT_DIRNAME = "Stable Diffusion UI" # in the user's home folder
PRESERVE_CONFIG_VARS = ["FORCE_FULL_PRECISION"]
TASK_TTL = 15 * 60 # Discard last session's task timeout
APP_CONFIG_DEFAULTS = {
# auto: selects the cuda device with the most free memory, cuda: use the currently active cuda device.
"render_devices": "auto", # valid entries: 'auto', 'cpu' or 'cuda:N' (where N is a GPU index)
"update_branch": "main",
"ui": {
"open_browser_on_start": True,
},
}
IMAGE_EXTENSIONS = [".png", ".apng", ".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".jxl", ".gif", ".webp", ".avif", ".svg"]
CUSTOM_MODIFIERS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "modifiers"))
CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS=[".portrait", "_portrait", " portrait", "-portrait"]
CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS=[".landscape", "_landscape", " landscape", "-landscape"]
def init():
os.makedirs(USER_UI_PLUGINS_DIR, exist_ok=True)
os.makedirs(USER_SERVER_PLUGINS_DIR, exist_ok=True)
load_server_plugins()
update_render_threads()
def getConfig(default_val=APP_CONFIG_DEFAULTS):
try:
config_json_path = os.path.join(CONFIG_DIR, "config.json")
if not os.path.exists(config_json_path):
config = default_val
else:
with open(config_json_path, "r", encoding="utf-8") as f:
config = json.load(f)
if "net" not in config:
config["net"] = {}
if os.getenv("SD_UI_BIND_PORT") is not None:
config["net"]["listen_port"] = int(os.getenv("SD_UI_BIND_PORT"))
else:
config["net"]["listen_port"] = 9000
if os.getenv("SD_UI_BIND_IP") is not None:
config["net"]["listen_to_network"] = os.getenv("SD_UI_BIND_IP") == "0.0.0.0"
else:
config["net"]["listen_to_network"] = True
return config
except Exception as e:
log.warn(traceback.format_exc())
return default_val
def setConfig(config):
try: # config.json
config_json_path = os.path.join(CONFIG_DIR, "config.json")
with open(config_json_path, "w", encoding="utf-8") as f:
json.dump(config, f)
except:
log.error(traceback.format_exc())
try: # config.bat
config_bat_path = os.path.join(CONFIG_DIR, "config.bat")
config_bat = []
if "update_branch" in config:
config_bat.append(f"@set update_branch={config['update_branch']}")
config_bat.append(f"@set SD_UI_BIND_PORT={config['net']['listen_port']}")
bind_ip = "0.0.0.0" if config["net"]["listen_to_network"] else "127.0.0.1"
config_bat.append(f"@set SD_UI_BIND_IP={bind_ip}")
# Preserve these variables if they are set
for var in PRESERVE_CONFIG_VARS:
if os.getenv(var) is not None:
config_bat.append(f"@set {var}={os.getenv(var)}")
if len(config_bat) > 0:
with open(config_bat_path, "w", encoding="utf-8") as f:
f.write("\n".join(config_bat))
except:
log.error(traceback.format_exc())
try: # config.sh
config_sh_path = os.path.join(CONFIG_DIR, "config.sh")
config_sh = ["#!/bin/bash"]
if "update_branch" in config:
config_sh.append(f"export update_branch={config['update_branch']}")
config_sh.append(f"export SD_UI_BIND_PORT={config['net']['listen_port']}")
bind_ip = "0.0.0.0" if config["net"]["listen_to_network"] else "127.0.0.1"
config_sh.append(f"export SD_UI_BIND_IP={bind_ip}")
# Preserve these variables if they are set
for var in PRESERVE_CONFIG_VARS:
if os.getenv(var) is not None:
config_bat.append(f'export {var}="{shlex.quote(os.getenv(var))}"')
if len(config_sh) > 1:
with open(config_sh_path, "w", encoding="utf-8") as f:
f.write("\n".join(config_sh))
except:
log.error(traceback.format_exc())
def save_to_config(ckpt_model_name, vae_model_name, hypernetwork_model_name, vram_usage_level):
config = getConfig()
if "model" not in config:
config["model"] = {}
config["model"]["stable-diffusion"] = ckpt_model_name
config["model"]["vae"] = vae_model_name
config["model"]["hypernetwork"] = hypernetwork_model_name
if vae_model_name is None or vae_model_name == "":
del config["model"]["vae"]
if hypernetwork_model_name is None or hypernetwork_model_name == "":
del config["model"]["hypernetwork"]
config["vram_usage_level"] = vram_usage_level
setConfig(config)
def update_render_threads():
config = getConfig()
render_devices = config.get("render_devices", "auto")
active_devices = task_manager.get_devices()["active"].keys()
log.debug(f"requesting for render_devices: {render_devices}")
task_manager.update_render_threads(render_devices, active_devices)
def getUIPlugins():
plugins = []
for plugins_dir, dir_prefix in UI_PLUGINS_SOURCES:
for file in os.listdir(plugins_dir):
if file.endswith(".plugin.js"):
plugins.append(f"/plugins/{dir_prefix}/{file}")
return plugins
def load_server_plugins():
if not os.path.exists(USER_SERVER_PLUGINS_DIR):
return
import importlib
def load_plugin(file):
mod_path = file.replace(".py", "")
return importlib.import_module(mod_path)
def apply_plugin(file, plugin):
if hasattr(plugin, "get_cond_and_uncond"):
import sdkit.generate.image_generator
sdkit.generate.image_generator.get_cond_and_uncond = plugin.get_cond_and_uncond
log.info(f"Overridden get_cond_and_uncond with the one in the server plugin: {file}")
for file in os.listdir(USER_SERVER_PLUGINS_DIR):
file_path = os.path.join(USER_SERVER_PLUGINS_DIR, file)
if (not os.path.isdir(file_path) and not file_path.endswith("_plugin.py")) or (
os.path.isdir(file_path) and not file_path.endswith("_plugin")
):
continue
try:
log.info(f"Loading server plugin: {file}")
mod = load_plugin(file)
log.info(f"Applying server plugin: {file}")
apply_plugin(file, mod)
except:
log.warn(f"Error while loading a server plugin")
log.warn(traceback.format_exc())
def getIPConfig():
try:
ips = socket.gethostbyname_ex(socket.gethostname())
ips[2].append(ips[0])
return ips[2]
except Exception as e:
log.exception(e)
return []
def open_browser():
config = getConfig()
ui = config.get("ui", {})
net = config.get("net", {"listen_port": 9000})
port = net.get("listen_port", 9000)
if ui.get("open_browser_on_start", True):
import webbrowser
webbrowser.open(f"http://localhost:{port}")
def get_image_modifiers():
modifiers_json_path = os.path.join(SD_UI_DIR, "modifiers.json")
modifier_categories = {}
original_category_order=[]
with open(modifiers_json_path, "r", encoding="utf-8") as f:
modifiers_file = json.load(f)
# The trailing slash is needed to support symlinks
if not os.path.isdir(f"{CUSTOM_MODIFIERS_DIR}/"):
return modifiers_file
# convert modifiers from a list of objects to a dict of dicts
for category_item in modifiers_file:
category_name = category_item['category']
original_category_order.append(category_name)
category = {}
for modifier_item in category_item['modifiers']:
modifier = {}
for preview_item in modifier_item['previews']:
modifier[preview_item['name']] = preview_item['path']
category[modifier_item['modifier']] = modifier
modifier_categories[category_name] = category
def scan_directory(directory_path: str, category_name="Modifiers"):
for entry in os.scandir(directory_path):
if entry.is_file():
file_extension = list(filter(lambda e: entry.name.endswith(e), IMAGE_EXTENSIONS))
if len(file_extension) == 0:
continue
modifier_name = entry.name[: -len(file_extension[0])]
modifier_path = f"custom/{entry.path[len(CUSTOM_MODIFIERS_DIR) + 1:]}"
# URL encode path segments
modifier_path = "/".join(map(lambda segment: urllib.parse.quote(segment), modifier_path.split("/")))
is_portrait = True
is_landscape = True
portrait_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_PORTRAIT_EXTENSIONS))
landscape_extension = list(filter(lambda e: modifier_name.lower().endswith(e), CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS))
if len(portrait_extension) > 0:
is_landscape = False
modifier_name = modifier_name[: -len(portrait_extension[0])]
elif len(landscape_extension) > 0:
is_portrait = False
modifier_name = modifier_name[: -len(landscape_extension[0])]
if (category_name not in modifier_categories):
modifier_categories[category_name] = {}
category = modifier_categories[category_name]
if (modifier_name not in category):
category[modifier_name] = {}
if (is_portrait or "portrait" not in category[modifier_name]):
category[modifier_name]["portrait"] = modifier_path
if (is_landscape or "landscape" not in category[modifier_name]):
category[modifier_name]["landscape"] = modifier_path
elif entry.is_dir():
scan_directory(
entry.path,
entry.name if directory_path==CUSTOM_MODIFIERS_DIR else f"{category_name}/{entry.name}",
)
scan_directory(CUSTOM_MODIFIERS_DIR)
custom_categories = sorted(
[cn for cn in modifier_categories.keys() if cn not in original_category_order],
key=str.casefold,
)
# convert the modifiers back into a list of objects
modifier_categories_list = []
for category_name in [*original_category_order, *custom_categories]:
category = { 'category': category_name, 'modifiers': [] }
for modifier_name in sorted(modifier_categories[category_name].keys(), key=str.casefold):
modifier = { 'modifier': modifier_name, 'previews': [] }
for preview_name, preview_path in modifier_categories[category_name][modifier_name].items():
modifier['previews'].append({ 'name': preview_name, 'path': preview_path })
category['modifiers'].append(modifier)
modifier_categories_list.append(category)
return modifier_categories_list

View File

@ -0,0 +1,253 @@
import os
import platform
import torch
import traceback
import re
from easydiffusion.utils import log
"""
Set `FORCE_FULL_PRECISION` in the environment variables, or in `config.bat`/`config.sh` to set full precision (i.e. float32).
Otherwise the models will load at half-precision (i.e. float16).
Half-precision is fine most of the time. Full precision is only needed for working around GPU bugs (like NVIDIA 16xx GPUs).
"""
COMPARABLE_GPU_PERCENTILE = (
0.65 # if a GPU's free_mem is within this % of the GPU with the most free_mem, it will be picked
)
mem_free_threshold = 0
def get_device_delta(render_devices, active_devices):
"""
render_devices: 'cpu', or 'auto', or 'mps' or ['cuda:N'...]
active_devices: ['cpu', 'mps', 'cuda:N'...]
"""
if render_devices in ("cpu", "auto", "mps"):
render_devices = [render_devices]
elif render_devices is not None:
if isinstance(render_devices, str):
render_devices = [render_devices]
if isinstance(render_devices, list) and len(render_devices) > 0:
render_devices = list(filter(lambda x: x.startswith("cuda:") or x == "mps", render_devices))
if len(render_devices) == 0:
raise Exception(
'Invalid render_devices value in config.json. Valid: {"render_devices": ["cuda:0", "cuda:1"...]}, or {"render_devices": "cpu"} or {"render_devices": "mps"} or {"render_devices": "auto"}'
)
render_devices = list(filter(lambda x: is_device_compatible(x), render_devices))
if len(render_devices) == 0:
raise Exception(
"Sorry, none of the render_devices configured in config.json are compatible with Stable Diffusion"
)
else:
raise Exception(
'Invalid render_devices value in config.json. Valid: {"render_devices": ["cuda:0", "cuda:1"...]}, or {"render_devices": "cpu"} or {"render_devices": "auto"}'
)
else:
render_devices = ["auto"]
if "auto" in render_devices:
render_devices = auto_pick_devices(active_devices)
if "cpu" in render_devices:
log.warn("WARNING: Could not find a compatible GPU. Using the CPU, but this will be very slow!")
active_devices = set(active_devices)
render_devices = set(render_devices)
devices_to_start = render_devices - active_devices
devices_to_stop = active_devices - render_devices
return devices_to_start, devices_to_stop
def is_mps_available():
return (
platform.system() == "Darwin"
and hasattr(torch.backends, "mps")
and torch.backends.mps.is_available()
and torch.backends.mps.is_built()
)
def is_cuda_available():
return torch.cuda.is_available()
def auto_pick_devices(currently_active_devices):
global mem_free_threshold
if is_mps_available():
return ["mps"]
if not is_cuda_available():
return ["cpu"]
device_count = torch.cuda.device_count()
if device_count == 1:
return ["cuda:0"] if is_device_compatible("cuda:0") else ["cpu"]
log.debug("Autoselecting GPU. Using most free memory.")
devices = []
for device in range(device_count):
device = f"cuda:{device}"
if not is_device_compatible(device):
continue
mem_free, mem_total = torch.cuda.mem_get_info(device)
mem_free /= float(10**9)
mem_total /= float(10**9)
device_name = torch.cuda.get_device_name(device)
log.debug(
f"{device} detected: {device_name} - Memory (free/total): {round(mem_free, 2)}Gb / {round(mem_total, 2)}Gb"
)
devices.append({"device": device, "device_name": device_name, "mem_free": mem_free})
devices.sort(key=lambda x: x["mem_free"], reverse=True)
max_mem_free = devices[0]["mem_free"]
curr_mem_free_threshold = COMPARABLE_GPU_PERCENTILE * max_mem_free
mem_free_threshold = max(curr_mem_free_threshold, mem_free_threshold)
# Auto-pick algorithm:
# 1. Pick the top 75 percentile of the GPUs, sorted by free_mem.
# 2. Also include already-running devices (GPU-only), otherwise their free_mem will
# always be very low (since their VRAM contains the model).
# These already-running devices probably aren't terrible, since they were picked in the past.
# Worst case, the user can restart the program and that'll get rid of them.
devices = list(
filter((lambda x: x["mem_free"] > mem_free_threshold or x["device"] in currently_active_devices), devices)
)
devices = list(map(lambda x: x["device"], devices))
return devices
def device_init(context, device):
"""
This function assumes the 'device' has already been verified to be compatible.
`get_device_delta()` has already filtered out incompatible devices.
"""
validate_device_id(device, log_prefix="device_init")
if "cuda" not in device:
context.device = device
context.device_name = get_processor_name()
context.half_precision = False
log.debug(f"Render device available as {context.device_name}")
return
context.device_name = torch.cuda.get_device_name(device)
context.device = device
# Force full precision on 1660 and 1650 NVIDIA cards to avoid creating green images
if needs_to_force_full_precision(context):
log.warn(f"forcing full precision on this GPU, to avoid green images. GPU detected: {context.device_name}")
# Apply force_full_precision now before models are loaded.
context.half_precision = False
log.info(f'Setting {device} as active, with precision: {"half" if context.half_precision else "full"}')
torch.cuda.device(device)
def needs_to_force_full_precision(context):
if "FORCE_FULL_PRECISION" in os.environ:
return True
device_name = context.device_name.lower()
return (
("nvidia" in device_name or "geforce" in device_name or "quadro" in device_name)
and (
" 1660" in device_name
or " 1650" in device_name
or " t400" in device_name
or " t550" in device_name
or " t600" in device_name
or " t1000" in device_name
or " t1200" in device_name
or " t2000" in device_name
)
) or ("tesla k40m" in device_name)
def get_max_vram_usage_level(device):
if "cuda" in device:
_, mem_total = torch.cuda.mem_get_info(device)
else:
return "high"
mem_total /= float(10**9)
if mem_total < 4.5:
return "low"
elif mem_total < 6.5:
return "balanced"
return "high"
def validate_device_id(device, log_prefix=""):
def is_valid():
if not isinstance(device, str):
return False
if device == "cpu" or device == "mps":
return True
if not device.startswith("cuda:") or not device[5:].isnumeric():
return False
return True
if not is_valid():
raise EnvironmentError(
f"{log_prefix}: device id should be 'cpu', 'mps', or 'cuda:N' (where N is an integer index for the GPU). Got: {device}"
)
def is_device_compatible(device):
"""
Returns True/False, and prints any compatibility errors
"""
# static variable "history".
is_device_compatible.history = getattr(is_device_compatible, "history", {})
try:
validate_device_id(device, log_prefix="is_device_compatible")
except:
log.error(str(e))
return False
if device in ("cpu", "mps"):
return True
# Memory check
try:
_, mem_total = torch.cuda.mem_get_info(device)
mem_total /= float(10**9)
if mem_total < 3.0:
if is_device_compatible.history.get(device) == None:
log.warn(f"GPU {device} with less than 3 GB of VRAM is not compatible with Stable Diffusion")
is_device_compatible.history[device] = 1
return False
except RuntimeError as e:
log.error(str(e))
return False
return True
def get_processor_name():
try:
import subprocess
if platform.system() == "Windows":
return platform.processor()
elif platform.system() == "Darwin":
os.environ["PATH"] = os.environ["PATH"] + os.pathsep + "/usr/sbin"
command = "sysctl -n machdep.cpu.brand_string"
return subprocess.check_output(command, shell=True).decode().strip()
elif platform.system() == "Linux":
command = "cat /proc/cpuinfo"
all_info = subprocess.check_output(command, shell=True).decode().strip()
for line in all_info.split("\n"):
if "model name" in line:
return re.sub(".*model name.*:", "", line, 1).strip()
except:
log.error(traceback.format_exc())
return "cpu"

View File

@ -0,0 +1,255 @@
import os
from easydiffusion import app
from easydiffusion.types import TaskData
from easydiffusion.utils import log
from sdkit import Context
from sdkit.models import load_model, unload_model, scan_model
KNOWN_MODEL_TYPES = ["stable-diffusion", "vae", "hypernetwork", "gfpgan", "realesrgan"]
MODEL_EXTENSIONS = {
"stable-diffusion": [".ckpt", ".safetensors"],
"vae": [".vae.pt", ".ckpt", ".safetensors"],
"hypernetwork": [".pt", ".safetensors"],
"gfpgan": [".pth"],
"realesrgan": [".pth"],
}
DEFAULT_MODELS = {
"stable-diffusion": [ # needed to support the legacy installations
"custom-model", # only one custom model file was supported initially, creatively named 'custom-model'
"sd-v1-4", # Default fallback.
],
"gfpgan": ["GFPGANv1.3"],
"realesrgan": ["RealESRGAN_x4plus"],
}
MODELS_TO_LOAD_ON_START = ["stable-diffusion", "vae", "hypernetwork"]
known_models = {}
def init():
make_model_folders()
getModels() # run this once, to cache the picklescan results
def load_default_models(context: Context):
set_vram_optimizations(context)
# init default model paths
for model_type in MODELS_TO_LOAD_ON_START:
context.model_paths[model_type] = resolve_model_to_use(model_type=model_type)
try:
load_model(context, model_type)
except Exception as e:
log.error(f"[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]")
log.error(f"[red]Error: {e}[/red]")
log.error(f"[red]Consider removing the model from the model folder.[red]")
def unload_all(context: Context):
for model_type in KNOWN_MODEL_TYPES:
unload_model(context, model_type)
def resolve_model_to_use(model_name: str = None, model_type: str = None):
model_extensions = MODEL_EXTENSIONS.get(model_type, [])
default_models = DEFAULT_MODELS.get(model_type, [])
config = app.getConfig()
model_dirs = [os.path.join(app.MODELS_DIR, model_type), app.SD_DIR]
if not model_name: # When None try user configured model.
# config = getConfig()
if "model" in config and model_type in config["model"]:
model_name = config["model"][model_type]
if model_name:
# Check models directory
models_dir_path = os.path.join(app.MODELS_DIR, model_type, model_name)
for model_extension in model_extensions:
if os.path.exists(models_dir_path + model_extension):
return models_dir_path + model_extension
if os.path.exists(model_name + model_extension):
return os.path.abspath(model_name + model_extension)
# Default locations
if model_name in default_models:
default_model_path = os.path.join(app.SD_DIR, model_name)
for model_extension in model_extensions:
if os.path.exists(default_model_path + model_extension):
return default_model_path + model_extension
# Can't find requested model, check the default paths.
for default_model in default_models:
for model_dir in model_dirs:
default_model_path = os.path.join(model_dir, default_model)
for model_extension in model_extensions:
if os.path.exists(default_model_path + model_extension):
if model_name is not None:
log.warn(
f"Could not find the configured custom model {model_name}{model_extension}. Using the default one: {default_model_path}{model_extension}"
)
return default_model_path + model_extension
return None
def reload_models_if_necessary(context: Context, task_data: TaskData):
model_paths_in_req = {
"stable-diffusion": task_data.use_stable_diffusion_model,
"vae": task_data.use_vae_model,
"hypernetwork": task_data.use_hypernetwork_model,
"gfpgan": task_data.use_face_correction,
"realesrgan": task_data.use_upscale,
"nsfw_checker": True if task_data.block_nsfw else None,
}
models_to_reload = {
model_type: path
for model_type, path in model_paths_in_req.items()
if context.model_paths.get(model_type) != path
}
if set_vram_optimizations(context): # reload SD
models_to_reload["stable-diffusion"] = model_paths_in_req["stable-diffusion"]
for model_type, model_path_in_req in models_to_reload.items():
context.model_paths[model_type] = model_path_in_req
action_fn = unload_model if context.model_paths[model_type] is None else load_model
action_fn(context, model_type, scan_model=False) # we've scanned them already
def resolve_model_paths(task_data: TaskData):
task_data.use_stable_diffusion_model = resolve_model_to_use(
task_data.use_stable_diffusion_model, model_type="stable-diffusion"
)
task_data.use_vae_model = resolve_model_to_use(task_data.use_vae_model, model_type="vae")
task_data.use_hypernetwork_model = resolve_model_to_use(task_data.use_hypernetwork_model, model_type="hypernetwork")
if task_data.use_face_correction:
task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, "gfpgan")
if task_data.use_upscale:
task_data.use_upscale = resolve_model_to_use(task_data.use_upscale, "realesrgan")
def set_vram_optimizations(context: Context):
config = app.getConfig()
vram_usage_level = config.get("vram_usage_level", "balanced")
if vram_usage_level != context.vram_usage_level:
context.vram_usage_level = vram_usage_level
return True
return False
def make_model_folders():
for model_type in KNOWN_MODEL_TYPES:
model_dir_path = os.path.join(app.MODELS_DIR, model_type)
os.makedirs(model_dir_path, exist_ok=True)
help_file_name = f"Place your {model_type} model files here.txt"
help_file_contents = f'Supported extensions: {" or ".join(MODEL_EXTENSIONS.get(model_type))}'
with open(os.path.join(model_dir_path, help_file_name), "w", encoding="utf-8") as f:
f.write(help_file_contents)
def is_malicious_model(file_path):
try:
if file_path.endswith(".safetensors"):
return False
scan_result = scan_model(file_path)
if scan_result.issues_count > 0 or scan_result.infected_files > 0:
log.warn(
":warning: [bold red]Scan %s: %d scanned, %d issue, %d infected.[/bold red]"
% (file_path, scan_result.scanned_files, scan_result.issues_count, scan_result.infected_files)
)
return True
else:
log.debug(
"Scan %s: [green]%d scanned, %d issue, %d infected.[/green]"
% (file_path, scan_result.scanned_files, scan_result.issues_count, scan_result.infected_files)
)
return False
except Exception as e:
log.error(f"error while scanning: {file_path}, error: {e}")
return False
def getModels():
models = {
"active": {
"stable-diffusion": "sd-v1-4",
"vae": "",
"hypernetwork": "",
},
"options": {
"stable-diffusion": ["sd-v1-4"],
"vae": [],
"hypernetwork": [],
},
}
models_scanned = 0
class MaliciousModelException(Exception):
"Raised when picklescan reports a problem with a model"
pass
def scan_directory(directory, suffixes, directoriesFirst: bool = True):
nonlocal models_scanned
tree = []
for entry in sorted(
os.scandir(directory), key=lambda entry: (entry.is_file() == directoriesFirst, entry.name.lower())
):
if entry.is_file():
matching_suffix = list(filter(lambda s: entry.name.endswith(s), suffixes))
if len(matching_suffix) == 0:
continue
matching_suffix = matching_suffix[0]
mtime = entry.stat().st_mtime
mod_time = known_models[entry.path] if entry.path in known_models else -1
if mod_time != mtime:
models_scanned += 1
if is_malicious_model(entry.path):
raise MaliciousModelException(entry.path)
known_models[entry.path] = mtime
tree.append(entry.name[: -len(matching_suffix)])
elif entry.is_dir():
scan = scan_directory(entry.path, suffixes, directoriesFirst=False)
if len(scan) != 0:
tree.append((entry.name, scan))
return tree
def listModels(model_type):
nonlocal models_scanned
model_extensions = MODEL_EXTENSIONS.get(model_type, [])
models_dir = os.path.join(app.MODELS_DIR, model_type)
if not os.path.exists(models_dir):
os.makedirs(models_dir)
try:
models["options"][model_type] = scan_directory(models_dir, model_extensions)
except MaliciousModelException as e:
models["scan-error"] = e
# custom models
listModels(model_type="stable-diffusion")
listModels(model_type="vae")
listModels(model_type="hypernetwork")
listModels(model_type="gfpgan")
if models_scanned > 0:
log.info(f"[green]Scanned {models_scanned} models. Nothing infected[/]")
# legacy
custom_weight_path = os.path.join(app.SD_DIR, "custom-model.ckpt")
if os.path.exists(custom_weight_path):
models["options"]["stable-diffusion"].append("custom-model")
return models

View File

@ -0,0 +1,177 @@
import queue
import time
import json
import pprint
from easydiffusion import device_manager
from easydiffusion.types import TaskData, Response, Image as ResponseImage, UserInitiatedStop, GenerateImageRequest
from easydiffusion.utils import get_printable_request, save_images_to_disk, log
from sdkit import Context
from sdkit.generate import generate_images
from sdkit.filter import apply_filters
from sdkit.utils import img_to_buffer, img_to_base64_str, latent_samples_to_images, gc
context = Context() # thread-local
"""
runtime data (bound locally to this thread), for e.g. device, references to loaded models, optimization flags etc
"""
def init(device):
"""
Initializes the fields that will be bound to this runtime's context, and sets the current torch device
"""
context.stop_processing = False
context.temp_images = {}
context.partial_x_samples = None
device_manager.device_init(context, device)
def make_images(
req: GenerateImageRequest, task_data: TaskData, data_queue: queue.Queue, task_temp_images: list, step_callback
):
context.stop_processing = False
print_task_info(req, task_data)
images, seeds = make_images_internal(req, task_data, data_queue, task_temp_images, step_callback)
res = Response(req, task_data, images=construct_response(images, seeds, task_data, base_seed=req.seed))
res = res.json()
data_queue.put(json.dumps(res))
log.info("Task completed")
return res
def print_task_info(req: GenerateImageRequest, task_data: TaskData):
req_str = pprint.pformat(get_printable_request(req)).replace("[", "\[")
task_str = pprint.pformat(task_data.dict()).replace("[", "\[")
log.info(f"request: {req_str}")
log.info(f"task data: {task_str}")
def make_images_internal(
req: GenerateImageRequest, task_data: TaskData, data_queue: queue.Queue, task_temp_images: list, step_callback
):
images, user_stopped = generate_images_internal(
req, task_data, data_queue, task_temp_images, step_callback, task_data.stream_image_progress, task_data.stream_image_progress_interval
)
filtered_images = filter_images(task_data, images, user_stopped)
if task_data.save_to_disk_path is not None:
save_images_to_disk(images, filtered_images, req, task_data)
seeds = [*range(req.seed, req.seed + len(images))]
if task_data.show_only_filtered_image or filtered_images is images:
return filtered_images, seeds
else:
return images + filtered_images, seeds + seeds
def generate_images_internal(
req: GenerateImageRequest,
task_data: TaskData,
data_queue: queue.Queue,
task_temp_images: list,
step_callback,
stream_image_progress: bool,
stream_image_progress_interval: int,
):
context.temp_images.clear()
callback = make_step_callback(req, task_data, data_queue, task_temp_images, step_callback, stream_image_progress, stream_image_progress_interval)
try:
if req.init_image is not None:
req.sampler_name = "ddim"
images = generate_images(context, callback=callback, **req.dict())
user_stopped = False
except UserInitiatedStop:
images = []
user_stopped = True
if context.partial_x_samples is not None:
images = latent_samples_to_images(context, context.partial_x_samples)
finally:
if hasattr(context, "partial_x_samples") and context.partial_x_samples is not None:
del context.partial_x_samples
context.partial_x_samples = None
return images, user_stopped
def filter_images(task_data: TaskData, images: list, user_stopped):
if user_stopped:
return images
filters_to_apply = []
if task_data.block_nsfw:
filters_to_apply.append("nsfw_checker")
if task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower():
filters_to_apply.append("gfpgan")
if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower():
filters_to_apply.append("realesrgan")
if len(filters_to_apply) == 0:
return images
return apply_filters(context, filters_to_apply, images, scale=task_data.upscale_amount)
def construct_response(images: list, seeds: list, task_data: TaskData, base_seed: int):
return [
ResponseImage(
data=img_to_base64_str(img, task_data.output_format, task_data.output_quality),
seed=seed,
)
for img, seed in zip(images, seeds)
]
def make_step_callback(
req: GenerateImageRequest,
task_data: TaskData,
data_queue: queue.Queue,
task_temp_images: list,
step_callback,
stream_image_progress: bool,
stream_image_progress_interval: int,
):
n_steps = req.num_inference_steps if req.init_image is None else int(req.num_inference_steps * req.prompt_strength)
last_callback_time = -1
def update_temp_img(x_samples, task_temp_images: list):
partial_images = []
images = latent_samples_to_images(context, x_samples)
for i, img in enumerate(images):
buf = img_to_buffer(img, output_format="JPEG")
context.temp_images[f"{task_data.request_id}/{i}"] = buf
task_temp_images[i] = buf
partial_images.append({"path": f"/image/tmp/{task_data.request_id}/{i}"})
del images
return partial_images
def on_image_step(x_samples, i):
nonlocal last_callback_time
context.partial_x_samples = x_samples
step_time = time.time() - last_callback_time if last_callback_time != -1 else -1
last_callback_time = time.time()
progress = {"step": i, "step_time": step_time, "total_steps": n_steps}
if stream_image_progress and stream_image_progress_interval > 0 and i % stream_image_progress_interval == 0:
progress["output"] = update_temp_img(x_samples, task_temp_images)
data_queue.put(json.dumps(progress))
step_callback()
if context.stop_processing:
raise UserInitiatedStop("User requested that we stop processing")
return on_image_step

299
ui/easydiffusion/server.py Normal file
View File

@ -0,0 +1,299 @@
"""server.py: FastAPI SD-UI Web Host.
Notes:
async endpoints always run on the main thread. Without they run on the thread pool.
"""
import os
import traceback
import datetime
from typing import List, Union
from fastapi import FastAPI, HTTPException
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse, JSONResponse, StreamingResponse
from pydantic import BaseModel
from easydiffusion import app, model_manager, task_manager
from easydiffusion.types import TaskData, GenerateImageRequest, MergeRequest
from easydiffusion.utils import log
log.info(f"started in {app.SD_DIR}")
log.info(f"started at {datetime.datetime.now():%x %X}")
server_api = FastAPI()
NOCACHE_HEADERS = {"Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0"}
class NoCacheStaticFiles(StaticFiles):
def __init__(self, directory: str):
# follow_symlink is only available on fastapi >= 0.92.0
if (os.path.islink(directory)):
super().__init__(directory = os.path.realpath(directory))
else:
super().__init__(directory = directory)
def is_not_modified(self, response_headers, request_headers) -> bool:
if "content-type" in response_headers and (
"javascript" in response_headers["content-type"] or "css" in response_headers["content-type"]
):
response_headers.update(NOCACHE_HEADERS)
return False
return super().is_not_modified(response_headers, request_headers)
class SetAppConfigRequest(BaseModel):
update_branch: str = None
render_devices: Union[List[str], List[int], str, int] = None
model_vae: str = None
ui_open_browser_on_start: bool = None
listen_to_network: bool = None
listen_port: int = None
def init():
if os.path.isdir(app.CUSTOM_MODIFIERS_DIR):
server_api.mount(
"/media/modifier-thumbnails/custom",
NoCacheStaticFiles(directory=app.CUSTOM_MODIFIERS_DIR),
name="custom-thumbnails",
)
server_api.mount("/media", NoCacheStaticFiles(directory=os.path.join(app.SD_UI_DIR, "media")), name="media")
for plugins_dir, dir_prefix in app.UI_PLUGINS_SOURCES:
server_api.mount(
f"/plugins/{dir_prefix}", NoCacheStaticFiles(directory=plugins_dir), name=f"plugins-{dir_prefix}"
)
@server_api.post("/app_config")
async def set_app_config(req: SetAppConfigRequest):
return set_app_config_internal(req)
@server_api.get("/get/{key:path}")
def read_web_data(key: str = None):
return read_web_data_internal(key)
@server_api.get("/ping") # Get server and optionally session status.
def ping(session_id: str = None):
return ping_internal(session_id)
@server_api.post("/render")
def render(req: dict):
return render_internal(req)
@server_api.post("/model/merge")
def model_merge(req: dict):
print(req)
return model_merge_internal(req)
@server_api.get("/image/stream/{task_id:int}")
def stream(task_id: int):
return stream_internal(task_id)
@server_api.get("/image/stop")
def stop(task: int):
return stop_internal(task)
@server_api.get("/image/tmp/{task_id:int}/{img_id:int}")
def get_image(task_id: int, img_id: int):
return get_image_internal(task_id, img_id)
@server_api.get("/")
def read_root():
return FileResponse(os.path.join(app.SD_UI_DIR, "index.html"), headers=NOCACHE_HEADERS)
@server_api.on_event("shutdown")
def shutdown_event(): # Signal render thread to close on shutdown
task_manager.current_state_error = SystemExit("Application shutting down.")
# API implementations
def set_app_config_internal(req: SetAppConfigRequest):
config = app.getConfig()
if req.update_branch is not None:
config["update_branch"] = req.update_branch
if req.render_devices is not None:
update_render_devices_in_config(config, req.render_devices)
if req.ui_open_browser_on_start is not None:
if "ui" not in config:
config["ui"] = {}
config["ui"]["open_browser_on_start"] = req.ui_open_browser_on_start
if req.listen_to_network is not None:
if "net" not in config:
config["net"] = {}
config["net"]["listen_to_network"] = bool(req.listen_to_network)
if req.listen_port is not None:
if "net" not in config:
config["net"] = {}
config["net"]["listen_port"] = int(req.listen_port)
try:
app.setConfig(config)
if req.render_devices:
app.update_render_threads()
return JSONResponse({"status": "OK"}, headers=NOCACHE_HEADERS)
except Exception as e:
log.error(traceback.format_exc())
raise HTTPException(status_code=500, detail=str(e))
def update_render_devices_in_config(config, render_devices):
if render_devices not in ("cpu", "auto") and not render_devices.startswith("cuda:"):
raise HTTPException(status_code=400, detail=f"Invalid render device requested: {render_devices}")
if render_devices.startswith("cuda:"):
render_devices = render_devices.split(",")
config["render_devices"] = render_devices
def read_web_data_internal(key: str = None):
if not key: # /get without parameters, stable-diffusion easter egg.
raise HTTPException(status_code=418, detail="StableDiffusion is drawing a teapot!") # HTTP418 I'm a teapot
elif key == "app_config":
return JSONResponse(app.getConfig(), headers=NOCACHE_HEADERS)
elif key == "system_info":
config = app.getConfig()
output_dir = config.get("force_save_path", os.path.join(os.path.expanduser("~"), app.OUTPUT_DIRNAME))
system_info = {
"devices": task_manager.get_devices(),
"hosts": app.getIPConfig(),
"default_output_dir": output_dir,
"enforce_output_dir": ("force_save_path" in config),
}
system_info["devices"]["config"] = config.get("render_devices", "auto")
return JSONResponse(system_info, headers=NOCACHE_HEADERS)
elif key == "models":
return JSONResponse(model_manager.getModels(), headers=NOCACHE_HEADERS)
elif key == "modifiers":
return JSONResponse(app.get_image_modifiers(), headers=NOCACHE_HEADERS)
elif key == "ui_plugins":
return JSONResponse(app.getUIPlugins(), headers=NOCACHE_HEADERS)
else:
raise HTTPException(status_code=404, detail=f"Request for unknown {key}") # HTTP404 Not Found
def ping_internal(session_id: str = None):
if task_manager.is_alive() <= 0: # Check that render threads are alive.
if task_manager.current_state_error:
raise HTTPException(status_code=500, detail=str(task_manager.current_state_error))
raise HTTPException(status_code=500, detail="Render thread is dead.")
if task_manager.current_state_error and not isinstance(task_manager.current_state_error, StopAsyncIteration):
raise HTTPException(status_code=500, detail=str(task_manager.current_state_error))
# Alive
response = {"status": str(task_manager.current_state)}
if session_id:
session = task_manager.get_cached_session(session_id, update_ttl=True)
response["tasks"] = {id(t): t.status for t in session.tasks}
response["devices"] = task_manager.get_devices()
return JSONResponse(response, headers=NOCACHE_HEADERS)
def render_internal(req: dict):
try:
# separate out the request data into rendering and task-specific data
render_req: GenerateImageRequest = GenerateImageRequest.parse_obj(req)
task_data: TaskData = TaskData.parse_obj(req)
# Overwrite user specified save path
config = app.getConfig()
if "force_save_path" in config:
task_data.save_to_disk_path = config["force_save_path"]
render_req.init_image_mask = req.get("mask") # hack: will rename this in the HTTP API in a future revision
app.save_to_config(
task_data.use_stable_diffusion_model,
task_data.use_vae_model,
task_data.use_hypernetwork_model,
task_data.vram_usage_level,
)
# enqueue the task
new_task = task_manager.render(render_req, task_data)
response = {
"status": str(task_manager.current_state),
"queue": len(task_manager.tasks_queue),
"stream": f"/image/stream/{id(new_task)}",
"task": id(new_task),
}
return JSONResponse(response, headers=NOCACHE_HEADERS)
except ChildProcessError as e: # Render thread is dead
raise HTTPException(status_code=500, detail=f"Rendering thread has died.") # HTTP500 Internal Server Error
except ConnectionRefusedError as e: # Unstarted task pending limit reached, deny queueing too many.
raise HTTPException(status_code=503, detail=str(e)) # HTTP503 Service Unavailable
except Exception as e:
log.error(traceback.format_exc())
raise HTTPException(status_code=500, detail=str(e))
def model_merge_internal(req: dict):
try:
from sdkit.train import merge_models
from easydiffusion.utils.save_utils import filename_regex
mergeReq: MergeRequest = MergeRequest.parse_obj(req)
merge_models(
model_manager.resolve_model_to_use(mergeReq.model0, "stable-diffusion"),
model_manager.resolve_model_to_use(mergeReq.model1, "stable-diffusion"),
mergeReq.ratio,
os.path.join(app.MODELS_DIR, "stable-diffusion", filename_regex.sub("_", mergeReq.out_path)),
mergeReq.use_fp16,
)
return JSONResponse({"status": "OK"}, headers=NOCACHE_HEADERS)
except Exception as e:
log.error(traceback.format_exc())
raise HTTPException(status_code=500, detail=str(e))
def stream_internal(task_id: int):
# TODO Move to WebSockets ??
task = task_manager.get_cached_task(task_id, update_ttl=True)
if not task:
raise HTTPException(status_code=404, detail=f"Request {task_id} not found.") # HTTP404 NotFound
# if (id(task) != task_id): raise HTTPException(status_code=409, detail=f'Wrong task id received. Expected:{id(task)}, Received:{task_id}') # HTTP409 Conflict
if task.buffer_queue.empty() and not task.lock.locked():
if task.response:
# log.info(f'Session {session_id} sending cached response')
return JSONResponse(task.response, headers=NOCACHE_HEADERS)
raise HTTPException(status_code=425, detail="Too Early, task not started yet.") # HTTP425 Too Early
# log.info(f'Session {session_id} opened live render stream {id(task.buffer_queue)}')
return StreamingResponse(task.read_buffer_generator(), media_type="application/json")
def stop_internal(task: int):
if not task:
if (
task_manager.current_state == task_manager.ServerStates.Online
or task_manager.current_state == task_manager.ServerStates.Unavailable
):
raise HTTPException(status_code=409, detail="Not currently running any tasks.") # HTTP409 Conflict
task_manager.current_state_error = StopAsyncIteration("")
return {"OK"}
task_id = task
task = task_manager.get_cached_task(task_id, update_ttl=False)
if not task:
raise HTTPException(status_code=404, detail=f"Task {task_id} was not found.") # HTTP404 Not Found
if isinstance(task.error, StopAsyncIteration):
raise HTTPException(status_code=409, detail=f"Task {task_id} is already stopped.") # HTTP409 Conflict
task.error = StopAsyncIteration(f"Task {task_id} stop requested.")
return {"OK"}
def get_image_internal(task_id: int, img_id: int):
task = task_manager.get_cached_task(task_id, update_ttl=True)
if not task:
raise HTTPException(status_code=410, detail=f"Task {task_id} could not be found.") # HTTP404 NotFound
if not task.temp_images[img_id]:
raise HTTPException(status_code=425, detail="Too Early, task data is not available yet.") # HTTP425 Too Early
try:
img_data = task.temp_images[img_id]
img_data.seek(0)
return StreamingResponse(img_data, media_type="image/jpeg")
except KeyError as e:
raise HTTPException(status_code=500, detail=str(e))

View File

@ -0,0 +1,565 @@
"""task_manager.py: manage tasks dispatching and render threads.
Notes:
render_threads should be the only hard reference held by the manager to the threads.
Use weak_thread_data to store all other data using weak keys.
This will allow for garbage collection after the thread dies.
"""
import json
import traceback
TASK_TTL = 15 * 60 # seconds, Discard last session's task timeout
import torch
import queue, threading, time, weakref
from typing import Any, Hashable
from easydiffusion import device_manager
from easydiffusion.types import TaskData, GenerateImageRequest
from easydiffusion.utils import log
from sdkit.utils import gc
THREAD_NAME_PREFIX = ""
ERR_LOCK_FAILED = " failed to acquire lock within timeout."
LOCK_TIMEOUT = 15 # Maximum locking time in seconds before failing a task.
# It's better to get an exception than a deadlock... ALWAYS use timeout in critical paths.
DEVICE_START_TIMEOUT = 60 # seconds - Maximum time to wait for a render device to init.
class SymbolClass(type): # Print nicely formatted Symbol names.
def __repr__(self):
return self.__qualname__
def __str__(self):
return self.__name__
class Symbol(metaclass=SymbolClass):
pass
class ServerStates:
class Init(Symbol):
pass
class LoadingModel(Symbol):
pass
class Online(Symbol):
pass
class Rendering(Symbol):
pass
class Unavailable(Symbol):
pass
class RenderTask: # Task with output queue and completion lock.
def __init__(self, req: GenerateImageRequest, task_data: TaskData):
task_data.request_id = id(self)
self.render_request: GenerateImageRequest = req # Initial Request
self.task_data: TaskData = task_data
self.response: Any = None # Copy of the last reponse
self.render_device = None # Select the task affinity. (Not used to change active devices).
self.temp_images: list = [None] * req.num_outputs * (1 if task_data.show_only_filtered_image else 2)
self.error: Exception = None
self.lock: threading.Lock = threading.Lock() # Locks at task start and unlocks when task is completed
self.buffer_queue: queue.Queue = queue.Queue() # Queue of JSON string segments
async def read_buffer_generator(self):
try:
while not self.buffer_queue.empty():
res = self.buffer_queue.get(block=False)
self.buffer_queue.task_done()
yield res
except queue.Empty as e:
yield
@property
def status(self):
if self.lock.locked():
return "running"
if isinstance(self.error, StopAsyncIteration):
return "stopped"
if self.error:
return "error"
if not self.buffer_queue.empty():
return "buffer"
if self.response:
return "completed"
return "pending"
@property
def is_pending(self):
return bool(not self.response and not self.error)
# Temporary cache to allow to query tasks results for a short time after they are completed.
class DataCache:
def __init__(self):
self._base = dict()
self._lock: threading.Lock = threading.Lock()
def _get_ttl_time(self, ttl: int) -> int:
return int(time.time()) + ttl
def _is_expired(self, timestamp: int) -> bool:
return int(time.time()) >= timestamp
def clean(self) -> None:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.clean" + ERR_LOCK_FAILED)
try:
# Create a list of expired keys to delete
to_delete = []
for key in self._base:
ttl, _ = self._base[key]
if self._is_expired(ttl):
to_delete.append(key)
# Remove Items
for key in to_delete:
(_, val) = self._base[key]
if isinstance(val, RenderTask):
log.debug(f"RenderTask {key} expired. Data removed.")
elif isinstance(val, SessionState):
log.debug(f"Session {key} expired. Data removed.")
else:
log.debug(f"Key {key} expired. Data removed.")
del self._base[key]
finally:
self._lock.release()
def clear(self) -> None:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.clear" + ERR_LOCK_FAILED)
try:
self._base.clear()
finally:
self._lock.release()
def delete(self, key: Hashable) -> bool:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.delete" + ERR_LOCK_FAILED)
try:
if key not in self._base:
return False
del self._base[key]
return True
finally:
self._lock.release()
def keep(self, key: Hashable, ttl: int) -> bool:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.keep" + ERR_LOCK_FAILED)
try:
if key in self._base:
_, value = self._base.get(key)
self._base[key] = (self._get_ttl_time(ttl), value)
return True
return False
finally:
self._lock.release()
def put(self, key: Hashable, value: Any, ttl: int) -> bool:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.put" + ERR_LOCK_FAILED)
try:
self._base[key] = (self._get_ttl_time(ttl), value)
except Exception as e:
log.error(traceback.format_exc())
return False
else:
return True
finally:
self._lock.release()
def tryGet(self, key: Hashable) -> Any:
if not self._lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("DataCache.tryGet" + ERR_LOCK_FAILED)
try:
ttl, value = self._base.get(key, (None, None))
if ttl is not None and self._is_expired(ttl):
log.debug(f"Session {key} expired. Discarding data.")
del self._base[key]
return None
return value
finally:
self._lock.release()
manager_lock = threading.RLock()
render_threads = []
current_state = ServerStates.Init
current_state_error: Exception = None
tasks_queue = []
session_cache = DataCache()
task_cache = DataCache()
weak_thread_data = weakref.WeakKeyDictionary()
idle_event: threading.Event = threading.Event()
class SessionState:
def __init__(self, id: str):
self._id = id
self._tasks_ids = []
@property
def id(self):
return self._id
@property
def tasks(self):
tasks = []
for task_id in self._tasks_ids:
task = task_cache.tryGet(task_id)
if task:
tasks.append(task)
return tasks
def put(self, task, ttl=TASK_TTL):
task_id = id(task)
self._tasks_ids.append(task_id)
if not task_cache.put(task_id, task, ttl):
return False
while len(self._tasks_ids) > len(render_threads) * 2:
self._tasks_ids.pop(0)
return True
def thread_get_next_task():
from easydiffusion import renderer
if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
log.warn(f"Render thread on device: {renderer.context.device} failed to acquire manager lock.")
return None
if len(tasks_queue) <= 0:
manager_lock.release()
return None
task = None
try: # Select a render task.
for queued_task in tasks_queue:
if queued_task.render_device and renderer.context.device != queued_task.render_device:
# Is asking for a specific render device.
if is_alive(queued_task.render_device) > 0:
continue # requested device alive, skip current one.
else:
# Requested device is not active, return error to UI.
queued_task.error = Exception(queued_task.render_device + " is not currently active.")
task = queued_task
break
if not queued_task.render_device and renderer.context.device == "cpu" and is_alive() > 1:
# not asking for any specific devices, cpu want to grab task but other render devices are alive.
continue # Skip Tasks, don't run on CPU unless there is nothing else or user asked for it.
task = queued_task
break
if task is not None:
del tasks_queue[tasks_queue.index(task)]
return task
finally:
manager_lock.release()
def thread_render(device):
global current_state, current_state_error
from easydiffusion import renderer, model_manager
try:
renderer.init(device)
weak_thread_data[threading.current_thread()] = {
"device": renderer.context.device,
"device_name": renderer.context.device_name,
"alive": True,
}
current_state = ServerStates.LoadingModel
model_manager.load_default_models(renderer.context)
current_state = ServerStates.Online
except Exception as e:
log.error(traceback.format_exc())
weak_thread_data[threading.current_thread()] = {"error": e, "alive": False}
return
while True:
session_cache.clean()
task_cache.clean()
if not weak_thread_data[threading.current_thread()]["alive"]:
log.info(f"Shutting down thread for device {renderer.context.device}")
model_manager.unload_all(renderer.context)
return
if isinstance(current_state_error, SystemExit):
current_state = ServerStates.Unavailable
return
task = thread_get_next_task()
if task is None:
idle_event.clear()
idle_event.wait(timeout=1)
continue
if task.error is not None:
log.error(task.error)
task.response = {"status": "failed", "detail": str(task.error)}
task.buffer_queue.put(json.dumps(task.response))
continue
if current_state_error:
task.error = current_state_error
task.response = {"status": "failed", "detail": str(task.error)}
task.buffer_queue.put(json.dumps(task.response))
continue
log.info(f"Session {task.task_data.session_id} starting task {id(task)} on {renderer.context.device_name}")
if not task.lock.acquire(blocking=False):
raise Exception("Got locked task from queue.")
try:
def step_callback():
global current_state_error
if (
isinstance(current_state_error, SystemExit)
or isinstance(current_state_error, StopAsyncIteration)
or isinstance(task.error, StopAsyncIteration)
):
renderer.context.stop_processing = True
if isinstance(current_state_error, StopAsyncIteration):
task.error = current_state_error
current_state_error = None
log.info(f"Session {task.task_data.session_id} sent cancel signal for task {id(task)}")
current_state = ServerStates.LoadingModel
model_manager.resolve_model_paths(task.task_data)
model_manager.reload_models_if_necessary(renderer.context, task.task_data)
current_state = ServerStates.Rendering
task.response = renderer.make_images(
task.render_request, task.task_data, task.buffer_queue, task.temp_images, step_callback
)
# Before looping back to the generator, mark cache as still alive.
task_cache.keep(id(task), TASK_TTL)
session_cache.keep(task.task_data.session_id, TASK_TTL)
except Exception as e:
task.error = str(e)
task.response = {"status": "failed", "detail": str(task.error)}
task.buffer_queue.put(json.dumps(task.response))
log.error(traceback.format_exc())
finally:
gc(renderer.context)
task.lock.release()
task_cache.keep(id(task), TASK_TTL)
session_cache.keep(task.task_data.session_id, TASK_TTL)
if isinstance(task.error, StopAsyncIteration):
log.info(f"Session {task.task_data.session_id} task {id(task)} cancelled!")
elif task.error is not None:
log.info(f"Session {task.task_data.session_id} task {id(task)} failed!")
else:
log.info(
f"Session {task.task_data.session_id} task {id(task)} completed by {renderer.context.device_name}."
)
current_state = ServerStates.Online
def get_cached_task(task_id: str, update_ttl: bool = False):
# By calling keep before tryGet, wont discard if was expired.
if update_ttl and not task_cache.keep(task_id, TASK_TTL):
# Failed to keep task, already gone.
return None
return task_cache.tryGet(task_id)
def get_cached_session(session_id: str, update_ttl: bool = False):
if update_ttl:
session_cache.keep(session_id, TASK_TTL)
session = session_cache.tryGet(session_id)
if not session:
session = SessionState(session_id)
session_cache.put(session_id, session, TASK_TTL)
return session
def get_devices():
devices = {
"all": {},
"active": {},
}
def get_device_info(device):
if device in ("cpu", "mps"):
return {"name": device_manager.get_processor_name()}
mem_free, mem_total = torch.cuda.mem_get_info(device)
mem_free /= float(10**9)
mem_total /= float(10**9)
return {
"name": torch.cuda.get_device_name(device),
"mem_free": mem_free,
"mem_total": mem_total,
"max_vram_usage_level": device_manager.get_max_vram_usage_level(device),
}
# list the compatible devices
cuda_count = torch.cuda.device_count()
for device in range(cuda_count):
device = f"cuda:{device}"
if not device_manager.is_device_compatible(device):
continue
devices["all"].update({device: get_device_info(device)})
if device_manager.is_mps_available():
devices["all"].update({"mps": get_device_info("mps")})
devices["all"].update({"cpu": get_device_info("cpu")})
# list the activated devices
if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("get_devices" + ERR_LOCK_FAILED)
try:
for rthread in render_threads:
if not rthread.is_alive():
continue
weak_data = weak_thread_data.get(rthread)
if not weak_data or not "device" in weak_data or not "device_name" in weak_data:
continue
device = weak_data["device"]
devices["active"].update({device: get_device_info(device)})
finally:
manager_lock.release()
return devices
def is_alive(device=None):
if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("is_alive" + ERR_LOCK_FAILED)
nbr_alive = 0
try:
for rthread in render_threads:
if device is not None:
weak_data = weak_thread_data.get(rthread)
if weak_data is None or not "device" in weak_data or weak_data["device"] is None:
continue
thread_device = weak_data["device"]
if thread_device != device:
continue
if rthread.is_alive():
nbr_alive += 1
return nbr_alive
finally:
manager_lock.release()
def start_render_thread(device):
if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("start_render_thread" + ERR_LOCK_FAILED)
log.info(f"Start new Rendering Thread on device: {device}")
try:
rthread = threading.Thread(target=thread_render, kwargs={"device": device})
rthread.daemon = True
rthread.name = THREAD_NAME_PREFIX + device
rthread.start()
render_threads.append(rthread)
finally:
manager_lock.release()
timeout = DEVICE_START_TIMEOUT
while not rthread.is_alive() or not rthread in weak_thread_data or not "device" in weak_thread_data[rthread]:
if rthread in weak_thread_data and "error" in weak_thread_data[rthread]:
log.error(f"{rthread}, {device}, error: {weak_thread_data[rthread]['error']}")
return False
if timeout <= 0:
return False
timeout -= 1
time.sleep(1)
return True
def stop_render_thread(device):
try:
device_manager.validate_device_id(device, log_prefix="stop_render_thread")
except:
log.error(traceback.format_exc())
return False
if not manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT):
raise Exception("stop_render_thread" + ERR_LOCK_FAILED)
log.info(f"Stopping Rendering Thread on device: {device}")
try:
thread_to_remove = None
for rthread in render_threads:
weak_data = weak_thread_data.get(rthread)
if weak_data is None or not "device" in weak_data or weak_data["device"] is None:
continue
thread_device = weak_data["device"]
if thread_device == device:
weak_data["alive"] = False
thread_to_remove = rthread
break
if thread_to_remove is not None:
render_threads.remove(rthread)
return True
finally:
manager_lock.release()
return False
def update_render_threads(render_devices, active_devices):
devices_to_start, devices_to_stop = device_manager.get_device_delta(render_devices, active_devices)
log.debug(f"devices_to_start: {devices_to_start}")
log.debug(f"devices_to_stop: {devices_to_stop}")
for device in devices_to_stop:
if is_alive(device) <= 0:
log.debug(f"{device} is not alive")
continue
if not stop_render_thread(device):
log.warn(f"{device} could not stop render thread")
for device in devices_to_start:
if is_alive(device) >= 1:
log.debug(f"{device} already registered.")
continue
if not start_render_thread(device):
log.warn(f"{device} failed to start.")
if is_alive() <= 0: # No running devices, probably invalid user config.
raise EnvironmentError(
'ERROR: No active render devices! Please verify the "render_devices" value in config.json'
)
log.debug(f"active devices: {get_devices()['active']}")
def shutdown_event(): # Signal render thread to close on shutdown
global current_state_error
current_state_error = SystemExit("Application shutting down.")
def render(render_req: GenerateImageRequest, task_data: TaskData):
current_thread_count = is_alive()
if current_thread_count <= 0: # Render thread is dead
raise ChildProcessError("Rendering thread has died.")
# Alive, check if task in cache
session = get_cached_session(task_data.session_id, update_ttl=True)
pending_tasks = list(filter(lambda t: t.is_pending, session.tasks))
if current_thread_count < len(pending_tasks):
raise ConnectionRefusedError(
f"Session {task_data.session_id} already has {len(pending_tasks)} pending tasks out of {current_thread_count}."
)
new_task = RenderTask(render_req, task_data)
if session.put(new_task, TASK_TTL):
# Use twice the normal timeout for adding user requests.
# Tries to force session.put to fail before tasks_queue.put would.
if manager_lock.acquire(blocking=True, timeout=LOCK_TIMEOUT * 2):
try:
tasks_queue.append(new_task)
idle_event.set()
return new_task
finally:
manager_lock.release()
raise RuntimeError("Failed to add task to cache.")

103
ui/easydiffusion/types.py Normal file
View File

@ -0,0 +1,103 @@
from pydantic import BaseModel
from typing import Any
class GenerateImageRequest(BaseModel):
prompt: str = ""
negative_prompt: str = ""
seed: int = 42
width: int = 512
height: int = 512
num_outputs: int = 1
num_inference_steps: int = 50
guidance_scale: float = 7.5
init_image: Any = None
init_image_mask: Any = None
prompt_strength: float = 0.8
preserve_init_image_color_profile = False
sampler_name: str = None # "ddim", "plms", "heun", "euler", "euler_a", "dpm2", "dpm2_a", "lms"
hypernetwork_strength: float = 0
class TaskData(BaseModel):
request_id: str = None
session_id: str = "session"
save_to_disk_path: str = None
vram_usage_level: str = "balanced" # or "low" or "medium"
use_face_correction: str = None # or "GFPGANv1.3"
use_upscale: str = None # or "RealESRGAN_x4plus" or "RealESRGAN_x4plus_anime_6B"
upscale_amount: int = 4 # or 2
use_stable_diffusion_model: str = "sd-v1-4"
# use_stable_diffusion_config: str = "v1-inference"
use_vae_model: str = None
use_hypernetwork_model: str = None
show_only_filtered_image: bool = False
block_nsfw: bool = False
output_format: str = "jpeg" # or "png" or "webp"
output_quality: int = 75
metadata_output_format: str = "txt" # or "json"
stream_image_progress: bool = False
stream_image_progress_interval: int = 5
class MergeRequest(BaseModel):
model0: str = None
model1: str = None
ratio: float = None
out_path: str = "mix"
use_fp16 = True
class Image:
data: str # base64
seed: int
is_nsfw: bool
path_abs: str = None
def __init__(self, data, seed):
self.data = data
self.seed = seed
def json(self):
return {
"data": self.data,
"seed": self.seed,
"path_abs": self.path_abs,
}
class Response:
render_request: GenerateImageRequest
task_data: TaskData
images: list
def __init__(self, render_request: GenerateImageRequest, task_data: TaskData, images: list):
self.render_request = render_request
self.task_data = task_data
self.images = images
def json(self):
del self.render_request.init_image
del self.render_request.init_image_mask
res = {
"status": "succeeded",
"render_request": self.render_request.dict(),
"task_data": self.task_data.dict(),
"output": [],
}
for image in self.images:
res["output"].append(image.json())
return res
class UserInitiatedStop(Exception):
pass

View File

@ -0,0 +1,8 @@
import logging
log = logging.getLogger("easydiffusion")
from .save_utils import (
save_images_to_disk,
get_printable_request,
)

View File

@ -0,0 +1,132 @@
import os
import time
import base64
import re
from easydiffusion.types import TaskData, GenerateImageRequest
from sdkit.utils import save_images, save_dicts
filename_regex = re.compile("[^a-zA-Z0-9._-]")
# keep in sync with `ui/media/js/dnd.js`
TASK_TEXT_MAPPING = {
"prompt": "Prompt",
"width": "Width",
"height": "Height",
"seed": "Seed",
"num_inference_steps": "Steps",
"guidance_scale": "Guidance Scale",
"prompt_strength": "Prompt Strength",
"use_face_correction": "Use Face Correction",
"use_upscale": "Use Upscaling",
"upscale_amount": "Upscale By",
"sampler_name": "Sampler",
"negative_prompt": "Negative Prompt",
"use_stable_diffusion_model": "Stable Diffusion model",
"use_vae_model": "VAE model",
"use_hypernetwork_model": "Hypernetwork model",
"hypernetwork_strength": "Hypernetwork Strength",
}
def save_images_to_disk(images: list, filtered_images: list, req: GenerateImageRequest, task_data: TaskData):
now = time.time()
save_dir_path = os.path.join(task_data.save_to_disk_path, filename_regex.sub("_", task_data.session_id))
metadata_entries = get_metadata_entries_for_request(req, task_data)
make_filename = make_filename_callback(req, now=now)
if task_data.show_only_filtered_image or filtered_images is images:
save_images(
filtered_images,
save_dir_path,
file_name=make_filename,
output_format=task_data.output_format,
output_quality=task_data.output_quality,
)
if task_data.metadata_output_format.lower() in ["json", "txt", "embed"]:
save_dicts(
metadata_entries,
save_dir_path,
file_name=make_filename,
output_format=task_data.metadata_output_format,
file_format=task_data.output_format,
)
else:
make_filter_filename = make_filename_callback(req, now=now, suffix="filtered")
save_images(
images,
save_dir_path,
file_name=make_filename,
output_format=task_data.output_format,
output_quality=task_data.output_quality,
)
save_images(
filtered_images,
save_dir_path,
file_name=make_filter_filename,
output_format=task_data.output_format,
output_quality=task_data.output_quality,
)
if task_data.metadata_output_format.lower() in ["json", "txt", "embed"]:
save_dicts(
metadata_entries,
save_dir_path,
file_name=make_filter_filename,
output_format=task_data.metadata_output_format,
file_format=task_data.output_format,
)
def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskData):
metadata = get_printable_request(req)
metadata.update(
{
"use_stable_diffusion_model": task_data.use_stable_diffusion_model,
"use_vae_model": task_data.use_vae_model,
"use_hypernetwork_model": task_data.use_hypernetwork_model,
"use_face_correction": task_data.use_face_correction,
"use_upscale": task_data.use_upscale,
}
)
if metadata["use_upscale"] is not None:
metadata["upscale_amount"] = task_data.upscale_amount
if task_data.use_hypernetwork_model is None:
del metadata["hypernetwork_strength"]
# if text, format it in the text format expected by the UI
is_txt_format = task_data.metadata_output_format.lower() == "txt"
if is_txt_format:
metadata = {TASK_TEXT_MAPPING[key]: val for key, val in metadata.items() if key in TASK_TEXT_MAPPING}
entries = [metadata.copy() for _ in range(req.num_outputs)]
for i, entry in enumerate(entries):
entry["Seed" if is_txt_format else "seed"] = req.seed + i
return entries
def get_printable_request(req: GenerateImageRequest):
metadata = req.dict()
del metadata["init_image"]
del metadata["init_image_mask"]
if req.init_image is None:
del metadata["prompt_strength"]
return metadata
def make_filename_callback(req: GenerateImageRequest, suffix=None, now=None):
if now is None:
now = time.time()
def make_filename(i):
img_id = base64.b64encode(int(now + i).to_bytes(8, "big")).decode() # Generate unique ID based on time.
img_id = img_id.translate({43: None, 47: None, 61: None})[-8:] # Remove + / = and keep last 8 chars.
prompt_flattened = filename_regex.sub("_", req.prompt)[:50]
name = f"{prompt_flattened}_{img_id}"
name = name if suffix is None else f"{name}_{suffix}"
return name
return make_filename

View File

@ -1,107 +1,170 @@
<!DOCTYPE html>
<html>
<head>
<title>Easy Diffusion</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="/media/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/media/favicon-32x32.png" sizes="32x32">
<link rel="stylesheet" href="/media/main.css?v=10">
<link rel="stylesheet" href="/media/modifier-thumbnails.css?v=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
<link rel="stylesheet" href="/media/drawingboard.min.css">
<script src="/media/jquery-3.6.1.min.js"></script>
<script src="/media/drawingboard.min.js"></script>
<meta name="theme-color" content="#673AB6">
<link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32">
<link rel="stylesheet" href="/media/css/jquery-confirm.min.css">
<link rel="stylesheet" href="/media/css/fonts.css">
<link rel="stylesheet" href="/media/css/themes.css">
<link rel="stylesheet" href="/media/css/main.css">
<link rel="stylesheet" href="/media/css/auto-save.css">
<link rel="stylesheet" href="/media/css/modifier-thumbnails.css">
<link rel="stylesheet" href="/media/css/fontawesome-all.min.css">
<link rel="stylesheet" href="/media/css/image-editor.css">
<link rel="stylesheet" href="/media/css/searchable-models.css">
<link rel="manifest" href="/media/manifest.webmanifest">
<script src="/media/js/jquery-3.6.1.min.js"></script>
<script src="/media/js/jquery-confirm.min.js"></script>
<script src="/media/js/marked.min.js"></script>
</head>
<body>
<div id="container">
<div id="top-nav">
<div id="logo">
<h1>Stable Diffusion UI <small>v2.195 <span id="updateBranchLabel"></span></small></h1>
<h1>
<img id="logo_img" src="/media/images/icon-512x512.png" >
Easy Diffusion
<small>v2.5.24 <span id="updateBranchLabel"></span></small>
</h1>
</div>
<ul id="top-nav-items">
<li class="dropdown">
<span><i class="fa fa-comments icon"></i> Help & Community</span>
<ul id="community-links" class="dropdown-content">
<li><a href="https://github.com/cmdr2/stable-diffusion-ui/blob/main/Troubleshooting.md" target="_blank"><i class="fa-solid fa-circle-question fa-fw"></i> Usual problems and solutions</a></li>
<li><a href="https://discord.com/invite/u9yhsFmEkB" target="_blank"><i class="fa-brands fa-discord fa-fw"></i> Discord user community</a></li>
<li><a href="https://www.reddit.com/r/StableDiffusionUI/" target="_blank"><i class="fa-brands fa-reddit fa-fw"></i> Reddit community</a></li>
<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>
</ul>
</li>
<li class="dropdown">
<div id="server-status">
<div id="server-status-color"></div>
<span id="server-status-msg">Stable Diffusion is starting..</span>
</div>
<div id="tab-container" class="tab-container">
<span id="tab-main" class="tab active">
<span><i class="fa fa-image icon"></i> Generate</span>
</span>
<span id="tab-settings" class="tab">
<span><i class="fa fa-gear icon"></i> Settings</span>
<div id="system-settings" class="panel-box settings-box dropdown-content">
<ul id="system-settings-entries">
<li><b class="settings-subheader">System Settings</b></li>
<br/>
<li><input id="save_to_disk" name="save_to_disk" type="checkbox"> <label for="save_to_disk">Automatically save to <input id="diskPath" name="diskPath" size="40" disabled></label></li>
<li><input id="sound_toggle" name="sound_toggle" type="checkbox" checked> <label for="sound_toggle">Play sound on task completion</label></li>
<li><input id="turbo" name="turbo" type="checkbox" checked> <label for="turbo">Turbo mode <small>(generates images faster, but uses an additional 1 GB of GPU memory)</small></label></li>
<li><input id="use_cpu" name="use_cpu" type="checkbox"> <label for="use_cpu">Use CPU instead of GPU <small>(warning: this will be *very* slow)</small></label></li>
<li><input id="use_full_precision" name="use_full_precision" type="checkbox"> <label for="use_full_precision">Use full precision <small>(for GPU-only. warning: this will consume more VRAM)</small></label></li>
<!-- <li><input id="allow_nsfw" name="allow_nsfw" type="checkbox"> <label for="allow_nsfw">Allow NSFW Content (You confirm you are above 18 years of age)</label></li> -->
<br/>
<li><input id="use_beta_channel" name="use_beta_channel" type="checkbox"> <label for="use_beta_channel">🔥Beta channel. Get the latest features immediately (but could be less stable). Please restart the program after changing this.</label></li>
</ul>
</div>
</li>
</ul>
</span>
<span id="tab-about" class="tab">
<span><i class="fa fa-comments icon"></i> Help & Community</span>
</span>
</div>
</div>
<div class="flex-container">
<div id="editor" class="col-fixed-10">
<div id="server-status">
<div id="server-status-color"></div>
<span id="server-status-msg">Stable Diffusion is starting..</span>
</div>
<div id="tab-content-wrapper">
<div id="tab-content-main" class="tab-content active flex-container">
<div id="editor">
<div id="editor-inputs">
<div id="editor-inputs-prompt" class="row">
<label for="prompt">Prompt</label>
<label for="prompt"><b>Enter Prompt</b></label> <small>or</small> <button id="promptsFromFileBtn" class="tertiaryButton">Load from a file</button>
<textarea id="prompt" class="col-free">a photograph of an astronaut riding a horse</textarea>
</div>
<div id="editor-inputs-init-image" class="row">
<label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /><br/>
<div id="init_image_preview_container" class="image_preview_container">
<img id="init_image_preview" src="" width="100" height="100" />
<button class="init_image_clear image_clear_btn">X</button>
<br/>
<input id="enable_mask" name="enable_mask" type="checkbox"> <label for="enable_mask">In-Painting (beta) <small>(select the area which the AI will paint into)</small></label>
<div id="inpaintingEditor"></div>
<input id="prompt_from_file" name="prompt_from_file" type="file" /> <!-- hidden -->
<label for="negative_prompt" class="collapsible" id="negative_prompt_handle">
Negative Prompt
<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>
<small>(optional)</small>
</label>
<div class="collapsible-content">
<textarea id="negative_prompt" name="negative_prompt" placeholder="list the things to remove from the image (e.g. fog, green)"></textarea>
</div>
</div>
<div id="editor-inputs-init-image" class="row">
<label for="init_image">Initial Image (img2img) <small>(optional)</small> </label>
<div id="init_image_preview_container" class="image_preview_container">
<div id="init_image_wrapper">
<img id="init_image_preview" src="" />
<span id="init_image_size_box" class="img_bottom_label"></span>
<button class="init_image_clear image_clear_btn"><i class="fa-solid fa-xmark"></i></button>
</div>
<div id="init_image_buttons">
<div class="button">
<i class="fa-regular fa-folder-open"></i>
Browse
<input id="init_image" name="init_image" type="file" />
</div>
<div id="init_image_button_draw" class="button">
<i class="fa-solid fa-pencil"></i>
Draw
</div>
<div id="inpaint_button_container">
<div id="init_image_button_inpaint" class="button">
<i class="fa-solid fa-paintbrush"></i>
Inpaint
</div>
<input id="enable_mask" name="enable_mask" type="checkbox">
</div>
</div>
</div>
<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>
</div>
<div id="editor-inputs-tags-container" class="row">
<label>Image Modifiers: <small>(click an Image Modifier to remove it)</small></label>
<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>
<div id="editor-inputs-tags-list"></div>
</div>
<button id="makeImage">Make Image</button>
<button id="stopImage" class="secondaryButton">Stop All</button>
<button id="makeImage" class="primaryButton">Make Image</button>
<div id="render-buttons">
<button id="stopImage" class="secondaryButton">Stop All</button>
<button id="pause"><i class="fa-solid fa-pause"></i> Pause All</button>
<button id="resume"><i class="fa-solid fa-play"></i> Resume</button>
</div>
</div>
<div class="line-separator">&nbsp;</div>
<span class="line-separator"></span>
<div id="editor-settings" class="panel-box settings-box">
<h4 class="collapsible">Image Settings</h4>
<ul id="editor-settings-entries" class="collapsible-content">
<li><b class="settings-subheader">Image Settings</b></li>
<li class="pl-5"><label for="seed">Seed:</label> <input id="seed" name="seed" size="10" value="30000"> <input id="random_seed" name="random_seed" type="checkbox" checked> <label for="random_seed">Random Image</label></li>
<li class="pl-5"><label for="num_outputs_total">Number of images to make:</label> <input id="num_outputs_total" name="num_outputs_total" value="1" size="1"> <label for="num_outputs_parallel">Generate in parallel:</label> <input id="num_outputs_parallel" name="num_outputs_parallel" value="1" size="1"> (images at once)</li>
<li id="samplerSelection" class="pl-5"><label for="sampler">Sampler:</label>
<select id="sampler" name="sampler">
<option value="plms" selected>plms</option>
<option value="ddim">ddim</option>
<option value="heun">heun</option>
<option value="euler">euler</option>
<option value="euler_a">euler_a</option>
<option value="dpm2">dpm2</option>
<option value="dpm2_a">dpm2_a</option>
<option value="lms">lms</option>
<div id="editor-settings" class="settings-box panel-box">
<h4 class="collapsible">
Image Settings
<i id="reset-image-settings" class="fa-solid fa-arrow-rotate-left section-button">
<span class="simple-tooltip top-left">
Reset Image Settings
</span>
</i>
</h4>
<div id="editor-settings-entries" class="collapsible-content">
<div><table>
<tr><b class="settings-subheader">Image Settings</b></tr>
<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>
<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>
<tr class="pl-5"><td><label for="stable_diffusion_model">Model:</label></td><td class="model-input">
<input id="stable_diffusion_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
<button id="reload-models" class="secondaryButton reloadModels"><i class='fa-solid fa-rotate'></i></button>
<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>
</td></tr>
<!-- <tr id="modelConfigSelection" class="pl-5"><td><label for="model_config">Model Config:</i></label></td><td>
<select id="model_config" name="model_config">
</select>
</li>
<li class="pl-5"><label>Image Size: </label>
</td></tr> -->
<tr class="pl-5"><td><label for="vae_model">Custom VAE:</i></label></td><td>
<input id="vae_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
<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>
</td></tr>
<tr id="samplerSelection" class="pl-5"><td><label for="sampler_name">Sampler:</label></td><td>
<select id="sampler_name" name="sampler_name">
<option value="plms">PLMS</option>
<option value="ddim">DDIM</option>
<option value="heun">Heun</option>
<option value="euler">Euler</option>
<option value="euler_a" selected>Euler Ancestral</option>
<option value="dpm2">DPM2</option>
<option value="dpm2_a">DPM2 Ancestral</option>
<option value="lms">LMS</option>
<option value="dpm_solver_stability">DPM Solver (Stability AI)</option>
<option value="dpmpp_2s_a">DPM++ 2s Ancestral</option>
<option value="dpmpp_2m">DPM++ 2m</option>
<option value="dpmpp_sde">DPM++ SDE</option>
<option value="dpm_fast">DPM Fast</option>
<option value="dpm_adaptive">DPM Adaptive</option>
<option value="unipc_snr">UniPC SNR</option>
<option value="unipc_tu">UniPC TU</option>
<option value="unipc_snr_2">UniPC SNR 2</option>
<option value="unipc_tu_2">UniPC TC 2</option>
<option value="unipc_tq">UniPC TQ</option>
</select>
<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>
</td></tr>
<tr class="pl-5"><td><label>Image Size: </label></td><td>
<select id="width" name="width" value="512">
<option value="128">128 (*)</option>
<option value="192">192</option>
@ -146,63 +209,235 @@
<option value="2048">2048</option>
</select>
<label for="height"><small>(height)</small></label>
</li>
<li class="pl-5"><label for="num_inference_steps">Number of inference steps:</label> <input id="num_inference_steps" name="num_inference_steps" size="4" value="50"></li>
<li class="pl-5"><label for="guidance_scale_slider">Guidance Scale:</label> <input id="guidance_scale_slider" name="guidance_scale_slider" class="editor-slider" value="75" type="range" min="10" max="500"> <input id="guidance_scale" name="guidance_scale" size="4"></li>
<li class="pl-5"><span id="prompt_strength_container"><label for="prompt_strength_slider">Prompt Strength:</label> <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"><br/></span></li>
<br/>
<li><b class="settings-subheader">Prompt Settings</b></li>
<li class="pl-5"><label for="negative_prompt">Negative Prompt:</label> <input id="negative_prompt" name="negative_prompt" size="55"></li>
<br/>
</td></tr>
<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>
<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>
<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>
<tr class="pl-5"><td><label for="hypernetwork_model">Hypernetwork:</i></label></td><td>
<input id="hypernetwork_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
</td></tr>
<tr id="hypernetwork_strength_container" class="pl-5">
<td><label for="hypernetwork_strength_slider">Hypernetwork Strength:</label></td>
<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>
</tr>
<tr class="pl-5"><td><label for="output_format">Output Format:</label></td><td>
<select id="output_format" name="output_format">
<option value="jpeg" selected>jpeg</option>
<option value="png">png</option>
<option value="webp">webp</option>
</select>
</td></tr>
<tr class="pl-5" id="output_quality_row"><td><label for="output_quality">Image Quality:</label></td><td>
<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)">
</td></tr>
</table></div>
<div><ul>
<li><b class="settings-subheader">Render Settings</b></li>
<li class="pl-5"><input id="stream_image_progress" name="stream_image_progress" type="checkbox"> <label for="stream_image_progress">Show a live preview of the image <small>(uses more VRAM, slightly slower image creation)</small></label></li>
<li class="pl-5"><input id="use_face_correction" name="use_face_correction" type="checkbox" checked> <label for="use_face_correction">Fix incorrect faces and eyes <small>(uses GFPGAN)</small></label></li>
<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>
<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>
<li class="pl-5">
<input id="use_upscale" name="use_upscale" type="checkbox"> <label for="use_upscale">Upscale the image to 4x resolution using </label>
<input id="use_upscale" name="use_upscale" type="checkbox"> <label for="use_upscale">Scale up by</label>
<select id="upscale_amount" name="upscale_amount">
<option value="2">2x</option>
<option value="4" selected>4x</option>
</select>
with
<select id="upscale_model" name="upscale_model">
<option value="RealESRGAN_x4plus" selected>RealESRGAN_x4plus</option>
<option value="RealESRGAN_x4plus_anime_6B">RealESRGAN_x4plus_anime_6B</option>
</select>
</li>
<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>
<br/>
<li><small>The system-related settings have been moved to the top-right corner.</small></li>
</ul>
</ul></div>
</div>
</div>
<div id="editor-modifiers" class="panel-box">
<h4 class="collapsible">Image Modifiers (art styles, tags etc)</h4>
<h4 class="collapsible">
Image Modifiers (art styles, tags etc)
<i id="modifier-settings-btn" class="fa-solid fa-gear section-button">
<span class="simple-tooltip left">
Add Custom Modifiers
</span>
</i>
</h4>
<div id="editor-modifiers-entries" class="collapsible-content">
<label for="preview-image">Image Style:</label>
<select id="preview-image" name="preview-image" value="portrait">
<option value="portrait" selected="">Face</option>
<option value="landscape">Landscape</option>
</select>
&nbsp;
<label for="modifier-card-size-slider">Thumbnail Size:</label>
<input id="modifier-card-size-slider" name="modifier-card-size-slider" value="0" type="range" min="-3" max="5">
<div id="editor-modifiers-entries-toolbar">
<label for="preview-image">Image Style:</label>
<select id="preview-image" name="preview-image" value="portrait">
<option value="portrait" selected="">Face</option>
<option value="landscape">Landscape</option>
</select>
&nbsp;
<label for="modifier-card-size-slider">Thumbnail Size:</label>
<input id="modifier-card-size-slider" name="modifier-card-size-slider" value="0" type="range" min="-3" max="5">
</div>
</div>
</div>
</div>
<div id="preview" class="col-free">
<div id="initial-text">
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/>You can also add modifiers like "Realistic", "Pencil Sketch", "ArtStation" etc by browsing through the "Image Modifiers" section and selecting the desired modifiers.<br/><br/>Click "Advanced Settings" for additional settings like seed, image size, number of images to generate etc.<br/><br/>Enjoy! :)
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/>
You can also add modifiers like "Realistic", "Pencil Sketch", "ArtStation" etc by browsing through the "Image Modifiers" section
and selecting the desired modifiers.<br/><br/>
Click "Image Settings" for additional settings like seed, image size, number of images to generate etc.<br/><br/>Enjoy! :)
</div>
<div id="preview-tools">
<button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can"></i> Clear All</button>
<div id="preview-content">
<div id="preview-tools">
<button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can icon"></i> Clear All</button>
<button id="save-all-images" class="tertiaryButton"><i class="fa-solid fa-download icon"></i> Download All Images</button>
<div class="display-settings">
<span class="auto-scroll"></span> <!-- hack for Rabbit Hole update -->
<button id="auto_scroll_btn" class="tertiaryButton">
<i class="fa-solid fa-arrows-up-to-line icon"></i>
<input id="auto_scroll" name="auto_scroll" type="checkbox" style="display: none">
<span class="simple-tooltip left">
Scroll to generated image (<span class="state">OFF</span>)
</span>
</button>
<button class="dropdown tertiaryButton">
<i class="fa-solid fa-magnifying-glass-plus icon dropbtn"></i>
<span class="simple-tooltip left">
Image Size
</span>
</button>
<div class="dropdown-content">
<div class="dropdown-item">
<input id="thumbnail_size" name="thumbnail_size" class="editor-slider" type="range" value="70" min="5" max="200" oninput="sliderUpdate(event)">
<input id="thumbnail_size-input" name="thumbnail_size-input" size="3" value="70" pattern="^[0-9.]+$" onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)">&nbsp;%
</div>
</div>
</div>
<div class="clearfix" style="clear: both;"></div>
</div>
</div>
</div>
</div>
<div id="tab-content-settings" class="tab-content">
<div id="system-settings" class="tab-content-inner">
<h1>System Settings</h1>
<div class="parameters-table"></div>
<br/>
<button id="save-system-settings-btn" class="primaryButton">Save</button>
<br/><br/>
<div>
<h3><i class="fa fa-microchip icon"></i> System Info</h3>
<div id="system-info">
<table>
<tr><td><label>Processor:</label></td><td id="system-info-cpu" class="value"></td></tr>
<tr><td><label>Compatible Graphics Cards (all):</label></td><td id="system-info-gpus-all" class="value"></td></tr>
<tr><td></td><td>&nbsp;</td></tr>
<tr><td><label>Used for rendering 🔥:</label></td><td id="system-info-rendering-devices" class="value"></td></tr>
<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>
</table>
</div>
</div>
</div>
</div>
<div id="tab-content-about" class="tab-content">
<div class="tab-content-inner">
<div class="float-container">
<div class="float-child">
<h1>Help</h1>
<ul id="help-links">
<li><span class="help-section">Using the software</span>
<ul>
<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>
<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>
<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>
<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>
<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>
</ul>
<li><span class="help-section">Installation</span>
<ul>
<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>
</ul>
<li><span class="help-section">Downloadable Content</span>
<ul>
<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>
<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>
<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>
</ul>
</ul>
</div>
<div class="float-child">
<h1>Community</h1>
<ul id="community-links">
<li><a href="https://discord.com/invite/u9yhsFmEkB" target="_blank"><i class="fa-brands fa-discord fa-fw"></i> Discord user community</a></li>
<li><a href="https://www.reddit.com/r/StableDiffusionUI/" target="_blank"><i class="fa-brands fa-reddit fa-fw"></i> Reddit community</a></li>
<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>
</ul>
</div>
</div>
</div>
</div>
</div>
<div id="save-settings-config" class="popup">
<div>
<i class="close-button fa-solid fa-xmark"></i>
<h1>Save Settings Configuration</h1>
<p>Select which settings should be remembered when restarting the browser</p>
<table id="save-settings-config-table" class="form-table">
</table>
</div>
</div>
<div id="modifier-settings-config" class="popup">
<div>
<i class="close-button fa-solid fa-xmark"></i>
<h1>Modifier Settings</h1>
<p>Set your custom modifiers (one per line)</p>
<textarea id="custom-modifiers-input" placeholder="Enter your custom modifiers, one-per-line"></textarea>
<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>
</div>
</div>
<div id="image-editor" class="popup image-editor-popup">
<div>
<i class="close-button fa-solid fa-xmark"></i>
<h1>Image Editor</h1>
<div class="flex-container">
<div class="editor-controls-left"></div>
<div class="editor-controls-center">
<div></div>
</div>
<div class="editor-controls-right">
<div></div>
</div>
</div>
</div>
</div>
<div class="line-separator">&nbsp;</div>
<div id="image-inpainter" class="popup image-editor-popup">
<div>
<i class="close-button fa-solid fa-xmark"></i>
<h1>Inpainter</h1>
<div class="flex-container">
<div class="editor-controls-left"></div>
<div class="editor-controls-center">
<div></div>
</div>
<div class="editor-controls-right">
<div></div>
</div>
</div>
</div>
</div>
<div id="footer" class="panel-box">
<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/kofi.png" id="coffeeButton"></a> to help cover the cost of development and maintenance! Thank you for your support!</p>
<div id="footer-spacer"></div>
<div id="footer">
<div class="line-separator">&nbsp;</div>
<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>
<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>
<div id="footer-legal">
<p><b>Disclaimer:</b> The authors of this project are not responsible for any content generated using this interface.</p>
@ -212,16 +447,34 @@
</div>
</div>
</body>
<script src="media/js/utils.js"></script>
<script src="media/js/engine.js"></script>
<script src="media/js/parameters.js"></script>
<script src="media/js/plugins.js"></script>
<script src="media/main.js?v=15"></script>
<script src="media/js/image-modifiers.js"></script>
<script src="media/js/auto-save.js"></script>
<script src="media/js/searchable-models.js"></script>
<script src="media/js/main.js"></script>
<script src="media/js/themes.js"></script>
<script src="media/js/dnd.js"></script>
<script src="media/js/image-editor.js"></script>
<script>
async function init() {
await loadModifiers()
await getDiskPath()
await initSettings()
await getModels()
await getAppConfig()
await loadUIPlugins()
await loadModifiers()
await getSystemInfo()
setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
healthCheck()
SD.init({
events: {
statusChange: setServerStatus
, idle: onIdle
}
})
playSound()
}

10
ui/main.py Normal file
View File

@ -0,0 +1,10 @@
from easydiffusion import model_manager, app, server
from easydiffusion.server import server_api # required for uvicorn
# Init the app
model_manager.init()
app.init()
server.init()
# start the browser ui
app.open_browser()

View File

@ -0,0 +1,81 @@
/* Auto-Settings Styling */
#auto_save_settings ~ button {
margin: 5px;
}
#auto_save_settings:not(:checked) ~ button {
display: none;
}
.form-table {
margin: auto;
}
.form-table th {
padding-top: 15px;
padding-bottom: 5px;
}
.form-table td:first-child > *,
.form-table th:first-child > * {
float: right;
white-space: nowrap;
}
.form-table td:last-child > *,
.form-table th:last-child > * {
float: left;
}
.parameters-table {
display: flex;
flex-direction: column;
gap: 1px;
}
.parameters-table > div {
background: var(--background-color2);
display: flex;
padding: 0px 4px;
}
.parameters-table > div > div {
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.parameters-table small {
color: rgb(153, 153, 153);
}
.parameters-table > div > div:nth-child(1) {
font-size: 20px;
width: 45px;
}
.parameters-table > div > div:nth-child(2) {
flex: 1;
flex-direction: column;
text-align: left;
justify-content: center;
align-items: start;
gap: 4px;
}
.parameters-table > div > div:nth-child(3) {
text-align: right;
}
.parameters-table > div:first-child {
border-radius: 12px 12px 0px 0px;
}
.parameters-table > div:last-child {
border-radius: 0px 0px 12px 12px;
}
.parameters-table .fa-fire {
color: #F7630C;
}

6
ui/media/css/fontawesome-all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

40
ui/media/css/fonts.css Normal file
View File

@ -0,0 +1,40 @@
/* work-sans-regular - latin */
@font-face {
font-family: 'Work Sans';
font-style: normal;
font-weight: 400;
src: local(''),
url('/media/fonts/work-sans-v18-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/media/fonts/work-sans-v18-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* work-sans-600 - latin */
@font-face {
font-family: 'Work Sans';
font-style: normal;
font-weight: 600;
src: local(''),
url('/media/fonts/work-sans-v18-latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/media/fonts/work-sans-v18-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* work-sans-700 - latin */
@font-face {
font-family: 'Work Sans';
font-style: normal;
font-weight: 700;
src: local(''),
url('/media/fonts/work-sans-v18-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/media/fonts/work-sans-v18-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* work-sans-800 - latin */
@font-face {
font-family: 'Work Sans';
font-style: normal;
font-weight: 800;
src: local(''),
url('/media/fonts/work-sans-v18-latin-800.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/media/fonts/work-sans-v18-latin-800.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

View File

@ -0,0 +1,223 @@
.editor-controls-left {
padding-left: 32px;
text-align: left;
padding-bottom: 20px;
max-width: min-content;
}
.editor-options-container {
display: flex;
row-gap: 10px;
}
.editor-options-container > * {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.editor-options-container > * > * {
position: inherit;
width: 32px;
height: 32px;
border-radius: 16px;
background: var(--background-color3);
cursor: pointer;
transition: opacity 0.25s;
}
.editor-options-container > * > *:hover {
opacity: 0.75;
}
.editor-options-container > * > *.active {
border: 1px solid #3584e4;
}
.image_editor_opacity .editor-options-container > * > *:not(.active) {
border: 1px solid var(--background-color3);
}
.image_editor_color .editor-options-container {
flex-wrap: wrap;
}
.image_editor_color .editor-options-container > * {
flex: 20%;
}
.image_editor_color .editor-options-container > * > * {
position: relative;
}
.image_editor_color .editor-options-container > * > *.active::before {
content: "\f00c";
display: var(--fa-display,inline-block);
font-style: normal;
font-variant: normal;
line-height: 1;
text-rendering: auto;
font-family: var(--fa-style-family, "Font Awesome 6 Free");
font-weight: var(--fa-style, 900);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) scale(125%);
color: black;
}
.image_editor_color .editor-options-container > *:first-child {
flex: 100%;
}
.image_editor_color .editor-options-container > *:first-child > * {
width: 100%;
}
.image_editor_color .editor-options-container > *:first-child > * > input {
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.image_editor_color .editor-options-container > *:first-child > * > span {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
opacity: 0.5;
}
.image_editor_color .editor-options-container > *:first-child > *.active > span {
opacity: 0;
}
.image_editor_tool .editor-options-container {
flex-wrap: wrap;
}
.image_editor_tool .editor-options-container > * {
padding: 2px;
flex: 50%;
}
.editor-controls-center {
/* background: var(--background-color2); */
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.editor-controls-center > div {
position: relative;
background: black;
}
.editor-controls-center canvas {
position: absolute;
left: 0;
top: 0;
}
.editor-controls-right {
padding: 32px;
display: flex;
flex-direction: column;
}
.editor-controls-right > div:last-child {
flex: 1;
display: flex;
flex-direction: column;
min-width: 200px;
gap: 5px;
justify-content: end;
}
.image-editor-button {
width: 100%;
height: 32px;
border-radius: 16px;
background: var(--background-color3);
}
.editor-controls-right .image-editor-button {
margin-bottom: 4px;
}
#init_image_button_inpaint .input-toggle {
position: absolute;
left: 16px;
}
#init_image_button_inpaint .input-toggle input:not(:checked) ~ label {
pointer-events: none;
}
.image-editor-popup {
--popup-margin: 16px;
--popup-padding: 24px;
}
.image-editor-popup > div {
margin: var(--popup-margin);
padding: var(--popup-padding);
min-height: calc(100vh - (2 * var(--popup-margin)));
max-width: none;
min-width: fit-content;
}
.image-editor-popup h1 {
position: absolute;
top: 32px;
left: 50%;
transform: translateX(-50%);
}
@media screen and (max-width: 700px) {
.image-editor-popup > div {
margin: 0px;
padding: 0px;
}
.image-editor-popup h1 {
position: relative;
transform: none;
left: auto;
}
}
.image-editor-popup > div > div {
min-height: calc(100vh - (2 * var(--popup-margin)) - (2 * var(--popup-padding)));
}
.inpainter .image_editor_color {
display: none;
}
.inpainter .editor-canvas-background {
opacity: 0.75;
}
#init_image_preview_container .button {
display: flex;
padding: 6px;
height: 24px;
box-shadow: 2px 2px 1px 1px #00000088;
}
#init_image_preview_container .button:hover {
background: var(--background-color4)
}
.image-editor-popup .button {
display: flex;
}
.image-editor-popup h4 {
text-align: left;
}
.image-editor-popup .load_mask {
display: none;
}
.inpainter .load_mask {
display: flex;
}

9
ui/media/css/jquery-confirm.min.css vendored Normal file

File diff suppressed because one or more lines are too long

1268
ui/media/css/main.css Normal file

File diff suppressed because it is too large Load Diff

View File

@ -214,3 +214,10 @@
margin-bottom: 0.5em;
vertical-align: middle;
}
#modifier-settings-btn {
float: right;
}
#modifier-settings-config textarea {
width: 90%;
height: 150px;
}

View File

@ -0,0 +1,99 @@
.model-list {
position: absolute;
margin-block-start: 2px;
display: none;
padding-inline-start: 0;
max-height: 200px;
overflow: auto;
background: var(--input-background-color);
border: var(--input-border-size) solid var(--input-border-color);
border-radius: var(--input-border-radius);
color: var(--input-text-color);
z-index: 1;
line-height: normal;
}
.model-list ul {
padding-right: 20px;
padding-inline-start: 0;
margin-top: 3pt;
}
.model-list li {
padding-top: 3px;
padding-bottom: 3px;
}
.model-list .icon {
padding-right: 3pt;
}
.model-result {
list-style: none;
}
.model-no-result {
color: var(--text-color);
list-style: none;
padding: 3px 6px 3px 6px;
font-size: 9pt;
font-style: italic;
display: none;
}
.model-list li.model-folder {
color: var(--text-color);
list-style: none;
padding: 6px 6px 6px 6px;
font-size: 9pt;
font-weight: bold;
border-top: 1px solid var(--background-color1);
}
.model-list li.model-file {
color: var(--input-text-color);
list-style: none;
padding-left: 12px;
padding-right:20px;
font-size: 10pt;
font-weight: normal;
transition: none;
transition:property: none;
cursor: default;
}
.model-list li.model-file.in-root-folder {
padding-left: 6px;
}
.model-list li.model-file.selected {
background: grey;
}
.model-selector {
cursor: pointer;
}
.model-selector-arrow {
position: absolute;
width: 17px;
margin: 5px -17px;
padding-top: 3px;
cursor: pointer;
font-size: 8pt;
transition: none;
}
.model-input {
white-space: nowrap;
}
.reloadModels {
background: var(--background-color2);
border: none;
padding: 0px 0px;
}
#reload-models.secondaryButton:hover {
background: var(--background-color2);
}

183
ui/media/css/themes.css Normal file
View File

@ -0,0 +1,183 @@
:root {
--main-hue: 222;
--main-saturation: 4%;
--value-base: 13%;
--value-step: 5%;
--background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
--background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1 * var(--value-step))));
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (0.5 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1.5 * var(--value-step))));
--accent-hue: 267;
--accent-lightness: 36%;
--accent-lightness-hover: 40%;
--text-color: #eee;
--input-text-color: #eee;
--input-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (0.7 * var(--value-step))));
--input-border-color: var(--background-color4);
--button-text-color: var(--input-text-color);
--button-color: var(--input-background-color);
--button-border: none;
/* other */
--input-border-radius: 4px;
--input-border-size: 1px;
--accent-color: hsl(var(--accent-hue), 100%, var(--accent-lightness));
--accent-color-hover: hsl(var(--accent-hue), 100%, var(--accent-lightness-hover));
--accent-text-color: rgb(255, 221, 255);
--primary-button-border: none;
--input-switch-padding: 1px;
--input-height: 18px;
--tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step))));
--tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3 * var(--value-step))));
--tertiary-color: var(--input-text-color)
/* Main theme color, hex color fallback. */
--theme-color-fallback: #673AB6;
}
.theme-light {
--background-color1: white;
--background-color2: #ececec;
--background-color3: #e7e9eb;
--background-color4: #cccccc;
--text-color: black;
--input-text-color: black;
--input-background-color: #f8f9fa;
--input-border-color: grey;
--theme-color-fallback: #aaaaaa;
--tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (16.8 * var(--value-step))));
--tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (12 * var(--value-step))));
--accent-text-color: white;
}
.theme-discord {
--background-color1: #36393f;
--background-color2: #2f3136;
--background-color3: #292b2f;
--background-color4: #202225;
--accent-hue: 235;
--accent-lightness: 65%;
--input-border-size: 2px;
--input-background-color: #202225;
--input-border-color: var(--input-background-color);
--theme-color-fallback: #202225;
--tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
--tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
--accent-text-color: white;
}
.theme-cool-blue {
--main-hue: 222;
--main-saturation: 18%;
--value-base: 18%;
--value-step: 3%;
--background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
--background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--input-background-color: var(--background-color3);
--accent-hue: 212;
--theme-color-fallback: #0056b8;
--tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
--tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
--accent-text-color: #f7fbff;
}
.theme-blurple {
--main-hue: 235;
--main-saturation: 18%;
--value-base: 16%;
--value-step: 3%;
--background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
--background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--input-background-color: var(--background-color3);
--theme-color-fallback: #5300b8;
--tertiary-background-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (3.5 * var(--value-step))));
--tertiary-border-color: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (4.5 * var(--value-step))));
}
.theme-super-dark {
--main-hue: 222;
--main-saturation: 18%;
--value-base: 5%;
--value-step: 5%;
--background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
--background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1 * var(--value-step))));
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1.4 * var(--value-step))));
--input-background-color: var(--background-color3);
--input-border-size: 0px;
--theme-color-fallback: #000000;
}
.theme-wild {
--main-hue: 128;
--main-saturation: 18%;
--value-base: 20%;
--value-step: 5%;
--background-color1: hsl(var(--main-hue), var(--main-saturation), var(--value-base));
--background-color2: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (1 * var(--value-step))));
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--accent-hue: 212;
--input-border-size: 1px;
--input-background-color: hsl(222, var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
--input-text-color: #FF0000;
--input-border-color: #005E05;
--tertiary-color: white;
--accent-text-color: #f7fbff;
}
.theme-gnomie {
--background-color1: #242424;
--background-color2: #353535;
--background-color3: #494949;
--background-color4: #000000;
--accent-hue: 213;
--accent-lightness: 55%;
--accent-color: #2168bf;
--input-border-radius: 6px;
--input-text-color: #ffffff;
--input-background-color: #2a2a2a;
--input-border-size: 0px;
--input-border-color: var(--input-background-color);
--theme-color-fallback: #2168bf;
}
.theme-gnomie .panel-box {
border: none;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 10px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 576" width="24" height="24">
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.-->
<path style="filter: drop-shadow(0px 0px 20px white)" d="M290.7 57.4 57.4 290.7c-25 25-25 65.5 0 90.5l80 80c12 12 28.3 18.7 45.3 18.7H512c17.7 0 32-14.3 32-32s-14.3-32-32-32H387.9l130.7-130.6c25-25 25-65.5 0-90.5L381.3 57.4c-25-25-65.5-25-90.5 0zm6.7 358.6H182.6l-80-80 124.7-124.7 137.4 137.4-67.3 67.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="24" height="24">
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.-->
<path style="filter: drop-shadow(0px 0px 20px white)" d="M341.6 29.2 240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4 101.5-101.6c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6v42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480h42.4c21.2 0 41.6-8.4 56.6-23.4l120.7-120.7-45.3-45.3-120.7 120.7c-3 3-7.1 4.7-11.3 4.7H96v-36.1c0-4.2 1.7-8.3 4.7-11.3l120.7-120.7-45.3-45.3L55.4 323.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 775 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 576" width="24" height="24">
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.-->
<path style="filter: drop-shadow(0px 0px 20px white)" d="M118.6 9.4c-12.5-12.5-32.7-12.5-45.2 0s-12.5 32.8 0 45.3l81.3 81.3-92.1 92.1c-37.5 37.5-37.5 98.3 0 135.8l117.5 117.5c37.5 37.5 98.3 37.5 135.8 0l190.4-190.5c28.1-28.1 28.1-73.7 0-101.8L354.9 37.7c-28.1-28.1-73.7-28.1-101.8 0l-53.1 53-81.4-81.3zM200 181.3l49.4 49.4c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L245.3 136l53.1-53.1c3.1-3.1 8.2-3.1 11.3 0l151.4 151.4c3.1 3.1 3.1 8.2 0 11.3L418.7 288H99.5c1.4-5.4 4.2-10.4 8.4-14.6l92.1-92.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="24" height="24">
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.-->
<path style="filter: drop-shadow(0px 0px 20px white)" d="m410.3 231 11.3-11.3-33.9-33.9-62.1-62.1-33.9-33.9-11.3 11.3-22.6 22.6L58.6 322.9c-10.4 10.4-18 23.3-22.2 37.4L1 480.7c-2.5 8.4-.2 17.5 6.1 23.7s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2l199.2-199.2 22.6-22.7zM160 399.4l-9.1 22.7c-4 3.1-8.5 5.4-13.3 6.9l-78.2 23 23-78.1c1.4-4.9 3.8-9.4 6.9-13.3l22.7-9.1v32c0 8.8 7.2 16 16 16h32zM362.7 18.7l-14.4 14.5-22.6 22.6-11.4 11.3 33.9 33.9 62.1 62.1 33.9 33.9 11.3-11.3 22.6-22.6 14.5-14.5c25-25 25-65.5 0-90.5l-39.3-39.4c-25-25-65.5-25-90.5 0zm-47.4 168-144 144c-6.2 6.2-16.4 6.2-22.6 0s-6.2-16.4 0-22.6l144-144c6.2-6.2 16.4-6.2 22.6 0s6.2 16.4 0 22.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

321
ui/media/js/auto-save.js Normal file
View File

@ -0,0 +1,321 @@
// Saving settings
let saveSettingsConfigTable = document.getElementById("save-settings-config-table")
let saveSettingsConfigOverlay = document.getElementById("save-settings-config")
let resetImageSettingsButton = document.getElementById("reset-image-settings")
const SETTINGS_KEY = "user_settings_v2"
const SETTINGS = {} // key=id. dict initialized in initSettings. { element, default, value, ignore }
const SETTINGS_IDS_LIST = [
"prompt",
"seed",
"random_seed",
"num_outputs_total",
"num_outputs_parallel",
"stable_diffusion_model",
"vae_model",
"hypernetwork_model",
"sampler_name",
"width",
"height",
"num_inference_steps",
"guidance_scale",
"prompt_strength",
"hypernetwork_strength",
"output_format",
"output_quality",
"negative_prompt",
"stream_image_progress",
"use_face_correction",
"gfpgan_model",
"use_upscale",
"upscale_amount",
"block_nsfw",
"show_only_filtered_image",
"upscale_model",
"preview-image",
"modifier-card-size-slider",
"theme",
"save_to_disk",
"diskPath",
"sound_toggle",
"vram_usage_level",
"confirm_dangerous_actions",
"metadata_output_format",
"auto_save_settings",
"apply_color_correction",
"process_order_toggle",
"thumbnail_size",
"auto_scroll"
]
const IGNORE_BY_DEFAULT = [
"prompt"
]
const SETTINGS_SECTIONS = [ // gets the "keys" property filled in with an ordered list of settings in this section via initSettings
{ id: "editor-inputs", name: "Prompt" },
{ id: "editor-settings", name: "Image Settings" },
{ id: "system-settings", name: "System Settings" },
{ id: "container", name: "Other" }
]
async function initSettings() {
SETTINGS_IDS_LIST.forEach(id => {
var element = document.getElementById(id)
if (!element) {
console.error(`Missing settings element ${id}`)
}
if (id in SETTINGS) { // don't create it again
return
}
SETTINGS[id] = {
key: id,
element: element,
label: getSettingLabel(element),
default: getSetting(element),
value: getSetting(element),
ignore: IGNORE_BY_DEFAULT.includes(id)
}
element.addEventListener("input", settingChangeHandler)
element.addEventListener("change", settingChangeHandler)
})
var unsorted_settings_ids = [...SETTINGS_IDS_LIST]
SETTINGS_SECTIONS.forEach(section => {
var name = section.name
var element = document.getElementById(section.id)
var unsorted_ids = unsorted_settings_ids.map(id => `#${id}`).join(",")
var children = unsorted_ids == "" ? [] : Array.from(element.querySelectorAll(unsorted_ids));
section.keys = []
children.forEach(e => {
section.keys.push(e.id)
})
unsorted_settings_ids = unsorted_settings_ids.filter(id => children.find(e => e.id == id) == undefined)
})
loadSettings()
}
function getSetting(element) {
if (element.dataset && 'path' in element.dataset) {
return element.dataset.path
}
if (typeof element === "string" || element instanceof String) {
element = SETTINGS[element].element
}
if (element.type == "checkbox") {
return element.checked
}
return element.value
}
function setSetting(element, value) {
if (element.dataset && 'path' in element.dataset) {
element.dataset.path = value
return // no need to dispatch any event here because the models are not loaded yet
}
if (typeof element === "string" || element instanceof String) {
element = SETTINGS[element].element
}
SETTINGS[element.id].value = value
if (getSetting(element) == value) {
return // no setting necessary
}
if (element.type == "checkbox") {
element.checked = value
}
else {
element.value = value
}
element.dispatchEvent(new Event("input"))
element.dispatchEvent(new Event("change"))
}
function saveSettings() {
var saved_settings = Object.values(SETTINGS).map(setting => {
return {
key: setting.key,
value: setting.value,
ignore: setting.ignore
}
})
localStorage.setItem(SETTINGS_KEY, JSON.stringify(saved_settings))
}
var CURRENTLY_LOADING_SETTINGS = false
function loadSettings() {
var saved_settings_text = localStorage.getItem(SETTINGS_KEY)
if (saved_settings_text) {
var saved_settings = JSON.parse(saved_settings_text)
if (saved_settings.find(s => s.key == "auto_save_settings")?.value == false) {
setSetting("auto_save_settings", false)
return
}
CURRENTLY_LOADING_SETTINGS = true
saved_settings.forEach(saved_setting => {
var setting = SETTINGS[saved_setting.key]
if (!setting) {
console.warn(`Attempted to load setting ${saved_setting.key}, but no setting found`);
return null;
}
setting.ignore = saved_setting.ignore
if (!setting.ignore) {
setting.value = saved_setting.value
setSetting(setting.element, setting.value)
}
})
CURRENTLY_LOADING_SETTINGS = false
}
else {
CURRENTLY_LOADING_SETTINGS = true
tryLoadOldSettings();
CURRENTLY_LOADING_SETTINGS = false
saveSettings()
}
}
function loadDefaultSettingsSection(section_id) {
CURRENTLY_LOADING_SETTINGS = true
var section = SETTINGS_SECTIONS.find(s => s.id == section_id);
section.keys.forEach(key => {
var setting = SETTINGS[key];
setting.value = setting.default
setSetting(setting.element, setting.value)
})
CURRENTLY_LOADING_SETTINGS = false
saveSettings()
}
function settingChangeHandler(event) {
if (!CURRENTLY_LOADING_SETTINGS) {
var element = event.target
var value = getSetting(element)
if (value != SETTINGS[element.id].value) {
SETTINGS[element.id].value = value
saveSettings()
}
}
}
function getSettingLabel(element) {
var labelElement = document.querySelector(`label[for='${element.id}']`)
var label = labelElement?.innerText || element.id
var truncate_length = 30
if (label.includes(" (")) {
label = label.substring(0, label.indexOf(" ("))
}
if (label.length > truncate_length) {
label = label.substring(0, truncate_length - 3) + "..."
}
label = label.replace("", "")
label = label.replace("", "")
return label
}
function fillSaveSettingsConfigTable() {
saveSettingsConfigTable.textContent = ""
SETTINGS_SECTIONS.forEach(section => {
var section_row = `<tr><th>${section.name}</th><td></td></tr>`
saveSettingsConfigTable.insertAdjacentHTML("beforeend", section_row)
section.keys.forEach(key => {
var setting = SETTINGS[key]
var element = setting.element
var checkbox_id = `shouldsave_${element.id}`
var is_checked = setting.ignore ? "" : "checked"
var value = setting.value
var value_truncate_length = 30
if ((typeof value === "string" || value instanceof String) && value.length > value_truncate_length) {
value = value.substring(0, value_truncate_length - 3) + "..."
}
var newrow = `<tr><td><label for="${checkbox_id}">${setting.label}</label></td><td><input id="${checkbox_id}" name="${checkbox_id}" ${is_checked} type="checkbox" ></td><td><small>(${value})</small></td></tr>`
saveSettingsConfigTable.insertAdjacentHTML("beforeend", newrow)
var checkbox = document.getElementById(checkbox_id)
checkbox.addEventListener("input", event => {
setting.ignore = !checkbox.checked
saveSettings()
})
})
})
prettifyInputs(saveSettingsConfigTable)
}
// configureSettingsSaveBtn
var autoSaveSettings = document.getElementById("auto_save_settings")
var configSettingsButton = document.createElement("button")
configSettingsButton.textContent = "Configure"
configSettingsButton.style.margin = "0px 5px"
autoSaveSettings.insertAdjacentElement("beforebegin", configSettingsButton)
autoSaveSettings.addEventListener("change", () => {
configSettingsButton.style.display = autoSaveSettings.checked ? "block" : "none"
})
configSettingsButton.addEventListener('click', () => {
fillSaveSettingsConfigTable()
saveSettingsConfigOverlay.classList.add("active")
})
resetImageSettingsButton.addEventListener('click', event => {
loadDefaultSettingsSection("editor-settings");
event.stopPropagation()
})
function tryLoadOldSettings() {
console.log("Loading old user settings")
// load v1 auto-save.js settings
var old_map = {
"guidance_scale_slider": "guidance_scale",
"prompt_strength_slider": "prompt_strength"
}
var settings_key_v1 = "user_settings"
var saved_settings_text = localStorage.getItem(settings_key_v1)
if (saved_settings_text) {
var saved_settings = JSON.parse(saved_settings_text)
Object.keys(saved_settings.should_save).forEach(key => {
key = key in old_map ? old_map[key] : key
if (!(key in SETTINGS)) return
SETTINGS[key].ignore = !saved_settings.should_save[key]
});
Object.keys(saved_settings.values).forEach(key => {
key = key in old_map ? old_map[key] : key
if (!(key in SETTINGS)) return
var setting = SETTINGS[key]
if (!setting.ignore) {
setting.value = saved_settings.values[key]
setSetting(setting.element, setting.value)
}
});
localStorage.removeItem(settings_key_v1)
}
// load old individually stored items
var individual_settings_map = { // maps old localStorage-key to new SETTINGS-key
"soundEnabled": "sound_toggle",
"saveToDisk": "save_to_disk",
"useCPU": "use_cpu",
"diskPath": "diskPath",
"useFaceCorrection": "use_face_correction",
"useUpscaling": "use_upscale",
"showOnlyFilteredImage": "show_only_filtered_image",
"streamImageProgress": "stream_image_progress",
"outputFormat": "output_format",
"autoSaveSettings": "auto_save_settings",
};
Object.keys(individual_settings_map).forEach(localStorageKey => {
var localStorageValue = localStorage.getItem(localStorageKey);
if (localStorageValue !== null) {
let key = individual_settings_map[localStorageKey]
var setting = SETTINGS[key]
if (!setting) {
console.warn(`Attempted to map old setting ${key}, but no setting found`);
return null;
}
if (setting.element.type == "checkbox" && (typeof localStorageValue === "string" || localStorageValue instanceof String)) {
localStorageValue = localStorageValue == "true"
}
setting.value = localStorageValue
setSetting(setting.element, setting.value)
localStorage.removeItem(localStorageKey);
}
})
}

619
ui/media/js/dnd.js Normal file
View File

@ -0,0 +1,619 @@
"use strict" // Opt in to a restricted variant of JavaScript
const EXT_REGEX = /(?:\.([^.]+))?$/
const TEXT_EXTENSIONS = ['txt', 'json']
const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'bmp', 'tiff', 'tif', 'tga', 'webp']
function parseBoolean(stringValue) {
if (typeof stringValue === 'boolean') {
return stringValue
}
if (typeof stringValue === 'number') {
return stringValue !== 0
}
if (typeof stringValue !== 'string') {
return false
}
switch(stringValue?.toLowerCase()?.trim()) {
case "true":
case "yes":
case "on":
case "1":
return true;
case "false":
case "no":
case "off":
case "0":
case "none":
case null:
case undefined:
return false;
}
try {
return Boolean(JSON.parse(stringValue));
} catch {
return Boolean(stringValue)
}
}
const TASK_MAPPING = {
prompt: { name: 'Prompt',
setUI: (prompt) => {
promptField.value = prompt
},
readUI: () => promptField.value,
parse: (val) => val
},
negative_prompt: { name: 'Negative Prompt',
setUI: (negative_prompt) => {
negativePromptField.value = negative_prompt
},
readUI: () => negativePromptField.value,
parse: (val) => val
},
active_tags: { name: "Image Modifiers",
setUI: (active_tags) => {
refreshModifiersState(active_tags)
},
readUI: () => activeTags.map(x => x.name),
parse: (val) => val
},
inactive_tags: { name: "Inactive Image Modifiers",
setUI: (inactive_tags) => {
refreshInactiveTags(inactive_tags)
},
readUI: () => activeTags.filter(tag => tag.inactive === true).map(x => x.name),
parse: (val) => val
},
width: { name: 'Width',
setUI: (width) => {
const oldVal = widthField.value
widthField.value = width
if (!widthField.value) {
widthField.value = oldVal
}
},
readUI: () => parseInt(widthField.value),
parse: (val) => parseInt(val)
},
height: { name: 'Height',
setUI: (height) => {
const oldVal = heightField.value
heightField.value = height
if (!heightField.value) {
heightField.value = oldVal
}
},
readUI: () => parseInt(heightField.value),
parse: (val) => parseInt(val)
},
seed: { name: 'Seed',
setUI: (seed) => {
if (!seed) {
randomSeedField.checked = true
seedField.disabled = true
seedField.value = 0
return
}
randomSeedField.checked = false
seedField.disabled = false
seedField.value = seed
},
readUI: () => parseInt(seedField.value), // just return the value the user is seeing in the UI
parse: (val) => parseInt(val)
},
num_inference_steps: { name: 'Steps',
setUI: (num_inference_steps) => {
numInferenceStepsField.value = num_inference_steps
},
readUI: () => parseInt(numInferenceStepsField.value),
parse: (val) => parseInt(val)
},
guidance_scale: { name: 'Guidance Scale',
setUI: (guidance_scale) => {
guidanceScaleField.value = guidance_scale
updateGuidanceScaleSlider()
},
readUI: () => parseFloat(guidanceScaleField.value),
parse: (val) => parseFloat(val)
},
prompt_strength: { name: 'Prompt Strength',
setUI: (prompt_strength) => {
promptStrengthField.value = prompt_strength
updatePromptStrengthSlider()
},
readUI: () => parseFloat(promptStrengthField.value),
parse: (val) => parseFloat(val)
},
init_image: { name: 'Initial Image',
setUI: (init_image) => {
initImagePreview.src = init_image
},
readUI: () => initImagePreview.src,
parse: (val) => val
},
mask: { name: 'Mask',
setUI: (mask) => {
setTimeout(() => { // add a delay to insure this happens AFTER the main image loads (which reloads the inpainter)
imageInpainter.setImg(mask)
}, 250)
maskSetting.checked = Boolean(mask)
},
readUI: () => (maskSetting.checked ? imageInpainter.getImg() : undefined),
parse: (val) => val
},
preserve_init_image_color_profile: { name: 'Preserve Color Profile',
setUI: (preserve_init_image_color_profile) => {
applyColorCorrectionField.checked = parseBoolean(preserve_init_image_color_profile)
},
readUI: () => applyColorCorrectionField.checked,
parse: (val) => parseBoolean(val)
},
use_face_correction: { name: 'Use Face Correction',
setUI: (use_face_correction) => {
const oldVal = gfpganModelField.value
gfpganModelField.value = getModelPath(use_face_correction, ['.pth'])
if (gfpganModelField.value) { // Is a valid value for the field.
useFaceCorrectionField.checked = true
gfpganModelField.disabled = false
} else { // Not a valid value, restore the old value and disable the filter.
gfpganModelField.disabled = true
gfpganModelField.value = oldVal
useFaceCorrectionField.checked = false
}
//useFaceCorrectionField.checked = parseBoolean(use_face_correction)
},
readUI: () => (useFaceCorrectionField.checked ? gfpganModelField.value : undefined),
parse: (val) => val
},
use_upscale: { name: 'Use Upscaling',
setUI: (use_upscale) => {
const oldVal = upscaleModelField.value
upscaleModelField.value = getModelPath(use_upscale, ['.pth'])
if (upscaleModelField.value) { // Is a valid value for the field.
useUpscalingField.checked = true
upscaleModelField.disabled = false
upscaleAmountField.disabled = false
} else { // Not a valid value, restore the old value and disable the filter.
upscaleModelField.disabled = true
upscaleAmountField.disabled = true
upscaleModelField.value = oldVal
useUpscalingField.checked = false
}
},
readUI: () => (useUpscalingField.checked ? upscaleModelField.value : undefined),
parse: (val) => val
},
upscale_amount: { name: 'Upscale By',
setUI: (upscale_amount) => {
upscaleAmountField.value = upscale_amount
},
readUI: () => upscaleAmountField.value,
parse: (val) => val
},
sampler_name: { name: 'Sampler',
setUI: (sampler_name) => {
samplerField.value = sampler_name
},
readUI: () => samplerField.value,
parse: (val) => val
},
use_stable_diffusion_model: { name: 'Stable Diffusion model',
setUI: (use_stable_diffusion_model) => {
const oldVal = stableDiffusionModelField.value
use_stable_diffusion_model = getModelPath(use_stable_diffusion_model, ['.ckpt', '.safetensors'])
stableDiffusionModelField.value = use_stable_diffusion_model
if (!stableDiffusionModelField.value) {
stableDiffusionModelField.value = oldVal
}
},
readUI: () => stableDiffusionModelField.value,
parse: (val) => val
},
use_vae_model: { name: 'VAE model',
setUI: (use_vae_model) => {
const oldVal = vaeModelField.value
use_vae_model = (use_vae_model === undefined || use_vae_model === null || use_vae_model === 'None' ? '' : use_vae_model)
if (use_vae_model !== '') {
use_vae_model = getModelPath(use_vae_model, ['.vae.pt', '.ckpt'])
use_vae_model = use_vae_model !== '' ? use_vae_model : oldVal
}
vaeModelField.value = use_vae_model
},
readUI: () => vaeModelField.value,
parse: (val) => val
},
use_hypernetwork_model: { name: 'Hypernetwork model',
setUI: (use_hypernetwork_model) => {
const oldVal = hypernetworkModelField.value
use_hypernetwork_model = (use_hypernetwork_model === undefined || use_hypernetwork_model === null || use_hypernetwork_model === 'None' ? '' : use_hypernetwork_model)
if (use_hypernetwork_model !== '') {
use_hypernetwork_model = getModelPath(use_hypernetwork_model, ['.pt'])
use_hypernetwork_model = use_hypernetwork_model !== '' ? use_hypernetwork_model : oldVal
}
hypernetworkModelField.value = use_hypernetwork_model
hypernetworkModelField.dispatchEvent(new Event('change'))
},
readUI: () => hypernetworkModelField.value,
parse: (val) => val
},
hypernetwork_strength: { name: 'Hypernetwork Strength',
setUI: (hypernetwork_strength) => {
hypernetworkStrengthField.value = hypernetwork_strength
updateHypernetworkStrengthSlider()
},
readUI: () => parseFloat(hypernetworkStrengthField.value),
parse: (val) => parseFloat(val)
},
num_outputs: { name: 'Parallel Images',
setUI: (num_outputs) => {
numOutputsParallelField.value = num_outputs
},
readUI: () => parseInt(numOutputsParallelField.value),
parse: (val) => val
},
use_cpu: { name: 'Use CPU',
setUI: (use_cpu) => {
useCPUField.checked = use_cpu
},
readUI: () => useCPUField.checked,
parse: (val) => val
},
stream_image_progress: { name: 'Stream Image Progress',
setUI: (stream_image_progress) => {
streamImageProgressField.checked = (parseInt(numOutputsTotalField.value) > 50 ? false : stream_image_progress)
},
readUI: () => streamImageProgressField.checked,
parse: (val) => Boolean(val)
},
show_only_filtered_image: { name: 'Show only the corrected/upscaled image',
setUI: (show_only_filtered_image) => {
showOnlyFilteredImageField.checked = show_only_filtered_image
},
readUI: () => showOnlyFilteredImageField.checked,
parse: (val) => Boolean(val)
},
output_format: { name: 'Output Format',
setUI: (output_format) => {
outputFormatField.value = output_format
},
readUI: () => outputFormatField.value,
parse: (val) => val
},
save_to_disk_path: { name: 'Save to disk path',
setUI: (save_to_disk_path) => {
saveToDiskField.checked = Boolean(save_to_disk_path)
diskPathField.value = save_to_disk_path
},
readUI: () => diskPathField.value,
parse: (val) => val
}
}
function restoreTaskToUI(task, fieldsToSkip) {
fieldsToSkip = fieldsToSkip || []
if ('numOutputsTotal' in task) {
numOutputsTotalField.value = task.numOutputsTotal
}
if ('seed' in task) {
randomSeedField.checked = false
seedField.value = task.seed
}
if (!('reqBody' in task)) {
return
}
for (const key in TASK_MAPPING) {
if (key in task.reqBody && !fieldsToSkip.includes(key)) {
TASK_MAPPING[key].setUI(task.reqBody[key])
}
}
// properly reset fields not present in the task
if (!('use_hypernetwork_model' in task.reqBody)) {
hypernetworkModelField.value = ""
hypernetworkModelField.dispatchEvent(new Event("change"))
}
// restore the original prompt if provided (e.g. use settings), fallback to prompt as needed (e.g. copy/paste or d&d)
promptField.value = task.reqBody.original_prompt
if (!('original_prompt' in task.reqBody)) {
promptField.value = task.reqBody.prompt
}
// properly reset checkboxes
if (!('use_face_correction' in task.reqBody)) {
useFaceCorrectionField.checked = false
gfpganModelField.disabled = true
}
if (!('use_upscale' in task.reqBody)) {
useUpscalingField.checked = false
}
if (!('mask' in task.reqBody) && maskSetting.checked) {
maskSetting.checked = false
maskSetting.dispatchEvent(new Event("click"))
}
upscaleModelField.disabled = !useUpscalingField.checked
upscaleAmountField.disabled = !useUpscalingField.checked
// hide/show source picture as needed
if (IMAGE_REGEX.test(initImagePreview.src) && task.reqBody.init_image == undefined) {
// hide source image
initImageClearBtn.dispatchEvent(new Event("click"))
}
else if (task.reqBody.init_image !== undefined) {
// listen for inpainter loading event, which happens AFTER the main image loads (which reloads the inpainter)
initImagePreview.addEventListener('load', function() {
if (Boolean(task.reqBody.mask)) {
imageInpainter.setImg(task.reqBody.mask)
maskSetting.checked = true
}
}, { once: true })
initImagePreview.src = task.reqBody.init_image
}
}
function readUI() {
const reqBody = {}
for (const key in TASK_MAPPING) {
reqBody[key] = TASK_MAPPING[key].readUI()
}
return {
'numOutputsTotal': parseInt(numOutputsTotalField.value),
'seed': TASK_MAPPING['seed'].readUI(),
'reqBody': reqBody
}
}
function getModelPath(filename, extensions)
{
if (typeof filename !== "string") {
return
}
let pathIdx
if (filename.includes('/models/stable-diffusion/')) {
pathIdx = filename.indexOf('/models/stable-diffusion/') + 25 // Linux, Mac paths
}
else if (filename.includes('\\models\\stable-diffusion\\')) {
pathIdx = filename.indexOf('\\models\\stable-diffusion\\') + 25 // Linux, Mac paths
}
if (pathIdx >= 0) {
filename = filename.slice(pathIdx)
}
extensions.forEach(ext => {
if (filename.endsWith(ext)) {
filename = filename.slice(0, filename.length - ext.length)
}
})
return filename
}
const TASK_TEXT_MAPPING = {
prompt: 'Prompt',
width: 'Width',
height: 'Height',
seed: 'Seed',
num_inference_steps: 'Steps',
guidance_scale: 'Guidance Scale',
prompt_strength: 'Prompt Strength',
use_face_correction: 'Use Face Correction',
use_upscale: 'Use Upscaling',
upscale_amount: 'Upscale By',
sampler_name: 'Sampler',
negative_prompt: 'Negative Prompt',
use_stable_diffusion_model: 'Stable Diffusion model',
use_hypernetwork_model: 'Hypernetwork model',
hypernetwork_strength: 'Hypernetwork Strength'
}
function parseTaskFromText(str) {
const taskReqBody = {}
const lines = str.split('\n')
if (lines.length === 0) {
return
}
// Prompt
let knownKeyOnFirstLine = false
for (let key in TASK_TEXT_MAPPING) {
if (lines[0].startsWith(TASK_TEXT_MAPPING[key] + ':')) {
knownKeyOnFirstLine = true
break
}
}
if (!knownKeyOnFirstLine) {
taskReqBody.prompt = lines[0]
console.log('Prompt:', taskReqBody.prompt)
}
for (const key in TASK_TEXT_MAPPING) {
if (key in taskReqBody) {
continue
}
const name = TASK_TEXT_MAPPING[key];
let val = undefined
const reName = new RegExp(`${name}\\ *:\\ *(.*)(?:\\r\\n|\\r|\\n)*`, 'igm')
const match = reName.exec(str);
if (match) {
str = str.slice(0, match.index) + str.slice(match.index + match[0].length)
val = match[1]
}
if (val !== undefined) {
taskReqBody[key] = TASK_MAPPING[key].parse(val.trim())
console.log(TASK_MAPPING[key].name + ':', taskReqBody[key])
if (!str) {
break
}
}
}
if (Object.keys(taskReqBody).length <= 0) {
return undefined
}
const task = { reqBody: taskReqBody }
if ('seed' in taskReqBody) {
task.seed = taskReqBody.seed
}
return task
}
async function parseContent(text) {
text = text.trim();
if (text.startsWith('{') && text.endsWith('}')) {
try {
const task = JSON.parse(text)
if (!('reqBody' in task)) { // support the format saved to the disk, by the UI
task.reqBody = Object.assign({}, task)
}
restoreTaskToUI(task)
return true
} catch (e) {
console.warn(`JSON text content couldn't be parsed.`, e)
}
return false
}
// Normal txt file.
const task = parseTaskFromText(text)
if (text.toLowerCase().includes('seed:') && task) { // only parse valid task content
restoreTaskToUI(task)
return true
} else {
console.warn(`Raw text content couldn't be parsed.`)
return false
}
}
async function readFile(file, i) {
console.log(`Event %o reading file[${i}]:${file.name}...`)
const fileContent = (await file.text()).trim()
return await parseContent(fileContent)
}
function dropHandler(ev) {
console.log('Content dropped...')
let items = []
if (ev?.dataTransfer?.items) { // Use DataTransferItemList interface
items = Array.from(ev.dataTransfer.items)
items = items.filter(item => item.kind === 'file')
items = items.map(item => item.getAsFile())
} else if (ev?.dataTransfer?.files) { // Use DataTransfer interface
items = Array.from(ev.dataTransfer.files)
}
items.forEach(item => {item.file_ext = EXT_REGEX.exec(item.name.toLowerCase())[1]})
let text_items = items.filter(item => TEXT_EXTENSIONS.includes(item.file_ext))
let image_items = items.filter(item => IMAGE_EXTENSIONS.includes(item.file_ext))
if (image_items.length > 0 && ev.target == initImageSelector) {
return // let the event bubble up, so that the Init Image filepicker can receive this
}
ev.preventDefault() // Prevent default behavior (Prevent file/content from being opened)
text_items.forEach(readFile)
}
function dragOverHandler(ev) {
console.log('Content in drop zone')
// Prevent default behavior (Prevent file/content from being opened)
ev.preventDefault()
ev.dataTransfer.dropEffect = "copy"
let img = new Image()
img.src = '//' + location.host + '/media/images/favicon-32x32.png'
ev.dataTransfer.setDragImage(img, 16, 16)
}
document.addEventListener("drop", dropHandler)
document.addEventListener("dragover", dragOverHandler)
const TASK_REQ_NO_EXPORT = [
"use_cpu",
"save_to_disk_path"
]
const resetSettings = document.getElementById('reset-image-settings')
function checkReadTextClipboardPermission (result) {
if (result.state != "granted" && result.state != "prompt") {
return
}
// PASTE ICON
const pasteIcon = document.createElement('i')
pasteIcon.className = 'fa-solid fa-paste section-button'
pasteIcon.innerHTML = `<span class="simple-tooltip top-left">Paste Image Settings</span>`
pasteIcon.addEventListener('click', async (event) => {
event.stopPropagation()
// Add css class 'active'
pasteIcon.classList.add('active')
// In 350 ms remove the 'active' class
asyncDelay(350).then(() => pasteIcon.classList.remove('active'))
// Retrieve clipboard content and try to parse it
const text = await navigator.clipboard.readText();
await parseContent(text)
})
resetSettings.parentNode.insertBefore(pasteIcon, resetSettings)
}
navigator.permissions.query({ name: "clipboard-read" }).then(checkReadTextClipboardPermission, (reason) => console.log('clipboard-read is not available. %o', reason))
document.addEventListener('paste', async (event) => {
if (event.target) {
const targetTag = event.target.tagName.toLowerCase()
// Disable when targeting input elements.
if (targetTag === 'input' || targetTag === 'textarea') {
return
}
}
const paste = (event.clipboardData || window.clipboardData).getData('text')
const selection = window.getSelection()
if (selection.toString().trim().length <= 0 && await parseContent(paste)) {
event.preventDefault()
return
}
})
// Adds a copy and a paste icon if the browser grants permission to write to clipboard.
function checkWriteToClipboardPermission (result) {
if (result.state != "granted" && result.state != "prompt") {
return
}
// COPY ICON
const copyIcon = document.createElement('i')
copyIcon.className = 'fa-solid fa-clipboard section-button'
copyIcon.innerHTML = `<span class="simple-tooltip top-left">Copy Image Settings</span>`
copyIcon.addEventListener('click', (event) => {
event.stopPropagation()
// Add css class 'active'
copyIcon.classList.add('active')
// In 350 ms remove the 'active' class
asyncDelay(350).then(() => copyIcon.classList.remove('active'))
const uiState = readUI()
TASK_REQ_NO_EXPORT.forEach((key) => delete uiState.reqBody[key])
if (uiState.reqBody.init_image && !IMAGE_REGEX.test(uiState.reqBody.init_image)) {
delete uiState.reqBody.init_image
delete uiState.reqBody.prompt_strength
}
navigator.clipboard.writeText(JSON.stringify(uiState, undefined, 4))
})
resetSettings.parentNode.insertBefore(copyIcon, resetSettings)
}
// Determine which access we have to the clipboard. Clipboard access is only available on localhost or via TLS.
navigator.permissions.query({ name: "clipboard-write" }).then(checkWriteToClipboardPermission, (e) => {
if (e instanceof TypeError && typeof navigator?.clipboard?.writeText === 'function') {
// Fix for firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1560373
checkWriteToClipboardPermission({state:"granted"})
}
})

1311
ui/media/js/engine.js Normal file

File diff suppressed because it is too large Load Diff

876
ui/media/js/image-editor.js Normal file
View File

@ -0,0 +1,876 @@
var editorControlsLeft = document.getElementById("image-editor-controls-left")
const IMAGE_EDITOR_MAX_SIZE = 800
const IMAGE_EDITOR_BUTTONS = [
{
name: "Cancel",
icon: "fa-regular fa-circle-xmark",
handler: editor => {
editor.hide()
}
},
{
name: "Save",
icon: "fa-solid fa-floppy-disk",
handler: editor => {
editor.saveImage()
}
}
]
const defaultToolBegin = (editor, ctx, x, y, is_overlay = false) => {
ctx.beginPath()
ctx.moveTo(x, y)
}
const defaultToolMove = (editor, ctx, x, y, is_overlay = false) => {
ctx.lineTo(x, y)
if (is_overlay) {
ctx.clearRect(0, 0, editor.width, editor.height)
ctx.stroke()
}
}
const defaultToolEnd = (editor, ctx, x, y, is_overlay = false) => {
ctx.stroke()
if (is_overlay) {
ctx.clearRect(0, 0, editor.width, editor.height)
}
}
const toolDoNothing = (editor, ctx, x, y, is_overlay = false) => {}
const IMAGE_EDITOR_TOOLS = [
{
id: "draw",
name: "Draw",
icon: "fa-solid fa-pencil",
cursor: "url(/media/images/fa-pencil.svg) 0 24, pointer",
begin: defaultToolBegin,
move: defaultToolMove,
end: defaultToolEnd
},
{
id: "erase",
name: "Erase",
icon: "fa-solid fa-eraser",
cursor: "url(/media/images/fa-eraser.svg) 0 14, pointer",
begin: defaultToolBegin,
move: (editor, ctx, x, y, is_overlay = false) => {
ctx.lineTo(x, y)
if (is_overlay) {
ctx.clearRect(0, 0, editor.width, editor.height)
ctx.globalCompositeOperation = "source-over"
ctx.globalAlpha = 1
ctx.filter = "none"
ctx.drawImage(editor.canvas_current, 0, 0)
editor.setBrush(editor.layers.overlay)
ctx.stroke()
editor.canvas_current.style.opacity = 0
}
},
end: (editor, ctx, x, y, is_overlay = false) => {
ctx.stroke()
if (is_overlay) {
ctx.clearRect(0, 0, editor.width, editor.height)
editor.canvas_current.style.opacity = ""
}
},
setBrush: (editor, layer) => {
layer.ctx.globalCompositeOperation = "destination-out"
}
},
{
id: "fill",
name: "Fill",
icon: "fa-solid fa-fill",
cursor: "url(/media/images/fa-fill.svg) 20 6, pointer",
begin: (editor, ctx, x, y, is_overlay = false) => {
if (!is_overlay) {
var color = hexToRgb(ctx.fillStyle)
color.a = parseInt(ctx.globalAlpha * 255) // layer.ctx.globalAlpha
flood_fill(editor, ctx, parseInt(x), parseInt(y), color)
}
},
move: toolDoNothing,
end: toolDoNothing
},
{
id: "colorpicker",
name: "Picker",
icon: "fa-solid fa-eye-dropper",
cursor: "url(/media/images/fa-eye-dropper.svg) 0 24, pointer",
begin: (editor, ctx, x, y, is_overlay = false) => {
if (!is_overlay) {
var img_rgb = editor.layers.background.ctx.getImageData(x, y, 1, 1).data
var drawn_rgb = editor.ctx_current.getImageData(x, y, 1, 1).data
var drawn_opacity = drawn_rgb[3] / 255
editor.custom_color_input.value = rgbToHex({
r: (drawn_rgb[0] * drawn_opacity) + (img_rgb[0] * (1 - drawn_opacity)),
g: (drawn_rgb[1] * drawn_opacity) + (img_rgb[1] * (1 - drawn_opacity)),
b: (drawn_rgb[2] * drawn_opacity) + (img_rgb[2] * (1 - drawn_opacity)),
})
editor.custom_color_input.dispatchEvent(new Event("change"))
}
},
move: toolDoNothing,
end: toolDoNothing
}
]
const IMAGE_EDITOR_ACTIONS = [
{
id: "load_mask",
name: "Load mask from file",
className: "load_mask",
icon: "fa-regular fa-folder-open",
handler: (editor) => {
let el = document.createElement('input')
el.setAttribute("type", "file")
el.addEventListener("change", function() {
if (this.files.length === 0) {
return
}
let reader = new FileReader()
let file = this.files[0]
reader.addEventListener('load', function(event) {
let maskData = reader.result
editor.layers.drawing.ctx.clearRect(0, 0, editor.width, editor.height)
var image = new Image()
image.onload = () => {
editor.layers.drawing.ctx.drawImage(image, 0, 0, editor.width, editor.height)
}
image.src = maskData
})
if (file) {
reader.readAsDataURL(file)
}
})
el.click()
},
trackHistory: true
},
{
id: "fill_all",
name: "Fill all",
icon: "fa-solid fa-paint-roller",
handler: (editor) => {
editor.ctx_current.globalCompositeOperation = "source-over"
editor.ctx_current.rect(0, 0, editor.width, editor.height)
editor.ctx_current.fill()
editor.setBrush()
},
trackHistory: true
},
{
id: "clear",
name: "Clear",
icon: "fa-solid fa-xmark",
handler: (editor) => {
editor.ctx_current.clearRect(0, 0, editor.width, editor.height)
},
trackHistory: true
},
{
id: "undo",
name: "Undo",
icon: "fa-solid fa-rotate-left",
handler: (editor) => {
editor.history.undo()
},
trackHistory: false
},
{
id: "redo",
name: "Redo",
icon: "fa-solid fa-rotate-right",
handler: (editor) => {
editor.history.redo()
},
trackHistory: false
}
]
var IMAGE_EDITOR_SECTIONS = [
{
name: "tool",
title: "Tool",
default: "draw",
options: Array.from(IMAGE_EDITOR_TOOLS.map(t => t.id)),
initElement: (element, option) => {
var tool_info = IMAGE_EDITOR_TOOLS.find(t => t.id == option)
element.className = "image-editor-button button"
var sub_element = document.createElement("div")
var icon = document.createElement("i")
tool_info.icon.split(" ").forEach(c => icon.classList.add(c))
sub_element.appendChild(icon)
sub_element.append(tool_info.name)
element.appendChild(sub_element)
}
},
{
name: "color",
title: "Color",
default: "#f1c232",
options: [
"custom",
"#ea9999", "#e06666", "#cc0000", "#990000", "#660000",
"#f9cb9c", "#f6b26b", "#e69138", "#b45f06", "#783f04",
"#ffe599", "#ffd966", "#f1c232", "#bf9000", "#7f6000",
"#b6d7a8", "#93c47d", "#6aa84f", "#38761d", "#274e13",
"#a4c2f4", "#6d9eeb", "#3c78d8", "#1155cc", "#1c4587",
"#b4a7d6", "#8e7cc3", "#674ea7", "#351c75", "#20124d",
"#d5a6bd", "#c27ba0", "#a64d79", "#741b47", "#4c1130",
"#ffffff", "#c0c0c0", "#838383", "#525252", "#000000",
],
initElement: (element, option) => {
if (option == "custom") {
var input = document.createElement("input")
input.type = "color"
element.appendChild(input)
var span = document.createElement("span")
span.textContent = "Custom"
span.onclick = function(e) {
input.click()
}
element.appendChild(span)
}
else {
element.style.background = option
}
},
getCustom: editor => {
var input = editor.popup.querySelector(".image_editor_color input")
return input.value
}
},
{
name: "brush_size",
title: "Brush Size",
default: 48,
options: [ 6, 12, 16, 24, 30, 40, 48, 64 ],
initElement: (element, option) => {
element.parentElement.style.flex = option
element.style.width = option + "px"
element.style.height = option + "px"
element.style['margin-right'] = '2px'
element.style["border-radius"] = (option / 2).toFixed() + "px"
}
},
{
name: "opacity",
title: "Opacity",
default: 0,
options: [ 0, 0.2, 0.4, 0.6, 0.8 ],
initElement: (element, option) => {
element.style.background = `repeating-conic-gradient(rgba(0, 0, 0, ${option}) 0% 25%, rgba(255, 255, 255, ${option}) 0% 50%) 50% / 10px 10px`
}
},
{
name: "sharpness",
title: "Sharpness",
default: 0,
options: [ 0, 0.05, 0.1, 0.2, 0.3 ],
initElement: (element, option) => {
var size = 32
var blur_amount = parseInt(option * size)
var sub_element = document.createElement("div")
sub_element.style.background = `var(--background-color3)`
sub_element.style.filter = `blur(${blur_amount}px)`
sub_element.style.width = `${size - 2}px`
sub_element.style.height = `${size - 2}px`
sub_element.style['border-radius'] = `${size}px`
element.style.background = "none"
element.appendChild(sub_element)
}
}
]
class EditorHistory {
constructor(editor) {
this.editor = editor
this.events = [] // stack of all events (actions/edits)
this.current_edit = null
this.rewind_index = 0 // how many events back into the history we've rewound to. (current state is just after event at index 'length - this.rewind_index - 1')
}
push(event) {
// probably add something here eventually to save state every x events
if (this.rewind_index != 0) {
this.events = this.events.slice(0, 0 - this.rewind_index)
this.rewind_index = 0
}
var snapshot_frequency = 20 // (every x edits, take a snapshot of the current drawing state, for faster rewinding)
if (this.events.length > 0 && this.events.length % snapshot_frequency == 0) {
event.snapshot = this.editor.layers.drawing.ctx.getImageData(0, 0, this.editor.width, this.editor.height)
}
this.events.push(event)
}
pushAction(action) {
this.push({
type: "action",
id: action
});
}
editBegin(x, y) {
this.current_edit = {
type: "edit",
id: this.editor.getOptionValue("tool"),
options: Object.assign({}, this.editor.options),
points: [ { x: x, y: y } ]
}
}
editMove(x, y) {
if (this.current_edit) {
this.current_edit.points.push({ x: x, y: y })
}
}
editEnd(x, y) {
if (this.current_edit) {
this.push(this.current_edit)
this.current_edit = null
}
}
clear() {
this.events = []
}
undo() {
this.rewindTo(this.rewind_index + 1)
}
redo() {
this.rewindTo(this.rewind_index - 1)
}
rewindTo(new_rewind_index) {
if (new_rewind_index < 0 || new_rewind_index > this.events.length) {
return; // do nothing if target index is out of bounds
}
var ctx = this.editor.layers.drawing.ctx
ctx.clearRect(0, 0, this.editor.width, this.editor.height)
var target_index = this.events.length - 1 - new_rewind_index
var snapshot_index = target_index
while (snapshot_index > -1) {
if (this.events[snapshot_index].snapshot) {
break
}
snapshot_index--
}
if (snapshot_index != -1) {
ctx.putImageData(this.events[snapshot_index].snapshot, 0, 0);
}
for (var i = (snapshot_index + 1); i <= target_index; i++) {
var event = this.events[i]
if (event.type == "action") {
var action = IMAGE_EDITOR_ACTIONS.find(a => a.id == event.id)
action.handler(this.editor)
}
else if (event.type == "edit") {
var tool = IMAGE_EDITOR_TOOLS.find(t => t.id == event.id)
this.editor.setBrush(this.editor.layers.drawing, event.options)
var first_point = event.points[0]
tool.begin(this.editor, ctx, first_point.x, first_point.y)
for (var point_i = 1; point_i < event.points.length; point_i++) {
tool.move(this.editor, ctx, event.points[point_i].x, event.points[point_i].y)
}
var last_point = event.points[event.points.length - 1]
tool.end(this.editor, ctx, last_point.x, last_point.y)
}
}
// re-set brush to current settings
this.editor.setBrush(this.editor.layers.drawing)
this.rewind_index = new_rewind_index
}
}
class ImageEditor {
constructor(popup, inpainter = false) {
this.inpainter = inpainter
this.popup = popup
this.history = new EditorHistory(this)
if (inpainter) {
this.popup.classList.add("inpainter")
}
this.drawing = false
this.temp_previous_tool = null // used for the ctrl-colorpicker functionality
this.container = popup.querySelector(".editor-controls-center > div")
this.layers = {}
var layer_names = [
"background",
"drawing",
"overlay"
]
layer_names.forEach(name => {
let canvas = document.createElement("canvas")
canvas.className = `editor-canvas-${name}`
this.container.appendChild(canvas)
this.layers[name] = {
name: name,
canvas: canvas,
ctx: canvas.getContext("2d")
}
})
// add mouse handlers
this.container.addEventListener("mousedown", this.mouseHandler.bind(this))
this.container.addEventListener("mouseup", this.mouseHandler.bind(this))
this.container.addEventListener("mousemove", this.mouseHandler.bind(this))
this.container.addEventListener("mouseout", this.mouseHandler.bind(this))
this.container.addEventListener("mouseenter", this.mouseHandler.bind(this))
this.container.addEventListener("touchstart", this.mouseHandler.bind(this))
this.container.addEventListener("touchmove", this.mouseHandler.bind(this))
this.container.addEventListener("touchcancel", this.mouseHandler.bind(this))
this.container.addEventListener("touchend", this.mouseHandler.bind(this))
// initialize editor controls
this.options = {}
this.optionElements = {}
IMAGE_EDITOR_SECTIONS.forEach(section => {
section.id = `image_editor_${section.name}`
var sectionElement = document.createElement("div")
sectionElement.className = section.id
var title = document.createElement("h4")
title.innerText = section.title
sectionElement.appendChild(title)
var optionsContainer = document.createElement("div")
optionsContainer.classList.add("editor-options-container")
this.optionElements[section.name] = []
section.options.forEach((option, index) => {
var optionHolder = document.createElement("div")
var optionElement = document.createElement("div")
optionHolder.appendChild(optionElement)
section.initElement(optionElement, option)
optionElement.addEventListener("click", target => this.selectOption(section.name, index))
optionsContainer.appendChild(optionHolder)
this.optionElements[section.name].push(optionElement)
})
this.selectOption(section.name, section.options.indexOf(section.default))
sectionElement.appendChild(optionsContainer)
this.popup.querySelector(".editor-controls-left").appendChild(sectionElement)
})
this.custom_color_input = this.popup.querySelector(`input[type="color"]`)
this.custom_color_input.addEventListener("change", () => {
this.custom_color_input.parentElement.style.background = this.custom_color_input.value
this.selectOption("color", 0)
})
if (this.inpainter) {
this.selectOption("color", IMAGE_EDITOR_SECTIONS.find(s => s.name == "color").options.indexOf("#ffffff"))
this.selectOption("opacity", IMAGE_EDITOR_SECTIONS.find(s => s.name == "opacity").options.indexOf(0.4))
}
// initialize the right-side controls
var buttonContainer = document.createElement("div")
IMAGE_EDITOR_BUTTONS.forEach(button => {
var element = document.createElement("div")
var icon = document.createElement("i")
element.className = "image-editor-button button"
icon.className = button.icon
element.appendChild(icon)
element.append(button.name)
buttonContainer.appendChild(element)
element.addEventListener("click", event => button.handler(this))
})
var actionsContainer = document.createElement("div")
var actionsTitle = document.createElement("h4")
actionsTitle.textContent = "Actions"
actionsContainer.appendChild(actionsTitle);
IMAGE_EDITOR_ACTIONS.forEach(action => {
var element = document.createElement("div")
var icon = document.createElement("i")
element.className = "image-editor-button button"
if (action.className) {
element.className += " " + action.className
}
icon.className = action.icon
element.appendChild(icon)
element.append(action.name)
actionsContainer.appendChild(element)
element.addEventListener("click", event => this.runAction(action.id))
})
this.popup.querySelector(".editor-controls-right").appendChild(actionsContainer)
this.popup.querySelector(".editor-controls-right").appendChild(buttonContainer)
this.keyHandlerBound = this.keyHandler.bind(this)
this.setSize(512, 512)
}
show() {
this.popup.classList.add("active")
document.addEventListener("keydown", this.keyHandlerBound)
document.addEventListener("keyup", this.keyHandlerBound)
}
hide() {
this.popup.classList.remove("active")
document.removeEventListener("keydown", this.keyHandlerBound)
document.removeEventListener("keyup", this.keyHandlerBound)
}
setSize(width, height) {
if (width == this.width && height == this.height) {
return
}
if (width > height) {
var max_size = Math.min(parseInt(window.innerWidth * 0.9), width, 768)
var multiplier = max_size / width
width = (multiplier * width).toFixed()
height = (multiplier * height).toFixed()
}
else {
var max_size = Math.min(parseInt(window.innerHeight * 0.9), height, 768)
var multiplier = max_size / height
width = (multiplier * width).toFixed()
height = (multiplier * height).toFixed()
}
this.width = parseInt(width)
this.height = parseInt(height)
this.container.style.width = width + "px"
this.container.style.height = height + "px"
Object.values(this.layers).forEach(layer => {
layer.canvas.width = width
layer.canvas.height = height
})
if (this.inpainter) {
this.saveImage() // We've reset the size of the image so inpainting is different
}
this.setBrush()
this.history.clear()
}
get tool() {
var tool_id = this.getOptionValue("tool")
return IMAGE_EDITOR_TOOLS.find(t => t.id == tool_id);
}
loadTool() {
this.drawing = false
this.container.style.cursor = this.tool.cursor;
}
setImage(url, width, height) {
this.setSize(width, height)
this.layers.background.ctx.clearRect(0, 0, this.width, this.height)
if (!(url && this.inpainter)) {
this.layers.drawing.ctx.clearRect(0, 0, this.width, this.height)
}
if (url) {
var image = new Image()
image.onload = () => {
this.layers.background.ctx.drawImage(image, 0, 0, this.width, this.height)
}
image.src = url
}
else {
this.layers.background.ctx.fillStyle = "#ffffff"
this.layers.background.ctx.beginPath()
this.layers.background.ctx.rect(0, 0, this.width, this.height)
this.layers.background.ctx.fill()
}
this.history.clear()
}
saveImage() {
if (!this.inpainter) {
// This is not an inpainter, so save the image as the new img2img input
this.layers.background.ctx.drawImage(this.layers.drawing.canvas, 0, 0, this.width, this.height)
var base64 = this.layers.background.canvas.toDataURL()
initImagePreview.src = base64 // this will trigger the rest of the app to use it
}
else {
// This is an inpainter, so make sure the toggle is set accordingly
var is_blank = !this.layers.drawing.ctx
.getImageData(0, 0, this.width, this.height).data
.some(channel => channel !== 0)
maskSetting.checked = !is_blank
}
this.hide()
}
getImg() { // a drop-in replacement of the drawingboard version
return this.layers.drawing.canvas.toDataURL()
}
setImg(dataUrl) { // a drop-in replacement of the drawingboard version
var image = new Image()
image.onload = () => {
var ctx = this.layers.drawing.ctx;
ctx.clearRect(0, 0, this.width, this.height)
ctx.globalCompositeOperation = "source-over"
ctx.globalAlpha = 1
ctx.filter = "none"
ctx.drawImage(image, 0, 0, this.width, this.height)
this.setBrush(this.layers.drawing)
}
image.src = dataUrl
}
runAction(action_id) {
var action = IMAGE_EDITOR_ACTIONS.find(a => a.id == action_id)
if (action.trackHistory) {
this.history.pushAction(action_id)
}
action.handler(this)
}
setBrush(layer = null, options = null) {
if (options == null) {
options = this.options
}
if (layer) {
layer.ctx.lineCap = "round"
layer.ctx.lineJoin = "round"
layer.ctx.lineWidth = options.brush_size
layer.ctx.fillStyle = options.color
layer.ctx.strokeStyle = options.color
var sharpness = parseInt(options.sharpness * options.brush_size)
layer.ctx.filter = sharpness == 0 ? `none` : `blur(${sharpness}px)`
layer.ctx.globalAlpha = (1 - options.opacity)
layer.ctx.globalCompositeOperation = "source-over"
var tool = IMAGE_EDITOR_TOOLS.find(t => t.id == options.tool)
if (tool && tool.setBrush) {
tool.setBrush(editor, layer)
}
}
else {
Object.values([ "drawing", "overlay" ]).map(name => this.layers[name]).forEach(l => {
this.setBrush(l)
})
}
}
get ctx_overlay() {
return this.layers.overlay.ctx
}
get ctx_current() { // the idea is this will help support having custom layers and editing each one
return this.layers.drawing.ctx
}
get canvas_current() {
return this.layers.drawing.canvas
}
keyHandler(event) { // handles keybinds like ctrl+z, ctrl+y
if (!this.popup.classList.contains("active")) {
document.removeEventListener("keydown", this.keyHandlerBound)
document.removeEventListener("keyup", this.keyHandlerBound)
return // this catches if something else closes the window but doesnt properly unbind the key handler
}
// keybindings
if (event.type == "keydown") {
if ((event.key == "z" || event.key == "Z") && event.ctrlKey) {
if (!event.shiftKey) {
this.history.undo()
}
else {
this.history.redo()
}
}
if (event.key == "y" && event.ctrlKey) {
this.history.redo()
}
if (event.key === "Escape") {
this.hide()
}
}
// dropper ctrl holding handler stuff
var dropper_active = this.temp_previous_tool != null;
if (dropper_active && !event.ctrlKey) {
this.selectOption("tool", IMAGE_EDITOR_TOOLS.findIndex(t => t.id == this.temp_previous_tool))
this.temp_previous_tool = null
}
else if (!dropper_active && event.ctrlKey) {
this.temp_previous_tool = this.getOptionValue("tool")
this.selectOption("tool", IMAGE_EDITOR_TOOLS.findIndex(t => t.id == "colorpicker"))
}
}
mouseHandler(event) {
var bbox = this.layers.overlay.canvas.getBoundingClientRect()
var x = (event.clientX || 0) - bbox.left
var y = (event.clientY || 0) - bbox.top
var type = event.type;
var touchmap = {
touchstart: "mousedown",
touchmove: "mousemove",
touchend: "mouseup",
touchcancel: "mouseup"
}
if (type in touchmap) {
type = touchmap[type]
if (event.touches && event.touches[0]) {
var touch = event.touches[0]
var x = (touch.clientX || 0) - bbox.left
var y = (touch.clientY || 0) - bbox.top
}
}
event.preventDefault()
// do drawing-related stuff
if (type == "mousedown" || (type == "mouseenter" && event.buttons == 1)) {
this.drawing = true
this.tool.begin(this, this.ctx_current, x, y)
this.tool.begin(this, this.ctx_overlay, x, y, true)
this.history.editBegin(x, y)
}
if (type == "mouseup" || type == "mousemove") {
if (this.drawing) {
if (x > 0 && y > 0) {
this.tool.move(this, this.ctx_current, x, y)
this.tool.move(this, this.ctx_overlay, x, y, true)
this.history.editMove(x, y)
}
}
}
if (type == "mouseup" || type == "mouseout") {
if (this.drawing) {
this.drawing = false
this.tool.end(this, this.ctx_current, x, y)
this.tool.end(this, this.ctx_overlay, x, y, true)
this.history.editEnd(x, y)
}
}
}
getOptionValue(section_name) {
var section = IMAGE_EDITOR_SECTIONS.find(s => s.name == section_name)
return this.options && section_name in this.options ? this.options[section_name] : section.default
}
selectOption(section_name, option_index) {
var section = IMAGE_EDITOR_SECTIONS.find(s => s.name == section_name)
var value = section.options[option_index]
this.options[section_name] = value == "custom" ? section.getCustom(this) : value
this.optionElements[section_name].forEach(element => element.classList.remove("active"))
this.optionElements[section_name][option_index].classList.add("active")
// change the editor
this.setBrush()
if (section.name == "tool") {
this.loadTool()
}
}
}
const imageEditor = new ImageEditor(document.getElementById("image-editor"))
const imageInpainter = new ImageEditor(document.getElementById("image-inpainter"), true)
imageEditor.setImage(null, 512, 512)
imageInpainter.setImage(null, 512, 512)
document.getElementById("init_image_button_draw").addEventListener("click", () => {
imageEditor.show()
})
document.getElementById("init_image_button_inpaint").addEventListener("click", () => {
imageInpainter.show()
})
img2imgUnload() // no init image when the app starts
function rgbToHex(rgb) {
function componentToHex(c) {
var hex = parseInt(c).toString(16)
return hex.length == 1 ? "0" + hex : hex
}
return "#" + componentToHex(rgb.r) + componentToHex(rgb.g) + componentToHex(rgb.b)
}
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function pixelCompare(int1, int2) {
return Math.abs(int1 - int2) < 4
}
// adapted from https://ben.akrin.com/canvas_fill/fill_04.html
function flood_fill(editor, the_canvas_context, x, y, color) {
pixel_stack = [{x:x, y:y}] ;
pixels = the_canvas_context.getImageData( 0, 0, editor.width, editor.height ) ;
var linear_cords = ( y * editor.width + x ) * 4 ;
var original_color = {r:pixels.data[linear_cords],
g:pixels.data[linear_cords+1],
b:pixels.data[linear_cords+2],
a:pixels.data[linear_cords+3]} ;
var opacity = color.a / 255;
var new_color = {
r: parseInt((color.r * opacity) + (original_color.r * (1 - opacity))),
g: parseInt((color.g * opacity) + (original_color.g * (1 - opacity))),
b: parseInt((color.b * opacity) + (original_color.b * (1 - opacity)))
}
if ((pixelCompare(new_color.r, original_color.r) &&
pixelCompare(new_color.g, original_color.g) &&
pixelCompare(new_color.b, original_color.b)))
{
return; // This color is already the color we want, so do nothing
}
var max_stack_size = editor.width * editor.height;
while( pixel_stack.length > 0 && pixel_stack.length < max_stack_size ) {
new_pixel = pixel_stack.shift() ;
x = new_pixel.x ;
y = new_pixel.y ;
linear_cords = ( y * editor.width + x ) * 4 ;
while( y-->=0 &&
(pixelCompare(pixels.data[linear_cords], original_color.r) &&
pixelCompare(pixels.data[linear_cords+1], original_color.g) &&
pixelCompare(pixels.data[linear_cords+2], original_color.b))) {
linear_cords -= editor.width * 4 ;
}
linear_cords += editor.width * 4 ;
y++ ;
var reached_left = false ;
var reached_right = false ;
while( y++<editor.height &&
(pixelCompare(pixels.data[linear_cords], original_color.r) &&
pixelCompare(pixels.data[linear_cords+1], original_color.g) &&
pixelCompare(pixels.data[linear_cords+2], original_color.b))) {
pixels.data[linear_cords] = new_color.r ;
pixels.data[linear_cords+1] = new_color.g ;
pixels.data[linear_cords+2] = new_color.b ;
pixels.data[linear_cords+3] = 255 ;
if( x>0 ) {
if( pixelCompare(pixels.data[linear_cords-4], original_color.r) &&
pixelCompare(pixels.data[linear_cords-4+1], original_color.g) &&
pixelCompare(pixels.data[linear_cords-4+2], original_color.b)) {
if( !reached_left ) {
pixel_stack.push( {x:x-1, y:y} ) ;
reached_left = true ;
}
} else if( reached_left ) {
reached_left = false ;
}
}
if( x<editor.width-1 ) {
if( pixelCompare(pixels.data[linear_cords+4], original_color.r) &&
pixelCompare(pixels.data[linear_cords+4+1], original_color.g) &&
pixelCompare(pixels.data[linear_cords+4+2], original_color.b)) {
if( !reached_right ) {
pixel_stack.push( {x:x+1,y:y} ) ;
reached_right = true ;
}
} else if( reached_right ) {
reached_right = false ;
}
}
linear_cords += editor.width * 4 ;
}
}
the_canvas_context.putImageData( pixels, 0, 0 ) ;
}

View File

@ -0,0 +1,360 @@
let activeTags = []
let modifiers = []
let customModifiersGroupElement = undefined
let editorModifierEntries = document.querySelector('#editor-modifiers-entries')
let editorModifierTagsList = document.querySelector('#editor-inputs-tags-list')
let editorTagsContainer = document.querySelector('#editor-inputs-tags-container')
let modifierCardSizeSlider = document.querySelector('#modifier-card-size-slider')
let previewImageField = document.querySelector('#preview-image')
let modifierSettingsBtn = document.querySelector('#modifier-settings-btn')
let modifierSettingsOverlay = document.querySelector('#modifier-settings-config')
let customModifiersTextBox = document.querySelector('#custom-modifiers-input')
let customModifierEntriesToolbar = document.querySelector('#editor-modifiers-entries-toolbar')
const modifierThumbnailPath = 'media/modifier-thumbnails'
const activeCardClass = 'modifier-card-active'
const CUSTOM_MODIFIERS_KEY = "customModifiers"
function createModifierCard(name, previews, removeBy) {
const modifierCard = document.createElement('div')
modifierCard.className = 'modifier-card'
modifierCard.innerHTML = `
<div class="modifier-card-overlay"></div>
<div class="modifier-card-image-container">
<div class="modifier-card-image-overlay">+</div>
<p class="modifier-card-error-label"></p>
<img onerror="this.remove()" alt="Modifier Image" class="modifier-card-image">
</div>
<div class="modifier-card-container">
<div class="modifier-card-label"><p></p></div>
</div>`
const image = modifierCard.querySelector('.modifier-card-image')
const errorText = modifierCard.querySelector('.modifier-card-error-label')
const label = modifierCard.querySelector('.modifier-card-label')
errorText.innerText = 'No Image'
if (typeof previews == 'object') {
image.src = previews[0]; // portrait
image.setAttribute('preview-type', 'portrait')
} else {
image.remove()
}
const maxLabelLength = 30
const cardLabel = removeBy ? name.replace('by ', '') : name
if(cardLabel.length <= maxLabelLength) {
label.querySelector('p').innerText = cardLabel
} else {
const tooltipText = document.createElement('span')
tooltipText.className = 'tooltip-text'
tooltipText.innerText = name
label.classList.add('tooltip')
label.appendChild(tooltipText)
label.querySelector('p').innerText = cardLabel.substring(0, maxLabelLength) + '...'
}
label.querySelector('p').dataset.fullName = name // preserve the full name
return modifierCard
}
function createModifierGroup(modifierGroup, initiallyExpanded, removeBy) {
const title = modifierGroup.category
const modifiers = modifierGroup.modifiers
const titleEl = document.createElement('h5')
titleEl.className = 'collapsible'
titleEl.innerText = title
const modifiersEl = document.createElement('div')
modifiersEl.classList.add('collapsible-content', 'editor-modifiers-leaf')
if (initiallyExpanded === true) {
titleEl.className += ' active'
}
modifiers.forEach(modObj => {
const modifierName = modObj.modifier
const modifierPreviews = modObj?.previews?.map(preview => `${IMAGE_REGEX.test(preview.image) ? preview.image : modifierThumbnailPath + '/' + preview.path}`)
const modifierCard = createModifierCard(modifierName, modifierPreviews, removeBy)
if(typeof modifierCard == 'object') {
modifiersEl.appendChild(modifierCard)
const trimmedName = trimModifiers(modifierName)
modifierCard.addEventListener('click', () => {
if (activeTags.map(x => trimModifiers(x.name)).includes(trimmedName)) {
// remove modifier from active array
activeTags = activeTags.filter(x => trimModifiers(x.name) != trimmedName)
toggleCardState(trimmedName, false)
} else {
// add modifier to active array
activeTags.push({
'name': modifierName,
'element': modifierCard.cloneNode(true),
'originElement': modifierCard,
'previews': modifierPreviews
})
toggleCardState(trimmedName, true)
}
refreshTagsList()
document.dispatchEvent(new Event('refreshImageModifiers'))
})
}
})
let brk = document.createElement('br')
brk.style.clear = 'both'
modifiersEl.appendChild(brk)
let e = document.createElement('div')
e.className = 'modifier-category'
e.appendChild(titleEl)
e.appendChild(modifiersEl)
editorModifierEntries.insertBefore(e, customModifierEntriesToolbar.nextSibling)
return e
}
function trimModifiers(tag) {
return tag.replace(/^\(+|\)+$/g, '').replace(/^\[+|\]+$/g, '')
}
async function loadModifiers() {
try {
let res = await fetch('/get/modifiers')
if (res.status === 200) {
res = await res.json()
modifiers = res; // update global variable
res.reverse()
res.forEach((modifierGroup, idx) => {
createModifierGroup(modifierGroup, idx === res.length - 1, modifierGroup === 'Artist' ? true : false) // only remove "By " for artists
})
createCollapsibles(editorModifierEntries)
}
} catch (e) {
console.log('error fetching modifiers', e)
}
loadCustomModifiers()
document.dispatchEvent(new Event('loadImageModifiers'))
}
function refreshModifiersState(newTags) {
// clear existing modifiers
document.querySelector('#editor-modifiers').querySelectorAll('.modifier-card').forEach(modifierCard => {
const modifierName = modifierCard.querySelector('.modifier-card-label p').dataset.fullName // pick the full modifier name
if (activeTags.map(x => x.name).includes(modifierName)) {
modifierCard.classList.remove(activeCardClass)
modifierCard.querySelector('.modifier-card-image-overlay').innerText = '+'
}
})
activeTags = []
// set new modifiers
newTags.forEach(tag => {
let found = false
document.querySelector('#editor-modifiers').querySelectorAll('.modifier-card').forEach(modifierCard => {
const modifierName = modifierCard.querySelector('.modifier-card-label p').dataset.fullName
const shortModifierName = modifierCard.querySelector('.modifier-card-label p').innerText
if (trimModifiers(tag) == trimModifiers(modifierName)) {
// add modifier to active array
if (!activeTags.map(x => x.name).includes(tag)) { // only add each tag once even if several custom modifier cards share the same tag
const imageModifierCard = modifierCard.cloneNode(true)
imageModifierCard.querySelector('.modifier-card-label p').innerText = shortModifierName
activeTags.push({
'name': modifierName,
'element': imageModifierCard,
'originElement': modifierCard
})
}
modifierCard.classList.add(activeCardClass)
modifierCard.querySelector('.modifier-card-image-overlay').innerText = '-'
found = true
}
})
if (found == false) { // custom tag went missing, create one here
let modifierCard = createModifierCard(tag, undefined, false) // create a modifier card for the missing tag, no image
modifierCard.addEventListener('click', () => {
if (activeTags.map(x => x.name).includes(tag)) {
// remove modifier from active array
activeTags = activeTags.filter(x => x.name != tag)
modifierCard.classList.remove(activeCardClass)
modifierCard.querySelector('.modifier-card-image-overlay').innerText = '+'
}
refreshTagsList()
})
activeTags.push({
'name': tag,
'element': modifierCard,
'originElement': undefined // no origin element for missing tags
})
}
})
refreshTagsList()
}
function refreshInactiveTags(inactiveTags) {
// update inactive tags
if (inactiveTags !== undefined && inactiveTags.length > 0) {
activeTags.forEach (tag => {
if (inactiveTags.find(element => element === tag.name) !== undefined) {
tag.inactive = true
}
})
}
// update cards
let overlays = document.querySelector('#editor-inputs-tags-list').querySelectorAll('.modifier-card-overlay')
overlays.forEach (i => {
let modifierName = i.parentElement.getElementsByClassName('modifier-card-label')[0].getElementsByTagName("p")[0].innerText
if (inactiveTags.find(element => element === modifierName) !== undefined) {
i.parentElement.classList.add('modifier-toggle-inactive')
}
})
}
function refreshTagsList() {
editorModifierTagsList.innerHTML = ''
if (activeTags.length == 0) {
editorTagsContainer.style.display = 'none'
return
} else {
editorTagsContainer.style.display = 'block'
}
activeTags.forEach((tag, index) => {
tag.element.querySelector('.modifier-card-image-overlay').innerText = '-'
tag.element.classList.add('modifier-card-tiny')
editorModifierTagsList.appendChild(tag.element)
tag.element.addEventListener('click', () => {
let idx = activeTags.findIndex(o => { return o.name === tag.name })
if (idx !== -1) {
toggleCardState(activeTags[idx].name, false)
activeTags.splice(idx, 1)
refreshTagsList()
}
document.dispatchEvent(new Event('refreshImageModifiers'))
})
})
let brk = document.createElement('br')
brk.style.clear = 'both'
editorModifierTagsList.appendChild(brk)
}
function toggleCardState(modifierName, makeActive) {
document.querySelector('#editor-modifiers').querySelectorAll('.modifier-card').forEach(card => {
const name = card.querySelector('.modifier-card-label').innerText
if ( trimModifiers(modifierName) == trimModifiers(name)
|| trimModifiers(modifierName) == 'by ' + trimModifiers(name)) {
if(makeActive) {
card.classList.add(activeCardClass)
card.querySelector('.modifier-card-image-overlay').innerText = '-'
}
else{
card.classList.remove(activeCardClass)
card.querySelector('.modifier-card-image-overlay').innerText = '+'
}
}
})
}
function changePreviewImages(val) {
const previewImages = document.querySelectorAll('.modifier-card-image-container img')
let previewArr = []
modifiers.map(x => x.modifiers).forEach(x => previewArr.push(...x.map(m => m.previews)))
previewArr = previewArr.map(x => {
let obj = {}
x.forEach(preview => {
obj[preview.name] = preview.path
})
return obj
})
previewImages.forEach(previewImage => {
const currentPreviewType = previewImage.getAttribute('preview-type')
const relativePreviewPath = previewImage.src.split(modifierThumbnailPath + '/').pop()
const previews = previewArr.find(preview => relativePreviewPath == preview[currentPreviewType])
if(typeof previews == 'object') {
let preview = null
if (val == 'portrait') {
preview = previews.portrait
}
else if (val == 'landscape') {
preview = previews.landscape
}
if(preview != null) {
previewImage.src = `${modifierThumbnailPath}/${preview}`
previewImage.setAttribute('preview-type', val)
}
}
})
}
function resizeModifierCards(val) {
const cardSizePrefix = 'modifier-card-size_'
const modifierCardClass = 'modifier-card'
const modifierCards = document.querySelectorAll(`.${modifierCardClass}`)
const cardSize = n => `${cardSizePrefix}${n}`
modifierCards.forEach(card => {
// remove existing size classes
const classes = card.className.split(' ').filter(c => !c.startsWith(cardSizePrefix))
card.className = classes.join(' ').trim()
if(val != 0) {
card.classList.add(cardSize(val))
}
})
}
modifierCardSizeSlider.onchange = () => resizeModifierCards(modifierCardSizeSlider.value)
previewImageField.onchange = () => changePreviewImages(previewImageField.value)
modifierSettingsBtn.addEventListener('click', function(e) {
modifierSettingsOverlay.classList.add("active")
e.stopPropagation()
})
function saveCustomModifiers() {
localStorage.setItem(CUSTOM_MODIFIERS_KEY, customModifiersTextBox.value.trim())
loadCustomModifiers()
}
function loadCustomModifiers() {
PLUGINS['MODIFIERS_LOAD'].forEach(fn=>fn.loader.call())
}
customModifiersTextBox.addEventListener('change', saveCustomModifiers)

10
ui/media/js/jquery-confirm.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1553
ui/media/js/main.js Normal file

File diff suppressed because it is too large Load Diff

6
ui/media/js/marked.min.js vendored Normal file

File diff suppressed because one or more lines are too long

479
ui/media/js/parameters.js Normal file
View File

@ -0,0 +1,479 @@
/**
* Enum of parameter types
* @readonly
* @enum {string}
*/
var ParameterType = {
checkbox: "checkbox",
select: "select",
select_multiple: "select_multiple",
slider: "slider",
custom: "custom",
};
/**
* JSDoc style
* @typedef {object} Parameter
* @property {string} id
* @property {ParameterType} type
* @property {string} label
* @property {?string} note
* @property {number|boolean|string} default
*/
/** @type {Array.<Parameter>} */
var PARAMETERS = [
{
id: "theme",
type: ParameterType.select,
label: "Theme",
default: "theme-default",
note: "customize the look and feel of the ui",
options: [ // Note: options expanded dynamically
{
value: "theme-default",
label: "Default"
}
],
icon: "fa-palette"
},
{
id: "save_to_disk",
type: ParameterType.checkbox,
label: "Auto-Save Images",
note: "automatically saves images to the specified location",
icon: "fa-download",
default: false,
},
{
id: "diskPath",
type: ParameterType.custom,
label: "Save Location",
render: (parameter) => {
return `<input id="${parameter.id}" name="${parameter.id}" size="30" disabled>`
}
},
{
id: "metadata_output_format",
type: ParameterType.select,
label: "Metadata format",
note: "will be saved to disk in this format",
default: "txt",
options: [
{
value: "none",
label: "none"
},
{
value: "txt",
label: "txt"
},
{
value: "json",
label: "json"
},
{
value: "embed",
label: "embed"
}
],
},
{
id: "block_nsfw",
type: ParameterType.checkbox,
label: "Block NSFW images",
note: "blurs out NSFW images",
icon: "fa-land-mine-on",
default: false,
},
{
id: "sound_toggle",
type: ParameterType.checkbox,
label: "Enable Sound",
note: "plays a sound on task completion",
icon: "fa-volume-low",
default: true,
},
{
id: "process_order_toggle",
type: ParameterType.checkbox,
label: "Process newest jobs first",
note: "reverse the normal processing order",
icon: "fa-arrow-down-short-wide",
default: false,
},
{
id: "ui_open_browser_on_start",
type: ParameterType.checkbox,
label: "Open browser on startup",
note: "starts the default browser on startup",
icon: "fa-window-restore",
default: true,
},
{
id: "vram_usage_level",
type: ParameterType.select,
label: "GPU Memory Usage",
note: "Faster performance requires more GPU memory (VRAM)<br/><br/>" +
"<b>Balanced:</b> nearly as fast as High, much lower VRAM usage<br/>" +
"<b>High:</b> fastest, maximum GPU memory usage</br>" +
"<b>Low:</b> slowest, recommended for GPUs with 3 to 4 GB memory",
icon: "fa-forward",
default: "balanced",
options: [
{value: "balanced", label: "Balanced"},
{value: "high", label: "High"},
{value: "low", label: "Low"}
],
},
{
id: "use_cpu",
type: ParameterType.checkbox,
label: "Use CPU (not GPU)",
note: "warning: this will be *very* slow",
icon: "fa-microchip",
default: false,
},
{
id: "auto_pick_gpus",
type: ParameterType.checkbox,
label: "Automatically pick the GPUs (experimental)",
default: false,
},
{
id: "use_gpus",
type: ParameterType.select_multiple,
label: "GPUs to use (experimental)",
note: "to process in parallel",
default: false,
},
{
id: "auto_save_settings",
type: ParameterType.checkbox,
label: "Auto-Save Settings",
note: "restores settings on browser load",
icon: "fa-gear",
default: true,
},
{
id: "confirm_dangerous_actions",
type: ParameterType.checkbox,
label: "Confirm dangerous actions",
note: "Actions that might lead to data loss must either be clicked with the shift key pressed, or confirmed in an 'Are you sure?' dialog",
icon: "fa-check-double",
default: true,
},
{
id: "listen_to_network",
type: ParameterType.checkbox,
label: "Make Stable Diffusion available on your network",
note: "Other devices on your network can access this web page",
icon: "fa-network-wired",
default: true,
},
{
id: "listen_port",
type: ParameterType.custom,
label: "Network port",
note: "Port that this server listens to. The '9000' part in 'http://localhost:9000'",
icon: "fa-anchor",
render: (parameter) => {
return `<input id="${parameter.id}" name="${parameter.id}" size="6" value="9000" onkeypress="preventNonNumericalInput(event)">`
}
},
{
id: "use_beta_channel",
type: ParameterType.checkbox,
label: "Beta channel",
note: "Get the latest features immediately (but could be less stable). Please restart the program after changing this.",
icon: "fa-fire",
default: false,
},
];
function getParameterSettingsEntry(id) {
let parameter = PARAMETERS.filter(p => p.id === id)
if (parameter.length === 0) {
return
}
return parameter[0].settingsEntry
}
function sliderUpdate(event) {
if (event.srcElement.id.endsWith('-input')) {
let slider = document.getElementById(event.srcElement.id.slice(0,-6))
slider.value = event.srcElement.value
slider.dispatchEvent(new Event("change"))
} else {
let field = document.getElementById(event.srcElement.id+'-input')
field.value = event.srcElement.value
field.dispatchEvent(new Event("change"))
}
}
function getParameterElement(parameter) {
switch (parameter.type) {
case ParameterType.checkbox:
var is_checked = parameter.default ? " checked" : "";
return `<input id="${parameter.id}" name="${parameter.id}"${is_checked} type="checkbox">`
case ParameterType.select:
case ParameterType.select_multiple:
var options = (parameter.options || []).map(option => `<option value="${option.value}">${option.label}</option>`).join("")
var multiple = (parameter.type == ParameterType.select_multiple ? 'multiple' : '')
return `<select id="${parameter.id}" name="${parameter.id}" ${multiple}>${options}</select>`
case ParameterType.slider:
return `<input id="${parameter.id}" name="${parameter.id}" class="editor-slider" type="range" value="${parameter.default}" min="${parameter.slider_min}" max="${parameter.slider_max}" oninput="sliderUpdate(event)"> <input id="${parameter.id}-input" name="${parameter.id}-input" size="4" value="${parameter.default}" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)">&nbsp;${parameter.slider_unit}`
case ParameterType.custom:
return parameter.render(parameter)
default:
console.error(`Invalid type for parameter ${parameter.id}`);
return "ERROR: Invalid Type"
}
}
let parametersTable = document.querySelector("#system-settings .parameters-table")
/* fill in the system settings popup table */
function initParameters() {
PARAMETERS.forEach(parameter => {
var element = getParameterElement(parameter)
var note = parameter.note ? `<small>${parameter.note}</small>` : "";
var icon = parameter.icon ? `<i class="fa ${parameter.icon}"></i>` : "";
var newrow = document.createElement('div')
newrow.innerHTML = `
<div>${icon}</div>
<div><label for="${parameter.id}">${parameter.label}</label>${note}</div>
<div>${element}</div>`
parametersTable.appendChild(newrow)
parameter.settingsEntry = newrow
})
}
initParameters()
let vramUsageLevelField = document.querySelector('#vram_usage_level')
let useCPUField = document.querySelector('#use_cpu')
let autoPickGPUsField = document.querySelector('#auto_pick_gpus')
let useGPUsField = document.querySelector('#use_gpus')
let saveToDiskField = document.querySelector('#save_to_disk')
let diskPathField = document.querySelector('#diskPath')
let metadataOutputFormatField = document.querySelector('#metadata_output_format')
let listenToNetworkField = document.querySelector("#listen_to_network")
let listenPortField = document.querySelector("#listen_port")
let useBetaChannelField = document.querySelector("#use_beta_channel")
let uiOpenBrowserOnStartField = document.querySelector("#ui_open_browser_on_start")
let confirmDangerousActionsField = document.querySelector("#confirm_dangerous_actions")
let saveSettingsBtn = document.querySelector('#save-system-settings-btn')
async function changeAppConfig(configDelta) {
try {
let res = await fetch('/app_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(configDelta)
})
res = await res.json()
console.log('set config status response', res)
} catch (e) {
console.log('set config status error', e)
}
}
async function getAppConfig() {
try {
let res = await fetch('/get/app_config')
const config = await res.json()
if (config.update_branch === 'beta') {
useBetaChannelField.checked = true
document.querySelector("#updateBranchLabel").innerText = "(beta)"
}
if (config.ui && config.ui.open_browser_on_start === false) {
uiOpenBrowserOnStartField.checked = false
}
if (config.net && config.net.listen_to_network === false) {
listenToNetworkField.checked = false
}
if (config.net && config.net.listen_port !== undefined) {
listenPortField.value = config.net.listen_port
}
console.log('get config status response', config)
} catch (e) {
console.log('get config status error', e)
}
}
saveToDiskField.addEventListener('change', function(e) {
diskPathField.disabled = !this.checked
metadataOutputFormatField.disabled = !this.checked
})
function getCurrentRenderDeviceSelection() {
let selectedGPUs = $('#use_gpus').val()
if (useCPUField.checked && !autoPickGPUsField.checked) {
return 'cpu'
}
if (autoPickGPUsField.checked || selectedGPUs.length == 0) {
return 'auto'
}
return selectedGPUs.join(',')
}
useCPUField.addEventListener('click', function() {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
if (this.checked) {
gpuSettingEntry.style.display = 'none'
autoPickGPUSettingEntry.style.display = 'none'
autoPickGPUsField.setAttribute('data-old-value', autoPickGPUsField.checked)
autoPickGPUsField.checked = false
} else if (useGPUsField.options.length >= MIN_GPUS_TO_SHOW_SELECTION) {
gpuSettingEntry.style.display = ''
autoPickGPUSettingEntry.style.display = ''
let oldVal = autoPickGPUsField.getAttribute('data-old-value')
if (oldVal === null || oldVal === undefined) { // the UI started with CPU selected by default
autoPickGPUsField.checked = true
} else {
autoPickGPUsField.checked = (oldVal === 'true')
}
gpuSettingEntry.style.display = (autoPickGPUsField.checked ? 'none' : '')
}
})
useGPUsField.addEventListener('click', function() {
let selectedGPUs = $('#use_gpus').val()
autoPickGPUsField.checked = (selectedGPUs.length === 0)
})
autoPickGPUsField.addEventListener('click', function() {
if (this.checked) {
$('#use_gpus').val([])
}
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = (this.checked ? 'none' : '')
})
async function setDiskPath(defaultDiskPath, force=false) {
var diskPath = getSetting("diskPath")
if (force || diskPath == '' || diskPath == undefined || diskPath == "undefined") {
setSetting("diskPath", defaultDiskPath)
}
}
function setDeviceInfo(devices) {
let cpu = devices.all.cpu.name
let allGPUs = Object.keys(devices.all).filter(d => d != 'cpu')
let activeGPUs = Object.keys(devices.active)
function ID_TO_TEXT(d) {
let info = devices.all[d]
if ("mem_free" in info && "mem_total" in info) {
return `${info.name} <small>(${d}) (${info.mem_free.toFixed(1)}Gb free / ${info.mem_total.toFixed(1)} Gb total)</small>`
} else {
return `${info.name} <small>(${d}) (no memory info)</small>`
}
}
allGPUs = allGPUs.map(ID_TO_TEXT)
activeGPUs = activeGPUs.map(ID_TO_TEXT)
let systemInfoEl = document.querySelector('#system-info')
systemInfoEl.querySelector('#system-info-cpu').innerText = cpu
systemInfoEl.querySelector('#system-info-gpus-all').innerHTML = allGPUs.join('</br>')
systemInfoEl.querySelector('#system-info-rendering-devices').innerHTML = activeGPUs.join('</br>')
}
function setHostInfo(hosts) {
let port = listenPortField.value
hosts = hosts.map(addr => `http://${addr}:${port}/`).map(url => `<div><a href="${url}">${url}</a></div>`)
document.querySelector('#system-info-server-hosts').innerHTML = hosts.join('')
}
async function getSystemInfo() {
try {
const res = await SD.getSystemInfo()
let devices = res['devices']
let allDeviceIds = Object.keys(devices['all']).filter(d => d !== 'cpu')
let activeDeviceIds = Object.keys(devices['active']).filter(d => d !== 'cpu')
if (activeDeviceIds.length === 0) {
useCPUField.checked = true
}
if (allDeviceIds.length < MIN_GPUS_TO_SHOW_SELECTION || useCPUField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
autoPickGPUSettingEntry.style.display = 'none'
}
if (allDeviceIds.length === 0) {
useCPUField.checked = true
useCPUField.disabled = true // no compatible GPUs, so make the CPU mandatory
}
autoPickGPUsField.checked = (devices['config'] === 'auto')
useGPUsField.innerHTML = ''
allDeviceIds.forEach(device => {
let deviceName = devices['all'][device]['name']
let deviceOption = `<option value="${device}">${deviceName} (${device})</option>`
useGPUsField.insertAdjacentHTML('beforeend', deviceOption)
})
if (autoPickGPUsField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
} else {
$('#use_gpus').val(activeDeviceIds)
}
setDeviceInfo(devices)
setHostInfo(res['hosts'])
let force = false
if (res['enforce_output_dir'] !== undefined) {
force = res['enforce_output_dir']
if (force == true) {
saveToDiskField.checked = true
metadataOutputFormatField.disabled = false
}
saveToDiskField.disabled = force
diskPathField.disabled = force
}
setDiskPath(res['default_output_dir'], force)
} catch (e) {
console.log('error fetching devices', e)
}
}
saveSettingsBtn.addEventListener('click', function() {
if (listenPortField.value == '') {
alert('The network port field must not be empty.')
return
}
if (listenPortField.value < 1 || listenPortField.value > 65535) {
alert('The network port must be a number from 1 to 65535')
return
}
let updateBranch = (useBetaChannelField.checked ? 'beta' : 'main')
changeAppConfig({
'render_devices': getCurrentRenderDeviceSelection(),
'update_branch': updateBranch,
'ui_open_browser_on_start': uiOpenBrowserOnStartField.checked,
'listen_to_network': listenToNetworkField.checked,
'listen_port': listenPortField.value
})
saveSettingsBtn.classList.add('active')
asyncDelay(300).then(() => saveSettingsBtn.classList.remove('active'))
})

74
ui/media/js/plugins.js Normal file
View File

@ -0,0 +1,74 @@
const PLUGIN_API_VERSION = "1.0"
const PLUGINS = {
/**
* Register new buttons to show on each output image.
*
* Example:
* PLUGINS['IMAGE_INFO_BUTTONS'].push({
* text: 'Make a Similar Image',
* on_click: function(origRequest, image) {
* let newTaskRequest = getCurrentUserRequest()
* newTaskRequest.reqBody = Object.assign({}, origRequest, {
* init_image: image.src,
* prompt_strength: 0.7,
* seed: Math.floor(Math.random() * 10000000)
* })
* newTaskRequest.seed = newTaskRequest.reqBody.seed
* createTask(newTaskRequest)
* },
* filter: function(origRequest, image) {
* // this is an optional function. return true/false to show/hide the button
* // if this function isn't set, the button will always be visible
* return true
* }
* })
*/
IMAGE_INFO_BUTTONS: [],
GET_PROMPTS_HOOK: [],
MODIFIERS_LOAD: [],
TASK_CREATE: [],
OUTPUTS_FORMATS: new ServiceContainer(
function png() { return (reqBody) => new SD.RenderTask(reqBody) }
, function jpeg() { return (reqBody) => new SD.RenderTask(reqBody) }
, function webp() { return (reqBody) => new SD.RenderTask(reqBody) }
),
}
PLUGINS.OUTPUTS_FORMATS.register = function(...args) {
const service = ServiceContainer.prototype.register.apply(this, args)
if (typeof outputFormatField !== 'undefined') {
const newOption = document.createElement("option")
newOption.setAttribute("value", service.name)
newOption.innerText = service.name
outputFormatField.appendChild(newOption)
}
return service
}
function loadScript(url) {
const script = document.createElement('script')
const promiseSrc = new PromiseSource()
script.addEventListener('error', () => promiseSrc.reject(new Error(`Script "${url}" couldn't be loaded.`)))
script.addEventListener('load', () => promiseSrc.resolve(url))
script.src = url + '?t=' + Date.now()
console.log('loading script', url)
document.head.appendChild(script)
return promiseSrc.promise
}
async function loadUIPlugins() {
try {
const res = await fetch('/get/ui_plugins')
if (!res.ok) {
console.error(`Error HTTP${res.status} while loading plugins list. - ${res.statusText}`)
return
}
const plugins = await res.json()
const loadingPromises = plugins.map(loadScript)
return await Promise.allSettled(loadingPromises)
} catch (e) {
console.log('error fetching plugin paths', e)
}
}

View File

@ -0,0 +1,687 @@
"use strict"
let modelsCache
let modelsOptions
/*
*** SEARCHABLE MODELS ***
Creates searchable dropdowns for SD, VAE, or HN models.
Also adds a reload models button (placed next to SD models, reloads everything including VAE and HN models).
More reload buttons may be added at strategic UI locations as needed.
Merely calling getModels() makes all the magic happen behind the scene to refresh the dropdowns.
HOW TO CREATE A MODEL DROPDOWN:
1) Create an input element. Make sure to add a data-path property, as this is how model dropdowns are identified in auto-save.js.
<input id="stable_diffusion_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
2) Just declare one of these for your own dropdown (remember to change the element id, e.g. #stable_diffusion_models to your own input's id).
let stableDiffusionModelField = new ModelDropdown(document.querySelector('#stable_diffusion_model'), 'stable-diffusion')
let vaeModelField = new ModelDropdown(document.querySelector('#vae_model'), 'vae', 'None')
let hypernetworkModelField = new ModelDropdown(document.querySelector('#hypernetwork_model'), 'hypernetwork', 'None')
3) Model dropdowns will be refreshed automatically when the reload models button is invoked.
*/
class ModelDropdown
{
modelFilter //= document.querySelector("#model-filter")
modelFilterArrow //= document.querySelector("#model-filter-arrow")
modelList //= document.querySelector("#model-list")
modelResult //= document.querySelector("#model-result")
modelNoResult //= document.querySelector("#model-no-result")
currentSelection //= { elem: undefined, value: '', path: ''}
highlightedModelEntry //= undefined
activeModel //= undefined
inputModels //= undefined
modelKey //= undefined
flatModelList //= []
noneEntry //= ''
modelFilterInitialized //= undefined
/* MIMIC A REGULAR INPUT FIELD */
get parentElement() {
return this.modelFilter.parentElement
}
get parentNode() {
return this.modelFilter.parentNode
}
get value() {
return this.modelFilter.dataset.path
}
set value(path) {
this.modelFilter.dataset.path = path
this.selectEntry(path)
}
get disabled() {
return this.modelFilter.disabled
}
set disabled(state) {
this.modelFilter.disabled = state
if (this.modelFilterArrow) {
this.modelFilterArrow.style.color = state ? 'dimgray' : ''
}
}
get modelElements() {
return this.modelList.querySelectorAll('.model-file')
}
addEventListener(type, listener, options) {
return this.modelFilter.addEventListener(type, listener, options)
}
dispatchEvent(event) {
return this.modelFilter.dispatchEvent(event)
}
appendChild(option) {
// do nothing
}
// remember 'this' - http://blog.niftysnippets.org/2008/04/you-must-remember-this.html
bind(f, obj) {
return function() {
return f.apply(obj, arguments)
}
}
/* SEARCHABLE INPUT */
constructor (input, modelKey, noneEntry = '') {
this.modelFilter = input
this.noneEntry = noneEntry
this.modelKey = modelKey
if (modelsOptions !== undefined) { // reuse models from cache (only useful for plugins, which are loaded after models)
this.inputModels = modelsOptions[this.modelKey]
this.populateModels()
}
document.addEventListener("refreshModels", this.bind(function(e) {
// reload the models
this.inputModels = modelsOptions[this.modelKey]
this.populateModels()
}, this))
}
saveCurrentSelection(elem, value, path) {
this.currentSelection.elem = elem
this.currentSelection.value = value
this.currentSelection.path = path
this.modelFilter.dataset.path = path
this.modelFilter.value = value
this.modelFilter.dispatchEvent(new Event('change'))
}
processClick(e) {
e.preventDefault()
if (e.srcElement.classList.contains('model-file') || e.srcElement.classList.contains('fa-file')) {
const elem = e.srcElement.classList.contains('model-file') ? e.srcElement : e.srcElement.parentElement
this.saveCurrentSelection(elem, elem.innerText, elem.dataset.path)
this.hideModelList()
this.modelFilter.focus()
this.modelFilter.select()
}
}
getPreviousVisibleSibling(elem) {
const modelElements = Array.from(this.modelElements)
const index = modelElements.indexOf(elem)
if (index <= 0) {
return undefined
}
return modelElements.slice(0, index).reverse().find(e => e.style.display === 'list-item')
}
getLastVisibleChild(elem) {
let lastElementChild = elem.lastElementChild
if (lastElementChild.style.display == 'list-item') return lastElementChild
return this.getPreviousVisibleSibling(lastElementChild)
}
getNextVisibleSibling(elem) {
const modelElements = Array.from(this.modelElements)
const index = modelElements.indexOf(elem)
return modelElements.slice(index + 1).find(e => e.style.display === 'list-item')
}
getFirstVisibleChild(elem) {
let firstElementChild = elem.firstElementChild
if (firstElementChild.style.display == 'list-item') return firstElementChild
return this.getNextVisibleSibling(firstElementChild)
}
selectModelEntry(elem) {
if (elem) {
if (this.highlightedModelEntry !== undefined) {
this.highlightedModelEntry.classList.remove('selected')
}
this.saveCurrentSelection(elem, elem.innerText, elem.dataset.path)
elem.classList.add('selected')
elem.scrollIntoView({block: 'nearest'})
this.highlightedModelEntry = elem
}
}
selectPreviousFile() {
const elem = this.getPreviousVisibleSibling(this.highlightedModelEntry)
if (elem) {
this.selectModelEntry(elem)
}
else
{
//this.highlightedModelEntry.parentElement.parentElement.scrollIntoView({block: 'nearest'})
this.highlightedModelEntry.closest('.model-list').scrollTop = 0
}
this.modelFilter.select()
}
selectNextFile() {
this.selectModelEntry(this.getNextVisibleSibling(this.highlightedModelEntry))
this.modelFilter.select()
}
selectFirstFile() {
this.selectModelEntry(this.modelList.querySelector('.model-file'))
this.highlightedModelEntry.scrollIntoView({block: 'nearest'})
this.modelFilter.select()
}
selectLastFile() {
const elems = this.modelList.querySelectorAll('.model-file:last-child')
this.selectModelEntry(elems[elems.length -1])
this.modelFilter.select()
}
resetSelection() {
this.hideModelList()
this.showAllEntries()
this.modelFilter.value = this.currentSelection.value
this.modelFilter.focus()
this.modelFilter.select()
}
validEntrySelected() {
return (this.modelNoResult.style.display === 'none')
}
processKey(e) {
switch (e.key) {
case 'Escape':
e.preventDefault()
this.resetSelection()
break
case 'Enter':
e.preventDefault()
if (this.validEntrySelected()) {
if (this.modelList.style.display != 'block') {
this.showModelList()
}
else
{
this.saveCurrentSelection(this.highlightedModelEntry, this.highlightedModelEntry.innerText, this.highlightedModelEntry.dataset.path)
this.hideModelList()
this.showAllEntries()
}
this.modelFilter.focus()
}
else
{
this.resetSelection()
}
break
case 'ArrowUp':
e.preventDefault()
if (this.validEntrySelected()) {
this.selectPreviousFile()
}
break
case 'ArrowDown':
e.preventDefault()
if (this.validEntrySelected()) {
this.selectNextFile()
}
break
case 'ArrowLeft':
if (this.modelList.style.display != 'block') {
e.preventDefault()
}
break
case 'ArrowRight':
if (this.modelList.style.display != 'block') {
e.preventDefault()
}
break
case 'PageUp':
e.preventDefault()
if (this.validEntrySelected()) {
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
this.selectPreviousFile()
}
break
case 'PageDown':
e.preventDefault()
if (this.validEntrySelected()) {
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
this.selectNextFile()
}
break
case 'Home':
//if (this.modelList.style.display != 'block') {
e.preventDefault()
if (this.validEntrySelected()) {
this.selectFirstFile()
}
//}
break
case 'End':
//if (this.modelList.style.display != 'block') {
e.preventDefault()
if (this.validEntrySelected()) {
this.selectLastFile()
}
//}
break
default:
//console.log(e.key)
}
}
modelListFocus() {
this.selectEntry()
this.showAllEntries()
}
showModelList() {
this.modelList.style.display = 'block'
this.selectEntry()
this.showAllEntries()
//this.modelFilter.value = ''
this.modelFilter.select() // preselect the entire string so user can just start typing.
this.modelFilter.focus()
this.modelFilter.style.cursor = 'auto'
}
hideModelList() {
this.modelList.style.display = 'none'
this.modelFilter.value = this.currentSelection.value
this.modelFilter.style.cursor = ''
}
toggleModelList(e) {
e.preventDefault()
if (!this.modelFilter.disabled) {
if (this.modelList.style.display != 'block') {
this.showModelList()
}
else
{
this.hideModelList()
this.modelFilter.select()
}
}
}
selectEntry(path) {
if (path !== undefined) {
const entries = this.modelElements;
for (const elem of entries) {
if (elem.dataset.path == path) {
this.saveCurrentSelection(elem, elem.innerText, elem.dataset.path)
this.highlightedModelEntry = elem
elem.scrollIntoView({block: 'nearest'})
break
}
}
}
if (this.currentSelection.elem !== undefined) {
// select the previous element
if (this.highlightedModelEntry !== undefined && this.highlightedModelEntry != this.currentSelection.elem) {
this.highlightedModelEntry.classList.remove('selected')
}
this.currentSelection.elem.classList.add('selected')
this.highlightedModelEntry = this.currentSelection.elem
this.currentSelection.elem.scrollIntoView({block: 'nearest'})
}
else
{
this.selectFirstFile()
}
}
highlightModelAtPosition(e) {
let elem = document.elementFromPoint(e.clientX, e.clientY)
if (elem.classList.contains('model-file')) {
this.highlightModel(elem)
}
}
highlightModel(elem) {
if (elem.classList.contains('model-file')) {
if (this.highlightedModelEntry !== undefined && this.highlightedModelEntry != elem) {
this.highlightedModelEntry.classList.remove('selected')
}
elem.classList.add('selected')
this.highlightedModelEntry = elem
}
}
showAllEntries() {
this.modelList.querySelectorAll('li').forEach(function(li) {
if (li.id !== 'model-no-result') {
li.style.display = 'list-item'
}
})
this.modelNoResult.style.display = 'none'
}
filterList(e) {
const filter = this.modelFilter.value.toLowerCase()
let found = false
let showAllChildren = false
this.modelList.querySelectorAll('li').forEach(function(li) {
if (li.classList.contains('model-folder')) {
showAllChildren = false
}
if (filter == '') {
li.style.display = 'list-item'
found = true
} else if (showAllChildren || li.textContent.toLowerCase().match(filter)) {
li.style.display = 'list-item'
if (li.classList.contains('model-folder') && li.firstChild.textContent.toLowerCase().match(filter)) {
showAllChildren = true
}
found = true
} else {
li.style.display = 'none'
}
})
if (found) {
this.modelResult.style.display = 'list-item'
this.modelNoResult.style.display = 'none'
const elem = this.getNextVisibleSibling(this.modelList.querySelector('.model-file'))
this.highlightModel(elem)
elem.scrollIntoView({block: 'nearest'})
}
else
{
this.modelResult.style.display = 'none'
this.modelNoResult.style.display = 'list-item'
}
this.modelList.style.display = 'block'
}
/* MODEL LOADER */
getElementDimensions(element) {
// Clone the element
const clone = element.cloneNode(true)
// Copy the styles of the original element to the cloned element
const originalStyles = window.getComputedStyle(element)
for (let i = 0; i < originalStyles.length; i++) {
const property = originalStyles[i]
clone.style[property] = originalStyles.getPropertyValue(property)
}
// Set its visibility to hidden and display to inline-block
clone.style.visibility = "hidden"
clone.style.display = "inline-block"
// Put the cloned element next to the original element
element.parentNode.insertBefore(clone, element.nextSibling)
// Get its width and height
const width = clone.offsetWidth
const height = clone.offsetHeight
// Remove it from the DOM
clone.remove()
// Return its width and height
return { width, height }
}
/**
* @param {Array<string>} models
*/
sortStringArray(models) {
models.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))
}
populateModels() {
this.activeModel = this.modelFilter.dataset.path
this.currentSelection = { elem: undefined, value: '', path: ''}
this.highlightedModelEntry = undefined
this.flatModelList = []
if(this.modelList !== undefined) {
this.modelList.remove()
this.modelFilterArrow.remove()
}
this.createDropdown()
}
createDropdown() {
// create dropdown entries
let rootModelList = this.createRootModelList(this.inputModels)
this.modelFilter.insertAdjacentElement('afterend', rootModelList)
this.modelFilter.insertAdjacentElement(
'afterend',
this.createElement(
'i',
{ id: `${this.modelFilter.id}-model-filter-arrow` },
['model-selector-arrow', 'fa-solid', 'fa-angle-down'],
),
)
this.modelFilter.classList.add('model-selector')
this.modelFilterArrow = document.querySelector(`#${this.modelFilter.id}-model-filter-arrow`)
if (this.modelFilterArrow) {
this.modelFilterArrow.style.color = this.modelFilter.disabled ? 'dimgray' : ''
}
this.modelList = document.querySelector(`#${this.modelFilter.id}-model-list`)
this.modelResult = document.querySelector(`#${this.modelFilter.id}-model-result`)
this.modelNoResult = document.querySelector(`#${this.modelFilter.id}-model-no-result`)
if (this.modelFilterInitialized !== true) {
this.modelFilter.addEventListener('input', this.bind(this.filterList, this))
this.modelFilter.addEventListener('focus', this.bind(this.modelListFocus, this))
this.modelFilter.addEventListener('blur', this.bind(this.hideModelList, this))
this.modelFilter.addEventListener('click', this.bind(this.showModelList, this))
this.modelFilter.addEventListener('keydown', this.bind(this.processKey, this))
this.modelFilterInitialized = true
}
this.modelFilterArrow.addEventListener('mousedown', this.bind(this.toggleModelList, this))
this.modelList.addEventListener('mousemove', this.bind(this.highlightModelAtPosition, this))
this.modelList.addEventListener('mousedown', this.bind(this.processClick, this))
let mf = this.modelFilter
this.modelFilter.addEventListener('focus', function() {
let modelFilterStyle = window.getComputedStyle(mf)
rootModelList.style.minWidth = modelFilterStyle.width
})
this.selectEntry(this.activeModel)
}
/**
*
* @param {string} tag
* @param {object} attributes
* @param {Array<string>} classes
* @returns {HTMLElement}
*/
createElement(tagName, attributes, classes, text, icon) {
const element = document.createElement(tagName)
if (attributes) {
Object.entries(attributes).forEach(([key, value]) => {
element.setAttribute(key, value)
})
}
if (classes) {
classes.forEach(className => element.classList.add(className))
}
if (icon) {
let iconEl = document.createElement('i')
iconEl.className = icon + ' icon'
element.appendChild(iconEl)
}
if (text) {
element.appendChild(document.createTextNode(text))
}
return element
}
/**
* @param {Array<string | object} modelTree
* @param {string} folderName
* @param {boolean} isRootFolder
* @returns {HTMLElement}
*/
createModelNodeList(folderName, modelTree, isRootFolder) {
const listElement = this.createElement('ul')
const foldersMap = new Map()
const modelsMap = new Map()
modelTree.forEach(model => {
if (Array.isArray(model)) {
const [childFolderName, childModels] = model
foldersMap.set(
childFolderName,
this.createModelNodeList(
`${folderName || ''}/${childFolderName}`,
childModels,
false,
),
)
} else {
const classes = ['model-file']
if (isRootFolder) {
classes.push('in-root-folder')
}
// Remove the leading slash from the model path
const fullPath = folderName ? `${folderName.substring(1)}/${model}` : model
modelsMap.set(
model,
this.createElement('li', { 'data-path': fullPath }, classes, model, 'fa-regular fa-file'),
)
}
})
const childFolderNames = Array.from(foldersMap.keys())
this.sortStringArray(childFolderNames)
const folderElements = childFolderNames.map(name => foldersMap.get(name))
const modelNames = Array.from(modelsMap.keys())
this.sortStringArray(modelNames)
const modelElements = modelNames.map(name => modelsMap.get(name))
if (modelElements.length && folderName) {
listElement.appendChild(this.createElement('li', undefined, ['model-folder'], folderName.substring(1), 'fa-solid fa-folder-open'))
}
// const allModelElements = isRootFolder ? [...folderElements, ...modelElements] : [...modelElements, ...folderElements]
const allModelElements = [...modelElements, ...folderElements]
allModelElements.forEach(e => listElement.appendChild(e))
return listElement
}
/**
* @param {object} modelTree
* @returns {HTMLElement}
*/
createRootModelList(modelTree) {
const rootList = this.createElement(
'ul',
{ id: `${this.modelFilter.id}-model-list` },
['model-list'],
)
rootList.appendChild(
this.createElement(
'li',
{ id: `${this.modelFilter.id}-model-no-result` },
['model-no-result'],
'No result'
),
)
if (this.noneEntry) {
rootList.appendChild(
this.createElement(
'li',
{ 'data-path': '' },
['model-file', 'in-root-folder'],
this.noneEntry,
),
)
}
if (modelTree.length > 0) {
const containerListItem = this.createElement(
'li',
{ id: `${this.modelFilter.id}-model-result` },
['model-result'],
)
//console.log(containerListItem)
containerListItem.appendChild(this.createModelNodeList(undefined, modelTree, true))
rootList.appendChild(containerListItem)
}
return rootList
}
}
/* (RE)LOAD THE MODELS */
async function getModels() {
try {
modelsCache = await SD.getModels()
modelsOptions = modelsCache['options']
if ("scan-error" in modelsCache) {
// let previewPane = document.getElementById('tab-content-wrapper')
let previewPane = document.getElementById('preview')
previewPane.style.background="red"
previewPane.style.textAlign="center"
previewPane.innerHTML = '<H1>🔥Malware alert!🔥</H1><h2>The file <i>' + modelsCache['scan-error'] + '</i> in your <tt>models/stable-diffusion</tt> folder is probably malware infected.</h2><h2>Please delete this file from the folder before proceeding!</h2>After deleting the file, reload this page.<br><br><button onClick="window.location.reload();">Reload Page</button>'
makeImageBtn.disabled = true
}
/* This code should no longer be needed. Commenting out for now, will cleanup later.
const sd_model_setting_key = "stable_diffusion_model"
const vae_model_setting_key = "vae_model"
const hypernetwork_model_key = "hypernetwork_model"
const stableDiffusionOptions = modelsOptions['stable-diffusion']
const vaeOptions = modelsOptions['vae']
const hypernetworkOptions = modelsOptions['hypernetwork']
// TODO: set default for model here too
SETTINGS[sd_model_setting_key].default = stableDiffusionOptions[0]
if (getSetting(sd_model_setting_key) == '' || SETTINGS[sd_model_setting_key].value == '') {
setSetting(sd_model_setting_key, stableDiffusionOptions[0])
}
*/
// notify ModelDropdown objects to refresh
document.dispatchEvent(new Event('refreshModels'))
} catch (e) {
console.log('get models error', e)
}
}
// reload models button
document.querySelector('#reload-models').addEventListener('click', getModels)

Some files were not shown because too many files have changed in this diff Show More