From 342a722991a4e9ca671532319ee6687183fd580d Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Mon, 4 Aug 2025 19:37:53 +0800 Subject: [PATCH] feat: refactor model API structure to support specific model types with dedicated API clients for Checkpoints, LoRAs, and Embeddings refactor: consolidate model API client creation into a factory function for better maintainability feat: implement move operations for LoRAs and handle unsupported operations for Checkpoints and Embeddings --- static/js/api/baseModelApi.js | 200 +----------------- static/js/api/checkpointApi.js | 47 ++++ static/js/api/embeddingApi.js | 30 +++ static/js/api/loraApi.js | 194 +++++++++++++++++ static/js/api/modelApiFactory.js | 35 +++ .../ContextMenu/CheckpointContextMenu.js | 2 +- .../ContextMenu/EmbeddingContextMenu.js | 2 +- .../components/ContextMenu/LoraContextMenu.js | 2 +- .../js/components/ModelDuplicatesManager.js | 2 +- static/js/components/alphabet/AlphabetBar.js | 2 +- .../controls/CheckpointsControls.js | 2 +- .../components/controls/EmbeddingsControls.js | 2 +- .../js/components/controls/LorasControls.js | 2 +- static/js/components/shared/ModelCard.js | 2 +- .../js/components/shared/ModelDescription.js | 2 +- static/js/components/shared/ModelMetadata.js | 2 +- static/js/components/shared/ModelModal.js | 2 +- static/js/components/shared/ModelTags.js | 2 +- static/js/components/shared/PresetTags.js | 2 +- static/js/components/shared/TriggerWords.js | 2 +- .../components/shared/showcase/MediaUtils.js | 2 +- static/js/managers/BulkManager.js | 2 +- static/js/managers/DownloadManager.js | 2 +- static/js/managers/FilterManager.js | 2 +- static/js/managers/MoveManager.js | 2 +- static/js/managers/SearchManager.js | 2 +- static/js/managers/SettingsManager.js | 2 +- static/js/utils/infiniteScroll.js | 2 +- static/js/utils/modalUtils.js | 2 +- 29 files changed, 341 insertions(+), 213 deletions(-) create mode 100644 static/js/api/checkpointApi.js create mode 100644 static/js/api/embeddingApi.js create mode 100644 static/js/api/loraApi.js create mode 100644 static/js/api/modelApiFactory.js diff --git a/static/js/api/baseModelApi.js b/static/js/api/baseModelApi.js index 38b76616..89f2ceab 100644 --- a/static/js/api/baseModelApi.js +++ b/static/js/api/baseModelApi.js @@ -8,12 +8,16 @@ import { DOWNLOAD_ENDPOINTS, WS_ENDPOINTS } from './apiConfig.js'; +import { createModelApiClient } from './modelApiFactory.js'; /** - * Universal API client for all model types + * Abstract base class for all model API clients */ -class ModelApiClient { +export class BaseModelApiClient { constructor(modelType = null) { + if (this.constructor === BaseModelApiClient) { + throw new Error("BaseModelApiClient is abstract and cannot be instantiated directly"); + } this.modelType = modelType || getCurrentModelType(); this.apiConfig = getCompleteApiConfig(this.modelType); } @@ -42,9 +46,6 @@ class ModelApiClient { return pageState; } - /** - * Fetch models with pagination - */ async fetchModelsPage(page = 1, pageSize = null) { const pageState = this.getPageState(); const actualPageSize = pageSize || pageState.pageSize || this.apiConfig.config.defaultPageSize; @@ -79,9 +80,6 @@ class ModelApiClient { } } - /** - * Reset and reload models with virtual scrolling - */ async loadMoreWithVirtualScroll(resetPage = false, updateFolders = false) { const pageState = this.getPageState(); @@ -93,24 +91,20 @@ class ModelApiClient { pageState.currentPage = 1; // Reset to first page } - // Fetch the current page const startTime = performance.now(); const result = await this.fetchModelsPage(pageState.currentPage, pageState.pageSize); const endTime = performance.now(); console.log(`fetchModelsPage耗时: ${(endTime - startTime).toFixed(2)} ms`); - // Update the virtual scroller state.virtualScroller.refreshWithData( result.items, result.totalItems, result.hasMore ); - // Update state pageState.hasMore = result.hasMore; pageState.currentPage = pageState.currentPage + 1; - // Update folders if needed if (updateFolders && result.folders) { updateFolderTags(result.folders); } @@ -126,9 +120,6 @@ class ModelApiClient { } } - /** - * Delete a model - */ async deleteModel(filePath) { try { state.loadingManager.showSimpleLoading(`Deleting ${this.apiConfig.config.singularName}...`); @@ -163,9 +154,6 @@ class ModelApiClient { } } - /** - * Exclude a model - */ async excludeModel(filePath) { try { state.loadingManager.showSimpleLoading(`Excluding ${this.apiConfig.config.singularName}...`); @@ -200,9 +188,6 @@ class ModelApiClient { } } - /** - * Rename a model file - */ async renameModelFile(filePath, newFileName) { try { state.loadingManager.showSimpleLoading(`Renaming ${this.apiConfig.config.singularName} file...`); @@ -239,9 +224,6 @@ class ModelApiClient { } } - /** - * Replace model preview - */ replaceModelPreview(filePath) { const input = document.createElement('input'); input.type = 'file'; @@ -257,9 +239,6 @@ class ModelApiClient { input.click(); } - /** - * Upload preview image - */ async uploadPreview(filePath, file, nsfwLevel = 0) { try { state.loadingManager.showSimpleLoading('Uploading preview...'); @@ -281,7 +260,6 @@ class ModelApiClient { const data = await response.json(); const pageState = this.getPageState(); - // Update the version timestamp const timestamp = Date.now(); if (pageState.previewVersions) { pageState.previewVersions.set(filePath, timestamp); @@ -305,9 +283,6 @@ class ModelApiClient { } } - /** - * Save model metadata - */ async saveModelMetadata(filePath, data) { try { state.loadingManager.showSimpleLoading('Saving metadata...'); @@ -332,9 +307,6 @@ class ModelApiClient { } } - /** - * Refresh models (scan) - */ async refreshModels(fullRebuild = false) { try { state.loadingManager.showSimpleLoading( @@ -360,9 +332,6 @@ class ModelApiClient { } } - /** - * Fetch CivitAI metadata for single model - */ async refreshSingleModelMetadata(filePath) { try { state.loadingManager.showSimpleLoading('Refreshing metadata...'); @@ -399,9 +368,6 @@ class ModelApiClient { } } - /** - * Fetch CivitAI metadata for all models - */ async fetchCivitaiMetadata() { let ws = null; @@ -477,9 +443,6 @@ class ModelApiClient { }); } - /** - * Fetch CivitAI metadata for multiple models with progress tracking - */ async refreshBulkModelMetadata(filePaths) { if (!filePaths || filePaths.length === 0) { throw new Error('No file paths provided'); @@ -493,7 +456,6 @@ class ModelApiClient { const progressController = state.loadingManager.showEnhancedProgress('Starting metadata refresh...'); try { - // Process files sequentially to avoid overwhelming the API for (let i = 0; i < filePaths.length; i++) { const filePath = filePaths[i]; const fileName = filePath.split('/').pop(); @@ -535,7 +497,6 @@ class ModelApiClient { processedCount++; } - // Show completion message let completionMessage; if (successCount === totalItems) { completionMessage = `Successfully refreshed all ${successCount} ${this.apiConfig.config.displayName}s`; @@ -575,113 +536,6 @@ class ModelApiClient { } } - /** - * Move a single model to target path - * @returns {string|null} - The new file path if moved, null if not moved - */ - async moveSingleModel(filePath, targetPath) { - if (filePath.substring(0, filePath.lastIndexOf('/')) === targetPath) { - showToast('Model is already in the selected folder', 'info'); - return null; - } - - const response = await fetch(this.apiConfig.endpoints.specific.moveModel, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - file_path: filePath, - target_path: targetPath - }) - }); - - const result = await response.json(); - - if (!response.ok) { - if (result && result.error) { - throw new Error(result.error); - } - throw new Error('Failed to move model'); - } - - if (result && result.message) { - showToast(result.message, 'info'); - } else { - showToast('Model moved successfully', 'success'); - } - - // Return new file path if move succeeded - if (result.success) { - return result.new_file_path; - } - return null; - } - - /** - * Move multiple models to target path - * @returns {Array} - Array of new file paths that were moved successfully - */ - async moveBulkModels(filePaths, targetPath) { - const movedPaths = filePaths.filter(path => { - return path.substring(0, path.lastIndexOf('/')) !== targetPath; - }); - - if (movedPaths.length === 0) { - showToast('All selected models are already in the target folder', 'info'); - return []; - } - - const response = await fetch(this.apiConfig.endpoints.specific.moveBulk, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - file_paths: movedPaths, - target_path: targetPath - }) - }); - - const result = await response.json(); - - if (!response.ok) { - throw new Error('Failed to move models'); - } - - let successFilePaths = []; - if (result.success) { - if (result.failure_count > 0) { - showToast(`Moved ${result.success_count} models, ${result.failure_count} failed`, 'warning'); - console.log('Move operation results:', result.results); - const failedFiles = result.results - .filter(r => !r.success) - .map(r => { - const fileName = r.path.substring(r.path.lastIndexOf('/') + 1); - return `${fileName}: ${r.message}`; - }); - if (failedFiles.length > 0) { - const failureMessage = failedFiles.length <= 3 - ? failedFiles.join('\n') - : failedFiles.slice(0, 3).join('\n') + `\n(and ${failedFiles.length - 3} more)`; - showToast(`Failed moves:\n${failureMessage}`, 'warning', 6000); - } - } else { - showToast(`Successfully moved ${result.success_count} models`, 'success'); - } - // Collect new file paths for successful moves - successFilePaths = result.results - .filter(r => r.success) - .map(r => r.path); - } else { - throw new Error(result.message || 'Failed to move models'); - } - return successFilePaths; - } - - /** - * Fetch Civitai model versions - */ async fetchCivitaiVersions(modelId) { try { const response = await fetch(`${this.apiConfig.endpoints.civitaiVersions}/${modelId}`); @@ -699,9 +553,6 @@ class ModelApiClient { } } - /** - * Fetch model roots - */ async fetchModelRoots() { try { const response = await fetch(this.apiConfig.endpoints.roots); @@ -715,9 +566,6 @@ class ModelApiClient { } } - /** - * Fetch model folders - */ async fetchModelFolders() { try { const response = await fetch(this.apiConfig.endpoints.folders); @@ -731,9 +579,6 @@ class ModelApiClient { } } - /** - * Download a model - */ async downloadModel(modelId, versionId, modelRoot, relativePath, downloadId) { try { const response = await fetch(DOWNLOAD_ENDPOINTS.download, { @@ -759,13 +604,9 @@ class ModelApiClient { } } - /** - * Build query parameters for API requests - */ _buildQueryParams(baseParams, pageState) { const params = new URLSearchParams(baseParams); - // Add common parameters if (pageState.activeFolder !== null) { params.append('folder', pageState.activeFolder); } @@ -774,12 +615,10 @@ class ModelApiClient { params.append('favorites_only', 'true'); } - // Add letter filter for supported model types if (this.apiConfig.config.supportsLetterFilter && pageState.activeLetterFilter) { params.append('first_letter', pageState.activeLetterFilter); } - // Add search parameters if (pageState.filters?.search) { params.append('search', pageState.filters.search); params.append('fuzzy', 'true'); @@ -794,7 +633,6 @@ class ModelApiClient { } } - // Add filter parameters if (pageState.filters) { if (pageState.filters.tags && pageState.filters.tags.length > 0) { pageState.filters.tags.forEach(tag => { @@ -809,17 +647,12 @@ class ModelApiClient { } } - // Add model-specific parameters this._addModelSpecificParams(params, pageState); return params; } - /** - * Add model-specific parameters to query - */ _addModelSpecificParams(params, pageState) { - // Override in specific implementations or handle via configuration if (this.modelType === 'loras') { const filterLoraHash = getSessionItem('recipe_to_lora_filterLoraHash'); const filterLoraHashes = getSessionItem('recipe_to_lora_filterLoraHashes'); @@ -837,23 +670,12 @@ class ModelApiClient { } } } -} -// Export factory functions and utilities -export function createModelApiClient(modelType = null) { - return new ModelApiClient(modelType); -} - -let _singletonClient = null; - -export function getModelApiClient() { - if (!_singletonClient) { - _singletonClient = new ModelApiClient(); + async moveSingleModel(filePath, targetPath) { + throw new Error("moveSingleModel must be implemented by subclass"); } - _singletonClient.setModelType(state.currentPageType); - return _singletonClient; -} -export async function resetAndReload(updateFolders = false) { - return getModelApiClient().loadMoreWithVirtualScroll(true, updateFolders); + async moveBulkModels(filePaths, targetPath) { + throw new Error("moveBulkModels must be implemented by subclass"); + } } \ No newline at end of file diff --git a/static/js/api/checkpointApi.js b/static/js/api/checkpointApi.js new file mode 100644 index 00000000..50a6edc0 --- /dev/null +++ b/static/js/api/checkpointApi.js @@ -0,0 +1,47 @@ +import { BaseModelApiClient } from './baseModelApi.js'; +import { showToast } from '../utils/uiHelpers.js'; + +/** + * Checkpoint-specific API client + */ +export class CheckpointApiClient extends BaseModelApiClient { + /** + * Checkpoints don't support move operations + */ + async moveSingleModel(filePath, targetPath) { + showToast('Moving checkpoints is not supported', 'warning'); + return null; + } + + /** + * Checkpoints don't support bulk move operations + */ + async moveBulkModels(filePaths, targetPath) { + showToast('Moving checkpoints is not supported', 'warning'); + return []; + } + + /** + * Get checkpoint information + */ + async getCheckpointInfo(filePath) { + try { + const response = await fetch(this.apiConfig.endpoints.specific.info, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ file_path: filePath }) + }); + + if (!response.ok) { + throw new Error('Failed to fetch checkpoint info'); + } + + return await response.json(); + } catch (error) { + console.error('Error fetching checkpoint info:', error); + throw error; + } + } +} diff --git a/static/js/api/embeddingApi.js b/static/js/api/embeddingApi.js new file mode 100644 index 00000000..fe9ca363 --- /dev/null +++ b/static/js/api/embeddingApi.js @@ -0,0 +1,30 @@ +import { BaseModelApiClient } from './baseModelApi.js'; +import { showToast } from '../utils/uiHelpers.js'; + +/** + * Embedding-specific API client + */ +export class EmbeddingApiClient extends BaseModelApiClient { + /** + * Move a single embedding to target path + */ + async moveSingleModel(filePath, targetPath) { + if (filePath.substring(0, filePath.lastIndexOf('/')) === targetPath) { + showToast('Embedding is already in the selected folder', 'info'); + return null; + } + + // TODO: Implement embedding move endpoint when available + showToast('Moving embeddings is not yet implemented', 'info'); + return null; + } + + /** + * Move multiple embeddings to target path + */ + async moveBulkModels(filePaths, targetPath) { + // TODO: Implement embedding bulk move endpoint when available + showToast('Moving embeddings is not yet implemented', 'info'); + return []; + } +} diff --git a/static/js/api/loraApi.js b/static/js/api/loraApi.js new file mode 100644 index 00000000..eee8d1dc --- /dev/null +++ b/static/js/api/loraApi.js @@ -0,0 +1,194 @@ +import { BaseModelApiClient } from './baseModelApi.js'; +import { showToast } from '../utils/uiHelpers.js'; +import { getSessionItem } from '../utils/storageHelpers.js'; + +/** + * LoRA-specific API client + */ +export class LoraApiClient extends BaseModelApiClient { + /** + * Add LoRA-specific parameters to query + */ + _addModelSpecificParams(params, pageState) { + const filterLoraHash = getSessionItem('recipe_to_lora_filterLoraHash'); + const filterLoraHashes = getSessionItem('recipe_to_lora_filterLoraHashes'); + + if (filterLoraHash) { + params.append('lora_hash', filterLoraHash); + } else if (filterLoraHashes) { + try { + if (Array.isArray(filterLoraHashes) && filterLoraHashes.length > 0) { + params.append('lora_hashes', filterLoraHashes.join(',')); + } + } catch (error) { + console.error('Error parsing lora hashes from session storage:', error); + } + } + } + + /** + * Move a single LoRA to target path + */ + async moveSingleModel(filePath, targetPath) { + if (filePath.substring(0, filePath.lastIndexOf('/')) === targetPath) { + showToast('LoRA is already in the selected folder', 'info'); + return null; + } + + const response = await fetch(this.apiConfig.endpoints.specific.moveModel, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + file_path: filePath, + target_path: targetPath + }) + }); + + const result = await response.json(); + + if (!response.ok) { + if (result && result.error) { + throw new Error(result.error); + } + throw new Error('Failed to move LoRA'); + } + + if (result && result.message) { + showToast(result.message, 'info'); + } else { + showToast('LoRA moved successfully', 'success'); + } + + if (result.success) { + return result.new_file_path; + } + return null; + } + + /** + * Move multiple LoRAs to target path + */ + async moveBulkModels(filePaths, targetPath) { + const movedPaths = filePaths.filter(path => { + return path.substring(0, path.lastIndexOf('/')) !== targetPath; + }); + + if (movedPaths.length === 0) { + showToast('All selected LoRAs are already in the target folder', 'info'); + return []; + } + + const response = await fetch(this.apiConfig.endpoints.specific.moveBulk, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + file_paths: movedPaths, + target_path: targetPath + }) + }); + + const result = await response.json(); + + if (!response.ok) { + throw new Error('Failed to move LoRAs'); + } + + let successFilePaths = []; + if (result.success) { + if (result.failure_count > 0) { + showToast(`Moved ${result.success_count} LoRAs, ${result.failure_count} failed`, 'warning'); + console.log('Move operation results:', result.results); + const failedFiles = result.results + .filter(r => !r.success) + .map(r => { + const fileName = r.path.substring(r.path.lastIndexOf('/') + 1); + return `${fileName}: ${r.message}`; + }); + if (failedFiles.length > 0) { + const failureMessage = failedFiles.length <= 3 + ? failedFiles.join('\n') + : failedFiles.slice(0, 3).join('\n') + `\n(and ${failedFiles.length - 3} more)`; + showToast(`Failed moves:\n${failureMessage}`, 'warning', 6000); + } + } else { + showToast(`Successfully moved ${result.success_count} LoRAs`, 'success'); + } + successFilePaths = result.results + .filter(r => r.success) + .map(r => r.path); + } else { + throw new Error(result.message || 'Failed to move LoRAs'); + } + return successFilePaths; + } + + /** + * Get LoRA notes + */ + async getLoraNote(filePath) { + try { + const response = await fetch(this.apiConfig.endpoints.specific.notes, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ file_path: filePath }) + } + ); + + if (!response.ok) { + throw new Error('Failed to fetch LoRA notes'); + } + + return await response.json(); + } catch (error) { + console.error('Error fetching LoRA notes:', error); + throw error; + } + } + + /** + * Get LoRA trigger words + */ + async getLoraTriggerWords(filePath) { + try { + const response = await fetch(this.apiConfig.endpoints.specific.triggerWords, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ file_path: filePath }) + }); + + if (!response.ok) { + throw new Error('Failed to fetch trigger words'); + } + + return await response.json(); + } catch (error) { + console.error('Error fetching trigger words:', error); + throw error; + } + } + + /** + * Get letter counts for LoRAs + */ + async getLetterCounts() { + try { + const response = await fetch(this.apiConfig.endpoints.specific.letterCounts); + if (!response.ok) { + throw new Error('Failed to fetch letter counts'); + } + return await response.json(); + } catch (error) { + console.error('Error fetching letter counts:', error); + throw error; + } + } +} diff --git a/static/js/api/modelApiFactory.js b/static/js/api/modelApiFactory.js new file mode 100644 index 00000000..5aad0d6e --- /dev/null +++ b/static/js/api/modelApiFactory.js @@ -0,0 +1,35 @@ +import { LoraApiClient } from './loraApi.js'; +import { CheckpointApiClient } from './checkpointApi.js'; +import { EmbeddingApiClient } from './embeddingApi.js'; +import { MODEL_TYPES } from './apiConfig.js'; +import { state } from '../state/index.js'; + +export function createModelApiClient(modelType) { + switch (modelType) { + case MODEL_TYPES.LORA: + return new LoraApiClient(); + case MODEL_TYPES.CHECKPOINT: + return new CheckpointApiClient(); + case MODEL_TYPES.EMBEDDING: + return new EmbeddingApiClient(); + default: + throw new Error(`Unsupported model type: ${modelType}`); + } +} + +let _singletonClient = null; + +export function getModelApiClient() { + const currentType = state.currentPageType; + + if (!_singletonClient || _singletonClient.modelType !== currentType) { + _singletonClient = createModelApiClient(currentType); + } + + return _singletonClient; +} + +export function resetAndReload(updateFolders = false) { + const client = getModelApiClient(); + return client.loadMoreWithVirtualScroll(true, updateFolders); +} \ No newline at end of file diff --git a/static/js/components/ContextMenu/CheckpointContextMenu.js b/static/js/components/ContextMenu/CheckpointContextMenu.js index 20eccea2..9f8f6216 100644 --- a/static/js/components/ContextMenu/CheckpointContextMenu.js +++ b/static/js/components/ContextMenu/CheckpointContextMenu.js @@ -1,6 +1,6 @@ import { BaseContextMenu } from './BaseContextMenu.js'; import { ModelContextMenuMixin } from './ModelContextMenuMixin.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { showToast } from '../../utils/uiHelpers.js'; import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js'; diff --git a/static/js/components/ContextMenu/EmbeddingContextMenu.js b/static/js/components/ContextMenu/EmbeddingContextMenu.js index c0ef079b..a820ea16 100644 --- a/static/js/components/ContextMenu/EmbeddingContextMenu.js +++ b/static/js/components/ContextMenu/EmbeddingContextMenu.js @@ -1,6 +1,6 @@ import { BaseContextMenu } from './BaseContextMenu.js'; import { ModelContextMenuMixin } from './ModelContextMenuMixin.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { showToast } from '../../utils/uiHelpers.js'; import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js'; diff --git a/static/js/components/ContextMenu/LoraContextMenu.js b/static/js/components/ContextMenu/LoraContextMenu.js index 61ba4837..83719e58 100644 --- a/static/js/components/ContextMenu/LoraContextMenu.js +++ b/static/js/components/ContextMenu/LoraContextMenu.js @@ -1,6 +1,6 @@ import { BaseContextMenu } from './BaseContextMenu.js'; import { ModelContextMenuMixin } from './ModelContextMenuMixin.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { copyToClipboard, sendLoraToWorkflow } from '../../utils/uiHelpers.js'; import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js'; diff --git a/static/js/components/ModelDuplicatesManager.js b/static/js/components/ModelDuplicatesManager.js index 06596642..fd864bab 100644 --- a/static/js/components/ModelDuplicatesManager.js +++ b/static/js/components/ModelDuplicatesManager.js @@ -2,7 +2,7 @@ import { showToast } from '../utils/uiHelpers.js'; import { state, getCurrentPageState } from '../state/index.js'; import { formatDate } from '../utils/formatters.js'; -import { resetAndReload} from '../api/baseModelApi.js'; +import { resetAndReload} from '../api/modelApiFactory.js'; import { LoadingManager } from '../managers/LoadingManager.js'; export class ModelDuplicatesManager { diff --git a/static/js/components/alphabet/AlphabetBar.js b/static/js/components/alphabet/AlphabetBar.js index 44f8803d..82113758 100644 --- a/static/js/components/alphabet/AlphabetBar.js +++ b/static/js/components/alphabet/AlphabetBar.js @@ -1,7 +1,7 @@ // AlphabetBar.js - Component for alphabet filtering import { getCurrentPageState } from '../../state/index.js'; import { getStorageItem, setStorageItem } from '../../utils/storageHelpers.js'; -import { resetAndReload } from '../../api/baseModelApi.js'; +import { resetAndReload } from '../../api/modelApiFactory.js'; /** * AlphabetBar class - Handles the alphabet filtering UI and interactions diff --git a/static/js/components/controls/CheckpointsControls.js b/static/js/components/controls/CheckpointsControls.js index 492434dc..2ddeb990 100644 --- a/static/js/components/controls/CheckpointsControls.js +++ b/static/js/components/controls/CheckpointsControls.js @@ -1,6 +1,6 @@ // CheckpointsControls.js - Specific implementation for the Checkpoints page import { PageControls } from './PageControls.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { showToast } from '../../utils/uiHelpers.js'; import { downloadManager } from '../../managers/DownloadManager.js'; diff --git a/static/js/components/controls/EmbeddingsControls.js b/static/js/components/controls/EmbeddingsControls.js index c5b618e4..612ece4c 100644 --- a/static/js/components/controls/EmbeddingsControls.js +++ b/static/js/components/controls/EmbeddingsControls.js @@ -1,6 +1,6 @@ // EmbeddingsControls.js - Specific implementation for the Embeddings page import { PageControls } from './PageControls.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { showToast } from '../../utils/uiHelpers.js'; import { downloadManager } from '../../managers/DownloadManager.js'; diff --git a/static/js/components/controls/LorasControls.js b/static/js/components/controls/LorasControls.js index 8ec51983..725a960a 100644 --- a/static/js/components/controls/LorasControls.js +++ b/static/js/components/controls/LorasControls.js @@ -1,6 +1,6 @@ // LorasControls.js - Specific implementation for the LoRAs page import { PageControls } from './PageControls.js'; -import { getModelApiClient, resetAndReload } from '../../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { getSessionItem, removeSessionItem } from '../../utils/storageHelpers.js'; import { createAlphabetBar } from '../alphabet/index.js'; import { downloadManager } from '../../managers/DownloadManager.js'; diff --git a/static/js/components/shared/ModelCard.js b/static/js/components/shared/ModelCard.js index be421fcc..69d3ea43 100644 --- a/static/js/components/shared/ModelCard.js +++ b/static/js/components/shared/ModelCard.js @@ -5,7 +5,7 @@ import { toggleShowcase } from './showcase/ShowcaseView.js'; import { bulkManager } from '../../managers/BulkManager.js'; import { modalManager } from '../../managers/ModalManager.js'; import { NSFW_LEVELS } from '../../utils/constants.js'; -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; import { showDeleteModal } from '../../utils/modalUtils.js'; // Add global event delegation handlers diff --git a/static/js/components/shared/ModelDescription.js b/static/js/components/shared/ModelDescription.js index a2297e01..fefb97af 100644 --- a/static/js/components/shared/ModelDescription.js +++ b/static/js/components/shared/ModelDescription.js @@ -121,7 +121,7 @@ export function setupModelDescriptionEditing(filePath) { } try { // Save to backend - const { getModelApiClient } = await import('../../api/baseModelApi.js'); + const { getModelApiClient } = await import('../../api/modelApiFactory.js'); await getModelApiClient().saveModelMetadata(filePath, { modelDescription: newValue }); showToast('Model description updated', 'success'); } catch (err) { diff --git a/static/js/components/shared/ModelMetadata.js b/static/js/components/shared/ModelMetadata.js index 17b33817..a8dc4e7d 100644 --- a/static/js/components/shared/ModelMetadata.js +++ b/static/js/components/shared/ModelMetadata.js @@ -4,7 +4,7 @@ */ import { showToast } from '../../utils/uiHelpers.js'; import { BASE_MODELS } from '../../utils/constants.js'; -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; /** * Set up model name editing functionality diff --git a/static/js/components/shared/ModelModal.js b/static/js/components/shared/ModelModal.js index 72d6bbaf..d731cdee 100644 --- a/static/js/components/shared/ModelModal.js +++ b/static/js/components/shared/ModelModal.js @@ -13,7 +13,7 @@ import { setupFileNameEditing } from './ModelMetadata.js'; import { setupTagEditMode } from './ModelTags.js'; -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; import { renderCompactTags, setupTagTooltip, formatFileSize } from './utils.js'; import { renderTriggerWords, setupTriggerWordsEditMode } from './TriggerWords.js'; import { parsePresets, renderPresetTags } from './PresetTags.js'; diff --git a/static/js/components/shared/ModelTags.js b/static/js/components/shared/ModelTags.js index c58889d2..3ba523f2 100644 --- a/static/js/components/shared/ModelTags.js +++ b/static/js/components/shared/ModelTags.js @@ -3,7 +3,7 @@ * Module for handling model tag editing functionality - 共享版本 */ import { showToast } from '../../utils/uiHelpers.js'; -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; // Preset tag suggestions const PRESET_TAGS = [ diff --git a/static/js/components/shared/PresetTags.js b/static/js/components/shared/PresetTags.js index fb682ee8..865c6851 100644 --- a/static/js/components/shared/PresetTags.js +++ b/static/js/components/shared/PresetTags.js @@ -2,7 +2,7 @@ * PresetTags.js * Handles LoRA model preset parameter tags - Shared version */ -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; /** * Parse preset parameters diff --git a/static/js/components/shared/TriggerWords.js b/static/js/components/shared/TriggerWords.js index f27db73d..26323e9b 100644 --- a/static/js/components/shared/TriggerWords.js +++ b/static/js/components/shared/TriggerWords.js @@ -4,7 +4,7 @@ * Moved to shared directory for consistency */ import { showToast, copyToClipboard } from '../../utils/uiHelpers.js'; -import { getModelApiClient } from '../../api/baseModelApi.js'; +import { getModelApiClient } from '../../api/modelApiFactory.js'; /** * Fetch trained words for a model diff --git a/static/js/components/shared/showcase/MediaUtils.js b/static/js/components/shared/showcase/MediaUtils.js index 5a19749f..4e8d0d4b 100644 --- a/static/js/components/shared/showcase/MediaUtils.js +++ b/static/js/components/shared/showcase/MediaUtils.js @@ -5,7 +5,7 @@ */ import { showToast, copyToClipboard } from '../../../utils/uiHelpers.js'; import { state } from '../../../state/index.js'; -import { getModelApiClient } from '../../../api/baseModelApi.js'; +import { getModelApiClient } from '../../../api/modelApiFactory.js'; /** * Try to load local image first, fall back to remote if local fails diff --git a/static/js/managers/BulkManager.js b/static/js/managers/BulkManager.js index 44d13144..3207128e 100644 --- a/static/js/managers/BulkManager.js +++ b/static/js/managers/BulkManager.js @@ -2,7 +2,7 @@ import { state } from '../state/index.js'; import { showToast, copyToClipboard, sendLoraToWorkflow } from '../utils/uiHelpers.js'; import { updateCardsForBulkMode } from '../components/shared/ModelCard.js'; import { modalManager } from './ModalManager.js'; -import { getModelApiClient } from '../api/baseModelApi.js'; +import { getModelApiClient } from '../api/modelApiFactory.js'; export class BulkManager { constructor() { diff --git a/static/js/managers/DownloadManager.js b/static/js/managers/DownloadManager.js index 5ddafb9a..b4d25460 100644 --- a/static/js/managers/DownloadManager.js +++ b/static/js/managers/DownloadManager.js @@ -1,7 +1,7 @@ import { modalManager } from './ModalManager.js'; import { showToast } from '../utils/uiHelpers.js'; import { LoadingManager } from './LoadingManager.js'; -import { getModelApiClient, resetAndReload } from '../api/baseModelApi.js'; +import { getModelApiClient, resetAndReload } from '../api/modelApiFactory.js'; import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js'; export class DownloadManager { diff --git a/static/js/managers/FilterManager.js b/static/js/managers/FilterManager.js index c6d49164..e29a86f1 100644 --- a/static/js/managers/FilterManager.js +++ b/static/js/managers/FilterManager.js @@ -1,6 +1,6 @@ import { getCurrentPageState } from '../state/index.js'; import { showToast, updatePanelPositions } from '../utils/uiHelpers.js'; -import { getModelApiClient } from '../api/baseModelApi.js'; +import { getModelApiClient } from '../api/modelApiFactory.js'; import { removeStorageItem, setStorageItem, getStorageItem } from '../utils/storageHelpers.js'; export class FilterManager { diff --git a/static/js/managers/MoveManager.js b/static/js/managers/MoveManager.js index b734c16a..a0c3f5e4 100644 --- a/static/js/managers/MoveManager.js +++ b/static/js/managers/MoveManager.js @@ -2,7 +2,7 @@ import { showToast, updateFolderTags } from '../utils/uiHelpers.js'; import { state, getCurrentPageState } from '../state/index.js'; import { modalManager } from './ModalManager.js'; import { getStorageItem } from '../utils/storageHelpers.js'; -import { getModelApiClient } from '../api/baseModelApi.js'; +import { getModelApiClient } from '../api/modelApiFactory.js'; class MoveManager { constructor() { diff --git a/static/js/managers/SearchManager.js b/static/js/managers/SearchManager.js index 81663791..6686bb00 100644 --- a/static/js/managers/SearchManager.js +++ b/static/js/managers/SearchManager.js @@ -1,6 +1,6 @@ import { updatePanelPositions } from "../utils/uiHelpers.js"; import { getCurrentPageState } from "../state/index.js"; -import { getModelApiClient } from "../api/baseModelApi.js"; +import { getModelApiClient } from "../api/modelApiFactory.js"; import { setStorageItem, getStorageItem } from "../utils/storageHelpers.js"; /** * SearchManager - Handles search functionality across different pages diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js index 88c64038..29ffa887 100644 --- a/static/js/managers/SettingsManager.js +++ b/static/js/managers/SettingsManager.js @@ -1,7 +1,7 @@ import { modalManager } from './ModalManager.js'; import { showToast } from '../utils/uiHelpers.js'; import { state } from '../state/index.js'; -import { resetAndReload } from '../api/baseModelApi.js'; +import { resetAndReload } from '../api/modelApiFactory.js'; import { setStorageItem, getStorageItem } from '../utils/storageHelpers.js'; import { DOWNLOAD_PATH_TEMPLATES, MAPPABLE_BASE_MODELS } from '../utils/constants.js'; diff --git a/static/js/utils/infiniteScroll.js b/static/js/utils/infiniteScroll.js index 01f732e3..8ad852ee 100644 --- a/static/js/utils/infiniteScroll.js +++ b/static/js/utils/infiniteScroll.js @@ -1,7 +1,7 @@ import { state, getCurrentPageState } from '../state/index.js'; import { VirtualScroller } from './VirtualScroller.js'; import { createModelCard, setupModelCardEventDelegation } from '../components/shared/ModelCard.js'; -import { getModelApiClient } from '../api/baseModelApi.js'; +import { getModelApiClient } from '../api/modelApiFactory.js'; import { showToast } from './uiHelpers.js'; // Function to dynamically import the appropriate card creator based on page type diff --git a/static/js/utils/modalUtils.js b/static/js/utils/modalUtils.js index 25af1fbc..7d143956 100644 --- a/static/js/utils/modalUtils.js +++ b/static/js/utils/modalUtils.js @@ -1,5 +1,5 @@ import { modalManager } from '../managers/ModalManager.js'; -import { getModelApiClient } from '../api/baseModelApi.js'; +import { getModelApiClient } from '../api/modelApiFactory.js'; const apiClient = getModelApiClient();