#!/usr/bin/env python3 """Generate a LoRA trigger word dictionary HTML page from .safetensors metadata. Usage: lora-trigger-sheet # default: ~/mnt/nimo.loc/ComfyUI/models/loras lora-trigger-sheet /path/to/loras # specify directory lora-trigger-sheet . # current directory lora-trigger-sheet /path/to/loras /path/to/output # specify both input and output """ import json import os import re import struct import sys from pathlib import Path def read_safetensors_meta(filepath): try: with open(filepath, "rb") as f: header_len = struct.unpack(" 0 top8_html = ", ".join( f"{_e(t)} ({c}x)" for t, c in top8 ) rest_html = "" more_id = "" if has_rest: more_id = "m_" + html_id() more_count = sum(c for _, c in rest) rest_html = " " + str(more_count) + " more…" rest_list = ", ".join( f"{_e(t)} ({c}x)" for t, c in rest ) rest_html += "\n " + rest_list + "" triggers = top8_html + rest_html else: no_trigger_files.append((fname_no_ext, tool, base)) triggers = "(none)" rows.append((fname_no_ext, tool, base, triggers)) num_files = len(rows) table_rows = "" for fname, tool, base, triggers in rows: table_rows += ( f" \n" f" {_e(fname)}\n" f" {_e(tool)}\n" f" {_e(base)}\n" f" {triggers}\n" f" \n" ) html = f""" LoRA Info Sheet

LoRA Info Sheet

{num_files} LoRA files · {num_files} visible

{num_files} / {num_files}
{table_rows}
File Tool Base Trigger(s)
""" return html def _e(s): """Escape HTML entities.""" s = str(s) s = s.replace("&", "&") s = s.replace("<", "<") s = s.replace(">", ">") s = s.replace('"', """) return s def main(): args = sys.argv[1:] if len(args) >= 1: target = args[0] else: target = os.path.expanduser("~/mnt/nimo.loc/ComfyUI/models/loras") target = os.path.abspath(os.path.expanduser(target)) if not os.path.isdir(target): print(f"Error: {target} is not a directory", file=sys.stderr) sys.exit(1) safetensors = sorted([ f for f in os.listdir(target) if f.endswith(".safetensors") and not f.startswith("._") ]) if not safetensors: print(f"No .safetensors files found in {target}", file=sys.stderr) sys.exit(1) loras = [] for fname in safetensors: fpath = os.path.join(target, fname) meta = read_safetensors_meta(fpath) loras.append((fname, meta)) html = generate_html(loras) if len(args) >= 2: out_path = os.path.abspath(os.path.expanduser(args[1])) else: out_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lora-info-sheet.html") with open(out_path, "w") as f: f.write(html) print(f"Generated {out_path} with {len(loras)} LoRA entries") if __name__ == "__main__": main()