Download custom_nodes/dolphin_nodes/arch_logic.py from bjooo/tutorials: direct link, hf CLI and curl.
- Browser
- Download file 6.16 kB
-
https://huggingface.co/bjooo/tutorials/resolve/main/custom_nodes/dolphin_nodes/arch_logic.py
- Command line
-
hf download hf://bjooo/tutorials/custom_nodes/dolphin_nodes/arch_logic.py
-
curl -L -o arch_logic.py https://huggingface.co/bjooo/tutorials/resolve/main/custom_nodes/dolphin_nodes/arch_logic.py
6.16 kB
| import os | |
| import json | |
| import folder_paths | |
| import comfy.sd | |
| import comfy.utils | |
| from safetensors import safe_open | |
| import hashlib | |
| import urllib.request | |
| CACHE_FILE = os.path.join(os.path.dirname(__file__), "dolphin_tags_cache.json") | |
| def load_dolphin_cache(): | |
| if os.path.exists(CACHE_FILE): | |
| try: | |
| with open(CACHE_FILE, "r", encoding="utf-8") as f: | |
| return json.load(f) | |
| except: return {} | |
| return {} | |
| def save_dolphin_cache(cache_data): | |
| try: | |
| with open(CACHE_FILE, "w", encoding="utf-8") as f: | |
| json.dump(cache_data, f, indent=4) | |
| except: pass | |
| class DolphinArchitectV15: | |
| def INPUT_TYPES(s): | |
| loras = ["None"] + folder_paths.get_filename_list("loras") | |
| res = { | |
| "required": { | |
| "global_switch": ("BOOLEAN", {"default": True, "label_on": "GLOBAL ON", "label_off": "GLOBAL OFF (SKIP)"}), | |
| "model_base": ("MODEL",), "clip_base": ("CLIP",), | |
| "model_high": ("MODEL",), "clip_high": ("CLIP",), | |
| "model_low": ("MODEL",), "clip_low": ("CLIP",), | |
| }, | |
| "optional": {} | |
| } | |
| # [๋ค์ด์ดํธ ์๋ฃ] ์ค์ง ์ด๋ฆ๊ณผ ์จ์ดํธ๋ง ๋จ๊ฒจ์ ๊ฐ์ฅ ์์ UI๋ฅผ ๋ง๋ญ๋๋ค. | |
| res["optional"]["header_master"] = ("STRING", {"default": "โโโ [ MASTER: B+H ] โโโ", "multiline": False}) | |
| for i in range(1, 5): | |
| res["optional"][f"master_l_{i}"] = (loras, {"default": "None"}) | |
| res["optional"][f"master_b_w_{i}"] = ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}) | |
| res["optional"][f"master_h_w_{i}"] = ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}) | |
| res["optional"]["header_low"] = ("STRING", {"default": "โโโ [ LOW ONLY ] โโโ", "multiline": False}) | |
| for i in range(1, 5): | |
| res["optional"][f"low_l_{i}"] = (loras, {"default": "None"}) | |
| res["optional"][f"low_w_{i}"] = ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}) | |
| res["optional"]["manual_triggers"] = ("STRING", {"default": "", "multiline": True}) | |
| return res | |
| RETURN_TYPES = ("MODEL", "CLIP", "MODEL", "CLIP", "MODEL", "CLIP", "STRING") | |
| RETURN_NAMES = ("M_BASE", "C_BASE", "M_HIGH", "C_HIGH", "M_LOW", "C_LOW", "triggers") | |
| FUNCTION = "exec" | |
| CATEGORY = "Dolphin" | |
| def get_trig(self, lora_name): | |
| if lora_name == "None": return [] | |
| path = folder_paths.get_full_path("loras", lora_name) | |
| if not path or not os.path.exists(path): return [] | |
| triggers = [] | |
| try: | |
| with safe_open(path, framework="pt", device="cpu") as f: | |
| m = f.metadata() | |
| if m and "modelspec.trigger_words" in m: | |
| tw = json.loads(m["modelspec.trigger_words"]) | |
| if isinstance(tw, list): triggers.extend(tw) | |
| elif isinstance(tw, str): triggers.append(tw) | |
| except: pass | |
| if triggers: return triggers | |
| cache = load_dolphin_cache() | |
| if lora_name in cache and cache[lora_name]: return cache[lora_name] | |
| try: | |
| sha256_hash = hashlib.sha256() | |
| with open(path, "rb") as f: | |
| for byte_block in iter(lambda: f.read(4096 * 1024), b""): | |
| sha256_hash.update(byte_block) | |
| url = f"https://civitai.com/api/v1/model-versions/by-hash/{sha256_hash.hexdigest()}" | |
| req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) | |
| with urllib.request.urlopen(req, timeout=5) as response: | |
| data = json.loads(response.read().decode('utf-8')) | |
| api_triggers = data.get("trainedWords", []) | |
| if api_triggers: | |
| cache[lora_name] = api_triggers | |
| save_dolphin_cache(cache) | |
| return api_triggers | |
| except: pass | |
| return triggers | |
| def exec(self, global_switch, model_base, clip_base, model_high, clip_high, model_low, clip_low, manual_triggers="", **kwargs): | |
| mb, cb = model_base, clip_base | |
| mh, ch = model_high, clip_high | |
| ml, cl = model_low, clip_low | |
| if not global_switch: | |
| trigs = [t.strip() for t in manual_triggers.split(',') if t.strip()] | |
| ut = ", ".join(list(dict.fromkeys(trigs))) | |
| return (mb, cb, mh, ch, ml, cl, ut) | |
| applied_names = [] | |
| for i in range(1, 5): | |
| n = kwargs.get(f"master_l_{i}", "None") | |
| w_b = kwargs.get(f"master_b_w_{i}", 1.0) | |
| w_h = kwargs.get(f"master_h_w_{i}", 1.0) | |
| # [์ต์ ํ] None์ด ์๋๋ฉด์, ์จ์ดํธ๊ฐ 0.0์ด ์๋ ๋๋ง ์ ์ฉ (0.0์ด๋ฉด ์ค์์น OFF ํจ๊ณผ) | |
| if n != "None" and (w_b != 0.0 or w_h != 0.0): | |
| applied_names.append(n) | |
| lora_data = comfy.utils.load_torch_file(folder_paths.get_full_path("loras", n)) | |
| mb, cb = comfy.sd.load_lora_for_models(mb, cb, lora_data, w_b, w_b) | |
| mh, ch = comfy.sd.load_lora_for_models(mh, ch, lora_data, w_h, w_h) | |
| for i in range(1, 5): | |
| n = kwargs.get(f"low_l_{i}", "None") | |
| w = kwargs.get(f"low_w_{i}", 1.0) | |
| if n != "None" and w != 0.0: | |
| applied_names.append(n) | |
| lora_data = comfy.utils.load_torch_file(folder_paths.get_full_path("loras", n)) | |
| ml, cl = comfy.sd.load_lora_for_models(ml, cl, lora_data, w, w) | |
| trigs = [] | |
| for n in set(applied_names): | |
| trigs.extend(self.get_trig(n)) | |
| if manual_triggers.strip(): | |
| manual_list = [t.strip() for t in manual_triggers.split(',') if t.strip()] | |
| trigs.extend(manual_list) | |
| unique_trigs = ", ".join(list(dict.fromkeys(trigs))) | |
| return (mb, cb, mh, ch, ml, cl, unique_trigs) |