mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
Refactor API structure to unify model operations
- Introduced MODEL_TYPES and MODEL_CONFIG for centralized model type management. - Created a unified API client for checkpoints and loras to streamline operations. - Updated all API calls in checkpointApi.js and loraApi.js to use the new client. - Simplified context menus and model card operations to leverage the unified API client. - Enhanced state management to accommodate new model types and their configurations. - Added virtual scrolling functions for recipes and improved loading states. - Refactored modal utilities to handle model exclusion and deletion generically. - Improved error handling and user feedback across various operations.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { BaseContextMenu } from './BaseContextMenu.js';
|
||||
import { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
||||
import { refreshSingleCheckpointMetadata, saveModelMetadata, replaceCheckpointPreview, resetAndReload } from '../../api/checkpointApi.js';
|
||||
import { resetAndReload } from '../../api/checkpointApi.js';
|
||||
import { getModelApiClient } from '../../api/baseModelApi.js';
|
||||
import { showToast } from '../../utils/uiHelpers.js';
|
||||
import { showExcludeModal } from '../../utils/modalUtils.js';
|
||||
|
||||
@@ -19,7 +20,7 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
|
||||
// Implementation needed by the mixin
|
||||
async saveModelMetadata(filePath, data) {
|
||||
return saveModelMetadata(filePath, data);
|
||||
return getModelApiClient().saveModelMetadata(filePath, data);
|
||||
}
|
||||
|
||||
handleMenuAction(action) {
|
||||
@@ -28,6 +29,8 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiClient = getModelApiClient();
|
||||
|
||||
// Otherwise handle checkpoint-specific actions
|
||||
switch(action) {
|
||||
case 'details':
|
||||
@@ -36,7 +39,7 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
break;
|
||||
case 'replace-preview':
|
||||
// Add new action for replacing preview images
|
||||
replaceCheckpointPreview(this.currentCard.dataset.filepath);
|
||||
apiClient.replaceModelPreview(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'delete':
|
||||
// Delete checkpoint
|
||||
@@ -52,14 +55,14 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
break;
|
||||
case 'refresh-metadata':
|
||||
// Refresh metadata from CivitAI
|
||||
refreshSingleCheckpointMetadata(this.currentCard.dataset.filepath);
|
||||
apiClient.refreshSingleModelMetadata(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'move':
|
||||
// Move to folder (placeholder)
|
||||
showToast('Move to folder feature coming soon', 'info');
|
||||
break;
|
||||
case 'exclude':
|
||||
showExcludeModal(this.currentCard.dataset.filepath, 'checkpoint');
|
||||
showExcludeModal(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import { showModelModal } from './ModelModal.js';
|
||||
import { bulkManager } from '../../managers/BulkManager.js';
|
||||
import { modalManager } from '../../managers/ModalManager.js';
|
||||
import { NSFW_LEVELS } from '../../utils/constants.js';
|
||||
import { replacePreview, saveModelMetadata as saveLoraMetadata } from '../../api/loraApi.js';
|
||||
import { replaceCheckpointPreview as apiReplaceCheckpointPreview, saveModelMetadata as saveCheckpointMetadata } from '../../api/checkpointApi.js';
|
||||
import { getModelApiClient } from '../../api/baseModelApi.js';
|
||||
import { showDeleteModal } from '../../utils/modalUtils.js';
|
||||
|
||||
// Add global event delegation handlers
|
||||
@@ -31,6 +30,8 @@ function handleModelCardEvent_internal(event, modelType) {
|
||||
// Find the closest card element
|
||||
const card = event.target.closest('.lora-card');
|
||||
if (!card) return;
|
||||
|
||||
const apiClient = getModelApiClient();
|
||||
|
||||
// Handle specific elements within the card
|
||||
if (event.target.closest('.toggle-blur-btn')) {
|
||||
@@ -73,13 +74,13 @@ function handleModelCardEvent_internal(event, modelType) {
|
||||
|
||||
if (event.target.closest('.fa-trash')) {
|
||||
event.stopPropagation();
|
||||
showDeleteModal(card.dataset.filepath, modelType);
|
||||
showDeleteModal(card.dataset.filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest('.fa-image')) {
|
||||
event.stopPropagation();
|
||||
handleReplacePreview(card.dataset.filepath, modelType);
|
||||
apiClient.replaceModelPreview(card.dataset.filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,9 +137,7 @@ async function toggleFavorite(card, modelType) {
|
||||
const newFavoriteState = !isFavorite;
|
||||
|
||||
try {
|
||||
// Use the appropriate save function based on model type
|
||||
const saveFunction = modelType === 'lora' ? saveLoraMetadata : saveCheckpointMetadata;
|
||||
await saveFunction(card.dataset.filepath, {
|
||||
await apiClient.saveModelMetadata(card.dataset.filepath, {
|
||||
favorite: newFavoriteState
|
||||
});
|
||||
|
||||
@@ -179,15 +178,7 @@ function handleCopyAction(card, modelType) {
|
||||
}
|
||||
|
||||
function handleReplacePreview(filePath, modelType) {
|
||||
if (modelType === 'lora') {
|
||||
replacePreview(filePath);
|
||||
} else {
|
||||
if (window.replaceCheckpointPreview) {
|
||||
window.replaceCheckpointPreview(filePath);
|
||||
} else {
|
||||
apiReplaceCheckpointPreview(filePath);
|
||||
}
|
||||
}
|
||||
apiClient.replaceModelPreview(filePath);
|
||||
}
|
||||
|
||||
async function handleExampleImagesAccess(card, modelType) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { BASE_MODELS } from '../../utils/constants.js';
|
||||
import { state } from '../../state/index.js';
|
||||
import { saveModelMetadata as saveLoraMetadata, renameLoraFile } from '../../api/loraApi.js';
|
||||
import { saveModelMetadata as saveCheckpointMetadata, renameCheckpointFile } from '../../api/checkpointApi.js';
|
||||
import { getModelApiClient } from '../../api/baseModelApi.js';
|
||||
|
||||
/**
|
||||
* Set up model name editing functionality
|
||||
@@ -114,9 +115,7 @@ export function setupModelNameEditing(filePath) {
|
||||
// Get the file path from the dataset
|
||||
const filePath = this.dataset.filePath;
|
||||
|
||||
const saveFunction = state.currentPageType === 'checkpoints' ? saveCheckpointMetadata : saveLoraMetadata;
|
||||
|
||||
await saveFunction(filePath, { model_name: newModelName });
|
||||
await getModelApiClient().saveModelMetadata(filePath, { model_name: newModelName });
|
||||
|
||||
showToast('Model name updated successfully', 'success');
|
||||
} catch (error) {
|
||||
@@ -295,9 +294,7 @@ async function saveBaseModel(filePath, originalValue) {
|
||||
}
|
||||
|
||||
try {
|
||||
const saveFunction = state.currentPageType === 'checkpoints' ? saveCheckpointMetadata : saveLoraMetadata;
|
||||
|
||||
await saveFunction(filePath, { base_model: newBaseModel });
|
||||
await getModelApiClient().saveModelMetadata(filePath, { base_model: newBaseModel });
|
||||
|
||||
showToast('Base model updated successfully', 'success');
|
||||
} catch (error) {
|
||||
@@ -417,29 +414,7 @@ export function setupFileNameEditing(filePath) {
|
||||
// Get the file path from the dataset
|
||||
const filePath = this.dataset.filePath;
|
||||
|
||||
let result;
|
||||
|
||||
if (state.currentPageType === 'checkpoints') {
|
||||
result = await renameCheckpointFile(filePath, newFileName);
|
||||
} else {
|
||||
// Use LoRA rename function
|
||||
result = await renameLoraFile(filePath, newFileName);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
showToast('File name updated successfully', 'success');
|
||||
|
||||
// Update virtual scroller if available (mainly for LoRAs)
|
||||
if (state.virtualScroller && typeof state.virtualScroller.updateSingleItem === 'function') {
|
||||
const newFilePath = filePath.replace(originalValue, newFileName);
|
||||
state.virtualScroller.updateSingleItem(filePath, {
|
||||
file_name: newFileName,
|
||||
file_path: newFilePath
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new Error(result.error || 'Unknown error');
|
||||
}
|
||||
await getModelApiClient().renameModelFile(filePath, newFileName);
|
||||
} catch (error) {
|
||||
console.error('Error renaming file:', error);
|
||||
this.textContent = originalValue; // Restore original file name
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import { showToast, copyToClipboard } from '../../../utils/uiHelpers.js';
|
||||
import { state } from '../../../state/index.js';
|
||||
import { uploadPreview } from '../../../api/baseModelApi.js';
|
||||
import { getModelApiClient } from '../../../api/baseModelApi.js';
|
||||
|
||||
/**
|
||||
* Try to load local image first, fall back to remote if local fails
|
||||
@@ -515,6 +515,7 @@ function initSetPreviewHandlers(container) {
|
||||
|
||||
// Get local file path if available
|
||||
const useLocalFile = mediaElement.dataset.localSrc && !mediaElement.dataset.localSrc.includes('undefined');
|
||||
const apiClient = getModelApiClient();
|
||||
|
||||
if (useLocalFile) {
|
||||
// We have a local file, use it directly
|
||||
@@ -523,7 +524,7 @@ function initSetPreviewHandlers(container) {
|
||||
const file = new File([blob], 'preview.jpg', { type: blob.type });
|
||||
|
||||
// Use the existing baseModelApi uploadPreview method with nsfw level
|
||||
await uploadPreview(modelFilePath, file, modelType, nsfwLevel);
|
||||
await apiClient.uploadPreview(modelFilePath, file, modelType, nsfwLevel);
|
||||
} else {
|
||||
// We need to download the remote file first
|
||||
const response = await fetch(mediaElement.src);
|
||||
@@ -531,7 +532,7 @@ function initSetPreviewHandlers(container) {
|
||||
const file = new File([blob], 'preview.jpg', { type: blob.type });
|
||||
|
||||
// Use the existing baseModelApi uploadPreview method with nsfw level
|
||||
await uploadPreview(modelFilePath, file, modelType, nsfwLevel);
|
||||
await apiClient.uploadPreview(modelFilePath, file, modelType, nsfwLevel);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error setting preview:', error);
|
||||
|
||||
Reference in New Issue
Block a user