File size: 6,159 Bytes
9c98083 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 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:
@classmethod
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) |