Fix lazy hash calculation for checkpoints in extra paths

- Allow empty sha256 when hash_status is 'pending' in cache entry validator
- Add on-demand hash calculation during bulk metadata refresh for checkpoints
  with pending hash status
- Add comprehensive tests for both fixes

Fixes issue where checkpoints in extra paths were not visible in UI and
not processed during bulk metadata refresh due to empty sha256.
This commit is contained in:
Will Miao
2026-02-27 19:19:16 +08:00
parent 31901f1f0e
commit 77a2215e62
4 changed files with 487 additions and 10 deletions

View File

@@ -125,16 +125,20 @@ class CacheEntryValidator:
)
# Special validation: sha256 must not be empty for required field
# BUT allow empty sha256 when hash_status is pending (lazy hash calculation)
sha256 = working_entry.get('sha256', '')
hash_status = working_entry.get('hash_status', 'completed')
if not sha256 or (isinstance(sha256, str) and not sha256.strip()):
errors.append("Required field 'sha256' is empty")
# Cannot repair empty sha256 - entry is invalid
return ValidationResult(
is_valid=False,
repaired=repaired,
errors=errors,
entry=working_entry if auto_repair else None
)
# Allow empty sha256 for lazy hash calculation (checkpoints)
if hash_status != 'pending':
errors.append("Required field 'sha256' is empty")
# Cannot repair empty sha256 - entry is invalid
return ValidationResult(
is_valid=False,
repaired=repaired,
errors=errors,
entry=working_entry if auto_repair else None
)
# Normalize sha256 to lowercase if needed
if isinstance(sha256, str):

View File

@@ -47,8 +47,7 @@ class BulkMetadataRefreshUseCase:
to_process: Sequence[Dict[str, Any]] = [
model
for model in cache.raw_data
if model.get("sha256")
and not model.get("skip_metadata_refresh", False)
if not model.get("skip_metadata_refresh", False)
and not self._is_in_skip_path(model.get("folder", ""), skip_paths)
and (not model.get("civitai") or not model["civitai"].get("id"))
and not (
@@ -85,6 +84,36 @@ class BulkMetadataRefreshUseCase:
return {"success": False, "message": "Operation cancelled", "processed": processed, "updated": success, "total": total_models}
try:
original_name = model.get("model_name")
# Handle lazy hash calculation for models with pending hash status
sha256 = model.get("sha256", "")
hash_status = model.get("hash_status", "completed")
file_path = model.get("file_path")
if not sha256 and hash_status == "pending" and file_path:
self._logger.info(f"Calculating pending hash for {file_path}")
# Check if scanner has calculate_hash_for_model method (CheckpointScanner)
calculate_hash_method = getattr(self._service.scanner, "calculate_hash_for_model", None)
if calculate_hash_method:
sha256 = await calculate_hash_method(file_path)
if sha256:
model["sha256"] = sha256
model["hash_status"] = "completed"
else:
self._logger.error(f"Failed to calculate hash for {file_path}")
processed += 1
continue
else:
self._logger.warning(f"Scanner does not support lazy hash calculation for {file_path}")
processed += 1
continue
# Skip models without valid hash
if not model.get("sha256"):
self._logger.warning(f"Skipping model without hash: {file_path}")
processed += 1
continue
await MetadataManager.hydrate_model_data(model)
result, _ = await self._metadata_sync.fetch_and_update_model(
sha256=model["sha256"],