add:easy ipadapterStyleComposition

This commit is contained in:
yolain
2024-04-09 23:48:41 +08:00
parent 689d988130
commit fdc761ebfa
10 changed files with 285 additions and 56 deletions
+2 -1
View File
@@ -31,8 +31,9 @@
## Changelog
**v1.1.4**
**v1.1.4 2024/4/10)**
- Added `easy ipadapterStyleComposition`
- Added the right-click menu to view checkpoints and lora information in all Loaders
- Fixed `easy preSamplingNoiseIn`、`easy latentNoisy`、`east Unsampler` compatible with ComfyUI Revision>=2098 [0542088e] or later
+2 -1
View File
@@ -35,8 +35,9 @@
## 更新日志
**v1.1.4 (2024/4/7)**
**v1.1.4 2024/4/10)**
- 增加 `easy ipadapterStyleComposition`
- 增加 在Loaders上右键菜单可查看 checkpoints、lora 信息
- 修复 `easy preSamplingNoiseIn`、`easy latentNoisy`、`east Unsampler` 以兼容ComfyUI Revision>=2098 [0542088e] 以上版本
+113 -40
View File
@@ -22,13 +22,13 @@ from .wildcards import process_with_loras, get_wildcard_list, process
from .adv_encode import advanced_encode
from .layer_diffuse.func import LayerDiffuse, LayerMethod
from .libs.utils import find_wildcards_seed, is_linked_styles_selector, easySave, get_local_filepath, add_folder_path_and_extensions
from .libs.utils import find_wildcards_seed, is_linked_styles_selector, easySave, get_local_filepath, add_folder_path_and_extensions, AlwaysEqualProxy
from .libs.loader import easyLoader
from .libs.sampler import easySampler
from .libs.xyplot import easyXYPlot
from .libs.controlnet import easyControlnet
from .libs.conditioning import prompt_to_cond, set_cond
from .libs.cache import cache, update_cache
from .libs import cache as backend_cache
from .libs.easing import EasingBase
sampler = easySampler()
@@ -280,20 +280,23 @@ class promptLine:
@classmethod
def INPUT_TYPES(s):
return {"required": {"prompt": ("STRING", {"multiline": True, "default": "text"}),
"start_index": ("INT", {"default": 0, "min": 0, "max": 9999}),
"max_rows": ("INT", {"default": 1000, "min": 1, "max": 9999}),
}
}
return {"required": {
"prompt": ("STRING", {"multiline": True, "default": "text"}),
"start_index": ("INT", {"default": 0, "min": 0, "max": 9999}),
"max_rows": ("INT", {"default": 1000, "min": 1, "max": 9999}),
},
"hidden":{
"workflow_prompt": "PROMPT", "my_unique_id": "UNIQUE_ID"
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("STRING",)
OUTPUT_IS_LIST = (True,)
RETURN_TYPES = ("STRING", AlwaysEqualProxy('*'))
RETURN_NAMES = ("STRING", "COMBO")
OUTPUT_IS_LIST = (True, True)
FUNCTION = "generate_strings"
CATEGORY = "EasyUse/Prompt"
def generate_strings(self, prompt, start_index, max_rows):
def generate_strings(self, prompt, start_index, max_rows, workflow_prompt=None, my_unique_id=None):
lines = prompt.split('\n')
start_index = max(0, min(start_index, len(lines) - 1))
@@ -302,7 +305,8 @@ class promptLine:
rows = lines[start_index:end_index]
return (rows,)
return (rows, rows)
class promptConcat:
@classmethod
@@ -2041,8 +2045,7 @@ class ipadapter:
'FACEID PLUS V2',
'FACEID PORTRAIT (style transfer)'
]
self.weight_types = ["linear", "ease in", "ease out", 'ease in-out', 'reverse in-out', 'weak input', 'weak output',
'weak middle', 'strong middle', 'style transfer (SDXL)']
self.weight_types = ["linear", "ease in", "ease out", 'ease in-out', 'reverse in-out', 'weak input', 'weak output', 'weak middle', 'strong middle', 'style transfer', 'composition']
self.presets = self.normal_presets + self.faceid_presets
@@ -2061,8 +2064,8 @@ class ipadapter:
clipvision_name = clipvision_files[0] if len(clipvision_files)>0 else None
clipvision_file = folder_paths.get_full_path("clip_vision", clipvision_name) if clipvision_name else None
if clipvision_name is not None:
log_node_info(node_name, f"Using {clipvision_name}")
# if clipvision_name is not None:
# log_node_info(node_name, f"Using {clipvision_name}")
return clipvision_file, clipvision_name
@@ -2145,8 +2148,8 @@ class ipadapter:
ipadapter_files = [e for e in ipadapter_list if re.search(pattern, e, re.IGNORECASE)]
ipadapter_name = ipadapter_files[0] if len(ipadapter_files)>0 else None
ipadapter_file = folder_paths.get_full_path("ipadapter", ipadapter_name) if ipadapter_name else None
if ipadapter_name is not None:
log_node_info(node_name, f"Using {ipadapter_name}")
# if ipadapter_name is not None:
# log_node_info(node_name, f"Using {ipadapter_name}")
return ipadapter_file, ipadapter_name, is_insightface, lora_pattern
@@ -2196,12 +2199,14 @@ class ipadapter:
raise Exception("ClipVision model not found.")
if clipvision_file == pipeline['clipvision']['file']:
clip_vision = pipeline['clipvision']['model']
elif cache_mode in ["all", "clip_vision only"] and clipvision_name in cache:
log_node_info("easy ipadapterApply", f"Using ClipModel {clipvision_name} Cached")
clip_vision = cache[clipvision_name][1]
elif cache_mode in ["all", "clip_vision only"] and clipvision_name in backend_cache.cache:
log_node_info("easy ipadapterApply", f"Using ClipVisonModel {clipvision_name} Cached")
_, clip_vision = backend_cache.cache[clipvision_name][1]
else:
clip_vision = load_clip_vision(clipvision_file)
update_cache(clipvision_name, (False, clip_vision))
log_node_info("easy ipadapterApply", f"Using ClipVisonModel {clipvision_name}")
if cache_mode in ["all", "clip_vision only"]:
backend_cache.update_cache(clipvision_name, 'clip_vision', (False, clip_vision))
pipeline['clipvision']['file'] = clipvision_file
pipeline['clipvision']['model'] = clip_vision
@@ -2210,9 +2215,21 @@ class ipadapter:
ipadapter_file, ipadapter_name, is_insightface, lora_pattern = self.get_ipadapter_file(preset, is_sdxl, node_name)
model_type = 'sdxl' if is_sdxl else 'sd15'
if ipadapter_file is None:
ipadapter_file = get_local_filepath(IPADAPTER_MODELS[preset][model_type]["model_url"], IPADAPTER_DIR)
ipadapter = self.ipadapter_model_loader(ipadapter_file)
pipeline['ipadapter']['file'] = ipadapter_file
model_url = IPADAPTER_MODELS[preset][model_type]["model_url"]
ipadapter_file = get_local_filepath(model_url, IPADAPTER_DIR)
ipadapter_name = os.path.basename(model_url)
if ipadapter_file == pipeline['ipadapter']['file']:
ipadapter = pipeline['ipadapter']['model']
elif cache_mode in ["all", "ipadapter only"] and ipadapter_name in backend_cache.cache:
log_node_info("easy ipadapterApply", f"Using IpAdapterModel {ipadapter_name} Cached")
_, ipadapter = backend_cache.cache[ipadapter_name][1]
else:
ipadapter = self.ipadapter_model_loader(ipadapter_file)
pipeline['ipadapter']['file'] = ipadapter_file
log_node_info("easy ipadapterApply", f"Using IpAdapterModel {ipadapter_name}")
if cache_mode in ["all", "ipadapter only"]:
backend_cache.update_cache(ipadapter_name, 'ipadapter', (False, ipadapter))
pipeline['ipadapter']['model'] = ipadapter
# 3. Load the lora model if needed
@@ -2225,12 +2242,13 @@ class ipadapter:
icache_key = 'insightface-' + provider
if provider == pipeline['insightface']['provider']:
insightface = pipeline['insightface']['model']
elif icache_key in cache:
elif cache_mode in ["all", "insightface only"] and icache_key in backend_cache.cache:
log_node_info("easy ipadapterApply", f"Using InsightFaceModel {icache_key} Cached")
insightface = cache[icache_key][1]
_, insightface = backend_cache.cache[icache_key][1]
else:
insightface = insightface_loader(provider)
update_cache(icache_key, (False, insightface))
if cache_mode in ["all", "insightface only"]:
backend_cache.update_cache(icache_key, 'insightface',(False, insightface))
pipeline['insightface']['provider'] = provider
pipeline['insightface']['model'] = insightface
@@ -2255,7 +2273,7 @@ class ipadapterApply(ipadapter):
"weight_faceidv2": ("FLOAT", { "default": 1.0, "min": -1, "max": 5.0, "step": 0.05 }),
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"cache_mode": (["insightface only", "clip_vision only", "all", "none"], {"default": "insightface only"},),
"cache_mode": (["insightface only", "clip_vision only", "ipadapter only", "all", "none"], {"default": "insightface only"},),
"use_tiled": ("BOOLEAN", {"default": False},),
},
@@ -2316,7 +2334,7 @@ class ipadapterApplyAdvanced(ipadapter):
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"embeds_scaling": (['V only', 'K+V', 'K+V w/ C penalty', 'K+mean(V) w/ C penalty'],),
"cache_mode": (["insightface only", "clip_vision only", "all", "none"], {"default": "insightface only"},),
"cache_mode": (["insightface only", "clip_vision only","ipadapter only", "all", "none"], {"default": "insightface only"},),
"use_tiled": ("BOOLEAN", {"default": False},),
"use_batch": ("BOOLEAN", {"default": False},),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
@@ -2335,9 +2353,10 @@ class ipadapterApplyAdvanced(ipadapter):
CATEGORY = "EasyUse/Adapter"
FUNCTION = "apply"
def apply(self, model, image, preset, lora_strength, provider, weight, weight_faceidv2, weight_type, combine_embeds, start_at, end_at, embeds_scaling, cache_mode, use_tiled, use_batch, sharpening, image_negative=None, clip_vision=None, attn_mask=None, optional_ipadapter=None):
def apply(self, model, image, preset, lora_strength, provider, weight, weight_faceidv2, weight_type, combine_embeds, start_at, end_at, embeds_scaling, cache_mode, use_tiled, use_batch, sharpening, weight_style=1.0, weight_composition=1.0, image_style=None, image_composition=None, expand_style=False, image_negative=None, clip_vision=None, attn_mask=None, optional_ipadapter=None):
tiles, masks = image, [None]
model, ipadapter = self.load_model(model, preset, lora_strength, provider, clip_vision=clip_vision, optional_ipadapter=optional_ipadapter, cache_mode=cache_mode)
if use_tiled:
if use_batch:
if "IPAdapterTiledBatch" not in ALL_NODE_CLASS_MAPPINGS:
@@ -2347,7 +2366,7 @@ class ipadapterApplyAdvanced(ipadapter):
if "IPAdapterTiled" not in ALL_NODE_CLASS_MAPPINGS:
self.error()
cls = ALL_NODE_CLASS_MAPPINGS["IPAdapterTiled"]
model, tiles, masks = cls().apply_tiled(model, ipadapter, image, weight, weight_type, start_at, end_at, sharpening=sharpening, combine_embeds=combine_embeds, image_negative=image_negative, attn_mask=attn_mask, clip_vision=clip_vision, embeds_scaling=embeds_scaling)
model, tiles, masks = cls().apply_tiled(model, ipadapter, weight, weight_type, start_at, end_at, sharpening=sharpening, combine_embeds=combine_embeds, image_negative=image_negative, attn_mask=attn_mask, clip_vision=clip_vision, embeds_scaling=embeds_scaling)
else:
if use_batch:
if "IPAdapterBatch" not in ALL_NODE_CLASS_MAPPINGS:
@@ -2357,9 +2376,61 @@ class ipadapterApplyAdvanced(ipadapter):
if "IPAdapterAdvanced" not in ALL_NODE_CLASS_MAPPINGS:
self.error()
cls = ALL_NODE_CLASS_MAPPINGS["IPAdapterAdvanced"]
model, = cls().apply_ipadapter(model, ipadapter, weight=weight, weight_type=weight_type, start_at=start_at, end_at=end_at, combine_embeds=combine_embeds, weight_faceidv2=weight_faceidv2, image=image, image_negative=image_negative, clip_vision=clip_vision, attn_mask=attn_mask, insightface=None, embeds_scaling=embeds_scaling)
model, = cls().apply_ipadapter(model, ipadapter, weight=weight, weight_type=weight_type, start_at=start_at, end_at=end_at, combine_embeds=combine_embeds, weight_faceidv2=weight_faceidv2, image=image, image_negative=image_negative, weight_style=1.0, weight_composition=1.0, image_style=image_style, image_composition=image_composition, expand_style=expand_style, clip_vision=clip_vision, attn_mask=attn_mask, insightface=None, embeds_scaling=embeds_scaling)
return (model, tiles, masks, ipadapter)
class ipadapterStyleComposition(ipadapter):
def __init__(self):
super().__init__()
pass
@classmethod
def INPUT_TYPES(cls):
ipa_cls = cls()
normal_presets = ipa_cls.normal_presets
weight_types = ipa_cls.weight_types
return {
"required": {
"model": ("MODEL",),
"image_style": ("IMAGE",),
"preset": (normal_presets,),
"weight_style": ("FLOAT", {"default": 1.0, "min": -1, "max": 5, "step": 0.05}),
"weight_composition": ("FLOAT", {"default": 1.0, "min": -1, "max": 5, "step": 0.05}),
"expand_style": ("BOOLEAN", {"default": False}),
"combine_embeds": (["concat", "add", "subtract", "average", "norm average"], {"default": "average"}),
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
"embeds_scaling": (['V only', 'K+V', 'K+V w/ C penalty', 'K+mean(V) w/ C penalty'],),
"cache_mode": (["insightface only", "clip_vision only", "ipadapter only", "all", "none"],
{"default": "insightface only"},),
},
"optional": {
"image_composition": ("IMAGE",),
"image_negative": ("IMAGE",),
"attn_mask": ("MASK",),
"clip_vision": ("CLIP_VISION",),
"optional_ipadapter": ("IPADAPTER",),
}
}
CATEGORY = "EasyUse/Adapter"
RETURN_TYPES = ("MODEL", "IPADAPTER",)
RETURN_NAMES = ("model", "ipadapter",)
CATEGORY = "EasyUse/Adapter"
FUNCTION = "apply"
def apply(self, model, preset, weight_style, weight_composition, expand_style, combine_embeds, start_at, end_at, embeds_scaling, cache_mode, image_style=None , image_composition=None, image_negative=None, clip_vision=None, attn_mask=None, optional_ipadapter=None):
model, ipadapter = self.load_model(model, preset, 0, 'CPU', clip_vision=None, optional_ipadapter=optional_ipadapter, cache_mode=cache_mode)
if "IPAdapterAdvanced" not in ALL_NODE_CLASS_MAPPINGS:
self.error()
cls = ALL_NODE_CLASS_MAPPINGS["IPAdapterAdvanced"]
model, = cls().apply_ipadapter(model, ipadapter, start_at=start_at, end_at=end_at, weight_style=weight_style, weight_composition=weight_composition, weight_type='linear', combine_embeds=combine_embeds, weight_faceidv2=weight_composition, image_style=image_style, image_composition=image_composition, image_negative=image_negative, expand_style=expand_style, clip_vision=clip_vision, attn_mask=attn_mask, insightface=None, embeds_scaling=embeds_scaling)
return (model, ipadapter)
class ipadapterApplyEncoder(ipadapter):
def __init__(self):
super().__init__()
@@ -2501,23 +2572,23 @@ class instantID:
model = pipe['model']
# Load InstantID
cache_key = 'instantID'
if cache_key in cache:
if cache_key in backend_cache.cache:
log_node_info("easy instantIDApply","Using InstantIDModel Cached")
instantid_model = cache[cache_key][1]
_, instantid_model = backend_cache.cache[cache_key][1]
if "InstantIDModelLoader" in ALL_NODE_CLASS_MAPPINGS:
load_instant_cls = ALL_NODE_CLASS_MAPPINGS["InstantIDModelLoader"]
instantid_model, = load_instant_cls().load_model(instantid_file)
update_cache(cache_key, (False, instantid_model))
backend_cache.update_cache(cache_key, 'instantid', (False, instantid_model))
else:
self.error()
icache_key = 'insightface-' + insightface
if icache_key in cache:
if icache_key in backend_cache.cache:
log_node_info("easy instantIDApply", f"Using InsightFaceModel {insightface} Cached")
insightface_model = cache[icache_key][1]
_, insightface_model = backend_cache.cache[icache_key][1]
elif "InstantIDFaceAnalysis" in ALL_NODE_CLASS_MAPPINGS:
load_insightface_cls = ALL_NODE_CLASS_MAPPINGS["InstantIDFaceAnalysis"]
insightface_model, = load_insightface_cls().load_insight_face(insightface)
update_cache(icache_key, (False, insightface_model))
backend_cache.update_cache(icache_key, 'insightface', (False, insightface_model))
else:
self.error()
@@ -6417,6 +6488,7 @@ NODE_CLASS_MAPPINGS = {
"easy ipadapterApplyADV": ipadapterApplyAdvanced,
"easy ipadapterApplyEncoder": ipadapterApplyEncoder,
"easy ipadapterApplyEmbeds": ipadapterApplyEmbeds,
"easy ipadapterStyleComposition": ipadapterStyleComposition,
"easy instantIDApply": instantIDApply,
"easy instantIDApplyADV": instantIDApplyAdvanced,
# Inpaint 内补
@@ -6511,6 +6583,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
# Adapter 适配器
"easy ipadapterApply": "Easy Apply IPAdapter",
"easy ipadapterApplyADV": "Easy Apply IPAdapter (Advanced)",
"easy ipadapterStyleComposition": "Easy Apply IPAdapter (StyleComposition)",
"easy ipadapterApplyEncoder": "Easy Apply IPAdapter (Encoder)",
"easy ipadapterApplyEmbeds": "Easy Apply IPAdapter (Embeds)",
"easy instantIDApply": "Easy Apply InstantID",
+79 -5
View File
@@ -1,12 +1,86 @@
cache = {}
import itertools
from typing import Optional
class TaggedCache:
def __init__(self, tag_settings: Optional[dict]=None):
self._tag_settings = tag_settings or {} # tag cache size
self._data = {}
def __getitem__(self, key):
for tag_data in self._data.values():
if key in tag_data:
return tag_data[key]
raise KeyError(f'Key `{key}` does not exist')
def __setitem__(self, key, value: tuple):
# value: (tag: str, (islist: bool, data: *))
# if key already exists, pop old value
for tag_data in self._data.values():
if key in tag_data:
tag_data.pop(key, None)
break
tag = value[0]
if tag not in self._data:
try:
from cachetools import LRUCache
default_size = 20
if 'ckpt' in tag:
default_size = 5
elif tag in ['latent', 'image']:
default_size = 100
self._data[tag] = LRUCache(maxsize=self._tag_settings.get(tag, default_size))
except (ImportError, ModuleNotFoundError):
# TODO: implement a simple lru dict
self._data[tag] = {}
self._data[tag][key] = value
def __delitem__(self, key):
for tag_data in self._data.values():
if key in tag_data:
del tag_data[key]
return
raise KeyError(f'Key `{key}` does not exist')
def __contains__(self, key):
return any(key in tag_data for tag_data in self._data.values())
def items(self):
yield from itertools.chain(*map(lambda x :x.items(), self._data.values()))
def get(self, key, default=None):
"""D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."""
for tag_data in self._data.values():
if key in tag_data:
return tag_data[key]
return default
def clear(self):
# clear all cache
self._data = {}
cache_settings = {}
cache = TaggedCache(cache_settings)
cache_count = {}
def update_cache(k, v):
cache[k] = v
def update_cache(k, tag, v):
cache[k] = (tag, v)
cnt = cache_count.get(k)
if cnt is None:
cnt = 0
cache_count[k] = cnt
else:
cache_count[k] += 1
cache_count[k] += 1
def remove_cache(key):
global cache
if key == '*':
cache = TaggedCache(cache_settings)
elif key in cache:
del cache[key]
else:
print(f"invalid {key}")
+7
View File
@@ -1,3 +1,10 @@
class AlwaysEqualProxy(str):
def __eq__(self, _):
return True
def __ne__(self, _):
return False
comfy_ui_revision = None
def get_comfyui_revision():
try:
+46 -7
View File
@@ -1,6 +1,7 @@
from typing import Iterator, List, Tuple, Dict, Any, Union, Optional
from _decimal import Context, getcontext
from decimal import Decimal
from .libs.utils import AlwaysEqualProxy
import torch
import numpy as np
import json
@@ -287,12 +288,6 @@ COMPARE_FUNCTIONS = {
"a <= b": lambda a, b: a <= b,
"a >= b": lambda a, b: a >= b,
}
class AlwaysEqualProxy(str):
def __eq__(self, _):
return True
def __ne__(self, _):
return False
# 比较
class Compare:
@@ -517,6 +512,46 @@ class cleanGPUUsed:
return ()
from .libs.cache import remove_cache
class cleanCacheKey:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"anything": (AlwaysEqualProxy("*"), {}),
"cache_key": ("STRING", {"default": "*"}),
}, "optional": {},
"hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO",}
}
RETURN_TYPES = ()
RETURN_NAMES = ()
OUTPUT_NODE = True
FUNCTION = "empty_cache"
CATEGORY = "EasyUse/Logic"
def empty_cache(self, anything, cache_name, unique_id=None, extra_pnginfo=None):
remove_cache(cache_name)
return ()
class cleanCacheAll:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"anything": (AlwaysEqualProxy("*"), {}),
}, "optional": {},
"hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO",}
}
RETURN_TYPES = ()
RETURN_NAMES = ()
OUTPUT_NODE = True
FUNCTION = "empty_cache"
CATEGORY = "EasyUse/Logic"
def empty_cache(self, anything, unique_id=None, extra_pnginfo=None):
remove_cache('*')
return ()
NODE_CLASS_MAPPINGS = {
"easy string": String,
"easy int": Int,
@@ -532,7 +567,9 @@ NODE_CLASS_MAPPINGS = {
"easy convertAnything": ConvertAnything,
"easy showAnything": showAnything,
"easy showTensorShape": showTensorShape,
"easy cleanGpuUsed": cleanGPUUsed
"easy cleanCacheKey": cleanCacheKey,
"easy cleanCacheAll": cleanCacheAll,
"easy cleanGpuUsed": cleanGPUUsed,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"easy string": "String",
@@ -549,5 +586,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"easy convertAnything": "Convert Any",
"easy showAnything": "Show Any",
"easy showTensorShape": "Show Tensor Shape",
"easy cleanCacheKey": "Clean Cache Key",
"easy cleanCacheAll": "Clean Cache All",
"easy cleanGpuUsed": "Clean GPU Used"
}
+1
View File
@@ -24,6 +24,7 @@ const zhCN = {
"Saving Preview...": "正在保存预览图...",
"Saving Succeed":"保存成功",
"Saving Failed":"保存失败",
"No COMBO link": "沒有找到COMBO连接",
// GroupMap
"Groups Map (EasyUse)": "管理组 (EasyUse)",
"Always": "启用中",
+32
View File
@@ -1,6 +1,8 @@
import { app } from "/scripts/app.js";
import { api } from "/scripts/api.js";
import { ComfyWidgets } from "/scripts/widgets.js";
import { toast} from "../common/toast.js";
import { $t } from '../common/i18n.js';
let origProps = {};
@@ -1028,6 +1030,36 @@ app.registerExtension({
}
}
if (nodeData.name == 'easy promptLine') {
const onAdded = nodeType.prototype.onAdded;
nodeType.prototype.onAdded = async function () {
onAdded ? onAdded.apply(this, []) : undefined;
let prompt_widget = this.widgets.find(w => w.name == "prompt")
const button = this.addWidget("button", "get values from COMBO link", '', () => {
const output_link = this.outputs[1]?.links?.length>0 ? this.outputs[1]['links'][0] : null
const all_nodes = app.graph._nodes
const node = all_nodes.find(cate=> cate.inputs?.find(input=> input.link == output_link))
if(!output_link || !node){
toast.error($t('No COMBO link'), 3000)
return
}
else{
const input = node.inputs.find(input=> input.link == output_link)
const widget_name = input.widget.name
const widgets = node.widgets
const widget = widgets.find(cate=> cate.name == widget_name)
let values = widget?.options.values || null
if(values){
values = values.join('\n')
prompt_widget.value = values
}
}
}, {
serialize: false
})
}
}
}
});
+2 -1
View File
@@ -6,7 +6,7 @@ const loaders = ['easy fullLoader', 'easy a1111Loader', 'easy comfyLoader']
const preSampling = ['easy preSampling', 'easy preSamplingAdvanced', 'easy preSamplingDynamicCFG', 'easy preSamplingNoiseIn', 'easy preSamplingLayerDiffusion', 'easy fullkSampler']
const kSampler = ['easy kSampler', 'easy kSamplerTiled', 'easy kSamplerInpainting', 'easy kSamplerDownscaleUnet', 'easy kSamplerLayerDiffusion']
const controlnet = ['easy controlnetLoader', 'easy controlnetLoaderADV', 'easy instantIDApply', 'easy instantIDApplyADV']
const ipadapter = ['easy ipadapterApply', 'easy ipadapterApplyADV']
const ipadapter = ['easy ipadapterApply', 'easy ipadapterApplyADV', 'easy ipadapterStyleComposition']
const positive_prompt = ['easy positive', 'easy wildcards']
const widgetMapping = {
"positive_prompt":{
@@ -90,6 +90,7 @@ const inputMapping = {
"ipadapter":{
"model":"model",
"image":"image",
"image_style": "image",
"attn_mask":"attn_mask",
"optional_ipadapter":"optional_ipadapter"
}
+1 -1
View File
@@ -8,7 +8,7 @@ const preSamplingNodes = ["easy preSampling", "easy preSamplingAdvanced", "easy
const kSampler = ["easy kSampler", "easy kSamplerTiled","easy kSamplerInpainting", "easy kSamplerDownscaleUnet", "easy kSamplerSDTurbo"]
const controlNetNodes = ["easy controlnetLoader", "easy controlnetLoaderADV"]
const instantIDNodes = ["easy instantIDApply", "easy instantIDApplyADV"]
const ipadapterNodes = ["easy ipadapterApply", "easy ipadapterApplyADV"]
const ipadapterNodes = ["easy ipadapterApply", "easy ipadapterApplyADV" , "easy ipadapterStyleComposition"]
const pipeNodes = ['easy pipeIn','easy pipeOut', 'easy pipeEdit']
const xyNodes = ['easy XYPlot', 'easy XYPlotAdvanced']
const extraNodes = ['easy setNode']