Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bef51aed03 | |||
| 1398485789 | |||
| 141a17e969 | |||
| da67afe5f6 | |||
| 28bc85a20a | |||
| 978c7fadb3 | |||
| d558cb69b0 | |||
| 0b07a6cf26 | |||
| 024a32a09b | |||
| b47756385d | |||
| eaf5e0289a | |||
| f97e3548e5 | |||
| e651ca8adb | |||
| 78e421e4ea | |||
| a10c8df876 | |||
| 3069716510 | |||
| dfab42c949 | |||
| 6bc35be10a | |||
| b53989b195 | |||
| 726aaea0fe | |||
| 052fbde3ac | |||
| 140d58b512 | |||
| 532c340829 | |||
| 92ab0ef7d6 | |||
| c7808825b1 | |||
| cb52279c3e | |||
| 3345218439 | |||
| 4652fc5ac3 |
+15
-4
@@ -7,11 +7,11 @@
|
||||
* Support for SDXL-Inpaint Model ([#14390](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14390))
|
||||
* Use Spandrel for upscaling and face restoration architectures ([#14425](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14425), [#14467](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14467), [#14473](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14473), [#14474](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14474), [#14477](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14477), [#14476](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14476), [#14484](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14484), [#14500](https://github.com/AUTOMATIC1111/stable-difusion-webui/pull/14500), [#14501](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14501), [#14504](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14504), [#14524](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14524), [#14809](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14809))
|
||||
* Automatic backwards version compatibility (when loading infotexts from old images with program version specified, will add compatibility settings)
|
||||
* Implement zero terminal SNR noise schedule option (**[SEED BREAKING CHANGE](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Seed-breaking-changes#180-dev-170-225-2024-01-01---zero-terminal-snr-noise-schedule-option)**, [#14145](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14145))
|
||||
* Implement zero terminal SNR noise schedule option (**[SEED BREAKING CHANGE](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Seed-breaking-changes#180-dev-170-225-2024-01-01---zero-terminal-snr-noise-schedule-option)**, [#14145](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14145), [#14979](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14979))
|
||||
* Add a [✨] button to run hires fix on selected image in the gallery (with help from [#14598](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14598), [#14626](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14626), [#14728](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14728))
|
||||
* [Separate assets repository](https://github.com/AUTOMATIC1111/stable-diffusion-webui-assets); serve fonts locally rather than from google's servers
|
||||
* Official LCM Sampler Support ([#14583](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14583))
|
||||
* Add support for DAT upscaler models ([#14690](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14690))
|
||||
* Add support for DAT upscaler models ([#14690](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14690), [#15039](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15039))
|
||||
* Extra Networks Tree View ([#14588](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14588), [#14900](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14900))
|
||||
* NPU Support ([#14801](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14801))
|
||||
* Propmpt comments support
|
||||
@@ -34,13 +34,17 @@
|
||||
* Add checkpoint info to csv log file when saving images ([#14663](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14663))
|
||||
* Make more columns resizable ([#14740](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14740), [#14884](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14884))
|
||||
* Add an option to not overlay original image for inpainting for #14727
|
||||
* Add Pad conds v0 option
|
||||
* Add Pad conds v0 option to support same generation with DDIM as before 1.6.0
|
||||
* Add "Interrupting..." placeholder.
|
||||
* Button for refresh extensions list ([#14857](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14857))
|
||||
* Add an option to disable normalization after calculating emphasis. ([#14874](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14874))
|
||||
* When counting tokens, also include enabled styles (can be disabled in settings to revert to previous behavior)
|
||||
* Configuration for the [📂] button for image gallery ([#14947](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14947))
|
||||
* Support inference with LyCORIS BOFT networks ([#14871](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14871), [#14973](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14973))
|
||||
* support resizable columns for touch (tablets) ([#15002](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15002))
|
||||
|
||||
### Extensions and API:
|
||||
* Removed packages from requirements: basicsr, gfpgan, realesrgan; as well as their dependencies: absl-py, addict, beautifulsoup4, future, gdown, grpcio, importlib-metadata, lmdb, lpips, Markdown, platformdirs, PySocks, soupsieve, tb-nightly, tensorboard-data-server, tomli, Werkzeug, yapf, zipp, soupsieve
|
||||
* Enable task ids for API ([#14314](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14314))
|
||||
* add override_settings support for infotext API
|
||||
* rename generation_parameters_copypaste module to infotext_utils
|
||||
@@ -55,6 +59,7 @@
|
||||
* modules/api/api.py: add api endpoint to refresh embeddings list ([#14715](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14715))
|
||||
* set_named_arg ([#14773](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14773))
|
||||
* add before_token_counter callback and use it for prompt comments
|
||||
* ResizeHandleRow - allow overriden column scale parameter ([#15004](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15004))
|
||||
|
||||
### Performance
|
||||
* Massive performance improvement for extra networks directories with a huge number of files in them in an attempt to tackle #14507 ([#14528](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14528))
|
||||
@@ -96,6 +101,10 @@
|
||||
* Gracefully handle mtime read exception from cache ([#14933](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14933))
|
||||
* Only trigger interrupt on `Esc` when interrupt button visible ([#14932](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14932))
|
||||
* Disable prompt token counters option actually disables token counting rather than just hiding results.
|
||||
* avoid doble upscaling in inpaint ([#14966](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14966))
|
||||
* Fix #14591 using translated content to do categories mapping ([#14995](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14995))
|
||||
* fix: the `split_threshold` parameter does not work when running Split oversized images ([#15006](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15006))
|
||||
* Fix resize-handle for mobile ([#15010](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15010), [#15065](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15065))
|
||||
|
||||
### Other:
|
||||
* Assign id for "extra_options". Replace numeric field with slider. ([#14270](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14270))
|
||||
@@ -116,8 +125,9 @@
|
||||
* extensions tab table row hover highlight ([#14885](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14885))
|
||||
* Always add timestamp to displayed image ([#14890](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14890))
|
||||
* Added core.filemode=false so doesn't track changes in file permission… ([#14930](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14930))
|
||||
* Normalize command-line argument paths ([#14934](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14934))
|
||||
* Normalize command-line argument paths ([#14934](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14934), [#15035](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15035))
|
||||
* Use original App Title in progress bar ([#14916](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14916))
|
||||
* register_tmp_file also for mtime ([#15012](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/15012))
|
||||
|
||||
## 1.7.0
|
||||
|
||||
@@ -162,6 +172,7 @@
|
||||
* add FP32 fallback support on sd_vae_approx ([#14046](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14046))
|
||||
* support XYZ scripts / split hires path from unet ([#14126](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14126))
|
||||
* allow use of mutiple styles csv files ([#14125](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14125))
|
||||
* make extra network card description plaintext by default, with an option (Treat card description as HTML) to re-enable HTML as it was (originally by [#13241](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/13241))
|
||||
|
||||
### Extensions and API:
|
||||
* update gradio to 3.41.2
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import torch
|
||||
import network
|
||||
from lyco_helpers import factorization
|
||||
from einops import rearrange
|
||||
|
||||
|
||||
@@ -22,20 +21,28 @@ class NetworkModuleOFT(network.NetworkModule):
|
||||
self.org_module: list[torch.Module] = [self.sd_module]
|
||||
|
||||
self.scale = 1.0
|
||||
self.is_R = False
|
||||
self.is_boft = False
|
||||
|
||||
# kohya-ss
|
||||
# kohya-ss/New LyCORIS OFT/BOFT
|
||||
if "oft_blocks" in weights.w.keys():
|
||||
self.is_kohya = True
|
||||
self.oft_blocks = weights.w["oft_blocks"] # (num_blocks, block_size, block_size)
|
||||
self.alpha = weights.w["alpha"] # alpha is constraint
|
||||
self.alpha = weights.w.get("alpha", None) # alpha is constraint
|
||||
self.dim = self.oft_blocks.shape[0] # lora dim
|
||||
# LyCORIS
|
||||
# Old LyCORIS OFT
|
||||
elif "oft_diag" in weights.w.keys():
|
||||
self.is_kohya = False
|
||||
self.is_R = True
|
||||
self.oft_blocks = weights.w["oft_diag"]
|
||||
# self.alpha is unused
|
||||
self.dim = self.oft_blocks.shape[1] # (num_blocks, block_size, block_size)
|
||||
|
||||
# LyCORIS BOFT
|
||||
if self.oft_blocks.dim() == 4:
|
||||
self.is_boft = True
|
||||
self.rescale = weights.w.get('rescale', None)
|
||||
if self.rescale is not None:
|
||||
self.rescale = self.rescale.reshape(-1, *[1]*(self.org_module[0].weight.dim() - 1))
|
||||
|
||||
is_linear = type(self.sd_module) in [torch.nn.Linear, torch.nn.modules.linear.NonDynamicallyQuantizableLinear]
|
||||
is_conv = type(self.sd_module) in [torch.nn.Conv2d]
|
||||
is_other_linear = type(self.sd_module) in [torch.nn.MultiheadAttention] # unsupported
|
||||
@@ -47,35 +54,64 @@ class NetworkModuleOFT(network.NetworkModule):
|
||||
elif is_other_linear:
|
||||
self.out_dim = self.sd_module.embed_dim
|
||||
|
||||
if self.is_kohya:
|
||||
self.constraint = self.alpha * self.out_dim
|
||||
self.num_blocks = self.dim
|
||||
self.block_size = self.out_dim // self.dim
|
||||
else:
|
||||
self.num_blocks = self.dim
|
||||
self.block_size = self.out_dim // self.dim
|
||||
self.constraint = (0 if self.alpha is None else self.alpha) * self.out_dim
|
||||
if self.is_R:
|
||||
self.constraint = None
|
||||
self.block_size, self.num_blocks = factorization(self.out_dim, self.dim)
|
||||
self.block_size = self.dim
|
||||
self.num_blocks = self.out_dim // self.dim
|
||||
elif self.is_boft:
|
||||
self.boft_m = self.oft_blocks.shape[0]
|
||||
self.num_blocks = self.oft_blocks.shape[1]
|
||||
self.block_size = self.oft_blocks.shape[2]
|
||||
self.boft_b = self.block_size
|
||||
|
||||
def calc_updown(self, orig_weight):
|
||||
oft_blocks = self.oft_blocks.to(orig_weight.device)
|
||||
eye = torch.eye(self.block_size, device=oft_blocks.device)
|
||||
|
||||
if self.is_kohya:
|
||||
block_Q = oft_blocks - oft_blocks.transpose(1, 2) # ensure skew-symmetric orthogonal matrix
|
||||
norm_Q = torch.norm(block_Q.flatten())
|
||||
new_norm_Q = torch.clamp(norm_Q, max=self.constraint.to(oft_blocks.device))
|
||||
block_Q = block_Q * ((new_norm_Q + 1e-8) / (norm_Q + 1e-8))
|
||||
if not self.is_R:
|
||||
block_Q = oft_blocks - oft_blocks.transpose(-1, -2) # ensure skew-symmetric orthogonal matrix
|
||||
if self.constraint != 0:
|
||||
norm_Q = torch.norm(block_Q.flatten())
|
||||
new_norm_Q = torch.clamp(norm_Q, max=self.constraint.to(oft_blocks.device))
|
||||
block_Q = block_Q * ((new_norm_Q + 1e-8) / (norm_Q + 1e-8))
|
||||
oft_blocks = torch.matmul(eye + block_Q, (eye - block_Q).float().inverse())
|
||||
|
||||
R = oft_blocks.to(orig_weight.device)
|
||||
|
||||
# This errors out for MultiheadAttention, might need to be handled up-stream
|
||||
merged_weight = rearrange(orig_weight, '(k n) ... -> k n ...', k=self.num_blocks, n=self.block_size)
|
||||
merged_weight = torch.einsum(
|
||||
'k n m, k n ... -> k m ...',
|
||||
R,
|
||||
merged_weight
|
||||
)
|
||||
merged_weight = rearrange(merged_weight, 'k m ... -> (k m) ...')
|
||||
if not self.is_boft:
|
||||
# This errors out for MultiheadAttention, might need to be handled up-stream
|
||||
merged_weight = rearrange(orig_weight, '(k n) ... -> k n ...', k=self.num_blocks, n=self.block_size)
|
||||
merged_weight = torch.einsum(
|
||||
'k n m, k n ... -> k m ...',
|
||||
R,
|
||||
merged_weight
|
||||
)
|
||||
merged_weight = rearrange(merged_weight, 'k m ... -> (k m) ...')
|
||||
else:
|
||||
# TODO: determine correct value for scale
|
||||
scale = 1.0
|
||||
m = self.boft_m
|
||||
b = self.boft_b
|
||||
r_b = b // 2
|
||||
inp = orig_weight
|
||||
for i in range(m):
|
||||
bi = R[i] # b_num, b_size, b_size
|
||||
if i == 0:
|
||||
# Apply multiplier/scale and rescale into first weight
|
||||
bi = bi * scale + (1 - scale) * eye
|
||||
inp = rearrange(inp, "(c g k) ... -> (c k g) ...", g=2, k=2**i * r_b)
|
||||
inp = rearrange(inp, "(d b) ... -> d b ...", b=b)
|
||||
inp = torch.einsum("b i j, b j ... -> b i ...", bi, inp)
|
||||
inp = rearrange(inp, "d b ... -> (d b) ...")
|
||||
inp = rearrange(inp, "(c k g) ... -> (c g k) ...", g=2, k=2**i * r_b)
|
||||
merged_weight = inp
|
||||
|
||||
# Rescale mechanism
|
||||
if self.rescale is not None:
|
||||
merged_weight = self.rescale.to(merged_weight) * merged_weight
|
||||
|
||||
updown = merged_weight.to(orig_weight.device) - orig_weight.to(merged_weight.dtype)
|
||||
output_shape = orig_weight.shape
|
||||
|
||||
+83
-44
@@ -1,8 +1,8 @@
|
||||
(function() {
|
||||
const GRADIO_MIN_WIDTH = 320;
|
||||
const GRID_TEMPLATE_COLUMNS = '1fr 16px 1fr';
|
||||
const PAD = 16;
|
||||
const DEBOUNCE_TIME = 100;
|
||||
const DOUBLE_TAP_DELAY = 200; //ms
|
||||
|
||||
const R = {
|
||||
tracking: false,
|
||||
@@ -11,6 +11,7 @@
|
||||
leftCol: null,
|
||||
leftColStartWidth: null,
|
||||
screenX: null,
|
||||
lastTapTime: null,
|
||||
};
|
||||
|
||||
let resizeTimer;
|
||||
@@ -23,21 +24,17 @@
|
||||
function displayResizeHandle(parent) {
|
||||
if (window.innerWidth < GRADIO_MIN_WIDTH * 2 + PAD * 4) {
|
||||
parent.style.display = 'flex';
|
||||
if (R.handle != null) {
|
||||
R.handle.style.opacity = '0';
|
||||
}
|
||||
parent.resizeHandle.style.display = "none";
|
||||
return false;
|
||||
} else {
|
||||
parent.style.display = 'grid';
|
||||
if (R.handle != null) {
|
||||
R.handle.style.opacity = '100';
|
||||
}
|
||||
parent.resizeHandle.style.display = "block";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function afterResize(parent) {
|
||||
if (displayResizeHandle(parent) && parent.style.gridTemplateColumns != GRID_TEMPLATE_COLUMNS) {
|
||||
if (displayResizeHandle(parent) && parent.style.gridTemplateColumns != parent.style.originalGridTemplateColumns) {
|
||||
const oldParentWidth = R.parentWidth;
|
||||
const newParentWidth = parent.offsetWidth;
|
||||
const widthL = parseInt(parent.style.gridTemplateColumns.split(' ')[0]);
|
||||
@@ -52,6 +49,14 @@
|
||||
}
|
||||
|
||||
function setup(parent) {
|
||||
|
||||
function onDoubleClick(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
parent.style.gridTemplateColumns = parent.style.originalGridTemplateColumns;
|
||||
}
|
||||
|
||||
const leftCol = parent.firstElementChild;
|
||||
const rightCol = parent.lastElementChild;
|
||||
|
||||
@@ -59,63 +64,97 @@
|
||||
|
||||
parent.style.display = 'grid';
|
||||
parent.style.gap = '0';
|
||||
parent.style.gridTemplateColumns = GRID_TEMPLATE_COLUMNS;
|
||||
const gridTemplateColumns = `${parent.children[0].style.flexGrow}fr ${PAD}px ${parent.children[1].style.flexGrow}fr`;
|
||||
parent.style.gridTemplateColumns = gridTemplateColumns;
|
||||
parent.style.originalGridTemplateColumns = gridTemplateColumns;
|
||||
|
||||
const resizeHandle = document.createElement('div');
|
||||
resizeHandle.classList.add('resize-handle');
|
||||
parent.insertBefore(resizeHandle, rightCol);
|
||||
parent.resizeHandle = resizeHandle;
|
||||
|
||||
resizeHandle.addEventListener('mousedown', (evt) => {
|
||||
if (evt.button !== 0) return;
|
||||
['mousedown', 'touchstart'].forEach((eventType) => {
|
||||
resizeHandle.addEventListener(eventType, (evt) => {
|
||||
if (eventType.startsWith('mouse')) {
|
||||
if (evt.button !== 0) return;
|
||||
} else {
|
||||
if (evt.changedTouches.length !== 1) return;
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
const currentTime = new Date().getTime();
|
||||
if (R.lastTapTime && currentTime - R.lastTapTime <= DOUBLE_TAP_DELAY) {
|
||||
onDoubleClick(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.classList.add('resizing');
|
||||
R.lastTapTime = currentTime;
|
||||
}
|
||||
|
||||
R.tracking = true;
|
||||
R.parent = parent;
|
||||
R.parentWidth = parent.offsetWidth;
|
||||
R.handle = resizeHandle;
|
||||
R.leftCol = leftCol;
|
||||
R.leftColStartWidth = leftCol.offsetWidth;
|
||||
R.screenX = evt.screenX;
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
document.body.classList.add('resizing');
|
||||
|
||||
R.tracking = true;
|
||||
R.parent = parent;
|
||||
R.parentWidth = parent.offsetWidth;
|
||||
R.leftCol = leftCol;
|
||||
R.leftColStartWidth = leftCol.offsetWidth;
|
||||
if (eventType.startsWith('mouse')) {
|
||||
R.screenX = evt.screenX;
|
||||
} else {
|
||||
R.screenX = evt.changedTouches[0].screenX;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
resizeHandle.addEventListener('dblclick', (evt) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
parent.style.gridTemplateColumns = GRID_TEMPLATE_COLUMNS;
|
||||
});
|
||||
resizeHandle.addEventListener('dblclick', onDoubleClick);
|
||||
|
||||
afterResize(parent);
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove', (evt) => {
|
||||
if (evt.button !== 0) return;
|
||||
['mousemove', 'touchmove'].forEach((eventType) => {
|
||||
window.addEventListener(eventType, (evt) => {
|
||||
if (eventType.startsWith('mouse')) {
|
||||
if (evt.button !== 0) return;
|
||||
} else {
|
||||
if (evt.changedTouches.length !== 1) return;
|
||||
}
|
||||
|
||||
if (R.tracking) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (R.tracking) {
|
||||
if (eventType.startsWith('mouse')) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
evt.stopPropagation();
|
||||
|
||||
const delta = R.screenX - evt.screenX;
|
||||
const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - GRADIO_MIN_WIDTH - PAD), GRADIO_MIN_WIDTH);
|
||||
setLeftColGridTemplate(R.parent, leftColWidth);
|
||||
}
|
||||
let delta = 0;
|
||||
if (eventType.startsWith('mouse')) {
|
||||
delta = R.screenX - evt.screenX;
|
||||
} else {
|
||||
delta = R.screenX - evt.changedTouches[0].screenX;
|
||||
}
|
||||
const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - GRADIO_MIN_WIDTH - PAD), GRADIO_MIN_WIDTH);
|
||||
setLeftColGridTemplate(R.parent, leftColWidth);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', (evt) => {
|
||||
if (evt.button !== 0) return;
|
||||
['mouseup', 'touchend'].forEach((eventType) => {
|
||||
window.addEventListener(eventType, (evt) => {
|
||||
if (eventType.startsWith('mouse')) {
|
||||
if (evt.button !== 0) return;
|
||||
} else {
|
||||
if (evt.changedTouches.length !== 1) return;
|
||||
}
|
||||
|
||||
if (R.tracking) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (R.tracking) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
R.tracking = false;
|
||||
R.tracking = false;
|
||||
|
||||
document.body.classList.remove('resizing');
|
||||
}
|
||||
document.body.classList.remove('resizing');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ onOptionsChanged(function() {
|
||||
});
|
||||
|
||||
opts._categories.forEach(function(x) {
|
||||
var section = x[0];
|
||||
var category = x[1];
|
||||
var section = localization[x[0]] ?? x[0];
|
||||
var category = localization[x[1]] ?? x[1];
|
||||
|
||||
var span = document.createElement('SPAN');
|
||||
span.textContent = category;
|
||||
|
||||
@@ -53,6 +53,7 @@ parser.add_argument("--gfpgan-models-path", type=normalized_filepath, help="Path
|
||||
parser.add_argument("--esrgan-models-path", type=normalized_filepath, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN'))
|
||||
parser.add_argument("--bsrgan-models-path", type=normalized_filepath, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN'))
|
||||
parser.add_argument("--realesrgan-models-path", type=normalized_filepath, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN'))
|
||||
parser.add_argument("--dat-models-path", type=normalized_filepath, help="Path to directory with DAT model file(s).", default=os.path.join(models_path, 'DAT'))
|
||||
parser.add_argument("--clip-models-path", type=normalized_filepath, help="Path to directory with CLIP model file(s).", default=None)
|
||||
parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers")
|
||||
parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work")
|
||||
|
||||
@@ -7,7 +7,7 @@ import shlex
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
normalized_filepath = lambda filepath: str(Path(filepath).resolve())
|
||||
normalized_filepath = lambda filepath: str(Path(filepath).absolute())
|
||||
|
||||
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
|
||||
sys.argv += shlex.split(commandline_args)
|
||||
|
||||
+7
-36
@@ -74,16 +74,18 @@ def uncrop(image, dest_size, paste_loc):
|
||||
|
||||
def apply_overlay(image, paste_loc, overlay):
|
||||
if overlay is None:
|
||||
return image
|
||||
return image, image.copy()
|
||||
|
||||
if paste_loc is not None:
|
||||
image = uncrop(image, (overlay.width, overlay.height), paste_loc)
|
||||
|
||||
original_denoised_image = image.copy()
|
||||
|
||||
image = image.convert('RGBA')
|
||||
image.alpha_composite(overlay)
|
||||
image = image.convert('RGB')
|
||||
|
||||
return image
|
||||
return image, original_denoised_image
|
||||
|
||||
def create_binary_mask(image, round=True):
|
||||
if image.mode == 'RGBA' and image.getextrema()[-1] != (255, 255):
|
||||
@@ -913,33 +915,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
if p.n_iter > 1:
|
||||
shared.state.job = f"Batch {n+1} out of {p.n_iter}"
|
||||
|
||||
def rescale_zero_terminal_snr_abar(alphas_cumprod):
|
||||
alphas_bar_sqrt = alphas_cumprod.sqrt()
|
||||
|
||||
# Store old values.
|
||||
alphas_bar_sqrt_0 = alphas_bar_sqrt[0].clone()
|
||||
alphas_bar_sqrt_T = alphas_bar_sqrt[-1].clone()
|
||||
|
||||
# Shift so the last timestep is zero.
|
||||
alphas_bar_sqrt -= (alphas_bar_sqrt_T)
|
||||
|
||||
# Scale so the first timestep is back to the old value.
|
||||
alphas_bar_sqrt *= alphas_bar_sqrt_0 / (alphas_bar_sqrt_0 - alphas_bar_sqrt_T)
|
||||
|
||||
# Convert alphas_bar_sqrt to betas
|
||||
alphas_bar = alphas_bar_sqrt**2 # Revert sqrt
|
||||
alphas_bar[-1] = 4.8973451890853435e-08
|
||||
return alphas_bar
|
||||
|
||||
if hasattr(p.sd_model, 'alphas_cumprod') and hasattr(p.sd_model, 'alphas_cumprod_original'):
|
||||
p.sd_model.alphas_cumprod = p.sd_model.alphas_cumprod_original.to(shared.device)
|
||||
|
||||
if opts.use_downcasted_alpha_bar:
|
||||
p.extra_generation_params['Downcast alphas_cumprod'] = opts.use_downcasted_alpha_bar
|
||||
p.sd_model.alphas_cumprod = p.sd_model.alphas_cumprod.half().to(shared.device)
|
||||
if opts.sd_noise_schedule == "Zero Terminal SNR":
|
||||
p.extra_generation_params['Noise Schedule'] = opts.sd_noise_schedule
|
||||
p.sd_model.alphas_cumprod = rescale_zero_terminal_snr_abar(p.sd_model.alphas_cumprod).to(shared.device)
|
||||
sd_models.apply_alpha_schedule_override(p.sd_model, p)
|
||||
|
||||
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)
|
||||
@@ -1021,7 +997,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
|
||||
if p.color_corrections is not None and i < len(p.color_corrections):
|
||||
if save_samples and opts.save_images_before_color_correction:
|
||||
image_without_cc = apply_overlay(image, p.paste_to, overlay_image)
|
||||
image_without_cc, _ = apply_overlay(image, p.paste_to, overlay_image)
|
||||
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)
|
||||
|
||||
@@ -1029,12 +1005,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
# that is being composited over the original image,
|
||||
# we need to keep the original image around
|
||||
# and use it in the composite step.
|
||||
original_denoised_image = image.copy()
|
||||
|
||||
if p.paste_to is not None:
|
||||
original_denoised_image = uncrop(original_denoised_image, (overlay_image.width, overlay_image.height), p.paste_to)
|
||||
|
||||
image = apply_overlay(image, p.paste_to, overlay_image)
|
||||
image, original_denoised_image = apply_overlay(image, p.paste_to, overlay_image)
|
||||
|
||||
if p.scripts is not None:
|
||||
pp = scripts.PostprocessImageArgs(image)
|
||||
|
||||
@@ -15,6 +15,7 @@ from ldm.util import instantiate_from_config
|
||||
|
||||
from modules import paths, shared, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config, sd_unet, sd_models_xl, cache, extra_networks, processing, lowvram, sd_hijack, patches
|
||||
from modules.timer import Timer
|
||||
from modules.shared import opts
|
||||
import tomesd
|
||||
import numpy as np
|
||||
|
||||
@@ -427,6 +428,8 @@ def load_model_weights(model, checkpoint_info: CheckpointInfo, state_dict, timer
|
||||
devices.dtype_unet = torch.float16
|
||||
timer.record("apply half()")
|
||||
|
||||
apply_alpha_schedule_override(model)
|
||||
|
||||
for module in model.modules():
|
||||
if hasattr(module, 'fp16_weight'):
|
||||
del module.fp16_weight
|
||||
@@ -550,6 +553,48 @@ def repair_config(sd_config):
|
||||
sd_config.model.params.noise_aug_config.params.clip_stats_path = sd_config.model.params.noise_aug_config.params.clip_stats_path.replace("checkpoints/karlo_models", karlo_path)
|
||||
|
||||
|
||||
def rescale_zero_terminal_snr_abar(alphas_cumprod):
|
||||
alphas_bar_sqrt = alphas_cumprod.sqrt()
|
||||
|
||||
# Store old values.
|
||||
alphas_bar_sqrt_0 = alphas_bar_sqrt[0].clone()
|
||||
alphas_bar_sqrt_T = alphas_bar_sqrt[-1].clone()
|
||||
|
||||
# Shift so the last timestep is zero.
|
||||
alphas_bar_sqrt -= (alphas_bar_sqrt_T)
|
||||
|
||||
# Scale so the first timestep is back to the old value.
|
||||
alphas_bar_sqrt *= alphas_bar_sqrt_0 / (alphas_bar_sqrt_0 - alphas_bar_sqrt_T)
|
||||
|
||||
# Convert alphas_bar_sqrt to betas
|
||||
alphas_bar = alphas_bar_sqrt ** 2 # Revert sqrt
|
||||
alphas_bar[-1] = 4.8973451890853435e-08
|
||||
return alphas_bar
|
||||
|
||||
|
||||
def apply_alpha_schedule_override(sd_model, p=None):
|
||||
"""
|
||||
Applies an override to the alpha schedule of the model according to settings.
|
||||
- downcasts the alpha schedule to half precision
|
||||
- rescales the alpha schedule to have zero terminal SNR
|
||||
"""
|
||||
|
||||
if not hasattr(sd_model, 'alphas_cumprod') or not hasattr(sd_model, 'alphas_cumprod_original'):
|
||||
return
|
||||
|
||||
sd_model.alphas_cumprod = sd_model.alphas_cumprod_original.to(shared.device)
|
||||
|
||||
if opts.use_downcasted_alpha_bar:
|
||||
if p is not None:
|
||||
p.extra_generation_params['Downcast alphas_cumprod'] = opts.use_downcasted_alpha_bar
|
||||
sd_model.alphas_cumprod = sd_model.alphas_cumprod.half().to(shared.device)
|
||||
|
||||
if opts.sd_noise_schedule == "Zero Terminal SNR":
|
||||
if p is not None:
|
||||
p.extra_generation_params['Noise Schedule'] = opts.sd_noise_schedule
|
||||
sd_model.alphas_cumprod = rescale_zero_terminal_snr_abar(sd_model.alphas_cumprod).to(shared.device)
|
||||
|
||||
|
||||
sd1_clip_weight = 'cond_stage_model.transformer.text_model.embeddings.token_embedding.weight'
|
||||
sd2_clip_weight = 'cond_stage_model.model.transformer.resblocks.0.attn.in_proj_weight'
|
||||
sdxl_clip_weight = 'conditioner.embedders.1.model.ln_final.weight'
|
||||
|
||||
@@ -220,10 +220,10 @@ class CFGDenoiser(torch.nn.Module):
|
||||
|
||||
self.padded_cond_uncond = False
|
||||
self.padded_cond_uncond_v0 = False
|
||||
if shared.opts.pad_cond_uncond and tensor.shape[1] != uncond.shape[1]:
|
||||
tensor, uncond = self.pad_cond_uncond(tensor, uncond)
|
||||
elif shared.opts.pad_cond_uncond_v0 and tensor.shape[1] != uncond.shape[1]:
|
||||
if shared.opts.pad_cond_uncond_v0 and tensor.shape[1] != uncond.shape[1]:
|
||||
tensor, uncond = self.pad_cond_uncond_v0(tensor, uncond)
|
||||
elif shared.opts.pad_cond_uncond and tensor.shape[1] != uncond.shape[1]:
|
||||
tensor, uncond = self.pad_cond_uncond(tensor, uncond)
|
||||
|
||||
if tensor.shape[1] == uncond.shape[1] or skip_uncond:
|
||||
if is_edit_model:
|
||||
|
||||
@@ -211,7 +211,7 @@ options_templates.update(options_section(('optimizations', "Optimizations", "sd"
|
||||
"token_merging_ratio_img2img": OptionInfo(0.0, "Token merging ratio for img2img", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}).info("only applies if non-zero and overrides above"),
|
||||
"token_merging_ratio_hr": OptionInfo(0.0, "Token merging ratio for high-res pass", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}, infotext='Token merging ratio hr').info("only applies if non-zero and overrides above"),
|
||||
"pad_cond_uncond": OptionInfo(False, "Pad prompt/negative prompt", infotext='Pad conds').info("improves performance when prompt and negative prompt have different lengths; changes seeds"),
|
||||
"pad_cond_uncond_v0": OptionInfo(False, "Pad prompt/negative prompt (v0)", infotext='Pad conds v0').info("alternative implementation for the above; used prior to 1.6.0 for DDIM sampler; ignored if the above is set; changes seeds"),
|
||||
"pad_cond_uncond_v0": OptionInfo(False, "Pad prompt/negative prompt (v0)", infotext='Pad conds v0').info("alternative implementation for the above; used prior to 1.6.0 for DDIM sampler; overrides the above if set; WARNING: truncates negative prompt if it's too long; changes seeds"),
|
||||
"persistent_cond_cache": OptionInfo(True, "Persistent cond cache").info("do not recalculate conds from prompts if prompts have not changed since previous calculation"),
|
||||
"batch_cond_uncond": OptionInfo(True, "Batch cond/uncond").info("do both conditional and unconditional denoising in one batch; uses a bit more VRAM during sampling, but improves speed; previously this was controlled by --always-batch-cond-uncond comandline argument"),
|
||||
"fp8_storage": OptionInfo("Disable", "FP8 weight", gr.Radio, {"choices": ["Disable", "Enable for SDXL", "Enable"]}).info("Use FP8 to store Linear/Conv layers' weight. Require pytorch>=2.1.0."),
|
||||
@@ -254,6 +254,7 @@ options_templates.update(options_section(('extra_networks', "Extra Networks", "s
|
||||
"extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks").info("in pixels"),
|
||||
"extra_networks_card_text_scale": OptionInfo(1.0, "Card text scale", gr.Slider, {"minimum": 0.0, "maximum": 2.0, "step": 0.01}).info("1 = original size"),
|
||||
"extra_networks_card_show_desc": OptionInfo(True, "Show description on card"),
|
||||
"extra_networks_card_description_is_html": OptionInfo(False, "Treat card description as HTML"),
|
||||
"extra_networks_card_order_field": OptionInfo("Path", "Default order field for Extra Networks cards", gr.Dropdown, {"choices": ['Path', 'Name', 'Date Created', 'Date Modified']}).needs_reload_ui(),
|
||||
"extra_networks_card_order": OptionInfo("Ascending", "Default order for Extra Networks cards", gr.Dropdown, {"choices": ['Ascending', 'Descending']}).needs_reload_ui(),
|
||||
"extra_networks_tree_view_default_enabled": OptionInfo(False, "Enables the Extra Networks directory tree view by default").needs_reload_ui(),
|
||||
@@ -284,6 +285,7 @@ options_templates.update(options_section(('ui_gallery', "Gallery", "ui"), {
|
||||
"sd_webui_modal_lightbox_icon_opacity": OptionInfo(1, "Full page image viewer: control icon unfocused opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(),
|
||||
"sd_webui_modal_lightbox_toolbar_opacity": OptionInfo(0.9, "Full page image viewer: tool bar opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(),
|
||||
"gallery_height": OptionInfo("", "Gallery height", gr.Textbox).info("can be any valid CSS value, for example 768px or 20em").needs_reload_ui(),
|
||||
"open_dir_button_choice": OptionInfo("Subdirectory", "What directory the [📂] button opens", gr.Radio, {"choices": ["Output Root", "Subdirectory", "Subdirectory (even temp dir)"]}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('ui_alternatives', "UI alternatives", "ui"), {
|
||||
|
||||
+35
-17
@@ -9,7 +9,7 @@ import sys
|
||||
import gradio as gr
|
||||
import subprocess as sp
|
||||
|
||||
from modules import call_queue, shared
|
||||
from modules import call_queue, shared, ui_tempdir
|
||||
from modules.infotext_utils import image_from_url_text
|
||||
import modules.images
|
||||
from modules.ui_components import ToolButton
|
||||
@@ -164,29 +164,43 @@ class OutputPanel:
|
||||
def create_output_panel(tabname, outdir, toprow=None):
|
||||
res = OutputPanel()
|
||||
|
||||
def open_folder(f):
|
||||
def open_folder(f, images=None, index=None):
|
||||
if shared.cmd_opts.hide_ui_dir_config:
|
||||
return
|
||||
|
||||
try:
|
||||
if 'Sub' in shared.opts.open_dir_button_choice:
|
||||
image_dir = os.path.split(images[index]["name"].rsplit('?', 1)[0])[0]
|
||||
if 'temp' in shared.opts.open_dir_button_choice or not ui_tempdir.is_gradio_temp_path(image_dir):
|
||||
f = image_dir
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not os.path.exists(f):
|
||||
print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.')
|
||||
msg = f'Folder "{f}" does not exist. After you create an image, the folder will be created.'
|
||||
print(msg)
|
||||
gr.Info(msg)
|
||||
return
|
||||
elif not os.path.isdir(f):
|
||||
print(f"""
|
||||
msg = f"""
|
||||
WARNING
|
||||
An open_folder request was made with an argument that is not a folder.
|
||||
This could be an error or a malicious attempt to run code on your computer.
|
||||
Requested path was: {f}
|
||||
""", file=sys.stderr)
|
||||
"""
|
||||
print(msg, file=sys.stderr)
|
||||
gr.Warning(msg)
|
||||
return
|
||||
|
||||
if not shared.cmd_opts.hide_ui_dir_config:
|
||||
path = os.path.normpath(f)
|
||||
if platform.system() == "Windows":
|
||||
os.startfile(path)
|
||||
elif platform.system() == "Darwin":
|
||||
sp.Popen(["open", path])
|
||||
elif "microsoft-standard-WSL2" in platform.uname().release:
|
||||
sp.Popen(["wsl-open", path])
|
||||
else:
|
||||
sp.Popen(["xdg-open", path])
|
||||
path = os.path.normpath(f)
|
||||
if platform.system() == "Windows":
|
||||
os.startfile(path)
|
||||
elif platform.system() == "Darwin":
|
||||
sp.Popen(["open", path])
|
||||
elif "microsoft-standard-WSL2" in platform.uname().release:
|
||||
sp.Popen(["wsl-open", path])
|
||||
else:
|
||||
sp.Popen(["xdg-open", path])
|
||||
|
||||
with gr.Column(elem_id=f"{tabname}_results"):
|
||||
if toprow:
|
||||
@@ -213,8 +227,12 @@ Requested path was: {f}
|
||||
res.button_upscale = ToolButton('✨', elem_id=f'{tabname}_upscale', tooltip="Create an upscaled version of the current image using hires fix settings.")
|
||||
|
||||
open_folder_button.click(
|
||||
fn=lambda: open_folder(shared.opts.outdir_samples or outdir),
|
||||
inputs=[],
|
||||
fn=lambda images, index: open_folder(shared.opts.outdir_samples or outdir, images, index),
|
||||
_js="(y, w) => [y, selected_gallery_index()]",
|
||||
inputs=[
|
||||
res.gallery,
|
||||
open_folder_button, # placeholder for index
|
||||
],
|
||||
outputs=[],
|
||||
)
|
||||
|
||||
|
||||
@@ -289,12 +289,16 @@ class ExtraNetworksPage:
|
||||
}
|
||||
)
|
||||
|
||||
description = (item.get("description", "") or "" if shared.opts.extra_networks_card_show_desc else "")
|
||||
if not shared.opts.extra_networks_card_description_is_html:
|
||||
description = html.escape(description)
|
||||
|
||||
# Some items here might not be used depending on HTML template used.
|
||||
args = {
|
||||
"background_image": background_image,
|
||||
"card_clicked": onclick,
|
||||
"copy_path_button": btn_copy_path,
|
||||
"description": (item.get("description", "") or "" if shared.opts.extra_networks_card_show_desc else ""),
|
||||
"description": description,
|
||||
"edit_button": btn_edit_item,
|
||||
"local_preview": quote_js(item["local_preview"]),
|
||||
"metadata_button": btn_metadata,
|
||||
@@ -472,7 +476,7 @@ class ExtraNetworksPage:
|
||||
|
||||
return f"<ul class='tree-list tree-list--tree'>{res}</ul>"
|
||||
|
||||
def create_card_view_html(self, tabname: str) -> str:
|
||||
def create_card_view_html(self, tabname: str, *, none_message) -> str:
|
||||
"""Generates HTML for the network Card View section for a tab.
|
||||
|
||||
This HTML goes into the `extra-networks-pane.html` <div> with
|
||||
@@ -480,6 +484,7 @@ class ExtraNetworksPage:
|
||||
|
||||
Args:
|
||||
tabname: The name of the active tab.
|
||||
none_message: HTML text to show when there are no cards.
|
||||
|
||||
Returns:
|
||||
HTML formatted string.
|
||||
@@ -490,24 +495,28 @@ class ExtraNetworksPage:
|
||||
|
||||
if res == "":
|
||||
dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()])
|
||||
res = shared.html("extra-networks-no-cards.html").format(dirs=dirs)
|
||||
res = none_message or shared.html("extra-networks-no-cards.html").format(dirs=dirs)
|
||||
|
||||
return res
|
||||
|
||||
def create_html(self, tabname):
|
||||
def create_html(self, tabname, *, empty=False):
|
||||
"""Generates an HTML string for the current pane.
|
||||
|
||||
The generated HTML uses `extra-networks-pane.html` as a template.
|
||||
|
||||
Args:
|
||||
tabname: The name of the active tab.
|
||||
empty: create an empty HTML page with no items
|
||||
|
||||
Returns:
|
||||
HTML formatted string.
|
||||
"""
|
||||
self.lister.reset()
|
||||
self.metadata = {}
|
||||
self.items = {x["name"]: x for x in self.list_items()}
|
||||
|
||||
items_list = [] if empty else self.list_items()
|
||||
self.items = {x["name"]: x for x in items_list}
|
||||
|
||||
# Populate the instance metadata for each item.
|
||||
for item in self.items.values():
|
||||
metadata = item.get("metadata")
|
||||
@@ -536,7 +545,7 @@ class ExtraNetworksPage:
|
||||
"tree_view_btn_extra_class": tree_view_btn_extra_class,
|
||||
"tree_view_div_extra_class": tree_view_div_extra_class,
|
||||
"tree_html": self.create_tree_view_html(tabname),
|
||||
"items_html": self.create_card_view_html(tabname),
|
||||
"items_html": self.create_card_view_html(tabname, none_message="Loading..." if empty else None),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -655,7 +664,7 @@ def create_ui(interface: gr.Blocks, unrelated_tabs, tabname):
|
||||
pass
|
||||
|
||||
elem_id = f"{tabname}_{page.extra_networks_tabname}_cards_html"
|
||||
page_elem = gr.HTML('Loading...', elem_id=elem_id)
|
||||
page_elem = gr.HTML(page.create_html(tabname, empty=True), elem_id=elem_id)
|
||||
ui.pages.append(page_elem)
|
||||
editor = page.create_user_metadata_editor(ui, tabname)
|
||||
editor.create_ui()
|
||||
|
||||
+18
-1
@@ -35,7 +35,9 @@ def save_pil_to_file(self, pil_image, dir=None, format="png"):
|
||||
already_saved_as = getattr(pil_image, 'already_saved_as', None)
|
||||
if already_saved_as and os.path.isfile(already_saved_as):
|
||||
register_tmp_file(shared.demo, already_saved_as)
|
||||
return f'{already_saved_as}?{os.path.getmtime(already_saved_as)}'
|
||||
filename_with_mtime = f'{already_saved_as}?{os.path.getmtime(already_saved_as)}'
|
||||
register_tmp_file(shared.demo, filename_with_mtime)
|
||||
return filename_with_mtime
|
||||
|
||||
if shared.opts.temp_dir != "":
|
||||
dir = shared.opts.temp_dir
|
||||
@@ -81,3 +83,18 @@ def cleanup_tmpdr():
|
||||
|
||||
filename = os.path.join(root, name)
|
||||
os.remove(filename)
|
||||
|
||||
|
||||
def is_gradio_temp_path(path):
|
||||
"""
|
||||
Check if the path is a temp dir used by gradio
|
||||
"""
|
||||
path = Path(path)
|
||||
if shared.opts.temp_dir and path.is_relative_to(shared.opts.temp_dir):
|
||||
return True
|
||||
if gradio_temp_dir := os.environ.get("GRADIO_TEMP_DIR"):
|
||||
if path.is_relative_to(gradio_temp_dir):
|
||||
return True
|
||||
if path.is_relative_to(Path(tempfile.gettempdir()) / "gradio"):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -167,7 +167,7 @@ document.addEventListener('keydown', function(e) {
|
||||
const lightboxModal = document.querySelector('#lightboxModal');
|
||||
if (!globalPopup || globalPopup.style.display === 'none') {
|
||||
if (document.activeElement === lightboxModal) return;
|
||||
if (interruptButton.style.display !== 'none') {
|
||||
if (interruptButton.style.display === 'block') {
|
||||
interruptButton.click();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class ScriptPostprocessingSplitOversized(scripts_postprocessing.ScriptPostproces
|
||||
ratio = (pp.image.height * width) / (pp.image.width * height)
|
||||
inverse_xy = True
|
||||
|
||||
if ratio >= 1.0 and ratio > split_threshold:
|
||||
if ratio >= 1.0 or ratio > split_threshold:
|
||||
return
|
||||
|
||||
result, *others = split_pic(pp.image, inverse_xy, width, height, overlap_ratio)
|
||||
|
||||
Reference in New Issue
Block a user