Upgrade to v1.1.6
This commit is contained in:
+39
-14
@@ -33,6 +33,17 @@
|
||||
-
|
||||
## Changelog
|
||||
|
||||
**v1.1.6 (2024/4/26)**
|
||||
|
||||
- Added `easy styleAlignedBatchAlign` - Credit of [style_aligned_comfy](https://github.com/brianfitzgerald/style_aligned_comfy)
|
||||
- Added `easy ckptNames`
|
||||
- Added `easy controlnetNames`
|
||||
- Added `easy imagesSplitimage` - Batch images split into single images
|
||||
- Added `easy imageCount` - Get Image Count
|
||||
- Added `easy textSwitch` - Text Switch
|
||||
- `easy kSampler` & `easy fullkSampler` added **Preview&Choose** to **image_output** widget
|
||||
|
||||
|
||||
**v1.1.5 (2024/4/24)**
|
||||
|
||||
- Rewrite `easy cleanGPUUsed` - the memory usage of the comfyUI can to be cleared
|
||||
@@ -60,7 +71,7 @@
|
||||
- Added `easy promptConcat`
|
||||
- `easy wildcards` Added **multiline_mode**
|
||||
|
||||
**v1.1.2 (39c5ccf)**
|
||||
**v1.1.2**
|
||||
|
||||
- Optimized some of the recommended nodes for slots related to EasyUse
|
||||
- Added **Enable ContextMenu Auto Nest Subdirectories** The setting item is enabled by default, and it can be classified into subdirectories, checkpoints and loras previews
|
||||
@@ -76,7 +87,7 @@
|
||||
- Fixed layerDiffuse xyplot bug
|
||||
- `easy kSamplerInpainting` add *additional* widget,you can choose 'Differential Diffusion' or 'Only InpaintModelConditioning'
|
||||
|
||||
**v1.1.1 (2024/3/16)**
|
||||
**v1.1.1**
|
||||
|
||||
- The issue that the seed is 0 when a node with a seed control is added and **control before generate** is fixed for the first time run queue prompt.
|
||||
- `easy preSamplingAdvanced` Added **return_with_leftover_noise**
|
||||
@@ -86,7 +97,7 @@
|
||||
- Remove forced **control_before_generate** settings。 If you want to use control_before_generate, change widget_value_control_mode to before in system settings
|
||||
- Added `easy imageRemBg` - The default is BriaAI's RMBG-1.4 model, which removes the background effect more and faster
|
||||
|
||||
**v1.1.0 (d5ff84e)**
|
||||
**v1.1.0**
|
||||
|
||||
- Added `easy imageSplitList` - to split every N images
|
||||
- Added `easy preSamplingDiffusionADDTL` - It can modify foreground、background or blended additional prompt
|
||||
@@ -102,15 +113,18 @@
|
||||
- Fixed `easy instantIDApply` mask not input right
|
||||
|
||||
|
||||
**v1.0.9 (ff1add1)**
|
||||
<details>
|
||||
<summary><b>v1.0.9</b></summary>
|
||||
|
||||
- Fixed the error when ComfyUI-Impack-Pack and ComfyUI_InstantID were not installed
|
||||
- Fixed `easy pipeIn`
|
||||
- Added `easy instantIDApply` - you need installed [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID) fisrt, Workflow[Example](https://github.com/yolain/ComfyUI-Easy-Use/blob/main/README.en.md#InstantID)
|
||||
- Fixed `easy detailerFix` not added to the list of nodes available for saving images formatting extensions
|
||||
- Fixed `easy XYInputs: PromptSR` errors are reported when replacing negative prompts
|
||||
</details>
|
||||
|
||||
**v1.0.8 (f28cbf7)**
|
||||
<details>
|
||||
<summary><b>v1.0.8</b></summary>
|
||||
|
||||
- `easy cascadeLoader` stage_c and stage_b support the checkpoint model (Download [checkpoints](https://huggingface.co/stabilityai/stable-cascade/tree/main/comfyui_checkpoints) models)
|
||||
- `easy styleSelector` The search box is modified to be case-insensitive
|
||||
@@ -120,8 +134,10 @@
|
||||
- Fixed the error of SDXLClipModel in ComfyUI revision 2016[c2cb8e88] and above (the revision number was judged to be compatible with the old revision)
|
||||
- Fixed `easy detailerFix` generation error when batch size is greater than 1
|
||||
- Optimize the code, reduce a lot of redundant code and improve the running speed
|
||||
</details>
|
||||
|
||||
**v1.0.7 (2024-02-19)**
|
||||
<details>
|
||||
<summary><b>v1.0.7</b></summary>
|
||||
|
||||
- Added `easy cascadeLoader` - stable cascade Loader
|
||||
- Added `easy preSamplingCascade` - stable cascade preSampling Settings
|
||||
@@ -129,22 +145,28 @@
|
||||
- Added `easy cascadeKSampler` - stable cascade stage-c ksampler simple
|
||||
-
|
||||
- Optimize the image to image[Example](https://github.com/yolain/ComfyUI-Easy-Use/blob/main/README.en.md#image-to-image)
|
||||
</details>
|
||||
|
||||
**v1.0.6**
|
||||
<details>
|
||||
<summary><b>v1.0.6</b></summary>
|
||||
|
||||
- Added `easy XYInputs: Checkpoint`
|
||||
- Added `easy XYInputs: Lora`
|
||||
- `easy seed` can manually switch the random seed when increasing the fixed seed value
|
||||
- Fixed `easy fullLoader` and all loaders to automatically adjust the node size when switching LoRa
|
||||
- Removed the original ttn image saving logic and adapted to the default image saving format extension of ComfyUI
|
||||
</details>
|
||||
|
||||
- **v1.0.5**
|
||||
<details>
|
||||
<summary><b>v1.0.5</b></summary>
|
||||
|
||||
- Added `easy isSDXL`
|
||||
- Added prompt word control on `easy svdLoader`, which can be used with open_clip model
|
||||
- Added **populated_text** on `easy wildcards`, wildcard populated text can be output
|
||||
</details>
|
||||
|
||||
**v1.0.4**
|
||||
<details>
|
||||
<summary><b>v1.0.4</b></summary>
|
||||
|
||||
- `easy showAnything` added support for converting other types (e.g., tensor conditions, images, etc.)
|
||||
- Added `easy showLoaderSettingsNames` can display the model and VAE name in the output loader assembly
|
||||
@@ -164,9 +186,10 @@
|
||||
- Changing the first-time install node package no longer automatically replaces the theme, you need to manually adjust and refresh the page
|
||||
- `easy imageSave` added **only_preivew**
|
||||
- Adjust the `easy latentCompositeMaskedWithCond` node
|
||||
</details>
|
||||
|
||||
|
||||
**v1.0.3**
|
||||
<details>
|
||||
<summary><b>v1.0.3</b></summary>
|
||||
|
||||
- Added `easy stylesSelector`
|
||||
- Added **scale_soft_weights** in `easy controlnetLoader` and `easy controlnetLoaderADV`
|
||||
@@ -184,9 +207,10 @@
|
||||
|
||||
- Adjust the UI theme, divided into two sets of styles: the official default background and the dark black background, which can be switched in the color palette in the settings
|
||||
- Modify the styles path to be compatible with other environments
|
||||
</details>
|
||||
|
||||
|
||||
**v1.0.2**
|
||||
<details>
|
||||
<summary><b>v1.0.2</b></summary>
|
||||
|
||||
- Added `easy XYPlotAdvanced` and some nodes about `easy XYInputs`
|
||||
- Added **Alt+1-Alt+9** Shortcut keys to quickly paste node presets for Node templates (corresponding to 1~9 sequences)
|
||||
@@ -203,7 +227,7 @@
|
||||
- Removed `easy imageRemBg`
|
||||
- Remove the introductory diagram and workflow files from the package to reduce the package size
|
||||
- Replaced the font file used in the generation of XY diagrams
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.1</b></summary>
|
||||
@@ -298,6 +322,7 @@ Disclaimer: Opened source was not easy. I have a lot of respect for the contribu
|
||||
| easy preSamplingLayerDiffusion | [ComfyUI-layerdiffusion](https://github.com/huchenlei/ComfyUI-layerdiffusion) | LayeredDiffusionApply... |
|
||||
| easy dynamiCrafterLoader | [ComfyUI-layerdiffusion](https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter) | Apply Dynamicrafter |
|
||||
| easy imageChooser | [cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) | Preview Chooser |
|
||||
| easy styleAlignedBatchAlign | [style_aligned_comfy](https://github.com/chrisgoringe/cg-image-picker) | styleAlignedBatchAlign |
|
||||
|
||||
## Workflow Examples
|
||||
|
||||
|
||||
@@ -37,7 +37,17 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
**v1.1.5 (2024/4/24)**
|
||||
**v1.1.6 (2024/4/26)**
|
||||
|
||||
- 增加 `easy styleAlignedBatchAlign` - 风格对齐 [style_aligned_comfy](https://github.com/brianfitzgerald/style_aligned_comfy)
|
||||
- 增加 `easy ckptNames`
|
||||
- 增加 `easy controlnetNames`
|
||||
- 增加 `easy imagesSplitimage` - 批次图像拆分单张
|
||||
- 增加 `easy imageCount` - 图像数量
|
||||
- 增加 `easy textSwitch` - 文字切换
|
||||
- `easy kSampler` 和 `easy fullkSampler` 的 **image_output** 增加 **Preview&Choose**选项
|
||||
|
||||
**v1.1.5**
|
||||
|
||||
- 重写 `easy cleanGPUUsed` - 可强制清理comfyUI的模型显存占用
|
||||
- 增加 `easy humanSegmentation` - 多类分割、人像分割
|
||||
@@ -47,7 +57,7 @@
|
||||
- 增加 `easy imageInterrogator` - 图像反推
|
||||
- 增加 `easy stableDiffusion3API` - 简易的Stable Diffusion 3 多账号API节点
|
||||
|
||||
**v1.1.4 (2024/4/13)**
|
||||
**v1.1.4**
|
||||
|
||||
- 增加 `easy imageChooser` - 从[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker)简化的图片选择器
|
||||
- 增加 `easy preSamplingCustom` - 自定义预采样,可支持cosXL-edit
|
||||
@@ -56,7 +66,7 @@
|
||||
- 修复 `easy preSamplingNoiseIn`、`easy latentNoisy`、`east Unsampler` 以兼容ComfyUI Revision>=2098 [0542088e] 以上版本
|
||||
- 修复 FooocusInpaint修改ModelPatcher计算权重引发的问题,理应在生成model后重置ModelPatcher为默认值
|
||||
|
||||
**v1.1.3 (2024/4/4)**
|
||||
**v1.1.3**
|
||||
|
||||
- `easy ipadapterApply` 增加 **COMPOSITION** 预置项
|
||||
- 增加 对[ResAdapter](https://huggingface.co/jiaxiangc/res-adapter) lora模型 的加载支持
|
||||
@@ -66,7 +76,7 @@
|
||||
- `easy wildcards` 增加 **multiline_mode**属性
|
||||
- 增加 当节点需要下载模型时,若huggingface连接超时,会切换至镜像地址下载模型
|
||||
|
||||
**v1.1.2 (39c5ccf)**
|
||||
**v1.1.2**
|
||||
|
||||
- 改写 EasyUse 相关节点的部分插槽推荐节点
|
||||
- 增加 **启用上下文菜单自动嵌套子目录** 设置项,默认为启用状态,可分类子目录及checkpoints、loras预览图
|
||||
@@ -82,7 +92,7 @@
|
||||
- 修复 `easy pipeEdit` 提示词输入lora时报错
|
||||
- 修复 layerDiffuse xyplot相关bug
|
||||
|
||||
**v1.1.1 (5c8af8f)**
|
||||
**v1.1.1**
|
||||
|
||||
- 修复首次添加含seed的节点且当前模式为control_before_generate时,seed为0的问题
|
||||
- `easy preSamplingAdvanced` 增加 **return_with_leftover_noise**
|
||||
@@ -93,7 +103,7 @@
|
||||
- 去除强制**control_before_generate**设定
|
||||
- 增加 `easy imageRemBg` - 默认为BriaAI的RMBG-1.4模型, 移除背景效果更加,速度更快
|
||||
|
||||
**v1.1.0 (d5ff84e)**
|
||||
**v1.1.0**
|
||||
|
||||
- 增加 `easy imageSplitList` - 拆分每 N 张图像
|
||||
- 增加 `easy preSamplingDiffusionADDTL` - 可配置前景、背景、blended的additional_prompt等
|
||||
@@ -107,15 +117,18 @@
|
||||
- 修复 `easy instantIDApply` mask 未传入正确值
|
||||
- 修复 在 非a1111提示词风格下 BREAK 不生效的问题
|
||||
|
||||
**v1.0.9 (ff1add1)**
|
||||
<details>
|
||||
<summary><b>v1.0.9</b></summary>
|
||||
|
||||
- 修复未安装 ComfyUI-Impack-Pack 和 ComfyUI_InstantID 时报错
|
||||
- 修复 `easy pipeIn` - pipe设为可不必选
|
||||
- 增加 `easy instantIDApply` - 需要先安装 [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID), 工作流参考[示例](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#InstantID)
|
||||
- 修复 `easy detailerFix` 未添加到保存图片格式化扩展名可用节点列表
|
||||
- 修复 `easy XYInputs: PromptSR` 在替换负面提示词时报错
|
||||
</details>
|
||||
|
||||
**v1.0.8 (f28cbf7)**
|
||||
<details>
|
||||
<summary><b>v1.0.8</b></summary>
|
||||
|
||||
- `easy cascadeLoader` stage_c 与 stage_b 支持checkpoint模型 (需要下载[checkpoints](https://huggingface.co/stabilityai/stable-cascade/tree/main/comfyui_checkpoints))
|
||||
- `easy styleSelector` 搜索框修改为不区分大小写匹配
|
||||
@@ -129,13 +142,16 @@
|
||||
|
||||
(翻译对照已由 [AIGODLIKE-COMFYUI-TRANSLATION](https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation) 统一维护啦!
|
||||
首次下载或者版本较早的朋友请更新 AIGODLIKE-COMFYUI-TRANSLATION 和本节点包至最新版本。)
|
||||
</details>
|
||||
|
||||
**v1.0.7**
|
||||
<details>
|
||||
<summary><b>v1.0.7</b></summary>
|
||||
|
||||
- 增加 `easy cascadeLoader` - stable cascade 加载器
|
||||
- 增加 `easy preSamplingCascade` - stabled cascade stage_c 预采样参数
|
||||
- 增加 `easy fullCascadeKSampler` - stable cascade stage_c 完整版采样器
|
||||
- 增加 `easy cascadeKSampler` - stable cascade stage-c ksampler simple
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.6</b></summary>
|
||||
@@ -310,6 +326,7 @@
|
||||
| easy preSamplingLayerDiffusion | [ComfyUI-layerdiffusion](https://github.com/huchenlei/ComfyUI-layerdiffusion) | LayeredDiffusionApply等 |
|
||||
| easy dynamiCrafterLoader | [ComfyUI-layerdiffusion](https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter) | Apply Dynamicrafter |
|
||||
| easy imageChooser | [cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) | Preview Chooser |
|
||||
| easy styleAlignedBatchAlign | [style_aligned_comfy](https://github.com/chrisgoringe/cg-image-picker) | styleAlignedBatchAlign |
|
||||
|
||||
## 示例
|
||||
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
__version__ = "1.1.6"
|
||||
|
||||
import os
|
||||
import glob
|
||||
import folder_paths
|
||||
@@ -85,4 +87,4 @@ WEB_DIRECTORY = "./web"
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', "WEB_DIRECTORY"]
|
||||
|
||||
|
||||
print('\033[34mComfy-Easy-Use (v1.1.5): \033[92mLoaded\033[0m')
|
||||
print(f'\033[34mComfy-Easy-Use v{__version__}: \033[92mLoaded\033[0m')
|
||||
+92
-5
@@ -22,7 +22,7 @@ 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, AlwaysEqualProxy
|
||||
from .libs.utils import find_wildcards_seed, is_linked_styles_selector, easySave, get_local_filepath, add_folder_path_and_extensions, AlwaysEqualProxy, get_sd_version
|
||||
from .libs.loader import easyLoader
|
||||
from .libs.sampler import easySampler
|
||||
from .libs.xyplot import easyXYPlot
|
||||
@@ -819,6 +819,39 @@ class globalSeed:
|
||||
|
||||
#---------------------------------------------------------------加载器 开始----------------------------------------------------------------------#
|
||||
|
||||
class setCkptName:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required": {
|
||||
"ckpt_name": (folder_paths.get_filename_list("checkpoints"),),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy('*'),)
|
||||
RETURN_NAMES = ("ckpt_name",)
|
||||
FUNCTION = "set_name"
|
||||
CATEGORY = "EasyUse/Utils"
|
||||
|
||||
def set_name(self, ckpt_name):
|
||||
return (ckpt_name,)
|
||||
|
||||
class setControlName:
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required": {
|
||||
"controlnet_name": (folder_paths.get_filename_list("controlnet"),),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy('*'),)
|
||||
RETURN_NAMES = ("controlnet_name",)
|
||||
FUNCTION = "set_name"
|
||||
CATEGORY = "EasyUse/Utils"
|
||||
|
||||
def set_name(self, controlnet_name):
|
||||
return (controlnet_name,)
|
||||
|
||||
# 简易加载器完整
|
||||
class fullLoader:
|
||||
|
||||
@@ -2084,6 +2117,27 @@ class fooocusInpaintLoader:
|
||||
return ((inpaint_head_model, inpaint_lora),)
|
||||
|
||||
#---------------------------------------------------------------适配器 开始----------------------------------------------------------------------#
|
||||
from .libs.styleAlign import styleAlignBatch, SHARE_NORM_OPTIONS, SHARE_ATTN_OPTIONS
|
||||
class styleAlignedBatchAlign:
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"model": ("MODEL",),
|
||||
"share_norm": (SHARE_NORM_OPTIONS,),
|
||||
"share_attn": (SHARE_ATTN_OPTIONS,),
|
||||
"scale": ("FLOAT", {"default": 1, "min": 0, "max": 1.0, "step": 0.1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MODEL",)
|
||||
FUNCTION = "align"
|
||||
CATEGORY = "EasyUse/Adapter"
|
||||
|
||||
def align(self, model, share_norm, share_attn, scale):
|
||||
return (styleAlignBatch(model, share_norm, share_attn, scale),)
|
||||
|
||||
def insightface_loader(provider):
|
||||
try:
|
||||
from insightface.app import FaceAnalysis
|
||||
@@ -3236,7 +3290,7 @@ class samplerCustomSettings:
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"cfg_negative": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS + ['inversed_euler'],),
|
||||
"scheduler": (comfy.samplers.KSampler.SCHEDULERS + ['karrasADV','exponentialADV','polyExponential','sdturbo','vp'],),
|
||||
"scheduler": (comfy.samplers.KSampler.SCHEDULERS + ['karrasADV','exponentialADV','polyExponential', 'sdturbo', 'vp'],),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"sigma_max": ("FLOAT", {"default": 14.614642, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}),
|
||||
"sigma_min": ("FLOAT", {"default": 0.0291675, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}),
|
||||
@@ -3327,6 +3381,7 @@ class samplerCustomSettings:
|
||||
return (ksampler,)
|
||||
|
||||
def settings(self, pipe, guider, cfg, cfg_negative, sampler_name, scheduler, steps, sigma_max, sigma_min, rho, beta_d, beta_min, eps_s, flip_sigmas, denoise, add_noise, seed, image_to_latent=None, latent=None, optional_sampler=None, optional_sigmas=None, prompt=None, extra_pnginfo=None, my_unique_id=None):
|
||||
|
||||
# 图生图转换
|
||||
vae = pipe["vae"]
|
||||
model = pipe["model"]
|
||||
@@ -3334,6 +3389,7 @@ class samplerCustomSettings:
|
||||
negative = pipe['negative']
|
||||
batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1
|
||||
_guider, sigmas = None, None
|
||||
print(get_sd_version(model))
|
||||
if image_to_latent is not None:
|
||||
if guider == "IP2P+DualCFG":
|
||||
positive, negative, latent = self.ip2p(pipe['positive'], pipe['negative'], vae, image_to_latent)
|
||||
@@ -3384,6 +3440,8 @@ class samplerCustomSettings:
|
||||
sigmas, = PolyexponentialScheduler().get_sigmas(steps, sigma_max, sigma_min, rho)
|
||||
elif scheduler == 'sdturbo':
|
||||
sigmas, = SDTurboScheduler().get_sigmas(model, steps, denoise)
|
||||
elif scheduler == 'alignYourSteps':
|
||||
pass
|
||||
else:
|
||||
sigmas, = BasicScheduler().get_sigmas(model, scheduler, steps, denoise)
|
||||
|
||||
@@ -3937,6 +3995,7 @@ class dynamicThresholdingFull:
|
||||
#---------------------------------------------------------------采样器 开始----------------------------------------------------------------------
|
||||
|
||||
# 完整采样器
|
||||
from .libs.chooser import ChooserMessage, ChooserCancelled
|
||||
class samplerFull(LayerDiffuse):
|
||||
|
||||
def __init__(self):
|
||||
@@ -3951,7 +4010,7 @@ class samplerFull(LayerDiffuse):
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
||||
"scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
|
||||
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"image_output": (["Hide", "Preview", "Save", "Hide/Save", "Sender", "Sender/Save"],),
|
||||
"image_output": (["Hide", "Preview", "Preview&Choose", "Save", "Hide/Save", "Sender", "Sender/Save"],),
|
||||
"link_id": ("INT", {"default": 0, "min": 0, "max": sys.maxsize, "step": 1}),
|
||||
"save_prefix": ("STRING", {"default": "ComfyUI"}),
|
||||
},
|
||||
@@ -4121,6 +4180,26 @@ class samplerFull(LayerDiffuse):
|
||||
|
||||
del pipe
|
||||
|
||||
if image_output == 'Preview&Choose':
|
||||
if my_unique_id not in ChooserMessage.stash:
|
||||
ChooserMessage.stash[my_unique_id] = {}
|
||||
my_stash = ChooserMessage.stash[my_unique_id]
|
||||
|
||||
PromptServer.instance.send_sync("easyuse-image-choose", {"id": my_unique_id, "urls": results})
|
||||
# wait for selection
|
||||
try:
|
||||
selections = ChooserMessage.waitForMessage(my_unique_id, asList=True)
|
||||
new_images = [new_images[x] for x in selections if x >= 0] if len(selections) > 1 else [0]
|
||||
samp_images = [samp_images[x] for x in selections if x >= 0] if len(selections) > 1 else [0]
|
||||
except ChooserCancelled:
|
||||
raise comfy.model_management.InterruptProcessingException()
|
||||
|
||||
new_pipe['images'] = new_images
|
||||
new_pipe['samp_images'] = samp_images
|
||||
|
||||
return {"ui": {"images": results},
|
||||
"result": sampler.get_output(new_pipe,)}
|
||||
|
||||
if image_output in ("Hide", "Hide/Save"):
|
||||
return {"ui": {},
|
||||
"result": sampler.get_output(new_pipe,)}
|
||||
@@ -4272,7 +4351,7 @@ class samplerSimple:
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required":
|
||||
{"pipe": ("PIPE_LINE",),
|
||||
"image_output": (["Hide", "Preview", "Save", "Hide/Save", "Sender", "Sender/Save"],{"default": "Preview"}),
|
||||
"image_output": (["Hide", "Preview", "Preview&Choose", "Save", "Hide/Save", "Sender", "Sender/Save"],{"default": "Preview"}),
|
||||
"link_id": ("INT", {"default": 0, "min": 0, "max": sys.maxsize, "step": 1}),
|
||||
"save_prefix": ("STRING", {"default": "ComfyUI"}),
|
||||
},
|
||||
@@ -6946,6 +7025,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy ipadapterStyleComposition": ipadapterStyleComposition,
|
||||
"easy instantIDApply": instantIDApply,
|
||||
"easy instantIDApplyADV": instantIDApplyAdvanced,
|
||||
"easy styleAlignedBatchAlign": styleAlignedBatchAlign,
|
||||
# Inpaint 内补
|
||||
"easy fooocusInpaintLoader": fooocusInpaintLoader,
|
||||
# latent 潜空间
|
||||
@@ -7009,6 +7089,9 @@ NODE_CLASS_MAPPINGS = {
|
||||
"dynamicThresholdingFull": dynamicThresholdingFull,
|
||||
# api 相关
|
||||
"easy stableDiffusion3API": stableDiffusion3API,
|
||||
# utils
|
||||
"easy ckptNames": setCkptName,
|
||||
"easy controlnetNames": setControlName,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -7048,6 +7131,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy ipadapterApplyFromParams": "Easy Apply IPAdapter (From Params)",
|
||||
"easy instantIDApply": "Easy Apply InstantID",
|
||||
"easy instantIDApplyADV": "Easy Apply InstantID (Advanced)",
|
||||
"easy styleAlignedBatchAlign": "Easy Apply StyleAlign",
|
||||
# Inpaint 内补
|
||||
"easy fooocusInpaintLoader": "Load Fooocus Inpaint",
|
||||
# latent 潜空间
|
||||
@@ -7111,4 +7195,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"dynamicThresholdingFull": "DynamicThresholdingFull",
|
||||
# api 相关
|
||||
"easy stableDiffusion3API": "Stable Diffusion 3 (API)",
|
||||
}
|
||||
# utils
|
||||
"easy ckptNames": "Ckpt Names",
|
||||
"easy controlnetNames": "ControlNet Names",
|
||||
}
|
||||
+43
-2
@@ -15,6 +15,25 @@ from .libs.chooser import ChooserMessage, ChooserCancelled
|
||||
from .config import REMBG_DIR, REMBG_MODELS, HUMANPARSING_MODELS, MEDIAPIPE_MODELS, MEDIAPIPE_DIR
|
||||
|
||||
|
||||
# 图像数量
|
||||
class imageCount:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = "EasyUse/Image"
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
RETURN_NAMES = ("count",)
|
||||
FUNCTION = "get_count"
|
||||
|
||||
def get_count(self, images):
|
||||
return (images.size(0),)
|
||||
|
||||
# 图像裁切
|
||||
class imageInsetCrop:
|
||||
|
||||
@@ -519,6 +538,24 @@ class imageSplitList:
|
||||
new_images[1].append(img)
|
||||
return new_images
|
||||
|
||||
class imagesSplitImage:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "IMAGE", "IMAGE")
|
||||
RETURN_NAMES = ("image1", "image2", "image3", "image4", "image5")
|
||||
FUNCTION = "split"
|
||||
CATEGORY = "EasyUse/Image"
|
||||
|
||||
def split(self, images,):
|
||||
new_images = torch.chunk(images, len(images), dim=0)
|
||||
return new_images
|
||||
|
||||
# 图片背景移除
|
||||
from .briaai.rembg import BriaRMBG, preprocess_image, postprocess_image
|
||||
from .libs.utils import get_local_filepath, easySave, install_package
|
||||
@@ -901,7 +938,7 @@ class loadImageBase64:
|
||||
RETURN_TYPES = ("IMAGE", "MASK")
|
||||
OUTPUT_NODE = True
|
||||
FUNCTION = "load_image"
|
||||
CATEGORY = "image"
|
||||
CATEGORY = "EasyUse/Image/LoadImage"
|
||||
|
||||
def convert_color(self, image,):
|
||||
if len(image.shape) > 2 and image.shape[2] >= 4:
|
||||
@@ -1005,6 +1042,7 @@ class poseEditor:
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"easy imageInsetCrop": imageInsetCrop,
|
||||
"easy imageCount": imageCount,
|
||||
"easy imageSize": imageSize,
|
||||
"easy imageSizeBySide": imageSizeBySide,
|
||||
"easy imageSizeByLongerSide": imageSizeByLongerSide,
|
||||
@@ -1015,6 +1053,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy imageRatio": imageRatio,
|
||||
"easy imageToMask": imageToMask,
|
||||
"easy imageSplitList": imageSplitList,
|
||||
"easy imagesSplitImage": imagesSplitImage,
|
||||
"easy imageSave": imageSaveSimple,
|
||||
"easy imageRemBg": imageRemBg,
|
||||
"easy imageChooser": imageChooser,
|
||||
@@ -1029,6 +1068,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy imageInsetCrop": "ImageInsetCrop",
|
||||
"easy imageCount": "ImageCount",
|
||||
"easy imageSize": "ImageSize",
|
||||
"easy imageSizeBySide": "ImageSize (Side)",
|
||||
"easy imageSizeByLongerSide": "ImageSize (LongerSide)",
|
||||
@@ -1040,13 +1080,14 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy imageToMask": "ImageToMask",
|
||||
"easy imageHSVMask": "ImageHSVMask",
|
||||
"easy imageSplitList": "imageSplitList",
|
||||
"easy imagesSplitImage": "imagesSplitImage",
|
||||
"easy imageSave": "SaveImage (Simple)",
|
||||
"easy imageRemBg": "Image Remove Bg",
|
||||
"easy imageChooser": "Image Chooser",
|
||||
"easy imageColorMatch": "Image Color Match",
|
||||
"easy imageInterrogator": "Image To Prompt",
|
||||
"easy joinImageBatch": "JoinImageBatch",
|
||||
"easy loadImageBase64": "LoadImage (Base64)",
|
||||
"easy loadImageBase64": "Load Image (Base64)",
|
||||
"easy imageToBase64": "Image To Base64",
|
||||
"easy humanSegmentation": "Human Segmentation",
|
||||
"easy poseEditor": "PoseEditor",
|
||||
|
||||
+14
-15
@@ -111,27 +111,26 @@ class CI_Inference:
|
||||
|
||||
def image_to_prompt(self, image, mode, model_name='ViT-L-14/openai', low_vram=False):
|
||||
try:
|
||||
install_package("clip_interrogator", "0.6.0")
|
||||
from clip_interrogator import Config, Interrogator
|
||||
global Config, Interrogator
|
||||
except:
|
||||
install_package("clip_interrogator", "0.6.0")
|
||||
from clip_interrogator import Config, Interrogator
|
||||
|
||||
pbar = comfy.utils.ProgressBar(len(image))
|
||||
pbar = comfy.utils.ProgressBar(len(image))
|
||||
|
||||
self._load_model(model_name, low_vram)
|
||||
prompt = []
|
||||
for i in range(len(image)):
|
||||
im = image[i]
|
||||
self._load_model(model_name, low_vram)
|
||||
prompt = []
|
||||
for i in range(len(image)):
|
||||
im = image[i]
|
||||
|
||||
im = tensor2pil(im)
|
||||
im = im.convert('RGB')
|
||||
im = tensor2pil(im)
|
||||
im = im.convert('RGB')
|
||||
|
||||
_prompt = self._interrogate(im, mode)
|
||||
pbar.update(1)
|
||||
prompt.append(_prompt)
|
||||
_prompt = self._interrogate(im, mode)
|
||||
pbar.update(1)
|
||||
prompt.append(_prompt)
|
||||
|
||||
return prompt
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return [""]
|
||||
return prompt
|
||||
|
||||
ci = CI_Inference()
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from comfy.model_patcher import ModelPatcher
|
||||
from typing import Union
|
||||
|
||||
T = torch.Tensor
|
||||
|
||||
|
||||
def exists(val):
|
||||
return val is not None
|
||||
|
||||
|
||||
def default(val, d):
|
||||
if exists(val):
|
||||
return val
|
||||
return d
|
||||
|
||||
|
||||
class StyleAlignedArgs:
|
||||
def __init__(self, share_attn: str) -> None:
|
||||
self.adain_keys = "k" in share_attn
|
||||
self.adain_values = "v" in share_attn
|
||||
self.adain_queries = "q" in share_attn
|
||||
|
||||
share_attention: bool = True
|
||||
adain_queries: bool = True
|
||||
adain_keys: bool = True
|
||||
adain_values: bool = True
|
||||
|
||||
|
||||
def expand_first(
|
||||
feat: T,
|
||||
scale=1.0,
|
||||
) -> T:
|
||||
"""
|
||||
Expand the first element so it has the same shape as the rest of the batch.
|
||||
"""
|
||||
b = feat.shape[0]
|
||||
feat_style = torch.stack((feat[0], feat[b // 2])).unsqueeze(1)
|
||||
if scale == 1:
|
||||
feat_style = feat_style.expand(2, b // 2, *feat.shape[1:])
|
||||
else:
|
||||
feat_style = feat_style.repeat(1, b // 2, 1, 1, 1)
|
||||
feat_style = torch.cat([feat_style[:, :1], scale * feat_style[:, 1:]], dim=1)
|
||||
return feat_style.reshape(*feat.shape)
|
||||
|
||||
|
||||
def concat_first(feat: T, dim=2, scale=1.0) -> T:
|
||||
"""
|
||||
concat the the feature and the style feature expanded above
|
||||
"""
|
||||
feat_style = expand_first(feat, scale=scale)
|
||||
return torch.cat((feat, feat_style), dim=dim)
|
||||
|
||||
|
||||
def calc_mean_std(feat, eps: float = 1e-5) -> "tuple[T, T]":
|
||||
feat_std = (feat.var(dim=-2, keepdims=True) + eps).sqrt()
|
||||
feat_mean = feat.mean(dim=-2, keepdims=True)
|
||||
return feat_mean, feat_std
|
||||
|
||||
def adain(feat: T) -> T:
|
||||
feat_mean, feat_std = calc_mean_std(feat)
|
||||
feat_style_mean = expand_first(feat_mean)
|
||||
feat_style_std = expand_first(feat_std)
|
||||
feat = (feat - feat_mean) / feat_std
|
||||
feat = feat * feat_style_std + feat_style_mean
|
||||
return feat
|
||||
|
||||
class SharedAttentionProcessor:
|
||||
def __init__(self, args: StyleAlignedArgs, scale: float):
|
||||
self.args = args
|
||||
self.scale = scale
|
||||
|
||||
def __call__(self, q, k, v, extra_options):
|
||||
if self.args.adain_queries:
|
||||
q = adain(q)
|
||||
if self.args.adain_keys:
|
||||
k = adain(k)
|
||||
if self.args.adain_values:
|
||||
v = adain(v)
|
||||
if self.args.share_attention:
|
||||
k = concat_first(k, -2, scale=self.scale)
|
||||
v = concat_first(v, -2)
|
||||
|
||||
return q, k, v
|
||||
|
||||
|
||||
def get_norm_layers(
|
||||
layer: nn.Module,
|
||||
norm_layers_: "dict[str, list[Union[nn.GroupNorm, nn.LayerNorm]]]",
|
||||
share_layer_norm: bool,
|
||||
share_group_norm: bool,
|
||||
):
|
||||
if isinstance(layer, nn.LayerNorm) and share_layer_norm:
|
||||
norm_layers_["layer"].append(layer)
|
||||
if isinstance(layer, nn.GroupNorm) and share_group_norm:
|
||||
norm_layers_["group"].append(layer)
|
||||
else:
|
||||
for child_layer in layer.children():
|
||||
get_norm_layers(
|
||||
child_layer, norm_layers_, share_layer_norm, share_group_norm
|
||||
)
|
||||
|
||||
|
||||
def register_norm_forward(
|
||||
norm_layer: Union[nn.GroupNorm, nn.LayerNorm],
|
||||
) -> Union[nn.GroupNorm, nn.LayerNorm]:
|
||||
if not hasattr(norm_layer, "orig_forward"):
|
||||
setattr(norm_layer, "orig_forward", norm_layer.forward)
|
||||
orig_forward = norm_layer.orig_forward
|
||||
|
||||
def forward_(hidden_states: T) -> T:
|
||||
n = hidden_states.shape[-2]
|
||||
hidden_states = concat_first(hidden_states, dim=-2)
|
||||
hidden_states = orig_forward(hidden_states) # type: ignore
|
||||
return hidden_states[..., :n, :]
|
||||
|
||||
norm_layer.forward = forward_ # type: ignore
|
||||
return norm_layer
|
||||
|
||||
|
||||
def register_shared_norm(
|
||||
model: ModelPatcher,
|
||||
share_group_norm: bool = True,
|
||||
share_layer_norm: bool = True,
|
||||
):
|
||||
norm_layers = {"group": [], "layer": []}
|
||||
get_norm_layers(model.model, norm_layers, share_layer_norm, share_group_norm)
|
||||
print(
|
||||
f"Patching {len(norm_layers['group'])} group norms, {len(norm_layers['layer'])} layer norms."
|
||||
)
|
||||
return [register_norm_forward(layer) for layer in norm_layers["group"]] + [
|
||||
register_norm_forward(layer) for layer in norm_layers["layer"]
|
||||
]
|
||||
|
||||
|
||||
SHARE_NORM_OPTIONS = ["both", "group", "layer", "disabled"]
|
||||
SHARE_ATTN_OPTIONS = ["q+k", "q+k+v", "disabled"]
|
||||
|
||||
|
||||
def styleAlignBatch(model, share_norm, share_attn, scale=1.0):
|
||||
m = model.clone()
|
||||
share_group_norm = share_norm in ["group", "both"]
|
||||
share_layer_norm = share_norm in ["layer", "both"]
|
||||
register_shared_norm(model, share_group_norm, share_layer_norm)
|
||||
args = StyleAlignedArgs(share_attn)
|
||||
m.set_model_attn1_patch(SharedAttentionProcessor(args, scale))
|
||||
return m
|
||||
+6
-1
@@ -98,12 +98,17 @@ import comfy.supported_models_base
|
||||
def get_sd_version(model):
|
||||
base: BaseModel = model.model
|
||||
model_config: comfy.supported_models.supported_models_base.BASE = base.model_config
|
||||
print(model_config)
|
||||
if isinstance(model_config, comfy.supported_models.SDXL):
|
||||
return 'sdxl'
|
||||
elif isinstance(
|
||||
model_config, (comfy.supported_models.SD15, comfy.supported_models.SD20)
|
||||
):
|
||||
return 'sd15'
|
||||
elif isinstance(
|
||||
model_config, (comfy.supported_models.SVD_img2vid)
|
||||
):
|
||||
return 'svd'
|
||||
else:
|
||||
return 'unknown'
|
||||
|
||||
@@ -231,7 +236,7 @@ def easySave(images, filename_prefix, output_type, prompt=None, extra_pnginfo=No
|
||||
from nodes import PreviewImage, SaveImage
|
||||
if output_type == "Hide":
|
||||
return list()
|
||||
if output_type == "Preview":
|
||||
if output_type in ["Preview", "Preview&Choose"]:
|
||||
filename_prefix = 'easyPreview'
|
||||
results = PreviewImage().save_images(images, filename_prefix, prompt, extra_pnginfo)
|
||||
return results['ui']['images']
|
||||
|
||||
+29
@@ -277,6 +277,30 @@ class imageSwitch:
|
||||
else:
|
||||
return (image_b, )
|
||||
|
||||
class textSwitch:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"input": ("INT", {"default": 1, "min": 1, "max": 2}),
|
||||
},
|
||||
"optional": {
|
||||
"text1": ("STRING", {"forceInput": True}),
|
||||
"text2": ("STRING", {"forceInput": True}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("STRING",)
|
||||
CATEGORY = "EasyUse/Logic/Switch"
|
||||
FUNCTION = "switch"
|
||||
|
||||
def switch(self, input, text1=None, text2=None,):
|
||||
if input == 1:
|
||||
return (text1,)
|
||||
else:
|
||||
return (text2,)
|
||||
|
||||
# ---------------------------------------------------------------运算 开始----------------------------------------------------------------------#
|
||||
|
||||
COMPARE_FUNCTIONS = {
|
||||
@@ -549,6 +573,9 @@ class clearCacheAll:
|
||||
remove_cache('*')
|
||||
return ()
|
||||
|
||||
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"easy string": String,
|
||||
"easy int": Int,
|
||||
@@ -558,6 +585,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy boolean": Boolean,
|
||||
"easy compare": Compare,
|
||||
"easy imageSwitch": imageSwitch,
|
||||
"easy textSwitch": textSwitch,
|
||||
"easy if": If,
|
||||
"easy isSDXL": isSDXL,
|
||||
"easy xyAny": xyAny,
|
||||
@@ -577,6 +605,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy boolean": "Boolean",
|
||||
"easy compare": "Compare",
|
||||
"easy imageSwitch": "Image Switch",
|
||||
"easy textSwitch": "Text Switch",
|
||||
"easy if": "If",
|
||||
"easy isSDXL": "Is SDXL",
|
||||
"easy xyAny": "XYAny",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.easyuse-chooser-dialog{
|
||||
max-width: 600px;
|
||||
}
|
||||
.easyuse-chooser-dialog-title{
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color:var(--input-text);
|
||||
margin:0;
|
||||
}
|
||||
.easyuse-chooser-dialog-images{
|
||||
margin-top:10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.easyuse-chooser-dialog-images img{
|
||||
width: 50%;
|
||||
height: auto;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
filter:brightness(80%);
|
||||
}
|
||||
.easyuse-chooser-dialog-images img:hover{
|
||||
filter:brightness(100%);
|
||||
}
|
||||
.easyuse-chooser-dialog-images img.selected{
|
||||
border: 4px solid var(--success-color);
|
||||
}
|
||||
+2
-1
@@ -5,4 +5,5 @@
|
||||
@import "contextmenu.css";
|
||||
@import "modelinfo.css";
|
||||
@import "toast.css";
|
||||
@import "account.css";
|
||||
@import "account.css";
|
||||
@import "chooser.css";
|
||||
@@ -59,6 +59,9 @@ const zhCN = {
|
||||
"APIKEY is not Empty": "APIKEY 不能为空",
|
||||
"Add Account": "添加账号",
|
||||
"Getting Your APIKEY": "获取您的APIKEY",
|
||||
// choosers
|
||||
"Choose Selected Images": "选择选中的图片",
|
||||
"Choose images to continue": "选择图片以继续",
|
||||
// seg
|
||||
"Background": "背景",
|
||||
"Hat": "帽子",
|
||||
|
||||
@@ -56,7 +56,7 @@ function widgetLogic(node, widget) {
|
||||
}else {
|
||||
toggleWidget(node, findWidgetByName(node, 'link_id'))
|
||||
}
|
||||
if (widget.value === 'Hide' || widget.value === 'Preview' || widget.value == 'PreviewChooser' || widget.value === 'Sender') {
|
||||
if (widget.value === 'Hide' || widget.value === 'Preview' || widget.value == 'Preview&Choose' || widget.value === 'Sender') {
|
||||
toggleWidget(node, findWidgetByName(node, 'save_prefix'))
|
||||
toggleWidget(node, findWidgetByName(node, 'output_path'))
|
||||
toggleWidget(node, findWidgetByName(node, 'embed_workflow'))
|
||||
|
||||
@@ -273,11 +273,11 @@ const addMenu = (content, type, nodes_include, nodeType, has_submenu=true) => {
|
||||
has_submenu: has_submenu,
|
||||
callback: (value, options, e, menu, node) => showSwapMenu(value, options, e, menu, node, type, nodes_include)
|
||||
})
|
||||
if(type == 'loaders'){
|
||||
if(type == 'loaders') {
|
||||
options.unshift({
|
||||
content: $t("💎 View Lora Info..."),
|
||||
callback: (value, options, e, menu, node) => {
|
||||
const widget = node.widgets.find(cate=> cate.name == 'lora_name')
|
||||
const widget = node.widgets.find(cate => cate.name == 'lora_name')
|
||||
let name = widget.value;
|
||||
if (!name || name == 'None') return
|
||||
new LoraInfoDialog(name).show('loras', name);
|
||||
@@ -522,7 +522,19 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
})
|
||||
// ckptNames
|
||||
if(nodeData.name == 'easy ckptNames'){
|
||||
options.unshift({
|
||||
content: $t("💎 View Checkpoint Info..."),
|
||||
callback: (value, options, e, menu, node) => {
|
||||
let name = node.widgets[0].value;
|
||||
if (!name || name == 'None') return
|
||||
new CheckpointInfoDialog(name).show('checkpoints', name);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Swap提示词
|
||||
if (positive_prompt.includes(nodeData.name)) {
|
||||
addMenu("↪️ Swap EasyPrompt", 'positive_prompt', positive_prompt, nodeType)
|
||||
|
||||
@@ -747,6 +747,7 @@ const NODE_COLORS = {
|
||||
"easy promptReplace":"cyan",
|
||||
"easy XYInputs: Seeds++ Batch": customXYLink,
|
||||
"easy XYInputs: ModelMergeBlocks": customXYLink,
|
||||
'easy textSwitch': "pale_blue"
|
||||
}
|
||||
|
||||
function setNodeColors(node, theme) {
|
||||
|
||||
@@ -1,14 +1,70 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
import { api } from "/scripts/api.js";
|
||||
import { ComfyDialog, $el } from "/scripts/ui.js";
|
||||
|
||||
import { restart_from_here } from "./prompt.js";
|
||||
import { FlowState } from "./state.js";
|
||||
import { send_cancel, send_message, send_onstart, skip_next_restart_message } from "./messaging.js";
|
||||
import { display_preview_images, additionalDrawBackground, click_is_in_image } from "./preview.js";
|
||||
import {toggleWidget} from "../common/utils.js";
|
||||
import {$t} from "../common/i18n.js";
|
||||
|
||||
function progressButtonPressed() {
|
||||
const node = app.graph._nodes_by_id[this.node_id];
|
||||
|
||||
class chooserImageDialog extends ComfyDialog {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.node = null
|
||||
this.select_index = []
|
||||
this.dialog_div = null
|
||||
}
|
||||
|
||||
show(image,node){
|
||||
this.select_index = []
|
||||
this.node = node
|
||||
|
||||
const images_div = image.map((img, index) => {
|
||||
const imgEl = $el('img', {
|
||||
src: img.src,
|
||||
onclick: _ => {
|
||||
if(this.select_index.includes(index)){
|
||||
this.select_index = this.select_index.filter(i => i !== index)
|
||||
imgEl.classList.remove('selected')
|
||||
} else {
|
||||
this.select_index.push(index)
|
||||
imgEl.classList.add('selected')
|
||||
}
|
||||
if (node.selected.has(index)) node.selected.delete(index);
|
||||
else node.selected.add(index);
|
||||
}
|
||||
})
|
||||
return imgEl
|
||||
})
|
||||
super.show($el('div.easyuse-chooser-dialog',[
|
||||
$el('h5.easyuse-chooser-dialog-title', $t('Choose images to continue')),
|
||||
$el('div.easyuse-chooser-dialog-images',images_div)
|
||||
]))
|
||||
}
|
||||
createButtons() {
|
||||
const btns = super.createButtons();
|
||||
btns[0].onclick = _ => {
|
||||
cancelButtonPressed()
|
||||
super.close()
|
||||
}
|
||||
btns.unshift($el('button', {
|
||||
type: 'button',
|
||||
textContent: $t('Choose Selected Images'),
|
||||
onclick: _ => {
|
||||
progressButtonPressed(this.node)
|
||||
super.close()
|
||||
}
|
||||
}))
|
||||
return btns
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function progressButtonPressed(_node) {
|
||||
const node = _node ? _node : app.graph._nodes_by_id[this.node_id];
|
||||
if (node) {
|
||||
if (FlowState.paused()) {
|
||||
send_message(node.id, [...node.selected, -1, ...node.anti_selected]);
|
||||
@@ -29,7 +85,11 @@ app.registerExtension({
|
||||
},
|
||||
setup(app) {
|
||||
function easyuseImageChooser(event) {
|
||||
display_preview_images(event);
|
||||
const {node,image,isKSampler} = display_preview_images(event);
|
||||
if(isKSampler) {
|
||||
const dialog = new chooserImageDialog();
|
||||
dialog.show(image,node)
|
||||
}
|
||||
}
|
||||
api.addEventListener("easyuse-image-choose", easyuseImageChooser);
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
|
||||
const kSampler = ['easy kSampler', 'easy kSamplerTiled', 'easy fullkSampler']
|
||||
|
||||
function display_preview_images(event) {
|
||||
const node = app.graph._nodes_by_id[event.detail.id];
|
||||
if (node) {
|
||||
node.selected = new Set();
|
||||
node.anti_selected = new Set();
|
||||
showImages(node, event.detail.urls);
|
||||
const image = showImages(node, event.detail.urls);
|
||||
return {node,image,isKSampler:kSampler.includes(node.type)}
|
||||
} else {
|
||||
console.log(`Image Chooser Preview - failed to find ${event.detail.id}`)
|
||||
}
|
||||
@@ -20,6 +23,7 @@ function showImages(node, urls) {
|
||||
img.src = `/view?filename=${encodeURIComponent(u.filename)}&type=temp&subfolder=${app.getPreviewFormatParam()}`
|
||||
})
|
||||
node.setSizeForImage?.();
|
||||
return node.imgs
|
||||
}
|
||||
|
||||
function drawRect(node, s, ctx) {
|
||||
|
||||
Reference in New Issue
Block a user