mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-07-03 07:51:16 -03:00
Cache corruption (NULL model_name/file_name from legacy DB rows or partial writes) caused format_response to raise KeyError/AttributeError, failing the entire /loras/list request and showing no models in the UI. Fix across three layers: - format_response (lora/checkpoint/embedding): replace direct dict[] access with .get() fallbacks; return None for entries missing file_path - handlers: filter None entries from list/excluded/fetch/duplicate/conflict endpoints instead of letting them crash or appear as null in responses - model_scanner: always use validate_batch repaired copies (previously discarded when no invalid entries, leaving None values in raw_data) - persistent_model_cache: add or-empty-string guards on read and write for nullable TEXT columns (model_name, file_name, folder, base_model, etc.)
78 lines
3.5 KiB
Python
78 lines
3.5 KiB
Python
import os
|
|
import logging
|
|
from typing import Dict, Optional
|
|
|
|
from .base_model_service import BaseModelService
|
|
from .auto_tag_service import extract_auto_tags
|
|
from ..utils.models import CheckpointMetadata
|
|
from ..config import config
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class CheckpointService(BaseModelService):
|
|
"""Checkpoint-specific service implementation"""
|
|
|
|
def __init__(self, scanner, update_service=None):
|
|
"""Initialize Checkpoint service
|
|
|
|
Args:
|
|
scanner: Checkpoint scanner instance
|
|
update_service: Optional service for remote update tracking.
|
|
"""
|
|
super().__init__("checkpoint", scanner, CheckpointMetadata, update_service=update_service)
|
|
|
|
async def format_response(self, checkpoint_data: Dict) -> Optional[Dict]:
|
|
"""Format Checkpoint data for API response.
|
|
|
|
Returns None when the entry is missing critical fields (corrupted cache
|
|
row), so the handler layer can filter it out. See issue #730.
|
|
"""
|
|
# Guard against corrupted cache entries missing critical fields
|
|
file_path = checkpoint_data.get("file_path")
|
|
if not file_path or not isinstance(file_path, str):
|
|
logger.warning(
|
|
"Skipping corrupted checkpoint entry (missing file_path): %s",
|
|
checkpoint_data.get("file_name", "<unknown>"),
|
|
)
|
|
return None
|
|
|
|
# Get sub_type from cache entry (new canonical field)
|
|
sub_type = checkpoint_data.get("sub_type", "checkpoint")
|
|
|
|
file_name = checkpoint_data.get("file_name") or ""
|
|
model_name = checkpoint_data.get("model_name") or file_name
|
|
folder = checkpoint_data.get("folder") or ""
|
|
|
|
return {
|
|
"model_name": model_name,
|
|
"file_name": file_name,
|
|
"preview_url": config.get_preview_static_url(checkpoint_data.get("preview_url", "")),
|
|
"preview_nsfw_level": checkpoint_data.get("preview_nsfw_level", 0),
|
|
"base_model": checkpoint_data.get("base_model", ""),
|
|
"folder": folder,
|
|
"sha256": checkpoint_data.get("sha256", ""),
|
|
"file_path": file_path.replace(os.sep, "/"),
|
|
"file_size": checkpoint_data.get("size", 0),
|
|
"modified": checkpoint_data.get("modified", ""),
|
|
"tags": checkpoint_data.get("tags", []),
|
|
"from_civitai": checkpoint_data.get("from_civitai", True),
|
|
"usage_count": checkpoint_data.get("usage_count", 0),
|
|
"notes": checkpoint_data.get("notes", ""),
|
|
"sub_type": sub_type,
|
|
"favorite": checkpoint_data.get("favorite", False),
|
|
"exclude": bool(checkpoint_data.get("exclude", False)),
|
|
"update_available": bool(checkpoint_data.get("update_available", False)),
|
|
"skip_metadata_refresh": bool(checkpoint_data.get("skip_metadata_refresh", False)),
|
|
"civitai": self.filter_civitai_data(checkpoint_data.get("civitai", {}), minimal=True),
|
|
"auto_tags": checkpoint_data.get("auto_tags") or extract_auto_tags(checkpoint_data),
|
|
"version_count": checkpoint_data.get("version_count"),
|
|
}
|
|
|
|
def find_duplicate_hashes(self) -> Dict:
|
|
"""Find Checkpoints with duplicate SHA256 hashes"""
|
|
return self.scanner._hash_index.get_duplicate_hashes()
|
|
|
|
def find_duplicate_filenames(self) -> Dict:
|
|
"""Find Checkpoints with conflicting filenames"""
|
|
return self.scanner._hash_index.get_duplicate_filenames()
|