diff --git a/ComfyUI-Easy-Use.json b/ComfyUI-Easy-Use.json index 22c7c76..427122d 100644 --- a/ComfyUI-Easy-Use.json +++ b/ComfyUI-Easy-Use.json @@ -107,7 +107,8 @@ "positive_weight_interpretation": "正面权重理解", "negative": "负面提示词", "negative_token_normalization": "负面规范", - "negative_weight_interpretation": "负面权重理解" + "negative_weight_interpretation": "负面权重理解", + "a1111_prompt_style": "A1111提示词风格" }, "inputs": { "optional_lora_stack": "Lora堆(可选)", @@ -133,7 +134,8 @@ "empty_latent_height": "高", "batch_size": "每批生成数量", "positive": "正面提示词", - "negative": "负面提示词" + "negative": "负面提示词", + "a1111_prompt_style": "A1111提示词风格" }, "inputs": { "optional_lora_stack": "Lora堆(可选)" diff --git a/README.en.md b/README.en.md index b09c6d0..c138826 100644 --- a/README.en.md +++ b/README.en.md @@ -31,6 +31,7 @@ After installing the node package, the UI interface will be automatically switch **v1.0.1(Updated at 12/26/2023)** +- 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 diff --git a/README.md b/README.md index f24f320..8d8393b 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ **v1.0.1(2023-12-26)** +- 新增 `easy seed` - 简易随机种 - 修复 `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) 才能使用此功能 diff --git a/py/easyNodes.py b/py/easyNodes.py index 10b1aa9..7274a07 100644 --- a/py/easyNodes.py +++ b/py/easyNodes.py @@ -738,6 +738,33 @@ class easyXYPlot: easyCache = easyLoader() sampler = easySampler() + +def check_link_to_clip(node_id, clip_id, visited=None, node=None): + """Check if a given node links directly or indirectly to a loader node.""" + if visited is None: + visited = set() + + if node_id in visited: + return False + visited.add(node_id) + if "pipe" in node["inputs"]: + link_ids = node["inputs"]["pipe"] + for id in link_ids: + if id != 0 and id == str(clip_id): + return True + return False + +def find_nearest_steps(clip_id, prompt): + """Find the nearest KSampler or preSampling node that references the given id.""" + for id in prompt: + node = prompt[id] + if "Sampler" in node["class_type"] or "sampler" in node["class_type"] or "Sampling" in node["class_type"]: + # Check if this KSampler node directly or indirectly references the given CLIPTextEncode node + if check_link_to_clip(id, clip_id, None, node): + steps = node["inputs"]["steps"] if "steps" in node["inputs"] else 1 + return steps + return 1 + def find_wildcards_seed(text, prompt): if "__" in text: for i in prompt: @@ -1256,6 +1283,27 @@ class portraitMaster: return (prompt, negative_prompt,) +# 随机种 +class easySeed: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "seed_num": ("INT", {"default": 0, "min": 0, "max": 1125899906842624}), + }, + "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, + } + + RETURN_TYPES = ("INT",) + RETURN_NAMES = ("seed_num",) + FUNCTION = "doit" + + CATEGORY = "EasyUse/Prompt" + + OUTPUT_NODE = True + + def doit(self, seed_num=0, prompt=None, extra_pnginfo=None, my_unique_id=None): + return seed_num, # 全局随机种 class globalSeed: @classmethod @@ -1316,7 +1364,8 @@ class fullLoader: "batch_size": ("INT", {"default": 1, "min": 1, "max": 64}), }, "optional": {"model_override": ("MODEL",), "clip_override": ("CLIP",), "optional_lora_stack": ("LORA_STACK",), "a1111_prompt_style": ("BOOLEAN", {"default": a1111_prompt_style_default}),}, - "hidden": {"prompt": "PROMPT"}, "my_unique_id": "UNIQUE_ID"} + "hidden": {"prompt": "PROMPT", "my_unique_id": "UNIQUE_ID"} + } RETURN_TYPES = ("PIPE_LINE", "MODEL", "VAE", "CLIP") RETURN_NAMES = ("pipe", "model", "vae", "clip") @@ -1384,8 +1433,9 @@ class fullLoader: if a1111_prompt_style: if "smZ CLIPTextEncode" in ALL_NODE_CLASS_MAPPINGS: cls = ALL_NODE_CLASS_MAPPINGS['smZ CLIPTextEncode'] - positive_embeddings_final, = cls().encode(clipped, positive, positive_weight_interpretation, True, True, False, False, 6, 1024, 1024, 0, 0, 1024, 1024, '', '') - negative_embeddings_final, = cls().encode(clipped, negative, negative_weight_interpretation, True, True, False, False, 6, 1024, 1024, 0, 0, 1024, 1024, '', '') + steps = find_nearest_steps(my_unique_id, prompt) + positive_embeddings_final, = cls().encode(clipped, positive, "A1111", True, True, False, False, 6, 1024, 1024, 0, 0, 1024, 1024, '', '', steps) + negative_embeddings_final, = cls().encode(clipped, negative, "A1111", True, True, False, False, 6, 1024, 1024, 0, 0, 1024, 1024, '', '', steps) else: raise Exception(f"[ERROR] To use clip text encode same as webui, you need to install 'smzNodes'") else: @@ -1469,7 +1519,8 @@ class a1111Loader: "batch_size": ("INT", {"default": 1, "min": 1, "max": 64}), }, "optional": {"optional_lora_stack": ("LORA_STACK",), "a1111_prompt_style": ("BOOLEAN", {"default": a1111_prompt_style_default})}, - "hidden": {"prompt": "PROMPT",}, "my_unique_id": "UNIQUE_ID"} + "hidden": {"prompt": "PROMPT", "my_unique_id": "UNIQUE_ID"} + } RETURN_TYPES = ("PIPE_LINE", "MODEL", "VAE") RETURN_NAMES = ("pipe", "model", "vae") @@ -3591,6 +3642,7 @@ NODE_CLASS_MAPPINGS = { "easy loraStack": loraStackLoader, "easy controlnetLoader": controlnetSimple, "easy controlnetLoaderADV": controlnetAdvanced, + "easy seed": easySeed, "easy globalSeed": globalSeed, "easy preSampling": samplerSettings, "easy preSamplingAdvanced": samplerSettingsAdvanced, @@ -3625,6 +3677,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { "easy loraStack": "EasyLoraStack", "easy controlnetLoader": "EasyControlnet", "easy controlnetLoaderADV": "EasyControlnet (Advanced)", + "easy seed": "EasySeed", "easy globalSeed": "EasyGlobalSeed", "easy preSampling": "PreSampling", "easy preSamplingAdvanced": "PreSampling (Advanced)", diff --git a/py/server.py b/py/server.py index 5193a6c..50be3c6 100644 --- a/py/server.py +++ b/py/server.py @@ -128,7 +128,7 @@ def prompt_seed_update(json_data): if 'class_type' not in v: continue cls = v['class_type'] - if cls == "easy wildcards" or cls == "easy preSampling" or cls == "easy preSamplingAdvanced" or cls == "easy preSamplingSdTurbo" or cls == "easy preSamplingDynamicCFG" or cls == "easy fullkSampler": + if cls == "easy wildcards" or cls == "easy preSampling" or cls == "easy preSamplingAdvanced" or cls == "easy preSamplingSdTurbo" or cls == "easy preSamplingDynamicCFG" or cls == "easy fullkSampler" or cls == 'easy seed': extra_data = next((x for x in workflow["nodes"] if str(x["id"]) == k), None) if extra_data is not None: widgets_value = extra_data.get('widgets_values') diff --git a/py/wildcards.py b/py/wildcards.py index 34ac18d..e27e33e 100644 --- a/py/wildcards.py +++ b/py/wildcards.py @@ -51,7 +51,6 @@ def read_wildcard_dict(wildcard_path): read_wildcard(k, v) elif file.endswith('.json'): file_path = os.path.join(root, file) - print(file_path) try: with open(file_path, 'r') as f: json_data = json.load(f) diff --git a/web/js/easy/easyDynamicWidgets.js b/web/js/easy/easyDynamicWidgets.js index 0c67ce9..9fab60b 100644 --- a/web/js/easy/easyDynamicWidgets.js +++ b/web/js/easy/easyDynamicWidgets.js @@ -324,7 +324,7 @@ app.registerExtension({ }; } - if (["easy wildcards", "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingSdTurbo", "easy preSamplingDynamicCFG", "easy fullkSampler"].includes(nodeData.name)) { + if (["easy seed", "easy wildcards", "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingSdTurbo", "easy preSamplingDynamicCFG", "easy fullkSampler"].includes(nodeData.name)) { const onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = async function () { onNodeCreated ? onNodeCreated.apply(this, []) : undefined; diff --git a/web/js/seed.js b/web/js/seed.js index 9dff246..dc6c17e 100644 --- a/web/js/seed.js +++ b/web/js/seed.js @@ -16,7 +16,6 @@ function globalSeedHandler(event) { else{ if(node.widgets) { const w = node.widgets.find((w) => w.name == 'seed_num' || w.name == 'seed' || w.name == 'noise_seed'); - console.log(w) if(w && event.detail.seed_map[node.id] != undefined) { w.value = event.detail.seed_map[node.id]; }