Download worker/lora_from_url.py from nikdevs/qwen: direct link, hf CLI and curl.
- Browser
- Download file 2.96 kB
-
https://huggingface.co/nikdevs/qwen/resolve/main/worker/lora_from_url.py
- Command line
-
hf download hf://nikdevs/qwen/worker/lora_from_url.py
-
curl -L -o lora_from_url.py https://huggingface.co/nikdevs/qwen/resolve/main/worker/lora_from_url.py
2.96 kB
| """ComfyUI custom node: load a LoRA fetched from a URL at request time. | |
| Lets serverless workflows reference LoRAs by URL (HF, civitai, anywhere) | |
| instead of requiring the file to be pre-baked into the image. Downloads are | |
| cached on the worker's disk keyed by URL hash. Supports HF_TOKEN and | |
| CIVITAI_TOKEN env vars for authenticated downloads. | |
| """ | |
| import hashlib | |
| import logging | |
| import os | |
| import urllib.request | |
| import comfy.lora | |
| import comfy.sd | |
| import comfy.utils | |
| CACHE_DIR = "/lora-cache" | |
| os.makedirs(CACHE_DIR, exist_ok=True) | |
| def _fetch(url: str) -> str: | |
| path = os.path.join(CACHE_DIR, hashlib.sha1(url.encode()).hexdigest() + ".safetensors") | |
| if os.path.exists(path): | |
| return path | |
| headers = {} | |
| hf_token = os.environ.get("HF_TOKEN") | |
| if hf_token and "huggingface.co" in url: | |
| headers["Authorization"] = f"Bearer {hf_token}" | |
| civitai_token = os.environ.get("CIVITAI_TOKEN") | |
| if civitai_token and "civitai" in url: | |
| url += ("&" if "?" in url else "?") + "token=" + civitai_token | |
| req = urllib.request.Request(url, headers=headers) | |
| tmp = path + ".part" | |
| with urllib.request.urlopen(req, timeout=600) as r, open(tmp, "wb") as f: | |
| while chunk := r.read(1 << 20): | |
| f.write(chunk) | |
| os.rename(tmp, path) | |
| return path | |
| class LoraFromURLModelOnly: | |
| def INPUT_TYPES(cls): | |
| return { | |
| "required": { | |
| "model": ("MODEL",), | |
| "url": ("STRING", {"default": ""}), | |
| "strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}), | |
| } | |
| } | |
| RETURN_TYPES = ("MODEL",) | |
| FUNCTION = "load" | |
| CATEGORY = "loaders" | |
| def load(self, model, url, strength): | |
| url = (url or "").strip() | |
| name = url.rsplit("/", 1)[-1] or "lora" | |
| if not url or strength == 0: | |
| logging.info(f"[lora_from_url] {name}: skipped (empty url / strength 0)") | |
| return (model,) | |
| lora_sd = comfy.utils.load_torch_file(_fetch(url), safe_load=True) | |
| total = len(lora_sd) | |
| # How many lora keys actually map onto this model's weights — the | |
| # definitive "did it bind" signal. load_lora consumes matched keys and | |
| # returns the leftovers it could not place. | |
| key_map = comfy.lora.model_lora_keys_unet(model.model, {}) | |
| loaded = comfy.lora.load_lora(lora_sd, key_map) | |
| matched = len(loaded) | |
| model_lora, _ = comfy.sd.load_lora_for_models(model, None, lora_sd, strength, 0) | |
| logging.info( | |
| f"[lora_from_url] {name}: matched {matched} target modules " | |
| f"from {total} tensors at strength {strength}" | |
| + (" ⚠ ZERO MATCHES — lora did NOT bind" if matched == 0 else "") | |
| ) | |
| return (model_lora,) | |
| NODE_CLASS_MAPPINGS = {"LoraFromURLModelOnly": LoraFromURLModelOnly} | |
| NODE_DISPLAY_NAME_MAPPINGS = {"LoraFromURLModelOnly": "Load LoRA from URL (model only)"} | |