Guest User

Untitled

a guest
Feb 11th, 2025
127
0
64 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.34 KB | None | 0 0
  1. import os
  2. import hashlib
  3. import functools
  4. from typing import List
  5. from pathlib import Path
  6.  
  7. import git
  8.  
  9. import folder_paths
  10.  
  11.  
  12. @functools.lru_cache(maxsize=128)
  13. def addnet_hash_safetensors(filepath: str) -> str:
  14.     """Cached version of kohya-ss hash for safetensors"""
  15.     hash_sha256 = hashlib.sha256()
  16.     blksize = 1024 * 1024
  17.  
  18.     with open(filepath, "rb") as b:
  19.         header = b.read(8)
  20.         n = int.from_bytes(header, "little")
  21.  
  22.         offset = n + 8
  23.         b.seek(offset)
  24.         for chunk in iter(lambda: b.read(blksize), b""):
  25.             hash_sha256.update(chunk)
  26.  
  27.     return hash_sha256.hexdigest()
  28.  
  29. class Lora:
  30.     def __init__(self, name: str, unet: float, te: float, path: str):
  31.         self.name = name
  32.         self.unet = unet
  33.         self.te = te
  34.         self.path = path
  35.         self.full_path = folder_paths.get_full_path("loras", self.path)
  36.  
  37.         if self.full_path:
  38.             self.hash = addnet_hash_safetensors(self.full_path)[:12]
  39.  
  40.     def __str__(self):
  41.         if self.unet != self.te:
  42.             return f"<lora:{self.name}:unet={self.unet}:te={self.te}>"
  43.         return f"<lora:{self.name}:{self.unet}>"
  44.  
  45. def extract_loras(workflow: dict) -> List[Lora]:
  46.     result = []
  47.     for node in workflow["nodes"]:
  48.         if node["type"] == "Power Lora Loader (rgthree)":
  49.             for widget in node.get("widgets_values", []):
  50.                 if isinstance(widget, dict) and widget.get("on"):
  51.                     lora_path = widget["lora"]
  52.                     name = os.path.splitext(os.path.basename(lora_path))[0]
  53.                     unet = widget["strength"]
  54.                     te = widget["strengthTwo"]
  55.                     result.append(Lora(name=name, unet=unet, te=te, path=lora_path))
  56.     return result
  57.  
  58.  
  59. class AddA1111LikeMetadata:
  60.     @classmethod
  61.     def INPUT_TYPES(s):
  62.         return {
  63.             "required": {
  64.                 "positive": ("STRING", {"forceInput": True}),
  65.                 "negative": ("STRING", {"forceInput": True}),
  66.                 "seed": ("INT", {"forceInput": True}),
  67.                 "model": ("STRING", {"forceInput": True}),
  68.                 "include_hashes": ("BOOLEAN", {"default": True}),
  69.             },
  70.             "hidden": {"extra_pnginfo": "EXTRA_PNGINFO"},
  71.         }
  72.  
  73.     DESCRIPTION = "Adds A1111-like metadata to the PNG info."
  74.  
  75.     RETURN_TYPES = ()
  76.     OUTPUT_NODE = True
  77.  
  78.     FUNCTION = "add_a1111_metadata"
  79.  
  80.     _version = None
  81.  
  82.     @classmethod
  83.     def get_version(cls):
  84.         if cls._version is None:
  85.             try:
  86.                 repo = git.Repo(os.getcwd())
  87.                 version_str = repo.git.describe(tags=True).strip()
  88.                 if repo.active_branch.name != "master":
  89.                     version_str += f" ({repo.active_branch.name})"
  90.                 cls._version = version_str
  91.             except Exception:
  92.                 cls._version = "(Unknown version)"
  93.         return cls._version
  94.  
  95.     def build_metadata(self, positive: str, negative: str, seed: int, include_hashes: bool, model: str, loras: List[Lora]):
  96.         metadata = {
  97.             "Negative prompt": negative,
  98.             "Seed": seed,
  99.             "Model": model,
  100.         }
  101.  
  102.         if include_hashes and loras:
  103.             metadata.update({
  104.                 "Lora hashes": f'"{", ".join([f"{lora.name}: {lora.hash}" for lora in loras])}"'
  105.             })
  106.  
  107.         parts = [(positive + '\n' + ' '.join(str(lora) for lora in loras)).strip()]
  108.         parts.extend(f"{key}: {value}" for key, value in metadata.items())
  109.         parts.append(f"Version: ComfyUI {self.get_version()}")
  110.  
  111.         final_string = "\n".join([parts[0], parts[1], ", ".join(parts[2:])]).strip() + " [Full workflow included in the file]"
  112.         return final_string
  113.  
  114.  
  115.     def add_a1111_metadata(self, positive, negative, seed, model, include_hashes, extra_pnginfo=None):
  116.         if extra_pnginfo is not None:
  117.             extra_pnginfo["parameters"] = self.build_metadata(
  118.                 positive,
  119.                 negative,
  120.                 seed,
  121.                 include_hashes,
  122.                 Path(model).stem,
  123.                 extract_loras(extra_pnginfo['workflow']),
  124.             )
  125.  
  126.         return {}
  127.  
  128. NODE_CLASS_MAPPINGS = {
  129.     "AddA1111LikeMetadata": AddA1111LikeMetadata,
  130. }
  131.  
  132. NODE_DISPLAY_NAME_MAPPINGS = {
  133.     "AddA1111LikeMetadata": "Add A1111-like Metadata",
  134. }
  135.  
Advertisement
Add Comment
Please, Sign In to add comment