import json import folder_paths # Import parent LoraLoader from ComfyUI built-in nodes from nodes import LoraLoader from .cache_manager import cache_manager class KaiCivitaiLoRALoader(LoraLoader): @classmethod def INPUT_TYPES(s): return { "required": { "model": ("MODEL", {}), "clip": ("CLIP", {}), "lora_name": (folder_paths.get_filename_list("loras"), {}), "strength_model": ( "FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}, ), "strength_clip": ( "FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}, ), } } RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING") RETURN_NAMES = ("model", "clip", "trigger_words", "civitai_json") FUNCTION = "load_lora_with_info" CATEGORY = "KaiUtilities/loaders" def load_lora_with_info(self, model, clip, lora_name, strength_model, strength_clip): # Load LoRA using parent logic model_out, clip_out = self.load_lora( model, clip, lora_name, strength_model, strength_clip ) # Get cached info if available (node does NOT auto-fetch; user must click button) try: lora_path = folder_paths.get_full_path_or_raise("loras", lora_name) except (FileNotFoundError, KeyError): # If path resolution fails, still return LoRA outputs with empty extras return (model_out, clip_out, "", "") # Use sync cache lookup because ComfyUI node FUNCTIONs run synchronously # in worker threads (not in the async event loop). The sync hash function # is safe here because worker threads can block on file I/O. try: cache = cache_manager.get_cache_for_file_sync(lora_path) except Exception: # Defensive: any unexpected failure in cache lookup should not crash the node return (model_out, clip_out, "", "") trigger_words = "" civitai_json = "" if cache: words = cache.get("triggerWords") if isinstance(words, list): trigger_words = ", ".join(str(w) for w in words) civitai_json = json.dumps(cache) return (model_out, clip_out, trigger_words, civitai_json)