Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb08cc3e07 | |||
| 6685e532df | |||
| d4f02b8916 | |||
| e0be7a8427 | |||
| 2174ce5afe | |||
| 82bf9a3730 | |||
| ebbc56b4ec | |||
| 6d664438ba | |||
| 3064b21e23 | |||
| 374bb6cc38 | |||
| e7edad6fe9 | |||
| d8688def65 | |||
| 435b1df2db | |||
| 7fd7fc67f7 | |||
| 9d1accfea0 | |||
| c59a2badd2 | |||
| 9f670bc7e8 | |||
| afbd3da2fa | |||
| 32595360f2 | |||
| 8c7bc08f60 | |||
| 57e15ec9b5 | |||
| 021154d8b1 | |||
| b82ba9b0be | |||
| 45493949cd | |||
| 8c6c973614 | |||
| a037918748 | |||
| 4fa673a68a | |||
| 813c3912fc | |||
| 078d04ef23 | |||
| 1a773bf2c8 | |||
| f113474a6e | |||
| 6577e063d1 | |||
| 7953c570d9 | |||
| f25c3fc9cb | |||
| fc0952abb9 | |||
| b414c62ce4 | |||
| 04903af798 | |||
| e8c3b1f2a0 | |||
| 8bf30e3c42 | |||
| fbc51fa210 | |||
| 7025a2c4a5 | |||
| 0120768f63 | |||
| b425b97ad6 | |||
| 539ea3982d | |||
| 65bd61e87c | |||
| 023454b49e | |||
| cd869bb7a3 | |||
| 95686227bd | |||
| df74c3c638 |
@@ -88,6 +88,7 @@ module.exports = {
|
|||||||
// imageviewer.js
|
// imageviewer.js
|
||||||
modalPrevImage: "readonly",
|
modalPrevImage: "readonly",
|
||||||
modalNextImage: "readonly",
|
modalNextImage: "readonly",
|
||||||
|
updateModalImageIfVisible: "readonly",
|
||||||
// localStorage.js
|
// localStorage.js
|
||||||
localSet: "readonly",
|
localSet: "readonly",
|
||||||
localGet: "readonly",
|
localGet: "readonly",
|
||||||
|
|||||||
@@ -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 .
|
run: ruff check .
|
||||||
lint-js:
|
lint-js:
|
||||||
name: eslint
|
name: eslint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ If your system is very new, you need to install python3.11 or python3.10:
|
|||||||
# Ubuntu 24.04
|
# Ubuntu 24.04
|
||||||
sudo add-apt-repository ppa:deadsnakes/ppa
|
sudo add-apt-repository ppa:deadsnakes/ppa
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install python3.11
|
sudo apt install python3.11 python3.11-venv
|
||||||
|
|
||||||
# Manjaro/Arch
|
# Manjaro/Arch
|
||||||
sudo pacman -S yay
|
sudo pacman -S yay
|
||||||
|
|||||||
@@ -226,8 +226,6 @@ onUiLoaded(async() => {
|
|||||||
canvas_show_tooltip: true,
|
canvas_show_tooltip: true,
|
||||||
canvas_auto_expand: true,
|
canvas_auto_expand: true,
|
||||||
canvas_blur_prompt: false,
|
canvas_blur_prompt: false,
|
||||||
canvas_hotkey_undo: "KeyZ",
|
|
||||||
canvas_hotkey_clear: "KeyC",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const functionMap = {
|
const functionMap = {
|
||||||
@@ -238,9 +236,7 @@ onUiLoaded(async() => {
|
|||||||
"Moving canvas": "canvas_hotkey_move",
|
"Moving canvas": "canvas_hotkey_move",
|
||||||
"Fullscreen": "canvas_hotkey_fullscreen",
|
"Fullscreen": "canvas_hotkey_fullscreen",
|
||||||
"Reset Zoom": "canvas_hotkey_reset",
|
"Reset Zoom": "canvas_hotkey_reset",
|
||||||
"Overlap": "canvas_hotkey_overlap",
|
"Overlap": "canvas_hotkey_overlap"
|
||||||
"Undo": "canvas_hotkey_undo",
|
|
||||||
"Clear": "canvas_hotkey_clear"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Loading the configuration from opts
|
// Loading the configuration from opts
|
||||||
@@ -325,8 +321,6 @@ onUiLoaded(async() => {
|
|||||||
action: "Adjust brush size",
|
action: "Adjust brush size",
|
||||||
keySuffix: " + wheel"
|
keySuffix: " + wheel"
|
||||||
},
|
},
|
||||||
{configKey: "canvas_hotkey_undo", action: "Undo brush stroke"},
|
|
||||||
{configKey: "canvas_hotkey_clear", action: "Clear canvas"},
|
|
||||||
{configKey: "canvas_hotkey_reset", action: "Reset zoom"},
|
{configKey: "canvas_hotkey_reset", action: "Reset zoom"},
|
||||||
{
|
{
|
||||||
configKey: "canvas_hotkey_fullscreen",
|
configKey: "canvas_hotkey_fullscreen",
|
||||||
@@ -470,45 +464,22 @@ onUiLoaded(async() => {
|
|||||||
gradioApp().querySelector(
|
gradioApp().querySelector(
|
||||||
`${elemId} button[aria-label="Use brush"]`
|
`${elemId} button[aria-label="Use brush"]`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
input.click();
|
input.click();
|
||||||
if (!withoutValue) {
|
if (!withoutValue) {
|
||||||
const maxValue = parseFloat(input.getAttribute("max")) || 100;
|
const maxValue =
|
||||||
const minValue = parseFloat(input.getAttribute("min")) || 1;
|
parseFloat(input.getAttribute("max")) || 100;
|
||||||
// allow brush size up to 1/2 diagonal of the image, beyond gradio's arbitrary limit
|
const changeAmount = maxValue * (percentage / 100);
|
||||||
const canvasImg = gradioApp().querySelector(`${elemId} img`);
|
const newValue =
|
||||||
if (canvasImg) {
|
parseFloat(input.value) +
|
||||||
const maxDiameter = Math.sqrt(canvasImg.naturalWidth ** 2 + canvasImg.naturalHeight ** 2) / 2;
|
(deltaY > 0 ? -changeAmount : changeAmount);
|
||||||
if (maxDiameter > maxValue) {
|
input.value = Math.min(Math.max(newValue, 0), maxValue);
|
||||||
input.setAttribute("max", maxDiameter);
|
|
||||||
}
|
|
||||||
if (minValue > 1) {
|
|
||||||
input.setAttribute("min", '1');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const brush_factor = deltaY > 0 ? 1 - opts.canvas_hotkey_brush_factor : 1 + opts.canvas_hotkey_brush_factor;
|
|
||||||
const currentRadius = parseFloat(input.value);
|
|
||||||
let delta = Math.sqrt(currentRadius ** 2 * brush_factor) - currentRadius;
|
|
||||||
// minimum brush size step of 1
|
|
||||||
if (Math.abs(delta) < 1) {
|
|
||||||
delta = deltaY > 0 ? -1 : 1;
|
|
||||||
}
|
|
||||||
const newValue = currentRadius + delta;
|
|
||||||
input.value = Math.max(newValue, 1);
|
|
||||||
input.dispatchEvent(new Event("change"));
|
input.dispatchEvent(new Event("change"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo the last brush stroke by clicking the undo button
|
|
||||||
function undoBrushStroke() {
|
|
||||||
gradioApp().querySelector(`${elemId} button[aria-label='Undo']`).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearCanvas() {
|
|
||||||
gradioApp().querySelector(`${elemId} button[aria-label='Clear']`).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset zoom when uploading a new image
|
// Reset zoom when uploading a new image
|
||||||
const fileInput = gradioApp().querySelector(
|
const fileInput = gradioApp().querySelector(
|
||||||
`${elemId} input[type="file"][accept="image/*"].svelte-116rqfv`
|
`${elemId} input[type="file"][accept="image/*"].svelte-116rqfv`
|
||||||
@@ -728,9 +699,7 @@ onUiLoaded(async() => {
|
|||||||
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
|
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
|
||||||
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen,
|
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen,
|
||||||
[hotkeysConfig.canvas_hotkey_shrink_brush]: () => adjustBrushSize(elemId, 10),
|
[hotkeysConfig.canvas_hotkey_shrink_brush]: () => adjustBrushSize(elemId, 10),
|
||||||
[hotkeysConfig.canvas_hotkey_grow_brush]: () => adjustBrushSize(elemId, -10),
|
[hotkeysConfig.canvas_hotkey_grow_brush]: () => adjustBrushSize(elemId, -10)
|
||||||
[hotkeysConfig.canvas_hotkey_undo]: undoBrushStroke,
|
|
||||||
[hotkeysConfig.canvas_hotkey_clear]: clearCanvas
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const action = hotkeyActions[event.code];
|
const action = hotkeyActions[event.code];
|
||||||
|
|||||||
@@ -2,19 +2,16 @@ import gradio as gr
|
|||||||
from modules import shared
|
from modules import shared
|
||||||
|
|
||||||
shared.options_templates.update(shared.options_section(('canvas_hotkey', "Canvas Hotkeys"), {
|
shared.options_templates.update(shared.options_section(('canvas_hotkey', "Canvas Hotkeys"), {
|
||||||
"canvas_hotkey_zoom": shared.OptionInfo("Alt", "Zoom canvas", gr.Radio, {"choices": ["Shift", "Ctrl", "Alt"]}).info("If you choose 'Shift' you cannot scroll horizontally, 'Alt' can cause a little trouble in firefox"),
|
"canvas_hotkey_zoom": shared.OptionInfo("Alt", "Zoom canvas", gr.Radio, {"choices": ["Shift","Ctrl", "Alt"]}).info("If you choose 'Shift' you cannot scroll horizontally, 'Alt' can cause a little trouble in firefox"),
|
||||||
"canvas_hotkey_adjust": shared.OptionInfo("Ctrl", "Adjust brush size", gr.Radio, {"choices": ["Shift", "Ctrl", "Alt"]}).info("If you choose 'Shift' you cannot scroll horizontally, 'Alt' can cause a little trouble in firefox"),
|
"canvas_hotkey_adjust": shared.OptionInfo("Ctrl", "Adjust brush size", gr.Radio, {"choices": ["Shift","Ctrl", "Alt"]}).info("If you choose 'Shift' you cannot scroll horizontally, 'Alt' can cause a little trouble in firefox"),
|
||||||
"canvas_hotkey_shrink_brush": shared.OptionInfo("Q", "Shrink the brush size"),
|
"canvas_hotkey_shrink_brush": shared.OptionInfo("Q", "Shrink the brush size"),
|
||||||
"canvas_hotkey_grow_brush": shared.OptionInfo("W", "Enlarge the brush size"),
|
"canvas_hotkey_grow_brush": shared.OptionInfo("W", "Enlarge the brush size"),
|
||||||
"canvas_hotkey_move": shared.OptionInfo("F", "Moving the canvas").info("To work correctly in firefox, turn off 'Automatically search the page text when typing' in the browser settings"),
|
"canvas_hotkey_move": shared.OptionInfo("F", "Moving the canvas").info("To work correctly in firefox, turn off 'Automatically search the page text when typing' in the browser settings"),
|
||||||
"canvas_hotkey_undo": shared.OptionInfo("Z", "Undo brush stroke"),
|
|
||||||
"canvas_hotkey_clear": shared.OptionInfo("C", "Clear canvas"),
|
|
||||||
"canvas_hotkey_fullscreen": shared.OptionInfo("S", "Fullscreen Mode, maximizes the picture so that it fits into the screen and stretches it to its full width "),
|
"canvas_hotkey_fullscreen": shared.OptionInfo("S", "Fullscreen Mode, maximizes the picture so that it fits into the screen and stretches it to its full width "),
|
||||||
"canvas_hotkey_reset": shared.OptionInfo("R", "Reset zoom and canvas position"),
|
"canvas_hotkey_reset": shared.OptionInfo("R", "Reset zoom and canvas position"),
|
||||||
"canvas_hotkey_overlap": shared.OptionInfo("O", "Toggle overlap").info("Technical button, needed for testing"),
|
"canvas_hotkey_overlap": shared.OptionInfo("O", "Toggle overlap").info("Technical button, needed for testing"),
|
||||||
"canvas_show_tooltip": shared.OptionInfo(True, "Enable tooltip on the canvas"),
|
"canvas_show_tooltip": shared.OptionInfo(True, "Enable tooltip on the canvas"),
|
||||||
"canvas_auto_expand": shared.OptionInfo(True, "Automatically expands an image that does not fit completely in the canvas area, similar to manually pressing the S and R buttons"),
|
"canvas_auto_expand": shared.OptionInfo(True, "Automatically expands an image that does not fit completely in the canvas area, similar to manually pressing the S and R buttons"),
|
||||||
"canvas_blur_prompt": shared.OptionInfo(False, "Take the focus off the prompt when working with a canvas"),
|
"canvas_blur_prompt": shared.OptionInfo(False, "Take the focus off the prompt when working with a canvas"),
|
||||||
"canvas_disabled_functions": shared.OptionInfo(["Overlap"], "Disable function that you don't use", gr.CheckboxGroup, {"choices": ["Zoom", "Adjust brush size", "Hotkey enlarge brush", "Hotkey shrink brush", "Undo", "Clear", "Moving canvas", "Fullscreen", "Reset Zoom", "Overlap"]}),
|
"canvas_disabled_functions": shared.OptionInfo(["Overlap"], "Disable function that you don't use", gr.CheckboxGroup, {"choices": ["Zoom","Adjust brush size","Hotkey enlarge brush","Hotkey shrink brush","Moving canvas","Fullscreen","Reset Zoom","Overlap"]}),
|
||||||
"canvas_hotkey_brush_factor": shared.OptionInfo(0.1, "Brush size change rate", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}).info('controls how much the brush size is changed when using hotkeys or scroll wheel'),
|
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,36 +1,69 @@
|
|||||||
// Stable Diffusion WebUI - Bracket checker
|
// Stable Diffusion WebUI - Bracket Checker
|
||||||
// By Hingashi no Florin/Bwin4L & @akx
|
// By @Bwin4L, @akx, @w-e-w, @Haoming02
|
||||||
// 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, counterElt) {
|
function checkBrackets(textArea, counterElem) {
|
||||||
var counts = {};
|
const pairs = [
|
||||||
(textArea.value.match(/[(){}[\]]/g) || []).forEach(bracket => {
|
['(', ')', 'round brackets'],
|
||||||
counts[bracket] = (counts[bracket] || 0) + 1;
|
['[', ']', 'square brackets'],
|
||||||
});
|
['{', '}', 'curly brackets']
|
||||||
var errors = [];
|
];
|
||||||
|
|
||||||
function checkPair(open, close, kind) {
|
const counts = {};
|
||||||
if (counts[open] !== counts[close]) {
|
const errors = new Set();
|
||||||
errors.push(
|
let i = 0;
|
||||||
`${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`
|
|
||||||
);
|
while (i < textArea.value.length) {
|
||||||
|
let char = textArea.value[i];
|
||||||
|
let escaped = false;
|
||||||
|
while (char === '\\' && i + 1 < textArea.value.length) {
|
||||||
|
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}.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPair('(', ')', 'round brackets');
|
i++;
|
||||||
checkPair('[', ']', 'square brackets');
|
}
|
||||||
checkPair('{', '}', 'curly brackets');
|
|
||||||
counterElt.title = errors.join('\n');
|
for (const [open, close, label] of pairs) {
|
||||||
counterElt.classList.toggle('error', errors.length !== 0);
|
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');
|
||||||
|
counterElem.classList.toggle('error', errors.size !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupBracketChecking(id_prompt, id_counter) {
|
function setupBracketChecking(id_prompt, id_counter) {
|
||||||
var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea");
|
const textarea = gradioApp().querySelector(`#${id_prompt} > label > textarea`);
|
||||||
var counter = gradioApp().getElementById(id_counter);
|
const counter = gradioApp().getElementById(id_counter);
|
||||||
|
|
||||||
if (textarea && counter) {
|
if (textarea && counter) {
|
||||||
textarea.addEventListener("input", () => checkBrackets(textarea, counter));
|
onEdit(`${id_prompt}_BracketChecking`, textarea, 400, () => checkBrackets(textarea, counter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<a href="{api_docs}">API</a>
|
<a href="{api_docs}" target="_blank">API</a>
|
||||||
•
|
•
|
||||||
<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui">GitHub</a>
|
<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui">GitHub</a>
|
||||||
•
|
•
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ function updateOnBackgroundChange() {
|
|||||||
updateModalImage();
|
updateModalImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const updateModalImageIfVisible = updateOnBackgroundChange;
|
||||||
|
|
||||||
function modalImageSwitch(offset) {
|
function modalImageSwitch(offset) {
|
||||||
var galleryButtons = all_gallery_buttons();
|
var galleryButtons = all_gallery_buttons();
|
||||||
@@ -164,6 +165,7 @@ function modalLivePreviewToggle(event) {
|
|||||||
const modalToggleLivePreview = gradioApp().getElementById("modal_toggle_live_preview");
|
const modalToggleLivePreview = gradioApp().getElementById("modal_toggle_live_preview");
|
||||||
opts.js_live_preview_in_modal_lightbox = !opts.js_live_preview_in_modal_lightbox;
|
opts.js_live_preview_in_modal_lightbox = !opts.js_live_preview_in_modal_lightbox;
|
||||||
modalToggleLivePreview.innerHTML = opts.js_live_preview_in_modal_lightbox ? "🗇" : "🗆";
|
modalToggleLivePreview.innerHTML = opts.js_live_preview_in_modal_lightbox ? "🗇" : "🗆";
|
||||||
|
updateModalImageIfVisible();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre
|
|||||||
livePreview.className = 'livePreview';
|
livePreview.className = 'livePreview';
|
||||||
gallery.insertBefore(livePreview, gallery.firstElementChild);
|
gallery.insertBefore(livePreview, gallery.firstElementChild);
|
||||||
}
|
}
|
||||||
|
updateModalImageIfVisible();
|
||||||
livePreview.appendChild(img);
|
livePreview.appendChild(img);
|
||||||
if (livePreview.childElementCount > 2) {
|
if (livePreview.childElementCount > 2) {
|
||||||
livePreview.removeChild(livePreview.firstElementChild);
|
livePreview.removeChild(livePreview.firstElementChild);
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ git = launch_utils.git
|
|||||||
index_url = launch_utils.index_url
|
index_url = launch_utils.index_url
|
||||||
dir_repos = launch_utils.dir_repos
|
dir_repos = launch_utils.dir_repos
|
||||||
|
|
||||||
|
if args.uv:
|
||||||
|
from modules.uv_hook import patch
|
||||||
|
patch()
|
||||||
|
|
||||||
|
|
||||||
commit_hash = launch_utils.commit_hash
|
commit_hash = launch_utils.commit_hash
|
||||||
git_tag = launch_utils.git_tag
|
git_tag = launch_utils.git_tag
|
||||||
|
|
||||||
|
|||||||
@@ -126,3 +126,4 @@ parser.add_argument("--skip-load-model-at-start", action='store_true', help="if
|
|||||||
parser.add_argument("--unix-filenames-sanitization", action='store_true', help="allow any symbols except '/' in filenames. May conflict with your browser and file system")
|
parser.add_argument("--unix-filenames-sanitization", action='store_true', help="allow any symbols except '/' in filenames. May conflict with your browser and file system")
|
||||||
parser.add_argument("--filenames-max-length", type=int, default=128, help='maximal length of filenames of saved images. If you override it, it can conflict with your file system')
|
parser.add_argument("--filenames-max-length", type=int, default=128, help='maximal length of filenames of saved images. If you override it, it can conflict with your file system')
|
||||||
parser.add_argument("--no-prompt-history", action='store_true', help="disable read prompt from last generation feature; settings this argument will not create '--data_path/params.txt' file")
|
parser.add_argument("--no-prompt-history", action='store_true', help="disable read prompt from last generation feature; settings this argument will not create '--data_path/params.txt' file")
|
||||||
|
parser.add_argument("--uv", action='store_true', help="use the uv package manager")
|
||||||
|
|||||||
+30
-2
@@ -1,7 +1,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from modules import shared
|
from modules import shared, errors
|
||||||
import modules.cache
|
import modules.cache
|
||||||
|
|
||||||
dump_cache = modules.cache.dump_cache
|
dump_cache = modules.cache.dump_cache
|
||||||
@@ -32,7 +32,7 @@ def sha256_from_cache(filename, title, use_addnet_hash=False):
|
|||||||
cached_sha256 = hashes[title].get("sha256", None)
|
cached_sha256 = hashes[title].get("sha256", None)
|
||||||
cached_mtime = hashes[title].get("mtime", 0)
|
cached_mtime = hashes[title].get("mtime", 0)
|
||||||
|
|
||||||
if ondisk_mtime > cached_mtime or cached_sha256 is None:
|
if ondisk_mtime != cached_mtime or cached_sha256 is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return cached_sha256
|
return cached_sha256
|
||||||
@@ -82,3 +82,31 @@ def addnet_hash_safetensors(b):
|
|||||||
|
|
||||||
return hash_sha256.hexdigest()
|
return hash_sha256.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def partial_hash_from_cache(filename, *, ignore_cache: bool = False, digits: int = 8):
|
||||||
|
"""old hash that only looks at a small part of the file and is prone to collisions
|
||||||
|
kept for compatibility, don't use this for new things
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
filename = str(filename)
|
||||||
|
mtime = os.path.getmtime(filename)
|
||||||
|
hashes = cache('partial-hash')
|
||||||
|
cache_entry = hashes.get(filename, {})
|
||||||
|
cache_mtime = cache_entry.get("mtime", 0)
|
||||||
|
cache_hash = cache_entry.get("hash", None)
|
||||||
|
if mtime == cache_mtime and cache_hash and not ignore_cache:
|
||||||
|
return cache_hash[0:digits]
|
||||||
|
|
||||||
|
with open(filename, 'rb') as file:
|
||||||
|
m = hashlib.sha256()
|
||||||
|
file.seek(0x100000)
|
||||||
|
m.update(file.read(0x10000))
|
||||||
|
partial_hash = m.hexdigest()
|
||||||
|
hashes[filename] = {'mtime': mtime, 'hash': partial_hash}
|
||||||
|
return partial_hash[0:digits]
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
errors.report(f'Error calculating partial hash for {filename}', exc_info=True)
|
||||||
|
return 'NOFILE'
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ class FilenameGenerator:
|
|||||||
'generation_number': lambda self: NOTHING_AND_SKIP_PREVIOUS_TEXT if (self.p.n_iter == 1 and self.p.batch_size == 1) or self.zip else self.p.iteration * self.p.batch_size + self.p.batch_index + 1,
|
'generation_number': lambda self: NOTHING_AND_SKIP_PREVIOUS_TEXT if (self.p.n_iter == 1 and self.p.batch_size == 1) or self.zip else self.p.iteration * self.p.batch_size + self.p.batch_index + 1,
|
||||||
'hasprompt': lambda self, *args: self.hasprompt(*args), # accepts formats:[hasprompt<prompt1|default><prompt2>..]
|
'hasprompt': lambda self, *args: self.hasprompt(*args), # accepts formats:[hasprompt<prompt1|default><prompt2>..]
|
||||||
'clip_skip': lambda self: opts.data["CLIP_stop_at_last_layers"],
|
'clip_skip': lambda self: opts.data["CLIP_stop_at_last_layers"],
|
||||||
|
'randn_source': lambda self: opts.data["randn_source"],
|
||||||
'denoising': lambda self: self.p.denoising_strength if self.p and self.p.denoising_strength else NOTHING_AND_SKIP_PREVIOUS_TEXT,
|
'denoising': lambda self: self.p.denoising_strength if self.p and self.p.denoising_strength else NOTHING_AND_SKIP_PREVIOUS_TEXT,
|
||||||
'user': lambda self: self.p.user,
|
'user': lambda self: self.p.user,
|
||||||
'vae_filename': lambda self: self.get_vae_filename(),
|
'vae_filename': lambda self: self.get_vae_filename(),
|
||||||
|
|||||||
+51
-6
@@ -43,9 +43,7 @@ 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):
|
||||||
import modules.errors
|
errors.print_error_explanation(f"""
|
||||||
|
|
||||||
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}.
|
||||||
@@ -315,9 +313,56 @@ def requirements_met(requirements_file):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_cuda_comp_cap():
|
||||||
|
"""
|
||||||
|
Returns float of CUDA Compute Capability using nvidia-smi
|
||||||
|
Returns 0.0 on error
|
||||||
|
CUDA Compute Capability
|
||||||
|
ref https://developer.nvidia.com/cuda-gpus
|
||||||
|
ref https://en.wikipedia.org/wiki/CUDA
|
||||||
|
Blackwell consumer GPUs should return 12.0 data-center GPUs should return 10.0
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return max(map(float, subprocess.check_output(['nvidia-smi', '--query-gpu=compute_cap', '--format=noheader,csv'], text=True).splitlines()))
|
||||||
|
except Exception as _:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def early_access_blackwell_wheels():
|
||||||
|
"""For Blackwell GPUs, use Early Access PyTorch Wheels provided by Nvidia"""
|
||||||
|
print('deprecated early_access_blackwell_wheels')
|
||||||
|
if all([
|
||||||
|
os.environ.get('TORCH_INDEX_URL') is None,
|
||||||
|
sys.version_info.major == 3,
|
||||||
|
sys.version_info.minor in (10, 11, 12),
|
||||||
|
platform.system() == "Windows",
|
||||||
|
get_cuda_comp_cap() >= 10, # Blackwell
|
||||||
|
]):
|
||||||
|
base_repo = 'https://huggingface.co/w-e-w/torch-2.6.0-cu128.nv/resolve/main/'
|
||||||
|
ea_whl = {
|
||||||
|
10: f'{base_repo}torch-2.6.0+cu128.nv-cp310-cp310-win_amd64.whl#sha256=fef3de7ce8f4642e405576008f384304ad0e44f7b06cc1aa45e0ab4b6e70490d {base_repo}torchvision-0.20.0a0+cu128.nv-cp310-cp310-win_amd64.whl#sha256=50841254f59f1db750e7348b90a8f4cd6befec217ab53cbb03780490b225abef',
|
||||||
|
11: f'{base_repo}torch-2.6.0+cu128.nv-cp311-cp311-win_amd64.whl#sha256=6665c36e6a7e79e7a2cb42bec190d376be9ca2859732ed29dd5b7b5a612d0d26 {base_repo}torchvision-0.20.0a0+cu128.nv-cp311-cp311-win_amd64.whl#sha256=bbc0ee4938e35fe5a30de3613bfcd2d8ef4eae334cf8d49db860668f0bb47083',
|
||||||
|
12: f'{base_repo}torch-2.6.0+cu128.nv-cp312-cp312-win_amd64.whl#sha256=a3197f72379d34b08c4a4bcf49ea262544a484e8702b8c46cbcd66356c89def6 {base_repo}torchvision-0.20.0a0+cu128.nv-cp312-cp312-win_amd64.whl#sha256=235e7be71ac4e75b0f8e817bae4796d7bac8a67146d2037ab96394f2bdc63e6c'
|
||||||
|
}
|
||||||
|
return f'pip install {ea_whl.get(sys.version_info.minor)}'
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_torch_index_url():
|
||||||
|
"""Choose default torch index url based on GPU CUDA Compute Capability (CC)
|
||||||
|
Use cu126 for CC <= 7.2, cu128 for CC > 7.2
|
||||||
|
PyTorch have dropped support for older GPUs on their cu128 and above wheels,
|
||||||
|
For Nvidia 10 series and older GPUs (CC < 7.0) should use cu126 wheels
|
||||||
|
Since GPUs with CC <= 7.2 are considered legacy by Nvidia
|
||||||
|
ref 2025-11-07 https://developer.nvidia.com/cuda-legacy-gpus
|
||||||
|
"""
|
||||||
|
if get_cuda_comp_cap() <= 7.2:
|
||||||
|
return "https://download.pytorch.org/whl/cu126"
|
||||||
|
return "https://download.pytorch.org/whl/cu128"
|
||||||
|
|
||||||
|
|
||||||
def prepare_environment():
|
def prepare_environment():
|
||||||
torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://download.pytorch.org/whl/cu121")
|
torch_index_url = os.environ.get('TORCH_INDEX_URL', get_default_torch_index_url())
|
||||||
torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.1.2 torchvision==0.16.2 --extra-index-url {torch_index_url}")
|
torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.7.0 torchvision==0.22.0 --extra-index-url {torch_index_url}")
|
||||||
if args.use_ipex:
|
if args.use_ipex:
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
# The "Nuullll/intel-extension-for-pytorch" wheels were built from IPEX source for Intel Arc GPU: https://github.com/intel/intel-extension-for-pytorch/tree/xpu-main
|
# The "Nuullll/intel-extension-for-pytorch" wheels were built from IPEX source for Intel Arc GPU: https://github.com/intel/intel-extension-for-pytorch/tree/xpu-main
|
||||||
@@ -341,7 +386,7 @@ def prepare_environment():
|
|||||||
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
|
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
|
||||||
requirements_file_for_npu = os.environ.get('REQS_FILE_FOR_NPU', "requirements_npu.txt")
|
requirements_file_for_npu = os.environ.get('REQS_FILE_FOR_NPU', "requirements_npu.txt")
|
||||||
|
|
||||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.23.post1')
|
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.30')
|
||||||
clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip")
|
clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip")
|
||||||
openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip")
|
openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip")
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class SdOptimizationXformers(SdOptimization):
|
|||||||
priority = 100
|
priority = 100
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self):
|
||||||
return shared.cmd_opts.force_enable_xformers or (shared.xformers_available and torch.cuda.is_available() and (6, 0) <= torch.cuda.get_device_capability(shared.device) <= (9, 0))
|
return shared.cmd_opts.force_enable_xformers or (shared.xformers_available and torch.cuda.is_available() and (6, 0) <= torch.cuda.get_device_capability(shared.device) <= (12, 0))
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
ldm.modules.attention.CrossAttention.forward = xformers_attention_forward
|
ldm.modules.attention.CrossAttention.forward = xformers_attention_forward
|
||||||
|
|||||||
+2
-16
@@ -13,6 +13,7 @@ from urllib import request
|
|||||||
import ldm.modules.midas as midas
|
import ldm.modules.midas as midas
|
||||||
|
|
||||||
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 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.hashes import partial_hash_from_cache as model_hash # noqa: F401 for backwards compatibility
|
||||||
from modules.timer import Timer
|
from modules.timer import Timer
|
||||||
from modules.shared import opts
|
from modules.shared import opts
|
||||||
import tomesd
|
import tomesd
|
||||||
@@ -87,7 +88,7 @@ class CheckpointInfo:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.name_for_extra = os.path.splitext(os.path.basename(filename))[0]
|
self.name_for_extra = os.path.splitext(os.path.basename(filename))[0]
|
||||||
self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]
|
self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]
|
||||||
self.hash = model_hash(filename)
|
self.hash = hashes.partial_hash_from_cache(filename)
|
||||||
|
|
||||||
self.sha256 = hashes.sha256_from_cache(self.filename, f"checkpoint/{name}")
|
self.sha256 = hashes.sha256_from_cache(self.filename, f"checkpoint/{name}")
|
||||||
self.shorthash = self.sha256[0:10] if self.sha256 else None
|
self.shorthash = self.sha256[0:10] if self.sha256 else None
|
||||||
@@ -200,21 +201,6 @@ def get_closet_checkpoint_match(search_string):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def model_hash(filename):
|
|
||||||
"""old hash that only looks at a small part of the file and is prone to collisions"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(filename, "rb") as file:
|
|
||||||
import hashlib
|
|
||||||
m = hashlib.sha256()
|
|
||||||
|
|
||||||
file.seek(0x100000)
|
|
||||||
m.update(file.read(0x10000))
|
|
||||||
return m.hexdigest()[0:8]
|
|
||||||
except FileNotFoundError:
|
|
||||||
return 'NOFILE'
|
|
||||||
|
|
||||||
|
|
||||||
def select_checkpoint():
|
def select_checkpoint():
|
||||||
"""Raises `FileNotFoundError` if no checkpoints are found."""
|
"""Raises `FileNotFoundError` if no checkpoints are found."""
|
||||||
model_checkpoint = shared.opts.sd_model_checkpoint
|
model_checkpoint = shared.opts.sd_model_checkpoint
|
||||||
|
|||||||
@@ -117,12 +117,15 @@ def ddim_scheduler(n, sigma_min, sigma_max, inner_model, device):
|
|||||||
|
|
||||||
|
|
||||||
def beta_scheduler(n, sigma_min, sigma_max, inner_model, device):
|
def beta_scheduler(n, sigma_min, sigma_max, inner_model, device):
|
||||||
# From "Beta Sampling is All You Need" [arXiv:2407.12173] (Lee et. al, 2024) """
|
# From "Beta Sampling is All You Need" [arXiv:2407.12173] (Lee et. al, 2024)
|
||||||
alpha = shared.opts.beta_dist_alpha
|
alpha = shared.opts.beta_dist_alpha
|
||||||
beta = shared.opts.beta_dist_beta
|
beta = shared.opts.beta_dist_beta
|
||||||
timesteps = 1 - np.linspace(0, 1, n)
|
curve = [stats.beta.ppf(x, alpha, beta) for x in np.linspace(1, 0, n)]
|
||||||
timesteps = [stats.beta.ppf(x, alpha, beta) for x in timesteps]
|
|
||||||
sigmas = [sigma_min + (x * (sigma_max-sigma_min)) for x in timesteps]
|
start = inner_model.sigma_to_t(torch.tensor(sigma_max))
|
||||||
|
end = inner_model.sigma_to_t(torch.tensor(sigma_min))
|
||||||
|
timesteps = [end + x * (start - end) for x in curve]
|
||||||
|
sigmas = [inner_model.t_to_sigma(ts) for ts in timesteps]
|
||||||
sigmas += [0.0]
|
sigmas += [0.0]
|
||||||
return torch.FloatTensor(sigmas).to(device)
|
return torch.FloatTensor(sigmas).to(device)
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ def ui_reorder_categories():
|
|||||||
|
|
||||||
def callbacks_order_settings():
|
def callbacks_order_settings():
|
||||||
options = {
|
options = {
|
||||||
"sd_vae_explanation": OptionHTML("""
|
"callbacks_order_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'),
|
"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_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'),
|
"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_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,6 +128,7 @@ 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"), {
|
||||||
@@ -406,8 +407,8 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters"
|
|||||||
'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final", infotext='UniPC lower order final'),
|
'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final", infotext='UniPC lower order final'),
|
||||||
'sd_noise_schedule': OptionInfo("Default", "Noise schedule for sampling", gr.Radio, {"choices": ["Default", "Zero Terminal SNR"]}, infotext="Noise Schedule").info("for use with zero terminal SNR trained models"),
|
'sd_noise_schedule': OptionInfo("Default", "Noise schedule for sampling", gr.Radio, {"choices": ["Default", "Zero Terminal SNR"]}, infotext="Noise Schedule").info("for use with zero terminal SNR trained models"),
|
||||||
'skip_early_cond': OptionInfo(0.0, "Ignore negative prompt during early sampling", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext="Skip Early CFG").info("disables CFG on a proportion of steps at the beginning of generation; 0=skip none; 1=skip all; can both improve sample diversity/quality and speed up sampling; XYZ plot: Skip Early CFG"),
|
'skip_early_cond': OptionInfo(0.0, "Ignore negative prompt during early sampling", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext="Skip Early CFG").info("disables CFG on a proportion of steps at the beginning of generation; 0=skip none; 1=skip all; can both improve sample diversity/quality and speed up sampling; XYZ plot: Skip Early CFG"),
|
||||||
'beta_dist_alpha': OptionInfo(0.6, "Beta scheduler - alpha", gr.Slider, {"minimum": 0.01, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler alpha').info('Default = 0.6; the alpha parameter of the beta distribution used in Beta sampling'),
|
'beta_dist_alpha': OptionInfo(0.6, "Beta scheduler - alpha", gr.Slider, {"minimum": 0.01, "maximum": 5.0, "step": 0.01}, infotext='Beta scheduler alpha').info('Default = 0.6; the alpha parameter of the beta distribution used in Beta sampling'),
|
||||||
'beta_dist_beta': OptionInfo(0.6, "Beta scheduler - beta", gr.Slider, {"minimum": 0.01, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler beta').info('Default = 0.6; the beta parameter of the beta distribution used in Beta sampling'),
|
'beta_dist_beta': OptionInfo(0.6, "Beta scheduler - beta", gr.Slider, {"minimum": 0.01, "maximum": 5.0, "step": 0.01}, infotext='Beta scheduler beta').info('Default = 0.6; the beta parameter of the beta distribution used in Beta sampling'),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
options_templates.update(options_section(('postprocessing', "Postprocessing", "postprocessing"), {
|
options_templates.update(options_section(('postprocessing', "Postprocessing", "postprocessing"), {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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
|
||||||
@@ -106,19 +107,25 @@ 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)
|
||||||
|
|
||||||
for ext in exts:
|
lock = threading.Lock()
|
||||||
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()
|
shared.state.nextjob()
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=max(1, int(shared.opts.concurrent_git_fetch_limit))) as executor:
|
||||||
|
for ext in exts:
|
||||||
|
executor.submit(_check_update, ext)
|
||||||
|
|
||||||
return extension_table(), ""
|
return extension_table(), ""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import annotations
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import sys
|
||||||
|
import copy
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
BAD_FLAGS = ("--prefer-binary", '-I', '--ignore-installed')
|
||||||
|
|
||||||
|
|
||||||
|
def patch():
|
||||||
|
if hasattr(subprocess, "__original_run"):
|
||||||
|
return
|
||||||
|
|
||||||
|
print("using uv")
|
||||||
|
try:
|
||||||
|
subprocess.run(['uv', '-V'])
|
||||||
|
except FileNotFoundError:
|
||||||
|
subprocess.run([sys.executable, '-m', 'pip', 'install', 'uv'])
|
||||||
|
|
||||||
|
subprocess.__original_run = subprocess.run
|
||||||
|
|
||||||
|
@wraps(subprocess.__original_run)
|
||||||
|
def patched_run(*args, **kwargs):
|
||||||
|
_kwargs = copy.copy(kwargs)
|
||||||
|
if args:
|
||||||
|
command, *_args = args
|
||||||
|
else:
|
||||||
|
command, _args = _kwargs.pop("args", ""), ()
|
||||||
|
|
||||||
|
if isinstance(command, str):
|
||||||
|
command = shlex.split(command)
|
||||||
|
else:
|
||||||
|
command = [arg.strip() for arg in command]
|
||||||
|
|
||||||
|
if not isinstance(command, list) or "pip" not in command:
|
||||||
|
return subprocess.__original_run(*args, **kwargs)
|
||||||
|
|
||||||
|
cmd = command[command.index("pip") + 1:]
|
||||||
|
|
||||||
|
cmd = [arg for arg in cmd if arg not in BAD_FLAGS]
|
||||||
|
|
||||||
|
modified_command = ["uv", "pip", *cmd]
|
||||||
|
|
||||||
|
cmd_str = shlex.join([*modified_command, *_args])
|
||||||
|
result = subprocess.__original_run(cmd_str, **_kwargs)
|
||||||
|
if result.returncode != 0:
|
||||||
|
return subprocess.__original_run(*args, **kwargs)
|
||||||
|
return result
|
||||||
|
|
||||||
|
subprocess.run = patched_run
|
||||||
@@ -182,7 +182,7 @@ document.addEventListener('keydown', function(e) {
|
|||||||
const lightboxModal = document.querySelector('#lightboxModal');
|
const lightboxModal = document.querySelector('#lightboxModal');
|
||||||
if (!globalPopup || globalPopup.style.display === 'none') {
|
if (!globalPopup || globalPopup.style.display === 'none') {
|
||||||
if (document.activeElement === lightboxModal) return;
|
if (document.activeElement === lightboxModal) return;
|
||||||
if (interruptButton.style.display === 'block') {
|
if (interruptButton?.style.display === 'block') {
|
||||||
interruptButton.click();
|
interruptButton.click();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ 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,6 +26,10 @@ 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
|
||||||
|
|||||||
@@ -480,8 +480,10 @@ div.toprow-compact-tools{
|
|||||||
}
|
}
|
||||||
|
|
||||||
#settings_result{
|
#settings_result{
|
||||||
height: 1.4em;
|
min-height: 1.4em;
|
||||||
margin: 0 1.2em;
|
margin: 0 1.2em;
|
||||||
|
max-height: calc(var(--text-md) * var(--line-sm) * 5);
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.popup-table{
|
table.popup-table{
|
||||||
@@ -600,6 +602,7 @@ table.popup-table .link{
|
|||||||
background: var(--background-fill-primary);
|
background: var(--background-fill-primary);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.livePreview img{
|
.livePreview img{
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check prerequisites
|
# Check prerequisites
|
||||||
gpu_info=$(lspci 2>/dev/null | grep -E "VGA|Display")
|
gpu_info=$(lspci 2>/dev/null | grep -E "VGA|Display|CMP")
|
||||||
case "$gpu_info" in
|
case "$gpu_info" in
|
||||||
*"Navi 1"*)
|
*"Navi 1"*)
|
||||||
export HSA_OVERRIDE_GFX_VERSION=10.3.0
|
export HSA_OVERRIDE_GFX_VERSION=10.3.0
|
||||||
|
|||||||
Reference in New Issue
Block a user