Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e0cc2ea71 | ||
|
|
a1125b20bc | ||
|
|
db14b955a5 | ||
|
|
6a61c1cf89 | ||
|
|
c974a60749 | ||
|
|
a844119335 | ||
|
|
c22e434e38 | ||
|
|
2c2751a762 | ||
|
|
4f283c3b55 | ||
|
|
d68f0804ed | ||
|
|
9edc20e810 | ||
|
|
615289f00e | ||
|
|
d0f269807e | ||
|
|
f5efee7f23 | ||
|
|
b26fcef6d7 | ||
|
|
54a7c22296 | ||
|
|
0ab09df6c4 | ||
|
|
aa57e309ba | ||
|
|
d56cbf572d |
@@ -52,6 +52,13 @@ git clone https://github.com/yolain/ComfyUI-Easy-Use
|
||||
|
||||
## 📜 更新日志
|
||||
|
||||
**v1.2.6**
|
||||
|
||||
- 修复了在缺少自定义节点时缺少 “红色框框” 样式的问题。
|
||||
- 在一些简单的加载器中,将 `clip_skip` 的默认值从 `-1` 调整为 `-2`。
|
||||
- 修复因设置节点中缺少相连接的自定义节点而导致弄乱画布的问题
|
||||
- 修复 'easy imageChooser' 不能循环使用的问题。
|
||||
|
||||
**v1.2.5**
|
||||
|
||||
- 在 `easy preSamplingCustom` 和 `easy preSamplingAdvanced` 上增加 `enable (GPU=A1111)` 噪波生成模式选择项
|
||||
|
||||
@@ -47,6 +47,13 @@ Double-click install.bat to install the required dependencies
|
||||
|
||||
## 📜 Changelog
|
||||
|
||||
**v1.2.6**
|
||||
|
||||
- Fix missing the "Red Rect" styles when you are missing custom nodes.
|
||||
- Adjust the default value of `clip_skip` from `-1` to `-2` in some easy loaders.
|
||||
- Fix the issue due to set nodes missing custom nodes which their connected, causing canvas to be messed up.
|
||||
- Fix the `easy imageChooser` can not using in a loop.
|
||||
|
||||
**v1.2.5**
|
||||
|
||||
- Added `enable (GPU=A1111)` noise mode on `easy preSamplingCustom` and `easy preSamplingAdvanced`
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
__version__ = "1.2.5"
|
||||
__version__ = "1.2.6"
|
||||
|
||||
import yaml
|
||||
import os
|
||||
|
||||
+3
-3
@@ -877,7 +877,7 @@ class fullLoader:
|
||||
"ckpt_name": (folder_paths.get_filename_list("checkpoints"),),
|
||||
"config_name": (["Default", ] + folder_paths.get_filename_list("configs"), {"default": "Default"}),
|
||||
"vae_name": (["Baked VAE"] + folder_paths.get_filename_list("vae"),),
|
||||
"clip_skip": ("INT", {"default": -1, "min": -24, "max": 0, "step": 1}),
|
||||
"clip_skip": ("INT", {"default": -2, "min": -24, "max": 0, "step": 1}),
|
||||
|
||||
"lora_name": (["None"] + folder_paths.get_filename_list("loras"),),
|
||||
"lora_model_strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||
@@ -986,7 +986,7 @@ class a1111Loader(fullLoader):
|
||||
"required": {
|
||||
"ckpt_name": (checkpoints,),
|
||||
"vae_name": (["Baked VAE"] + folder_paths.get_filename_list("vae"),),
|
||||
"clip_skip": ("INT", {"default": -1, "min": -24, "max": 0, "step": 1}),
|
||||
"clip_skip": ("INT", {"default": -2, "min": -24, "max": 0, "step": 1}),
|
||||
|
||||
"lora_name": (loras,),
|
||||
"lora_model_strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||
@@ -1037,7 +1037,7 @@ class comfyLoader(fullLoader):
|
||||
"required": {
|
||||
"ckpt_name": (folder_paths.get_filename_list("checkpoints"),),
|
||||
"vae_name": (["Baked VAE"] + folder_paths.get_filename_list("vae"),),
|
||||
"clip_skip": ("INT", {"default": -1, "min": -24, "max": 0, "step": 1}),
|
||||
"clip_skip": ("INT", {"default": -2, "min": -24, "max": 0, "step": 1}),
|
||||
|
||||
"lora_name": (["None"] + folder_paths.get_filename_list("loras"),),
|
||||
"lora_model_strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||
|
||||
+39
-16
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import json
|
||||
import copy
|
||||
import hashlib
|
||||
import folder_paths
|
||||
import torch
|
||||
@@ -17,7 +18,7 @@ from torchvision.transforms.functional import to_pil_image
|
||||
from .libs.log import log_node_info
|
||||
from .libs.utils import AlwaysEqualProxy, ByPassTypeTuple
|
||||
from .libs.cache import cache, update_cache, remove_cache
|
||||
from .libs.image import pil2tensor, tensor2pil, ResizeMode, get_new_bounds, RGB2RGBA, image2mask
|
||||
from .libs.image import pil2tensor, tensor2pil, ResizeMode, get_new_bounds, RGB2RGBA, image2mask, empty_image
|
||||
from .libs.colorfix import adain_color_fix, wavelet_color_fix
|
||||
from .libs.chooser import ChooserMessage, ChooserCancelled
|
||||
from .config import REMBG_DIR, REMBG_MODELS, HUMANPARSING_MODELS, MEDIAPIPE_MODELS, MEDIAPIPE_DIR
|
||||
@@ -801,10 +802,10 @@ class imageRemBg:
|
||||
"rem_mode": (("RMBG-2.0", "RMBG-1.4","Inspyrenet"), {"default": "RMBG-1.4"}),
|
||||
"image_output": (["Hide", "Preview", "Save", "Hide/Save"], {"default": "Preview"}),
|
||||
"save_prefix": ("STRING", {"default": "ComfyUI"}),
|
||||
|
||||
},
|
||||
"optional":{
|
||||
"torchscript_jit": ("BOOLEAN", {"default": False}),
|
||||
"add_background": (["none", "white", "black"], {"default": "none"})
|
||||
},
|
||||
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||
}
|
||||
@@ -816,7 +817,8 @@ class imageRemBg:
|
||||
|
||||
CATEGORY = "EasyUse/Image"
|
||||
|
||||
def remove(self, rem_mode, images, image_output, save_prefix, torchscript_jit=False, prompt=None, extra_pnginfo=None):
|
||||
|
||||
def remove(self, rem_mode, images, image_output, save_prefix, torchscript_jit=False, add_background='none',prompt=None, extra_pnginfo=None):
|
||||
new_images = list()
|
||||
masks = list()
|
||||
if rem_mode == "RMBG-2.0":
|
||||
@@ -911,6 +913,13 @@ class imageRemBg:
|
||||
new_images = torch.cat(new_images, dim=0)
|
||||
masks = torch.cat(masks, dim=0)
|
||||
|
||||
if add_background != 'none':
|
||||
|
||||
_layer = tensor2pil(new_images)
|
||||
_canvas = Image.new('RGB', _layer.size, (255,255,255) if add_background == 'white' else (0, 0, 0))
|
||||
_canvas.paste(_layer, mask=_layer)
|
||||
new_images = pil2tensor(_canvas)
|
||||
|
||||
results = easySave(new_images, save_prefix, image_output, prompt, extra_pnginfo)
|
||||
|
||||
if image_output in ("Hide", "Hide/Save"):
|
||||
@@ -956,6 +965,7 @@ class imageChooser(PreviewImage):
|
||||
|
||||
def chooser(self, prompt=None, my_unique_id=None, extra_pnginfo=None, **kwargs):
|
||||
id = my_unique_id[0]
|
||||
id = id.split('.')[len(id.split('.')) - 1] if "." in id else id
|
||||
if id not in ChooserMessage.stash:
|
||||
ChooserMessage.stash[id] = {}
|
||||
my_stash = ChooserMessage.stash[id]
|
||||
@@ -1234,10 +1244,14 @@ class humanSegmentation:
|
||||
|
||||
from functools import reduce
|
||||
|
||||
model_path = get_local_filepath(MEDIAPIPE_MODELS['selfie_multiclass_256x256']['model_url'], MEDIAPIPE_DIR)
|
||||
model_asset_buffer = None
|
||||
with open(model_path, "rb") as f:
|
||||
model_asset_buffer = f.read()
|
||||
if method in cache:
|
||||
_, model_asset_buffer = cache["selfie_multiclass_256x256"][1]
|
||||
else:
|
||||
model_path = get_local_filepath(MEDIAPIPE_MODELS['selfie_multiclass_256x256']['model_url'], MEDIAPIPE_DIR)
|
||||
model_asset_buffer = None
|
||||
with open(model_path, "rb") as f:
|
||||
model_asset_buffer = f.read()
|
||||
update_cache(method, 'human_segmentation', (False, model_asset_buffer))
|
||||
image_segmenter_base_options = mp.tasks.BaseOptions(model_asset_buffer=model_asset_buffer)
|
||||
options = mp.tasks.vision.ImageSegmenterOptions(
|
||||
base_options=image_segmenter_base_options,
|
||||
@@ -1303,10 +1317,15 @@ class humanSegmentation:
|
||||
mask = torch.cat(ret_masks, dim=0)
|
||||
|
||||
elif method == "human_parsing_lip":
|
||||
from .human_parsing.run_parsing import HumanParsing
|
||||
onnx_path = os.path.join(folder_paths.models_dir, 'onnx')
|
||||
model_path = get_local_filepath(HUMANPARSING_MODELS['parsing_lip']['model_url'], onnx_path)
|
||||
parsing = HumanParsing(model_path=model_path)
|
||||
if method in cache:
|
||||
_, parsing = cache[method][1]
|
||||
else:
|
||||
from .human_parsing.run_parsing import HumanParsing
|
||||
onnx_path = os.path.join(folder_paths.models_dir, 'onnx')
|
||||
model_path = get_local_filepath(HUMANPARSING_MODELS['parsing_lip']['model_url'], onnx_path)
|
||||
parsing = HumanParsing(model_path=model_path)
|
||||
update_cache(method, 'human_segmentation', (False, parsing))
|
||||
|
||||
model_image = image.squeeze(0)
|
||||
model_image = model_image.permute((2, 0, 1))
|
||||
model_image = to_pil_image(model_image)
|
||||
@@ -1320,11 +1339,15 @@ class humanSegmentation:
|
||||
output_image, = JoinImageWithAlpha().join_image_with_alpha(image, alpha)
|
||||
|
||||
elif method == "human_parts (deeplabv3p)":
|
||||
from .human_parsing.run_parsing import HumanParts
|
||||
onnx_path = os.path.join(folder_paths.models_dir, 'onnx')
|
||||
human_parts_path = os.path.join(onnx_path, 'human-parts')
|
||||
model_path = get_local_filepath(HUMANPARSING_MODELS['human-parts']['model_url'], human_parts_path)
|
||||
parsing = HumanParts(model_path=model_path)
|
||||
if method in cache:
|
||||
_, parsing = cache[method][1]
|
||||
else:
|
||||
from .human_parsing.run_parsing import HumanParts
|
||||
onnx_path = os.path.join(folder_paths.models_dir, 'onnx')
|
||||
human_parts_path = os.path.join(onnx_path, 'human-parts')
|
||||
model_path = get_local_filepath(HUMANPARSING_MODELS['human-parts']['model_url'], human_parts_path)
|
||||
parsing = HumanParts(model_path=model_path)
|
||||
update_cache(method, 'human_segmentation', (False, parsing))
|
||||
|
||||
ret_images = []
|
||||
ret_masks = []
|
||||
|
||||
@@ -123,9 +123,9 @@ class InstantXFluxIpadapterApply:
|
||||
# process control image
|
||||
image_prompt_embeds = self.get_image_embeds(pil_image=pil_image, clip_image_embeds=None)
|
||||
# set model
|
||||
is_patched = is_model_pathched(model.model)
|
||||
# is_patched = is_model_pathched(model.model)
|
||||
bi = model.clone()
|
||||
FluxUpdateModules(bi, ip_attn_procs, image_prompt_embeds, is_patched)
|
||||
FluxUpdateModules(bi, ip_attn_procs, image_prompt_embeds)
|
||||
|
||||
return (bi, image)
|
||||
|
||||
|
||||
+37
-16
@@ -2,6 +2,7 @@ import torch
|
||||
from torch import Tensor, nn
|
||||
|
||||
from .math import attention
|
||||
from ..attention_processor import IPAFluxAttnProcessor2_0
|
||||
from comfy.ldm.flux.layers import DoubleStreamBlock, SingleStreamBlock
|
||||
from comfy import model_management as mm
|
||||
|
||||
@@ -27,12 +28,13 @@ class DoubleStreamBlockIPA(nn.Module):
|
||||
|
||||
self.txt_norm2 = original_block.txt_norm2
|
||||
self.txt_mlp = original_block.txt_mlp
|
||||
self.flipped_img_txt = original_block.flipped_img_txt
|
||||
|
||||
self.ip_adapter = ip_adapter
|
||||
self.image_emb = image_emb
|
||||
self.device = mm.get_torch_device()
|
||||
|
||||
def forward(self, img: Tensor, txt: Tensor, vec: Tensor, pe: Tensor, t: Tensor):
|
||||
def forward(self, img: Tensor, txt: Tensor, vec: Tensor, pe: Tensor, t: Tensor, attn_mask=None):
|
||||
img_mod1, img_mod2 = self.img_mod(vec)
|
||||
txt_mod1, txt_mod2 = self.txt_mod(vec)
|
||||
|
||||
@@ -52,18 +54,29 @@ class DoubleStreamBlockIPA(nn.Module):
|
||||
1, 4)
|
||||
txt_q, txt_k = self.txt_attn.norm(txt_q, txt_k, txt_v)
|
||||
|
||||
# run actual attention
|
||||
attn = attention(torch.cat((txt_q, img_q), dim=2),
|
||||
torch.cat((txt_k, img_k), dim=2),
|
||||
torch.cat((txt_v, img_v), dim=2), pe=pe)
|
||||
if self.flipped_img_txt:
|
||||
# run actual attention
|
||||
attn = attention(torch.cat((img_q, txt_q), dim=2),
|
||||
torch.cat((img_k, txt_k), dim=2),
|
||||
torch.cat((img_v, txt_v), dim=2),
|
||||
pe=pe, mask=attn_mask)
|
||||
|
||||
txt_attn, img_attn = attn[:, : txt.shape[1]], attn[:, txt.shape[1]:]
|
||||
img_attn, txt_attn = attn[:, : img.shape[1]], attn[:, img.shape[1]:]
|
||||
else:
|
||||
# run actual attention
|
||||
attn = attention(torch.cat((txt_q, img_q), dim=2),
|
||||
torch.cat((txt_k, img_k), dim=2),
|
||||
torch.cat((txt_v, img_v), dim=2),
|
||||
pe=pe, mask=attn_mask)
|
||||
|
||||
ip_hidden_states = self.ip_adapter(self.num_heads, img_q, self.image_emb, t)
|
||||
if ip_hidden_states is not None:
|
||||
ip_hidden_states.to(device=self.device)
|
||||
img_attn = img_attn + ip_hidden_states
|
||||
txt_attn, img_attn = attn[:, : txt.shape[1]], attn[:, txt.shape[1]:]
|
||||
|
||||
for adapter, image in zip(self.ip_adapter, self.image_emb):
|
||||
# this does a separate attention for each adapter
|
||||
ip_hidden_states = adapter(self.num_heads, img_q, image, t)
|
||||
if ip_hidden_states is not None:
|
||||
ip_hidden_states = ip_hidden_states.to(self.device)
|
||||
img_attn = img_attn + ip_hidden_states
|
||||
|
||||
# calculate the img bloks
|
||||
img = img + img_mod1.gate * self.img_attn.proj(img_attn)
|
||||
@@ -109,7 +122,11 @@ class SingleStreamBlockIPA(nn.Module):
|
||||
self.image_emb = image_emb
|
||||
self.device = mm.get_torch_device()
|
||||
|
||||
def forward(self, x: Tensor, vec: Tensor, pe: Tensor, t: Tensor) -> Tensor:
|
||||
def add_adapter(self, ip_adapter: IPAFluxAttnProcessor2_0, image_emb):
|
||||
self.ip_adapter.append(ip_adapter)
|
||||
self.image_emb.append(image_emb)
|
||||
|
||||
def forward(self, x: Tensor, vec: Tensor, pe: Tensor, t: Tensor, attn_mask=None) -> Tensor:
|
||||
mod, _ = self.modulation(vec)
|
||||
x_mod = (1 + mod.scale) * self.pre_norm(x) + mod.shift
|
||||
qkv, mlp = torch.split(self.linear1(x_mod), [3 * self.hidden_size, self.mlp_hidden_dim], dim=-1)
|
||||
@@ -118,12 +135,16 @@ class SingleStreamBlockIPA(nn.Module):
|
||||
q, k = self.norm(q, k, v)
|
||||
|
||||
# compute attention
|
||||
attn = attention(q, k, v, pe=pe)
|
||||
attn = attention(q, k, v, pe=pe, mask=attn_mask)
|
||||
|
||||
for adapter, image in zip(self.ip_adapter, self.image_emb):
|
||||
# this does a separate attention for each adapter
|
||||
# maybe we want a single joint attention call for all adapters?
|
||||
ip_hidden_states = adapter(self.num_heads, q, image, t)
|
||||
if ip_hidden_states is not None:
|
||||
ip_hidden_states = ip_hidden_states.to(self.device)
|
||||
attn = attn + ip_hidden_states
|
||||
|
||||
ip_hidden_states = self.ip_adapter(self.num_heads, q, self.image_emb, t)
|
||||
if ip_hidden_states is not None:
|
||||
ip_hidden_states.to(device=self.device)
|
||||
attn = attn + ip_hidden_states
|
||||
# compute activation in mlp stream, cat again and run second linear layer
|
||||
output = self.linear2(torch.cat((attn, self.mlp_act(mlp)), 2))
|
||||
x += mod.gate * output
|
||||
|
||||
@@ -4,11 +4,11 @@ from torch import Tensor
|
||||
from comfy.ldm.modules.attention import optimized_attention
|
||||
import comfy.model_management
|
||||
|
||||
def attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor) -> Tensor:
|
||||
def attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask=None) -> Tensor:
|
||||
q, k = apply_rope(q, k, pe)
|
||||
|
||||
heads = q.shape[1]
|
||||
x = optimized_attention(q, k, v, heads, skip_reshape=True)
|
||||
x = optimized_attention(q, k, v, heads, skip_reshape=True, mask=mask)
|
||||
return x
|
||||
|
||||
|
||||
|
||||
+38
-22
@@ -4,19 +4,33 @@ from .flux.layers import DoubleStreamBlockIPA, SingleStreamBlockIPA
|
||||
from comfy.ldm.flux.layers import timestep_embedding
|
||||
from types import MethodType
|
||||
|
||||
def FluxUpdateModules(bi, ip_attn_procs, image_emb, is_patched):
|
||||
def FluxUpdateModules(bi, ip_attn_procs, image_emb):
|
||||
flux_model = bi.model
|
||||
bi.add_object_patch(f"diffusion_model.forward_orig", MethodType(forward_orig_ipa, flux_model.diffusion_model))
|
||||
dsb_count = len(flux_model.diffusion_model.double_blocks)
|
||||
ssb_count = len(flux_model.diffusion_model.single_blocks)
|
||||
for i in range(dsb_count):
|
||||
temp_layer = DoubleStreamBlockIPA(
|
||||
flux_model.diffusion_model.double_blocks[i], ip_attn_procs[f"double_blocks.{i}"], image_emb)
|
||||
bi.add_object_patch(f"diffusion_model.double_blocks.{i}",temp_layer)
|
||||
for i in range(ssb_count):
|
||||
temp_layer = SingleStreamBlockIPA(
|
||||
flux_model.diffusion_model.single_blocks[i], ip_attn_procs[f"single_blocks.{i}"], image_emb)
|
||||
bi.add_object_patch(f"diffusion_model.single_blocks.{i}", temp_layer)
|
||||
for i, original in enumerate(flux_model.diffusion_model.double_blocks):
|
||||
patch_name = f"double_blocks.{i}"
|
||||
maybe_patched_layer = bi.get_model_object(f"diffusion_model.{patch_name}")
|
||||
# if there's already a patch there, collect its adapters and replace it
|
||||
procs = [ip_attn_procs[patch_name]]
|
||||
embs = [image_emb]
|
||||
if isinstance(maybe_patched_layer, DoubleStreamBlockIPA):
|
||||
procs = maybe_patched_layer.ip_adapter + procs
|
||||
embs = maybe_patched_layer.image_emb + embs
|
||||
# initial ipa models with image embeddings
|
||||
new_layer = DoubleStreamBlockIPA(original, procs, embs)
|
||||
# for example, ComfyUI internally uses model.add_patches to add loras
|
||||
bi.add_object_patch(f"diffusion_model.{patch_name}", new_layer)
|
||||
for i, original in enumerate(flux_model.diffusion_model.single_blocks):
|
||||
patch_name = f"single_blocks.{i}"
|
||||
maybe_patched_layer = bi.get_model_object(f"diffusion_model.{patch_name}")
|
||||
procs = [ip_attn_procs[patch_name]]
|
||||
embs = [image_emb]
|
||||
if isinstance(maybe_patched_layer, SingleStreamBlockIPA):
|
||||
procs = maybe_patched_layer.ip_adapter + procs
|
||||
embs = maybe_patched_layer.image_emb + embs
|
||||
# initial ipa models with image embeddings
|
||||
new_layer = SingleStreamBlockIPA(original, procs, embs)
|
||||
bi.add_object_patch(f"diffusion_model.{patch_name}", new_layer)
|
||||
|
||||
def is_model_pathched(model):
|
||||
def test(mod):
|
||||
@@ -31,6 +45,7 @@ def is_model_pathched(model):
|
||||
result = test(model)
|
||||
return result
|
||||
|
||||
|
||||
def forward_orig_ipa(
|
||||
self,
|
||||
img: Tensor,
|
||||
@@ -39,9 +54,10 @@ def forward_orig_ipa(
|
||||
txt_ids: Tensor,
|
||||
timesteps: Tensor,
|
||||
y: Tensor,
|
||||
guidance: Tensor = None,
|
||||
guidance: Tensor|None = None,
|
||||
control=None,
|
||||
transformer_options={},
|
||||
attn_mask: Tensor = None,
|
||||
) -> Tensor:
|
||||
patches_replace = transformer_options.get("patches_replace", {})
|
||||
if img.ndim != 3 or txt.ndim != 3:
|
||||
@@ -67,18 +83,18 @@ def forward_orig_ipa(
|
||||
def block_wrap(args):
|
||||
out = {}
|
||||
if isinstance(block, DoubleStreamBlockIPA): # ipadaper
|
||||
out["img"], out["txt"] = block(img=args["img"], txt=args["txt"], vec=args["vec"], pe=args["pe"], t=args["timesteps"])
|
||||
out["img"], out["txt"] = block(img=args["img"], txt=args["txt"], vec=args["vec"], pe=args["pe"], t=args["timesteps"], attn_mask=args.get("attn_mask"))
|
||||
else:
|
||||
out["img"], out["txt"] = block(img=args["img"], txt=args["txt"], vec=args["vec"], pe=args["pe"])
|
||||
out["img"], out["txt"] = block(img=args["img"], txt=args["txt"], vec=args["vec"], pe=args["pe"], attn_mask=args.get("attn_mask"))
|
||||
return out
|
||||
out = blocks_replace[("double_block", i)]({"img": img, "txt": txt, "vec": vec, "pe": pe, "timesteps": timesteps}, {"original_block": block_wrap})
|
||||
out = blocks_replace[("double_block", i)]({"img": img, "txt": txt, "vec": vec, "pe": pe, "timesteps": timesteps, "attn_mask": attn_mask}, {"original_block": block_wrap})
|
||||
txt = out["txt"]
|
||||
img = out["img"]
|
||||
else:
|
||||
if isinstance(block, DoubleStreamBlockIPA): # ipadaper
|
||||
img, txt = block(img=img, txt=txt, vec=vec, pe=pe, t=timesteps)
|
||||
img, txt = block(img=img, txt=txt, vec=vec, pe=pe, t=timesteps, attn_mask=attn_mask)
|
||||
else:
|
||||
img, txt = block(img=img, txt=txt, vec=vec, pe=pe)
|
||||
img, txt = block(img=img, txt=txt, vec=vec, pe=pe, attn_mask=attn_mask)
|
||||
|
||||
if control is not None: # Controlnet
|
||||
control_i = control.get("input")
|
||||
@@ -94,18 +110,18 @@ def forward_orig_ipa(
|
||||
def block_wrap(args):
|
||||
out = {}
|
||||
if isinstance(block, SingleStreamBlockIPA): # ipadaper
|
||||
out["img"] = block(args["img"], vec=args["vec"], pe=args["pe"], t=args["timesteps"])
|
||||
out["img"] = block(args["img"], vec=args["vec"], pe=args["pe"], t=args["timesteps"], attn_mask=args.get("attn_mask"))
|
||||
else:
|
||||
out["img"] = block(args["img"], vec=args["vec"], pe=args["pe"])
|
||||
out["img"] = block(args["img"], vec=args["vec"], pe=args["pe"], attn_mask=args.get("attn_mask"))
|
||||
return out
|
||||
|
||||
out = blocks_replace[("single_block", i)]({"img": img, "vec": vec, "pe": pe, "timesteps": timesteps}, {"original_block": block_wrap})
|
||||
out = blocks_replace[("single_block", i)]({"img": img, "vec": vec, "pe": pe, "timesteps": timesteps, "attn_mask": attn_mask}, {"original_block": block_wrap})
|
||||
img = out["img"]
|
||||
else:
|
||||
if isinstance(block, SingleStreamBlockIPA): # ipadaper
|
||||
img = block(img, vec=vec, pe=pe, t=timesteps)
|
||||
img = block(img, vec=vec, pe=pe, t=timesteps, attn_mask=attn_mask)
|
||||
else:
|
||||
img = block(img, vec=vec, pe=pe)
|
||||
img = block(img, vec=vec, pe=pe, attn_mask=attn_mask)
|
||||
|
||||
if control is not None: # Controlnet
|
||||
control_o = control.get("output")
|
||||
|
||||
+1
-1
@@ -296,7 +296,7 @@ class applyKolorsUnet:
|
||||
|
||||
|
||||
def is_kolors_model(model):
|
||||
unet_config = model.model.model_config.unet_config
|
||||
unet_config = model.model.model_config.unet_config if hasattr(model, 'model') else None
|
||||
if unet_config and "adm_in_channels" in unet_config and unet_config["adm_in_channels"] == 5632:
|
||||
return True
|
||||
else:
|
||||
|
||||
@@ -23,7 +23,11 @@ class easyControlnet:
|
||||
control_net = patch_controlnet(model, control_net)
|
||||
else:
|
||||
if control_net is None:
|
||||
control_net = easyCache.load_controlnet(control_net_name, scale_soft_weights, use_cache)
|
||||
if easyCache is not None:
|
||||
control_net = easyCache.load_controlnet(control_net_name, scale_soft_weights, use_cache)
|
||||
else:
|
||||
controlnet_path = folder_paths.get_full_path("controlnet", control_net_name)
|
||||
control_net = comfy.controlnet.load_controlnet(controlnet_path)
|
||||
|
||||
# union controlnet
|
||||
if union_type is not None:
|
||||
|
||||
+4
-5
@@ -42,11 +42,10 @@ class FluxAIAPI:
|
||||
|
||||
response = requests.post(url, json=json, headers=headers)
|
||||
res = response.json()
|
||||
data = res['data']
|
||||
if "error" in data:
|
||||
return data['error']
|
||||
elif "prompt" in data:
|
||||
return data['prompt']
|
||||
if "error" in res:
|
||||
return res['error']
|
||||
elif "data" in res and "prompt" in res['data']:
|
||||
return res['data']['prompt']
|
||||
|
||||
fluxaiAPI = FluxAIAPI()
|
||||
|
||||
|
||||
@@ -105,6 +105,11 @@ class blendImage:
|
||||
return blended_image
|
||||
|
||||
|
||||
def empty_image(width, height, batch_size=1, color=0):
|
||||
r = torch.full([batch_size, height, width, 1], ((color >> 16) & 0xFF) / 0xFF)
|
||||
g = torch.full([batch_size, height, width, 1], ((color >> 8) & 0xFF) / 0xFF)
|
||||
b = torch.full([batch_size, height, width, 1], ((color) & 0xFF) / 0xFF)
|
||||
return torch.cat((r, g, b), dim=-1)
|
||||
|
||||
|
||||
class ResizeMode(Enum):
|
||||
|
||||
@@ -12,8 +12,8 @@ from .utils import install_package
|
||||
try:
|
||||
from lark import Lark, Transformer, v_args
|
||||
except:
|
||||
print('install lark-parser...')
|
||||
install_package('lark-parser')
|
||||
print('install lark...')
|
||||
install_package('lark')
|
||||
from lark import Lark, Transformer, v_args
|
||||
|
||||
model_path = os.path.join(folder_paths.models_dir, 'prompt_generator')
|
||||
@@ -185,7 +185,7 @@ class ChinesePromptTranslate(Transformer):
|
||||
|
||||
|
||||
#定义Prompt文法
|
||||
grammar = """
|
||||
grammar = r"""
|
||||
start: sentence
|
||||
sentence: phrase ("," phrase)*
|
||||
phrase: emphasis | weight | word | lora | embedding | schedule
|
||||
|
||||
@@ -168,7 +168,7 @@ def process(text, seed=None):
|
||||
replacements_found = True
|
||||
string = string.replace(f"__{match}__", replacement, 1)
|
||||
elif '*' in keyword:
|
||||
subpattern = keyword.replace('*', '.*').replace('+','\+')
|
||||
subpattern = keyword.replace('*', '.*').replace('+', r'\+')
|
||||
total_patterns = []
|
||||
found = False
|
||||
for k, v in easy_wildcard_dict.items():
|
||||
|
||||
Regular → Executable
+7
-4
@@ -1256,7 +1256,6 @@ class batchAnything:
|
||||
return samples_out
|
||||
|
||||
def batch(self, any_1, any_2):
|
||||
|
||||
if isinstance(any_1, torch.Tensor) or isinstance(any_2, torch.Tensor):
|
||||
if any_1 is None:
|
||||
return (any_2,)
|
||||
@@ -1271,13 +1270,17 @@ class batchAnything:
|
||||
return (any_1,)
|
||||
elif isinstance(any_2, tuple):
|
||||
return (any_2 + (any_1,),)
|
||||
return ((any_1, any_2),)
|
||||
elif isinstance(any_2, list):
|
||||
return (any_2 + [any_1],)
|
||||
return ([any_1, any_2],)
|
||||
elif isinstance(any_2, (str, float, int)):
|
||||
if any_1 is None:
|
||||
return (any_2,)
|
||||
elif isinstance(any_1, tuple):
|
||||
return (any_1 + (any_2,),)
|
||||
return ((any_2, any_1),)
|
||||
elif isinstance(any_1, list):
|
||||
return (any_1 + [any_2],)
|
||||
return ([any_2, any_1],)
|
||||
elif isinstance(any_1, dict) and 'samples' in any_1:
|
||||
if any_2 is None:
|
||||
return (any_1,)
|
||||
@@ -1728,7 +1731,7 @@ class saveText:
|
||||
if not os.path.isabs(output_file_path):
|
||||
output_path = os.path.join(self.output_dir, output_path)
|
||||
base_output = os.path.basename(output_path)
|
||||
if output_path.endswith("ComfyUI/output") or output_path.endswith("ComfyUI\output"):
|
||||
if output_path.endswith("ComfyUI/output") or output_path.endswith(r"ComfyUI\output"):
|
||||
base_output = ""
|
||||
|
||||
# Check output destination
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
[project]
|
||||
name = "comfyui-easy-use"
|
||||
description = "To enhance the usability of ComfyUI, optimizations and integrations have been implemented for several commonly used nodes."
|
||||
version = "1.2.5"
|
||||
version = "1.2.6"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["diffusers", "accelerate", "clip_interrogator>=0.6.0", "sentencepiece", "lark-parser", "onnxruntime", "spandrel", "opencv-python"]
|
||||
dependencies = ["diffusers", "accelerate", "clip_interrogator>=0.6.0", "sentencepiece", "lark", "onnxruntime", "spandrel", "opencv-python"]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/yolain/ComfyUI-Easy-Use"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
diffusers
|
||||
accelerate
|
||||
clip_interrogator>=0.6.0
|
||||
lark-parser
|
||||
lark
|
||||
onnxruntime
|
||||
opencv-python
|
||||
sentencepiece
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user