import os import comfy.sd import comfy.utils import folder_paths import json import urllib.request import urllib.parse _TRIPLE_LORA_CACHE = {} CACHE_FILE = os.path.join(os.path.dirname(__file__), "dolphin_lora_trigger_cache.json") def get_trigger_words(lora_name): if lora_name == "None": return [] cache = {} if os.path.exists(CACHE_FILE): try: with open(CACHE_FILE, "r") as f: cache = json.load(f) except: pass if lora_name in cache: return cache[lora_name] try: # ๐Ÿ’ก ์š”์ฒญํ•˜์‹  civitaired.com ๋„๋ฉ”์ธ API๋กœ ๋ณ€๊ฒฝ # API ๊ตฌ์กฐ๊ฐ€ civitai.com๊ณผ ๋™์ผํ•˜๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ ์šฉ query = urllib.parse.quote(lora_name.replace(".safetensors", "")) url = f"https://civitaired.com/api/v1/model-versions/by-file?query={query}" req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) with urllib.request.urlopen(req, timeout=5) as res: data = json.load(res) # trainedWords ํ‚ค๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ triggers = data.get("trainedWords", []) cache[lora_name] = triggers with open(CACHE_FILE, "w") as f: json.dump(cache, f) return triggers except Exception as e: print(f"โš ๏ธ [Dolphin] civitaired.com ํŠธ๋ฆฌ๊ฑฐ ์›Œ๋“œ ์กฐํšŒ ์‹คํŒจ: {e}") return [] class DolphinTripleLoraMatrix: @classmethod def INPUT_TYPES(s): loras = ["None"] + folder_paths.get_filename_list("loras") inputs = { "model_base": ("MODEL",), "clip_base": ("CLIP",), "model_high": ("MODEL",), "clip_high": ("CLIP",), "model_low": ("MODEL",), "clip_low": ("CLIP",), } for i in range(1, 7): inputs[f"lora_{i}"] = (loras, {"default": "None"}) inputs[f"weights_{i}"] = ("STRING", {"default": "0.0, 0.0, 0.0"}) return {"required": inputs} RETURN_TYPES = ("MODEL", "CLIP", "MODEL", "CLIP", "MODEL", "CLIP", "STRING") RETURN_NAMES = ("M_BASE", "C_BASE", "M_HIGH", "C_HIGH", "M_LOW", "C_LOW", "trigger_words") FUNCTION = "apply_matrix" CATEGORY = "Dolphin" def apply_matrix(self, model_base, clip_base, model_high, clip_high, model_low, clip_low, **kwargs): m_b, c_b = model_base, clip_base m_h, c_h = model_high, clip_high m_l, c_l = model_low, clip_low all_triggers = [] for i in range(1, 7): lora_name = kwargs.get(f"lora_{i}") w_str = kwargs.get(f"weights_{i}") if lora_name == "None": continue # ํŠธ๋ฆฌ๊ฑฐ ์›Œ๋“œ ์ˆ˜์ง‘ (civitaired.com ์—ฐ๋™) all_triggers.extend(get_trigger_words(lora_name)) try: parts = [float(x.strip()) for x in w_str.split(',')] wb, wh, wl = parts[0], parts[1], parts[2] except: continue if lora_name not in _TRIPLE_LORA_CACHE: path = folder_paths.get_full_path("loras", lora_name) _TRIPLE_LORA_CACHE[lora_name] = comfy.utils.load_torch_file(path) data = _TRIPLE_LORA_CACHE[lora_name] if wb != 0: m_b, c_b = comfy.sd.load_lora_for_models(m_b, c_b, data, wb, wb) if wh != 0: m_h, c_h = comfy.sd.load_lora_for_models(m_h, c_h, data, wh, wh) if wl != 0: m_l, c_l = comfy.sd.load_lora_for_models(m_l, c_l, data, wl, wl) return (m_b, c_b, m_h, c_h, m_l, c_l, ", ".join(list(set(all_triggers))))