mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-09 07:20:15 -03:00
feat(metadata): add CivitAI AutoV3 hash support across all storage layers
- Three-state autov3 field (not-checked / checked-unavailable / 12-hex value) in .metadata.json sidecars, in-memory ModelHashIndex, and SQLite (models.autov3 column + autov3_index table) with column-presence migration - Background self-terminating backfill for legacy rows: per-model-type concurrency guard, executor-offloaded I/O, Civitai-first resolution (SHA256-matched version file) falling back to the embedded safetensors header hash - Civitai-first propagation on metadata refresh, scan, and download paths; reject the empty-string SHA256 placeholder and strip OneTrainer 0x prefix - List API hash filters and hash index lookups accept 12-char AutoV3 - Cap safetensors header reads at 64 MiB to prevent crafted-file allocation - Prevent stale AutoV3 mappings on file replacement while preserving them on same-file re-registration (lazy-hash completion)
This commit is contained in:
@@ -9,6 +9,8 @@ from typing import Any
|
||||
from .constants import (
|
||||
CARD_PREVIEW_WIDTH,
|
||||
DEFAULT_HASH_CHUNK_SIZE_MB,
|
||||
INVALID_AUTOV3_EMPTY_HASH,
|
||||
MAX_SAFETENSORS_HEADER_BYTES,
|
||||
PREVIEW_EXTENSIONS,
|
||||
)
|
||||
from .exif_utils import ExifUtils
|
||||
@@ -90,6 +92,8 @@ def read_safetensors_metadata(file_path: str) -> dict[str, Any]:
|
||||
if len(header_len_bytes) < 8:
|
||||
return {}
|
||||
header_len = struct.unpack("<Q", header_len_bytes)[0]
|
||||
if header_len > MAX_SAFETENSORS_HEADER_BYTES:
|
||||
return {}
|
||||
header_bytes = f.read(header_len)
|
||||
if len(header_bytes) < header_len:
|
||||
return {}
|
||||
@@ -123,8 +127,16 @@ def calculate_autov3(file_path: str) -> str | None:
|
||||
return None
|
||||
|
||||
embedded_hash = metadata.get("sshs_model_hash") or metadata.get("modelspec.hash_sha256")
|
||||
if embedded_hash and isinstance(embedded_hash, str) and len(embedded_hash) >= 12:
|
||||
return embedded_hash[:12]
|
||||
if embedded_hash and isinstance(embedded_hash, str):
|
||||
# OneTrainer writes modelspec.hash_sha256 with a "0x" prefix.
|
||||
embedded_hash = embedded_hash.strip().removeprefix("0x").removeprefix("0X")
|
||||
if len(embedded_hash) >= 12:
|
||||
autov3 = embedded_hash[:12].lower()
|
||||
# The empty-string SHA256 placeholder written by some repackaging
|
||||
# tools is not a real hash; treat it as unavailable so broken
|
||||
# models never share one bogus value.
|
||||
if autov3 != INVALID_AUTOV3_EMPTY_HASH:
|
||||
return autov3
|
||||
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user