mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-24 21:30:15 +08:00
Merge branch 'comfyanonymous:master' into feature/blockweights
This commit is contained in:
commit
012873cdbf
@ -83,7 +83,7 @@ Put your VAE in: models/vae
|
|||||||
|
|
||||||
At the time of writing this pytorch has issues with python versions higher than 3.10 so make sure your python/pip versions are 3.10.
|
At the time of writing this pytorch has issues with python versions higher than 3.10 so make sure your python/pip versions are 3.10.
|
||||||
|
|
||||||
### AMD (Linux only)
|
### AMD GPUs (Linux only)
|
||||||
AMD users can install rocm and pytorch with pip if you don't have it already installed, this is the command to install the stable version:
|
AMD users can install rocm and pytorch with pip if you don't have it already installed, this is the command to install the stable version:
|
||||||
|
|
||||||
```pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/rocm5.4.2```
|
```pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/rocm5.4.2```
|
||||||
|
|||||||
@ -211,7 +211,10 @@ def sampling_function(model_function, x, timestep, uncond, cond, cond_scale, con
|
|||||||
|
|
||||||
max_total_area = model_management.maximum_batch_area()
|
max_total_area = model_management.maximum_batch_area()
|
||||||
cond, uncond = calc_cond_uncond_batch(model_function, cond, uncond, x, timestep, max_total_area, cond_concat, model_options)
|
cond, uncond = calc_cond_uncond_batch(model_function, cond, uncond, x, timestep, max_total_area, cond_concat, model_options)
|
||||||
return uncond + (cond - uncond) * cond_scale
|
if "sampler_cfg_function" in model_options:
|
||||||
|
return model_options["sampler_cfg_function"](cond, uncond, cond_scale)
|
||||||
|
else:
|
||||||
|
return uncond + (cond - uncond) * cond_scale
|
||||||
|
|
||||||
|
|
||||||
class CompVisVDenoiser(k_diffusion_external.DiscreteVDDPMDenoiser):
|
class CompVisVDenoiser(k_diffusion_external.DiscreteVDDPMDenoiser):
|
||||||
|
|||||||
@ -289,6 +289,9 @@ class ModelPatcher:
|
|||||||
def set_model_tomesd(self, ratio):
|
def set_model_tomesd(self, ratio):
|
||||||
self.model_options["transformer_options"]["tomesd"] = {"ratio": ratio}
|
self.model_options["transformer_options"]["tomesd"] = {"ratio": ratio}
|
||||||
|
|
||||||
|
def set_model_sampler_cfg_function(self, sampler_cfg_function):
|
||||||
|
self.model_options["sampler_cfg_function"] = sampler_cfg_function
|
||||||
|
|
||||||
def model_dtype(self):
|
def model_dtype(self):
|
||||||
return self.model.diffusion_model.dtype
|
return self.model.diffusion_model.dtype
|
||||||
|
|
||||||
|
|||||||
28
nodes.py
28
nodes.py
@ -586,6 +586,24 @@ class EmptyLatentImage:
|
|||||||
return ({"samples":latent}, )
|
return ({"samples":latent}, )
|
||||||
|
|
||||||
|
|
||||||
|
class LatentFromBatch:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required": { "samples": ("LATENT",),
|
||||||
|
"batch_index": ("INT", {"default": 0, "min": 0, "max": 63}),
|
||||||
|
}}
|
||||||
|
RETURN_TYPES = ("LATENT",)
|
||||||
|
FUNCTION = "rotate"
|
||||||
|
|
||||||
|
CATEGORY = "latent"
|
||||||
|
|
||||||
|
def rotate(self, samples, batch_index):
|
||||||
|
s = samples.copy()
|
||||||
|
s_in = samples["samples"]
|
||||||
|
batch_index = min(s_in.shape[0] - 1, batch_index)
|
||||||
|
s["samples"] = s_in[batch_index:batch_index + 1].clone()
|
||||||
|
s["batch_index"] = batch_index
|
||||||
|
return (s,)
|
||||||
|
|
||||||
class LatentUpscale:
|
class LatentUpscale:
|
||||||
upscale_methods = ["nearest-exact", "bilinear", "area"]
|
upscale_methods = ["nearest-exact", "bilinear", "area"]
|
||||||
@ -761,7 +779,14 @@ def common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive,
|
|||||||
if disable_noise:
|
if disable_noise:
|
||||||
noise = torch.zeros(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, device="cpu")
|
noise = torch.zeros(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, device="cpu")
|
||||||
else:
|
else:
|
||||||
noise = torch.randn(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, generator=torch.manual_seed(seed), device="cpu")
|
batch_index = 0
|
||||||
|
if "batch_index" in latent:
|
||||||
|
batch_index = latent["batch_index"]
|
||||||
|
|
||||||
|
generator = torch.manual_seed(seed)
|
||||||
|
for i in range(batch_index):
|
||||||
|
noise = torch.randn([1] + list(latent_image.size())[1:], dtype=latent_image.dtype, layout=latent_image.layout, generator=generator, device="cpu")
|
||||||
|
noise = torch.randn(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, generator=generator, device="cpu")
|
||||||
|
|
||||||
if "noise_mask" in latent:
|
if "noise_mask" in latent:
|
||||||
noise_mask = latent['noise_mask']
|
noise_mask = latent['noise_mask']
|
||||||
@ -1149,6 +1174,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"VAELoader": VAELoader,
|
"VAELoader": VAELoader,
|
||||||
"EmptyLatentImage": EmptyLatentImage,
|
"EmptyLatentImage": EmptyLatentImage,
|
||||||
"LatentUpscale": LatentUpscale,
|
"LatentUpscale": LatentUpscale,
|
||||||
|
"LatentFromBatch": LatentFromBatch,
|
||||||
"SaveImage": SaveImage,
|
"SaveImage": SaveImage,
|
||||||
"PreviewImage": PreviewImage,
|
"PreviewImage": PreviewImage,
|
||||||
"LoadImage": LoadImage,
|
"LoadImage": LoadImage,
|
||||||
|
|||||||
117
web/extensions/core/editAttention.js
Normal file
117
web/extensions/core/editAttention.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { app } from "/scripts/app.js";
|
||||||
|
|
||||||
|
// Allows you to edit the attention weight by holding ctrl (or cmd) and using the up/down arrow keys
|
||||||
|
|
||||||
|
const id = "Comfy.EditAttention";
|
||||||
|
app.registerExtension({
|
||||||
|
name:id,
|
||||||
|
init() {
|
||||||
|
function incrementWeight(weight, delta) {
|
||||||
|
const floatWeight = parseFloat(weight);
|
||||||
|
if (isNaN(floatWeight)) return weight;
|
||||||
|
const newWeight = floatWeight + delta;
|
||||||
|
if (newWeight < 0) return "0";
|
||||||
|
return String(Number(newWeight.toFixed(10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNearestEnclosure(text, cursorPos) {
|
||||||
|
let start = cursorPos, end = cursorPos;
|
||||||
|
let openCount = 0, closeCount = 0;
|
||||||
|
|
||||||
|
// Find opening parenthesis before cursor
|
||||||
|
while (start >= 0) {
|
||||||
|
start--;
|
||||||
|
if (text[start] === "(" && openCount === closeCount) break;
|
||||||
|
if (text[start] === "(") openCount++;
|
||||||
|
if (text[start] === ")") closeCount++;
|
||||||
|
}
|
||||||
|
if (start < 0) return false;
|
||||||
|
|
||||||
|
openCount = 0;
|
||||||
|
closeCount = 0;
|
||||||
|
|
||||||
|
// Find closing parenthesis after cursor
|
||||||
|
while (end < text.length) {
|
||||||
|
if (text[end] === ")" && openCount === closeCount) break;
|
||||||
|
if (text[end] === "(") openCount++;
|
||||||
|
if (text[end] === ")") closeCount++;
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
if (end === text.length) return false;
|
||||||
|
|
||||||
|
return { start: start + 1, end: end };
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWeightToParentheses(text) {
|
||||||
|
const parenRegex = /^\((.*)\)$/;
|
||||||
|
const parenMatch = text.match(parenRegex);
|
||||||
|
|
||||||
|
const floatRegex = /:([+-]?(\d*\.)?\d+([eE][+-]?\d+)?)/;
|
||||||
|
const floatMatch = text.match(floatRegex);
|
||||||
|
|
||||||
|
if (parenMatch && !floatMatch) {
|
||||||
|
return `(${parenMatch[1]}:1.0)`;
|
||||||
|
} else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function editAttention(event) {
|
||||||
|
const inputField = event.composedPath()[0];
|
||||||
|
const delta = 0.025;
|
||||||
|
|
||||||
|
if (inputField.tagName !== "TEXTAREA") return;
|
||||||
|
if (!(event.key === "ArrowUp" || event.key === "ArrowDown")) return;
|
||||||
|
if (!event.ctrlKey && !event.metaKey) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
let start = inputField.selectionStart;
|
||||||
|
let end = inputField.selectionEnd;
|
||||||
|
let selectedText = inputField.value.substring(start, end);
|
||||||
|
|
||||||
|
// If there is no selection, attempt to find the nearest enclosure
|
||||||
|
if (!selectedText) {
|
||||||
|
const nearestEnclosure = findNearestEnclosure(inputField.value, start);
|
||||||
|
if (nearestEnclosure) {
|
||||||
|
start = nearestEnclosure.start;
|
||||||
|
end = nearestEnclosure.end;
|
||||||
|
selectedText = inputField.value.substring(start, end);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the selection ends with a space, remove it
|
||||||
|
if (selectedText[selectedText.length - 1] === " ") {
|
||||||
|
selectedText = selectedText.substring(0, selectedText.length - 1);
|
||||||
|
end -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are parentheses left and right of the selection, select them
|
||||||
|
if (inputField.value[start - 1] === "(" && inputField.value[end] === ")") {
|
||||||
|
start -= 1;
|
||||||
|
end += 1;
|
||||||
|
selectedText = inputField.value.substring(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the selection is not enclosed in parentheses, add them
|
||||||
|
if (selectedText[0] !== "(" || selectedText[selectedText.length - 1] !== ")") {
|
||||||
|
console.log("adding parentheses", inputField.value[start], inputField.value[end], selectedText);
|
||||||
|
selectedText = `(${selectedText})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the selection does not have a weight, add a weight of 1.0
|
||||||
|
selectedText = addWeightToParentheses(selectedText);
|
||||||
|
|
||||||
|
// Increment the weight
|
||||||
|
const weightDelta = event.key === "ArrowUp" ? delta : -delta;
|
||||||
|
const updatedText = selectedText.replace(/(.*:)(\d+(\.\d+)?)(.*)/, (match, prefix, weight, _, suffix) => {
|
||||||
|
return prefix + incrementWeight(weight, weightDelta) + suffix;
|
||||||
|
});
|
||||||
|
|
||||||
|
inputField.setRangeText(updatedText, start, end, "select");
|
||||||
|
}
|
||||||
|
window.addEventListener("keydown", editAttention);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -5,12 +5,6 @@ app.registerExtension({
|
|||||||
name: id,
|
name: id,
|
||||||
init() {
|
init() {
|
||||||
const keybindListener = function(event) {
|
const keybindListener = function(event) {
|
||||||
const target = event.composedPath()[0];
|
|
||||||
|
|
||||||
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modifierPressed = event.ctrlKey || event.metaKey;
|
const modifierPressed = event.ctrlKey || event.metaKey;
|
||||||
|
|
||||||
// Queue prompt using ctrl or command + enter
|
// Queue prompt using ctrl or command + enter
|
||||||
@ -19,6 +13,12 @@ app.registerExtension({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const target = event.composedPath()[0];
|
||||||
|
|
||||||
|
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const modifierKeyIdMap = {
|
const modifierKeyIdMap = {
|
||||||
"s": "#comfy-save-button",
|
"s": "#comfy-save-button",
|
||||||
83: "#comfy-save-button",
|
83: "#comfy-save-button",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user