Refactor model response inclusion to only include groups with multiple models; update model removal logic to accept hash value. See #221

This commit is contained in:
Will Miao
2025-06-11 19:52:44 +08:00
parent e0d9880b32
commit eb01ad3af9
6 changed files with 48 additions and 25 deletions

View File

@@ -1209,7 +1209,7 @@ class ApiRoutes:
if primary_model:
group["models"].insert(0, self._format_lora_response(primary_model))
if group["models"]: # Only include if we found models
if len(group["models"]) > 1: # Only include if we found multiple models
result.append(group)
return web.json_response({

View File

@@ -735,7 +735,7 @@ class CheckpointsRoutes:
if primary_model:
group["models"].insert(0, self._format_checkpoint_response(primary_model))
if group["models"]:
if len(group["models"]) > 1: # Only include if we found multiple models
result.append(group)
return web.json_response({

View File

@@ -63,16 +63,16 @@ class ModelHashIndex:
"""Extract filename without extension from path"""
return os.path.splitext(os.path.basename(file_path))[0]
def remove_by_path(self, file_path: str) -> None:
def remove_by_path(self, file_path: str, hash_val: str = None) -> None:
"""Remove entry by file path"""
filename = self._get_filename_from_path(file_path)
hash_val = None
# Find the hash for this file path
for h, p in self._hash_to_path.items():
if p == file_path:
hash_val = h
break
if hash_val is None:
for h, p in self._hash_to_path.items():
if p == file_path:
hash_val = h
break
# If we didn't find a hash, nothing to do
if not hash_val:
@@ -219,16 +219,7 @@ class ModelHashIndex:
return set(self._filename_to_hash.keys())
def get_duplicate_hashes(self) -> Dict[str, List[str]]:
"""Get dictionary of duplicate hashes and their paths"""
# Remove entries that have only one path
hashes_to_remove = []
for sha256, paths in self._duplicate_hashes.items():
if len(paths) <= 1:
hashes_to_remove.append(sha256)
for sha256 in hashes_to_remove:
del self._duplicate_hashes[sha256]
"""Get dictionary of duplicate hashes and their paths"""
return self._duplicate_hashes
def get_duplicate_filenames(self) -> Dict[str, List[str]]:

View File

@@ -1342,7 +1342,7 @@ class ModelScanner:
hash_val = model.get('sha256', '').lower()
# Remove from hash index
self._hash_index.remove_by_path(file_path)
self._hash_index.remove_by_path(file_path, hash_val)
# Check and clean up duplicates
self._cleanup_duplicates_after_removal(hash_val, file_name)

View File

@@ -132,8 +132,6 @@ export function appendLoraCards(loras) {
}
export async function resetAndReload(updateFolders = false) {
const pageState = getCurrentPageState();
// Check if virtual scroller is available
if (state.virtualScroller) {
return resetAndReloadWithVirtualScroll({

View File

@@ -2,6 +2,8 @@
import { showToast } from '../utils/uiHelpers.js';
import { state, getCurrentPageState } from '../state/index.js';
import { formatDate } from '../utils/formatters.js';
import { resetAndReload as resetAndReloadLoras } from '../api/loraApi.js';
import { resetAndReload as resetAndReloadCheckpoints } from '../api/checkpointApi.js';
export class ModelDuplicatesManager {
constructor(pageManager, modelType = 'loras') {
@@ -536,11 +538,43 @@ export class ModelDuplicatesManager {
showToast(`Successfully deleted ${data.total_deleted} models`, 'success');
// Exit duplicate mode if deletions were successful
// If models were successfully deleted
if (data.total_deleted > 0) {
// Check duplicates count after deletion
this.checkDuplicatesCount();
this.exitDuplicateMode();
// Reload model data with updated folders
if (this.modelType === 'loras') {
await resetAndReloadLoras(true);
} else {
await resetAndReloadCheckpoints(true);
}
// Check if there are still duplicates
try {
const endpoint = `/api/${this.modelType}/find-duplicates`;
const dupResponse = await fetch(endpoint);
if (!dupResponse.ok) {
throw new Error(`Failed to get duplicates: ${dupResponse.statusText}`);
}
const dupData = await dupResponse.json();
const remainingDuplicatesCount = (dupData.duplicates || []).length;
// Update badge count
this.updateDuplicatesBadge(remainingDuplicatesCount);
// If no more duplicates, exit duplicate mode
if (remainingDuplicatesCount === 0) {
this.exitDuplicateMode();
} else {
// If duplicates remain, refresh duplicate groups display
this.duplicateGroups = dupData.duplicates || [];
this.selectedForDeletion.clear();
this.renderDuplicateGroups();
this.updateSelectedCount();
}
} catch (error) {
console.error('Error checking remaining duplicates:', error);
}
}
} catch (error) {