Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02695fe0df | ||
|
|
9b5b2399e1 | ||
|
|
4167733d39 | ||
|
|
6964e11f3d | ||
|
|
e9439f0dc0 | ||
|
|
f1ee79a9ae | ||
|
|
d0118ca742 | ||
|
|
d31c9076c3 | ||
|
|
ac25ebad3c | ||
|
|
9b05d46ff2 | ||
|
|
e514bc1d8a | ||
|
|
ffb0bf5de9 | ||
|
|
1897c3acfd | ||
|
|
7b1dc8ce62 | ||
|
|
d7ee354fe4 | ||
|
|
d4a443607f | ||
|
|
df918829dd | ||
|
|
ba701d1d59 | ||
|
|
12002acd93 | ||
|
|
5d1721d0c3 | ||
|
|
0d4e1ede0f | ||
|
|
a808e30a23 | ||
|
|
913722813e | ||
|
|
49374e012e | ||
|
|
2b69b4f33a | ||
|
|
8ba8c214a3 | ||
|
|
a060322a88 | ||
|
|
52508f0f35 | ||
|
|
a6c4158af3 | ||
|
|
d4a8f0d415 | ||
|
|
a8ca28ebca | ||
|
|
4608de5cbf | ||
|
|
8c14ffdafe | ||
|
|
5ab388d690 | ||
|
|
a78ba7dd35 | ||
|
|
81d97ca81f | ||
|
|
51dcc04be4 | ||
|
|
9bf1e808b2 | ||
|
|
a0e195d1c1 | ||
|
|
6bce70780f | ||
|
|
c1a85e3aa2 | ||
|
|
763cff49e4 | ||
|
|
daaa44eddf | ||
|
|
7f25ce6cd2 | ||
|
|
5d68d617f9 | ||
|
|
400ffebb49 | ||
|
|
99e05344bf | ||
|
|
6a1b5b8d69 | ||
|
|
24ee3ffea5 | ||
|
|
500eae510d | ||
|
|
2e79ec2504 | ||
|
|
33c7e9513f | ||
|
|
ef64db05e3 | ||
|
|
f1ab83f429 | ||
|
|
9e85e3a25c | ||
|
|
6cab7a18e3 | ||
|
|
6d6004ce0d | ||
|
|
625b295a9c | ||
|
|
4145471d24 | ||
|
|
a5e12ff375 | ||
|
|
5f60119ab9 |
+1
-1
@@ -1,3 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: ["https://afdian.net/a/yolain"]
|
||||
custom: ["https://space.bilibili.com/1840885116"]
|
||||
@@ -8,6 +8,8 @@ styles/**
|
||||
workflow/**
|
||||
autocomplete/**
|
||||
web_beta/**
|
||||
web_version/dev/**
|
||||
ComfyUI-Easy-Use-Frontend/
|
||||
docs/**
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
+465
@@ -0,0 +1,465 @@
|
||||

|
||||
|
||||
<div align="center">
|
||||
<a href="https://space.bilibili.com/1840885116">视频介绍</a> |
|
||||
文档 (康明孙) |
|
||||
<a href="https://github.com/yolain/ComfyUI-Yolain-Workflows">工作流合集</a> |
|
||||
<a href="#%EF%B8%8F-donation">捐助</a>
|
||||
<br><br>
|
||||
<a href="./README.md"><img src="https://img.shields.io/badge/🇬🇧English-e9e9e9"></a>
|
||||
<a href="./README.ZH_CN.md"><img src="https://img.shields.io/badge/🇨🇳中文简体-0b8cf5"></a>
|
||||
</div>
|
||||
|
||||
**ComfyUI-Easy-Use** 是一个化繁为简的节点整合包, 在 [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) 的基础上进行延展,并针对了诸多主流的节点包做了整合与优化,以达到更快更方便使用ComfyUI的目的,在保证自由度的同时还原了本属于Stable Diffusion的极致畅快出图体验。
|
||||
|
||||
## 👨🏻🎨 特色介绍
|
||||
|
||||
- 沿用了 [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) 的思路,大大减少了折腾工作流的时间成本。
|
||||
- UI界面美化,首次安装的用户,如需使用UI主题,请在 Settings -> Color Palette 中自行切换主题并**刷新页面**即可
|
||||
- 增加了预采样参数配置的节点,可与采样节点分离,更方便预览。
|
||||
- 支持通配符与Lora的提示词节点,如需使用Lora Block Weight用法,需先保证自定义节点包中安装了 [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
||||
- 可多选的风格化提示词选择器,默认是Fooocus的样式json,可自定义json放在styles底下,samples文件夹里可放预览图(名称和name一致,图片文件名如有空格需转为下划线'_')
|
||||
- 加载器可开启A1111提示词风格模式,可重现与webui生成近乎相同的图像,需先安装 [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes)
|
||||
- 可使用`easy latentNoisy`或`easy preSamplingNoiseIn`节点实现对潜空间的噪声注入
|
||||
- 简化 SD1.x、SD2.x、SDXL、SVD、Zero123等流程
|
||||
- 简化 Stable Cascade [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#1-13-stable-cascade)
|
||||
- 简化 Layer Diffuse [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-3-layerdiffusion)
|
||||
- 简化 InstantID [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-2-instantid), 需先保证自定义节点包中安装了 [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID)
|
||||
- 简化 IPAdapter, 需先保证自定义节点包中安装最新版v2的 [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus)
|
||||
- 扩展 XYplot 的可用性
|
||||
- 整合了Fooocus Inpaint功能
|
||||
- 整合了常用的逻辑计算、转换类型、展示所有类型等
|
||||
- 支持节点上checkpoint、lora模型子目录分类及预览图 (请在设置中开启上下文菜单嵌套子目录)
|
||||
- 支持BriaAI的RMBG-1.4模型的背景去除节点,[技术参考](https://huggingface.co/briaai/RMBG-1.4)
|
||||
- 支持 强制清理comfyUI模型显存占用
|
||||
- 支持Stable Diffusion 3 多账号API节点
|
||||
- 支持IC-Light的应用 [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-5-ic-light) | [代码整合来源](https://github.com/huchenlei/ComfyUI-IC-Light) | [技术参考](https://github.com/lllyasviel/IC-Light)
|
||||
- 中文提示词自动识别,使用[opus-mt-zh-en模型](https://huggingface.co/Helsinki-NLP/opus-mt-zh-en)
|
||||
- 支持 sd3 模型
|
||||
- 支持 kolors 模型
|
||||
- 支持 flux 模型
|
||||
- 支持 惰性条件判断(ifElse)和 for循环
|
||||
|
||||
## 👨🏻🔧 安装
|
||||
|
||||
1. 将存储库克隆到 **custom_nodes** 目录并安装依赖
|
||||
```shell
|
||||
#1. git下载
|
||||
git clone https://github.com/yolain/ComfyUI-Easy-Use
|
||||
#2. 安装依赖
|
||||
双击install.bat安装依赖
|
||||
```
|
||||
|
||||
## 👨🏻🚀 计划
|
||||
|
||||
- [x] 更新便于维护的新前端代码
|
||||
- [x] 使用sass维护css样式
|
||||
- [x] 对原有扩展进行优化
|
||||
- [x] 增加新的组件(如节点时间统计等)
|
||||
- [ ] 在[ComfyUI-Yolain-Workflows](https://github.com/yolain/ComfyUI-Yolain-Workflows)中上传更多的工作流(如kolors,sd3等),并更新english版本的readme
|
||||
- [ ] 更详细功能介绍的 gitbook
|
||||
|
||||
## 📜 更新日志
|
||||
|
||||
**v1.2.2**
|
||||
|
||||
- 增加 `easy batchAny`
|
||||
- 增加 `easy anythingIndexSwitch`
|
||||
- 增加 `easy forLoopStart` 和 `easy forLoopEnd`
|
||||
- 增加 `easy ifElse`
|
||||
- 增加 v2 版本新前端代码
|
||||
- 增加 `easy fluxLoader`
|
||||
- 增加 `controlnetApply` 相关节点对sd3和hunyuanDiT的支持
|
||||
- 修复 当使用fooocus inpaint后,再使用Lora模型无法生效的问题
|
||||
|
||||
**v1.2.1**
|
||||
|
||||
- 增加 `easy ipadapterApplyFaceIDKolors`
|
||||
- `easy ipadapterApply` 和 `easy ipadapterApplyADV` 增加 **PLUS (kolors genernal)** 和 **FACEID PLUS KOLORS** 预置项
|
||||
- `easy imageRemBg` 增加 **inspyrenet** 选项
|
||||
- 增加 `easy controlnetLoader++`
|
||||
- 去除 `easy positive` `easy negative` 等prompt节点的自动将中文翻译功能,自动翻译仅在 `easy a1111Loader` 等不支持中文TE的加载器中生效
|
||||
- 增加 `easy kolorsLoader` - 可灵加载器,参考了 [MinusZoneAI](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ) 和 [kijai](https://github.com/kijai/ComfyUI-KwaiKolorsWrapper) 的代码。
|
||||
|
||||
**v1.2.0**
|
||||
|
||||
- 增加 `easy pulIDApply` 和 `easy pulIDApplyADV`
|
||||
- 增加 `easy hunyuanDiTLoader` 和 `easy pixArtLoader`
|
||||
- 当新菜单的位置在上或者下时增加上 crystools 的显示,推荐开两个就好(如果后续crystools有更新UI适配我可能会删除掉)
|
||||
- 增加 **easy sliderControl** - 滑块控制节点,当前可用于控制ipadapterMS的参数 (双击滑块可重置为默认值)
|
||||
- 增加 **layer_weights** 属性在 `easy ipadapterApplyADV` 节点
|
||||
|
||||
**v1.1.9**
|
||||
|
||||
- 增加 新的调度器 **gitsScheduler**
|
||||
- 增加 `easy imageBatchToImageList` 和 `easy imageListToImageBatch` (修复Impact版的一点小问题)
|
||||
- 递归模型子目录嵌套
|
||||
- 支持 sd3 模型
|
||||
- 增加 `easy applyInpaint` - 局部重绘全模式节点 (相比与之前的kSamplerInpating节点逻辑会更合理些)
|
||||
|
||||
**v1.1.8**
|
||||
|
||||
- 增加中文提示词自动翻译,使用[opus-mt-zh-en模型](https://huggingface.co/Helsinki-NLP/opus-mt-zh-en), 默认已对wildcard、lora正则处理, 其他需要保留的中文,可使用`@你的提示词@`包裹 (若依赖安装完成后报错, 请重启),测算大约会占0.3GB显存
|
||||
- 增加 `easy controlnetStack` - controlnet堆
|
||||
- 增加 `easy applyBrushNet` - [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4brushnet_1.1.8.json)
|
||||
- 增加 `easy applyPowerPaint` - [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4powerpaint_outpaint_1.1.8.json)
|
||||
|
||||
**v1.1.7**
|
||||
|
||||
- 修复 一些模型(如controlnet模型等)未成功写入缓存,导致修改前置节点束参数(如提示词)需要二次载入模型的问题
|
||||
- 增加 `easy prompt` - 主体和光影预置项,后期可能会调整
|
||||
- 增加 `easy icLightApply` - 重绘光影, 从[ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light)优化
|
||||
- 增加 `easy imageSplitGrid` - 图像网格拆分
|
||||
- `easy kSamplerInpainting` 的 **additional** 属性增加差异扩散和brushnet等相关选项
|
||||
- 增加 brushnet模型加载的支持 - [ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet)
|
||||
- 增加 `easy applyFooocusInpaint` - Fooocus内补节点 替代原有的 FooocusInpaintLoader
|
||||
- 移除 `easy fooocusInpaintLoader` - 容易bug,不再使用
|
||||
- 修改 easy kSampler等采样器中并联的model 不再替换输出中pipe里的model
|
||||
|
||||
**v1.1.6**
|
||||
|
||||
- 增加步调齐整适配 - 在所有的预采样和全采样器节点中的 调度器(schedulder) 增加了 **alignYourSteps** 选项
|
||||
- `easy kSampler` 和 `easy fullkSampler` 的 **image_output** 增加 **Preview&Choose**选项
|
||||
- 增加 `easy styleAlignedBatchAlign` - 风格对齐 [style_aligned_comfy](https://github.com/brianfitzgerald/style_aligned_comfy)
|
||||
- 增加 `easy ckptNames`
|
||||
- 增加 `easy controlnetNames`
|
||||
- 增加 `easy imagesSplitimage` - 批次图像拆分单张
|
||||
- 增加 `easy imageCount` - 图像数量
|
||||
- 增加 `easy textSwitch` - 文字切换
|
||||
|
||||
**v1.1.5**
|
||||
|
||||
- 重写 `easy cleanGPUUsed` - 可强制清理comfyUI的模型显存占用
|
||||
- 增加 `easy humanSegmentation` - 多类分割、人像分割
|
||||
- 增加 `easy imageColorMatch`
|
||||
- 增加 `easy ipadapterApplyRegional`
|
||||
- 增加 `easy ipadapterApplyFromParams`
|
||||
- 增加 `easy imageInterrogator` - 图像反推
|
||||
- 增加 `easy stableDiffusion3API` - 简易的Stable Diffusion 3 多账号API节点
|
||||
|
||||
**v1.1.4**
|
||||
|
||||
- 增加 `easy imageChooser` - 从[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker)简化的图片选择器
|
||||
- 增加 `easy preSamplingCustom` - 自定义预采样,可支持cosXL-edit
|
||||
- 增加 `easy ipadapterStyleComposition`
|
||||
- 增加 在Loaders上右键菜单可查看 checkpoints、lora 信息
|
||||
- 修复 `easy preSamplingNoiseIn`、`easy latentNoisy`、`east Unsampler` 以兼容ComfyUI Revision>=2098 [0542088e] 以上版本
|
||||
- 修复 FooocusInpaint修改ModelPatcher计算权重引发的问题,理应在生成model后重置ModelPatcher为默认值
|
||||
|
||||
**v1.1.3**
|
||||
|
||||
- `easy ipadapterApply` 增加 **COMPOSITION** 预置项
|
||||
- 增加 对[ResAdapter](https://huggingface.co/jiaxiangc/res-adapter) lora模型 的加载支持
|
||||
- 增加 `easy promptLine`
|
||||
- 增加 `easy promptReplace`
|
||||
- 增加 `easy promptConcat`
|
||||
- `easy wildcards` 增加 **multiline_mode**属性
|
||||
- 增加 当节点需要下载模型时,若huggingface连接超时,会切换至镜像地址下载模型
|
||||
|
||||
<details>
|
||||
<summary><b>v1.1.2</b></summary>
|
||||
|
||||
- 改写 EasyUse 相关节点的部分插槽推荐节点
|
||||
- 增加 **启用上下文菜单自动嵌套子目录** 设置项,默认为启用状态,可分类子目录及checkpoints、loras预览图
|
||||
- 增加 `easy sv3dLoader`
|
||||
- 增加 `easy dynamiCrafterLoader`
|
||||
- 增加 `easy ipadapterApply`
|
||||
- 增加 `easy ipadapterApplyADV`
|
||||
- 增加 `easy ipadapterApplyEncoder`
|
||||
- 增加 `easy ipadapterApplyEmbeds`
|
||||
- 增加 `easy preMaskDetailerFix`
|
||||
- `easy kSamplerInpainting` 增加 **additional** 属性,可设置成 Differential Diffusion 或 Only InpaintModelConditioning
|
||||
- 修复 `easy stylesSelector` 当未选择样式时,原有提示词发生了变化
|
||||
- 修复 `easy pipeEdit` 提示词输入lora时报错
|
||||
- 修复 layerDiffuse xyplot相关bug
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.1.1/b></summary>
|
||||
|
||||
- 修复首次添加含seed的节点且当前模式为control_before_generate时,seed为0的问题
|
||||
- `easy preSamplingAdvanced` 增加 **return_with_leftover_noise**
|
||||
- 修复 `easy stylesSelector` 当选择自定义样式文件时运行队列报错
|
||||
- `easy preSamplingLayerDiffusion` 增加 mask 可选传入参数
|
||||
- 将所有 **seed_num** 调整回 **seed**
|
||||
- 修补官方BUG: 当control_mode为before 在首次加载页面时未修改节点中widget名称为 control_before_generate
|
||||
- 去除强制**control_before_generate**设定
|
||||
- 增加 `easy imageRemBg` - 默认为BriaAI的RMBG-1.4模型, 移除背景效果更加,速度更快
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.1.0</b></summary>
|
||||
|
||||
- 增加 `easy imageSplitList` - 拆分每 N 张图像
|
||||
- 增加 `easy preSamplingDiffusionADDTL` - 可配置前景、背景、blended的additional_prompt等
|
||||
- 增加 `easy preSamplingNoiseIn` 可替代需要前置的`easy latentNoisy`节点 实现效果更好的噪声注入
|
||||
- `easy pipeEdit` 增加 条件拼接模式选择,可选择替换、合并、联结、平均、设置条件时间
|
||||
- 增加 `easy pipeEdit` - 可编辑Pipe的节点(包含可重新输入提示词)
|
||||
- 增加 `easy preSamplingLayerDiffusion` 与 `easy kSamplerLayerDiffusion` (连接 `easy kSampler` 也能通)
|
||||
- 增加 在 加载器、预采样、采样器、Controlnet等节点上右键可快速替换同类型节点的便捷菜单
|
||||
- 增加 `easy instantIDApplyADV` 可连入 positive 与 negative
|
||||
- 修复 `easy wildcards` 读取lora未填写完整路径时未自动检索导致加载lora失败的问题
|
||||
- 修复 `easy instantIDApply` mask 未传入正确值
|
||||
- 修复 在 非a1111提示词风格下 BREAK 不生效的问题
|
||||
</details>
|
||||
|
||||
<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-Yolain-Workflows?tab=readme-ov-file#2-2-instantid)
|
||||
- 修复 `easy detailerFix` 未添加到保存图片格式化扩展名可用节点列表
|
||||
- 修复 `easy XYInputs: PromptSR` 在替换负面提示词时报错
|
||||
</details>
|
||||
|
||||
<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` 搜索框修改为不区分大小写匹配
|
||||
- `easy fullLoader` 增加 **positive**、**negative**、**latent** 输出项
|
||||
- 修复 SDXLClipModel 在 ComfyUI 修订版本号 2016[c2cb8e88] 及以上的报错(判断了版本号可兼容老版本)
|
||||
- 修复 `easy detailerFix` 批次大小大于1时生成出错
|
||||
- 修复`easy preSampling`等 latent传入后无法根据批次索引生成的问题
|
||||
- 修复 `easy svdLoader` 报错
|
||||
- 优化代码,减少了诸多冗余,提升运行速度
|
||||
- 去除中文翻译对照文本
|
||||
|
||||
(翻译对照已由 [AIGODLIKE-COMFYUI-TRANSLATION](https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation) 统一维护啦!
|
||||
首次下载或者版本较早的朋友请更新 AIGODLIKE-COMFYUI-TRANSLATION 和本节点包至最新版本。)
|
||||
</details>
|
||||
|
||||
<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>
|
||||
|
||||
- 增加 `easy XYInputs: Checkpoint`
|
||||
- 增加 `easy XYInputs: Lora`
|
||||
- `easy seed` 增加固定种子值时可手动切换随机种
|
||||
- 修复 `easy fullLoader`等加载器切换lora时自动调整节点大小的问题
|
||||
- 去除原有ttn的图片保存逻辑并适配ComfyUI默认的图片保存格式化扩展
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.5</b></summary>
|
||||
|
||||
- 增加 `easy isSDXL`
|
||||
- `easy svdLoader` 增加提示词控制, 可配合open_clip模型进行使用
|
||||
- `easy wildcards` 增加 **populated_text** 可输出通配填充后文本
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.4</b></summary>
|
||||
|
||||
- 增加 `easy showLoaderSettingsNames` 可显示与输出加载器部件中的 模型与VAE名称
|
||||
- 增加 `easy promptList` - 提示词列表
|
||||
- 增加 `easy fooocusInpaintLoader` - Fooocus内补节点(仅支持XL模型的流程)
|
||||
- 增加 **Logic** 逻辑类节点 - 包含类型、计算、判断和转换类型等
|
||||
- 增加 `easy imageSave` - 带日期转换和宽高格式化的图像保存节点
|
||||
- 增加 `easy joinImageBatch` - 合并图像批次
|
||||
- `easy showAnything` 增加支持转换其他类型(如:tensor类型的条件、图像等)
|
||||
- `easy kSamplerInpainting` 增加 **patch** 传入值,配合Fooocus内补节点使用
|
||||
- `easy imageSave` 增加 **only_preivew**
|
||||
|
||||
- 修复 xyplot在pillow>9.5中报错
|
||||
- 修复 `easy wildcards` 在使用PS扩展插件运行时报错
|
||||
- 修复 `easy latentCompositeMaskedWithCond`
|
||||
- 修复 `easy XYInputs: ControlNet` 报错
|
||||
- 修复 `easy loraStack` **toggle** 为 disabled 时报错
|
||||
|
||||
- 修改首次安装节点包不再自动替换主题,需手动调整并刷新页面
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.3</b></summary>
|
||||
|
||||
- 增加 `easy stylesSelector` 风格化提示词选择器
|
||||
- 增加队列进度条设置项,默认为未启用状态
|
||||
- `easy controlnetLoader` 和 `easy controlnetLoaderADV` 增加参数 **scale_soft_weights**
|
||||
|
||||
|
||||
- 修复 `easy XYInputs: Sampler/Scheduler` 报错
|
||||
- 修复 右侧菜单 点击按钮时老是跑位的问题
|
||||
- 修复 styles 路径在其他环境报错
|
||||
- 修复 `easy comfyLoader` 读取错误
|
||||
- 修复 xyPlot 在连接 zero123 时报错
|
||||
- 修复加载器中提示词为组件时报错
|
||||
- 修复 `easy getNode` 和 `easy setNode` 加载时标题未更改
|
||||
- 修复所有采样器中存储图片使用子目录前缀不生效的问题
|
||||
|
||||
|
||||
- 调整UI主题
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.2</b></summary>
|
||||
|
||||
- 增加 **autocomplete** 文件夹,如果您安装了 [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts), 将在启动时合并该文件夹下的所有txt文件并覆盖到pyssss包里的autocomplete.txt文件。
|
||||
- 增加 `easy XYPlotAdvanced` 和 `easy XYInputs` 等相关节点
|
||||
- 增加 **Alt+1到9** 快捷键,可快速粘贴 Node templates 的节点预设 (对应 1到9 顺序)
|
||||
|
||||
- 修复 `easy imageInsetCrop` 测量值为百分比时步进为1
|
||||
- 修复 开启 `a1111_prompt_style` 时XY图表无法使用的问题
|
||||
- 右键菜单中增加了一个 `📜Groups Map(EasyUse)`
|
||||
|
||||
- 修复在Comfy新版本中UI加载失败
|
||||
- 修复 `easy pipeToBasicPipe` 报错
|
||||
- 修改 `easy fullLoader` 和 `easy a1111Loader` 中的 **a1111_prompt_style** 默认值为 False
|
||||
- `easy XYInputs ModelMergeBlocks` 支持csv文件导入数值
|
||||
|
||||
- 替换了XY图生成时的字体文件
|
||||
|
||||
- 移除 `easy imageRemBg`
|
||||
- 移除包中的介绍图和工作流文件,减少包体积
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.1</b></summary>
|
||||
|
||||
- 新增 `easy seed` - 简易随机种
|
||||
- `easy preDetailerFix` 新增了 `optional_image` 传入图像可选,如未传默认取值为pipe里的图像
|
||||
- 新增 `easy kSamplerInpainting` 用于内补潜空间的采样器
|
||||
- 新增 `easy pipeToBasicPipe` 用于转换到Impact的某些节点上
|
||||
|
||||
- 修复 `easy comfyLoader` 报错
|
||||
- 修复所有包含输出图片尺寸的节点取值方式无法批处理的问题
|
||||
- 修复 `width` 和 `height` 无法在 `easy svdLoader` 自定义的报错问题
|
||||
- 修复所有采样器预览图片的地址链接 (解决在 MACOS 系统中图片无法在采样器中预览的问题)
|
||||
- 修复 `vae_name` 在 `easy fullLoader` 和 `easy a1111Loader` 和 `easy comfyLoader` 中选择但未替换原始vae问题
|
||||
- 修复 `easy fullkSampler` 除pipe外其他输出值的报错
|
||||
- 修复 `easy hiresFix` 输入连接pipe和image、vae同时存在时报错
|
||||
- 修复 `easy fullLoader` 中 `model_override` 连接后未执行
|
||||
- 修复 因新增`easy seed` 导致action错误
|
||||
- 修复 `easy xyplot` 的字体文件路径读取错误
|
||||
- 修复 convert 到 `easy seed` 随机种无法固定的问题
|
||||
- 修复 `easy pipeIn` 值传入的报错问题
|
||||
- 修复 `easy zero123Loader` 和 `easy svdLoader` 读取模型时将模型加入到缓存中
|
||||
- 修复 `easy kSampler` `easy kSamplerTiled` `easy detailerFix` 的 `image_output` 默认值为 Preview
|
||||
- `easy fullLoader` 和 `easy a1111Loader` 新增了 `a1111_prompt_style` 参数可以重现和webui生成相同的图像,当前您需要安装 [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) 才能使用此功能
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.0</b></summary>
|
||||
|
||||
- 新增`easy positive` - 简易正面提示词文本
|
||||
- 新增`easy negative` - 简易负面提示词文本
|
||||
- 新增`easy wildcards` - 支持通配符和Lora选择的提示词文本
|
||||
- 新增`easy portraitMaster` - 肖像大师v2.2
|
||||
- 新增`easy loraStack` - Lora堆
|
||||
- 新增`easy fullLoader` - 完整版的加载器
|
||||
- 新增`easy zero123Loader` - 简易zero123加载器
|
||||
- 新增`easy svdLoader` - 简易svd加载器
|
||||
- 新增`easy fullkSampler` - 完整版的采样器(无分离)
|
||||
- 新增`easy hiresFix` - 支持Pipe的高清修复
|
||||
- 新增`easy predetailerFix` `easy DetailerFix` - 支持Pipe的细节修复
|
||||
- 新增`easy ultralyticsDetectorPipe` `easy samLoaderPipe` - 检测加载器(细节修复的输入项)
|
||||
- 新增`easy pipein` `easy pipeout` - Pipe的输入与输出
|
||||
- 新增`easy xyPlot` - 简易的xyplot (后续会更新更多可控参数)
|
||||
- 新增`easy imageRemoveBG` - 图像去除背景
|
||||
- 新增`easy imagePixelPerfect` - 图像完美像素
|
||||
- 新增`easy poseEditor` - 姿势编辑器
|
||||
- 新增UI主题(黑曜石)- 默认自动加载UI, 也可在设置中自行更替
|
||||
|
||||
- 修复 `easy globalSeed` 不生效问题
|
||||
- 修复所有的`seed_num` 因 [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) 实时更新图表导致值错乱的问题
|
||||
- 修复`easy imageSize` `easy imageSizeBySide` `easy imageSizeByLongerSide` 可作为终节点
|
||||
- 修复 `seed_num` (随机种子值) 在历史记录中读取无法一致的Bug
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><b>v0.5</b></summary>
|
||||
|
||||
- 新增 `easy controlnetLoaderADV` 节点
|
||||
- 新增 `easy imageSizeBySide` 节点,可选输出为长边或短边
|
||||
- 新增 `easy LLLiteLoader` 节点,如果您预先安装过 kohya-ss/ControlNet-LLLite-ComfyUI 包,请将 models 里的模型文件移动至 ComfyUI\models\controlnet\ (即comfy默认的controlnet路径里,请勿修改模型的文件名,不然会读取不到)。
|
||||
- 新增 `easy imageSize` 和 `easy imageSizeByLongerSize` 输出的尺寸显示。
|
||||
- 新增 `easy showSpentTime` 节点用于展示图片推理花费时间与VAE解码花费时间。
|
||||
- `easy controlnetLoaderADV` 和 `easy controlnetLoader` 新增 `control_net` 可选传入参数
|
||||
- `easy preSampling` 和 `easy preSamplingAdvanced` 新增 `image_to_latent` 可选传入参数
|
||||
- `easy a1111Loader` 和 `easy comfyLoader` 新增 `batch_size` 传入参数
|
||||
|
||||
- 修改 `easy controlnetLoader` 到 loader 分类底下。
|
||||
</details>
|
||||
|
||||
## 整合参考到的相关节点包
|
||||
|
||||
声明: 非常尊重这些原作者们的付出,开源不易,我仅仅只是做了一些整合与优化。
|
||||
|
||||
| 节点名 (搜索名) | 相关的库 | 库相关的节点 |
|
||||
|:-------------------------------|:----------------------------------------------------------------------------|:------------------------|
|
||||
| easy setNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.SetNode |
|
||||
| easy getNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.GetNode |
|
||||
| easy bookmark | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | Bookmark 🔖 |
|
||||
| easy portraitMarker | [comfyui-portrait-master](https://github.com/florestefano1975/comfyui-portrait-master) | Portrait Master |
|
||||
| easy LLLiteLoader | [ControlNet-LLLite-ComfyUI](https://github.com/kohya-ss/ControlNet-LLLite-ComfyUI) | LLLiteLoader |
|
||||
| easy globalSeed | [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) | Global Seed (Inspire) |
|
||||
| easy preSamplingDynamicCFG | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| dynamicThresholdingFull | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| easy imageInsetCrop | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | ImageInsetCrop |
|
||||
| easy poseEditor | [ComfyUI_Custom_Nodes_AlekPet](https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet) | poseNode |
|
||||
| easy if | [ComfyUI-Logic](https://github.com/theUpsider/ComfyUI-Logic) | IfExecute |
|
||||
| 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 |
|
||||
| easy icLightApply | [ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light) | ICLightApply等 |
|
||||
| easy kolorsLoader | [ComfyUI-Kolors-MZ](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ) | kolorsLoader |
|
||||
|
||||
## Credits
|
||||
|
||||
[ComfyUI](https://github.com/comfyanonymous/ComfyUI) - 功能强大且模块化的Stable Diffusion GUI
|
||||
|
||||
[ComfyUI-ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager) - ComfyUI管理器
|
||||
|
||||
[tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) - 管道节点(节点束)让用户减少了不必要的连接
|
||||
|
||||
[ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) - diffus3的获取与设置点让用户可以分离工作流构成
|
||||
|
||||
[ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) - 常规整合包1
|
||||
|
||||
[ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) - 常规整合包2
|
||||
|
||||
[ComfyUI-Logic](https://github.com/theUpsider/ComfyUI-Logic) - ComfyUI逻辑运算
|
||||
|
||||
[ComfyUI-ResAdapter](https://github.com/jiaxiangc/ComfyUI-ResAdapter) - 让模型生成不受训练分辨率限制
|
||||
|
||||
[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - 风格迁移
|
||||
|
||||
[ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID) - 人脸迁移
|
||||
|
||||
[ComfyUI_PuLID](https://github.com/cubiq/PuLID_ComfyUI) - 人脸迁移
|
||||
|
||||
[ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) - pyssss 小蛇🐍脚本
|
||||
|
||||
[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) - 图片选择器
|
||||
|
||||
[ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet) - BrushNet 内补节点
|
||||
|
||||
[ComfyUI_ExtraModels](https://github.com/city96/ComfyUI_ExtraModels) - DiT架构相关节点(Pixart、混元DiT等)
|
||||
|
||||
## ☕️ Donation
|
||||
|
||||
**Comfyui-Easy-Use** 是一个 GPL 许可的开源项目。为了项目取得更好、可持续的发展,我希望能够获得更多的支持。 如果我的自定义节点为您的一天增添了价值,请考虑喝杯咖啡来进一步补充能量! 💖感谢您的支持,每一杯咖啡都是我创作的动力!
|
||||
|
||||
- [BiliBili充电](https://space.bilibili.com/1840885116)
|
||||
- [爱发电](https://afdian.com/a/yolain)
|
||||
- [Wechat/Alipay](https://github.com/user-attachments/assets/803469bd-ed6a-4fab-932d-50e5088a2d03)
|
||||
|
||||
感谢您的捐助,我将用这些费用来租用 GPU 或购买其他 GPT 服务,以便更好地调试和完善 ComfyUI-Easy-Use 功能
|
||||
|
||||
## 🌟Stargazers
|
||||
|
||||
My gratitude extends to the generous souls who bestow a star. Your support is much appreciated!
|
||||
|
||||
[](https://github.com/yolain/ComfyUI-Easy-Use/stargazers)
|
||||
-423
@@ -1,423 +0,0 @@
|
||||
<p align="right">
|
||||
<a href="./README.md">中文</a> | <strong>English</strong>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
# ComfyUI Easy Use
|
||||
</div>
|
||||
|
||||
**ComfyUI-Easy-Use** is a simplified node integration package, which is extended on the basis of [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes), and has been integrated and optimized for many mainstream node packages to achieve the purpose of faster and more convenient use of ComfyUI. While ensuring the degree of freedom, it restores the ultimate smooth image production experience that belongs to Stable Diffusion.
|
||||
|
||||
[](https://github.com/yolain/ComfyUI-Yolain-Workflows)
|
||||
|
||||
## 👨🏻🎨 Introduce
|
||||
|
||||
- Inspire by [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes), which greatly reduces the time cost of tossing workflows。
|
||||
- UI interface beautification, the first time you install the user, if you need to use the UI theme, please switch the theme in Settings -> Color Palette and refresh page.
|
||||
- Added a node for pre-sampling parameter configuration, which can be separated from the sampling node for easier previewing
|
||||
- Wildcards and lora's are supported, for Lora Block Weight usage, ensure that the custom node package has the [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
||||
- Multi-selectable styled cue word selector, default is Fooocus style json, custom json can be placed under styles, samples folder can be placed in the preview image (name and name consistent, image file name such as spaces need to be converted to underscores '_')
|
||||
- The loader enables the A1111 prompt mode, which reproduces nearly identical images to those generated by webui, and needs to be installed [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) first.
|
||||
- Noise injection into the latent space can be achieved using the `easy latentNoisy` or `easy preSamplingNoiseIn` node
|
||||
- Simplified processes for SD1.x, SD2.x, SDXL, SVD, Zero123, etc. [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#StableDiffusion)
|
||||
- Simplified Stable Cascade [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#StableCascade)
|
||||
- Simplified Layer Diffuse [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#LayerDiffusion),The first time you use it you may need to run `pip install -r requirements.txt` to install the required dependencies.
|
||||
- Simplified InstantID [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#InstantID), You need to make sure that the custom node package has the [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID)
|
||||
- Extending the usability of XYplot
|
||||
- Fooocus Inpaint integration
|
||||
- Integration of common logical calculations, conversion of types, display of all types, etc.
|
||||
- Background removal nodes for the RMBG-1.4 model supporting BriaAI, [BriaAI Guide](https://huggingface.co/briaai/RMBG-1.4)
|
||||
- Forcibly cleared the memory usage of the comfy UI model are supported
|
||||
- Stable Diffusion 3 multi-account API nodes are supported
|
||||
- Support Stable Diffusion 3 model
|
||||
- Support Kolors model
|
||||
|
||||
## 👨🏻🔧 Installation
|
||||
Clone the repo into the **custom_nodes** directory and install the requirements:
|
||||
```shell
|
||||
#1. Clone the repo
|
||||
git clone https://github.com/yolain/ComfyUI-Easy-Use
|
||||
#2. Install the requirements
|
||||
Double-click install.bat to install the required dependencies
|
||||
```
|
||||
|
||||
## ☕️ Plan
|
||||
|
||||
- [ ] Updated new front-end code for easier maintenance
|
||||
- [x] Maintain css styles using sass
|
||||
- [ ] Optimize existing extensions
|
||||
- [ ] Add new components
|
||||
- [ ] Add light theme
|
||||
- [ ] Upload new workflows to [ComfyUI-Yolain-Workflows](https://github.com/yolain/ComfyUI-Yolain-Workflows) and translate readme to english version.
|
||||
- [ ] Write gitbook with more detailed function introdution
|
||||
|
||||
## 📜 Changelog
|
||||
|
||||
**v1.2.1**
|
||||
|
||||
- Added `easy ipadapterApplyFaceIDKolors`
|
||||
- Added **inspyrenet** to `easy imageRemBg`
|
||||
- Added `easy controlnetLoader++`
|
||||
- Added **PLUS (kolors genernal)** and **FACEID PLUS KOLORS** preset to `easy ipadapterApply` and `easy ipadapterApplyADV` (Supported kolors ipadapter)
|
||||
- Added `easy kolorsLoader` - Code based on [MinusZoneAI](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ)'s and [kijai](https://github.com/kijai/ComfyUI-KwaiKolorsWrapper)'s repo, thanks for their contribution.
|
||||
|
||||
**v1.2.0**
|
||||
|
||||
- Added `easy pulIDApply` and `easy pulIDApplyADV`
|
||||
- Added `easy huanyuanDiTLoader` and `easy pixArtLoader`
|
||||
- Added **easy sliderControl** - Slider control node, which can currently be used to control the parameters of ipadapterMS (double-click the slider to reset to default)
|
||||
- Added **layer_weights** in `easy ipadapterApplyADV`
|
||||
|
||||
**v1.1.9**
|
||||
|
||||
- Added **gitsScheduler**
|
||||
- Added `easy imageBatchToImageList` and `easy imageListToImageBatch`
|
||||
- Recursive subcategories nested for models
|
||||
- Support for Stable Diffusion 3 model
|
||||
- Added `easy applyInpaint` - All inpainting mode in this node
|
||||
|
||||
**v1.1.8**
|
||||
|
||||
- Added `easy controlnetStack`
|
||||
- Added `easy applyBrushNet` - [Workflow Example](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4brushnet_1.1.8.json)
|
||||
- Added `easy applyPowerPaint` - [Workflow Example](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4powerpaint_outpaint_1.1.8.json)
|
||||
|
||||
**v1.1.7**
|
||||
|
||||
- Added `easy prompt` - Subject and light presets, maybe adjusted later
|
||||
- Added `easy icLightApply` - Light and shadow migration, Code based on [ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light)
|
||||
- Added `easy imageSplitGrid`
|
||||
- `easy kSamplerInpainting` added options such as different diffusion and brushnet in **additional** widget
|
||||
- Support for brushnet model loading - [ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet)
|
||||
- Added `easy applyFooocusInpaint` - Replace FooocusInpaintLoader
|
||||
- Removed `easy fooocusInpaintLoader`
|
||||
|
||||
**v1.1.6**
|
||||
|
||||
- Added **alignYourSteps** to **schedulder** widget in all `easy preSampling` and `easy fullkSampler`
|
||||
- Added **Preview&Choose** to **image_output** widget in `easy kSampler` & `easy fullkSampler`
|
||||
- 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
|
||||
|
||||
**v1.1.5**
|
||||
|
||||
- Rewrite `easy cleanGPUUsed` - the memory usage of the comfyUI can to be cleared
|
||||
- Added `easy humanSegmentation` - Human Part Segmentation
|
||||
- Added `easy imageColorMatch`
|
||||
- Added `easy ipadapterApplyRegional`
|
||||
- Added `easy ipadapterApplyFromParams`
|
||||
- Added `easy imageInterrogator` - Image To Prompt
|
||||
- Added `easy stableDiffusion3API` - Easy Stable Diffusion 3 Multiple accounts API Node
|
||||
|
||||
**v1.1.4**
|
||||
|
||||
- Added `easy preSamplingCustom` - Custom-PreSampling, can be supported cosXL-edit
|
||||
- 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
|
||||
|
||||
|
||||
**v1.1.3**
|
||||
|
||||
- `easy ipadapterApply` Added **COMPOSITION** preset
|
||||
- Supported [ResAdapter](https://huggingface.co/jiaxiangc/res-adapter) when load ResAdapter lora
|
||||
- Added `easy promptLine`
|
||||
- Added `easy promptReplace`
|
||||
- Added `easy promptConcat`
|
||||
- `easy wildcards` Added **multiline_mode**
|
||||
|
||||
**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
|
||||
- Added `easy sv3dLoader`
|
||||
- Added `easy dynamiCrafterLoader`
|
||||
- Added `easy ipadapterApply`
|
||||
- Added `easy ipadapterApplyADV`
|
||||
- Added `easy ipadapterApplyEncoder`
|
||||
- Added `easy ipadapterApplyEmbeds`
|
||||
- Added `easy preMaskDetailerFix`
|
||||
- Fixed `easy stylesSelector` is change the prompt when not select the style
|
||||
- Fixed `easy pipeEdit` error when add lora to prompt
|
||||
- Fixed layerDiffuse xyplot bug
|
||||
- `easy kSamplerInpainting` add *additional* widget,you can choose 'Differential Diffusion' or 'Only InpaintModelConditioning'
|
||||
|
||||
**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**
|
||||
- Fixed `easy stylesSelector` error when choose the custom file
|
||||
- `easy preSamplingLayerDiffusion` Added optional input parameter for mask
|
||||
- Renamed all nodes widget name named seed_num to seed
|
||||
- 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
|
||||
|
||||
<details>
|
||||
<summary><b>v1.1.0</b></summary>
|
||||
|
||||
- Added `easy imageSplitList` - to split every N images
|
||||
- Added `easy preSamplingDiffusionADDTL` - It can modify foreground、background or blended additional prompt
|
||||
- Added `easy preSamplingNoiseIn` It can replace the `easy latentNoisy` node that needs to be fronted to achieve better noise injection
|
||||
- `easy pipeEdit` Added conditioning splicing mode selection, you can choose to replace, concat, combine, average, and set timestep range
|
||||
- Added `easy pipeEdit` - nodes that can edit pipes (including re-enterable prompts)
|
||||
- Added `easy preSamplingLayerDiffusion` and `easy kSamplerLayerDiffusion`
|
||||
- Added a convenient menu to right-click on nodes such as Loader, Presampler, Sampler, Controlnet, etc. to quickly replace nodes of the same type
|
||||
- Added `easy instantIDApplyADV` can link positive and negative
|
||||
- Fixed layerDiffusion error when batch size greater than 1
|
||||
- Fixed `easy wildcards` When LoRa is not filled in completely, LoRa is not automatically retrieved, resulting in failure to load LoRa
|
||||
- Fixed the issue that 'BREAK' non-initiation when didn't use a1111 prompt style
|
||||
- Fixed `easy instantIDApply` mask not input right
|
||||
</details>
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
- `easy fullLoader` **positive**、**negative**、**latent** added to the output items
|
||||
- Fixed the issue that 'easy preSampling' and other similar node, latent could not be generated based on the batch index after passing in
|
||||
- Fixed `easy svdLoader` error when the positive or negative is empty
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.7</b></summary>
|
||||
|
||||
- Added `easy cascadeLoader` - stable cascade Loader
|
||||
- Added `easy preSamplingCascade` - stable cascade preSampling Settings
|
||||
- Added `easy fullCascadeKSampler` - stable cascade stage-c ksampler full
|
||||
- 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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
- Added `easy promptList`
|
||||
- Added `easy fooocusInpaintLoader` (only the process of SDXLModel is supported)
|
||||
- Added **Logic** nodes
|
||||
- Added `easy imageSave` - Image saving node with date conversion and aspect and height formatting
|
||||
- Added `easy joinImageBatch`
|
||||
- `easy kSamplerInpainting` Added the **patch** input value to be used with the FooocusInpaintLoader node
|
||||
|
||||
- Fixed xyplot error when with Pillow>9.5
|
||||
- Fixed `easy wildcards` An error is reported when running with the PS extension
|
||||
- Fixed `easy XYInputs: ControlNet` Error
|
||||
- Fixed `easy loraStack` error when **toggle** is disabled
|
||||
|
||||
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.3</b></summary>
|
||||
|
||||
- Added `easy stylesSelector`
|
||||
- Added **scale_soft_weights** in `easy controlnetLoader` and `easy controlnetLoaderADV`
|
||||
- Added the queue progress bar setting item, which is not enabled by default
|
||||
|
||||
|
||||
- Fixed `easy XYInputs: Sampler/Scheduler` Error
|
||||
- Fixed the right menu has a problem when clicking the button
|
||||
- Fixed `easy comfyLoader` error
|
||||
- Fixed xyPlot error when connecting to zero123
|
||||
- Fixed the error message in the loader when the prompt word was component
|
||||
- Fixed `easy getNode` and `easy setNode` the title does not change when loading
|
||||
- Fixed all samplers using subdirectories to store images
|
||||
|
||||
|
||||
- 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>
|
||||
|
||||
<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)
|
||||
- Added a `📜Groups Map(EasyUse)` to the context menu.
|
||||
- An `autocomplete` folder has been added, If you have [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) installed, the txt files in that folder will be merged and overwritten to the autocomplete .txt file of the pyssss package at startup.
|
||||
|
||||
|
||||
- Fixed XYPlot is not working when `a1111_prompt_style` is True
|
||||
- Fixed UI loading failure in the new version of ComfyUI
|
||||
- `easy XYInputs ModelMergeBlocks` Values can be imported from CSV files
|
||||
- Fixed `easy pipeToBasicPipe` Bug
|
||||
|
||||
|
||||
- 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>
|
||||
|
||||
- Fixed `easy comfyLoader` error
|
||||
- Fixed All nodes that contain the value of the image size
|
||||
- Added `easy kSamplerInpainting`
|
||||
- Added `easy pipeToBasicPipe`
|
||||
- Fixed `width` and `height` can not customize in `easy svdLoader`
|
||||
- Fixed all preview image path (Previously, it was not possible to preview the image on the Mac system)
|
||||
- Fixed `vae_name` is not working in `easy fullLoader` and `easy a1111Loader` and `easy comfyLoader`
|
||||
- Fixed `easy fullkSampler` outputs error
|
||||
- Fixed `model_override` is not working in `easy fullLoader`
|
||||
- Fixed `easy hiresFix` error
|
||||
- Fixed `easy xyplot` font file path error
|
||||
- Fixed seed that cannot be fixed when you convert `seed_num` to `easy seed`
|
||||
- Fixed `easy pipeIn` inputs bug
|
||||
- `easy preDetailerFix` have added a new parameter `optional_image`
|
||||
- Fixed `easy zero123Loader` and `easy svdLoader` model into cache.
|
||||
- Added `easy seed`
|
||||
- Fixed `image_output` default value is "Preview"
|
||||
- `easy fullLoader` and `easy a1111Loader` have added a new parameter `a1111_prompt_style`,that can reproduce the same image generated from stable-diffusion-webui on comfyui, but you need to install [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) to use this feature in the current version
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.0</b></summary>
|
||||
|
||||
- Added `easy positive` - simple positive prompt text
|
||||
- Added `easy negative` - simple negative prompt text
|
||||
- Added `easy wildcards` - support for wildcards and hint text selected by Lora
|
||||
- Added `easy portraitMaster` - PortraitMaster v2.2
|
||||
- Added `easy loraStack` - Lora stack
|
||||
- Added `easy fullLoader` - full version of the loader
|
||||
- Added `easy zero123Loader` - simple zero123 loader
|
||||
- Added `easy svdLoader` - easy svd loader
|
||||
- Added `easy fullkSampler` - full version of the sampler (no separation)
|
||||
- Added `easy hiresFix` - support for HD repair of Pipe
|
||||
- Added `easy predetailerFix` and `easy DetailerFix` - support for Pipe detail fixing
|
||||
- Added `easy ultralyticsDetectorPipe` and `easy samLoaderPipe` - Detect loader (detail fixed input)
|
||||
- Added `easy pipein` `easy pipeout` - Pipe input and output
|
||||
- Added `easy xyPlot` - simple xyplot (more controllable parameters will be updated in the future)
|
||||
- Added `easy imageRemoveBG` - image to remove background
|
||||
- Added `easy imagePixelPerfect` - image pixel perfect
|
||||
- Added `easy poseEditor` - Pose editor
|
||||
- New UI Theme (Obsidian) - Auto-load UI by default, which can also be changed in the settings
|
||||
|
||||
- Fixed `easy globalSeed` is not working
|
||||
- Fixed an issue where all `seed_num` values were out of order due to [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) updating the chart in real time
|
||||
- Fixed `easy imageSize`, `easy imageSizeBySide`, `easy imageSizeByLongerSide` as end nodes
|
||||
- Fixed the bug that `seed_num` (random seed value) could not be read consistently in history
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Updated at 12/14/2023</b></summary>
|
||||
|
||||
- `easy a1111Loader` and `easy comfyLoader` added `batch_size` of required input parameters
|
||||
- Added the `easy controlnetLoaderADV` node
|
||||
- `easy controlnetLoaderADV` and `easy controlnetLoader` added `control_net ` of optional input parameters
|
||||
- `easy preSampling` and `easy preSamplingAdvanced` added `image_to_latent` optional input parameters
|
||||
- Added the `easy imageSizeBySide` node, which can be output as a long side or a short side
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Updated at 12/13/2023</b></summary>
|
||||
|
||||
- Added the `easy LLLiteLoader` node, if you have pre-installed the kohya-ss/ControlNet-LLLite-ComfyUI package, please move the model files in the models to `ComfyUI\models\controlnet\` (i.e. in the default controlnet path of comfy, please do not change the file name of the model, otherwise it will not be read).
|
||||
- Modify `easy controlnetLoader` to the bottom of the loader category.
|
||||
- Added size display for `easy imageSize` and `easy imageSizeByLongerSize` outputs.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Updated at 12/11/2023</b></summary>
|
||||
- Added the `showSpentTime` node to display the time spent on image diffusion and the time spent on VAE decoding images
|
||||
</details>
|
||||
|
||||
## The relevant node package involved
|
||||
|
||||
Disclaimer: Opened source was not easy. I have a lot of respect for the contributions of these original authors. I just did some integration and optimization.
|
||||
|
||||
| Nodes Name(Search Name) | Related libraries | Library-related node |
|
||||
|:-------------------------------|:----------------------------------------------------------------------------|:-------------------------|
|
||||
| easy setNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.SetNode |
|
||||
| easy getNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.GetNode |
|
||||
| easy bookmark | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | Bookmark 🔖 |
|
||||
| easy portraitMarker | [comfyui-portrait-master](https://github.com/florestefano1975/comfyui-portrait-master) | Portrait Master |
|
||||
| easy LLLiteLoader | [ControlNet-LLLite-ComfyUI](https://github.com/kohya-ss/ControlNet-LLLite-ComfyUI) | LLLiteLoader |
|
||||
| easy globalSeed | [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) | Global Seed (Inspire) |
|
||||
| easy preSamplingDynamicCFG | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| dynamicThresholdingFull | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| easy imageInsetCrop | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | ImageInsetCrop |
|
||||
| easy poseEditor | [ComfyUI_Custom_Nodes_AlekPet](https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet) | poseNode |
|
||||
| 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 |
|
||||
| easy kolorsLoader | [ComfyUI-Kolors-MZ](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ) | kolorsLoader |
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
[ComfyUI](https://github.com/comfyanonymous/ComfyUI) - Powerful and modular Stable Diffusion GUI
|
||||
|
||||
[ComfyUI-ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager) - ComfyUI Manager
|
||||
|
||||
[tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) - Pipe nodes (node bundles) allow users to reduce unnecessary connections
|
||||
|
||||
[ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) - Diffus3 gets and sets points that allow the user to detach the composition of the workflow
|
||||
|
||||
[ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) - General modpack 1
|
||||
|
||||
[ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) - General Modpack 2
|
||||
|
||||
[ComfyUI-ResAdapter](https://github.com/jiaxiangc/ComfyUI-ResAdapter) - Make model generation independent of training resolution
|
||||
|
||||
[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - Style migration
|
||||
|
||||
[ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID) - Face migration
|
||||
|
||||
[ComfyUI_PuLID](https://github.com/cubiq/PuLID_ComfyUI) - Face migration
|
||||
|
||||
[ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) - pyssss🐍
|
||||
|
||||
[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) - Image Preview Chooser
|
||||
|
||||
[ComfyUI_ExtraModels](https://github.com/city96/ComfyUI_ExtraModels) - DiT custom nodes
|
||||
|
||||
|
||||
## 🌟Stargazers
|
||||
|
||||
My gratitude extends to the generous souls who bestow a star. Your support is much appreciated!
|
||||
|
||||
[](https://github.com/yolain/ComfyUI-Easy-Use/stargazers)
|
||||
@@ -1,439 +1,451 @@
|
||||
<p align="right">
|
||||
<strong>中文</strong> | <a href="./README.en.md">English</a>
|
||||
</p>
|
||||

|
||||
|
||||
<div align="center">
|
||||
|
||||
# ComfyUI Easy Use
|
||||
|
||||
[](https://www.bilibili.com/video/BV1w6421F7Uv)
|
||||
[](https://www.bilibili.com/video/BV1vQ4y1G7z7/)
|
||||
<a href="https://space.bilibili.com/1840885116">Video Tutorial</a> |
|
||||
Docs (Cooming Soon) |
|
||||
<a href="https://github.com/yolain/ComfyUI-Yolain-Workflows">Workflow Collection</a> |
|
||||
<a href="#%EF%B8%8F-donation">Donation</a>
|
||||
<br><br>
|
||||
<a href="./README.md"><img src="https://img.shields.io/badge/🇬🇧English-0b8cf5"></a>
|
||||
<a href="./README.ZH_CN.md"><img src="https://img.shields.io/badge/🇨🇳中文简体-e9e9e9"></a>
|
||||
</div>
|
||||
|
||||
**ComfyUI-Easy-Use** 是一个化繁为简的节点整合包, 在 [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) 的基础上进行延展,并针对了诸多主流的节点包做了整合与优化,以达到更快更方便使用ComfyUI的目的,在保证自由度的同时还原了本属于Stable Diffusion的极致畅快出图体验。
|
||||
**ComfyUI-Easy-Use** is an efficiency custom nodes integration package, which is extended on the basis of [TinyTerraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes). It has been integrated and optimized for many popular awesome custom nodes to achieve the purpose of faster and more convenient use of ComfyUI. While ensuring the degree of freedom, it restores the ultimate smooth image production experience that belongs to Stable Diffusion.
|
||||
|
||||
[](https://github.com/yolain/ComfyUI-Yolain-Workflows)
|
||||
## 👨🏻🎨 Introduce
|
||||
|
||||
## 👨🏻🎨 特色介绍
|
||||
- Inspire by [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes), which greatly reduces the time cost of tossing workflows。
|
||||
- UI interface beautification, the first time you install the user, if you need to use the UI theme, please switch the theme in Settings -> Color Palette and refresh page.
|
||||
- Added a node for pre-sampling parameter configuration, which can be separated from the sampling node for easier previewing
|
||||
- Wildcards and lora's are supported, for Lora Block Weight usage, ensure that the custom node package has the [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
||||
- Multi-selectable styled cue word selector, default is Fooocus style json, custom json can be placed under styles, samples folder can be placed in the preview image (name and name consistent, image file name such as spaces need to be converted to underscores '_')
|
||||
- The loader enables the A1111 prompt mode, which reproduces nearly identical images to those generated by webui, and needs to be installed [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) first.
|
||||
- Noise injection into the latent space can be achieved using the `easy latentNoisy` or `easy preSamplingNoiseIn` node
|
||||
- Simplified processes for SD1.x, SD2.x, SDXL, SVD, Zero123, etc. [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#StableDiffusion)
|
||||
- Simplified Stable Cascade [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#StableCascade)
|
||||
- Simplified Layer Diffuse [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#LayerDiffusion),The first time you use it you may need to run `pip install -r requirements.txt` to install the required dependencies.
|
||||
- Simplified InstantID [Example](https://github.com/yolain/ComfyUI-Easy-Use?tab=readme-ov-file#InstantID), You need to make sure that the custom node package has the [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID)
|
||||
- Extending the usability of XYplot
|
||||
- Fooocus Inpaint integration
|
||||
- Integration of common logical calculations, conversion of types, display of all types, etc.
|
||||
- Background removal nodes for the RMBG-1.4 model supporting BriaAI, [BriaAI Guide](https://huggingface.co/briaai/RMBG-1.4)
|
||||
- Forcibly cleared the memory usage of the comfy UI model are supported
|
||||
- Stable Diffusion 3 multi-account API nodes are supported
|
||||
- Support SD3's model
|
||||
- Support Kolors‘s model
|
||||
- Support Flux's model
|
||||
- Support lazy if else and for loops
|
||||
|
||||
- 沿用了 [tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) 的思路,大大减少了折腾工作流的时间成本。
|
||||
- UI界面美化,首次安装的用户,如需使用UI主题,请在 Settings -> Color Palette 中自行切换主题并**刷新页面**即可
|
||||
- 增加了预采样参数配置的节点,可与采样节点分离,更方便预览。
|
||||
- 支持通配符与Lora的提示词节点,如需使用Lora Block Weight用法,需先保证自定义节点包中安装了 [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
||||
- 可多选的风格化提示词选择器,默认是Fooocus的样式json,可自定义json放在styles底下,samples文件夹里可放预览图(名称和name一致,图片文件名如有空格需转为下划线'_')
|
||||
- 加载器可开启A1111提示词风格模式,可重现与webui生成近乎相同的图像,需先安装 [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes)
|
||||
- 可使用`easy latentNoisy`或`easy preSamplingNoiseIn`节点实现对潜空间的噪声注入
|
||||
- 简化 SD1.x、SD2.x、SDXL、SVD、Zero123等流程
|
||||
- 简化 Stable Cascade [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#1-13-stable-cascade)
|
||||
- 简化 Layer Diffuse [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-3-layerdiffusion)
|
||||
- 简化 InstantID [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-2-instantid), 需先保证自定义节点包中安装了 [ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID)
|
||||
- 简化 IPAdapter, 需先保证自定义节点包中安装最新版v2的 [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus)
|
||||
- 扩展 XYplot 的可用性
|
||||
- 整合了Fooocus Inpaint功能
|
||||
- 整合了常用的逻辑计算、转换类型、展示所有类型等
|
||||
- 支持节点上checkpoint、lora模型子目录分类及预览图 (请在设置中开启上下文菜单嵌套子目录)
|
||||
- 支持BriaAI的RMBG-1.4模型的背景去除节点,[技术参考](https://huggingface.co/briaai/RMBG-1.4)
|
||||
- 支持 强制清理comfyUI模型显存占用
|
||||
- 支持Stable Diffusion 3 多账号API节点
|
||||
- 支持IC-Light的应用 [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows?tab=readme-ov-file#2-5-ic-light) | [代码整合来源](https://github.com/huchenlei/ComfyUI-IC-Light) | [技术参考](https://github.com/lllyasviel/IC-Light)
|
||||
- 中文提示词自动识别,使用[opus-mt-zh-en模型](https://huggingface.co/Helsinki-NLP/opus-mt-zh-en)
|
||||
- 支持 sd3 模型
|
||||
- 支持 kolors 模型
|
||||
|
||||
## 👨🏻🔧 安装
|
||||
|
||||
1. 将存储库克隆到 **custom_nodes** 目录并安装依赖
|
||||
## 👨🏻🔧 Installation
|
||||
Clone the repo into the **custom_nodes** directory and install the requirements:
|
||||
```shell
|
||||
#1. git下载
|
||||
#1. Clone the repo
|
||||
git clone https://github.com/yolain/ComfyUI-Easy-Use
|
||||
#2. 安装依赖
|
||||
双击install.bat安装依赖
|
||||
#2. Install the requirements
|
||||
Double-click install.bat to install the required dependencies
|
||||
```
|
||||
|
||||
## ☕️ 计划
|
||||
## 👨🏻🚀 Plan
|
||||
|
||||
- [ ] 更新便于维护的新前端代码
|
||||
- [x] 使用sass维护css样式
|
||||
- [ ] 对原有扩展进行优化
|
||||
- [ ] 增加新的组件(如节点时间统计等)
|
||||
- [ ] 增加浅色主题
|
||||
- [ ] 在[ComfyUI-Yolain-Workflows](https://github.com/yolain/ComfyUI-Yolain-Workflows)中上传更多的工作流(如kolors,sd3等),并更新english版本的readme
|
||||
- [ ] 更详细功能介绍的 gitbook
|
||||
- [x] Updated new front-end code for easier maintenance
|
||||
- [x] Maintain css styles using sass
|
||||
- [x] Optimize existing extensions
|
||||
- [x] Add new components
|
||||
- [ ] Upload new workflows to [ComfyUI-Yolain-Workflows](https://github.com/yolain/ComfyUI-Yolain-Workflows) and translate readme to english version.
|
||||
- [ ] Write gitbook with more detailed function introdution
|
||||
|
||||
## 📜 更新日志
|
||||
## 📜 Changelog
|
||||
|
||||
**v1.2.2**
|
||||
|
||||
- Added `easy batchAny`
|
||||
- Added `easy anythingIndexSwitch`
|
||||
- Added `easy forLoopStart` and `easy forLoopEnd`
|
||||
- Added `easy ifElse`
|
||||
- Added v2 web frond-end code
|
||||
- Added `easy fluxLoader`
|
||||
- Added support for `controlnetApply` Related nodes with SD3 and hunyuanDiT
|
||||
- Fixed after using `easy applyFooocusInpaint`, all lora models become unusable
|
||||
|
||||
**v1.2.1**
|
||||
|
||||
- 增加 `easy ipadapterApplyFaceIDKolors`
|
||||
- `easy ipadapterApply` 和 `easy ipadapterApplyADV` 增加 **PLUS (kolors genernal)** 和 **FACEID PLUS KOLORS** 预置项
|
||||
- `easy imageRemBg` 增加 **inspyrenet** 选项
|
||||
- 增加 `easy controlnetLoader++`
|
||||
- 去除 `easy positive` `easy negative` 等prompt节点的自动将中文翻译功能,自动翻译仅在 `easy a1111Loader` 等不支持中文TE的加载器中生效
|
||||
- 增加 `easy kolorsLoader` - 可灵加载器,参考了 [MinusZoneAI](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ) 和 [kijai](https://github.com/kijai/ComfyUI-KwaiKolorsWrapper) 的代码。
|
||||
- Added `easy ipadapterApplyFaceIDKolors`
|
||||
- Added **inspyrenet** to `easy imageRemBg`
|
||||
- Added `easy controlnetLoader++`
|
||||
- Added **PLUS (kolors genernal)** and **FACEID PLUS KOLORS** preset to `easy ipadapterApply` and `easy ipadapterApplyADV` (Supported kolors ipadapter)
|
||||
- Added `easy kolorsLoader` - Code based on [MinusZoneAI](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ)'s and [kijai](https://github.com/kijai/ComfyUI-KwaiKolorsWrapper)'s repo, thanks for their contribution.
|
||||
|
||||
**v1.2.0**
|
||||
|
||||
- 增加 `easy pulIDApply` 和 `easy pulIDApplyADV`
|
||||
- 增加 `easy hunyuanDiTLoader` 和 `easy pixArtLoader`
|
||||
- 当新菜单的位置在上或者下时增加上 crystools 的显示,推荐开两个就好(如果后续crystools有更新UI适配我可能会删除掉)
|
||||
- 增加 **easy sliderControl** - 滑块控制节点,当前可用于控制ipadapterMS的参数 (双击滑块可重置为默认值)
|
||||
- 增加 **layer_weights** 属性在 `easy ipadapterApplyADV` 节点
|
||||
- Added `easy pulIDApply` and `easy pulIDApplyADV`
|
||||
- Added `easy huanyuanDiTLoader` and `easy pixArtLoader`
|
||||
- Added **easy sliderControl** - Slider control node, which can currently be used to control the parameters of ipadapterMS (double-click the slider to reset to default)
|
||||
- Added **layer_weights** in `easy ipadapterApplyADV`
|
||||
|
||||
**v1.1.9**
|
||||
|
||||
- 增加 新的调度器 **gitsScheduler**
|
||||
- 增加 `easy imageBatchToImageList` 和 `easy imageListToImageBatch` (修复Impact版的一点小问题)
|
||||
- 递归模型子目录嵌套
|
||||
- 支持 sd3 模型
|
||||
- 增加 `easy applyInpaint` - 局部重绘全模式节点 (相比与之前的kSamplerInpating节点逻辑会更合理些)
|
||||
- Added **gitsScheduler**
|
||||
- Added `easy imageBatchToImageList` and `easy imageListToImageBatch`
|
||||
- Recursive subcategories nested for models
|
||||
- Support for Stable Diffusion 3 model
|
||||
- Added `easy applyInpaint` - All inpainting mode in this node
|
||||
|
||||
**v1.1.8**
|
||||
|
||||
- 增加中文提示词自动翻译,使用[opus-mt-zh-en模型](https://huggingface.co/Helsinki-NLP/opus-mt-zh-en), 默认已对wildcard、lora正则处理, 其他需要保留的中文,可使用`@你的提示词@`包裹 (若依赖安装完成后报错, 请重启),测算大约会占0.3GB显存
|
||||
- 增加 `easy controlnetStack` - controlnet堆
|
||||
- 增加 `easy applyBrushNet` - [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4brushnet_1.1.8.json)
|
||||
- 增加 `easy applyPowerPaint` - [示例参考](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4powerpaint_outpaint_1.1.8.json)
|
||||
- Added `easy controlnetStack`
|
||||
- Added `easy applyBrushNet` - [Workflow Example](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4brushnet_1.1.8.json)
|
||||
- Added `easy applyPowerPaint` - [Workflow Example](https://github.com/yolain/ComfyUI-Yolain-Workflows/blob/main/workflows/2_advanced/2-4inpainting/2-4powerpaint_outpaint_1.1.8.json)
|
||||
|
||||
**v1.1.7**
|
||||
|
||||
- 修复 一些模型(如controlnet模型等)未成功写入缓存,导致修改前置节点束参数(如提示词)需要二次载入模型的问题
|
||||
- 增加 `easy prompt` - 主体和光影预置项,后期可能会调整
|
||||
- 增加 `easy icLightApply` - 重绘光影, 从[ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light)优化
|
||||
- 增加 `easy imageSplitGrid` - 图像网格拆分
|
||||
- `easy kSamplerInpainting` 的 **additional** 属性增加差异扩散和brushnet等相关选项
|
||||
- 增加 brushnet模型加载的支持 - [ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet)
|
||||
- 增加 `easy applyFooocusInpaint` - Fooocus内补节点 替代原有的 FooocusInpaintLoader
|
||||
- 移除 `easy fooocusInpaintLoader` - 容易bug,不再使用
|
||||
- 修改 easy kSampler等采样器中并联的model 不再替换输出中pipe里的model
|
||||
- Added `easy prompt` - Subject and light presets, maybe adjusted later
|
||||
- Added `easy icLightApply` - Light and shadow migration, Code based on [ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light)
|
||||
- Added `easy imageSplitGrid`
|
||||
- `easy kSamplerInpainting` added options such as different diffusion and brushnet in **additional** widget
|
||||
- Support for brushnet model loading - [ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet)
|
||||
- Added `easy applyFooocusInpaint` - Replace FooocusInpaintLoader
|
||||
- Removed `easy fooocusInpaintLoader`
|
||||
|
||||
**v1.1.6**
|
||||
|
||||
- 增加步调齐整适配 - 在所有的预采样和全采样器节点中的 调度器(schedulder) 增加了 **alignYourSteps** 选项
|
||||
- `easy kSampler` 和 `easy fullkSampler` 的 **image_output** 增加 **Preview&Choose**选项
|
||||
- 增加 `easy styleAlignedBatchAlign` - 风格对齐 [style_aligned_comfy](https://github.com/brianfitzgerald/style_aligned_comfy)
|
||||
- 增加 `easy ckptNames`
|
||||
- 增加 `easy controlnetNames`
|
||||
- 增加 `easy imagesSplitimage` - 批次图像拆分单张
|
||||
- 增加 `easy imageCount` - 图像数量
|
||||
- 增加 `easy textSwitch` - 文字切换
|
||||
- Added **alignYourSteps** to **schedulder** widget in all `easy preSampling` and `easy fullkSampler`
|
||||
- Added **Preview&Choose** to **image_output** widget in `easy kSampler` & `easy fullkSampler`
|
||||
- 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
|
||||
|
||||
**v1.1.5**
|
||||
|
||||
- 重写 `easy cleanGPUUsed` - 可强制清理comfyUI的模型显存占用
|
||||
- 增加 `easy humanSegmentation` - 多类分割、人像分割
|
||||
- 增加 `easy imageColorMatch`
|
||||
- 增加 `easy ipadapterApplyRegional`
|
||||
- 增加 `easy ipadapterApplyFromParams`
|
||||
- 增加 `easy imageInterrogator` - 图像反推
|
||||
- 增加 `easy stableDiffusion3API` - 简易的Stable Diffusion 3 多账号API节点
|
||||
- Rewrite `easy cleanGPUUsed` - the memory usage of the comfyUI can to be cleared
|
||||
- Added `easy humanSegmentation` - Human Part Segmentation
|
||||
- Added `easy imageColorMatch`
|
||||
- Added `easy ipadapterApplyRegional`
|
||||
- Added `easy ipadapterApplyFromParams`
|
||||
- Added `easy imageInterrogator` - Image To Prompt
|
||||
- Added `easy stableDiffusion3API` - Easy Stable Diffusion 3 Multiple accounts API Node
|
||||
|
||||
**v1.1.4**
|
||||
|
||||
- 增加 `easy imageChooser` - 从[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker)简化的图片选择器
|
||||
- 增加 `easy preSamplingCustom` - 自定义预采样,可支持cosXL-edit
|
||||
- 增加 `easy ipadapterStyleComposition`
|
||||
- 增加 在Loaders上右键菜单可查看 checkpoints、lora 信息
|
||||
- 修复 `easy preSamplingNoiseIn`、`easy latentNoisy`、`east Unsampler` 以兼容ComfyUI Revision>=2098 [0542088e] 以上版本
|
||||
- 修复 FooocusInpaint修改ModelPatcher计算权重引发的问题,理应在生成model后重置ModelPatcher为默认值
|
||||
- Added `easy preSamplingCustom` - Custom-PreSampling, can be supported cosXL-edit
|
||||
- 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
|
||||
|
||||
|
||||
**v1.1.3**
|
||||
|
||||
- `easy ipadapterApply` 增加 **COMPOSITION** 预置项
|
||||
- 增加 对[ResAdapter](https://huggingface.co/jiaxiangc/res-adapter) lora模型 的加载支持
|
||||
- 增加 `easy promptLine`
|
||||
- 增加 `easy promptReplace`
|
||||
- 增加 `easy promptConcat`
|
||||
- `easy wildcards` 增加 **multiline_mode**属性
|
||||
- 增加 当节点需要下载模型时,若huggingface连接超时,会切换至镜像地址下载模型
|
||||
- `easy ipadapterApply` Added **COMPOSITION** preset
|
||||
- Supported [ResAdapter](https://huggingface.co/jiaxiangc/res-adapter) when load ResAdapter lora
|
||||
- Added `easy promptLine`
|
||||
- Added `easy promptReplace`
|
||||
- Added `easy promptConcat`
|
||||
- `easy wildcards` Added **multiline_mode**
|
||||
|
||||
**v1.1.2**
|
||||
<details>
|
||||
<summary><b>v1.1.2</b></summary>
|
||||
|
||||
- 改写 EasyUse 相关节点的部分插槽推荐节点
|
||||
- 增加 **启用上下文菜单自动嵌套子目录** 设置项,默认为启用状态,可分类子目录及checkpoints、loras预览图
|
||||
- 增加 `easy sv3dLoader`
|
||||
- 增加 `easy dynamiCrafterLoader`
|
||||
- 增加 `easy ipadapterApply`
|
||||
- 增加 `easy ipadapterApplyADV`
|
||||
- 增加 `easy ipadapterApplyEncoder`
|
||||
- 增加 `easy ipadapterApplyEmbeds`
|
||||
- 增加 `easy preMaskDetailerFix`
|
||||
- `easy kSamplerInpainting` 增加 **additional** 属性,可设置成 Differential Diffusion 或 Only InpaintModelConditioning
|
||||
- 修复 `easy stylesSelector` 当未选择样式时,原有提示词发生了变化
|
||||
- 修复 `easy pipeEdit` 提示词输入lora时报错
|
||||
- 修复 layerDiffuse xyplot相关bug
|
||||
- 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
|
||||
- Added `easy sv3dLoader`
|
||||
- Added `easy dynamiCrafterLoader`
|
||||
- Added `easy ipadapterApply`
|
||||
- Added `easy ipadapterApplyADV`
|
||||
- Added `easy ipadapterApplyEncoder`
|
||||
- Added `easy ipadapterApplyEmbeds`
|
||||
- Added `easy preMaskDetailerFix`
|
||||
- Fixed `easy stylesSelector` is change the prompt when not select the style
|
||||
- Fixed `easy pipeEdit` error when add lora to prompt
|
||||
- Fixed layerDiffuse xyplot bug
|
||||
- `easy kSamplerInpainting` add *additional* widget,you can choose 'Differential Diffusion' or 'Only InpaintModelConditioning'
|
||||
</details>
|
||||
|
||||
**v1.1.1**
|
||||
|
||||
- 修复首次添加含seed的节点且当前模式为control_before_generate时,seed为0的问题
|
||||
- `easy preSamplingAdvanced` 增加 **return_with_leftover_noise**
|
||||
- 修复 `easy stylesSelector` 当选择自定义样式文件时运行队列报错
|
||||
- `easy preSamplingLayerDiffusion` 增加 mask 可选传入参数
|
||||
- 将所有 **seed_num** 调整回 **seed**
|
||||
- 修补官方BUG: 当control_mode为before 在首次加载页面时未修改节点中widget名称为 control_before_generate
|
||||
- 去除强制**control_before_generate**设定
|
||||
- 增加 `easy imageRemBg` - 默认为BriaAI的RMBG-1.4模型, 移除背景效果更加,速度更快
|
||||
<details>
|
||||
<summary><b>v1.1.1</b></summary>
|
||||
|
||||
- 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**
|
||||
- Fixed `easy stylesSelector` error when choose the custom file
|
||||
- `easy preSamplingLayerDiffusion` Added optional input parameter for mask
|
||||
- Renamed all nodes widget name named seed_num to seed
|
||||
- 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
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.1.0</b></summary>
|
||||
|
||||
- 增加 `easy imageSplitList` - 拆分每 N 张图像
|
||||
- 增加 `easy preSamplingDiffusionADDTL` - 可配置前景、背景、blended的additional_prompt等
|
||||
- 增加 `easy preSamplingNoiseIn` 可替代需要前置的`easy latentNoisy`节点 实现效果更好的噪声注入
|
||||
- `easy pipeEdit` 增加 条件拼接模式选择,可选择替换、合并、联结、平均、设置条件时间
|
||||
- 增加 `easy pipeEdit` - 可编辑Pipe的节点(包含可重新输入提示词)
|
||||
- 增加 `easy preSamplingLayerDiffusion` 与 `easy kSamplerLayerDiffusion` (连接 `easy kSampler` 也能通)
|
||||
- 增加 在 加载器、预采样、采样器、Controlnet等节点上右键可快速替换同类型节点的便捷菜单
|
||||
- 增加 `easy instantIDApplyADV` 可连入 positive 与 negative
|
||||
- 修复 `easy wildcards` 读取lora未填写完整路径时未自动检索导致加载lora失败的问题
|
||||
- 修复 `easy instantIDApply` mask 未传入正确值
|
||||
- 修复 在 非a1111提示词风格下 BREAK 不生效的问题
|
||||
- Added `easy imageSplitList` - to split every N images
|
||||
- Added `easy preSamplingDiffusionADDTL` - It can modify foreground、background or blended additional prompt
|
||||
- Added `easy preSamplingNoiseIn` It can replace the `easy latentNoisy` node that needs to be fronted to achieve better noise injection
|
||||
- `easy pipeEdit` Added conditioning splicing mode selection, you can choose to replace, concat, combine, average, and set timestep range
|
||||
- Added `easy pipeEdit` - nodes that can edit pipes (including re-enterable prompts)
|
||||
- Added `easy preSamplingLayerDiffusion` and `easy kSamplerLayerDiffusion`
|
||||
- Added a convenient menu to right-click on nodes such as Loader, Presampler, Sampler, Controlnet, etc. to quickly replace nodes of the same type
|
||||
- Added `easy instantIDApplyADV` can link positive and negative
|
||||
- Fixed layerDiffusion error when batch size greater than 1
|
||||
- Fixed `easy wildcards` When LoRa is not filled in completely, LoRa is not automatically retrieved, resulting in failure to load LoRa
|
||||
- Fixed the issue that 'BREAK' non-initiation when didn't use a1111 prompt style
|
||||
- Fixed `easy instantIDApply` mask not input right
|
||||
</details>
|
||||
|
||||
<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-Yolain-Workflows?tab=readme-ov-file#2-2-instantid)
|
||||
- 修复 `easy detailerFix` 未添加到保存图片格式化扩展名可用节点列表
|
||||
- 修复 `easy XYInputs: PromptSR` 在替换负面提示词时报错
|
||||
- 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>
|
||||
|
||||
<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` 搜索框修改为不区分大小写匹配
|
||||
- `easy fullLoader` 增加 **positive**、**negative**、**latent** 输出项
|
||||
- 修复 SDXLClipModel 在 ComfyUI 修订版本号 2016[c2cb8e88] 及以上的报错(判断了版本号可兼容老版本)
|
||||
- 修复 `easy detailerFix` 批次大小大于1时生成出错
|
||||
- 修复`easy preSampling`等 latent传入后无法根据批次索引生成的问题
|
||||
- 修复 `easy svdLoader` 报错
|
||||
- 优化代码,减少了诸多冗余,提升运行速度
|
||||
- 去除中文翻译对照文本
|
||||
|
||||
(翻译对照已由 [AIGODLIKE-COMFYUI-TRANSLATION](https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation) 统一维护啦!
|
||||
首次下载或者版本较早的朋友请更新 AIGODLIKE-COMFYUI-TRANSLATION 和本节点包至最新版本。)
|
||||
- `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
|
||||
- `easy fullLoader` **positive**、**negative**、**latent** added to the output items
|
||||
- Fixed the issue that 'easy preSampling' and other similar node, latent could not be generated based on the batch index after passing in
|
||||
- Fixed `easy svdLoader` error when the positive or negative is empty
|
||||
- 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>
|
||||
|
||||
<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
|
||||
- Added `easy cascadeLoader` - stable cascade Loader
|
||||
- Added `easy preSamplingCascade` - stable cascade preSampling Settings
|
||||
- Added `easy fullCascadeKSampler` - stable cascade stage-c ksampler full
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.6</b></summary>
|
||||
|
||||
- 增加 `easy XYInputs: Checkpoint`
|
||||
- 增加 `easy XYInputs: Lora`
|
||||
- `easy seed` 增加固定种子值时可手动切换随机种
|
||||
- 修复 `easy fullLoader`等加载器切换lora时自动调整节点大小的问题
|
||||
- 去除原有ttn的图片保存逻辑并适配ComfyUI默认的图片保存格式化扩展
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.5</b></summary>
|
||||
|
||||
- 增加 `easy isSDXL`
|
||||
- `easy svdLoader` 增加提示词控制, 可配合open_clip模型进行使用
|
||||
- `easy wildcards` 增加 **populated_text** 可输出通配填充后文本
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.4</b></summary>
|
||||
|
||||
- 增加 `easy showLoaderSettingsNames` 可显示与输出加载器部件中的 模型与VAE名称
|
||||
- 增加 `easy promptList` - 提示词列表
|
||||
- 增加 `easy fooocusInpaintLoader` - Fooocus内补节点(仅支持XL模型的流程)
|
||||
- 增加 **Logic** 逻辑类节点 - 包含类型、计算、判断和转换类型等
|
||||
- 增加 `easy imageSave` - 带日期转换和宽高格式化的图像保存节点
|
||||
- 增加 `easy joinImageBatch` - 合并图像批次
|
||||
- `easy showAnything` 增加支持转换其他类型(如:tensor类型的条件、图像等)
|
||||
- `easy kSamplerInpainting` 增加 **patch** 传入值,配合Fooocus内补节点使用
|
||||
- `easy imageSave` 增加 **only_preivew**
|
||||
- `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
|
||||
- Added `easy promptList`
|
||||
- Added `easy fooocusInpaintLoader` (only the process of SDXLModel is supported)
|
||||
- Added **Logic** nodes
|
||||
- Added `easy imageSave` - Image saving node with date conversion and aspect and height formatting
|
||||
- Added `easy joinImageBatch`
|
||||
- `easy kSamplerInpainting` Added the **patch** input value to be used with the FooocusInpaintLoader node
|
||||
|
||||
- 修复 xyplot在pillow>9.5中报错
|
||||
- 修复 `easy wildcards` 在使用PS扩展插件运行时报错
|
||||
- 修复 `easy latentCompositeMaskedWithCond`
|
||||
- 修复 `easy XYInputs: ControlNet` 报错
|
||||
- 修复 `easy loraStack` **toggle** 为 disabled 时报错
|
||||
- Fixed xyplot error when with Pillow>9.5
|
||||
- Fixed `easy wildcards` An error is reported when running with the PS extension
|
||||
- Fixed `easy XYInputs: ControlNet` Error
|
||||
- Fixed `easy loraStack` error when **toggle** is disabled
|
||||
|
||||
- 修改首次安装节点包不再自动替换主题,需手动调整并刷新页面
|
||||
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.3</b></summary>
|
||||
|
||||
- 增加 `easy stylesSelector` 风格化提示词选择器
|
||||
- 增加队列进度条设置项,默认为未启用状态
|
||||
- `easy controlnetLoader` 和 `easy controlnetLoaderADV` 增加参数 **scale_soft_weights**
|
||||
- Added `easy stylesSelector`
|
||||
- Added **scale_soft_weights** in `easy controlnetLoader` and `easy controlnetLoaderADV`
|
||||
- Added the queue progress bar setting item, which is not enabled by default
|
||||
|
||||
|
||||
- 修复 `easy XYInputs: Sampler/Scheduler` 报错
|
||||
- 修复 右侧菜单 点击按钮时老是跑位的问题
|
||||
- 修复 styles 路径在其他环境报错
|
||||
- 修复 `easy comfyLoader` 读取错误
|
||||
- 修复 xyPlot 在连接 zero123 时报错
|
||||
- 修复加载器中提示词为组件时报错
|
||||
- 修复 `easy getNode` 和 `easy setNode` 加载时标题未更改
|
||||
- 修复所有采样器中存储图片使用子目录前缀不生效的问题
|
||||
- Fixed `easy XYInputs: Sampler/Scheduler` Error
|
||||
- Fixed the right menu has a problem when clicking the button
|
||||
- Fixed `easy comfyLoader` error
|
||||
- Fixed xyPlot error when connecting to zero123
|
||||
- Fixed the error message in the loader when the prompt word was component
|
||||
- Fixed `easy getNode` and `easy setNode` the title does not change when loading
|
||||
- Fixed all samplers using subdirectories to store images
|
||||
|
||||
|
||||
- 调整UI主题
|
||||
- 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>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.2</b></summary>
|
||||
|
||||
- 增加 **autocomplete** 文件夹,如果您安装了 [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts), 将在启动时合并该文件夹下的所有txt文件并覆盖到pyssss包里的autocomplete.txt文件。
|
||||
- 增加 `easy XYPlotAdvanced` 和 `easy XYInputs` 等相关节点
|
||||
- 增加 **Alt+1到9** 快捷键,可快速粘贴 Node templates 的节点预设 (对应 1到9 顺序)
|
||||
- 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)
|
||||
- Added a `📜Groups Map(EasyUse)` to the context menu.
|
||||
- An `autocomplete` folder has been added, If you have [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) installed, the txt files in that folder will be merged and overwritten to the autocomplete .txt file of the pyssss package at startup.
|
||||
|
||||
- 修复 `easy imageInsetCrop` 测量值为百分比时步进为1
|
||||
- 修复 开启 `a1111_prompt_style` 时XY图表无法使用的问题
|
||||
- 右键菜单中增加了一个 `📜Groups Map(EasyUse)`
|
||||
|
||||
- 修复在Comfy新版本中UI加载失败
|
||||
- 修复 `easy pipeToBasicPipe` 报错
|
||||
- 修改 `easy fullLoader` 和 `easy a1111Loader` 中的 **a1111_prompt_style** 默认值为 False
|
||||
- `easy XYInputs ModelMergeBlocks` 支持csv文件导入数值
|
||||
- Fixed XYPlot is not working when `a1111_prompt_style` is True
|
||||
- Fixed UI loading failure in the new version of ComfyUI
|
||||
- `easy XYInputs ModelMergeBlocks` Values can be imported from CSV files
|
||||
- Fixed `easy pipeToBasicPipe` Bug
|
||||
|
||||
- 替换了XY图生成时的字体文件
|
||||
|
||||
- 移除 `easy imageRemBg`
|
||||
- 移除包中的介绍图和工作流文件,减少包体积
|
||||
|
||||
- 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>
|
||||
|
||||
- 新增 `easy seed` - 简易随机种
|
||||
- `easy preDetailerFix` 新增了 `optional_image` 传入图像可选,如未传默认取值为pipe里的图像
|
||||
- 新增 `easy kSamplerInpainting` 用于内补潜空间的采样器
|
||||
- 新增 `easy pipeToBasicPipe` 用于转换到Impact的某些节点上
|
||||
|
||||
- 修复 `easy comfyLoader` 报错
|
||||
- 修复所有包含输出图片尺寸的节点取值方式无法批处理的问题
|
||||
- 修复 `width` 和 `height` 无法在 `easy svdLoader` 自定义的报错问题
|
||||
- 修复所有采样器预览图片的地址链接 (解决在 MACOS 系统中图片无法在采样器中预览的问题)
|
||||
- 修复 `vae_name` 在 `easy fullLoader` 和 `easy a1111Loader` 和 `easy comfyLoader` 中选择但未替换原始vae问题
|
||||
- 修复 `easy fullkSampler` 除pipe外其他输出值的报错
|
||||
- 修复 `easy hiresFix` 输入连接pipe和image、vae同时存在时报错
|
||||
- 修复 `easy fullLoader` 中 `model_override` 连接后未执行
|
||||
- 修复 因新增`easy seed` 导致action错误
|
||||
- 修复 `easy xyplot` 的字体文件路径读取错误
|
||||
- 修复 convert 到 `easy seed` 随机种无法固定的问题
|
||||
- 修复 `easy pipeIn` 值传入的报错问题
|
||||
- 修复 `easy zero123Loader` 和 `easy svdLoader` 读取模型时将模型加入到缓存中
|
||||
- 修复 `easy kSampler` `easy kSamplerTiled` `easy detailerFix` 的 `image_output` 默认值为 Preview
|
||||
- `easy fullLoader` 和 `easy a1111Loader` 新增了 `a1111_prompt_style` 参数可以重现和webui生成相同的图像,当前您需要安装 [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) 才能使用此功能
|
||||
- Fixed `easy comfyLoader` error
|
||||
- Fixed All nodes that contain the value of the image size
|
||||
- Added `easy kSamplerInpainting`
|
||||
- Added `easy pipeToBasicPipe`
|
||||
- Fixed `width` and `height` can not customize in `easy svdLoader`
|
||||
- Fixed all preview image path (Previously, it was not possible to preview the image on the Mac system)
|
||||
- Fixed `vae_name` is not working in `easy fullLoader` and `easy a1111Loader` and `easy comfyLoader`
|
||||
- Fixed `easy fullkSampler` outputs error
|
||||
- Fixed `model_override` is not working in `easy fullLoader`
|
||||
- Fixed `easy hiresFix` error
|
||||
- Fixed `easy xyplot` font file path error
|
||||
- Fixed seed that cannot be fixed when you convert `seed_num` to `easy seed`
|
||||
- Fixed `easy pipeIn` inputs bug
|
||||
- `easy preDetailerFix` have added a new parameter `optional_image`
|
||||
- Fixed `easy zero123Loader` and `easy svdLoader` model into cache.
|
||||
- Added `easy seed`
|
||||
- Fixed `image_output` default value is "Preview"
|
||||
- `easy fullLoader` and `easy a1111Loader` have added a new parameter `a1111_prompt_style`,that can reproduce the same image generated from stable-diffusion-webui on comfyui, but you need to install [ComfyUI_smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes) to use this feature in the current version
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.0.0</b></summary>
|
||||
|
||||
- 新增`easy positive` - 简易正面提示词文本
|
||||
- 新增`easy negative` - 简易负面提示词文本
|
||||
- 新增`easy wildcards` - 支持通配符和Lora选择的提示词文本
|
||||
- 新增`easy portraitMaster` - 肖像大师v2.2
|
||||
- 新增`easy loraStack` - Lora堆
|
||||
- 新增`easy fullLoader` - 完整版的加载器
|
||||
- 新增`easy zero123Loader` - 简易zero123加载器
|
||||
- 新增`easy svdLoader` - 简易svd加载器
|
||||
- 新增`easy fullkSampler` - 完整版的采样器(无分离)
|
||||
- 新增`easy hiresFix` - 支持Pipe的高清修复
|
||||
- 新增`easy predetailerFix` `easy DetailerFix` - 支持Pipe的细节修复
|
||||
- 新增`easy ultralyticsDetectorPipe` `easy samLoaderPipe` - 检测加载器(细节修复的输入项)
|
||||
- 新增`easy pipein` `easy pipeout` - Pipe的输入与输出
|
||||
- 新增`easy xyPlot` - 简易的xyplot (后续会更新更多可控参数)
|
||||
- 新增`easy imageRemoveBG` - 图像去除背景
|
||||
- 新增`easy imagePixelPerfect` - 图像完美像素
|
||||
- 新增`easy poseEditor` - 姿势编辑器
|
||||
- 新增UI主题(黑曜石)- 默认自动加载UI, 也可在设置中自行更替
|
||||
- Added `easy positive` - simple positive prompt text
|
||||
- Added `easy negative` - simple negative prompt text
|
||||
- Added `easy wildcards` - support for wildcards and hint text selected by Lora
|
||||
- Added `easy portraitMaster` - PortraitMaster v2.2
|
||||
- Added `easy loraStack` - Lora stack
|
||||
- Added `easy fullLoader` - full version of the loader
|
||||
- Added `easy zero123Loader` - simple zero123 loader
|
||||
- Added `easy svdLoader` - easy svd loader
|
||||
- Added `easy fullkSampler` - full version of the sampler (no separation)
|
||||
- Added `easy hiresFix` - support for HD repair of Pipe
|
||||
- Added `easy predetailerFix` and `easy DetailerFix` - support for Pipe detail fixing
|
||||
- Added `easy ultralyticsDetectorPipe` and `easy samLoaderPipe` - Detect loader (detail fixed input)
|
||||
- Added `easy pipein` `easy pipeout` - Pipe input and output
|
||||
- Added `easy xyPlot` - simple xyplot (more controllable parameters will be updated in the future)
|
||||
- Added `easy imageRemoveBG` - image to remove background
|
||||
- Added `easy imagePixelPerfect` - image pixel perfect
|
||||
- Added `easy poseEditor` - Pose editor
|
||||
- New UI Theme (Obsidian) - Auto-load UI by default, which can also be changed in the settings
|
||||
|
||||
- 修复 `easy globalSeed` 不生效问题
|
||||
- 修复所有的`seed_num` 因 [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) 实时更新图表导致值错乱的问题
|
||||
- 修复`easy imageSize` `easy imageSizeBySide` `easy imageSizeByLongerSide` 可作为终节点
|
||||
- 修复 `seed_num` (随机种子值) 在历史记录中读取无法一致的Bug
|
||||
- Fixed `easy globalSeed` is not working
|
||||
- Fixed an issue where all `seed_num` values were out of order due to [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) updating the chart in real time
|
||||
- Fixed `easy imageSize`, `easy imageSizeBySide`, `easy imageSizeByLongerSide` as end nodes
|
||||
- Fixed the bug that `seed_num` (random seed value) could not be read consistently in history
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><b>v0.5</b></summary>
|
||||
<summary><b>Updated at 12/14/2023</b></summary>
|
||||
|
||||
- 新增 `easy controlnetLoaderADV` 节点
|
||||
- 新增 `easy imageSizeBySide` 节点,可选输出为长边或短边
|
||||
- 新增 `easy LLLiteLoader` 节点,如果您预先安装过 kohya-ss/ControlNet-LLLite-ComfyUI 包,请将 models 里的模型文件移动至 ComfyUI\models\controlnet\ (即comfy默认的controlnet路径里,请勿修改模型的文件名,不然会读取不到)。
|
||||
- 新增 `easy imageSize` 和 `easy imageSizeByLongerSize` 输出的尺寸显示。
|
||||
- 新增 `easy showSpentTime` 节点用于展示图片推理花费时间与VAE解码花费时间。
|
||||
- `easy controlnetLoaderADV` 和 `easy controlnetLoader` 新增 `control_net` 可选传入参数
|
||||
- `easy preSampling` 和 `easy preSamplingAdvanced` 新增 `image_to_latent` 可选传入参数
|
||||
- `easy a1111Loader` 和 `easy comfyLoader` 新增 `batch_size` 传入参数
|
||||
|
||||
- 修改 `easy controlnetLoader` 到 loader 分类底下。
|
||||
- `easy a1111Loader` and `easy comfyLoader` added `batch_size` of required input parameters
|
||||
- Added the `easy controlnetLoaderADV` node
|
||||
- `easy controlnetLoaderADV` and `easy controlnetLoader` added `control_net ` of optional input parameters
|
||||
- `easy preSampling` and `easy preSamplingAdvanced` added `image_to_latent` optional input parameters
|
||||
- Added the `easy imageSizeBySide` node, which can be output as a long side or a short side
|
||||
</details>
|
||||
|
||||
## 整合参考到的相关节点包
|
||||
<details>
|
||||
<summary><b>Updated at 12/13/2023</b></summary>
|
||||
|
||||
声明: 非常尊重这些原作者们的付出,开源不易,我仅仅只是做了一些整合与优化。
|
||||
- Added the `easy LLLiteLoader` node, if you have pre-installed the kohya-ss/ControlNet-LLLite-ComfyUI package, please move the model files in the models to `ComfyUI\models\controlnet\` (i.e. in the default controlnet path of comfy, please do not change the file name of the model, otherwise it will not be read).
|
||||
- Modify `easy controlnetLoader` to the bottom of the loader category.
|
||||
- Added size display for `easy imageSize` and `easy imageSizeByLongerSize` outputs.
|
||||
</details>
|
||||
|
||||
| 节点名 (搜索名) | 相关的库 | 库相关的节点 |
|
||||
|:-------------------------------|:----------------------------------------------------------------------------|:------------------------|
|
||||
| easy setNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.SetNode |
|
||||
| easy getNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.GetNode |
|
||||
| easy bookmark | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | Bookmark 🔖 |
|
||||
| easy portraitMarker | [comfyui-portrait-master](https://github.com/florestefano1975/comfyui-portrait-master) | Portrait Master |
|
||||
| easy LLLiteLoader | [ControlNet-LLLite-ComfyUI](https://github.com/kohya-ss/ControlNet-LLLite-ComfyUI) | LLLiteLoader |
|
||||
| easy globalSeed | [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) | Global Seed (Inspire) |
|
||||
| easy preSamplingDynamicCFG | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| dynamicThresholdingFull | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| easy imageInsetCrop | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | ImageInsetCrop |
|
||||
| easy poseEditor | [ComfyUI_Custom_Nodes_AlekPet](https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet) | poseNode |
|
||||
| easy if | [ComfyUI-Logic](https://github.com/theUpsider/ComfyUI-Logic) | IfExecute |
|
||||
| easy preSamplingLayerDiffusion | [ComfyUI-layerdiffusion](https://github.com/huchenlei/ComfyUI-layerdiffusion) | LayeredDiffusionApply等 |
|
||||
| easy dynamiCrafterLoader | [ComfyUI-layerdiffusion](https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter) | Apply Dynamicrafter |
|
||||
<details>
|
||||
<summary><b>Updated at 12/11/2023</b></summary>
|
||||
- Added the `showSpentTime` node to display the time spent on image diffusion and the time spent on VAE decoding images
|
||||
</details>
|
||||
|
||||
## The relevant node package involved
|
||||
|
||||
Disclaimer: Opened source was not easy. I have a lot of respect for the contributions of these original authors. I just did some integration and optimization.
|
||||
|
||||
| Nodes Name(Search Name) | Related libraries | Library-related node |
|
||||
|:-------------------------------|:----------------------------------------------------------------------------|:-------------------------|
|
||||
| easy setNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.SetNode |
|
||||
| easy getNode | [ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) | diffus3.GetNode |
|
||||
| easy bookmark | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | Bookmark 🔖 |
|
||||
| easy portraitMarker | [comfyui-portrait-master](https://github.com/florestefano1975/comfyui-portrait-master) | Portrait Master |
|
||||
| easy LLLiteLoader | [ControlNet-LLLite-ComfyUI](https://github.com/kohya-ss/ControlNet-LLLite-ComfyUI) | LLLiteLoader |
|
||||
| easy globalSeed | [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) | Global Seed (Inspire) |
|
||||
| easy preSamplingDynamicCFG | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| dynamicThresholdingFull | [sd-dynamic-thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding) | DynamicThresholdingFull |
|
||||
| easy imageInsetCrop | [rgthree-comfy](https://github.com/rgthree/rgthree-comfy) | ImageInsetCrop |
|
||||
| easy poseEditor | [ComfyUI_Custom_Nodes_AlekPet](https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet) | poseNode |
|
||||
| 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 |
|
||||
| easy icLightApply | [ComfyUI-IC-Light](https://github.com/huchenlei/ComfyUI-IC-Light) | ICLightApply等 |
|
||||
| easy styleAlignedBatchAlign | [style_aligned_comfy](https://github.com/chrisgoringe/cg-image-picker) | styleAlignedBatchAlign |
|
||||
| easy kolorsLoader | [ComfyUI-Kolors-MZ](https://github.com/MinusZoneAI/ComfyUI-Kolors-MZ) | kolorsLoader |
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
[ComfyUI](https://github.com/comfyanonymous/ComfyUI) - 功能强大且模块化的Stable Diffusion GUI
|
||||
[ComfyUI](https://github.com/comfyanonymous/ComfyUI) - Powerful and modular Stable Diffusion GUI
|
||||
|
||||
[ComfyUI-ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager) - ComfyUI管理器
|
||||
[ComfyUI-ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager) - ComfyUI Manager
|
||||
|
||||
[tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) - 管道节点(节点束)让用户减少了不必要的连接
|
||||
[tinyterraNodes](https://github.com/TinyTerra/ComfyUI_tinyterraNodes) - Pipe nodes (node bundles) allow users to reduce unnecessary connections
|
||||
|
||||
[ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) - diffus3的获取与设置点让用户可以分离工作流构成
|
||||
[ComfyUI-extensions](https://github.com/diffus3/ComfyUI-extensions) - Diffus3 gets and sets points that allow the user to detach the composition of the workflow
|
||||
|
||||
[ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) - 常规整合包1
|
||||
[ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) - General modpack 1
|
||||
|
||||
[ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) - 常规整合包2
|
||||
[ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) - General Modpack 2
|
||||
|
||||
[ComfyUI-Logic](https://github.com/theUpsider/ComfyUI-Logic) - ComfyUI逻辑运算
|
||||
[ComfyUI-ResAdapter](https://github.com/jiaxiangc/ComfyUI-ResAdapter) - Make model generation independent of training resolution
|
||||
|
||||
[ComfyUI-ResAdapter](https://github.com/jiaxiangc/ComfyUI-ResAdapter) - 让模型生成不受训练分辨率限制
|
||||
[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - Style migration
|
||||
|
||||
[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - 风格迁移
|
||||
[ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID) - Face migration
|
||||
|
||||
[ComfyUI_InstantID](https://github.com/cubiq/ComfyUI_InstantID) - 人脸迁移
|
||||
[ComfyUI_PuLID](https://github.com/cubiq/PuLID_ComfyUI) - Face migration
|
||||
|
||||
[ComfyUI_PuLID](https://github.com/cubiq/PuLID_ComfyUI) - 人脸迁移
|
||||
[ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) - pyssss🐍
|
||||
|
||||
[ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) - pyssss 小蛇🐍脚本
|
||||
[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) - Image Preview Chooser
|
||||
|
||||
[cg-image-picker](https://github.com/chrisgoringe/cg-image-picker) - 图片选择器
|
||||
[ComfyUI_ExtraModels](https://github.com/city96/ComfyUI_ExtraModels) - DiT custom nodes
|
||||
|
||||
[ComfyUI-BrushNet](https://github.com/nullquant/ComfyUI-BrushNet) - BrushNet 内补节点
|
||||
## ☕️ Donation
|
||||
|
||||
[ComfyUI_ExtraModels](https://github.com/city96/ComfyUI_ExtraModels) - DiT架构相关节点(Pixart、混元DiT等)
|
||||
**Comfyui-Easy-Use** is an GPL-licensed open source project. In order to achieve better and sustainable development of the project, i expect to gain more backers. <br>
|
||||
If my custom nodes has added value to your day, consider indulging in a coffee to fuel it further! <br>
|
||||
💖You can support me in any of the following ways:
|
||||
|
||||
- [BiliBili](https://space.bilibili.com/1840885116)
|
||||
- [Afdian](https://afdian.com/a/yolain)
|
||||
- [Wechat / Alipay](https://github.com/user-attachments/assets/803469bd-ed6a-4fab-932d-50e5088a2d03)
|
||||
- 🪙 Wallet Address:
|
||||
- ETH: 0x01f7CEd3245CaB3891A0ec8f528178db352EaC74
|
||||
- USDT(tron): TP3AnJXkAzfebL2GKmFAvQvXgsxzivweV6
|
||||
|
||||
(This is a newly created wallet, and if it receives sponsorship, I'll use it to rent GPUs or other GPT services for better debugging and refinement of ComfyUI-Easy-Use features.)
|
||||
|
||||
## 🌟Stargazers
|
||||
|
||||
|
||||
+37
-5
@@ -1,5 +1,6 @@
|
||||
__version__ = "1.2.1"
|
||||
__version__ = "1.2.2"
|
||||
|
||||
import yaml
|
||||
import os
|
||||
import folder_paths
|
||||
import importlib
|
||||
@@ -24,7 +25,7 @@ for module_name in node_list:
|
||||
cwd_path = os.path.dirname(os.path.realpath(__file__))
|
||||
comfy_path = folder_paths.base_path
|
||||
|
||||
#Wildcards读取
|
||||
#Wildcards
|
||||
from .py.libs.wildcards import read_wildcard_dict
|
||||
wildcards_path = os.path.join(os.path.dirname(__file__), "wildcards")
|
||||
if os.path.exists(wildcards_path):
|
||||
@@ -53,8 +54,39 @@ for model in model_config:
|
||||
continue
|
||||
add_static_resource(path, path, limit=True)
|
||||
|
||||
WEB_DIRECTORY = "./web"
|
||||
# get comfyui revision
|
||||
from .py.libs.utils import compare_revision
|
||||
|
||||
new_frontend_revision = 2546
|
||||
web_default_version = 'v2' if compare_revision(new_frontend_revision) else 'v1'
|
||||
# web directory
|
||||
config_path = os.path.join(cwd_path, "config.yaml")
|
||||
if os.path.isfile(config_path):
|
||||
with open(config_path, 'r') as f:
|
||||
data = yaml.load(f, Loader=yaml.FullLoader)
|
||||
if data and "WEB_VERSION" in data:
|
||||
directory = f"web_version/{data['WEB_VERSION']}"
|
||||
with open(config_path, 'w') as f:
|
||||
yaml.dump(data, f)
|
||||
elif web_default_version != 'v1':
|
||||
if not data:
|
||||
data = {'WEB_VERSION': web_default_version}
|
||||
elif 'WEB_VERSION' not in data:
|
||||
data = {**data, 'WEB_VERSION': web_default_version}
|
||||
with open(config_path, 'w') as f:
|
||||
yaml.dump(data, f)
|
||||
directory = f"web_version/{web_default_version}"
|
||||
else:
|
||||
directory = f"web_version/v1"
|
||||
if not os.path.exists(os.path.join(cwd_path, directory)):
|
||||
print(f"web root {data['WEB_VERSION']} not found, using default")
|
||||
directory = f"web_version/{web_default_version}"
|
||||
WEB_DIRECTORY = directory
|
||||
else:
|
||||
directory = f"web_version/{web_default_version}"
|
||||
WEB_DIRECTORY = directory
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', "WEB_DIRECTORY"]
|
||||
|
||||
|
||||
print(f'\033[34mComfy-Easy-Use v{__version__}: \033[92mLoaded\033[0m')
|
||||
print(f'\033[34m[ComfyUI-Easy-Use] server: \033[0mv{__version__} \033[92mLoaded\033[0m')
|
||||
print(f'\033[34m[ComfyUI-Easy-Use] web root: \033[0m{os.path.join(cwd_path, directory)} \033[92mLoaded\033[0m')
|
||||
|
||||
@@ -7,7 +7,6 @@ import folder_paths
|
||||
from folder_paths import get_directory_by_type
|
||||
from server import PromptServer
|
||||
from .config import RESOURCES_DIR, FOOOCUS_STYLES_DIR, FOOOCUS_STYLES_SAMPLES
|
||||
from .logic import ConvertAnything
|
||||
from .libs.model import easyModelManager
|
||||
from .libs.utils import getMetadata, cleanGPUUsedForce, get_local_filepath
|
||||
from .libs.cache import remove_cache
|
||||
@@ -123,18 +122,6 @@ async def getStylesImage(request):
|
||||
return web.Response(text=FOOOCUS_STYLES_SAMPLES + name + '.jpg')
|
||||
return web.Response(status=400)
|
||||
|
||||
# convert type
|
||||
@PromptServer.instance.routes.post("/easyuse/convert")
|
||||
async def convertType(request):
|
||||
post = await request.post()
|
||||
type = post.get('type')
|
||||
if type:
|
||||
ConvertAnything.RETURN_TYPES = (type.upper(),)
|
||||
ConvertAnything.RETURN_NAMES = (type,)
|
||||
return web.Response(status=200)
|
||||
else:
|
||||
return web.Response(status=400)
|
||||
|
||||
# get models lists
|
||||
@PromptServer.instance.routes.get("/easyuse/models/list")
|
||||
async def getModelsList(request):
|
||||
@@ -150,11 +137,15 @@ async def getModelsList(request):
|
||||
# get models thumbnails
|
||||
@PromptServer.instance.routes.get("/easyuse/models/thumbnail")
|
||||
async def getModelsThumbnail(request):
|
||||
limit = 500
|
||||
if "limit" in request.rel_url.query:
|
||||
limit = request.rel_url.query.get("limit")
|
||||
limit = int(limit)
|
||||
checkpoints = folder_paths.get_filename_list("checkpoints_thumb")
|
||||
loras = folder_paths.get_filename_list("loras_thumb")
|
||||
checkpoints_full = []
|
||||
loras_full = []
|
||||
if len(checkpoints) + len(loras) >= 500:
|
||||
if len(checkpoints) + len(loras) >= limit:
|
||||
return web.Response(status=400)
|
||||
for index, i in enumerate(checkpoints):
|
||||
full_path = folder_paths.get_full_path('checkpoints_thumb', str(i))
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
#credit to comfyanonymous for this module
|
||||
#from https://github.com/comfyanonymous/ComfyUI_bitsandbytes_NF4
|
||||
import comfy.ops
|
||||
import torch
|
||||
import folder_paths
|
||||
from ..libs.utils import install_package
|
||||
|
||||
try:
|
||||
from bitsandbytes.nn.modules import Params4bit, QuantState
|
||||
except ImportError:
|
||||
Params4bit = torch.nn.Parameter
|
||||
raise ImportError("Please install bitsandbytes>=0.43.3")
|
||||
|
||||
def functional_linear_4bits(x, weight, bias):
|
||||
try:
|
||||
install_package("bitsandbytes", "0.43.3", True, "0.43.3")
|
||||
import bitsandbytes as bnb
|
||||
except ImportError:
|
||||
raise ImportError("Please install bitsandbytes>=0.43.3")
|
||||
|
||||
out = bnb.matmul_4bit(x, weight.t(), bias=bias, quant_state=weight.quant_state)
|
||||
out = out.to(x)
|
||||
return out
|
||||
|
||||
|
||||
def copy_quant_state(state, device: torch.device = None):
|
||||
if state is None:
|
||||
return None
|
||||
|
||||
device = device or state.absmax.device
|
||||
|
||||
state2 = (
|
||||
QuantState(
|
||||
absmax=state.state2.absmax.to(device),
|
||||
shape=state.state2.shape,
|
||||
code=state.state2.code.to(device),
|
||||
blocksize=state.state2.blocksize,
|
||||
quant_type=state.state2.quant_type,
|
||||
dtype=state.state2.dtype,
|
||||
)
|
||||
if state.nested
|
||||
else None
|
||||
)
|
||||
|
||||
return QuantState(
|
||||
absmax=state.absmax.to(device),
|
||||
shape=state.shape,
|
||||
code=state.code.to(device),
|
||||
blocksize=state.blocksize,
|
||||
quant_type=state.quant_type,
|
||||
dtype=state.dtype,
|
||||
offset=state.offset.to(device) if state.nested else None,
|
||||
state2=state2,
|
||||
)
|
||||
|
||||
|
||||
class ForgeParams4bit(Params4bit):
|
||||
|
||||
def to(self, *args, **kwargs):
|
||||
device, dtype, non_blocking, convert_to_format = torch._C._nn._parse_to(*args, **kwargs)
|
||||
if device is not None and device.type == "cuda" and not self.bnb_quantized:
|
||||
return self._quantize(device)
|
||||
else:
|
||||
n = ForgeParams4bit(
|
||||
torch.nn.Parameter.to(self, device=device, dtype=dtype, non_blocking=non_blocking),
|
||||
requires_grad=self.requires_grad,
|
||||
quant_state=copy_quant_state(self.quant_state, device),
|
||||
blocksize=self.blocksize,
|
||||
compress_statistics=self.compress_statistics,
|
||||
quant_type=self.quant_type,
|
||||
quant_storage=self.quant_storage,
|
||||
bnb_quantized=self.bnb_quantized,
|
||||
module=self.module
|
||||
)
|
||||
self.module.quant_state = n.quant_state
|
||||
self.data = n.data
|
||||
self.quant_state = n.quant_state
|
||||
return n
|
||||
|
||||
class ForgeLoader4Bit(torch.nn.Module):
|
||||
def __init__(self, *, device, dtype, quant_type, **kwargs):
|
||||
super().__init__()
|
||||
self.dummy = torch.nn.Parameter(torch.empty(1, device=device, dtype=dtype))
|
||||
self.weight = None
|
||||
self.quant_state = None
|
||||
self.bias = None
|
||||
self.quant_type = quant_type
|
||||
|
||||
def _save_to_state_dict(self, destination, prefix, keep_vars):
|
||||
super()._save_to_state_dict(destination, prefix, keep_vars)
|
||||
quant_state = getattr(self.weight, "quant_state", None)
|
||||
if quant_state is not None:
|
||||
for k, v in quant_state.as_dict(packed=True).items():
|
||||
destination[prefix + "weight." + k] = v if keep_vars else v.detach()
|
||||
return
|
||||
|
||||
def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs):
|
||||
quant_state_keys = {k[len(prefix + "weight."):] for k in state_dict.keys() if k.startswith(prefix + "weight.")}
|
||||
|
||||
if any('bitsandbytes' in k for k in quant_state_keys):
|
||||
quant_state_dict = {k: state_dict[prefix + "weight." + k] for k in quant_state_keys}
|
||||
|
||||
self.weight = ForgeParams4bit().from_prequantized(
|
||||
data=state_dict[prefix + 'weight'],
|
||||
quantized_stats=quant_state_dict,
|
||||
requires_grad=False,
|
||||
device=self.dummy.device,
|
||||
module=self
|
||||
)
|
||||
self.quant_state = self.weight.quant_state
|
||||
|
||||
if prefix + 'bias' in state_dict:
|
||||
self.bias = torch.nn.Parameter(state_dict[prefix + 'bias'].to(self.dummy))
|
||||
|
||||
del self.dummy
|
||||
elif hasattr(self, 'dummy'):
|
||||
if prefix + 'weight' in state_dict:
|
||||
self.weight = ForgeParams4bit(
|
||||
state_dict[prefix + 'weight'].to(self.dummy),
|
||||
requires_grad=False,
|
||||
compress_statistics=True,
|
||||
quant_type=self.quant_type,
|
||||
quant_storage=torch.uint8,
|
||||
module=self,
|
||||
)
|
||||
self.quant_state = self.weight.quant_state
|
||||
|
||||
if prefix + 'bias' in state_dict:
|
||||
self.bias = torch.nn.Parameter(state_dict[prefix + 'bias'].to(self.dummy))
|
||||
|
||||
del self.dummy
|
||||
else:
|
||||
super()._load_from_state_dict(state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs)
|
||||
|
||||
current_device = None
|
||||
current_dtype = None
|
||||
current_manual_cast_enabled = False
|
||||
current_bnb_dtype = None
|
||||
|
||||
class OPS(comfy.ops.manual_cast):
|
||||
class Linear(ForgeLoader4Bit):
|
||||
def __init__(self, *args, device=None, dtype=None, **kwargs):
|
||||
super().__init__(device=device, dtype=dtype, quant_type=current_bnb_dtype)
|
||||
self.parameters_manual_cast = current_manual_cast_enabled
|
||||
|
||||
def forward(self, x):
|
||||
self.weight.quant_state = self.quant_state
|
||||
|
||||
if self.bias is not None and self.bias.dtype != x.dtype:
|
||||
# Maybe this can also be set to all non-bnb ops since the cost is very low.
|
||||
# And it only invokes one time, and most linear does not have bias
|
||||
self.bias.data = self.bias.data.to(x.dtype)
|
||||
|
||||
if not self.parameters_manual_cast:
|
||||
return functional_linear_4bits(x, self.weight, self.bias)
|
||||
elif not self.weight.bnb_quantized:
|
||||
assert x.device.type == 'cuda', 'BNB Must Use CUDA as Computation Device!'
|
||||
layer_original_device = self.weight.device
|
||||
self.weight = self.weight._quantize(x.device)
|
||||
bias = self.bias.to(x.device) if self.bias is not None else None
|
||||
out = functional_linear_4bits(x, self.weight, bias)
|
||||
self.weight = self.weight.to(layer_original_device)
|
||||
return out
|
||||
else:
|
||||
weight, bias, signal = weights_manual_cast(self, x, skip_weight_dtype=True, skip_bias_dtype=True)
|
||||
with main_stream_worker(weight, bias, signal):
|
||||
return functional_linear_4bits(x, weight, bias)
|
||||
@@ -380,7 +380,7 @@ class EmbeddingLayerWithFixes(nn.Module):
|
||||
|
||||
return torch.cat(new_embedding, dim=0)
|
||||
|
||||
def forward(self, input_ids: torch.Tensor, external_embeddings: Optional[List[dict]] = None):
|
||||
def forward(self, input_ids: torch.Tensor, external_embeddings: Optional[List[dict]] = None, out_dtype = None):
|
||||
"""The forward function.
|
||||
|
||||
Args:
|
||||
@@ -397,7 +397,7 @@ class EmbeddingLayerWithFixes(nn.Module):
|
||||
input_ids = input_ids.unsqueeze(0)
|
||||
|
||||
if external_embeddings is None and not self.external_embeddings:
|
||||
return self.wrapped(input_ids)
|
||||
return self.wrapped(input_ids, out_dtype=out_dtype)
|
||||
|
||||
input_ids_fwd = self.replace_input_ids(input_ids)
|
||||
inputs_embeds = self.wrapped(input_ids_fwd)
|
||||
@@ -416,7 +416,7 @@ class EmbeddingLayerWithFixes(nn.Module):
|
||||
new_embedding = self.replace_embeddings(input_id, new_embedding, external_embedding)
|
||||
vecs.append(new_embedding)
|
||||
|
||||
return torch.stack(vecs)
|
||||
return torch.stack(vecs).to(out_dtype)
|
||||
|
||||
|
||||
def add_tokens(
|
||||
|
||||
@@ -118,7 +118,6 @@ def load_pixart(model_path, model_conf=None):
|
||||
model,
|
||||
load_device=load_device,
|
||||
offload_device=offload_device,
|
||||
current_device="cpu",
|
||||
)
|
||||
return model_patcher
|
||||
|
||||
|
||||
+257
-207
@@ -81,7 +81,6 @@ class wildcardsPrompt:
|
||||
RETURN_TYPES = ("STRING", "STRING")
|
||||
RETURN_NAMES = ("text", "populated_text")
|
||||
OUTPUT_IS_LIST = (True, True)
|
||||
OUTPUT_NODE = True
|
||||
FUNCTION = "main"
|
||||
|
||||
CATEGORY = "EasyUse/Prompt"
|
||||
@@ -162,7 +161,6 @@ class stylesPromptSelector:
|
||||
|
||||
CATEGORY = 'EasyUse/Prompt'
|
||||
FUNCTION = 'run'
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def run(self, styles, positive='', negative='', prompt=None, extra_pnginfo=None, my_unique_id=None):
|
||||
values = []
|
||||
@@ -667,7 +665,6 @@ class latentCompositeMaskedWithCond:
|
||||
RETURN_TYPES = ("PIPE_LINE", "LATENT", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "latent", "conditioning",)
|
||||
FUNCTION = "run"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
CATEGORY = "EasyUse/Latent"
|
||||
|
||||
@@ -805,8 +802,6 @@ class easySeed:
|
||||
|
||||
CATEGORY = "EasyUse/Seed"
|
||||
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def doit(self, seed=0, prompt=None, extra_pnginfo=None, my_unique_id=None):
|
||||
return seed,
|
||||
|
||||
@@ -940,7 +935,7 @@ class fullLoader:
|
||||
# Conditioning add controlnet
|
||||
if optional_controlnet_stack is not None and len(optional_controlnet_stack) > 0:
|
||||
for controlnet in optional_controlnet_stack:
|
||||
positive_embeddings_final, negative_embeddings_final = easyControlnet().apply(controlnet[0], controlnet[5], positive_embeddings_final, negative_embeddings_final, controlnet[1], start_percent=controlnet[2], end_percent=controlnet[3], control_net=None, scale_soft_weights=controlnet[4], mask=None, easyCache=easyCache, use_cache=True, model=model)
|
||||
positive_embeddings_final, negative_embeddings_final = easyControlnet().apply(controlnet[0], controlnet[5], positive_embeddings_final, negative_embeddings_final, controlnet[1], start_percent=controlnet[2], end_percent=controlnet[3], control_net=None, scale_soft_weights=controlnet[4], mask=None, easyCache=easyCache, use_cache=True, model=model, vae=vae)
|
||||
|
||||
log_node_warn("加载完毕...")
|
||||
pipe = {
|
||||
@@ -1896,6 +1891,7 @@ class kolorsLoader:
|
||||
log_node_warn("处理完毕...")
|
||||
pipe = {
|
||||
"model": model,
|
||||
"chatglm3_model": chatglm3_model,
|
||||
"positive": positive_embeddings_final,
|
||||
"negative": negative_embeddings_final,
|
||||
"vae": vae,
|
||||
@@ -1929,9 +1925,62 @@ class kolorsLoader:
|
||||
|
||||
return (chatglm3_model, None, None)
|
||||
|
||||
# Flux Loader
|
||||
class fluxLoader(fullLoader):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
checkpoints = folder_paths.get_filename_list("checkpoints")
|
||||
loras = ["None"] + folder_paths.get_filename_list("loras")
|
||||
return {
|
||||
"required": {
|
||||
"ckpt_name": (checkpoints,),
|
||||
"vae_name": (["Baked VAE"] + folder_paths.get_filename_list("vae"),),
|
||||
"lora_name": (loras,),
|
||||
"lora_model_strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||
"lora_clip_strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||
"resolution": (resolution_strings, {"default": "1024 x 1024"}),
|
||||
"empty_latent_width": ("INT", {"default": 1024, "min": 64, "max": MAX_RESOLUTION, "step": 8}),
|
||||
"empty_latent_height": ("INT", {"default": 1024, "min": 64, "max": MAX_RESOLUTION, "step": 8}),
|
||||
|
||||
"positive": ("STRING", {"default": "", "placeholder": "Positive", "multiline": True}),
|
||||
|
||||
"batch_size": ("INT", {"default": 1, "min": 1, "max": 64}),
|
||||
},
|
||||
"optional": {
|
||||
"model_override": ("MODEL",),
|
||||
"clip_override": ("CLIP",),
|
||||
"vae_override": ("VAE",),
|
||||
"optional_lora_stack": ("LORA_STACK",),
|
||||
"optional_controlnet_stack": ("CONTROL_NET_STACK",),
|
||||
},
|
||||
"hidden": {"prompt": "PROMPT", "my_unique_id": "UNIQUE_ID"}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "MODEL", "VAE")
|
||||
RETURN_NAMES = ("pipe", "model", "vae")
|
||||
|
||||
FUNCTION = "fluxloader"
|
||||
CATEGORY = "EasyUse/Loaders"
|
||||
|
||||
def fluxloader(self, ckpt_name, vae_name,
|
||||
lora_name, lora_model_strength, lora_clip_strength,
|
||||
resolution, empty_latent_width, empty_latent_height,
|
||||
positive, batch_size, model_override=None, clip_override=None, vae_override=None, optional_lora_stack=None, optional_controlnet_stack=None,
|
||||
a1111_prompt_style=False, prompt=None,
|
||||
my_unique_id=None):
|
||||
|
||||
return super().adv_pipeloader(ckpt_name, 'Default', vae_name, 0,
|
||||
lora_name, lora_model_strength, lora_clip_strength,
|
||||
resolution, empty_latent_width, empty_latent_height,
|
||||
positive, 'none', 'comfy',
|
||||
'', 'none', 'comfy',
|
||||
batch_size, model_override, clip_override, vae_override, optional_lora_stack=optional_lora_stack,
|
||||
optional_controlnet_stack=optional_controlnet_stack,
|
||||
a1111_prompt_style=a1111_prompt_style, prompt=prompt,
|
||||
my_unique_id=my_unique_id)
|
||||
|
||||
|
||||
# Dit Loader
|
||||
from .dit.utils import string_to_dtype
|
||||
from .dit.pixArt.config import pixart_conf, pixart_res
|
||||
|
||||
class pixArtLoader:
|
||||
@@ -2194,14 +2243,13 @@ class controlnetSimple:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "positive", "negative")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "controlnetApply"
|
||||
CATEGORY = "EasyUse/Loaders"
|
||||
|
||||
def controlnetApply(self, pipe, image, control_net_name, control_net=None, strength=1, scale_soft_weights=1, union_type=None):
|
||||
|
||||
positive, negative = easyControlnet().apply(control_net_name, image, pipe["positive"], pipe["negative"], strength, 0, 1, control_net, scale_soft_weights, mask=None, easyCache=easyCache, model=pipe['model'])
|
||||
positive, negative = easyControlnet().apply(control_net_name, image, pipe["positive"], pipe["negative"], strength, 0, 1, control_net, scale_soft_weights, mask=None, easyCache=easyCache, model=pipe['model'], vae=pipe['vae'])
|
||||
|
||||
new_pipe = {
|
||||
"model": pipe['model'],
|
||||
@@ -2243,7 +2291,6 @@ class controlnetAdvanced:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "positive", "negative")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "controlnetApply"
|
||||
CATEGORY = "EasyUse/Loaders"
|
||||
@@ -2251,7 +2298,7 @@ class controlnetAdvanced:
|
||||
|
||||
def controlnetApply(self, pipe, image, control_net_name, control_net=None, strength=1, start_percent=0, end_percent=1, scale_soft_weights=1):
|
||||
positive, negative = easyControlnet().apply(control_net_name, image, pipe["positive"], pipe["negative"],
|
||||
strength, start_percent, end_percent, control_net, scale_soft_weights, union_type=None, mask=None, easyCache=easyCache, model=pipe['model'])
|
||||
strength, start_percent, end_percent, control_net, scale_soft_weights, union_type=None, mask=None, easyCache=easyCache, model=pipe['model'], vae=pipe['vae'])
|
||||
|
||||
new_pipe = {
|
||||
"model": pipe['model'],
|
||||
@@ -2261,7 +2308,7 @@ class controlnetAdvanced:
|
||||
"clip": pipe['clip'],
|
||||
|
||||
"samples": pipe["samples"],
|
||||
"images": pipe["images"],
|
||||
"images": image,
|
||||
"seed": 0,
|
||||
|
||||
"loader_settings": pipe["loader_settings"]
|
||||
@@ -2295,7 +2342,6 @@ class controlnetPlusPlus:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "positive", "negative")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "controlnetApply"
|
||||
CATEGORY = "EasyUse/Loaders"
|
||||
@@ -2385,8 +2431,6 @@ class LLLiteLoader:
|
||||
#---------------------------------------------------------------Inpaint 开始----------------------------------------------------------------------#
|
||||
|
||||
# FooocusInpaint
|
||||
from .libs.fooocus import InpaintHead, InpaintWorker
|
||||
|
||||
class applyFooocusInpaint:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -2405,7 +2449,7 @@ class applyFooocusInpaint:
|
||||
FUNCTION = "apply"
|
||||
|
||||
def apply(self, model, latent, head, patch):
|
||||
|
||||
from .fooocus import InpaintHead, InpaintWorker
|
||||
head_file = get_local_filepath(FOOOCUS_INPAINT_HEAD[head]["model_url"], INPAINT_DIR)
|
||||
inpaint_head_model = InpaintHead()
|
||||
sd = torch.load(head_file, map_location='cpu')
|
||||
@@ -2724,7 +2768,6 @@ class icLightApply:
|
||||
RETURN_TYPES = ("MODEL", "IMAGE")
|
||||
RETURN_NAMES = ("model", "lighting_image")
|
||||
FUNCTION = "apply"
|
||||
OUTPUT_NODE = True
|
||||
CATEGORY = "EasyUse/Adapter"
|
||||
|
||||
def batch(self, image1, image2):
|
||||
@@ -3670,7 +3713,6 @@ class instantIDApply(instantID):
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "MODEL", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "model", "positive", "negative")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "apply"
|
||||
CATEGORY = "EasyUse/Adapter"
|
||||
@@ -3718,7 +3760,6 @@ class instantIDApplyAdvanced(instantID):
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", "MODEL", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("pipe", "model", "positive", "negative")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "apply_advanced"
|
||||
CATEGORY = "EasyUse/Adapter"
|
||||
@@ -3863,7 +3904,6 @@ class samplerSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", )
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -3944,7 +3984,6 @@ class samplerSettingsAdvanced:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", )
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4030,7 +4069,6 @@ class samplerSettingsNoiseIn:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", )
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4194,86 +4232,10 @@ class samplerCustomSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE", )
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
|
||||
def ip2p(self, positive, negative, vae=None, pixels=None, latent=None):
|
||||
if latent is not None:
|
||||
concat_latent = latent
|
||||
else:
|
||||
x = (pixels.shape[1] // 8) * 8
|
||||
y = (pixels.shape[2] // 8) * 8
|
||||
|
||||
if pixels.shape[1] != x or pixels.shape[2] != y:
|
||||
x_offset = (pixels.shape[1] % 8) // 2
|
||||
y_offset = (pixels.shape[2] % 8) // 2
|
||||
pixels = pixels[:, x_offset:x + x_offset, y_offset:y + y_offset, :]
|
||||
|
||||
concat_latent = vae.encode(pixels)
|
||||
|
||||
out_latent = {}
|
||||
out_latent["samples"] = torch.zeros_like(concat_latent)
|
||||
|
||||
out = []
|
||||
for conditioning in [positive, negative]:
|
||||
c = []
|
||||
for t in conditioning:
|
||||
d = t[1].copy()
|
||||
d["concat_latent_image"] = concat_latent
|
||||
n = [t[0], d]
|
||||
c.append(n)
|
||||
out.append(c)
|
||||
return (out[0], out[1], out_latent)
|
||||
|
||||
def get_inversed_euler_sampler(self):
|
||||
@torch.no_grad()
|
||||
def sample_inversed_euler(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0.,
|
||||
s_tmax=float('inf'), s_noise=1.):
|
||||
"""Implements Algorithm 2 (Euler steps) from Karras et al. (2022)."""
|
||||
extra_args = {} if extra_args is None else extra_args
|
||||
s_in = x.new_ones([x.shape[0]])
|
||||
for i in trange(1, len(sigmas), disable=disable):
|
||||
sigma_in = sigmas[i - 1]
|
||||
|
||||
if i == 1:
|
||||
sigma_t = sigmas[i]
|
||||
else:
|
||||
sigma_t = sigma_in
|
||||
|
||||
denoised = model(x, sigma_t * s_in, **extra_args)
|
||||
|
||||
if i == 1:
|
||||
d = (x - denoised) / (2 * sigmas[i])
|
||||
else:
|
||||
d = (x - denoised) / sigmas[i - 1]
|
||||
|
||||
dt = sigmas[i] - sigmas[i - 1]
|
||||
x = x + d * dt
|
||||
if callback is not None:
|
||||
callback(
|
||||
{'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
|
||||
return x / sigmas[-1]
|
||||
|
||||
ksampler = comfy.samplers.KSAMPLER(sample_inversed_euler)
|
||||
return (ksampler,)
|
||||
|
||||
def get_custom_cls(self, sampler_name):
|
||||
try:
|
||||
cls = custom_samplers.__dict__[sampler_name]
|
||||
return cls()
|
||||
except:
|
||||
raise Exception(f"Custom sampler {sampler_name} not found, Please updated your ComfyUI")
|
||||
|
||||
def add_model_patch_option(self, model):
|
||||
if 'transformer_options' not in model.model_options:
|
||||
model.model_options['transformer_options'] = {}
|
||||
to = model.model_options['transformer_options']
|
||||
if "model_patch" not in to:
|
||||
to["model_patch"] = {}
|
||||
return to
|
||||
|
||||
def settings(self, pipe, guider, cfg, cfg_negative, sampler_name, scheduler, coeff, 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):
|
||||
|
||||
# 图生图转换
|
||||
@@ -4282,60 +4244,6 @@ class samplerCustomSettings:
|
||||
positive = pipe['positive']
|
||||
negative = pipe['negative']
|
||||
batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1
|
||||
_guider, sigmas = None, None
|
||||
|
||||
# sigmas
|
||||
if optional_sigmas is not None:
|
||||
sigmas = optional_sigmas
|
||||
else:
|
||||
match scheduler:
|
||||
case 'vp':
|
||||
sigmas, = self.get_custom_cls('VPScheduler').get_sigmas(steps, beta_d, beta_min, eps_s)
|
||||
case 'karrasADV':
|
||||
sigmas, = self.get_custom_cls('KarrasScheduler').get_sigmas(steps, sigma_max, sigma_min, rho)
|
||||
case 'exponentialADV':
|
||||
sigmas, = self.get_custom_cls('ExponentialScheduler').get_sigmas(steps, sigma_max, sigma_min)
|
||||
case 'polyExponential':
|
||||
sigmas, = self.get_custom_cls('PolyexponentialScheduler').get_sigmas(steps, sigma_max, sigma_min,
|
||||
rho)
|
||||
case 'sdturbo':
|
||||
sigmas, = self.get_custom_cls('SDTurboScheduler').get_sigmas(model, steps, denoise)
|
||||
case 'alignYourSteps':
|
||||
model_type = get_sd_version(model)
|
||||
if model_type == 'unknown':
|
||||
model_type = 'sdxl'
|
||||
# raise Exception("This Model not supported")
|
||||
sigmas, = alignYourStepsScheduler().get_sigmas(model_type.upper(), steps, denoise)
|
||||
case 'gits':
|
||||
sigmas, = gitsScheduler().get_sigmas(coeff, steps, denoise)
|
||||
case _:
|
||||
sigmas, = self.get_custom_cls('BasicScheduler').get_sigmas(model, scheduler, steps, denoise)
|
||||
|
||||
# filp_sigmas
|
||||
if flip_sigmas:
|
||||
sigmas, = self.get_custom_cls('FlipSigmas').get_sigmas(sigmas)
|
||||
|
||||
#######################################################################################
|
||||
# brushnet
|
||||
to = None
|
||||
transformer_options = model.model_options['transformer_options'] if "transformer_options" in model.model_options else {}
|
||||
if 'model_patch' in transformer_options and 'brushnet' in transformer_options['model_patch']:
|
||||
to = self.add_model_patch_option(model)
|
||||
mp = to['model_patch']
|
||||
if isinstance(model.model.model_config, comfy.supported_models.SD15):
|
||||
mp['SDXL'] = False
|
||||
elif isinstance(model.model.model_config, comfy.supported_models.SDXL):
|
||||
mp['SDXL'] = True
|
||||
else:
|
||||
print('Base model type: ', type(model.model.model_config))
|
||||
raise Exception("Unsupported model type: ", type(model.model.model_config))
|
||||
|
||||
mp['all_sigmas'] = sigmas
|
||||
mp['unet'] = model.model.diffusion_model
|
||||
mp['step'] = 0
|
||||
mp['total_steps'] = 1
|
||||
#
|
||||
#######################################################################################
|
||||
|
||||
if image_to_latent is not None:
|
||||
_, height, width, _ = image_to_latent.shape
|
||||
@@ -4361,33 +4269,11 @@ class samplerCustomSettings:
|
||||
samples = pipe["samples"]
|
||||
images = pipe["images"]
|
||||
|
||||
# guider
|
||||
if guider == 'CFG':
|
||||
_guider, = self.get_custom_cls('CFGGuider').get_guider(model, positive, negative, cfg)
|
||||
elif guider in ['DualCFG', 'IP2P+DualCFG']:
|
||||
_guider, = self.get_custom_cls('DualCFGGuider').get_guider(model, positive, middle, negative, cfg, cfg_negative)
|
||||
else:
|
||||
_guider, = self.get_custom_cls('BasicGuider').get_guider(model, positive)
|
||||
|
||||
# sampler
|
||||
if optional_sampler:
|
||||
sampler = optional_sampler
|
||||
else:
|
||||
if sampler_name == 'inversed_euler':
|
||||
sampler, = self.get_inversed_euler_sampler()
|
||||
else:
|
||||
sampler, = self.get_custom_cls('KSamplerSelect').get_sampler(sampler_name)
|
||||
|
||||
# noise
|
||||
if add_noise == 'disable':
|
||||
noise, = self.get_custom_cls('DisableNoise').get_noise()
|
||||
else:
|
||||
noise, = self.get_custom_cls('RandomNoise').get_noise(seed)
|
||||
|
||||
new_pipe = {
|
||||
"model": pipe['model'],
|
||||
"positive": pipe['positive'],
|
||||
"negative": pipe['negative'],
|
||||
"model": model,
|
||||
"positive": positive,
|
||||
"negative": negative,
|
||||
"vae": pipe['vae'],
|
||||
"clip": pipe['clip'],
|
||||
|
||||
@@ -4397,17 +4283,27 @@ class samplerCustomSettings:
|
||||
|
||||
"loader_settings": {
|
||||
**pipe["loader_settings"],
|
||||
"middle": pipe['negative'],
|
||||
"steps": steps,
|
||||
"cfg": cfg,
|
||||
"cfg_negative": cfg_negative,
|
||||
"sampler_name": sampler_name,
|
||||
"scheduler": scheduler,
|
||||
"denoise": denoise,
|
||||
"add_noise": add_noise,
|
||||
"custom": {
|
||||
"noise": noise,
|
||||
"guider": _guider,
|
||||
"sampler": sampler,
|
||||
"sigmas": sigmas,
|
||||
}
|
||||
"guider": guider,
|
||||
"coeff": coeff,
|
||||
"sigma_max": sigma_max,
|
||||
"sigma_min": sigma_min,
|
||||
"rho": rho,
|
||||
"beta_d": beta_d,
|
||||
"beta_min": beta_min,
|
||||
"eps_s": beta_min,
|
||||
"flip_sigmas": flip_sigmas
|
||||
},
|
||||
"optional_sampler": optional_sampler,
|
||||
"optional_sigmas": optional_sigmas
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4444,7 +4340,6 @@ class sdTurboSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE",)
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4542,7 +4437,6 @@ class cascadeSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE",)
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4650,7 +4544,6 @@ class layerDiffusionSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE",)
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4751,7 +4644,6 @@ class layerDiffusionSettingsADDTL:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE",)
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4813,7 +4705,6 @@ class dynamicCFGSettings:
|
||||
|
||||
RETURN_TYPES = ("PIPE_LINE",)
|
||||
RETURN_NAMES = ("pipe",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "settings"
|
||||
CATEGORY = "EasyUse/PreSampling"
|
||||
@@ -4967,6 +4858,176 @@ class samplerFull:
|
||||
FUNCTION = "run"
|
||||
CATEGORY = "EasyUse/Sampler"
|
||||
|
||||
def ip2p(self, positive, negative, vae=None, pixels=None, latent=None):
|
||||
if latent is not None:
|
||||
concat_latent = latent
|
||||
else:
|
||||
x = (pixels.shape[1] // 8) * 8
|
||||
y = (pixels.shape[2] // 8) * 8
|
||||
|
||||
if pixels.shape[1] != x or pixels.shape[2] != y:
|
||||
x_offset = (pixels.shape[1] % 8) // 2
|
||||
y_offset = (pixels.shape[2] % 8) // 2
|
||||
pixels = pixels[:, x_offset:x + x_offset, y_offset:y + y_offset, :]
|
||||
|
||||
concat_latent = vae.encode(pixels)
|
||||
|
||||
out_latent = {}
|
||||
out_latent["samples"] = torch.zeros_like(concat_latent)
|
||||
|
||||
out = []
|
||||
for conditioning in [positive, negative]:
|
||||
c = []
|
||||
for t in conditioning:
|
||||
d = t[1].copy()
|
||||
d["concat_latent_image"] = concat_latent
|
||||
n = [t[0], d]
|
||||
c.append(n)
|
||||
out.append(c)
|
||||
return (out[0], out[1], out_latent)
|
||||
|
||||
def get_inversed_euler_sampler(self):
|
||||
@torch.no_grad()
|
||||
def sample_inversed_euler(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0.,s_tmax=float('inf'), s_noise=1.):
|
||||
"""Implements Algorithm 2 (Euler steps) from Karras et al. (2022)."""
|
||||
extra_args = {} if extra_args is None else extra_args
|
||||
s_in = x.new_ones([x.shape[0]])
|
||||
for i in trange(1, len(sigmas), disable=disable):
|
||||
sigma_in = sigmas[i - 1]
|
||||
|
||||
if i == 1:
|
||||
sigma_t = sigmas[i]
|
||||
else:
|
||||
sigma_t = sigma_in
|
||||
|
||||
denoised = model(x, sigma_t * s_in, **extra_args)
|
||||
|
||||
if i == 1:
|
||||
d = (x - denoised) / (2 * sigmas[i])
|
||||
else:
|
||||
d = (x - denoised) / sigmas[i - 1]
|
||||
|
||||
dt = sigmas[i] - sigmas[i - 1]
|
||||
x = x + d * dt
|
||||
if callback is not None:
|
||||
callback(
|
||||
{'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
|
||||
return x / sigmas[-1]
|
||||
|
||||
ksampler = comfy.samplers.KSAMPLER(sample_inversed_euler)
|
||||
return (ksampler,)
|
||||
|
||||
def get_custom_cls(self, sampler_name):
|
||||
try:
|
||||
cls = custom_samplers.__dict__[sampler_name]
|
||||
return cls()
|
||||
except:
|
||||
raise Exception(f"Custom sampler {sampler_name} not found, Please updated your ComfyUI")
|
||||
|
||||
def add_model_patch_option(self, model):
|
||||
if 'transformer_options' not in model.model_options:
|
||||
model.model_options['transformer_options'] = {}
|
||||
to = model.model_options['transformer_options']
|
||||
if "model_patch" not in to:
|
||||
to["model_patch"] = {}
|
||||
return to
|
||||
|
||||
def get_sampler_custom(self, model, positive, negative, seed, loader_settings):
|
||||
_guider = None
|
||||
middle = loader_settings['middle'] if "middle" in loader_settings else negative
|
||||
steps = loader_settings['steps'] if "steps" in loader_settings else 20
|
||||
cfg = loader_settings['cfg'] if "cfg" in loader_settings else 8.0
|
||||
cfg_negative = loader_settings['cfg_negative'] if "cfg_negative" in loader_settings else 8.0
|
||||
sampler_name = loader_settings['sampler_name'] if "sampler_name" in loader_settings else "euler"
|
||||
scheduler = loader_settings['scheduler'] if "scheduler" in loader_settings else "normal"
|
||||
guider = loader_settings['custom']['guider'] if "guider" in loader_settings['custom'] else "CFG"
|
||||
beta_d = loader_settings['custom']['beta_d'] if "beta_d" in loader_settings['custom'] else 0.1
|
||||
beta_min = loader_settings['custom']['beta_min'] if "beta_min" in loader_settings['custom'] else 0.1
|
||||
eps_s = loader_settings['custom']['eps_s'] if "eps_s" in loader_settings['custom'] else 0.1
|
||||
sigma_max = loader_settings['custom']['sigma_max'] if "sigma_max" in loader_settings['custom'] else 14.61
|
||||
sigma_min = loader_settings['custom']['sigma_min'] if "sigma_min" in loader_settings['custom'] else 0.03
|
||||
rho = loader_settings['custom']['rho'] if "rho" in loader_settings['custom'] else 7.0
|
||||
coeff = loader_settings['custom']['coeff'] if "coeff" in loader_settings['custom'] else 1.2
|
||||
flip_sigmas = loader_settings['custom']['flip_sigmas'] if "flip_sigmas" in loader_settings['custom'] else False
|
||||
denoise = loader_settings['denoise'] if "denoise" in loader_settings else 1.0
|
||||
add_noise = loader_settings['add_noise'] if "add_noise" in loader_settings else "enable"
|
||||
optional_sigmas = loader_settings['optional_sigmas'] if "optional_sigmas" in loader_settings else None
|
||||
optional_sampler = loader_settings['optional_sampler'] if "optional_sampler" in loader_settings else None
|
||||
|
||||
# sigmas
|
||||
if optional_sigmas is not None:
|
||||
sigmas = optional_sigmas
|
||||
else:
|
||||
if scheduler == 'vp':
|
||||
sigmas, = self.get_custom_cls('VPScheduler').get_sigmas(steps, beta_d, beta_min, eps_s)
|
||||
elif scheduler == 'karrasADV':
|
||||
sigmas, = self.get_custom_cls('KarrasScheduler').get_sigmas(steps, sigma_max, sigma_min, rho)
|
||||
elif scheduler == 'exponentialADV':
|
||||
sigmas, = self.get_custom_cls('ExponentialScheduler').get_sigmas(steps, sigma_max, sigma_min)
|
||||
elif scheduler == 'polyExponential':
|
||||
sigmas, = self.get_custom_cls('PolyexponentialScheduler').get_sigmas(steps, sigma_max, sigma_min, rho)
|
||||
elif scheduler == 'sdturbo':
|
||||
sigmas, = self.get_custom_cls('SDTurboScheduler').get_sigmas(model, steps, denoise)
|
||||
elif scheduler == 'alignYourSteps':
|
||||
model_type = get_sd_version(model)
|
||||
if model_type == 'unknown':
|
||||
model_type = 'sdxl'
|
||||
sigmas, = alignYourStepsScheduler().get_sigmas(model_type.upper(), steps, denoise)
|
||||
elif scheduler == 'gits':
|
||||
sigmas, = gitsScheduler().get_sigmas(coeff, steps, denoise)
|
||||
else:
|
||||
sigmas, = self.get_custom_cls('BasicScheduler').get_sigmas(model, scheduler, steps, denoise)
|
||||
|
||||
# filp_sigmas
|
||||
if flip_sigmas:
|
||||
sigmas, = self.get_custom_cls('FlipSigmas').get_sigmas(sigmas)
|
||||
|
||||
#######################################################################################
|
||||
# brushnet
|
||||
to = None
|
||||
transformer_options = model.model_options['transformer_options'] if "transformer_options" in model.model_options else {}
|
||||
if 'model_patch' in transformer_options and 'brushnet' in transformer_options['model_patch']:
|
||||
to = self.add_model_patch_option(model)
|
||||
mp = to['model_patch']
|
||||
if isinstance(model.model.model_config, comfy.supported_models.SD15):
|
||||
mp['SDXL'] = False
|
||||
elif isinstance(model.model.model_config, comfy.supported_models.SDXL):
|
||||
mp['SDXL'] = True
|
||||
else:
|
||||
print('Base model type: ', type(model.model.model_config))
|
||||
raise Exception("Unsupported model type: ", type(model.model.model_config))
|
||||
|
||||
mp['all_sigmas'] = sigmas
|
||||
mp['unet'] = model.model.diffusion_model
|
||||
mp['step'] = 0
|
||||
mp['total_steps'] = 1
|
||||
#######################################################################################
|
||||
# guider
|
||||
if guider == 'CFG':
|
||||
_guider, = self.get_custom_cls('CFGGuider').get_guider(model, positive, negative, cfg)
|
||||
elif guider in ['DualCFG', 'IP2P+DualCFG']:
|
||||
_guider, = self.get_custom_cls('DualCFGGuider').get_guider(model, positive, middle,
|
||||
negative, cfg, cfg_negative)
|
||||
else:
|
||||
_guider, = self.get_custom_cls('BasicGuider').get_guider(model, positive)
|
||||
|
||||
# sampler
|
||||
if optional_sampler:
|
||||
_sampler = optional_sampler
|
||||
else:
|
||||
if sampler_name == 'inversed_euler':
|
||||
_sampler, = self.get_inversed_euler_sampler()
|
||||
else:
|
||||
_sampler, = self.get_custom_cls('KSamplerSelect').get_sampler(sampler_name)
|
||||
|
||||
# noise
|
||||
if add_noise == 'disable':
|
||||
noise, = self.get_custom_cls('DisableNoise').get_noise()
|
||||
else:
|
||||
noise, = self.get_custom_cls('RandomNoise').get_noise(seed)
|
||||
|
||||
return (noise, _guider, _sampler, sigmas)
|
||||
|
||||
def run(self, pipe, steps, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, seed=None, model=None, positive=None, negative=None, latent=None, vae=None, clip=None, xyPlot=None, tile_size=None, prompt=None, extra_pnginfo=None, my_unique_id=None, force_full_denoise=False, disable_noise=False, downscale_options=None, image=None):
|
||||
|
||||
samp_model = model if model is not None else pipe["model"]
|
||||
@@ -4978,7 +5039,7 @@ class samplerFull:
|
||||
|
||||
samp_seed = seed if seed is not None else pipe['seed']
|
||||
|
||||
samp_custom = pipe["loader_settings"]["custom"] if "custom" in pipe["loader_settings"] else None
|
||||
samp_custom = pipe["loader_settings"] if "custom" in pipe["loader_settings"] else None
|
||||
|
||||
steps = steps if steps is not None else pipe['loader_settings']['steps']
|
||||
start_step = pipe['loader_settings']['start_step'] if 'start_step' in pipe['loader_settings'] else 0
|
||||
@@ -4997,8 +5058,6 @@ class samplerFull:
|
||||
if add_noise == "disable":
|
||||
disable_noise = True
|
||||
|
||||
|
||||
# When model is colors
|
||||
def downscale_model_unet(samp_model):
|
||||
# 获取Unet参数
|
||||
if "PatchModelAddDownscale" in ALL_NODE_CLASS_MAPPINGS:
|
||||
@@ -5069,16 +5128,12 @@ class samplerFull:
|
||||
start_time = int(time.time() * 1000)
|
||||
# 开始推理
|
||||
if samp_custom is not None:
|
||||
guider = samp_custom['guider'] if 'guider' in samp_custom else None
|
||||
_sampler = samp_custom['sampler'] if 'sampler' in samp_custom else None
|
||||
sigmas = samp_custom['sigmas'] if 'sigmas' in samp_custom else None
|
||||
noise = samp_custom['noise'] if 'noise' in samp_custom else None
|
||||
samp_samples, _ = sampler.custom_advanced_ksampler(noise, guider, _sampler, sigmas, samp_samples)
|
||||
noise, _guider, _sampler, sigmas = self.get_sampler_custom(samp_model, samp_positive, samp_negative, samp_seed, samp_custom)
|
||||
samp_samples, _ = sampler.custom_advanced_ksampler(noise, _guider, _sampler, sigmas, samp_samples)
|
||||
elif scheduler == 'align_your_steps':
|
||||
model_type = get_sd_version(samp_model)
|
||||
if model_type == 'unknown':
|
||||
model_type = 'sdxl'
|
||||
# raise Exception("This Model not supported")
|
||||
sigmas, = alignYourStepsScheduler().get_sigmas(model_type.upper(), steps, denoise)
|
||||
_sampler = comfy.samplers.sampler_object(sampler_name)
|
||||
samp_samples = sampler.custom_ksampler(samp_model, samp_seed, steps, cfg, _sampler, sigmas, samp_positive, samp_negative, samp_samples, disable_noise=disable_noise, preview_latent=preview_latent)
|
||||
@@ -5168,9 +5223,6 @@ class samplerFull:
|
||||
if image_output in ("Sender", "Sender&Save"):
|
||||
PromptServer.instance.send_sync("img-send", {"link_id": link_id, "images": results})
|
||||
|
||||
if hasattr(ModelPatcher, "original_calculate_weight"):
|
||||
ModelPatcher.calculate_weight = ModelPatcher.original_calculate_weight
|
||||
|
||||
return {"ui": {"images": results},
|
||||
"result": sampler.get_output(new_pipe,)}
|
||||
|
||||
@@ -5283,9 +5335,6 @@ class samplerFull:
|
||||
|
||||
del pipe
|
||||
|
||||
if hasattr(ModelPatcher, "original_calculate_weight"):
|
||||
ModelPatcher.calculate_weight = ModelPatcher.original_calculate_weight
|
||||
|
||||
if image_output in ("Hide", "Hide&Save"):
|
||||
return sampler.get_output(new_pipe)
|
||||
|
||||
@@ -5723,7 +5772,6 @@ class samplerSDTurbo:
|
||||
if image_output in ("Sender", "Sender&Save"):
|
||||
PromptServer.instance.send_sync("img-send", {"link_id": link_id, "images": results})
|
||||
|
||||
|
||||
return {"ui": {"images": results},
|
||||
"result": sampler.get_output(new_pipe, )}
|
||||
|
||||
@@ -6908,17 +6956,19 @@ class pipeEditPrompt:
|
||||
log_node_warn(f'pipeEdit[{my_unique_id}]', "Model missing from pipeLine")
|
||||
|
||||
from .kolors.loader import is_kolors_model
|
||||
if is_kolors_model(model):
|
||||
model_type = get_sd_version(model)
|
||||
if model_type == 'sdxl' and is_kolors_model(model):
|
||||
auto_clean_gpu = pipe["loader_settings"]["auto_clean_gpu"] if "auto_clean_gpu" in pipe["loader_settings"] else False
|
||||
chatglm3_model = pipe["chatglm3_model"] if "chatglm3_model" in pipe else None
|
||||
# text encode
|
||||
log_node_warn("正在进行正向提示词编码...")
|
||||
positive_embeddings_final = chatglm3_adv_text_encode(chatglm3_model, positive, auto_clean_gpu)
|
||||
log_node_warn("正在进行负面提示词编码...")
|
||||
negative_embeddings_final = chatglm3_adv_text_encode(chatglm3_model, negative, auto_clean_gpu)
|
||||
else:
|
||||
model_type = get_sd_version(model)
|
||||
clip_skip = pipe["loader_settings"]["clip_skip"] if "clip_skip" in pipe["loader_settings"] else -1
|
||||
lora_stack = pipe.get("lora_stack") if pipe is not None and "lora_stack" in pipe else []
|
||||
clip = pipe.get("clip") if pipe is not None and "clip" in pipe else None
|
||||
positive_token_normalization = pipe["loader_settings"]["positive_token_normalization"] if "positive_token_normalization" in pipe["loader_settings"] else "none"
|
||||
positive_weight_interpretation = pipe["loader_settings"]["positive_weight_interpretation"] if "positive_weight_interpretation" in pipe["loader_settings"] else "comfy"
|
||||
negative_token_normalization = pipe["loader_settings"]["negative_token_normalization"] if "negative_token_normalization" in pipe["loader_settings"] else "none"
|
||||
@@ -7454,7 +7504,6 @@ class sliderControl:
|
||||
RETURN_NAMES = ("layer_weights",)
|
||||
|
||||
FUNCTION = "control"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
CATEGORY = "EasyUse/Util"
|
||||
|
||||
@@ -7507,7 +7556,6 @@ class stableDiffusion3API:
|
||||
|
||||
#---------------------------------------------------------------API 结束----------------------------------------------------------------------
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
# seed 随机种
|
||||
"easy seed": easySeed,
|
||||
@@ -7534,6 +7582,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy dynamiCrafterLoader": dynamiCrafterLoader,
|
||||
"easy cascadeLoader": cascadeLoader,
|
||||
"easy kolorsLoader": kolorsLoader,
|
||||
"easy fluxLoader": fluxLoader,
|
||||
"easy pixArtLoader": pixArtLoader,
|
||||
"easy loraStack": loraStack,
|
||||
"easy controlnetStack": controlnetStack,
|
||||
@@ -7654,6 +7703,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy dynamiCrafterLoader": "EasyLoader (DynamiCrafter)",
|
||||
"easy cascadeLoader": "EasyCascadeLoader",
|
||||
"easy kolorsLoader": "EasyLoader (Kolors)",
|
||||
"easy fluxLoader": "EasyLoader (Flux)",
|
||||
"easy hunyuanDiTLoader": "EasyLoader (HunyuanDiT)",
|
||||
"easy pixArtLoader": "EasyLoader (PixArt)",
|
||||
"easy loraStack": "EasyLoraStack",
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#credit to Acly for this module
|
||||
#from https://github.com/Acly/comfyui-inpaint-nodes
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
import comfy
|
||||
from comfy.model_base import BaseModel
|
||||
from comfy.model_patcher import ModelPatcher
|
||||
from comfy.model_management import cast_to_device
|
||||
|
||||
from ..libs.log import log_node_warn, log_node_error, log_node_info
|
||||
|
||||
class InpaintHead(torch.nn.Module):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.head = torch.nn.Parameter(torch.empty(size=(320, 5, 3, 3), device="cpu"))
|
||||
|
||||
def __call__(self, x):
|
||||
x = F.pad(x, (1, 1, 1, 1), "replicate")
|
||||
return F.conv2d(x, weight=self.head)
|
||||
|
||||
|
||||
class applyFooocusPatch:
|
||||
def calculate_weight_patched(self, patches, weight, key, intermediate_type=torch.float32):
|
||||
remaining = []
|
||||
|
||||
for p in patches:
|
||||
alpha = p[0]
|
||||
v = p[1]
|
||||
|
||||
is_fooocus_patch = isinstance(v, tuple) and len(v) == 2 and v[0] == "fooocus"
|
||||
if not is_fooocus_patch:
|
||||
remaining.append(p)
|
||||
continue
|
||||
|
||||
if alpha != 0.0:
|
||||
v = v[1]
|
||||
w1 = cast_to_device(v[0], weight.device, torch.float32)
|
||||
if w1.shape == weight.shape:
|
||||
w_min = cast_to_device(v[1], weight.device, torch.float32)
|
||||
w_max = cast_to_device(v[2], weight.device, torch.float32)
|
||||
w1 = (w1 / 255.0) * (w_max - w_min) + w_min
|
||||
weight += alpha * cast_to_device(w1, weight.device, weight.dtype)
|
||||
else:
|
||||
pass
|
||||
# log_node_warn(self.node_name,
|
||||
# f"Shape mismatch {key}, weight not merged ({w1.shape} != {weight.shape})"
|
||||
# )
|
||||
|
||||
if len(remaining) > 0:
|
||||
return self.original_calculate_weight(remaining, weight, key, intermediate_type)
|
||||
return weight
|
||||
|
||||
def __enter__(self):
|
||||
try:
|
||||
print("[comfyui-easy-use] Injecting patched comfy.lora.calculate_weight.calculate_weight")
|
||||
self.original_calculate_weight = comfy.lora.calculate_weight
|
||||
comfy.lora.calculate_weight = self.calculate_weight_patched
|
||||
except AttributeError:
|
||||
print("[comfyui-easy-use] Injecting patched comfy.model_patcher.ModelPatcher.calculate_weight")
|
||||
self.original_calculate_weight = ModelPatcher.calculate_weight
|
||||
ModelPatcher.calculate_weight = self.calculate_weight_patched
|
||||
def __exit__(self, type, value, traceback):
|
||||
try:
|
||||
comfy.lora.calculate_weight = self.original_calculate_weight
|
||||
except AttributeError:
|
||||
ModelPatcher.calculate_weight = self.original_calculate_weight
|
||||
|
||||
|
||||
class InpaintWorker:
|
||||
def __init__(self, node_name):
|
||||
self.node_name = node_name if node_name is not None else ""
|
||||
|
||||
def load_fooocus_patch(self, lora: dict, to_load: dict):
|
||||
patch_dict = {}
|
||||
loaded_keys = set()
|
||||
for key in to_load.values():
|
||||
if value := lora.get(key, None):
|
||||
patch_dict[key] = ("fooocus", value)
|
||||
loaded_keys.add(key)
|
||||
|
||||
not_loaded = sum(1 for x in lora if x not in loaded_keys)
|
||||
if not_loaded > 0:
|
||||
log_node_info(self.node_name,
|
||||
f"{len(loaded_keys)} Lora keys loaded, {not_loaded} remaining keys not found in model."
|
||||
)
|
||||
return patch_dict
|
||||
|
||||
|
||||
def patch(self, model, latent, patch):
|
||||
with applyFooocusPatch():
|
||||
base_model: BaseModel = model.model
|
||||
latent_pixels = base_model.process_latent_in(latent["samples"])
|
||||
noise_mask = latent["noise_mask"].round()
|
||||
latent_mask = F.max_pool2d(noise_mask, (8, 8)).round().to(latent_pixels)
|
||||
|
||||
inpaint_head_model, inpaint_lora = patch
|
||||
feed = torch.cat([latent_mask, latent_pixels], dim=1)
|
||||
inpaint_head_model.to(device=feed.device, dtype=feed.dtype)
|
||||
inpaint_head_feature = inpaint_head_model(feed)
|
||||
|
||||
def input_block_patch(h, transformer_options):
|
||||
if transformer_options["block"][1] == 0:
|
||||
h = h + inpaint_head_feature.to(h)
|
||||
return h
|
||||
|
||||
lora_keys = comfy.lora.model_lora_keys_unet(model.model, {})
|
||||
lora_keys.update({x: x for x in base_model.state_dict().keys()})
|
||||
loaded_lora = self.load_fooocus_patch(inpaint_lora, lora_keys)
|
||||
|
||||
m = model.clone()
|
||||
m.set_model_input_block_patch(input_block_patch)
|
||||
patched = m.add_patches(loaded_lora, 1.0)
|
||||
|
||||
not_patched_count = sum(1 for x in loaded_lora if x not in patched)
|
||||
if not_patched_count > 0:
|
||||
log_node_error(self.node_name, f"Failed to patch {not_patched_count} keys")
|
||||
return (m,)
|
||||
+9
-10
@@ -8,10 +8,9 @@ import comfy.model_management
|
||||
from comfy.sd import load_unet
|
||||
from comfy.ldm.models.autoencoder import AutoencoderKL
|
||||
from comfy.model_base import BaseModel
|
||||
from comfy.model_patcher import ModelPatcher
|
||||
from PIL import Image
|
||||
from nodes import VAEEncode
|
||||
|
||||
from ..layer_diffuse.model import ModelPatcher, calculate_weight_adjust_channel
|
||||
from ..libs.image import np2tensor, pil2tensor
|
||||
|
||||
class UnetParams(TypedDict):
|
||||
@@ -20,7 +19,6 @@ class UnetParams(TypedDict):
|
||||
c: dict
|
||||
cond_or_uncond: torch.Tensor
|
||||
|
||||
|
||||
class VAEEncodeArgMax(VAEEncode):
|
||||
def encode(self, vae, pixels):
|
||||
assert isinstance(
|
||||
@@ -141,12 +139,7 @@ class ICLight:
|
||||
return image
|
||||
|
||||
|
||||
def apply(self, ic_model_path, model: ModelPatcher, c_concat: dict, ic_model=None) -> Tuple[ModelPatcher]:
|
||||
try:
|
||||
ModelPatcher.calculate_weight = calculate_weight_adjust_channel(ModelPatcher.calculate_weight)
|
||||
except:
|
||||
pass
|
||||
|
||||
def apply(self, ic_model_path, model, c_concat: dict, ic_model=None) -> Tuple[ModelPatcher]:
|
||||
device = comfy.model_management.get_torch_device()
|
||||
dtype = comfy.model_management.unet_dtype()
|
||||
work_model = model.clone()
|
||||
@@ -179,7 +172,13 @@ class ICLight:
|
||||
|
||||
work_model.add_patches(
|
||||
patches={
|
||||
("diffusion_model." + key): (value.to(dtype=dtype, device=device),)
|
||||
("diffusion_model." + key): (
|
||||
'diff',
|
||||
[
|
||||
value.to(dtype=dtype, device=device),
|
||||
{"pad_weight": key == 'input_blocks.0.0.weight'}
|
||||
]
|
||||
)
|
||||
for key, value in ic_model_state_dict.items()
|
||||
}
|
||||
)
|
||||
|
||||
+40
-84
@@ -404,46 +404,6 @@ class imagePixelPerfect:
|
||||
|
||||
return {"ui": {"text": text}, "result": (result,)}
|
||||
|
||||
# 图片到遮罩
|
||||
class imageToMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"image": ("IMAGE",),
|
||||
"channel": (['red', 'green', 'blue'],),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "convert"
|
||||
CATEGORY = "EasyUse/Image"
|
||||
|
||||
def convert_to_single_channel(self, image, channel='red'):
|
||||
# Convert to RGB mode to access individual channels
|
||||
image = image.convert('RGB')
|
||||
|
||||
# Extract the desired channel and convert to greyscale
|
||||
if channel == 'red':
|
||||
channel_img = image.split()[0].convert('L')
|
||||
elif channel == 'green':
|
||||
channel_img = image.split()[1].convert('L')
|
||||
elif channel == 'blue':
|
||||
channel_img = image.split()[2].convert('L')
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invalid channel option. Please choose 'red', 'green', or 'blue'.")
|
||||
|
||||
# Convert the greyscale channel back to RGB mode
|
||||
channel_img = Image.merge(
|
||||
'RGB', (channel_img, channel_img, channel_img))
|
||||
|
||||
return channel_img
|
||||
|
||||
def convert(self, image, channel='red'):
|
||||
image = self.convert_to_single_channel(tensor2pil(image), channel)
|
||||
image = pil2tensor(image)
|
||||
return (image.squeeze().mean(2),)
|
||||
|
||||
# 图像保存 (简易)
|
||||
from nodes import PreviewImage, SaveImage
|
||||
class imageSaveSimple:
|
||||
@@ -1523,46 +1483,46 @@ class removeLocalImage:
|
||||
|
||||
|
||||
# 姿势编辑器
|
||||
class poseEditor:
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
temp_dir = folder_paths.get_temp_directory()
|
||||
|
||||
if not os.path.isdir(temp_dir):
|
||||
os.makedirs(temp_dir)
|
||||
|
||||
temp_dir = folder_paths.get_temp_directory()
|
||||
|
||||
return {"required":
|
||||
{"image": (sorted(os.listdir(temp_dir)),)},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "output_pose"
|
||||
|
||||
CATEGORY = "EasyUse/Image"
|
||||
|
||||
def output_pose(self, image):
|
||||
image_path = os.path.join(folder_paths.get_temp_directory(), image)
|
||||
# print(f"Create: {image_path}")
|
||||
|
||||
i = Image.open(image_path)
|
||||
image = i.convert("RGB")
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = torch.from_numpy(image)[None,]
|
||||
|
||||
return (image,)
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(self, image):
|
||||
image_path = os.path.join(
|
||||
folder_paths.get_temp_directory(), image)
|
||||
# print(f'Change: {image_path}')
|
||||
|
||||
m = hashlib.sha256()
|
||||
with open(image_path, 'rb') as f:
|
||||
m.update(f.read())
|
||||
return m.digest().hex()
|
||||
# class poseEditor:
|
||||
# @classmethod
|
||||
# def INPUT_TYPES(self):
|
||||
# temp_dir = folder_paths.get_temp_directory()
|
||||
#
|
||||
# if not os.path.isdir(temp_dir):
|
||||
# os.makedirs(temp_dir)
|
||||
#
|
||||
# temp_dir = folder_paths.get_temp_directory()
|
||||
#
|
||||
# return {"required":
|
||||
# {"image": (sorted(os.listdir(temp_dir)),)},
|
||||
# }
|
||||
#
|
||||
# RETURN_TYPES = ("IMAGE",)
|
||||
# FUNCTION = "output_pose"
|
||||
#
|
||||
# CATEGORY = "EasyUse/🚫 Deprecated"
|
||||
#
|
||||
# def output_pose(self, image):
|
||||
# image_path = os.path.join(folder_paths.get_temp_directory(), image)
|
||||
# # print(f"Create: {image_path}")
|
||||
#
|
||||
# i = Image.open(image_path)
|
||||
# image = i.convert("RGB")
|
||||
# image = np.array(image).astype(np.float32) / 255.0
|
||||
# image = torch.from_numpy(image)[None,]
|
||||
#
|
||||
# return (image,)
|
||||
#
|
||||
# @classmethod
|
||||
# def IS_CHANGED(self, image):
|
||||
# image_path = os.path.join(
|
||||
# folder_paths.get_temp_directory(), image)
|
||||
# # print(f'Change: {image_path}')
|
||||
#
|
||||
# m = hashlib.sha256()
|
||||
# with open(image_path, 'rb') as f:
|
||||
# m.update(f.read())
|
||||
# return m.digest().hex()
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"easy imageInsetCrop": imageInsetCrop,
|
||||
@@ -1575,7 +1535,6 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy imageScaleDownBy": imageScaleDownBy,
|
||||
"easy imageScaleDownToSize": imageScaleDownToSize,
|
||||
"easy imageRatio": imageRatio,
|
||||
"easy imageToMask": imageToMask,
|
||||
"easy imageConcat": imageConcat,
|
||||
"easy imageListToImageBatch": imageListToImageBatch,
|
||||
"easy imageBatchToImageList": imageBatchToImageList,
|
||||
@@ -1595,7 +1554,6 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy joinImageBatch": JoinImageBatch,
|
||||
"easy humanSegmentation": humanSegmentation,
|
||||
"easy removeLocalImage": removeLocalImage,
|
||||
"easy poseEditor": poseEditor
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -1609,7 +1567,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy imageScaleDownBy": "Image Scale Down By",
|
||||
"easy imageScaleDownToSize": "Image Scale Down To Size",
|
||||
"easy imageRatio": "ImageRatio",
|
||||
"easy imageToMask": "ImageToMask",
|
||||
"easy imageHSVMask": "ImageHSVMask",
|
||||
"easy imageConcat": "imageConcat",
|
||||
"easy imageListToImageBatch": "Image List To Image Batch",
|
||||
@@ -1630,5 +1587,4 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy imageToBase64": "Image To Base64",
|
||||
"easy humanSegmentation": "Human Segmentation",
|
||||
"easy removeLocalImage": "Remove Local Image",
|
||||
"easy poseEditor": "PoseEditor",
|
||||
}
|
||||
+4
-3
@@ -1,6 +1,8 @@
|
||||
import json
|
||||
import os
|
||||
import torch
|
||||
import subprocess
|
||||
import sys
|
||||
import comfy.supported_models
|
||||
import comfy.model_patcher
|
||||
import comfy.model_management
|
||||
@@ -294,9 +296,8 @@ class applyKolorsUnet:
|
||||
|
||||
|
||||
def is_kolors_model(model):
|
||||
base: BaseModel = model.model
|
||||
model_config: comfy.supported_models.supported_models_base.BASE = base.model_config
|
||||
if isinstance(model_config, Kolors):
|
||||
unet_config = model.model.model_config.unet_config
|
||||
if unet_config and "adm_in_channels" in unet_config and unet_config["adm_in_channels"] == 5632:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -2,6 +2,7 @@
|
||||
#from https://github.com/huchenlei/ComfyUI-layerdiffuse
|
||||
import torch
|
||||
import comfy.model_management
|
||||
import comfy.lora
|
||||
import copy
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
@@ -59,7 +60,10 @@ class LayerDiffuse:
|
||||
image = image.movedim(-1, 1)
|
||||
|
||||
try:
|
||||
ModelPatcher.calculate_weight = calculate_weight_adjust_channel(ModelPatcher.calculate_weight)
|
||||
if hasattr(comfy.lora, "calculate_weight"):
|
||||
comfy.lora.calculate_weight = calculate_weight_adjust_channel(comfy.lora.calculate_weight)
|
||||
else:
|
||||
ModelPatcher.calculate_weight = calculate_weight_adjust_channel(ModelPatcher.calculate_weight)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import einops
|
||||
from comfy import model_management, utils
|
||||
from comfy.ldm.modules.attention import optimized_attention
|
||||
|
||||
|
||||
module_mapping_sd15 = {
|
||||
0: "input_blocks.1.1.transformer_blocks.0.attn1",
|
||||
1: "input_blocks.1.1.transformer_blocks.0.attn2",
|
||||
|
||||
@@ -324,9 +324,9 @@ try:
|
||||
"""Patches ComfyUI's LoRA weight application to accept multi-channel inputs."""
|
||||
@functools.wraps(func)
|
||||
def calculate_weight(
|
||||
self: ModelPatcher, patches, weight: torch.Tensor, key: str
|
||||
patches, weight: torch.Tensor, key: str, intermediate_type=torch.float32
|
||||
) -> torch.Tensor:
|
||||
weight = func(self, patches, weight, key)
|
||||
weight = func(patches, weight, key, intermediate_type)
|
||||
|
||||
for p in patches:
|
||||
alpha = p[0]
|
||||
|
||||
@@ -12,6 +12,8 @@ def prompt_to_cond(type, model, clip, clip_skip, lora_stack, text, prompt_token_
|
||||
log_node_warn("正在进行" + title + "...")
|
||||
|
||||
if model_type in ['hydit', 'flux']:
|
||||
if model_type == 'flux':
|
||||
text = zh_to_en([text])[0] if has_chinese(text) else text
|
||||
embeddings_final, = CLIPTextEncode().encode(clip, text)
|
||||
return (embeddings_final, "", model, clip)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class easyControlnet:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def apply(self, control_net_name, image, positive, negative, strength, start_percent=0, end_percent=1, control_net=None, scale_soft_weights=1, mask=None, union_type=None, easyCache=None, use_cache=True, model=None):
|
||||
def apply(self, control_net_name, image, positive, negative, strength, start_percent=0, end_percent=1, control_net=None, scale_soft_weights=1, mask=None, union_type=None, easyCache=None, use_cache=True, model=None, vae=None):
|
||||
if strength == 0:
|
||||
return (positive, negative)
|
||||
|
||||
@@ -69,7 +69,7 @@ class easyControlnet:
|
||||
if prev_cnet in cnets:
|
||||
c_net = cnets[prev_cnet]
|
||||
else:
|
||||
c_net = control_net.copy().set_cond_hint(control_hint, strength, (start_percent, end_percent))
|
||||
c_net = control_net.copy().set_cond_hint(control_hint, strength, (start_percent, end_percent), vae)
|
||||
c_net.set_previous_controlnet(prev_cnet)
|
||||
cnets[prev_cnet] = c_net
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
#credit to Acly for this module
|
||||
#from https://github.com/Acly/comfyui-inpaint-nodes
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
import comfy
|
||||
from comfy.model_base import BaseModel
|
||||
from comfy.model_patcher import ModelPatcher
|
||||
from comfy.model_management import cast_to_device
|
||||
|
||||
from .log import log_node_warn, log_node_error, log_node_info
|
||||
|
||||
# Inpaint
|
||||
original_calculate_weight = ModelPatcher.calculate_weight
|
||||
injected_model_patcher_calculate_weight = False
|
||||
|
||||
class InpaintHead(torch.nn.Module):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.head = torch.nn.Parameter(torch.empty(size=(320, 5, 3, 3), device="cpu"))
|
||||
|
||||
def __call__(self, x):
|
||||
x = F.pad(x, (1, 1, 1, 1), "replicate")
|
||||
return F.conv2d(x, weight=self.head)
|
||||
|
||||
def calculate_weight_patched(self: ModelPatcher, patches, weight, key):
|
||||
remaining = []
|
||||
|
||||
for p in patches:
|
||||
alpha = p[0]
|
||||
v = p[1]
|
||||
|
||||
is_fooocus_patch = isinstance(v, tuple) and len(v) == 2 and v[0] == "fooocus"
|
||||
if not is_fooocus_patch:
|
||||
remaining.append(p)
|
||||
continue
|
||||
|
||||
if alpha != 0.0:
|
||||
v = v[1]
|
||||
w1 = cast_to_device(v[0], weight.device, torch.float32)
|
||||
if w1.shape == weight.shape:
|
||||
w_min = cast_to_device(v[1], weight.device, torch.float32)
|
||||
w_max = cast_to_device(v[2], weight.device, torch.float32)
|
||||
w1 = (w1 / 255.0) * (w_max - w_min) + w_min
|
||||
weight += alpha * cast_to_device(w1, weight.device, weight.dtype)
|
||||
else:
|
||||
pass
|
||||
# log_node_warn(self.node_name,
|
||||
# f"Shape mismatch {key}, weight not merged ({w1.shape} != {weight.shape})"
|
||||
# )
|
||||
|
||||
if len(remaining) > 0:
|
||||
return original_calculate_weight(self, remaining, weight, key)
|
||||
return weight
|
||||
|
||||
def inject_patched_calculate_weight():
|
||||
global injected_model_patcher_calculate_weight
|
||||
if not injected_model_patcher_calculate_weight:
|
||||
print(
|
||||
"[comfyui-inpaint-nodes] Injecting patched comfy.model_patcher.ModelPatcher.calculate_weight"
|
||||
)
|
||||
ModelPatcher.calculate_weight = calculate_weight_patched
|
||||
injected_model_patcher_calculate_weight = True
|
||||
|
||||
class InpaintWorker:
|
||||
def __init__(self, node_name):
|
||||
self.node_name = node_name if node_name is not None else ""
|
||||
|
||||
def load_fooocus_patch(self, lora: dict, to_load: dict):
|
||||
patch_dict = {}
|
||||
loaded_keys = set()
|
||||
for key in to_load.values():
|
||||
if value := lora.get(key, None):
|
||||
patch_dict[key] = ("fooocus", value)
|
||||
loaded_keys.add(key)
|
||||
|
||||
not_loaded = sum(1 for x in lora if x not in loaded_keys)
|
||||
if not_loaded > 0:
|
||||
log_node_info(self.node_name,
|
||||
f"{len(loaded_keys)} Lora keys loaded, {not_loaded} remaining keys not found in model."
|
||||
)
|
||||
return patch_dict
|
||||
|
||||
|
||||
def patch(self, model, latent, patch):
|
||||
base_model: BaseModel = model.model
|
||||
latent_pixels = base_model.process_latent_in(latent["samples"])
|
||||
noise_mask = latent["noise_mask"].round()
|
||||
latent_mask = F.max_pool2d(noise_mask, (8, 8)).round().to(latent_pixels)
|
||||
|
||||
inpaint_head_model, inpaint_lora = patch
|
||||
feed = torch.cat([latent_mask, latent_pixels], dim=1)
|
||||
inpaint_head_model.to(device=feed.device, dtype=feed.dtype)
|
||||
inpaint_head_feature = inpaint_head_model(feed)
|
||||
|
||||
def input_block_patch(h, transformer_options):
|
||||
if transformer_options["block"][1] == 0:
|
||||
h = h + inpaint_head_feature.to(h)
|
||||
return h
|
||||
|
||||
lora_keys = comfy.lora.model_lora_keys_unet(model.model, {})
|
||||
lora_keys.update({x: x for x in base_model.state_dict().keys()})
|
||||
loaded_lora = self.load_fooocus_patch(inpaint_lora, lora_keys)
|
||||
|
||||
m = model.clone()
|
||||
m.set_model_input_block_patch(input_block_patch)
|
||||
patched = m.add_patches(loaded_lora, 1.0)
|
||||
|
||||
not_patched_count = sum(1 for x in loaded_lora if x not in patched)
|
||||
if not_patched_count > 0:
|
||||
log_node_error(self.node_name, f"Failed to patch {not_patched_count} keys")
|
||||
|
||||
inject_patched_calculate_weight()
|
||||
return (m,)
|
||||
+9
-3
@@ -1,4 +1,4 @@
|
||||
import time, os, psutil
|
||||
import re, time, os, psutil
|
||||
import folder_paths
|
||||
import comfy.utils
|
||||
import comfy.sd
|
||||
@@ -238,7 +238,11 @@ class easyLoader:
|
||||
config_path = folder_paths.get_full_path("configs", config_name)
|
||||
loaded_ckpt = comfy.sd.load_checkpoint(config_path, ckpt_path, output_vae=True, output_clip=output_clip, embedding_directory=folder_paths.get_folder_paths("embeddings"))
|
||||
else:
|
||||
loaded_ckpt = comfy.sd.load_checkpoint_guess_config(ckpt_path, output_vae=True, output_clip=output_clip, output_clipvision=output_clipvision, embedding_directory=folder_paths.get_folder_paths("embeddings"))
|
||||
model_options = {}
|
||||
if re.search("nf4", ckpt_name):
|
||||
from ..bitsandbytes_NF4 import OPS
|
||||
model_options = {"custom_operations": OPS}
|
||||
loaded_ckpt = comfy.sd.load_checkpoint_guess_config(ckpt_path, output_vae=True, output_clip=output_clip, output_clipvision=output_clipvision, embedding_directory=folder_paths.get_folder_paths("embeddings"), model_options=model_options)
|
||||
|
||||
self.add_to_cache("ckpt", cache_name, loaded_ckpt[0])
|
||||
self.add_to_cache("bvae", cache_name, loaded_ckpt[2])
|
||||
@@ -308,6 +312,8 @@ class easyLoader:
|
||||
clip_type = comfy.sd.CLIPType.STABLE_CASCADE
|
||||
elif type == 'sd3':
|
||||
clip_type = comfy.sd.CLIPType.SD3
|
||||
elif type == 'flux':
|
||||
clip_type = comfy.sd.CLIPType.FLUX
|
||||
elif type == 'stable_audio':
|
||||
clip_type = comfy.sd.CLIPType.STABLE_AUDIO
|
||||
clip_path = folder_paths.get_full_path("clip", clip_name)
|
||||
@@ -418,7 +424,7 @@ class easyLoader:
|
||||
|
||||
return None
|
||||
|
||||
def load_main(self, ckpt_name, config_name, vae_name, lora_name, lora_model_strength, lora_clip_strength, optional_lora_stack, model_override, clip_override, vae_override, prompt):
|
||||
def load_main(self, ckpt_name, config_name, vae_name, lora_name, lora_model_strength, lora_clip_strength, optional_lora_stack, model_override, clip_override, vae_override, prompt, nf4=False):
|
||||
model: ModelPatcher | None = None
|
||||
clip: comfy.sd.CLIP | None = None
|
||||
vae: comfy.sd.VAE | None = None
|
||||
|
||||
@@ -111,7 +111,6 @@ class easySampler:
|
||||
# add model patch
|
||||
# brushnet
|
||||
add_model_patch(model)
|
||||
# kolors
|
||||
#######################################################################################
|
||||
samples = comfy.sample.sample(model, noise, steps, cfg, sampler_name, scheduler, positive, negative,
|
||||
latent_image,
|
||||
|
||||
@@ -80,7 +80,7 @@ def has_chinese(text):
|
||||
_text = text
|
||||
_text = re.sub(r'<.*?>', '', _text)
|
||||
_text = re.sub(r'__.*?__', '', _text)
|
||||
_text = re.sub(r'embedding:.*?(\d+)?', '', _text)
|
||||
_text = re.sub(r'embedding:.*?$', '', _text)
|
||||
for char in _text:
|
||||
if '\u4e00' <= char <= '\u9fff':
|
||||
has_cn = True
|
||||
@@ -95,7 +95,6 @@ def translate(text):
|
||||
if not os.path.exists(zh_en_model_path):
|
||||
zh_en_model_path = 'Helsinki-NLP/opus-mt-zh-en'
|
||||
|
||||
print(zh_en_model_path)
|
||||
if zh_en_model is None:
|
||||
|
||||
zh_en_model = AutoModelForSeq2SeqLM.from_pretrained(zh_en_model_path).eval()
|
||||
|
||||
+679
-19
@@ -1,10 +1,17 @@
|
||||
from typing import Iterator, List, Tuple, Dict, Any, Union, Optional
|
||||
from _decimal import Context, getcontext
|
||||
from decimal import Decimal
|
||||
from .libs.utils import AlwaysEqualProxy, ByPassTypeTuple, cleanGPUUsedForce
|
||||
from .libs.utils import AlwaysEqualProxy, ByPassTypeTuple, cleanGPUUsedForce, compare_revision
|
||||
from .libs.cache import remove_cache
|
||||
import numpy as np
|
||||
import re
|
||||
import json
|
||||
import torch
|
||||
import comfy.utils
|
||||
|
||||
DEFAULT_FLOW_NUM = 2
|
||||
MAX_FLOW_NUM = 10
|
||||
lazy_options = {"lazy": True} if compare_revision(2543) else {}
|
||||
|
||||
def validate_list_args(args: Dict[str, List[Any]]) -> Tuple[bool, Optional[str], Optional[str]]:
|
||||
"""
|
||||
@@ -302,7 +309,466 @@ class textSwitch:
|
||||
else:
|
||||
return (text2,)
|
||||
|
||||
# ---------------------------------------------------------------运算 开始----------------------------------------------------------------------#
|
||||
# ---------------------------------------------------------------Index Switch----------------------------------------------------------------------#
|
||||
|
||||
class anythingIndexSwitch:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 9, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
for i in range(DEFAULT_FLOW_NUM):
|
||||
inputs["optional"]["value%d" % i] = (AlwaysEqualProxy("*"),lazy_options)
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy("*"),)
|
||||
RETURN_NAMES = ("value",)
|
||||
FUNCTION = "index_switch"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Index Switch"
|
||||
|
||||
def check_lazy_status(self, index, **kwargs):
|
||||
key = "value%d" % index
|
||||
if kwargs.get(key, None) is None:
|
||||
return [key]
|
||||
|
||||
def index_switch(self, index, **kwargs):
|
||||
key = "value%d" % index
|
||||
return (kwargs[key],)
|
||||
|
||||
class imageIndexSwitch:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 9, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
for i in range(DEFAULT_FLOW_NUM):
|
||||
inputs["optional"]["image%d" % i] = ("IMAGE",lazy_options)
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
FUNCTION = "index_switch"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Index Switch"
|
||||
|
||||
def check_lazy_status(self, index, **kwargs):
|
||||
key = "image%d" % index
|
||||
if kwargs.get(key, None) is None:
|
||||
return [key]
|
||||
|
||||
def index_switch(self, index, **kwargs):
|
||||
key = "image%d" % index
|
||||
return (kwargs[key],)
|
||||
|
||||
class textIndexSwitch:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 9, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
for i in range(DEFAULT_FLOW_NUM):
|
||||
inputs["optional"]["text%d" % i] = ("STRING",{**lazy_options,"forceInput":True})
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("text",)
|
||||
FUNCTION = "index_switch"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Index Switch"
|
||||
|
||||
def check_lazy_status(self, index, **kwargs):
|
||||
key = "text%d" % index
|
||||
if kwargs.get(key, None) is None:
|
||||
return [key]
|
||||
|
||||
def index_switch(self, index, **kwargs):
|
||||
key = "text%d" % index
|
||||
return (kwargs[key],)
|
||||
|
||||
class conditioningIndexSwitch:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 9, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
for i in range(DEFAULT_FLOW_NUM):
|
||||
inputs["optional"]["cond%d" % i] = ("CONDITIONING",lazy_options)
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = ("CONDITIONING",)
|
||||
RETURN_NAMES = ("conditioning",)
|
||||
FUNCTION = "index_switch"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Index Switch"
|
||||
|
||||
def check_lazy_status(self, index, **kwargs):
|
||||
key = "cond%d" % index
|
||||
if kwargs.get(key, None) is None:
|
||||
return [key]
|
||||
|
||||
def index_switch(self, index, **kwargs):
|
||||
key = "cond%d" % index
|
||||
return (kwargs[key],)
|
||||
|
||||
# ---------------------------------------------------------------Math----------------------------------------------------------------------#
|
||||
class mathIntOperation:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"a": ("INT", {"default": 0, "min": -0xffffffffffffffff, "max": 0xffffffffffffffff, "step": 1}),
|
||||
"b": ("INT", {"default": 0, "min": -0xffffffffffffffff, "max": 0xffffffffffffffff, "step": 1}),
|
||||
"operation": (["add", "subtract", "multiply", "divide", "modulo", "power"],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "int_math_operation"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Math"
|
||||
|
||||
def int_math_operation(self, a, b, operation):
|
||||
if operation == "add":
|
||||
return (a + b,)
|
||||
elif operation == "subtract":
|
||||
return (a - b,)
|
||||
elif operation == "multiply":
|
||||
return (a * b,)
|
||||
elif operation == "divide":
|
||||
return (a // b,)
|
||||
elif operation == "modulo":
|
||||
return (a % b,)
|
||||
elif operation == "power":
|
||||
return (a ** b,)
|
||||
|
||||
class mathFloatOperation:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"a": ("FLOAT", {"default": 0, "min": -999999999999.0, "max": 999999999999.0, "step": 1}),
|
||||
"b": ("FLOAT", {"default": 0, "min": -999999999999.0, "max": 999999999999.0, "step": 1}),
|
||||
"operation": (["==", "!=", "<", ">", "<=", ">="],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "float_math_operation"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Math"
|
||||
|
||||
def float_math_operation(self, a, b, operation):
|
||||
if operation == "==":
|
||||
return (a == b,)
|
||||
elif operation == "!=":
|
||||
return (a != b,)
|
||||
elif operation == "<":
|
||||
return (a < b,)
|
||||
elif operation == ">":
|
||||
return (a > b,)
|
||||
elif operation == "<=":
|
||||
return (a <= b,)
|
||||
elif operation == ">=":
|
||||
return (a >= b,)
|
||||
|
||||
class mathStringOperation:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"a": ("STRING", {"multiline": False}),
|
||||
"b": ("STRING", {"multiline": False}),
|
||||
"operation": (["a == b", "a != b", "a IN b", "a MATCH REGEX(b)", "a BEGINSWITH b", "a ENDSWITH b"],),
|
||||
"case_sensitive": ("BOOLEAN", {"default": True}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "string_math_operation"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/Math"
|
||||
|
||||
def string_math_operation(self, a, b, operation, case_sensitive):
|
||||
if not case_sensitive:
|
||||
a = a.lower()
|
||||
b = b.lower()
|
||||
|
||||
if operation == "a == b":
|
||||
return (a == b,)
|
||||
elif operation == "a != b":
|
||||
return (a != b,)
|
||||
elif operation == "a IN b":
|
||||
return (a in b,)
|
||||
elif operation == "a MATCH REGEX(b)":
|
||||
try:
|
||||
return (re.match(b, a) is not None,)
|
||||
except:
|
||||
return (False,)
|
||||
elif operation == "a BEGINSWITH b":
|
||||
return (a.startswith(b),)
|
||||
elif operation == "a ENDSWITH b":
|
||||
return (a.endswith(b),)
|
||||
|
||||
# ---------------------------------------------------------------Flow----------------------------------------------------------------------#
|
||||
try:
|
||||
from comfy_execution.graph_utils import GraphBuilder, is_link
|
||||
except:
|
||||
GraphBuilder = None
|
||||
|
||||
class whileLoopStart:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"condition": ("BOOLEAN", {"default": True}),
|
||||
},
|
||||
"optional": {
|
||||
},
|
||||
}
|
||||
for i in range(MAX_FLOW_NUM):
|
||||
inputs["optional"]["initial_value%d" % i] = ("*",)
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = ByPassTypeTuple(tuple(["FLOW_CONTROL"] + ["*"] * MAX_FLOW_NUM))
|
||||
RETURN_NAMES = ByPassTypeTuple(tuple(["flow"] + ["value%d" % i for i in range(MAX_FLOW_NUM)]))
|
||||
FUNCTION = "while_loop_open"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/While Loop"
|
||||
|
||||
def while_loop_open(self, condition, **kwargs):
|
||||
values = []
|
||||
for i in range(MAX_FLOW_NUM):
|
||||
values.append(kwargs.get("initial_value%d" % i, None))
|
||||
return tuple(["stub"] + values)
|
||||
|
||||
class whileLoopEnd:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
inputs = {
|
||||
"required": {
|
||||
"flow": ("FLOW_CONTROL", {"rawLink": True}),
|
||||
"condition": ("BOOLEAN", {}),
|
||||
},
|
||||
"optional": {
|
||||
},
|
||||
"hidden": {
|
||||
"dynprompt": "DYNPROMPT",
|
||||
"unique_id": "UNIQUE_ID",
|
||||
}
|
||||
}
|
||||
for i in range(MAX_FLOW_NUM):
|
||||
inputs["optional"]["initial_value%d" % i] = (AlwaysEqualProxy('*'),)
|
||||
return inputs
|
||||
|
||||
RETURN_TYPES = ByPassTypeTuple(tuple([AlwaysEqualProxy('*')] * MAX_FLOW_NUM))
|
||||
RETURN_NAMES = ByPassTypeTuple(tuple(["value%d" % i for i in range(MAX_FLOW_NUM)]))
|
||||
FUNCTION = "while_loop_close"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/While Loop"
|
||||
|
||||
def explore_dependencies(self, node_id, dynprompt, upstream):
|
||||
node_info = dynprompt.get_node(node_id)
|
||||
if "inputs" not in node_info:
|
||||
return
|
||||
for k, v in node_info["inputs"].items():
|
||||
if is_link(v):
|
||||
parent_id = v[0]
|
||||
if parent_id not in upstream:
|
||||
upstream[parent_id] = []
|
||||
self.explore_dependencies(parent_id, dynprompt, upstream)
|
||||
upstream[parent_id].append(node_id)
|
||||
|
||||
def collect_contained(self, node_id, upstream, contained):
|
||||
if node_id not in upstream:
|
||||
return
|
||||
for child_id in upstream[node_id]:
|
||||
if child_id not in contained:
|
||||
contained[child_id] = True
|
||||
self.collect_contained(child_id, upstream, contained)
|
||||
|
||||
|
||||
def while_loop_close(self, flow, condition, dynprompt=None, unique_id=None, **kwargs):
|
||||
if not condition:
|
||||
# We're done with the loop
|
||||
values = []
|
||||
for i in range(MAX_FLOW_NUM):
|
||||
values.append(kwargs.get("initial_value%d" % i, None))
|
||||
return tuple(values)
|
||||
|
||||
# We want to loop
|
||||
this_node = dynprompt.get_node(unique_id)
|
||||
upstream = {}
|
||||
# Get the list of all nodes between the open and close nodes
|
||||
self.explore_dependencies(unique_id, dynprompt, upstream)
|
||||
|
||||
contained = {}
|
||||
open_node = flow[0]
|
||||
self.collect_contained(open_node, upstream, contained)
|
||||
contained[unique_id] = True
|
||||
contained[open_node] = True
|
||||
|
||||
graph = GraphBuilder()
|
||||
for node_id in contained:
|
||||
original_node = dynprompt.get_node(node_id)
|
||||
node = graph.node(original_node["class_type"], "Recurse" if node_id == unique_id else node_id)
|
||||
node.set_override_display_id(node_id)
|
||||
for node_id in contained:
|
||||
original_node = dynprompt.get_node(node_id)
|
||||
node = graph.lookup_node("Recurse" if node_id == unique_id else node_id)
|
||||
for k, v in original_node["inputs"].items():
|
||||
if is_link(v) and v[0] in contained:
|
||||
parent = graph.lookup_node(v[0])
|
||||
node.set_input(k, parent.out(v[1]))
|
||||
else:
|
||||
node.set_input(k, v)
|
||||
|
||||
new_open = graph.lookup_node(open_node)
|
||||
for i in range(MAX_FLOW_NUM):
|
||||
key = "initial_value%d" % i
|
||||
new_open.set_input(key, kwargs.get(key, None))
|
||||
my_clone = graph.lookup_node("Recurse")
|
||||
result = map(lambda x: my_clone.out(x), range(MAX_FLOW_NUM))
|
||||
return {
|
||||
"result": tuple(result),
|
||||
"expand": graph.finalize(),
|
||||
}
|
||||
|
||||
class forLoopStart:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"total": ("INT", {"default": 1, "min": 1, "max": 100000, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
"initial_value%d" % i: (AlwaysEqualProxy("*"),) for i in range(1, MAX_FLOW_NUM)
|
||||
},
|
||||
"hidden": {
|
||||
"initial_value0": (AlwaysEqualProxy("*"),),
|
||||
"prompt": "PROMPT",
|
||||
"extra_pnginfo": "EXTRA_PNGINFO",
|
||||
"unique_id": "UNIQUE_ID"
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ByPassTypeTuple(tuple(["FLOW_CONTROL", "INT"] + [AlwaysEqualProxy("*")] * (MAX_FLOW_NUM - 1)))
|
||||
RETURN_NAMES = ByPassTypeTuple(tuple(["flow", "index"] + ["value%d" % i for i in range(1, MAX_FLOW_NUM)]))
|
||||
FUNCTION = "for_loop_start"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/For Loop"
|
||||
|
||||
def for_loop_start(self, total, prompt=None, extra_pnginfo=None, unique_id=None, **kwargs):
|
||||
graph = GraphBuilder()
|
||||
i = 0
|
||||
unique_id = unique_id.split('.')[len(unique_id.split('.'))-1] if "." in unique_id else unique_id
|
||||
node = next((x for x in extra_pnginfo['workflow']['nodes'] if x['id'] == int(unique_id)), None)
|
||||
if node:
|
||||
node['properties']['total'] = total
|
||||
if "initial_value0" in kwargs:
|
||||
i = kwargs["initial_value0"]
|
||||
initial_values = {("initial_value%d" % num): kwargs.get("initial_value%d" % num, None) for num in range(1, MAX_FLOW_NUM)}
|
||||
while_open = graph.node("easy whileLoopStart", condition=total, initial_value0=i, **initial_values)
|
||||
outputs = [kwargs.get("initial_value%d" % num, None) for num in range(1, MAX_FLOW_NUM)]
|
||||
return {
|
||||
"result": tuple(["stub", i] + outputs),
|
||||
"expand": graph.finalize(),
|
||||
}
|
||||
|
||||
class forLoopEnd:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"flow": ("FLOW_CONTROL", {"rawLink": True}),
|
||||
},
|
||||
"optional": {
|
||||
"initial_value%d" % i: (AlwaysEqualProxy("*"), {"rawLink": True}) for i in range(1, MAX_FLOW_NUM)
|
||||
},
|
||||
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ByPassTypeTuple(tuple([AlwaysEqualProxy("*")] * (MAX_FLOW_NUM - 1)))
|
||||
RETURN_NAMES = ByPassTypeTuple(tuple(["value%d" % i for i in range(1, MAX_FLOW_NUM)]))
|
||||
FUNCTION = "for_loop_end"
|
||||
|
||||
CATEGORY = "EasyUse/Logic/For Loop"
|
||||
|
||||
def for_loop_end(self, flow, prompt=None, extra_pnginfo=None, my_unique_id=None, **kwargs):
|
||||
graph = GraphBuilder()
|
||||
while_open = flow[0]
|
||||
total = None
|
||||
if extra_pnginfo:
|
||||
node = next((x for x in extra_pnginfo['workflow']['nodes'] if x['id'] == int(while_open)), None)
|
||||
if node:
|
||||
if 'properties' in node and 'total' in node['properties']:
|
||||
total = node['properties']['total']
|
||||
else:
|
||||
total = node['widgets_values'][0] if "widgets_values" in node else None
|
||||
if total is None:
|
||||
raise Exception("Unable to get parameters for the start of the loop")
|
||||
sub = graph.node("easy mathInt", operation="add", a=[while_open, 1], b=1)
|
||||
cond = graph.node("easy compare", a=sub.out(0), b=total, comparison='a < b')
|
||||
input_values = {("initial_value%d" % i): kwargs.get("initial_value%d" % i, None) for i in
|
||||
range(1, MAX_FLOW_NUM)}
|
||||
while_close = graph.node("easy whileLoopEnd",
|
||||
flow=flow,
|
||||
condition=cond.out(0),
|
||||
initial_value0=sub.out(0),
|
||||
**input_values)
|
||||
return {
|
||||
"result": tuple([while_close.out(i) for i in range(1, MAX_FLOW_NUM)]),
|
||||
"expand": graph.finalize(),
|
||||
}
|
||||
|
||||
COMPARE_FUNCTIONS = {
|
||||
"a == b": lambda a, b: a == b,
|
||||
@@ -317,46 +783,70 @@ COMPARE_FUNCTIONS = {
|
||||
class Compare:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
s.compare_functions = list(COMPARE_FUNCTIONS.keys())
|
||||
compare_functions = list(COMPARE_FUNCTIONS.keys())
|
||||
return {
|
||||
"required": {
|
||||
"a": (AlwaysEqualProxy("*"), {"default": 0}),
|
||||
"b": (AlwaysEqualProxy("*"), {"default": 0}),
|
||||
"comparison": (s.compare_functions, {"default": "a == b"}),
|
||||
"comparison": (compare_functions, {"default": "a == b"}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("boolean",)
|
||||
FUNCTION = "compare"
|
||||
CATEGORY = "EasyUse/Logic/Math"
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
def compare(self, a, b, comparison):
|
||||
return (COMPARE_FUNCTIONS[comparison](a, b),)
|
||||
|
||||
# 判断
|
||||
class If:
|
||||
class IfElse:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"any": (AlwaysEqualProxy("*"),),
|
||||
"if": (AlwaysEqualProxy("*"),),
|
||||
"else": (AlwaysEqualProxy("*"),),
|
||||
"boolean": ("BOOLEAN",),
|
||||
"on_true": (AlwaysEqualProxy("*"), lazy_options),
|
||||
"on_false": (AlwaysEqualProxy("*"), lazy_options),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy("*"),)
|
||||
RETURN_NAMES = ("?",)
|
||||
RETURN_NAMES = ("*",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "EasyUse/Logic/Math"
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
def check_lazy_status(self, boolean, on_true=None, on_false=None):
|
||||
if boolean and on_true is None:
|
||||
return ["on_true"]
|
||||
if not boolean and on_false is None:
|
||||
return ["on_false"]
|
||||
|
||||
def execute(self, *args, **kwargs):
|
||||
return (kwargs['if'] if kwargs['any'] else kwargs['else'],)
|
||||
|
||||
return (kwargs['on_true'] if kwargs['boolean'] else kwargs['on_false'],)
|
||||
|
||||
#是否为SDXL
|
||||
from comfy.sdxl_clip import SDXLClipModel, SDXLRefinerClipModel, SDXLClipG
|
||||
class isNone:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"any": (AlwaysEqualProxy("*"),)
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("boolean",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
def execute(self, any):
|
||||
return (True if any is None else False,)
|
||||
|
||||
class isSDXL:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -419,8 +909,52 @@ class xyAny:
|
||||
|
||||
return (new_x, new_y)
|
||||
|
||||
class batchAnything:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"any_1": (AlwaysEqualProxy("*"),{}),
|
||||
"any_2": (AlwaysEqualProxy("*"),{})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy("*"),)
|
||||
RETURN_NAMES = ("batch",)
|
||||
|
||||
FUNCTION = "batch"
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
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,)
|
||||
elif any_2 is None:
|
||||
return (any_1,)
|
||||
if any_1.shape[1:] != any_2.shape[1:]:
|
||||
any_2 = comfy.utils.common_upscale(any_2.movedim(-1, 1), any_1.shape[2], any_1.shape[1], "bilinear", "center").movedim(1, -1)
|
||||
return (torch.cat((any_1, any_2), 0),)
|
||||
elif isinstance(any_1, (str, float, int)):
|
||||
if any_2 is None:
|
||||
return (any_1,)
|
||||
elif isinstance(any_2, tuple):
|
||||
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),)
|
||||
else:
|
||||
if any_1 is None:
|
||||
return (any_2,)
|
||||
elif any_2 is None:
|
||||
return (any_1,)
|
||||
return (any_1 + any_2,)
|
||||
|
||||
# 转换所有类型
|
||||
class ConvertAnything:
|
||||
class convertAnything:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
@@ -434,7 +968,6 @@ class ConvertAnything:
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
def convert(self, *args, **kwargs):
|
||||
print(kwargs)
|
||||
anything = kwargs['*']
|
||||
output_type = kwargs['output_type']
|
||||
params = None
|
||||
@@ -519,6 +1052,24 @@ class showTensorShape:
|
||||
|
||||
return {"ui": {"text": shapes}}
|
||||
|
||||
class outputToList:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"tuple": (AlwaysEqualProxy("*"), {}),
|
||||
}, "optional": {},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy("*"),)
|
||||
RETURN_NAMES = ("list",)
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
FUNCTION = "output_to_List"
|
||||
CATEGORY = "EasyUse/Logic"
|
||||
|
||||
def output_to_List(self, tuple):
|
||||
return (tuple,)
|
||||
|
||||
# cleanGpuUsed
|
||||
class cleanGPUUsed:
|
||||
@classmethod
|
||||
@@ -577,8 +1128,83 @@ class clearCacheAll:
|
||||
remove_cache('*')
|
||||
return ()
|
||||
|
||||
# Deprecated
|
||||
class If:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"any": (AlwaysEqualProxy("*"),),
|
||||
"if": (AlwaysEqualProxy("*"),),
|
||||
"else": (AlwaysEqualProxy("*"),),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (AlwaysEqualProxy("*"),)
|
||||
RETURN_NAMES = ("?",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "EasyUse/🚫 Deprecated"
|
||||
DEPRECATED = True
|
||||
|
||||
def execute(self, *args, **kwargs):
|
||||
return (kwargs['if'] if kwargs['any'] else kwargs['else'],)
|
||||
|
||||
class poseEditor:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"image": ("STRING", {"default":""})
|
||||
}}
|
||||
|
||||
FUNCTION = "output_pose"
|
||||
CATEGORY = "EasyUse/🚫 Deprecated"
|
||||
DEPRECATED = True
|
||||
RETURN_TYPES = ()
|
||||
RETURN_NAMES = ()
|
||||
def output_pose(self, image):
|
||||
return ()
|
||||
|
||||
class imageToMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"image": ("IMAGE",),
|
||||
"channel": (['red', 'green', 'blue'],),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "convert"
|
||||
CATEGORY = "EasyUse/🚫 Deprecated"
|
||||
DEPRECATED = True
|
||||
|
||||
def convert_to_single_channel(self, image, channel='red'):
|
||||
from PIL import Image
|
||||
# Convert to RGB mode to access individual channels
|
||||
image = image.convert('RGB')
|
||||
|
||||
# Extract the desired channel and convert to greyscale
|
||||
if channel == 'red':
|
||||
channel_img = image.split()[0].convert('L')
|
||||
elif channel == 'green':
|
||||
channel_img = image.split()[1].convert('L')
|
||||
elif channel == 'blue':
|
||||
channel_img = image.split()[2].convert('L')
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invalid channel option. Please choose 'red', 'green', or 'blue'.")
|
||||
|
||||
# Convert the greyscale channel back to RGB mode
|
||||
channel_img = Image.merge(
|
||||
'RGB', (channel_img, channel_img, channel_img))
|
||||
|
||||
return channel_img
|
||||
|
||||
def convert(self, image, channel='red'):
|
||||
from .libs.image import pil2tensor, tensor2pil
|
||||
image = self.convert_to_single_channel(tensor2pil(image), channel)
|
||||
image = pil2tensor(image)
|
||||
return (image.squeeze().mean(2),)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"easy string": String,
|
||||
@@ -587,18 +1213,35 @@ NODE_CLASS_MAPPINGS = {
|
||||
"easy float": Float,
|
||||
"easy rangeFloat": RangeFloat,
|
||||
"easy boolean": Boolean,
|
||||
"easy mathString": mathStringOperation,
|
||||
"easy mathInt": mathIntOperation,
|
||||
"easy mathFloat": mathFloatOperation,
|
||||
"easy compare": Compare,
|
||||
"easy imageSwitch": imageSwitch,
|
||||
"easy textSwitch": textSwitch,
|
||||
"easy if": If,
|
||||
"easy anythingIndexSwitch": anythingIndexSwitch,
|
||||
"easy imageIndexSwitch": imageIndexSwitch,
|
||||
"easy textIndexSwitch": textIndexSwitch,
|
||||
"easy conditioningIndexSwitch": conditioningIndexSwitch,
|
||||
"easy whileLoopStart": whileLoopStart,
|
||||
"easy whileLoopEnd": whileLoopEnd,
|
||||
"easy forLoopStart": forLoopStart,
|
||||
"easy forLoopEnd": forLoopEnd,
|
||||
"easy ifElse": IfElse,
|
||||
"easy isNone": isNone,
|
||||
"easy isSDXL": isSDXL,
|
||||
"easy outputToList": outputToList,
|
||||
"easy xyAny": xyAny,
|
||||
"easy convertAnything": ConvertAnything,
|
||||
"easy batchAnything": batchAnything,
|
||||
"easy convertAnything": convertAnything,
|
||||
"easy showAnything": showAnything,
|
||||
"easy showTensorShape": showTensorShape,
|
||||
"easy clearCacheKey": clearCacheKey,
|
||||
"easy clearCacheAll": clearCacheAll,
|
||||
"easy cleanGpuUsed": cleanGPUUsed,
|
||||
"easy if": If,
|
||||
"easy poseEditor": poseEditor,
|
||||
"easy imageToMask": imageToMask
|
||||
}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy string": "String",
|
||||
@@ -608,15 +1251,32 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"easy rangeFloat": "Range(Float)",
|
||||
"easy boolean": "Boolean",
|
||||
"easy compare": "Compare",
|
||||
"easy mathString": "Math String",
|
||||
"easy mathInt": "Math Int",
|
||||
"easy mathFloat": "Math Float",
|
||||
"easy imageSwitch": "Image Switch",
|
||||
"easy textSwitch": "Text Switch",
|
||||
"easy if": "If",
|
||||
"easy anythingIndexSwitch": "Any Index Switch",
|
||||
"easy imageIndexSwitch": "Image Index Switch",
|
||||
"easy textIndexSwitch": "Text Index Switch",
|
||||
"easy conditioningIndexSwitch": "Conditioning Index Switch",
|
||||
"easy whileLoopStart": "While Loop Start",
|
||||
"easy whileLoopEnd": "While Loop End",
|
||||
"easy forLoopStart": "For Loop Start",
|
||||
"easy forLoopEnd": "For Loop End",
|
||||
"easy ifElse": "If else",
|
||||
"easy isNone": "Is None",
|
||||
"easy isSDXL": "Is SDXL",
|
||||
"easy outputToList": "Output to List",
|
||||
"easy xyAny": "XYAny",
|
||||
"easy batchAnything": "Batch Any",
|
||||
"easy convertAnything": "Convert Any",
|
||||
"easy showAnything": "Show Any",
|
||||
"easy showTensorShape": "Show Tensor Shape",
|
||||
"easy clearCacheKey": "Clear Cache Key",
|
||||
"easy clearCacheAll": "Clear Cache All",
|
||||
"easy cleanGpuUsed": "Clean GPU Used"
|
||||
"easy cleanGpuUsed": "Clean GPU Used",
|
||||
"easy if": "If (🚫Deprecated)",
|
||||
"easy poseEditor": "PoseEditor (🚫Deprecated)",
|
||||
"easy imageToMask": "ImageToMask (🚫Deprecated)"
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[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.1"
|
||||
version = "1.2.2"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["diffusers>=0.25.0", "accelerate>=0.25.0", "clip_interrogator>=0.6.0", "sentencepiece", "lark-parser", "onnxruntime", "spandrel", "opencv-python"]
|
||||
|
||||
|
||||
@@ -50,6 +50,9 @@ textarea{
|
||||
.comfy-modal button {
|
||||
border-width:1px;
|
||||
}
|
||||
.comfy-modal-content{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
dialog{
|
||||
@@ -7,7 +7,7 @@ import { $t } from '../common/i18n.js';
|
||||
import { findWidgetByName, toggleWidget, updateNodeHeight} from "../common/utils.js";
|
||||
|
||||
const seedNodes = ["easy seed", "easy latentNoisy", "easy wildcards", "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingNoiseIn", "easy preSamplingSdTurbo", "easy preSamplingCascade", "easy preSamplingDynamicCFG", "easy preSamplingLayerDiffusion", "easy fullkSampler", "easy fullCascadeKSampler"]
|
||||
const loaderNodes = ["easy fullLoader", "easy a1111Loader", "easy comfyLoader", "easy hunyuanDiTLoader", "easy pixArtLoader"]
|
||||
const loaderNodes = ["easy fullLoader", "easy a1111Loader", "easy comfyLoader", "easy fluxLoader", "easy hunyuanDiTLoader", "easy pixArtLoader"]
|
||||
|
||||
function widgetLogic(node, widget) {
|
||||
if (widget.name === 'lora_name') {
|
||||
@@ -697,6 +697,7 @@ app.registerExtension({
|
||||
switch (node.comfyClass){
|
||||
case "easy fullLoader":
|
||||
case "easy a1111Loader":
|
||||
case "easy fluxLoader":
|
||||
case "easy comfyLoader":
|
||||
case "easy cascadeLoader":
|
||||
case "easy svdLoader":
|
||||
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