From 4b0e0e16c5c7ec5efb032953f01c2ed6bdbc8d9a Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 4 Dec 2024 10:18:21 +0000 Subject: [PATCH] asdfsd --- __init__.py | 0 nodes.py | 184 +++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 14 ++++ requirements.txt | 1 + 4 files changed, 199 insertions(+) create mode 100644 __init__.py create mode 100644 nodes.py create mode 100644 pyproject.toml create mode 100644 requirements.txt diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes.py b/nodes.py new file mode 100644 index 0000000..5bb4318 --- /dev/null +++ b/nodes.py @@ -0,0 +1,184 @@ +import os + +import comfy.sd +import comfy.utils +from huggingface_hub import hf_hub_download +import requests +import hashlib + + +def download_file(url, filename): + # make dirs recursively + os.makedirs(os.path.dirname(filename), exist_ok=True) + response = requests.get(url, allow_redirects=True) + if response.status_code == 200: + with open(filename, 'wb') as file: + file.write(response.content) + else: + raise Exception(f"Failed to download file. Status code: {response.status_code}") + + +def get_filename_from_url(url: str, extension: str): + # md5 hash the url to get a unique filename + filename = hashlib.md5(url.encode()).hexdigest() + return f"{filename}.{extension}" + + +def find_or_create_cache(): + cwd = os.getcwd() + if os.path.exists(os.path.join(cwd, "ComfyUI")): + cwd = os.path.join(cwd, "ComfyUI") + if os.path.exists(os.path.join(cwd, "models")): + cwd = os.path.join(cwd, "models") + if not os.path.exists(os.path.join(cwd, "huggingface_cache")): + print("Creating huggingface_cache directory within comfy") + os.mkdir(os.path.join(cwd, "huggingface_cache")) + + return str(os.path.join(cwd, "huggingface_cache")) + + +def get_lora_from_url(url: str): + # clean the url + url = url.strip() + + # make sure it is a url + if url is None or url == "": + raise ValueError("URL is empty") + if not url.startswith("http"): + raise ValueError("Invalid URL") + + if "huggingface.co" in url: + # use hf hub download because it is faster + # strip the download=true query parameter - HF + if url.endswith("?download=true"): + url = url[:-len("?download=true")] + + # handle user copying the blob url - HF + if '/blob/' in url: + url = url.replace('/blob/', '/resolve/') + + # https://huggingface.co/owner_name/repo_name/resolve/main/file_name.safetensors + + if not url.lower().endswith("safetensors"): + raise ValueError("Only safetensors files are supported.") + + # parse hf repo from url + parser_string = url.replace("http://", "").replace("https://", "") + parts = parser_string.split("/") + # ['huggingface.co', 'owner_name', 'repo_name', 'resolve', 'main', 'file_name.safetensors'] + + # remove chunks that are not needed + repo_id = parts[1] + "/" + parts[2] + filename = parts[-1] + + # extract any depth of subfolders + # ['huggingface.co', 'owner_name', 'repo_name', 'resolve', 'main', 'subfolder', 'sub-subfolder', 'file_name.safetensors'] + subfolder = None + subfolder_length = len(parts) - 6 + + if subfolder_length > 0: + subfolder = "/".join(parts[5:-1]) + + lora_path = hf_hub_download( + repo_id=repo_id.strip(), + subfolder=subfolder, + filename=filename.strip(), + cache_dir=find_or_create_cache(), + ) + elif "civitai.com" in url: + # good https://civitai.com/api/download/models/0000000000?type=Model&format=SafeTensor + # bad https://civitai.com/models/111111111111?modelVersionId=0000000000 + + # fix bad url + if "modelVersionId" in url: + model_version_id = url.split("modelVersionId=")[1] + model_version_id = model_version_id.split("&")[0] + url = f"https://civitai.com/api/download/models/{model_version_id}?type=Model&format=SafeTensor" + + if not "SafeTensor" in url: + raise ValueError("Only safetensors files are supported for security reasons.") + + save_filename = get_filename_from_url(url, "safetensors") + + # check if env var for CIVITAI_API_KEY is set. Add after hashing the url + if "CIVITAI_API_KEY" in os.environ: + api_key = os.environ["CIVITAI_API_KEY"] + if api_key.strip() != "": + # add the api key to the url + url += f"&token={api_key}" + + # download the file + lora_path = os.path.join(find_or_create_cache(), 'civitai', save_filename) + # check if the file already exists + if not os.path.exists(lora_path): + # will fail for most if api key not set + download_file(url, lora_path) + else: + # could be stored somewhere else + if not url.lower().split("?")[0].endswith("safetensors"): + raise ValueError("Only safetensors files are supported for security reasons.") + + # try to download the file + save_filename = get_filename_from_url(url, "safetensors") + lora_path = os.path.join(find_or_create_cache(), 'general', save_filename) + # check if the file already exists + if not os.path.exists(lora_path): + download_file(url, lora_path) + + return lora_path + + +class LoadLoraModelOnlyWithUrl: + CATEGORY = "loaders" + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "model": ("MODEL",), + "url": ("STRING", {"default": ""}), + "strength_model": ( + "FLOAT", + {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}, + ), + } + } + + RETURN_TYPES = ("MODEL",) + FUNCTION = "load_lora_model_only_from_url" + + def __init__(self): + self.loaded_lora = None + self.loaded_lora_path = None + + def load_lora_model_only_from_url( + self, + model, + url: str, + strength_model: float, + strength_clip: float, + ): + if strength_model == 0: + return (model, ) + + lora_path = get_lora_from_url(url) + + lora = None + if self.loaded_lora is not None: + if self.loaded_lora_path == lora_path: + lora = self.loaded_lora + else: + temp = self.loaded_lora + self.loaded_lora = None + del temp + self.loaded_lora_path = None + + if lora is None: + lora = comfy.utils.load_torch_file( + lora_path, safe_load=True) + self.loaded_lora = lora + self.loaded_lora_path = lora_path + model_lora, _ = comfy.sd.load_lora_for_models( + model, None, lora, strength_model, strength_clip + ) + return (model_lora, ) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..aa85d6a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[project] +name = "ComfyUI-LoadLoraModelOnlyWithUrl" +description = "ComfyUI-LoadLoraModelOnlyWithUrl" +version = "1.0.0" +license = "LICENSE" +dependencies = ["diffusers==0.24.0"] + +[project.urls] +Repository = "https://github.com/sourceful-official/LoadLoraModelOnlyWithUrl" + +[tool.comfy] +PublisherId = "sourceful-official" +DisplayName = "ComfyUI-LoadLoraModelOnlyWithUrl" +Icon = "S" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..02f4751 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +diffusers==0.24.0