Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac8c05398b | |||
| 025080218f |
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- name: Install Ruff
|
- name: Install Ruff
|
||||||
run: pip install ruff==0.3.3
|
run: pip install ruff==0.3.3
|
||||||
- name: Run Ruff
|
- name: Run Ruff
|
||||||
run: ruff check .
|
run: ruff .
|
||||||
lint-js:
|
lint-js:
|
||||||
name: eslint
|
name: eslint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -1,69 +1,36 @@
|
|||||||
// Stable Diffusion WebUI - Bracket Checker
|
// Stable Diffusion WebUI - Bracket checker
|
||||||
// By @Bwin4L, @akx, @w-e-w, @Haoming02
|
// By Hingashi no Florin/Bwin4L & @akx
|
||||||
// Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs.
|
// Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs.
|
||||||
// If there's a mismatch, the keyword counter turns red, and if you hover on it, a tooltip tells you what's wrong.
|
// If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong.
|
||||||
|
|
||||||
function checkBrackets(textArea, counterElem) {
|
|
||||||
const pairs = [
|
|
||||||
['(', ')', 'round brackets'],
|
|
||||||
['[', ']', 'square brackets'],
|
|
||||||
['{', '}', 'curly brackets']
|
|
||||||
];
|
|
||||||
|
|
||||||
|
function checkBrackets(textArea, counterElt) {
|
||||||
const counts = {};
|
const counts = {};
|
||||||
const errors = new Set();
|
textArea.value.matchAll(/(?<!\\)(?:\\\\)*?([(){}[\]])/g).forEach(bracket => {
|
||||||
let i = 0;
|
counts[bracket[1]] = (counts[bracket[1]] || 0) + 1;
|
||||||
|
});
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
while (i < textArea.value.length) {
|
function checkPair(open, close, kind) {
|
||||||
let char = textArea.value[i];
|
if (counts[open] !== counts[close]) {
|
||||||
let escaped = false;
|
errors.push(
|
||||||
while (char === '\\' && i + 1 < textArea.value.length) {
|
`${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`
|
||||||
escaped = !escaped;
|
);
|
||||||
i++;
|
|
||||||
char = textArea.value[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (escaped) {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [open, close, label] of pairs) {
|
|
||||||
if (char === open) {
|
|
||||||
counts[label] = (counts[label] || 0) + 1;
|
|
||||||
} else if (char === close) {
|
|
||||||
counts[label] = (counts[label] || 0) - 1;
|
|
||||||
if (counts[label] < 0) {
|
|
||||||
errors.add(`Incorrect order of ${label}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [open, close, label] of pairs) {
|
|
||||||
if (counts[label] == undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (counts[label] > 0) {
|
|
||||||
errors.add(`${open} ... ${close} - Detected ${counts[label]} more opening than closing ${label}.`);
|
|
||||||
} else if (counts[label] < 0) {
|
|
||||||
errors.add(`${open} ... ${close} - Detected ${-counts[label]} more closing than opening ${label}.`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
counterElem.title = [...errors].join('\n');
|
checkPair('(', ')', 'round brackets');
|
||||||
counterElem.classList.toggle('error', errors.size !== 0);
|
checkPair('[', ']', 'square brackets');
|
||||||
|
checkPair('{', '}', 'curly brackets');
|
||||||
|
counterElt.title = errors.join('\n');
|
||||||
|
counterElt.classList.toggle('error', errors.length !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupBracketChecking(id_prompt, id_counter) {
|
function setupBracketChecking(id_prompt, id_counter) {
|
||||||
const textarea = gradioApp().querySelector(`#${id_prompt} > label > textarea`);
|
var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea");
|
||||||
const counter = gradioApp().getElementById(id_counter);
|
var counter = gradioApp().getElementById(id_counter);
|
||||||
|
|
||||||
if (textarea && counter) {
|
if (textarea && counter) {
|
||||||
onEdit(`${id_prompt}_BracketChecking`, textarea, 400, () => checkBrackets(textarea, counter));
|
textarea.addEventListener("input", () => checkBrackets(textarea, counter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,39 +69,3 @@ onOptionsChanged(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function downloadSysinfo() {
|
|
||||||
const pad = (n) => String(n).padStart(2, '0');
|
|
||||||
const now = new Date();
|
|
||||||
const YY = now.getFullYear();
|
|
||||||
const MM = pad(now.getMonth() + 1);
|
|
||||||
const DD = pad(now.getDate());
|
|
||||||
const HH = pad(now.getHours());
|
|
||||||
const mm = pad(now.getMinutes());
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.download = `sysinfo-${YY}-${MM}-${DD}-${HH}-${mm}.json`;
|
|
||||||
const sysinfo_textbox = gradioApp().querySelector('#internal-sysinfo-textbox textarea');
|
|
||||||
const content = sysinfo_textbox.value;
|
|
||||||
if (content.startsWith('file=')) {
|
|
||||||
link.href = content;
|
|
||||||
} else {
|
|
||||||
const blob = new Blob([content], {type: 'application/json'});
|
|
||||||
link.href = URL.createObjectURL(blob);
|
|
||||||
}
|
|
||||||
link.click();
|
|
||||||
sysinfo_textbox.value = '';
|
|
||||||
updateInput(sysinfo_textbox);
|
|
||||||
}
|
|
||||||
|
|
||||||
function openTabSysinfo() {
|
|
||||||
const sysinfo_textbox = gradioApp().querySelector('#internal-sysinfo-textbox textarea');
|
|
||||||
const content = sysinfo_textbox.value;
|
|
||||||
if (content.startsWith('file=')) {
|
|
||||||
window.open(content, '_blank');
|
|
||||||
} else {
|
|
||||||
const blob = new Blob([content], {type: 'application/json'});
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
window.open(url, '_blank');
|
|
||||||
}
|
|
||||||
sysinfo_textbox.value = '';
|
|
||||||
updateInput(sysinfo_textbox);
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-4
@@ -17,7 +17,7 @@ from fastapi.encoders import jsonable_encoder
|
|||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
|
|
||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, infotext_utils, sd_models, sd_schedulers, sysinfo
|
from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, infotext_utils, sd_models, sd_schedulers
|
||||||
from modules.api import models
|
from modules.api import models
|
||||||
from modules.shared import opts
|
from modules.shared import opts
|
||||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
||||||
@@ -33,7 +33,6 @@ import piexif.helper
|
|||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from modules.progress import create_task_id, add_task_to_queue, start_task, finish_task, current_task
|
from modules.progress import create_task_id, add_task_to_queue, start_task, finish_task, current_task
|
||||||
|
|
||||||
|
|
||||||
def script_name_to_index(name, scripts):
|
def script_name_to_index(name, scripts):
|
||||||
try:
|
try:
|
||||||
return [script.title().lower() for script in scripts].index(name.lower())
|
return [script.title().lower() for script in scripts].index(name.lower())
|
||||||
@@ -245,8 +244,6 @@ class Api:
|
|||||||
self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList)
|
self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList)
|
||||||
self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=list[models.ScriptInfo])
|
self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=list[models.ScriptInfo])
|
||||||
self.add_api_route("/sdapi/v1/extensions", self.get_extensions_list, methods=["GET"], response_model=list[models.ExtensionItem])
|
self.add_api_route("/sdapi/v1/extensions", self.get_extensions_list, methods=["GET"], response_model=list[models.ExtensionItem])
|
||||||
self.add_api_route("/internal/sysinfo", sysinfo.download_sysinfo, methods=["GET"])
|
|
||||||
self.add_api_route("/internal/sysinfo-download", lambda: sysinfo.download_sysinfo(attachment=True), methods=["GET"])
|
|
||||||
|
|
||||||
if shared.cmd_opts.api_server_stop:
|
if shared.cmd_opts.api_server_stop:
|
||||||
self.add_api_route("/sdapi/v1/server-kill", self.kill_webui, methods=["POST"])
|
self.add_api_route("/sdapi/v1/server-kill", self.kill_webui, methods=["POST"])
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ def check_python_version():
|
|||||||
supported_minors = [7, 8, 9, 10, 11]
|
supported_minors = [7, 8, 9, 10, 11]
|
||||||
|
|
||||||
if not (major == 3 and minor in supported_minors):
|
if not (major == 3 and minor in supported_minors):
|
||||||
errors.print_error_explanation(f"""
|
import modules.errors
|
||||||
|
|
||||||
|
modules.errors.print_error_explanation(f"""
|
||||||
INCOMPATIBLE PYTHON VERSION
|
INCOMPATIBLE PYTHON VERSION
|
||||||
|
|
||||||
This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}.
|
This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}.
|
||||||
|
|||||||
+34
-6
@@ -16,7 +16,7 @@ from skimage import exposure
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import modules.sd_hijack
|
import modules.sd_hijack
|
||||||
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, infotext_utils, extra_networks, sd_vae_approx, scripts, sd_samplers_common, sd_unet, errors, rng, profiling
|
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, infotext_utils, extra_networks, sd_vae_approx, scripts, sd_samplers_common, sd_unet, errors, rng, profiling, util
|
||||||
from modules.rng import slerp # noqa: F401
|
from modules.rng import slerp # noqa: F401
|
||||||
from modules.sd_hijack import model_hijack
|
from modules.sd_hijack import model_hijack
|
||||||
from modules.sd_samplers_common import images_tensor_to_samples, decode_first_stage, approximation_indexes
|
from modules.sd_samplers_common import images_tensor_to_samples, decode_first_stage, approximation_indexes
|
||||||
@@ -457,6 +457,20 @@ class StableDiffusionProcessing:
|
|||||||
opts.emphasis,
|
opts.emphasis,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def apply_generation_params_list(self, generation_params_states):
|
||||||
|
"""add and apply generation_params_states to self.extra_generation_params"""
|
||||||
|
for key, value in generation_params_states.items():
|
||||||
|
if key in self.extra_generation_params and isinstance(current_value := self.extra_generation_params[key], util.GenerationParametersList):
|
||||||
|
self.extra_generation_params[key] = current_value + value
|
||||||
|
else:
|
||||||
|
self.extra_generation_params[key] = value
|
||||||
|
|
||||||
|
def clear_marked_generation_params(self):
|
||||||
|
"""clears any generation parameters that are with the attribute to_be_clear_before_batch = True"""
|
||||||
|
for key, value in list(self.extra_generation_params.items()):
|
||||||
|
if getattr(value, 'to_be_clear_before_batch', False):
|
||||||
|
self.extra_generation_params.pop(key)
|
||||||
|
|
||||||
def get_conds_with_caching(self, function, required_prompts, steps, caches, extra_network_data, hires_steps=None):
|
def get_conds_with_caching(self, function, required_prompts, steps, caches, extra_network_data, hires_steps=None):
|
||||||
"""
|
"""
|
||||||
Returns the result of calling function(shared.sd_model, required_prompts, steps)
|
Returns the result of calling function(shared.sd_model, required_prompts, steps)
|
||||||
@@ -480,6 +494,10 @@ class StableDiffusionProcessing:
|
|||||||
|
|
||||||
for cache in caches:
|
for cache in caches:
|
||||||
if cache[0] is not None and cached_params == cache[0]:
|
if cache[0] is not None and cached_params == cache[0]:
|
||||||
|
if len(cache) == 3:
|
||||||
|
generation_params_states, cached_cached_params = cache[2]
|
||||||
|
if cached_params == cached_cached_params:
|
||||||
|
self.apply_generation_params_list(generation_params_states)
|
||||||
return cache[1]
|
return cache[1]
|
||||||
|
|
||||||
cache = caches[0]
|
cache = caches[0]
|
||||||
@@ -487,6 +505,13 @@ class StableDiffusionProcessing:
|
|||||||
with devices.autocast():
|
with devices.autocast():
|
||||||
cache[1] = function(shared.sd_model, required_prompts, steps, hires_steps, shared.opts.use_old_scheduling)
|
cache[1] = function(shared.sd_model, required_prompts, steps, hires_steps, shared.opts.use_old_scheduling)
|
||||||
|
|
||||||
|
generation_params_states = model_hijack.extract_generation_params_states()
|
||||||
|
self.apply_generation_params_list(generation_params_states)
|
||||||
|
if len(cache) == 2:
|
||||||
|
cache.append((generation_params_states, cached_params))
|
||||||
|
else:
|
||||||
|
cache[2] = (generation_params_states, cached_params)
|
||||||
|
|
||||||
cache[0] = cached_params
|
cache[0] = cached_params
|
||||||
return cache[1]
|
return cache[1]
|
||||||
|
|
||||||
@@ -502,6 +527,8 @@ class StableDiffusionProcessing:
|
|||||||
self.uc = self.get_conds_with_caching(prompt_parser.get_learned_conditioning, negative_prompts, total_steps, [self.cached_uc], self.extra_network_data)
|
self.uc = self.get_conds_with_caching(prompt_parser.get_learned_conditioning, negative_prompts, total_steps, [self.cached_uc], self.extra_network_data)
|
||||||
self.c = self.get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, prompts, total_steps, [self.cached_c], self.extra_network_data)
|
self.c = self.get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, prompts, total_steps, [self.cached_c], self.extra_network_data)
|
||||||
|
|
||||||
|
self.extra_generation_params.update(model_hijack.extra_generation_params)
|
||||||
|
|
||||||
def get_conds(self):
|
def get_conds(self):
|
||||||
return self.c, self.uc
|
return self.c, self.uc
|
||||||
|
|
||||||
@@ -801,10 +828,10 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter
|
|||||||
|
|
||||||
for key, value in generation_params.items():
|
for key, value in generation_params.items():
|
||||||
try:
|
try:
|
||||||
if isinstance(value, list):
|
if callable(value):
|
||||||
generation_params[key] = value[index]
|
|
||||||
elif callable(value):
|
|
||||||
generation_params[key] = value(**locals())
|
generation_params[key] = value(**locals())
|
||||||
|
elif isinstance(value, list):
|
||||||
|
generation_params[key] = value[index]
|
||||||
except Exception:
|
except Exception:
|
||||||
errors.report(f'Error creating infotext for key "{key}"', exc_info=True)
|
errors.report(f'Error creating infotext for key "{key}"', exc_info=True)
|
||||||
generation_params[key] = None
|
generation_params[key] = None
|
||||||
@@ -938,6 +965,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
if state.interrupted or state.stopping_generation:
|
if state.interrupted or state.stopping_generation:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
p.clear_marked_generation_params() # clean up some generation params are tagged to be cleared before batch
|
||||||
sd_models.reload_model_weights() # model can be changed for example by refiner
|
sd_models.reload_model_weights() # model can be changed for example by refiner
|
||||||
|
|
||||||
p.prompts = p.all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
|
p.prompts = p.all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
|
||||||
@@ -965,8 +993,6 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
|||||||
|
|
||||||
p.setup_conds()
|
p.setup_conds()
|
||||||
|
|
||||||
p.extra_generation_params.update(model_hijack.extra_generation_params)
|
|
||||||
|
|
||||||
# params.txt should be saved after scripts.process_batch, since the
|
# params.txt should be saved after scripts.process_batch, since the
|
||||||
# infotext could be modified by that callback
|
# infotext could be modified by that callback
|
||||||
# Example: a wildcard processed by process_batch sets an extra model
|
# Example: a wildcard processed by process_batch sets an extra model
|
||||||
@@ -1513,6 +1539,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
|||||||
self.hr_uc = self.get_conds_with_caching(prompt_parser.get_learned_conditioning, hr_negative_prompts, self.firstpass_steps, [self.cached_hr_uc, self.cached_uc], self.hr_extra_network_data, total_steps)
|
self.hr_uc = self.get_conds_with_caching(prompt_parser.get_learned_conditioning, hr_negative_prompts, self.firstpass_steps, [self.cached_hr_uc, self.cached_uc], self.hr_extra_network_data, total_steps)
|
||||||
self.hr_c = self.get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, hr_prompts, self.firstpass_steps, [self.cached_hr_c, self.cached_c], self.hr_extra_network_data, total_steps)
|
self.hr_c = self.get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, hr_prompts, self.firstpass_steps, [self.cached_hr_c, self.cached_c], self.hr_extra_network_data, total_steps)
|
||||||
|
|
||||||
|
self.extra_generation_params.update(model_hijack.extra_generation_params)
|
||||||
|
|
||||||
def setup_conds(self):
|
def setup_conds(self):
|
||||||
if self.is_hr_pass:
|
if self.is_hr_pass:
|
||||||
# if we are in hr pass right now, the call is being made from the refiner, and we don't need to setup firstpass cons or switch model
|
# if we are in hr pass right now, the call is being made from the refiner, and we don't need to setup firstpass cons or switch model
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import torch
|
|||||||
from torch.nn.functional import silu
|
from torch.nn.functional import silu
|
||||||
from types import MethodType
|
from types import MethodType
|
||||||
|
|
||||||
from modules import devices, sd_hijack_optimizations, shared, script_callbacks, errors, sd_unet, patches
|
from modules import devices, sd_hijack_optimizations, shared, script_callbacks, errors, sd_unet, patches, util
|
||||||
from modules.hypernetworks import hypernetwork
|
from modules.hypernetworks import hypernetwork
|
||||||
from modules.shared import cmd_opts
|
from modules.shared import cmd_opts
|
||||||
from modules import sd_hijack_clip, sd_hijack_open_clip, sd_hijack_unet, sd_hijack_xlmr, xlmr, xlmr_m18
|
from modules import sd_hijack_clip, sd_hijack_open_clip, sd_hijack_unet, sd_hijack_xlmr, xlmr, xlmr_m18
|
||||||
@@ -321,6 +321,14 @@ class StableDiffusionModelHijack:
|
|||||||
self.comments = []
|
self.comments = []
|
||||||
self.extra_generation_params = {}
|
self.extra_generation_params = {}
|
||||||
|
|
||||||
|
def extract_generation_params_states(self):
|
||||||
|
"""Extracts GenerationParametersList so that they can be cached and restored later"""
|
||||||
|
states = {}
|
||||||
|
for key in list(self.extra_generation_params):
|
||||||
|
if isinstance(self.extra_generation_params[key], util.GenerationParametersList):
|
||||||
|
states[key] = self.extra_generation_params.pop(key)
|
||||||
|
return states
|
||||||
|
|
||||||
def get_prompt_lengths(self, text):
|
def get_prompt_lengths(self, text):
|
||||||
if self.clip is None:
|
if self.clip is None:
|
||||||
return "-", "-"
|
return "-", "-"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from collections import namedtuple
|
|||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from modules import prompt_parser, devices, sd_hijack, sd_emphasis
|
from modules import prompt_parser, devices, sd_hijack, sd_emphasis, util
|
||||||
from modules.shared import opts
|
from modules.shared import opts
|
||||||
|
|
||||||
|
|
||||||
@@ -27,6 +27,30 @@ chunk. Those objects are found in PromptChunk.fixes and, are placed into FrozenC
|
|||||||
are applied by sd_hijack.EmbeddingsWithFixes's forward function."""
|
are applied by sd_hijack.EmbeddingsWithFixes's forward function."""
|
||||||
|
|
||||||
|
|
||||||
|
class EmphasisMode(util.GenerationParametersList):
|
||||||
|
def __init__(self, emphasis_mode:str = None):
|
||||||
|
super().__init__()
|
||||||
|
self.emphasis_mode = emphasis_mode
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.emphasis_mode
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if isinstance(other, EmphasisMode):
|
||||||
|
return self if self.emphasis_mode else other
|
||||||
|
elif isinstance(other, str):
|
||||||
|
return self.__str__() + other
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
if isinstance(other, str):
|
||||||
|
return other + self.__str__()
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.emphasis_mode if self.emphasis_mode else ''
|
||||||
|
|
||||||
|
|
||||||
class TextConditionalModel(torch.nn.Module):
|
class TextConditionalModel(torch.nn.Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -238,12 +262,10 @@ class TextConditionalModel(torch.nn.Module):
|
|||||||
hashes.append(f"{name}: {shorthash}")
|
hashes.append(f"{name}: {shorthash}")
|
||||||
|
|
||||||
if hashes:
|
if hashes:
|
||||||
if self.hijack.extra_generation_params.get("TI hashes"):
|
self.hijack.extra_generation_params["TI hashes"] = util.GenerationParametersList(hashes)
|
||||||
hashes.append(self.hijack.extra_generation_params.get("TI hashes"))
|
|
||||||
self.hijack.extra_generation_params["TI hashes"] = ", ".join(hashes)
|
|
||||||
|
|
||||||
if any(x for x in texts if "(" in x or "[" in x) and opts.emphasis != "Original":
|
if opts.emphasis != 'Original' and any(x for x in texts if '(' in x or '[' in x):
|
||||||
self.hijack.extra_generation_params["Emphasis"] = opts.emphasis
|
self.hijack.extra_generation_params["Emphasis"] = EmphasisMode(opts.emphasis)
|
||||||
|
|
||||||
if self.return_pooled:
|
if self.return_pooled:
|
||||||
return torch.hstack(zs), zs[0].pooled
|
return torch.hstack(zs), zs[0].pooled
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ def ui_reorder_categories():
|
|||||||
|
|
||||||
def callbacks_order_settings():
|
def callbacks_order_settings():
|
||||||
options = {
|
options = {
|
||||||
"callbacks_order_explanation": OptionHTML("""
|
"sd_vae_explanation": OptionHTML("""
|
||||||
For categories below, callbacks added to dropdowns happen before others, in order listed.
|
For categories below, callbacks added to dropdowns happen before others, in order listed.
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ categories.register_category("training", "Training")
|
|||||||
|
|
||||||
options_templates.update(options_section(('saving-images', "Saving images/grids", "saving"), {
|
options_templates.update(options_section(('saving-images', "Saving images/grids", "saving"), {
|
||||||
"samples_save": OptionInfo(True, "Always save all generated images"),
|
"samples_save": OptionInfo(True, "Always save all generated images"),
|
||||||
"samples_format": OptionInfo('png', 'File format for images', ui_components.DropdownEditable, {"choices": ("png", "jpg", "jpeg", "webp", "avif")}).info("manual input of <a href='https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html' target='_blank'>other formats</a> is possible, but compatibility is not guaranteed"),
|
"samples_format": OptionInfo('png', 'File format for images'),
|
||||||
"samples_filename_pattern": OptionInfo("", "Images filename pattern", component_args=hide_dirs).link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Images-Filename-Name-and-Subdirectory"),
|
"samples_filename_pattern": OptionInfo("", "Images filename pattern", component_args=hide_dirs).link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Images-Filename-Name-and-Subdirectory"),
|
||||||
"save_images_add_number": OptionInfo(True, "Add number to filename when saving", component_args=hide_dirs),
|
"save_images_add_number": OptionInfo(True, "Add number to filename when saving", component_args=hide_dirs),
|
||||||
"save_images_replace_action": OptionInfo("Replace", "Saving the image to an existing file", gr.Radio, {"choices": ["Replace", "Add number suffix"], **hide_dirs}),
|
"save_images_replace_action": OptionInfo("Replace", "Saving the image to an existing file", gr.Radio, {"choices": ["Replace", "Add number suffix"], **hide_dirs}),
|
||||||
"grid_save": OptionInfo(True, "Always save all generated image grids"),
|
"grid_save": OptionInfo(True, "Always save all generated image grids"),
|
||||||
"grid_format": OptionInfo('png', 'File format for grids', ui_components.DropdownEditable, {"choices": ("png", "jpg", "jpeg", "webp", "avif")}).info("manual input of <a href='https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html' target='_blank'>other formats</a> is possible, but compatibility is not guaranteed"),
|
"grid_format": OptionInfo('png', 'File format for grids'),
|
||||||
"grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"),
|
"grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"),
|
||||||
"grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"),
|
"grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"),
|
||||||
"grid_prevent_empty_spots": OptionInfo(False, "Prevent empty spots in grid (when set to autodetect)"),
|
"grid_prevent_empty_spots": OptionInfo(False, "Prevent empty spots in grid (when set to autodetect)"),
|
||||||
@@ -128,7 +128,6 @@ options_templates.update(options_section(('system', "System", "system"), {
|
|||||||
"disable_mmap_load_safetensors": OptionInfo(False, "Disable memmapping for loading .safetensors files.").info("fixes very slow loading speed in some cases"),
|
"disable_mmap_load_safetensors": OptionInfo(False, "Disable memmapping for loading .safetensors files.").info("fixes very slow loading speed in some cases"),
|
||||||
"hide_ldm_prints": OptionInfo(True, "Prevent Stability-AI's ldm/sgm modules from printing noise to console."),
|
"hide_ldm_prints": OptionInfo(True, "Prevent Stability-AI's ldm/sgm modules from printing noise to console."),
|
||||||
"dump_stacks_on_signal": OptionInfo(False, "Print stack traces before exiting the program with ctrl+c."),
|
"dump_stacks_on_signal": OptionInfo(False, "Print stack traces before exiting the program with ctrl+c."),
|
||||||
"concurrent_git_fetch_limit": OptionInfo(16, "Number of simultaneous extension update checks ", gr.Slider, {"step": 1, "minimum": 1, "maximum": 100}).info("reduce extension update check time"),
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
options_templates.update(options_section(('profiler', "Profiler", "system"), {
|
options_templates.update(options_section(('profiler', "Profiler", "system"), {
|
||||||
|
|||||||
@@ -213,13 +213,3 @@ def get_config():
|
|||||||
return json.load(f)
|
return json.load(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
def download_sysinfo(attachment=False):
|
|
||||||
from fastapi.responses import PlainTextResponse
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
text = get()
|
|
||||||
filename = f"sysinfo-{datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json"
|
|
||||||
|
|
||||||
return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'})
|
|
||||||
|
|||||||
+14
-2
@@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -9,10 +10,10 @@ import gradio as gr
|
|||||||
import gradio.utils
|
import gradio.utils
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PIL import Image, PngImagePlugin # noqa: F401
|
from PIL import Image, PngImagePlugin # noqa: F401
|
||||||
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401
|
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401
|
||||||
|
|
||||||
from modules import gradio_extensons, sd_schedulers # noqa: F401
|
from modules import gradio_extensons, sd_schedulers # noqa: F401
|
||||||
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils
|
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, sysinfo, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils
|
||||||
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML, InputAccordion, ResizeHandleRow
|
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML, InputAccordion, ResizeHandleRow
|
||||||
from modules.paths import script_path
|
from modules.paths import script_path
|
||||||
from modules.ui_common import create_refresh_button
|
from modules.ui_common import create_refresh_button
|
||||||
@@ -1222,5 +1223,16 @@ def setup_ui_api(app):
|
|||||||
|
|
||||||
app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
|
app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
|
||||||
|
|
||||||
|
def download_sysinfo(attachment=False):
|
||||||
|
from fastapi.responses import PlainTextResponse
|
||||||
|
|
||||||
|
text = sysinfo.get()
|
||||||
|
filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json"
|
||||||
|
|
||||||
|
return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'})
|
||||||
|
|
||||||
|
app.add_api_route("/internal/sysinfo", download_sysinfo, methods=["GET"])
|
||||||
|
app.add_api_route("/internal/sysinfo-download", lambda: download_sysinfo(attachment=True), methods=["GET"])
|
||||||
|
|
||||||
import fastapi.staticfiles
|
import fastapi.staticfiles
|
||||||
app.mount("/webui-assets", fastapi.staticfiles.StaticFiles(directory=launch_utils.repo_dir('stable-diffusion-webui-assets')), name="webui-assets")
|
app.mount("/webui-assets", fastapi.staticfiles.StaticFiles(directory=launch_utils.repo_dir('stable-diffusion-webui-assets')), name="webui-assets")
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
@@ -107,24 +106,18 @@ def check_updates(id_task, disable_list):
|
|||||||
exts = [ext for ext in extensions.extensions if ext.remote is not None and ext.name not in disabled]
|
exts = [ext for ext in extensions.extensions if ext.remote is not None and ext.name not in disabled]
|
||||||
shared.state.job_count = len(exts)
|
shared.state.job_count = len(exts)
|
||||||
|
|
||||||
lock = threading.Lock()
|
for ext in exts:
|
||||||
|
shared.state.textinfo = ext.name
|
||||||
|
|
||||||
def _check_update(ext):
|
|
||||||
try:
|
try:
|
||||||
ext.check_updates()
|
ext.check_updates()
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
if 'FETCH_HEAD' not in str(e):
|
if 'FETCH_HEAD' not in str(e):
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
with lock:
|
errors.report(f"Error checking updates for {ext.name}", exc_info=True)
|
||||||
errors.report(f"Error checking updates for {ext.name}", exc_info=True)
|
|
||||||
with lock:
|
|
||||||
shared.state.textinfo = ext.name
|
|
||||||
shared.state.nextjob()
|
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=max(1, int(shared.opts.concurrent_git_fetch_limit))) as executor:
|
shared.state.nextjob()
|
||||||
for ext in exts:
|
|
||||||
executor.submit(_check_update, ext)
|
|
||||||
|
|
||||||
return extension_table(), ""
|
return extension_table(), ""
|
||||||
|
|
||||||
|
|||||||
+3
-25
@@ -1,13 +1,12 @@
|
|||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo, timer, shared_items, paths_internal, util
|
from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo, timer, shared_items
|
||||||
from modules.call_queue import wrap_gradio_call_no_job
|
from modules.call_queue import wrap_gradio_call_no_job
|
||||||
from modules.options import options_section
|
from modules.options import options_section
|
||||||
from modules.shared import opts
|
from modules.shared import opts
|
||||||
from modules.ui_components import FormRow
|
from modules.ui_components import FormRow
|
||||||
from modules.ui_gradio_extensions import reload_javascript
|
from modules.ui_gradio_extensions import reload_javascript
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def get_value_for_setting(key):
|
def get_value_for_setting(key):
|
||||||
@@ -171,28 +170,7 @@ class UiSettings:
|
|||||||
loadsave.create_ui()
|
loadsave.create_ui()
|
||||||
|
|
||||||
with gr.TabItem("Sysinfo", id="sysinfo", elem_id="settings_tab_sysinfo"):
|
with gr.TabItem("Sysinfo", id="sysinfo", elem_id="settings_tab_sysinfo"):
|
||||||
download_sysinfo = gr.Button(value='Download system info', elem_id="internal-download-sysinfo", visible=False)
|
gr.HTML('<a href="./internal/sysinfo-download" class="sysinfo_big_link" download>Download system info</a><br /><a href="./internal/sysinfo" target="_blank">(or open as text in a new page)</a>', elem_id="sysinfo_download")
|
||||||
open_sysinfo = gr.Button(value='Open as text in a new page', elem_id="internal-open-sysinfo", visible=False)
|
|
||||||
sysinfo_html = gr.HTML('''<a class="sysinfo_big_link" onclick="gradioApp().getElementById('internal-download-sysinfo').click();">Download system info</a><br/><a onclick="gradioApp().getElementById('internal-open-sysinfo').click();">(or open as text in a new page)</a>''', elem_id="sysinfo_download")
|
|
||||||
sysinfo_textbox = gr.Textbox(label='Sysinfo textarea', elem_id="internal-sysinfo-textbox", visible=False)
|
|
||||||
|
|
||||||
def create_sysinfo():
|
|
||||||
sysinfo_str = sysinfo.get()
|
|
||||||
if len(sysinfo_utf8 := sysinfo_str.encode('utf8')) > 2 ** 20: # 1MB
|
|
||||||
sysinfo_path = Path(paths_internal.script_path) / 'tmp' / 'sysinfo.json'
|
|
||||||
sysinfo_path.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
sysinfo_path.write_bytes(sysinfo_utf8)
|
|
||||||
return gr.update(), gr.update(value=f'file={util.truncate_path(sysinfo_path)}')
|
|
||||||
return gr.update(), gr.update(value=sysinfo_str)
|
|
||||||
|
|
||||||
download_sysinfo.click(
|
|
||||||
fn=create_sysinfo, outputs=[sysinfo_html, sysinfo_textbox], show_progress=True).success(
|
|
||||||
fn=None, _js='downloadSysinfo'
|
|
||||||
)
|
|
||||||
open_sysinfo.click(
|
|
||||||
fn=create_sysinfo, outputs=[sysinfo_html, sysinfo_textbox], show_progress=True).success(
|
|
||||||
fn=None, _js='openTabSysinfo'
|
|
||||||
)
|
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
with gr.Column(scale=1):
|
with gr.Column(scale=1):
|
||||||
@@ -335,7 +313,7 @@ class UiSettings:
|
|||||||
|
|
||||||
for method in methods:
|
for method in methods:
|
||||||
method(
|
method(
|
||||||
fn=lambda value, key=k: self.run_settings_single(value, key=key),
|
fn=lambda value, k=k: self.run_settings_single(value, key=k),
|
||||||
inputs=[component],
|
inputs=[component],
|
||||||
outputs=[component, self.text_settings],
|
outputs=[component, self.text_settings],
|
||||||
show_progress=info.refresh is not None,
|
show_progress=info.refresh is not None,
|
||||||
|
|||||||
@@ -288,3 +288,49 @@ def compare_sha256(file_path: str, hash_prefix: str) -> bool:
|
|||||||
for chunk in iter(lambda: f.read(blksize), b""):
|
for chunk in iter(lambda: f.read(blksize), b""):
|
||||||
hash_sha256.update(chunk)
|
hash_sha256.update(chunk)
|
||||||
return hash_sha256.hexdigest().startswith(hash_prefix.strip().lower())
|
return hash_sha256.hexdigest().startswith(hash_prefix.strip().lower())
|
||||||
|
|
||||||
|
|
||||||
|
class GenerationParametersList(list):
|
||||||
|
"""A special object used in sd_hijack.StableDiffusionModelHijack for setting extra_generation_params
|
||||||
|
due to StableDiffusionProcessing.get_conds_with_caching
|
||||||
|
extra_generation_params set in StableDiffusionModelHijack will be lost when cached is used
|
||||||
|
|
||||||
|
When an extra_generation_params is set in StableDiffusionModelHijack using this object,
|
||||||
|
the params will be extracted by StableDiffusionModelHijack.extract_generation_params_states
|
||||||
|
the extracted params will be cached in StableDiffusionProcessing.get_conds_with_caching
|
||||||
|
and applyed to StableDiffusionProcessing.extra_generation_params by StableDiffusionProcessing.apply_generation_params_states
|
||||||
|
|
||||||
|
Example see modules.sd_hijack_clip.TextConditionalModel.hijack.extra_generation_params 'TI hashes' 'Emphasis'
|
||||||
|
|
||||||
|
Depending on the use case the methods can be overwritten.
|
||||||
|
In general __call__ method should return str or None, as normally it's called in modules.processing.create_infotext.
|
||||||
|
When called by create_infotext it will access to the locals() of the caller,
|
||||||
|
if return str, the value will be written to infotext, if return None will be ignored.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, to_be_clear_before_batch=True, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self._to_be_clear_before_batch = to_be_clear_before_batch
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return ', '.join(sorted(set(self), key=natural_sort_key))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def to_be_clear_before_batch(self):
|
||||||
|
return self._to_be_clear_before_batch
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if isinstance(other, GenerationParametersList):
|
||||||
|
return self.__class__([*self, *other])
|
||||||
|
elif isinstance(other, str):
|
||||||
|
return self.__str__() + other
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
if isinstance(other, str):
|
||||||
|
return other + self.__str__()
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.__call__()
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ class ScriptPostprocessingCodeFormer(scripts_postprocessing.ScriptPostprocessing
|
|||||||
res = Image.fromarray(restored_img)
|
res = Image.fromarray(restored_img)
|
||||||
|
|
||||||
if codeformer_visibility < 1.0:
|
if codeformer_visibility < 1.0:
|
||||||
if pp.image.size != res.size:
|
|
||||||
res = res.resize(pp.image.size)
|
|
||||||
if pp.image.mode != res.mode:
|
|
||||||
res = res.convert(pp.image.mode)
|
|
||||||
res = Image.blend(pp.image, res, codeformer_visibility)
|
res = Image.blend(pp.image, res, codeformer_visibility)
|
||||||
|
|
||||||
pp.image = res
|
pp.image = res
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ class ScriptPostprocessingGfpGan(scripts_postprocessing.ScriptPostprocessing):
|
|||||||
res = Image.fromarray(restored_img)
|
res = Image.fromarray(restored_img)
|
||||||
|
|
||||||
if gfpgan_visibility < 1.0:
|
if gfpgan_visibility < 1.0:
|
||||||
if pp.image.size != res.size:
|
|
||||||
res = res.resize(pp.image.size)
|
|
||||||
if pp.image.mode != res.mode:
|
|
||||||
res = res.convert(pp.image.mode)
|
|
||||||
res = Image.blend(pp.image, res, gfpgan_visibility)
|
res = Image.blend(pp.image, res, gfpgan_visibility)
|
||||||
|
|
||||||
pp.image = res
|
pp.image = res
|
||||||
|
|||||||
Reference in New Issue
Block a user