mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
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:
@@ -1209,7 +1209,7 @@ class ApiRoutes:
|
|||||||
if primary_model:
|
if primary_model:
|
||||||
group["models"].insert(0, self._format_lora_response(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)
|
result.append(group)
|
||||||
|
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
|
|||||||
@@ -735,7 +735,7 @@ class CheckpointsRoutes:
|
|||||||
if primary_model:
|
if primary_model:
|
||||||
group["models"].insert(0, self._format_checkpoint_response(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)
|
result.append(group)
|
||||||
|
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
|
|||||||
@@ -63,16 +63,16 @@ class ModelHashIndex:
|
|||||||
"""Extract filename without extension from path"""
|
"""Extract filename without extension from path"""
|
||||||
return os.path.splitext(os.path.basename(file_path))[0]
|
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"""
|
"""Remove entry by file path"""
|
||||||
filename = self._get_filename_from_path(file_path)
|
filename = self._get_filename_from_path(file_path)
|
||||||
hash_val = None
|
|
||||||
|
|
||||||
# Find the hash for this file path
|
# Find the hash for this file path
|
||||||
for h, p in self._hash_to_path.items():
|
if hash_val is None:
|
||||||
if p == file_path:
|
for h, p in self._hash_to_path.items():
|
||||||
hash_val = h
|
if p == file_path:
|
||||||
break
|
hash_val = h
|
||||||
|
break
|
||||||
|
|
||||||
# If we didn't find a hash, nothing to do
|
# If we didn't find a hash, nothing to do
|
||||||
if not hash_val:
|
if not hash_val:
|
||||||
@@ -219,16 +219,7 @@ class ModelHashIndex:
|
|||||||
return set(self._filename_to_hash.keys())
|
return set(self._filename_to_hash.keys())
|
||||||
|
|
||||||
def get_duplicate_hashes(self) -> Dict[str, List[str]]:
|
def get_duplicate_hashes(self) -> Dict[str, List[str]]:
|
||||||
"""Get dictionary of duplicate hashes and their paths"""
|
"""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]
|
|
||||||
|
|
||||||
return self._duplicate_hashes
|
return self._duplicate_hashes
|
||||||
|
|
||||||
def get_duplicate_filenames(self) -> Dict[str, List[str]]:
|
def get_duplicate_filenames(self) -> Dict[str, List[str]]:
|
||||||
|
|||||||
@@ -1342,7 +1342,7 @@ class ModelScanner:
|
|||||||
hash_val = model.get('sha256', '').lower()
|
hash_val = model.get('sha256', '').lower()
|
||||||
|
|
||||||
# Remove from hash index
|
# 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
|
# Check and clean up duplicates
|
||||||
self._cleanup_duplicates_after_removal(hash_val, file_name)
|
self._cleanup_duplicates_after_removal(hash_val, file_name)
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ export function appendLoraCards(loras) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function resetAndReload(updateFolders = false) {
|
export async function resetAndReload(updateFolders = false) {
|
||||||
const pageState = getCurrentPageState();
|
|
||||||
|
|
||||||
// Check if virtual scroller is available
|
// Check if virtual scroller is available
|
||||||
if (state.virtualScroller) {
|
if (state.virtualScroller) {
|
||||||
return resetAndReloadWithVirtualScroll({
|
return resetAndReloadWithVirtualScroll({
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
import { showToast } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
import { state, getCurrentPageState } from '../state/index.js';
|
import { state, getCurrentPageState } from '../state/index.js';
|
||||||
import { formatDate } from '../utils/formatters.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 {
|
export class ModelDuplicatesManager {
|
||||||
constructor(pageManager, modelType = 'loras') {
|
constructor(pageManager, modelType = 'loras') {
|
||||||
@@ -536,11 +538,43 @@ export class ModelDuplicatesManager {
|
|||||||
|
|
||||||
showToast(`Successfully deleted ${data.total_deleted} models`, 'success');
|
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) {
|
if (data.total_deleted > 0) {
|
||||||
// Check duplicates count after deletion
|
// Reload model data with updated folders
|
||||||
this.checkDuplicatesCount();
|
if (this.modelType === 'loras') {
|
||||||
this.exitDuplicateMode();
|
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) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user