Merge branch 'main_upstream'

This commit is contained in:
Manuel Schmid 2023-12-16 16:17:37 +01:00
commit 6ea37bec93
No known key found for this signature in database
GPG Key ID: 32C4F7569B40B84B
10 changed files with 134 additions and 244 deletions

View File

@ -94,6 +94,10 @@
overflow:inherit !important;
}
.gradio-container{
overflow: visible;
}
/* fullpage image viewer */
#lightboxModal{

View File

@ -1 +1 @@
version = '2.1.840'
version = '2.1.843'

View File

@ -1,18 +1,5 @@
onUiLoaded(async() => {
// Helper functions
// Get active tab
/**
* Waits for an element to be present in the DOM.
*/
const waitForElement = (id) => new Promise(resolve => {
const checkForElement = () => {
const element = document.querySelector(id);
if (element) return resolve(element);
setTimeout(checkForElement, 100);
};
checkForElement();
});
// Detect whether the element has a horizontal scroll bar
function hasHorizontalScrollbar(element) {
@ -33,140 +20,40 @@ onUiLoaded(async() => {
}
}
// Check if hotkey is valid
function isValidHotkey(value) {
const specialKeys = ["Ctrl", "Alt", "Shift", "Disable"];
return (
(typeof value === "string" &&
value.length === 1 &&
/[a-z]/i.test(value)) ||
specialKeys.includes(value)
);
}
// Normalize hotkey
function normalizeHotkey(hotkey) {
return hotkey.length === 1 ? "Key" + hotkey.toUpperCase() : hotkey;
}
// Format hotkey for display
function formatHotkeyForDisplay(hotkey) {
return hotkey.startsWith("Key") ? hotkey.slice(3) : hotkey;
}
// Create hotkey configuration with the provided options
function createHotkeyConfig(defaultHotkeysConfig) {
const result = {}; // Resulting hotkey configuration
for (const key in defaultHotkeysConfig) {
result[key] = defaultHotkeysConfig[key];
}
return result;
}
// Disables functions in the config object based on the provided list of function names
function disableFunctions(config, disabledFunctions) {
// Bind the hasOwnProperty method to the functionMap object to avoid errors
const hasOwnProperty =
Object.prototype.hasOwnProperty.bind(functionMap);
// Loop through the disabledFunctions array and disable the corresponding functions in the config object
disabledFunctions.forEach(funcName => {
if (hasOwnProperty(funcName)) {
const key = functionMap[funcName];
config[key] = "disable";
}
});
// Return the updated config object
return config;
}
/**
* The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio.
* If the image display property is set to 'none', the mask breaks. To fix this, the function
* temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds
* to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on
* very long images.
*/
function restoreImgRedMask(elements) {
const mainTabId = getTabId(elements);
if (!mainTabId) return;
const mainTab = gradioApp().querySelector(mainTabId);
const img = mainTab.querySelector("img");
const imageARPreview = gradioApp().querySelector("#imageARPreview");
if (!img || !imageARPreview) return;
imageARPreview.style.transform = "";
if (parseFloat(mainTab.style.width) > 865) {
const transformString = mainTab.style.transform;
const scaleMatch = transformString.match(
/scale\(([-+]?[0-9]*\.?[0-9]+)\)/
);
let zoom = 1; // default zoom
if (scaleMatch && scaleMatch[1]) {
zoom = Number(scaleMatch[1]);
}
imageARPreview.style.transformOrigin = "0 0";
imageARPreview.style.transform = `scale(${zoom})`;
}
if (img.style.display !== "none") return;
img.style.display = "block";
setTimeout(() => {
img.style.display = "none";
}, 400);
}
// Default config
const defaultHotkeysConfig = {
canvas_hotkey_zoom: "Alt",
canvas_hotkey_zoom: "Shift",
canvas_hotkey_adjust: "Ctrl",
canvas_zoom_undo_extra_key: "Ctrl",
canvas_zoom_hotkey_undo: "KeyZ",
canvas_hotkey_reset: "KeyR",
canvas_hotkey_fullscreen: "KeyS",
canvas_hotkey_move: "KeyF",
canvas_hotkey_overlap: "KeyO",
canvas_disabled_functions: [],
canvas_show_tooltip: true,
canvas_auto_expand: true,
canvas_blur_prompt: false,
};
const functionMap = {
"Zoom": "canvas_hotkey_zoom",
"Adjust brush size": "canvas_hotkey_adjust",
"Moving canvas": "canvas_hotkey_move",
"Fullscreen": "canvas_hotkey_fullscreen",
"Reset Zoom": "canvas_hotkey_reset",
"Overlap": "canvas_hotkey_overlap"
canvas_blur_prompt: true,
};
// Loading the configuration from opts
const preHotkeysConfig = createHotkeyConfig(
const hotkeysConfig = createHotkeyConfig(
defaultHotkeysConfig
);
// Disable functions that are not needed by the user
const hotkeysConfig = disableFunctions(
preHotkeysConfig,
preHotkeysConfig.canvas_disabled_functions
);
let isMoving = false;
let mouseX, mouseY;
let activeElement;
const elemData = {};
function applyZoomAndPan(elemId, isExtension = true) {
function applyZoomAndPan(elemId) {
const targetElement = gradioApp().querySelector(elemId);
if (!targetElement) {
@ -181,6 +68,7 @@ onUiLoaded(async() => {
panX: 0,
panY: 0
};
let fullScreenMode = false;
// Create tooltip
@ -211,44 +99,46 @@ onUiLoaded(async() => {
action: "Adjust brush size",
keySuffix: " + wheel"
},
{configKey: "canvas_zoom_hotkey_undo", action: "Undo last action", keyPrefix: `${hotkeysConfig.canvas_zoom_undo_extra_key} + ` },
{configKey: "canvas_hotkey_reset", action: "Reset zoom"},
{
configKey: "canvas_hotkey_fullscreen",
action: "Fullscreen mode"
},
{configKey: "canvas_hotkey_move", action: "Move canvas"},
{configKey: "canvas_hotkey_overlap", action: "Overlap"}
{configKey: "canvas_hotkey_move", action: "Move canvas"}
];
// Create hotkeys array with disabled property based on the config values
const hotkeys = hotkeysInfo.map(info => {
// Create hotkeys array based on the config values
const hotkeys = hotkeysInfo.map((info) => {
const configValue = hotkeysConfig[info.configKey];
const key = info.keySuffix ?
`${configValue}${info.keySuffix}` :
configValue.charAt(configValue.length - 1);
return {
key,
action: info.action,
disabled: configValue === "disable"
};
});
for (const hotkey of hotkeys) {
if (hotkey.disabled) {
continue;
let key = configValue.slice(-1);
if (info.keySuffix) {
key = `${configValue}${info.keySuffix}`;
}
if (info.keyPrefix && info.keyPrefix !== "None + ") {
key = `${info.keyPrefix}${configValue[3]}`;
}
return {
key,
action: info.action,
};
});
hotkeys
.forEach(hotkey => {
const p = document.createElement("p");
p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`;
tooltipContent.appendChild(p);
});
tooltip.append(info, tooltipContent);
const p = document.createElement("p");
p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`;
tooltipContent.appendChild(p);
}
// Add information and content elements to the tooltip element
tooltip.appendChild(info);
tooltip.appendChild(tooltipContent);
// Add a hint element to the target element
toolTipElemnt.appendChild(tooltip);
// Add a hint element to the target element
toolTipElemnt.appendChild(tooltip);
}
//Show tool tip if setting enable
@ -264,9 +154,7 @@ onUiLoaded(async() => {
panY: 0
};
if (isExtension) {
targetElement.style.overflow = "hidden";
}
targetElement.style.overflow = "hidden";
targetElement.isZoomed = false;
@ -284,7 +172,7 @@ onUiLoaded(async() => {
closeBtn.addEventListener("click", resetZoom);
}
if (canvas && isExtension) {
if (canvas) {
const parentElement = targetElement.closest('[id^="component-"]');
if (
canvas &&
@ -297,16 +185,6 @@ onUiLoaded(async() => {
}
if (
canvas &&
!isExtension &&
parseFloat(canvas.style.width) > 865 &&
parseFloat(targetElement.style.width) > 865
) {
fitToElement();
return;
}
targetElement.style.width = "";
}
@ -372,12 +250,10 @@ onUiLoaded(async() => {
targetElement.style.transformOrigin = "0 0";
targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${newZoomLevel})`;
targetElement.style.overflow = "visible";
toggleOverlap("on");
if (isExtension) {
targetElement.style.overflow = "visible";
}
return newZoomLevel;
}
@ -388,6 +264,7 @@ onUiLoaded(async() => {
let zoomPosX, zoomPosY;
let delta = 0.2;
if (elemData[elemId].zoomLevel > 7) {
delta = 0.9;
} else if (elemData[elemId].zoomLevel > 2) {
@ -421,12 +298,7 @@ onUiLoaded(async() => {
let parentElement;
if (isExtension) {
parentElement = targetElement.closest('[id^="component-"]');
} else {
parentElement = targetElement.parentElement;
}
parentElement = targetElement.closest('[id^="component-"]');
// Get element and screen dimensions
const elementWidth = targetElement.offsetWidth;
@ -455,6 +327,26 @@ onUiLoaded(async() => {
toggleOverlap("off");
}
// Undo last action
function undoLastAction(e) {
let isCtrlPressed = isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)
const isAuxButton = e.button >= 3;
if (isAuxButton) {
isCtrlPressed = true
} else {
if (!isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)) return;
}
// Move undoBtn query outside the if statement to avoid unnecessary queries
const undoBtn = document.querySelector(`${activeElement} button[aria-label="Undo"]`);
if ((isCtrlPressed) && undoBtn ) {
e.preventDefault();
undoBtn.click();
}
}
/**
* This function fits the target element to the screen by calculating
* the required scale and offsets. It also updates the global variables
@ -469,13 +361,8 @@ onUiLoaded(async() => {
if (!canvas) return;
if (canvas.offsetWidth > 862 || isExtension) {
targetElement.style.width = (canvas.offsetWidth + 2) + "px";
}
if (isExtension) {
targetElement.style.overflow = "visible";
}
targetElement.style.width = (canvas.offsetWidth + 2) + "px";
targetElement.style.overflow = "visible";
if (fullScreenMode) {
resetZoom();
@ -549,11 +436,11 @@ onUiLoaded(async() => {
}
}
const hotkeyActions = {
[hotkeysConfig.canvas_hotkey_reset]: resetZoom,
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen,
[hotkeysConfig.canvas_zoom_hotkey_undo]: undoLastAction,
};
const action = hotkeyActions[event.code];
@ -597,26 +484,27 @@ onUiLoaded(async() => {
}
targetElement.addEventListener("mousemove", getMousePosition);
targetElement.addEventListener("auxclick", undoLastAction);
//observers
// Creating an observer with a callback function to handle DOM changes
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
// If the style attribute of the canvas has changed, by observation it happens only when the picture changes
if (mutation.type === 'attributes' && mutation.attributeName === 'style' &&
mutation.target.tagName.toLowerCase() === 'canvas') {
targetElement.isExpanded = false;
setTimeout(resetZoom, 10);
}
// If the style attribute of the canvas has changed, by observation it happens only when the picture changes
if (mutation.type === 'attributes' && mutation.attributeName === 'style' &&
mutation.target.tagName.toLowerCase() === 'canvas') {
targetElement.isExpanded = false;
setTimeout(resetZoom, 10);
}
}
});
// Apply auto expand if enabled
if (hotkeysConfig.canvas_auto_expand) {
});
// Apply auto expand if enabled
if (hotkeysConfig.canvas_auto_expand) {
targetElement.addEventListener("mousemove", autoExpand);
// Set up an observer to track attribute changes
observer.observe(targetElement, {attributes: true, childList: true, subtree: true});
}
observer.observe(targetElement, { attributes: true, childList: true, subtree: true });
}
// Handle events only inside the targetElement
let isKeyDownHandlerAttached = false;
@ -661,7 +549,7 @@ onUiLoaded(async() => {
function handleMoveKeyDown(e) {
// Disable key locks to make pasting from the buffer work correctly
if ((e.ctrlKey && e.code === 'KeyV') || (e.ctrlKey && event.code === 'KeyC') || e.code === "F5") {
if ((e.ctrlKey && e.code === 'KeyV') || (e.ctrlKey && e.code === 'KeyC') || e.code === "F5") {
return;
}
@ -713,11 +601,7 @@ onUiLoaded(async() => {
if (isMoving && elemId === activeElement) {
updatePanPosition(e.movementX, e.movementY);
targetElement.style.pointerEvents = "none";
if (isExtension) {
targetElement.style.overflow = "visible";
}
targetElement.style.overflow = "visible";
} else {
targetElement.style.pointerEvents = "auto";
}
@ -745,18 +629,13 @@ onUiLoaded(async() => {
}
}
if (isExtension) {
targetElement.addEventListener("mousemove", checkForOutBox);
}
targetElement.addEventListener("mousemove", checkForOutBox);
window.addEventListener('resize', (e) => {
resetZoom();
if (isExtension) {
targetElement.isExpanded = false;
targetElement.isZoomed = false;
}
targetElement.isExpanded = false;
targetElement.isZoomed = false;
});
gradioApp().addEventListener("mousemove", handleMoveByKey);

View File

@ -29,9 +29,7 @@ def attention_basic_with_sim(q, k, v, heads, mask=None):
# force cast to fp32 to avoid overflowing
if _ATTN_PRECISION =="fp32":
with torch.autocast(enabled=False, device_type = 'cuda'):
q, k = q.float(), k.float()
sim = einsum('b i d, b j d -> b i j', q, k) * scale
sim = einsum('b i d, b j d -> b i j', q.float(), k.float()) * scale
else:
sim = einsum('b i d, b j d -> b i j', q, k) * scale
@ -113,7 +111,6 @@ class SelfAttentionGuidance:
m = model.clone()
attn_scores = None
mid_block_shape = None
# TODO: make this work properly with chunked batches
# currently, we can only save the attn from one UNet call
@ -136,7 +133,6 @@ class SelfAttentionGuidance:
def post_cfg_function(args):
nonlocal attn_scores
nonlocal mid_block_shape
uncond_attn = attn_scores
sag_scale = scale

View File

@ -104,9 +104,7 @@ def attention_basic(q, k, v, heads, mask=None):
# force cast to fp32 to avoid overflowing
if _ATTN_PRECISION =="fp32":
with torch.autocast(enabled=False, device_type = 'cuda'):
q, k = q.float(), k.float()
sim = einsum('b i d, b j d -> b i j', q, k) * scale
sim = einsum('b i d, b j d -> b i j', q.float(), k.float()) * scale
else:
sim = einsum('b i d, b j d -> b i j', q, k) * scale

View File

@ -2,6 +2,7 @@ from ldm_patched.k_diffusion import sampling as k_diffusion_sampling
from ldm_patched.unipc import uni_pc
import torch
import enum
import collections
from ldm_patched.modules import model_management
import math
from ldm_patched.modules import model_base
@ -61,9 +62,7 @@ def get_area_and_mult(conds, x_in, timestep_in):
for c in model_conds:
conditioning[c] = model_conds[c].process_cond(batch_size=x_in.shape[0], device=x_in.device, area=area)
control = None
if 'control' in conds:
control = conds['control']
control = conds.get('control', None)
patches = None
if 'gligen' in conds:
@ -78,7 +77,8 @@ def get_area_and_mult(conds, x_in, timestep_in):
patches['middle_patch'] = [gligen_patch]
return (input_x, mult, conditioning, area, control, patches)
cond_obj = collections.namedtuple('cond_obj', ['input_x', 'mult', 'conditioning', 'area', 'control', 'patches'])
return cond_obj(input_x, mult, conditioning, area, control, patches)
def cond_equal_size(c1, c2):
if c1 is c2:
@ -91,24 +91,24 @@ def cond_equal_size(c1, c2):
return True
def can_concat_cond(c1, c2):
if c1[0].shape != c2[0].shape:
if c1.input_x.shape != c2.input_x.shape:
return False
#control
if (c1[4] is None) != (c2[4] is None):
return False
if c1[4] is not None:
if c1[4] is not c2[4]:
def objects_concatable(obj1, obj2):
if (obj1 is None) != (obj2 is None):
return False
if obj1 is not None:
if obj1 is not obj2:
return False
return True
#patches
if (c1[5] is None) != (c2[5] is None):
if not objects_concatable(c1.control, c2.control):
return False
if (c1[5] is not None):
if c1[5] is not c2[5]:
return False
return cond_equal_size(c1[2], c2[2])
if not objects_concatable(c1.patches, c2.patches):
return False
return cond_equal_size(c1.conditioning, c2.conditioning)
def cond_cat(c_list):
c_crossattn = []
@ -184,13 +184,13 @@ def calc_cond_uncond_batch(model, cond, uncond, x_in, timestep, model_options):
for x in to_batch:
o = to_run.pop(x)
p = o[0]
input_x += [p[0]]
mult += [p[1]]
c += [p[2]]
area += [p[3]]
cond_or_uncond += [o[1]]
control = p[4]
patches = p[5]
input_x.append(p.input_x)
mult.append(p.mult)
c.append(p.conditioning)
area.append(p.area)
cond_or_uncond.append(o[1])
control = p.control
patches = p.patches
batch_chunks = len(cond_or_uncond)
input_x = torch.cat(input_x)

View File

@ -191,7 +191,7 @@ def encode_vae_inpaint(vae, pixels, mask):
latent_mask = mask[:, None, :, :]
latent_mask = torch.nn.functional.interpolate(latent_mask, size=(H * 8, W * 8), mode="bilinear").round()
latent_mask = torch.nn.functional.max_pool2d(latent_mask, (8, 8)).round()
latent_mask = torch.nn.functional.max_pool2d(latent_mask, (8, 8)).round().to(latent)
return latent, latent_mask

View File

@ -269,9 +269,10 @@ def sdxl_encode_adm_patched(self, **kwargs):
height = float(height) * positive_adm_scale
def embedder(number_list):
h = [self.embedder(torch.Tensor([number])) for number in number_list]
y = torch.flatten(torch.cat(h)).unsqueeze(dim=0).repeat(clip_pooled.shape[0], 1)
return y
h = torch.tensor(number_list, dtype=torch.float32)
h = self.embedder(h)
h = torch.flatten(h).unsqueeze(dim=0).repeat(clip_pooled.shape[0], 1)
return h
width, height = round_to_64(width), round_to_64(height)
target_width, target_height = round_to_64(target_width), round_to_64(target_height)

View File

@ -121,7 +121,7 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
In Colab, you can modify the last line to `!python entry_with_update.py --share` or `!python entry_with_update.py --preset anime --share` or `!python entry_with_update.py --preset realistic --share` for Fooocus Default/Anime/Realistic Edition.
Note that this Colab will disable refiner by default because Colab free's resource is relatively limited.
Note that this Colab will disable refiner by default because Colab free's resource is relatively limited (and some "big" features like image prompt may cause free-tier Colab to disconnect). We make sure that basic text-to-image is always working on free-tier Colab.
Thanks to [camenduru](https://github.com/camenduru)!
@ -384,7 +384,7 @@ See also [About Forking and Promotion of Forks](https://github.com/lllyasviel/Fo
## Thanks
Special thanks to [twri](https://github.com/twri) and [3Diva](https://github.com/3Diva) for creating additional SDXL styles available in Fooocus.
Special thanks to [twri](https://github.com/twri) and [3Diva](https://github.com/3Diva) for creating additional SDXL styles available in Fooocus. Thanks [daswer123](https://github.com/daswer123) for contributing the Canvas Zoom!
## Update Log

View File

@ -1,3 +1,15 @@
# 2.1.843
* Many improvements to Canvas. Thanks CanvasZoom author!
# 2.1.841
* Backend maintain.
* Fix some potential frozen after model mismatch.
* Fix crash when cfg=1 when using anime preset.
* Added some guidelines for troubleshoot the "CUDA kernel errors asynchronously" problem.
* Fix inpaint device problem in `--always-gpu` mode.
# 2.1.839
* Maintained some computation codes in backend for efficiency.