Compare commits

...

4 Commits

Author SHA1 Message Date
Will Miao
7124b5293f chore(settings): remove unused example_images config, add unet folder_paths example 2026-05-27 19:58:56 +08:00
Will Miao
d2a04f8993 fix(model-hash-index): clean up AutoV2 entry in remove_by_hash 2026-05-27 19:38:08 +08:00
pixelpaws
7027a7c270 Merge pull request #946 from 1756141021/fix/autov2-hash-matching
fix: match local LoRAs by AutoV2 hash when Civitai model is deleted
2026-05-27 19:20:31 +08:00
hein
0a1d7dfd4c fix: match local LoRAs by AutoV2 hash when Civitai model is deleted
When recipe metadata contains AutoV2 hashes (10-char short hash from
image metadata) and the Civitai API cannot resolve them to SHA256
(model deleted, API offline), the local hash index failed to match
because it only stored full SHA256 hashes.

AutoV2 is simply SHA256[:10], so we derive it automatically in
add_entry() — no extra file I/O or schema changes needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-27 14:15:01 +08:00
2 changed files with 37 additions and 11 deletions

View File

@@ -7,6 +7,7 @@ class ModelHashIndex:
def __init__(self):
self._hash_to_path: Dict[str, str] = {}
self._filename_to_hash: Dict[str, str] = {}
self._autov2_to_path: Dict[str, str] = {}
# New data structures for tracking duplicates
self._duplicate_hashes: Dict[str, List[str]] = {} # sha256 -> list of paths
self._duplicate_filenames: Dict[str, List[str]] = {} # filename -> list of paths
@@ -63,6 +64,9 @@ class ModelHashIndex:
# Add new mappings
self._hash_to_path[sha256] = file_path
self._filename_to_hash[filename] = sha256
# AutoV2 = first 10 chars of SHA256
if len(sha256) >= 10:
self._autov2_to_path[sha256[:10]] = file_path
def _get_filename_from_path(self, file_path: str) -> str:
"""Extract filename without extension from path"""
@@ -157,7 +161,12 @@ class ModelHashIndex:
del self._duplicate_filenames[filename]
if filename in self._filename_to_hash:
del self._filename_to_hash[filename]
# Remove from AutoV2 index
autov2_keys_to_remove = [k for k, v in self._autov2_to_path.items() if v == file_path]
for k in autov2_keys_to_remove:
del self._autov2_to_path[k]
def remove_by_hash(self, sha256: str) -> None:
"""Remove entry by hash"""
sha256 = sha256.lower()
@@ -177,6 +186,10 @@ class ModelHashIndex:
# Remove hash-to-path mapping
del self._hash_to_path[sha256]
autov2_key = sha256[:10]
if autov2_key in self._autov2_to_path:
del self._autov2_to_path[autov2_key]
# Update filename-to-hash and duplicate filenames for all paths
for path_to_remove in paths_to_remove:
fname = self._get_filename_from_path(path_to_remove)
@@ -195,13 +208,24 @@ class ModelHashIndex:
# If only one entry remains, it's no longer a duplicate
del self._duplicate_filenames[fname]
def has_hash(self, sha256: str) -> bool:
"""Check if hash exists in index"""
return sha256.lower() in self._hash_to_path
def get_path(self, sha256: str) -> Optional[str]:
"""Get file path for a hash"""
return self._hash_to_path.get(sha256.lower())
def has_hash(self, hash_value: str) -> bool:
"""Check if hash exists in index (SHA256 or AutoV2)"""
normalized = hash_value.lower()
if normalized in self._hash_to_path:
return True
if len(normalized) == 10:
return normalized in self._autov2_to_path
return False
def get_path(self, hash_value: str) -> Optional[str]:
"""Get file path for a hash (SHA256 or AutoV2)"""
normalized = hash_value.lower()
path = self._hash_to_path.get(normalized)
if path is not None:
return path
if len(normalized) == 10:
return self._autov2_to_path.get(normalized)
return None
def get_hash(self, file_path: str) -> Optional[str]:
"""Get hash for a file path"""
@@ -218,6 +242,7 @@ class ModelHashIndex:
"""Clear all entries"""
self._hash_to_path.clear()
self._filename_to_hash.clear()
self._autov2_to_path.clear()
self._duplicate_hashes.clear()
self._duplicate_filenames.clear()

View File

@@ -10,13 +10,14 @@
"C:/path/to/your/checkpoints_folder",
"C:/path/to/another/checkpoints_folder"
],
"unet": [
"C:/path/to/your/diffusion_models_folder",
"C:/path/to/another/diffusion_models_folder"
],
"embeddings": [
"C:/path/to/your/embeddings_folder",
"C:/path/to/another/embeddings_folder"
]
},
"example_images_open_mode": "system",
"example_images_local_root": "",
"example_images_open_uri_template": "",
"auto_organize_exclusions": []
}