Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31f2be3dce | |||
| 250c416474 | |||
| 12171ca961 | |||
| 56236dfd3f | |||
| 68f336bd99 | |||
| 50973ec77c | |||
| f82e08cf45 | |||
| 3039925b27 | |||
| 8220cf37da | |||
| 055461ae41 | |||
| 5c8f91b229 | |||
| 6b877c35da | |||
| eb6d330bb7 | |||
| 5360ae2cc5 | |||
| e16eb3d0cb | |||
| 99ef3b6c52 | |||
| 65b6f8d3d5 | |||
| b57a816038 | |||
| 11f996a096 | |||
| ce0aab3643 | |||
| c251e8db8d | |||
| 284822323a | |||
| 1f59be5188 | |||
| cad87bf4e3 | |||
| 704628b903 | |||
| 636ff513b0 | |||
| 51206edb62 | |||
| c5934fb6e3 | |||
| a3ddf464a2 | |||
| 2c11e9009e | |||
| 1f26815dd3 | |||
| 8218f6cd37 | |||
| 23c947ab03 | |||
| 0e47c36a28 | |||
| 4334d25978 | |||
| 05ccb4d0e3 | |||
| d5c850aab5 | |||
| 0a334b447f | |||
| c2b9754857 | |||
| c8b55f29e2 | |||
| 6094310704 | |||
| 0c4ca5f43e | |||
| b010eea520 | |||
| 2b42f73e3d | |||
| 136c8859a4 |
+35
-3
@@ -1,3 +1,35 @@
|
|||||||
|
## 1.5.2
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
* fix memory leak when generation fails
|
||||||
|
* update doggettx cross attention optimization to not use an unreasonable amount of memory in some edge cases -- suggestion by MorkTheOrk
|
||||||
|
|
||||||
|
|
||||||
|
## 1.5.1
|
||||||
|
|
||||||
|
### Minor:
|
||||||
|
* support parsing text encoder blocks in some new LoRAs
|
||||||
|
* delete scale checker script due to user demand
|
||||||
|
|
||||||
|
### Extensions and API:
|
||||||
|
* add postprocess_batch_list script callback
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
* fix TI training for SD1
|
||||||
|
* fix reload altclip model error
|
||||||
|
* prepend the pythonpath instead of overriding it
|
||||||
|
* fix typo in SD_WEBUI_RESTARTING
|
||||||
|
* if txt2img/img2img raises an exception, finally call state.end()
|
||||||
|
* fix composable diffusion weight parsing
|
||||||
|
* restyle Startup profile for black users
|
||||||
|
* fix webui not launching with --nowebui
|
||||||
|
* catch exception for non git extensions
|
||||||
|
* fix some options missing from /sdapi/v1/options
|
||||||
|
* fix for extension update status always saying "unknown"
|
||||||
|
* fix display of extra network cards that have `<>` in the name
|
||||||
|
* update lora extension to work with python 3.8
|
||||||
|
|
||||||
|
|
||||||
## 1.5.0
|
## 1.5.0
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
@@ -30,6 +62,7 @@
|
|||||||
* added `[none]` filename token.
|
* added `[none]` filename token.
|
||||||
* removed thumbs extra networks view mode (use settings tab to change width/height/scale to get thumbs)
|
* removed thumbs extra networks view mode (use settings tab to change width/height/scale to get thumbs)
|
||||||
* add always_discard_next_to_last_sigma option to XYZ plot
|
* add always_discard_next_to_last_sigma option to XYZ plot
|
||||||
|
* automatically switch to 32-bit float VAE if the generated picture has NaNs without the need for `--no-half-vae` commandline flag.
|
||||||
|
|
||||||
### Extensions and API:
|
### Extensions and API:
|
||||||
* api endpoints: /sdapi/v1/server-kill, /sdapi/v1/server-restart, /sdapi/v1/server-stop
|
* api endpoints: /sdapi/v1/server-kill, /sdapi/v1/server-restart, /sdapi/v1/server-stop
|
||||||
@@ -58,9 +91,8 @@
|
|||||||
* fix: check fill size none zero when resize (fixes #11425)
|
* fix: check fill size none zero when resize (fixes #11425)
|
||||||
* use submit and blur for quick settings textbox
|
* use submit and blur for quick settings textbox
|
||||||
* save img2img batch with images.save_image()
|
* save img2img batch with images.save_image()
|
||||||
*
|
* prevent running preload.py for disabled extensions
|
||||||
|
* fix: previously, model name was added together with directory name to infotext and to [model_name] filename pattern; directory name is now not included
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 1.4.1
|
## 1.4.1
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
|||||||
te_multiplier = float(params.positional[1]) if len(params.positional) > 1 else 1.0
|
te_multiplier = float(params.positional[1]) if len(params.positional) > 1 else 1.0
|
||||||
te_multiplier = float(params.named.get("te", te_multiplier))
|
te_multiplier = float(params.named.get("te", te_multiplier))
|
||||||
|
|
||||||
unet_multiplier = float(params.positional[2]) if len(params.positional) > 2 else 1.0
|
unet_multiplier = float(params.positional[2]) if len(params.positional) > 2 else te_multiplier
|
||||||
unet_multiplier = float(params.named.get("unet", unet_multiplier))
|
unet_multiplier = float(params.named.get("unet", unet_multiplier))
|
||||||
|
|
||||||
dyn_dim = int(params.positional[3]) if len(params.positional) > 3 else None
|
dyn_dim = int(params.positional[3]) if len(params.positional) > 3 else None
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import annotations
|
||||||
import os
|
import os
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import enum
|
import enum
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import network_full
|
|||||||
import torch
|
import torch
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from modules import shared, devices, sd_models, errors, scripts, sd_hijack, paths
|
from modules import shared, devices, sd_models, errors, scripts, sd_hijack
|
||||||
|
|
||||||
module_types = [
|
module_types = [
|
||||||
network_lora.ModuleTypeLora(),
|
network_lora.ModuleTypeLora(),
|
||||||
@@ -163,6 +163,11 @@ def load_network(name, network_on_disk):
|
|||||||
key = key_network_without_network_parts.replace("lora_te1_text_model", "0_transformer_text_model")
|
key = key_network_without_network_parts.replace("lora_te1_text_model", "0_transformer_text_model")
|
||||||
sd_module = shared.sd_model.network_layer_mapping.get(key, None)
|
sd_module = shared.sd_model.network_layer_mapping.get(key, None)
|
||||||
|
|
||||||
|
# some SD1 Loras also have correct compvis keys
|
||||||
|
if sd_module is None:
|
||||||
|
key = key_network_without_network_parts.replace("lora_te1_text_model", "transformer_text_model")
|
||||||
|
sd_module = shared.sd_model.network_layer_mapping.get(key, None)
|
||||||
|
|
||||||
if sd_module is None:
|
if sd_module is None:
|
||||||
keys_failed_to_match[key_network] = key
|
keys_failed_to_match[key_network] = key
|
||||||
continue
|
continue
|
||||||
@@ -399,7 +404,7 @@ def list_available_networks():
|
|||||||
os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True)
|
os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True)
|
||||||
|
|
||||||
candidates = list(shared.walk_files(shared.cmd_opts.lora_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
|
candidates = list(shared.walk_files(shared.cmd_opts.lora_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
|
||||||
candidates += list(shared.walk_files(os.path.join(paths.models_path, "LyCORIS"), allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
|
candidates += list(shared.walk_files(shared.cmd_opts.lyco_dir_backcompat, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
|
||||||
for filename in candidates:
|
for filename in candidates:
|
||||||
if os.path.isdir(filename):
|
if os.path.isdir(filename):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ from modules import paths
|
|||||||
|
|
||||||
def preload(parser):
|
def preload(parser):
|
||||||
parser.add_argument("--lora-dir", type=str, help="Path to directory with Lora networks.", default=os.path.join(paths.models_path, 'Lora'))
|
parser.add_argument("--lora-dir", type=str, help="Path to directory with Lora networks.", default=os.path.join(paths.models_path, 'Lora'))
|
||||||
|
parser.add_argument("--lyco-dir-backcompat", type=str, help="Path to directory with LyCORIS networks (for backawards compatibility; can also use --lyco-dir).", default=os.path.join(paths.models_path, 'LyCORIS'))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
import network
|
import network
|
||||||
import networks
|
import networks
|
||||||
|
|
||||||
from modules import shared, ui_extra_networks, paths
|
from modules import shared, ui_extra_networks
|
||||||
from modules.ui_extra_networks import quote_js
|
from modules.ui_extra_networks import quote_js
|
||||||
from ui_edit_user_metadata import LoraUserMetadataEditor
|
from ui_edit_user_metadata import LoraUserMetadataEditor
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
|||||||
yield item
|
yield item
|
||||||
|
|
||||||
def allowed_directories_for_previews(self):
|
def allowed_directories_for_previews(self):
|
||||||
return [shared.cmd_opts.lora_dir, os.path.join(paths.models_path, "LyCORIS")]
|
return [shared.cmd_opts.lora_dir, shared.cmd_opts.lyco_dir_backcompat]
|
||||||
|
|
||||||
def create_user_metadata_editor(self, ui, tabname):
|
def create_user_metadata_editor(self, ui, tabname):
|
||||||
return LoraUserMetadataEditor(ui, tabname, self)
|
return LoraUserMetadataEditor(ui, tabname, self)
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
(function() {
|
|
||||||
var ignore = localStorage.getItem("bad-scale-ignore-it") == "ignore-it";
|
|
||||||
|
|
||||||
function getScale() {
|
|
||||||
var ratio = 0,
|
|
||||||
screen = window.screen,
|
|
||||||
ua = navigator.userAgent.toLowerCase();
|
|
||||||
|
|
||||||
if (window.devicePixelRatio !== undefined) {
|
|
||||||
ratio = window.devicePixelRatio;
|
|
||||||
} else if (~ua.indexOf('msie')) {
|
|
||||||
if (screen.deviceXDPI && screen.logicalXDPI) {
|
|
||||||
ratio = screen.deviceXDPI / screen.logicalXDPI;
|
|
||||||
}
|
|
||||||
} else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
|
|
||||||
ratio = window.outerWidth / window.innerWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ratio == 0 ? 0 : Math.round(ratio * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
var showing = false;
|
|
||||||
|
|
||||||
var div = document.createElement("div");
|
|
||||||
div.style.position = "fixed";
|
|
||||||
div.style.top = "0px";
|
|
||||||
div.style.left = "0px";
|
|
||||||
div.style.width = "100vw";
|
|
||||||
div.style.backgroundColor = "firebrick";
|
|
||||||
div.style.textAlign = "center";
|
|
||||||
div.style.zIndex = 99;
|
|
||||||
|
|
||||||
var b = document.createElement("b");
|
|
||||||
b.innerHTML = 'Bad Scale: ??% ';
|
|
||||||
|
|
||||||
div.appendChild(b);
|
|
||||||
|
|
||||||
var note1 = document.createElement("p");
|
|
||||||
note1.innerHTML = "Change your browser or your computer settings!";
|
|
||||||
note1.title = 'Just make sure "computer-scale" * "browser-scale" = 100% ,\n' +
|
|
||||||
"you can keep your computer-scale and only change this page's scale,\n" +
|
|
||||||
"for example: your computer-scale is 125%, just use [\"CTRL\"+\"-\"] to make your browser-scale of this page to 80%.";
|
|
||||||
div.appendChild(note1);
|
|
||||||
|
|
||||||
var note2 = document.createElement("p");
|
|
||||||
note2.innerHTML = " Otherwise, it will cause this page to not function properly!";
|
|
||||||
note2.title = "When you click \"Copy image to: [inpaint sketch]\" in some img2img's tab,\n" +
|
|
||||||
"if scale<100% the canvas will be invisible,\n" +
|
|
||||||
"else if scale>100% this page will take large amount of memory and CPU performance.";
|
|
||||||
div.appendChild(note2);
|
|
||||||
|
|
||||||
var btn = document.createElement("button");
|
|
||||||
btn.innerHTML = "Click here to ignore";
|
|
||||||
|
|
||||||
div.appendChild(btn);
|
|
||||||
|
|
||||||
function tryShowTopBar(scale) {
|
|
||||||
if (showing) return;
|
|
||||||
|
|
||||||
b.innerHTML = 'Bad Scale: ' + scale + '% ';
|
|
||||||
|
|
||||||
var updateScaleTimer = setInterval(function() {
|
|
||||||
var newScale = getScale();
|
|
||||||
b.innerHTML = 'Bad Scale: ' + newScale + '% ';
|
|
||||||
if (newScale == 100) {
|
|
||||||
var p = div.parentNode;
|
|
||||||
if (p != null) p.removeChild(div);
|
|
||||||
showing = false;
|
|
||||||
clearInterval(updateScaleTimer);
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
}, 999);
|
|
||||||
|
|
||||||
btn.onclick = function() {
|
|
||||||
clearInterval(updateScaleTimer);
|
|
||||||
var p = div.parentNode;
|
|
||||||
if (p != null) p.removeChild(div);
|
|
||||||
ignore = true;
|
|
||||||
showing = false;
|
|
||||||
localStorage.setItem("bad-scale-ignore-it", "ignore-it");
|
|
||||||
};
|
|
||||||
|
|
||||||
document.body.appendChild(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
if (!ignore) {
|
|
||||||
var timer = setInterval(function() {
|
|
||||||
var scale = getScale();
|
|
||||||
if (scale != 100 && !ignore) {
|
|
||||||
tryShowTopBar(scale);
|
|
||||||
clearInterval(timer);
|
|
||||||
}
|
|
||||||
if (ignore) {
|
|
||||||
clearInterval(timer);
|
|
||||||
}
|
|
||||||
}, 999);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.readyState != "complete") {
|
|
||||||
document.onreadystatechange = function() {
|
|
||||||
if (document.readyState != "complete") check();
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
@@ -18,6 +18,7 @@ run_pip = launch_utils.run_pip
|
|||||||
check_run_python = launch_utils.check_run_python
|
check_run_python = launch_utils.check_run_python
|
||||||
git_clone = launch_utils.git_clone
|
git_clone = launch_utils.git_clone
|
||||||
git_pull_recursive = launch_utils.git_pull_recursive
|
git_pull_recursive = launch_utils.git_pull_recursive
|
||||||
|
list_extensions = launch_utils.list_extensions
|
||||||
run_extension_installer = launch_utils.run_extension_installer
|
run_extension_installer = launch_utils.run_extension_installer
|
||||||
prepare_environment = launch_utils.prepare_environment
|
prepare_environment = launch_utils.prepare_environment
|
||||||
configure_for_tests = launch_utils.configure_for_tests
|
configure_for_tests = launch_utils.configure_for_tests
|
||||||
|
|||||||
+6
-2
@@ -333,6 +333,7 @@ class Api:
|
|||||||
p.outpath_grids = opts.outdir_txt2img_grids
|
p.outpath_grids = opts.outdir_txt2img_grids
|
||||||
p.outpath_samples = opts.outdir_txt2img_samples
|
p.outpath_samples = opts.outdir_txt2img_samples
|
||||||
|
|
||||||
|
try:
|
||||||
shared.state.begin(job="scripts_txt2img")
|
shared.state.begin(job="scripts_txt2img")
|
||||||
if selectable_scripts is not None:
|
if selectable_scripts is not None:
|
||||||
p.script_args = script_args
|
p.script_args = script_args
|
||||||
@@ -340,6 +341,7 @@ class Api:
|
|||||||
else:
|
else:
|
||||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||||
processed = process_images(p)
|
processed = process_images(p)
|
||||||
|
finally:
|
||||||
shared.state.end()
|
shared.state.end()
|
||||||
|
|
||||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||||
@@ -390,6 +392,7 @@ class Api:
|
|||||||
p.outpath_grids = opts.outdir_img2img_grids
|
p.outpath_grids = opts.outdir_img2img_grids
|
||||||
p.outpath_samples = opts.outdir_img2img_samples
|
p.outpath_samples = opts.outdir_img2img_samples
|
||||||
|
|
||||||
|
try:
|
||||||
shared.state.begin(job="scripts_img2img")
|
shared.state.begin(job="scripts_img2img")
|
||||||
if selectable_scripts is not None:
|
if selectable_scripts is not None:
|
||||||
p.script_args = script_args
|
p.script_args = script_args
|
||||||
@@ -397,6 +400,7 @@ class Api:
|
|||||||
else:
|
else:
|
||||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||||
processed = process_images(p)
|
processed = process_images(p)
|
||||||
|
finally:
|
||||||
shared.state.end()
|
shared.state.end()
|
||||||
|
|
||||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||||
@@ -720,9 +724,9 @@ class Api:
|
|||||||
cuda = {'error': f'{err}'}
|
cuda = {'error': f'{err}'}
|
||||||
return models.MemoryResponse(ram=ram, cuda=cuda)
|
return models.MemoryResponse(ram=ram, cuda=cuda)
|
||||||
|
|
||||||
def launch(self, server_name, port):
|
def launch(self, server_name, port, root_path):
|
||||||
self.app.include_router(self.router)
|
self.app.include_router(self.router)
|
||||||
uvicorn.run(self.app, host=server_name, port=port, timeout_keep_alive=shared.cmd_opts.timeout_keep_alive)
|
uvicorn.run(self.app, host=server_name, port=port, timeout_keep_alive=shared.cmd_opts.timeout_keep_alive, root_path=root_path)
|
||||||
|
|
||||||
def kill_webui(self):
|
def kill_webui(self):
|
||||||
restart.stop_program()
|
restart.stop_program()
|
||||||
|
|||||||
@@ -208,11 +208,9 @@ class PreprocessResponse(BaseModel):
|
|||||||
fields = {}
|
fields = {}
|
||||||
for key, metadata in opts.data_labels.items():
|
for key, metadata in opts.data_labels.items():
|
||||||
value = opts.data.get(key)
|
value = opts.data.get(key)
|
||||||
optType = opts.typemap.get(type(metadata.default), type(metadata.default))
|
optType = opts.typemap.get(type(metadata.default), type(metadata.default)) if metadata.default else Any
|
||||||
|
|
||||||
if metadata.default is None:
|
if metadata is not None:
|
||||||
pass
|
|
||||||
elif metadata is not None:
|
|
||||||
fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))})
|
fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))})
|
||||||
else:
|
else:
|
||||||
fields.update({key: (Optional[optType], Field())})
|
fields.update({key: (Optional[optType], Field())})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import html
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from modules import shared, progress, errors
|
from modules import shared, progress, errors, devices
|
||||||
|
|
||||||
queue_lock = threading.Lock()
|
queue_lock = threading.Lock()
|
||||||
|
|
||||||
@@ -75,6 +75,8 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
|
|||||||
error_message = f'{type(e).__name__}: {e}'
|
error_message = f'{type(e).__name__}: {e}'
|
||||||
res = extra_outputs_array + [f"<div class='error'>{html.escape(error_message)}</div>"]
|
res = extra_outputs_array + [f"<div class='error'>{html.escape(error_message)}</div>"]
|
||||||
|
|
||||||
|
devices.torch_gc()
|
||||||
|
|
||||||
shared.state.skipped = False
|
shared.state.skipped = False
|
||||||
shared.state.interrupted = False
|
shared.state.interrupted = False
|
||||||
shared.state.job_count = 0
|
shared.state.job_count = 0
|
||||||
|
|||||||
+2
-1
@@ -14,7 +14,8 @@ def record_exception():
|
|||||||
if exception_records and exception_records[-1] == e:
|
if exception_records and exception_records[-1] == e:
|
||||||
return
|
return
|
||||||
|
|
||||||
exception_records.append((e, tb))
|
from modules import sysinfo
|
||||||
|
exception_records.append(sysinfo.format_exception(e, tb))
|
||||||
|
|
||||||
if len(exception_records) > 5:
|
if len(exception_records) > 5:
|
||||||
exception_records.pop(0)
|
exception_records.pop(0)
|
||||||
|
|||||||
@@ -56,10 +56,12 @@ class Extension:
|
|||||||
self.do_read_info_from_repo()
|
self.do_read_info_from_repo()
|
||||||
|
|
||||||
return self.to_dict()
|
return self.to_dict()
|
||||||
|
try:
|
||||||
d = cache.cached_data_for_file('extensions-git', self.name, os.path.join(self.path, ".git"), read_from_repo)
|
d = cache.cached_data_for_file('extensions-git', self.name, os.path.join(self.path, ".git"), read_from_repo)
|
||||||
self.from_dict(d)
|
self.from_dict(d)
|
||||||
self.status = 'unknown'
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
self.status = 'unknown' if self.status == '' else self.status
|
||||||
|
|
||||||
def do_read_info_from_repo(self):
|
def do_read_info_from_repo(self):
|
||||||
repo = None
|
repo = None
|
||||||
|
|||||||
+1
-1
@@ -363,7 +363,7 @@ class FilenameGenerator:
|
|||||||
'styles': lambda self: self.p and sanitize_filename_part(", ".join([style for style in self.p.styles if not style == "None"]) or "None", replace_spaces=False),
|
'styles': lambda self: self.p and sanitize_filename_part(", ".join([style for style in self.p.styles if not style == "None"]) or "None", replace_spaces=False),
|
||||||
'sampler': lambda self: self.p and sanitize_filename_part(self.p.sampler_name, replace_spaces=False),
|
'sampler': lambda self: self.p and sanitize_filename_part(self.p.sampler_name, replace_spaces=False),
|
||||||
'model_hash': lambda self: getattr(self.p, "sd_model_hash", shared.sd_model.sd_model_hash),
|
'model_hash': lambda self: getattr(self.p, "sd_model_hash", shared.sd_model.sd_model_hash),
|
||||||
'model_name': lambda self: sanitize_filename_part(shared.sd_model.sd_checkpoint_info.model_name, replace_spaces=False),
|
'model_name': lambda self: sanitize_filename_part(shared.sd_model.sd_checkpoint_info.name_for_extra, replace_spaces=False),
|
||||||
'date': lambda self: datetime.datetime.now().strftime('%Y-%m-%d'),
|
'date': lambda self: datetime.datetime.now().strftime('%Y-%m-%d'),
|
||||||
'datetime': lambda self, *args: self.datetime(*args), # accepts formats: [datetime], [datetime<Format>], [datetime<Format><Time Zone>]
|
'datetime': lambda self, *args: self.datetime(*args), # accepts formats: [datetime], [datetime<Format>], [datetime<Format><Time Zone>]
|
||||||
'job_timestamp': lambda self: getattr(self.p, "job_timestamp", shared.state.job_timestamp),
|
'job_timestamp': lambda self: getattr(self.p, "job_timestamp", shared.state.job_timestamp),
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ def run_extension_installer(extension_dir):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env['PYTHONPATH'] = os.path.abspath(".")
|
env['PYTHONPATH'] = f"{os.path.abspath('.')}{os.pathsep}{env.get('PYTHONPATH', '')}"
|
||||||
|
|
||||||
print(run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env))
|
print(run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -233,7 +233,7 @@ def run_extensions_installers(settings_file):
|
|||||||
re_requirement = re.compile(r"\s*([-_a-zA-Z0-9]+)\s*(?:==\s*([-+_.a-zA-Z0-9]+))?\s*")
|
re_requirement = re.compile(r"\s*([-_a-zA-Z0-9]+)\s*(?:==\s*([-+_.a-zA-Z0-9]+))?\s*")
|
||||||
|
|
||||||
|
|
||||||
def requrements_met(requirements_file):
|
def requirements_met(requirements_file):
|
||||||
"""
|
"""
|
||||||
Does a simple parse of a requirements.txt file to determine if all rerqirements in it
|
Does a simple parse of a requirements.txt file to determine if all rerqirements in it
|
||||||
are already installed. Returns True if so, False if not installed or parsing fails.
|
are already installed. Returns True if so, False if not installed or parsing fails.
|
||||||
@@ -354,7 +354,7 @@ def prepare_environment():
|
|||||||
if not os.path.isfile(requirements_file):
|
if not os.path.isfile(requirements_file):
|
||||||
requirements_file = os.path.join(script_path, requirements_file)
|
requirements_file = os.path.join(script_path, requirements_file)
|
||||||
|
|
||||||
if not requrements_met(requirements_file):
|
if not requirements_met(requirements_file):
|
||||||
run_pip(f"install -r \"{requirements_file}\"", "requirements")
|
run_pip(f"install -r \"{requirements_file}\"", "requirements")
|
||||||
|
|
||||||
run_extensions_installers(settings_file=args.ui_settings_file)
|
run_extensions_installers(settings_file=args.ui_settings_file)
|
||||||
|
|||||||
+4
-3
@@ -90,8 +90,12 @@ def setup_for_low_vram(sd_model, use_medvram):
|
|||||||
sd_model.conditioner.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.conditioner.register_forward_pre_hook(send_me_to_gpu)
|
||||||
elif is_sd2:
|
elif is_sd2:
|
||||||
sd_model.cond_stage_model.model.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.cond_stage_model.model.register_forward_pre_hook(send_me_to_gpu)
|
||||||
|
sd_model.cond_stage_model.model.token_embedding.register_forward_pre_hook(send_me_to_gpu)
|
||||||
|
parents[sd_model.cond_stage_model.model] = sd_model.cond_stage_model
|
||||||
|
parents[sd_model.cond_stage_model.model.token_embedding] = sd_model.cond_stage_model
|
||||||
else:
|
else:
|
||||||
sd_model.cond_stage_model.transformer.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.cond_stage_model.transformer.register_forward_pre_hook(send_me_to_gpu)
|
||||||
|
parents[sd_model.cond_stage_model.transformer] = sd_model.cond_stage_model
|
||||||
|
|
||||||
sd_model.first_stage_model.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.first_stage_model.register_forward_pre_hook(send_me_to_gpu)
|
||||||
sd_model.first_stage_model.encode = first_stage_model_encode_wrap
|
sd_model.first_stage_model.encode = first_stage_model_encode_wrap
|
||||||
@@ -101,9 +105,6 @@ def setup_for_low_vram(sd_model, use_medvram):
|
|||||||
if sd_model.embedder:
|
if sd_model.embedder:
|
||||||
sd_model.embedder.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.embedder.register_forward_pre_hook(send_me_to_gpu)
|
||||||
|
|
||||||
if hasattr(sd_model, 'cond_stage_model'):
|
|
||||||
parents[sd_model.cond_stage_model.transformer] = sd_model.cond_stage_model
|
|
||||||
|
|
||||||
if use_medvram:
|
if use_medvram:
|
||||||
sd_model.model.register_forward_pre_hook(send_me_to_gpu)
|
sd_model.model.register_forward_pre_hook(send_me_to_gpu)
|
||||||
else:
|
else:
|
||||||
|
|||||||
+63
-21
@@ -14,7 +14,7 @@ from skimage import exposure
|
|||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
import modules.sd_hijack
|
import modules.sd_hijack
|
||||||
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, extra_networks, sd_vae_approx, scripts, sd_samplers_common, sd_unet
|
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, extra_networks, sd_vae_approx, scripts, sd_samplers_common, sd_unet, errors
|
||||||
from modules.sd_hijack import model_hijack
|
from modules.sd_hijack import model_hijack
|
||||||
from modules.shared import opts, cmd_opts, state
|
from modules.shared import opts, cmd_opts, state
|
||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
@@ -538,6 +538,40 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see
|
|||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def decode_latent_batch(model, batch, target_device=None, check_for_nans=False):
|
||||||
|
samples = []
|
||||||
|
|
||||||
|
for i in range(batch.shape[0]):
|
||||||
|
sample = decode_first_stage(model, batch[i:i + 1])[0]
|
||||||
|
|
||||||
|
if check_for_nans:
|
||||||
|
try:
|
||||||
|
devices.test_for_nans(sample, "vae")
|
||||||
|
except devices.NansException as e:
|
||||||
|
if devices.dtype_vae == torch.float32 or not shared.opts.auto_vae_precision:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
errors.print_error_explanation(
|
||||||
|
"A tensor with all NaNs was produced in VAE.\n"
|
||||||
|
"Web UI will now convert VAE into 32-bit float and retry.\n"
|
||||||
|
"To disable this behavior, disable the 'Automaticlly revert VAE to 32-bit floats' setting.\n"
|
||||||
|
"To always start with 32-bit VAE, use --no-half-vae commandline flag."
|
||||||
|
)
|
||||||
|
|
||||||
|
devices.dtype_vae = torch.float32
|
||||||
|
model.first_stage_model.to(devices.dtype_vae)
|
||||||
|
batch = batch.to(devices.dtype_vae)
|
||||||
|
|
||||||
|
sample = decode_first_stage(model, batch[i:i + 1])[0]
|
||||||
|
|
||||||
|
if target_device is not None:
|
||||||
|
sample = sample.to(target_device)
|
||||||
|
|
||||||
|
samples.append(sample)
|
||||||
|
|
||||||
|
return samples
|
||||||
|
|
||||||
|
|
||||||
def decode_first_stage(model, x):
|
def decode_first_stage(model, x):
|
||||||
x = model.decode_first_stage(x.to(devices.dtype_vae))
|
x = model.decode_first_stage(x.to(devices.dtype_vae))
|
||||||
|
|
||||||
@@ -566,9 +600,13 @@ def program_version():
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, use_main_prompt=False):
|
def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, use_main_prompt=False, index=None, all_negative_prompts=None):
|
||||||
|
if index is None:
|
||||||
index = position_in_batch + iteration * p.batch_size
|
index = position_in_batch + iteration * p.batch_size
|
||||||
|
|
||||||
|
if all_negative_prompts is None:
|
||||||
|
all_negative_prompts = p.all_negative_prompts
|
||||||
|
|
||||||
clip_skip = getattr(p, 'clip_skip', opts.CLIP_stop_at_last_layers)
|
clip_skip = getattr(p, 'clip_skip', opts.CLIP_stop_at_last_layers)
|
||||||
enable_hr = getattr(p, 'enable_hr', False)
|
enable_hr = getattr(p, 'enable_hr', False)
|
||||||
token_merging_ratio = p.get_token_merging_ratio()
|
token_merging_ratio = p.get_token_merging_ratio()
|
||||||
@@ -583,12 +621,12 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter
|
|||||||
"Sampler": p.sampler_name,
|
"Sampler": p.sampler_name,
|
||||||
"CFG scale": p.cfg_scale,
|
"CFG scale": p.cfg_scale,
|
||||||
"Image CFG scale": getattr(p, 'image_cfg_scale', None),
|
"Image CFG scale": getattr(p, 'image_cfg_scale', None),
|
||||||
"Seed": all_seeds[index],
|
"Seed": p.all_seeds[0] if use_main_prompt else all_seeds[index],
|
||||||
"Face restoration": (opts.face_restoration_model if p.restore_faces else None),
|
"Face restoration": (opts.face_restoration_model if p.restore_faces else None),
|
||||||
"Size": f"{p.width}x{p.height}",
|
"Size": f"{p.width}x{p.height}",
|
||||||
"Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash),
|
"Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash),
|
||||||
"Model": (None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')),
|
"Model": (None if not opts.add_model_name_to_info else shared.sd_model.sd_checkpoint_info.name_for_extra),
|
||||||
"Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]),
|
"Variation seed": (None if p.subseed_strength == 0 else (p.all_subseeds[0] if use_main_prompt else all_subseeds[index])),
|
||||||
"Variation seed strength": (None if p.subseed_strength == 0 else p.subseed_strength),
|
"Variation seed strength": (None if p.subseed_strength == 0 else p.subseed_strength),
|
||||||
"Seed resize from": (None if p.seed_resize_from_w <= 0 or p.seed_resize_from_h <= 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}"),
|
"Seed resize from": (None if p.seed_resize_from_w <= 0 or p.seed_resize_from_h <= 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}"),
|
||||||
"Denoising strength": getattr(p, 'denoising_strength', None),
|
"Denoising strength": getattr(p, 'denoising_strength', None),
|
||||||
@@ -608,7 +646,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter
|
|||||||
generation_params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in generation_params.items() if v is not None])
|
generation_params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in generation_params.items() if v is not None])
|
||||||
|
|
||||||
prompt_text = p.prompt if use_main_prompt else all_prompts[index]
|
prompt_text = p.prompt if use_main_prompt else all_prompts[index]
|
||||||
negative_prompt_text = f"\nNegative prompt: {p.all_negative_prompts[index]}" if p.all_negative_prompts[index] else ""
|
negative_prompt_text = f"\nNegative prompt: {all_negative_prompts[index]}" if all_negative_prompts[index] else ""
|
||||||
|
|
||||||
return f"{prompt_text}{negative_prompt_text}\n{generation_params_text}".strip()
|
return f"{prompt_text}{negative_prompt_text}\n{generation_params_text}".strip()
|
||||||
|
|
||||||
@@ -682,9 +720,6 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
else:
|
else:
|
||||||
p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))]
|
p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))]
|
||||||
|
|
||||||
def infotext(iteration=0, position_in_batch=0, use_main_prompt=False):
|
|
||||||
return create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, comments, iteration, position_in_batch, use_main_prompt)
|
|
||||||
|
|
||||||
if os.path.exists(cmd_opts.embeddings_dir) and not p.do_not_reload_embeddings:
|
if os.path.exists(cmd_opts.embeddings_dir) and not p.do_not_reload_embeddings:
|
||||||
model_hijack.embedding_db.load_textual_inversion_embeddings()
|
model_hijack.embedding_db.load_textual_inversion_embeddings()
|
||||||
|
|
||||||
@@ -758,10 +793,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
with devices.without_autocast() if devices.unet_needs_upcast else devices.autocast():
|
with devices.without_autocast() if devices.unet_needs_upcast else devices.autocast():
|
||||||
samples_ddim = p.sample(conditioning=p.c, unconditional_conditioning=p.uc, seeds=p.seeds, subseeds=p.subseeds, subseed_strength=p.subseed_strength, prompts=p.prompts)
|
samples_ddim = p.sample(conditioning=p.c, unconditional_conditioning=p.uc, seeds=p.seeds, subseeds=p.subseeds, subseed_strength=p.subseed_strength, prompts=p.prompts)
|
||||||
|
|
||||||
x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
|
x_samples_ddim = decode_latent_batch(p.sd_model, samples_ddim, target_device=devices.cpu, check_for_nans=True)
|
||||||
for x in x_samples_ddim:
|
|
||||||
devices.test_for_nans(x, "vae")
|
|
||||||
|
|
||||||
x_samples_ddim = torch.stack(x_samples_ddim).float()
|
x_samples_ddim = torch.stack(x_samples_ddim).float()
|
||||||
x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
|
x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
|
||||||
|
|
||||||
@@ -775,6 +807,16 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
if p.scripts is not None:
|
if p.scripts is not None:
|
||||||
p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
|
p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
|
||||||
|
|
||||||
|
p.prompts = p.all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
|
||||||
|
p.negative_prompts = p.all_negative_prompts[n * p.batch_size:(n + 1) * p.batch_size]
|
||||||
|
|
||||||
|
batch_params = scripts.PostprocessBatchListArgs(list(x_samples_ddim))
|
||||||
|
p.scripts.postprocess_batch_list(p, batch_params, batch_number=n)
|
||||||
|
x_samples_ddim = batch_params.images
|
||||||
|
|
||||||
|
def infotext(index=0, use_main_prompt=False):
|
||||||
|
return create_infotext(p, p.prompts, p.seeds, p.subseeds, use_main_prompt=use_main_prompt, index=index, all_negative_prompts=p.negative_prompts)
|
||||||
|
|
||||||
for i, x_sample in enumerate(x_samples_ddim):
|
for i, x_sample in enumerate(x_samples_ddim):
|
||||||
p.batch_index = i
|
p.batch_index = i
|
||||||
|
|
||||||
@@ -783,7 +825,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
|
|
||||||
if p.restore_faces:
|
if p.restore_faces:
|
||||||
if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration:
|
if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration:
|
||||||
images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-face-restoration")
|
images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-before-face-restoration")
|
||||||
|
|
||||||
devices.torch_gc()
|
devices.torch_gc()
|
||||||
|
|
||||||
@@ -800,15 +842,15 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
if p.color_corrections is not None and i < len(p.color_corrections):
|
if p.color_corrections is not None and i < len(p.color_corrections):
|
||||||
if opts.save and not p.do_not_save_samples and opts.save_images_before_color_correction:
|
if opts.save and not p.do_not_save_samples and opts.save_images_before_color_correction:
|
||||||
image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||||
images.save_image(image_without_cc, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-color-correction")
|
images.save_image(image_without_cc, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-before-color-correction")
|
||||||
image = apply_color_correction(p.color_corrections[i], image)
|
image = apply_color_correction(p.color_corrections[i], image)
|
||||||
|
|
||||||
image = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
image = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||||
|
|
||||||
if opts.samples_save and not p.do_not_save_samples:
|
if opts.samples_save and not p.do_not_save_samples:
|
||||||
images.save_image(image, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(n, i), p=p)
|
images.save_image(image, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p)
|
||||||
|
|
||||||
text = infotext(n, i)
|
text = infotext(i)
|
||||||
infotexts.append(text)
|
infotexts.append(text)
|
||||||
if opts.enable_pnginfo:
|
if opts.enable_pnginfo:
|
||||||
image.info["parameters"] = text
|
image.info["parameters"] = text
|
||||||
@@ -819,10 +861,10 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), images.resize_image(2, p.mask_for_overlay, image.width, image.height).convert('L')).convert('RGBA')
|
image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), images.resize_image(2, p.mask_for_overlay, image.width, image.height).convert('L')).convert('RGBA')
|
||||||
|
|
||||||
if opts.save_mask:
|
if opts.save_mask:
|
||||||
images.save_image(image_mask, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask")
|
images.save_image(image_mask, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-mask")
|
||||||
|
|
||||||
if opts.save_mask_composite:
|
if opts.save_mask_composite:
|
||||||
images.save_image(image_mask_composite, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask-composite")
|
images.save_image(image_mask_composite, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-mask-composite")
|
||||||
|
|
||||||
if opts.return_mask:
|
if opts.return_mask:
|
||||||
output_images.append(image_mask)
|
output_images.append(image_mask)
|
||||||
@@ -863,7 +905,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
p,
|
p,
|
||||||
images_list=output_images,
|
images_list=output_images,
|
||||||
seed=p.all_seeds[0],
|
seed=p.all_seeds[0],
|
||||||
info=infotext(),
|
info=infotexts[0],
|
||||||
comments="".join(f"{comment}\n" for comment in comments),
|
comments="".join(f"{comment}\n" for comment in comments),
|
||||||
subseed=p.all_subseeds[0],
|
subseed=p.all_subseeds[0],
|
||||||
index_of_first_image=index_of_first_image,
|
index_of_first_image=index_of_first_image,
|
||||||
@@ -1029,7 +1071,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
|||||||
image = sd_samplers.sample_to_image(image, index, approximation=0)
|
image = sd_samplers.sample_to_image(image, index, approximation=0)
|
||||||
|
|
||||||
info = create_infotext(self, self.all_prompts, self.all_seeds, self.all_subseeds, [], iteration=self.iteration, position_in_batch=index)
|
info = create_infotext(self, self.all_prompts, self.all_seeds, self.all_subseeds, [], iteration=self.iteration, position_in_batch=index)
|
||||||
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], opts.samples_format, info=info, suffix="-before-highres-fix")
|
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], opts.samples_format, info=info, p=self, suffix="-before-highres-fix")
|
||||||
|
|
||||||
if latent_scale_mode is not None:
|
if latent_scale_mode is not None:
|
||||||
for i in range(samples.shape[0]):
|
for i in range(samples.shape[0]):
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ def get_learned_conditioning(model, prompts: SdConditioning | list[str], steps):
|
|||||||
|
|
||||||
|
|
||||||
re_AND = re.compile(r"\bAND\b")
|
re_AND = re.compile(r"\bAND\b")
|
||||||
re_weight = re.compile(r"^(.*?)(?:\s*:\s*([-+]?(?:\d+\.?|\d*\.\d+)))?\s*$")
|
re_weight = re.compile(r"^((?:\s|.)*?)(?:\s*:\s*([-+]?(?:\d+\.?|\d*\.\d+)))?\s*$")
|
||||||
|
|
||||||
|
|
||||||
def get_multicond_prompt_list(prompts: SdConditioning | list[str]):
|
def get_multicond_prompt_list(prompts: SdConditioning | list[str]):
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ def load_module(path):
|
|||||||
return module
|
return module
|
||||||
|
|
||||||
|
|
||||||
def preload_extensions(extensions_dir, parser):
|
def preload_extensions(extensions_dir, parser, extension_list=None):
|
||||||
if not os.path.isdir(extensions_dir):
|
if not os.path.isdir(extensions_dir):
|
||||||
return
|
return
|
||||||
|
|
||||||
for dirname in sorted(os.listdir(extensions_dir)):
|
extensions = extension_list if extension_list is not None else os.listdir(extensions_dir)
|
||||||
|
for dirname in sorted(extensions):
|
||||||
preload_script = os.path.join(extensions_dir, dirname, "preload.py")
|
preload_script = os.path.join(extensions_dir, dirname, "preload.py")
|
||||||
if not os.path.isfile(preload_script):
|
if not os.path.isfile(preload_script):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ class PostprocessImageArgs:
|
|||||||
self.image = image
|
self.image = image
|
||||||
|
|
||||||
|
|
||||||
|
class PostprocessBatchListArgs:
|
||||||
|
def __init__(self, images):
|
||||||
|
self.images = images
|
||||||
|
|
||||||
|
|
||||||
class Script:
|
class Script:
|
||||||
name = None
|
name = None
|
||||||
"""script's internal name derived from title"""
|
"""script's internal name derived from title"""
|
||||||
@@ -156,6 +161,25 @@ class Script:
|
|||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def postprocess_batch_list(self, p, pp: PostprocessBatchListArgs, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Same as postprocess_batch(), but receives batch images as a list of 3D tensors instead of a 4D tensor.
|
||||||
|
This is useful when you want to update the entire batch instead of individual images.
|
||||||
|
|
||||||
|
You can modify the postprocessing object (pp) to update the images in the batch, remove images, add images, etc.
|
||||||
|
If the number of images is different from the batch size when returning,
|
||||||
|
then the script has the responsibility to also update the following attributes in the processing object (p):
|
||||||
|
- p.prompts
|
||||||
|
- p.negative_prompts
|
||||||
|
- p.seeds
|
||||||
|
- p.subseeds
|
||||||
|
|
||||||
|
**kwargs will have same items as process_batch, and also:
|
||||||
|
- batch_number - index of current batch, from 0 to number of batches-1
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
def postprocess_image(self, p, pp: PostprocessImageArgs, *args):
|
def postprocess_image(self, p, pp: PostprocessImageArgs, *args):
|
||||||
"""
|
"""
|
||||||
Called for every image after it has been generated.
|
Called for every image after it has been generated.
|
||||||
@@ -536,6 +560,14 @@ class ScriptRunner:
|
|||||||
except Exception:
|
except Exception:
|
||||||
errors.report(f"Error running postprocess_batch: {script.filename}", exc_info=True)
|
errors.report(f"Error running postprocess_batch: {script.filename}", exc_info=True)
|
||||||
|
|
||||||
|
def postprocess_batch_list(self, p, pp: PostprocessBatchListArgs, **kwargs):
|
||||||
|
for script in self.alwayson_scripts:
|
||||||
|
try:
|
||||||
|
script_args = p.script_args[script.args_from:script.args_to]
|
||||||
|
script.postprocess_batch_list(p, pp, *script_args, **kwargs)
|
||||||
|
except Exception:
|
||||||
|
errors.report(f"Error running postprocess_batch_list: {script.filename}", exc_info=True)
|
||||||
|
|
||||||
def postprocess_image(self, p, pp: PostprocessImageArgs):
|
def postprocess_image(self, p, pp: PostprocessImageArgs):
|
||||||
for script in self.alwayson_scripts:
|
for script in self.alwayson_scripts:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ class StableDiffusionModelHijack:
|
|||||||
ldm.modules.diffusionmodules.openaimodel.UNetModel.forward = sd_unet.UNetModel_forward
|
ldm.modules.diffusionmodules.openaimodel.UNetModel.forward = sd_unet.UNetModel_forward
|
||||||
|
|
||||||
def undo_hijack(self, m):
|
def undo_hijack(self, m):
|
||||||
if type(m.cond_stage_model) == xlmr.BertSeriesModelWithTransformation:
|
if type(m.cond_stage_model) == sd_hijack_xlmr.FrozenXLMREmbedderWithCustomWords:
|
||||||
m.cond_stage_model = m.cond_stage_model.wrapped
|
m.cond_stage_model = m.cond_stage_model.wrapped
|
||||||
|
|
||||||
elif type(m.cond_stage_model) == sd_hijack_clip.FrozenCLIPEmbedderWithCustomWords:
|
elif type(m.cond_stage_model) == sd_hijack_clip.FrozenCLIPEmbedderWithCustomWords:
|
||||||
|
|||||||
@@ -270,12 +270,17 @@ class FrozenCLIPEmbedderWithCustomWordsBase(torch.nn.Module):
|
|||||||
|
|
||||||
z = self.encode_with_transformers(tokens)
|
z = self.encode_with_transformers(tokens)
|
||||||
|
|
||||||
|
pooled = getattr(z, 'pooled', None)
|
||||||
|
|
||||||
# restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise
|
# restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise
|
||||||
batch_multipliers = torch.asarray(batch_multipliers).to(devices.device)
|
batch_multipliers = torch.asarray(batch_multipliers).to(devices.device)
|
||||||
original_mean = z.mean()
|
original_mean = z.mean()
|
||||||
z *= batch_multipliers.reshape(batch_multipliers.shape + (1,)).expand(z.shape)
|
z = z * batch_multipliers.reshape(batch_multipliers.shape + (1,)).expand(z.shape)
|
||||||
new_mean = z.mean()
|
new_mean = z.mean()
|
||||||
z *= (original_mean / new_mean)
|
z = z * (original_mean / new_mean)
|
||||||
|
|
||||||
|
if pooled is not None:
|
||||||
|
z.pooled = pooled
|
||||||
|
|
||||||
return z
|
return z
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class FrozenOpenCLIPEmbedderWithCustomWords(sd_hijack_clip.FrozenCLIPEmbedderWit
|
|||||||
def encode_embedding_init_text(self, init_text, nvpt):
|
def encode_embedding_init_text(self, init_text, nvpt):
|
||||||
ids = tokenizer.encode(init_text)
|
ids = tokenizer.encode(init_text)
|
||||||
ids = torch.asarray([ids], device=devices.device, dtype=torch.int)
|
ids = torch.asarray([ids], device=devices.device, dtype=torch.int)
|
||||||
embedded = self.wrapped.model.token_embedding.wrapped(ids.to(self.wrapped.model.token_embedding.wrapped.weight.device)).squeeze(0)
|
embedded = self.wrapped.model.token_embedding.wrapped(ids).squeeze(0)
|
||||||
|
|
||||||
return embedded
|
return embedded
|
||||||
|
|
||||||
|
|||||||
@@ -256,9 +256,9 @@ def split_cross_attention_forward(self, x, context=None, mask=None, **kwargs):
|
|||||||
raise RuntimeError(f'Not enough memory, use lower resolution (max approx. {max_res}x{max_res}). '
|
raise RuntimeError(f'Not enough memory, use lower resolution (max approx. {max_res}x{max_res}). '
|
||||||
f'Need: {mem_required / 64 / gb:0.1f}GB free, Have:{mem_free_total / gb:0.1f}GB free')
|
f'Need: {mem_required / 64 / gb:0.1f}GB free, Have:{mem_free_total / gb:0.1f}GB free')
|
||||||
|
|
||||||
slice_size = q.shape[1] // steps if (q.shape[1] % steps) == 0 else q.shape[1]
|
slice_size = q.shape[1] // steps
|
||||||
for i in range(0, q.shape[1], slice_size):
|
for i in range(0, q.shape[1], slice_size):
|
||||||
end = i + slice_size
|
end = min(i + slice_size, q.shape[1])
|
||||||
s1 = einsum('b i d, b j d -> b i j', q[:, i:end], k)
|
s1 = einsum('b i d, b j d -> b i j', q[:, i:end], k)
|
||||||
|
|
||||||
s2 = s1.softmax(dim=-1, dtype=q.dtype)
|
s2 = s1.softmax(dim=-1, dtype=q.dtype)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ def get_learned_conditioning(self: sgm.models.diffusion.DiffusionEngine, batch:
|
|||||||
for embedder in self.conditioner.embedders:
|
for embedder in self.conditioner.embedders:
|
||||||
embedder.ucg_rate = 0.0
|
embedder.ucg_rate = 0.0
|
||||||
|
|
||||||
width = getattr(self, 'target_width', 1024)
|
width = getattr(batch, 'width', 1024)
|
||||||
height = getattr(self, 'target_height', 1024)
|
height = getattr(batch, 'height', 1024)
|
||||||
is_negative_prompt = getattr(batch, 'is_negative_prompt', False)
|
is_negative_prompt = getattr(batch, 'is_negative_prompt', False)
|
||||||
aesthetic_score = shared.opts.sdxl_refiner_low_aesthetic_score if is_negative_prompt else shared.opts.sdxl_refiner_high_aesthetic_score
|
aesthetic_score = shared.opts.sdxl_refiner_low_aesthetic_score if is_negative_prompt else shared.opts.sdxl_refiner_high_aesthetic_score
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -11,6 +11,7 @@ import gradio as gr
|
|||||||
import torch
|
import torch
|
||||||
import tqdm
|
import tqdm
|
||||||
|
|
||||||
|
import launch
|
||||||
import modules.interrogate
|
import modules.interrogate
|
||||||
import modules.memmon
|
import modules.memmon
|
||||||
import modules.styles
|
import modules.styles
|
||||||
@@ -26,7 +27,7 @@ demo = None
|
|||||||
|
|
||||||
parser = cmd_args.parser
|
parser = cmd_args.parser
|
||||||
|
|
||||||
script_loading.preload_extensions(extensions_dir, parser)
|
script_loading.preload_extensions(extensions_dir, parser, extension_list=launch.list_extensions(launch.args.ui_settings_file))
|
||||||
script_loading.preload_extensions(extensions_builtin_dir, parser)
|
script_loading.preload_extensions(extensions_builtin_dir, parser)
|
||||||
|
|
||||||
if os.environ.get('IGNORE_CMD_ARGS_ERRORS', None) is None:
|
if os.environ.get('IGNORE_CMD_ARGS_ERRORS', None) is None:
|
||||||
@@ -426,6 +427,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
|||||||
"comma_padding_backtrack": OptionInfo(20, "Prompt word wrap length limit", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1}).info("in tokens - for texts shorter than specified, if they don't fit into 75 token limit, move them to the next 75 token chunk"),
|
"comma_padding_backtrack": OptionInfo(20, "Prompt word wrap length limit", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1}).info("in tokens - for texts shorter than specified, if they don't fit into 75 token limit, move them to the next 75 token chunk"),
|
||||||
"CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}).link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#clip-skip").info("ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer"),
|
"CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}).link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#clip-skip").info("ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer"),
|
||||||
"upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"),
|
"upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"),
|
||||||
|
"auto_vae_precision": OptionInfo(True, "Automaticlly revert VAE to 32-bit floats").info("triggers when a tensor with NaNs is produced in VAE; disabling the option in this case will result in a black square image"),
|
||||||
"randn_source": OptionInfo("GPU", "Random number generator source.", gr.Radio, {"choices": ["GPU", "CPU"]}).info("changes seeds drastically; use CPU to produce the same picture across different videocard vendors"),
|
"randn_source": OptionInfo("GPU", "Random number generator source.", gr.Radio, {"choices": ["GPU", "CPU"]}).info("changes seeds drastically; use CPU to produce the same picture across different videocard vendors"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -109,11 +109,15 @@ def format_traceback(tb):
|
|||||||
return [[f"{x.filename}, line {x.lineno}, {x.name}", x.line] for x in traceback.extract_tb(tb)]
|
return [[f"{x.filename}, line {x.lineno}, {x.name}", x.line] for x in traceback.extract_tb(tb)]
|
||||||
|
|
||||||
|
|
||||||
|
def format_exception(e, tb):
|
||||||
|
return {"exception": str(e), "traceback": format_traceback(tb)}
|
||||||
|
|
||||||
|
|
||||||
def get_exceptions():
|
def get_exceptions():
|
||||||
try:
|
try:
|
||||||
from modules import errors
|
from modules import errors
|
||||||
|
|
||||||
return [{"exception": str(e), "traceback": format_traceback(tb)} for e, tb in reversed(errors.exception_records)]
|
return list(reversed(errors.exception_records))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class ExtraNetworksPage:
|
|||||||
"prompt": item.get("prompt", None),
|
"prompt": item.get("prompt", None),
|
||||||
"tabname": quote_js(tabname),
|
"tabname": quote_js(tabname),
|
||||||
"local_preview": quote_js(item["local_preview"]),
|
"local_preview": quote_js(item["local_preview"]),
|
||||||
"name": item["name"],
|
"name": html.escape(item["name"]),
|
||||||
"description": (item.get("description") or "" if shared.opts.extra_networks_card_show_desc else ""),
|
"description": (item.get("description") or "" if shared.opts.extra_networks_card_show_desc else ""),
|
||||||
"card_clicked": onclick,
|
"card_clicked": onclick,
|
||||||
"save_card_preview": '"' + html.escape(f"""return saveCardPreview(event, {quote_js(tabname)}, {quote_js(item["local_preview"])})""") + '"',
|
"save_card_preview": '"' + html.escape(f"""return saveCardPreview(event, {quote_js(tabname)}, {quote_js(item["local_preview"])})""") + '"',
|
||||||
|
|||||||
@@ -423,15 +423,16 @@ div#extras_scale_to_tab div.form{
|
|||||||
}
|
}
|
||||||
|
|
||||||
table.popup-table{
|
table.popup-table{
|
||||||
background: white;
|
background: var(--body-background-fill);
|
||||||
|
color: var(--body-text-color);
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
border: 4px solid white;
|
border: 4px solid var(--body-background-fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.popup-table td{
|
table.popup-table td{
|
||||||
padding: 0.4em;
|
padding: 0.4em;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid rgba(128, 128, 128, 0.5);
|
||||||
max-width: 36em;
|
max-width: 36em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ def api_only():
|
|||||||
api.launch(
|
api.launch(
|
||||||
server_name="0.0.0.0" if cmd_opts.listen else "127.0.0.1",
|
server_name="0.0.0.0" if cmd_opts.listen else "127.0.0.1",
|
||||||
port=cmd_opts.port if cmd_opts.port else 7861,
|
port=cmd_opts.port if cmd_opts.port else 7861,
|
||||||
root_path = f"/{cmd_opts.subpath}"
|
root_path=f"/{cmd_opts.subpath}" if cmd_opts.subpath else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
# change the variables in webui-user.sh instead #
|
# change the variables in webui-user.sh instead #
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
|
|
||||||
|
use_venv=1
|
||||||
|
if [[ $venv_dir == "-" ]]; then
|
||||||
|
use_venv=0
|
||||||
|
fi
|
||||||
|
|
||||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
|
||||||
# If run from macOS, load defaults from webui-macos-env.sh
|
# If run from macOS, load defaults from webui-macos-env.sh
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
if [[ -f "$SCRIPT_DIR"/webui-macos-env.sh ]]
|
if [[ -f "$SCRIPT_DIR"/webui-macos-env.sh ]]
|
||||||
@@ -47,7 +54,7 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# python3 venv without trailing slash (defaults to ${install_dir}/${clone_dir}/venv)
|
# python3 venv without trailing slash (defaults to ${install_dir}/${clone_dir}/venv)
|
||||||
if [[ -z "${venv_dir}" ]]
|
if [[ -z "${venv_dir}" ]] && [[ $use_venv -eq 1 ]]
|
||||||
then
|
then
|
||||||
venv_dir="venv"
|
venv_dir="venv"
|
||||||
fi
|
fi
|
||||||
@@ -164,7 +171,7 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if ! "${python_cmd}" -c "import venv" &>/dev/null
|
if [[ $use_venv -eq 1 ]] && ! "${python_cmd}" -c "import venv" &>/dev/null
|
||||||
then
|
then
|
||||||
printf "\n%s\n" "${delimiter}"
|
printf "\n%s\n" "${delimiter}"
|
||||||
printf "\e[1m\e[31mERROR: python3-venv is not installed, aborting...\e[0m"
|
printf "\e[1m\e[31mERROR: python3-venv is not installed, aborting...\e[0m"
|
||||||
@@ -184,7 +191,7 @@ else
|
|||||||
cd "${clone_dir}"/ || { printf "\e[1m\e[31mERROR: Can't cd to %s/%s/, aborting...\e[0m" "${install_dir}" "${clone_dir}"; exit 1; }
|
cd "${clone_dir}"/ || { printf "\e[1m\e[31mERROR: Can't cd to %s/%s/, aborting...\e[0m" "${install_dir}" "${clone_dir}"; exit 1; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${VIRTUAL_ENV}" ]];
|
if [[ $use_venv -eq 1 ]] && [[ -z "${VIRTUAL_ENV}" ]];
|
||||||
then
|
then
|
||||||
printf "\n%s\n" "${delimiter}"
|
printf "\n%s\n" "${delimiter}"
|
||||||
printf "Create and activate python venv"
|
printf "Create and activate python venv"
|
||||||
@@ -207,7 +214,7 @@ then
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
printf "\n%s\n" "${delimiter}"
|
printf "\n%s\n" "${delimiter}"
|
||||||
printf "python venv already activate: ${VIRTUAL_ENV}"
|
printf "python venv already activate or run without venv: ${VIRTUAL_ENV}"
|
||||||
printf "\n%s\n" "${delimiter}"
|
printf "\n%s\n" "${delimiter}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user