ComfyUI-Custom-Scripts icon indicating copy to clipboard operation
ComfyUI-Custom-Scripts copied to clipboard

Set preview images for all `lora` at once, and display preview images on `autocomplete lora text`

Open mijuku233 opened this issue 1 year ago • 8 comments

Is there a way to set previews for all loras at once? I have too many loras, and setting previews for them one by one is cumbersome and time-consuming.

In addition, when the mouse is hovering over Autocomplete lora text, It would be useful to be able to see a preview!

mijuku233 avatar Feb 01 '24 03:02 mijuku233

came here because I just ended up downloading a bunch more, and, yes... it's a pain.

ghostsquad avatar Feb 02 '24 23:02 ghostsquad

civit link auto downloads png previews and json files. These integrate perfectly with it.

marduk191 avatar Feb 20 '24 10:02 marduk191

civit link auto downloads png previews and json files. These integrate perfectly with it.

Sorry, could you be more specific? Which node downloads the previews?

ghostsquad avatar Mar 01 '24 20:03 ghostsquad

So, I ended up writing a janky lil' python script to handle image previews, if anyone here is handy with python and wants something they can kinda just run.

@pythongosssss I'd be happy to upstream this (after making it like, nicer) if you're interested, but I'd need to know what your preference is for activation - like, where should I put the button and how should this be triggered. My immediate thought is to have a checkbox somewhere that enables running on startup or something of that nature.

Also, how do you prefer your PRs? Forks I'm guessing?

Note if anyone plans on using this: You have to either get an api key from civitai and put that where it says REDACTED or just delete the authorization from the header entirely (which if I understood correctly would mean some models won't allow you to download their data?)

usage: python script.py <path-to-models-dir>

import os
import hashlib
from pathlib import Path
import requests
import sys
import json


def get_file_hash(file_path):
    hasher = hashlib.sha256()  # Using SHA256 for hashing
    with open(file_path, "rb") as file:
        chunk = file.read(4096)
        while chunk:
            hasher.update(chunk)
            chunk = file.read(4096)
    return hasher.hexdigest()


def get_model_image_url(file_path):
    file_hash = get_file_hash(file_path)
    api_url = f"https://civitai.com/api/v1/model-versions/by-hash/{file_hash}"
    headers = {"Content-Type": "application/json", "Authorization": "Bearer REDACTED"}
    response = requests.get(api_url, headers=headers)

    try:
        return response.json()["images"][0]["url"]
    except Exception as e:
        print(f"could not establish image url: {e}")


def save_model_preview_image(file_path):
    preview_path = file_path.with_suffix(".preview.png")
    if Path(preview_path).exists():
        print(f"{preview_path} exists.   Skipping...")
    else:
        image_url = get_model_image_url(file_path)
        if image_url is not None:
            response = requests.get(image_url)
            if response.status_code == 200:
                with open(preview_path, "wb") as f:
                    f.write(response.content)
        else:
            print(f"No image URL; Couldn't save image for {file_path}")


def fetch_and_save_previews(directory):
    # Walk through all directories and files in the specified directory
    for root, dirs, files in os.walk(directory):
        for filename in files:
            # Check if the file is a .safetensors file
            if filename.endswith(".safetensors"):
                file_path = Path(root) / filename
                save_model_preview_image(file_path)


if __name__ == "__main__":
    file_path = sys.argv[1]
    fetch_and_save_previews(file_path)

pksebben avatar Apr 12 '24 22:04 pksebben

this is good, yet, I feel like most of this logic already exists, and should be leveraged from here: ~~https://github.com/pythongosssss/ComfyUI-Custom-Scripts/blob/main/py/model_info.py~~

That way we get the previews, we get the .sha256 files, etc.

EDIT: Sorry, wrong place. Need to recheck, I thought this was all done in python somewhere.

ghostsquad avatar Apr 16 '24 15:04 ghostsquad

My bad. This all happens in JS here: https://github.com/pythongosssss/ComfyUI-Custom-Scripts/blob/3f2c021e50be2fed3c9d1552ee8dcaae06ad1fe5/web/js/common/modelInfoDialog.js#L211

https://github.com/pythongosssss/ComfyUI-Custom-Scripts/blob/3f2c021e50be2fed3c9d1552ee8dcaae06ad1fe5/web/js/common/modelInfoDialog.js#L270-L290

ghostsquad avatar Apr 16 '24 16:04 ghostsquad

@pksebben in the short term, this could be just a regular node. Not something that would run often, but loading up an empty workflow with just this one thing would be fine. Another idea for where it could be used is in the ComfyUI Manager as another button there.

ghostsquad avatar Apr 16 '24 18:04 ghostsquad

@pksebben I made some improvements to the script. Saving/Reading the .sha256 file in order to avoid hashing each model on every run.

import os
import hashlib
from pathlib import Path
import requests
import sys


def get_and_save_file_hash(file_path):
    sha256_path = file_path.with_suffix(".sha256")
    if Path(sha256_path).exists():
        print(f"existing hash found: {sha256_path}")
        with open(sha256_path, "r") as file:
            return str(file.read()).strip()

    print(f"hashing: {file_path}")
    hasher = hashlib.sha256()  # Using SHA256 for hashing
    with open(file_path, "rb") as file:
        chunk = file.read(4096)
        while chunk:
            hasher.update(chunk)
            chunk = file.read(4096)
    file_hash = str(hasher.hexdigest())

    with open(sha256_path, "w") as file:
        file.write(file_hash)

    return file_hash


def get_model_image_url(file_hash):
    api_url = f"https://civitai.com/api/v1/model-versions/by-hash/{file_hash}"
    print(f"getting model info from: {api_url}")
    headers = {"Content-Type": "application/json", "Authorization": "Bearer REDACTED"}
    response = requests.get(api_url, headers=headers)

    try:
        return response.json()["images"][0]["url"]
    except Exception as e:
        print(f"could not establish image url: {e}")


def save_model_meta(file_path):
    preview_path = file_path.with_suffix(".preview.png")
    file_hash = get_and_save_file_hash(file_path)
    if Path(preview_path).exists():
        print(f"{preview_path} exists.   Skipping...")
    else:
        image_url = get_model_image_url(file_hash)
        if image_url is not None:
            response = requests.get(image_url)
            if response.status_code == 200:
                with open(preview_path, "wb") as f:
                    f.write(response.content)
        else:
            print(f"No image URL; Couldn't save image for {file_path}")


def fetch_and_save_previews(directory):
    # Walk through all directories and files in the specified directory
    for root, _, files in os.walk(directory):
        for filename in files:
            # Check if the file is a .safetensors file
            if filename.endswith(".safetensors"):
                file_path = Path(root) / filename
                print(f"→ {file_path}")
                save_model_meta(file_path)


if __name__ == "__main__":
    file_path = sys.argv[1]
    fetch_and_save_previews(file_path)

ghostsquad avatar Apr 16 '24 23:04 ghostsquad