File size: 3,555 Bytes
7aaa385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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))))