mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat(misc): add VAE and Upscaler model management page
This commit is contained in:
@@ -9,7 +9,8 @@ import { state } from '../state/index.js';
|
||||
export const MODEL_TYPES = {
|
||||
LORA: 'loras',
|
||||
CHECKPOINT: 'checkpoints',
|
||||
EMBEDDING: 'embeddings' // Future model type
|
||||
EMBEDDING: 'embeddings',
|
||||
MISC: 'misc'
|
||||
};
|
||||
|
||||
// Base API configuration for each model type
|
||||
@@ -40,6 +41,15 @@ export const MODEL_CONFIG = {
|
||||
supportsBulkOperations: true,
|
||||
supportsMove: true,
|
||||
templateName: 'embeddings.html'
|
||||
},
|
||||
[MODEL_TYPES.MISC]: {
|
||||
displayName: 'Misc',
|
||||
singularName: 'misc',
|
||||
defaultPageSize: 100,
|
||||
supportsLetterFilter: false,
|
||||
supportsBulkOperations: true,
|
||||
supportsMove: true,
|
||||
templateName: 'misc.html'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -133,6 +143,11 @@ export const MODEL_SPECIFIC_ENDPOINTS = {
|
||||
},
|
||||
[MODEL_TYPES.EMBEDDING]: {
|
||||
metadata: `/api/lm/${MODEL_TYPES.EMBEDDING}/metadata`,
|
||||
},
|
||||
[MODEL_TYPES.MISC]: {
|
||||
metadata: `/api/lm/${MODEL_TYPES.MISC}/metadata`,
|
||||
vae_roots: `/api/lm/${MODEL_TYPES.MISC}/vae_roots`,
|
||||
upscaler_roots: `/api/lm/${MODEL_TYPES.MISC}/upscaler_roots`,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
62
static/js/api/miscApi.js
Normal file
62
static/js/api/miscApi.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { BaseModelApiClient } from './baseModelApi.js';
|
||||
import { getSessionItem } from '../utils/storageHelpers.js';
|
||||
|
||||
export class MiscApiClient extends BaseModelApiClient {
|
||||
_addModelSpecificParams(params, pageState) {
|
||||
const filterMiscHash = getSessionItem('recipe_to_misc_filterHash');
|
||||
const filterMiscHashes = getSessionItem('recipe_to_misc_filterHashes');
|
||||
|
||||
if (filterMiscHash) {
|
||||
params.append('misc_hash', filterMiscHash);
|
||||
} else if (filterMiscHashes) {
|
||||
try {
|
||||
if (Array.isArray(filterMiscHashes) && filterMiscHashes.length > 0) {
|
||||
params.append('misc_hashes', filterMiscHashes.join(','));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing misc hashes from session storage:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (pageState.subType) {
|
||||
params.append('sub_type', pageState.subType);
|
||||
}
|
||||
}
|
||||
|
||||
async getMiscInfo(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 misc info');
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching misc info:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getVaeRoots() {
|
||||
try {
|
||||
const response = await fetch(this.apiConfig.endpoints.specific.vae_roots, { method: 'GET' });
|
||||
if (!response.ok) throw new Error('Failed to fetch VAE roots');
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching VAE roots:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getUpscalerRoots() {
|
||||
try {
|
||||
const response = await fetch(this.apiConfig.endpoints.specific.upscaler_roots, { method: 'GET' });
|
||||
if (!response.ok) throw new Error('Failed to fetch upscaler roots');
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching upscaler roots:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { LoraApiClient } from './loraApi.js';
|
||||
import { CheckpointApiClient } from './checkpointApi.js';
|
||||
import { EmbeddingApiClient } from './embeddingApi.js';
|
||||
import { MiscApiClient } from './miscApi.js';
|
||||
import { MODEL_TYPES, isValidModelType } from './apiConfig.js';
|
||||
import { state } from '../state/index.js';
|
||||
|
||||
@@ -12,6 +13,8 @@ export function createModelApiClient(modelType) {
|
||||
return new CheckpointApiClient(MODEL_TYPES.CHECKPOINT);
|
||||
case MODEL_TYPES.EMBEDDING:
|
||||
return new EmbeddingApiClient(MODEL_TYPES.EMBEDDING);
|
||||
case MODEL_TYPES.MISC:
|
||||
return new MiscApiClient(MODEL_TYPES.MISC);
|
||||
default:
|
||||
throw new Error(`Unsupported model type: ${modelType}`);
|
||||
}
|
||||
|
||||
85
static/js/components/ContextMenu/MiscContextMenu.js
Normal file
85
static/js/components/ContextMenu/MiscContextMenu.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import { BaseContextMenu } from './BaseContextMenu.js';
|
||||
import { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
||||
import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js';
|
||||
import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js';
|
||||
import { moveManager } from '../../managers/MoveManager.js';
|
||||
import { i18n } from '../../i18n/index.js';
|
||||
|
||||
export class MiscContextMenu extends BaseContextMenu {
|
||||
constructor() {
|
||||
super('miscContextMenu', '.model-card');
|
||||
this.nsfwSelector = document.getElementById('nsfwLevelSelector');
|
||||
this.modelType = 'misc';
|
||||
this.resetAndReload = resetAndReload;
|
||||
|
||||
this.initNSFWSelector();
|
||||
}
|
||||
|
||||
// Implementation needed by the mixin
|
||||
async saveModelMetadata(filePath, data) {
|
||||
return getModelApiClient().saveModelMetadata(filePath, data);
|
||||
}
|
||||
|
||||
showMenu(x, y, card) {
|
||||
super.showMenu(x, y, card);
|
||||
|
||||
// Update the "Move to other root" label based on current model type
|
||||
const moveOtherItem = this.menu.querySelector('[data-action="move-other"]');
|
||||
if (moveOtherItem) {
|
||||
const currentType = card.dataset.sub_type || 'vae';
|
||||
const otherType = currentType === 'vae' ? 'upscaler' : 'vae';
|
||||
const typeLabel = i18n.t(`misc.modelTypes.${otherType}`);
|
||||
moveOtherItem.innerHTML = `<i class="fas fa-exchange-alt"></i> ${i18n.t('misc.contextMenu.moveToOtherTypeFolder', { otherType: typeLabel })}`;
|
||||
}
|
||||
}
|
||||
|
||||
handleMenuAction(action) {
|
||||
// First try to handle with common actions
|
||||
if (ModelContextMenuMixin.handleCommonMenuActions.call(this, action)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiClient = getModelApiClient();
|
||||
|
||||
// Otherwise handle misc-specific actions
|
||||
switch (action) {
|
||||
case 'details':
|
||||
// Show misc details
|
||||
this.currentCard.click();
|
||||
break;
|
||||
case 'replace-preview':
|
||||
// Add new action for replacing preview images
|
||||
apiClient.replaceModelPreview(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'delete':
|
||||
showDeleteModal(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'copyname':
|
||||
// Copy misc model name
|
||||
if (this.currentCard.querySelector('.fa-copy')) {
|
||||
this.currentCard.querySelector('.fa-copy').click();
|
||||
}
|
||||
break;
|
||||
case 'refresh-metadata':
|
||||
// Refresh metadata from CivitAI
|
||||
apiClient.refreshSingleModelMetadata(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'move':
|
||||
moveManager.showMoveModal(this.currentCard.dataset.filepath, this.currentCard.dataset.sub_type);
|
||||
break;
|
||||
case 'move-other':
|
||||
{
|
||||
const currentType = this.currentCard.dataset.sub_type || 'vae';
|
||||
const otherType = currentType === 'vae' ? 'upscaler' : 'vae';
|
||||
moveManager.showMoveModal(this.currentCard.dataset.filepath, otherType);
|
||||
}
|
||||
break;
|
||||
case 'exclude':
|
||||
showExcludeModal(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mix in shared methods
|
||||
Object.assign(MiscContextMenu.prototype, ModelContextMenuMixin);
|
||||
@@ -2,6 +2,7 @@ export { LoraContextMenu } from './LoraContextMenu.js';
|
||||
export { RecipeContextMenu } from './RecipeContextMenu.js';
|
||||
export { CheckpointContextMenu } from './CheckpointContextMenu.js';
|
||||
export { EmbeddingContextMenu } from './EmbeddingContextMenu.js';
|
||||
export { MiscContextMenu } from './MiscContextMenu.js';
|
||||
export { GlobalContextMenu } from './GlobalContextMenu.js';
|
||||
export { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
||||
|
||||
@@ -9,6 +10,7 @@ import { LoraContextMenu } from './LoraContextMenu.js';
|
||||
import { RecipeContextMenu } from './RecipeContextMenu.js';
|
||||
import { CheckpointContextMenu } from './CheckpointContextMenu.js';
|
||||
import { EmbeddingContextMenu } from './EmbeddingContextMenu.js';
|
||||
import { MiscContextMenu } from './MiscContextMenu.js';
|
||||
import { GlobalContextMenu } from './GlobalContextMenu.js';
|
||||
|
||||
// Factory method to create page-specific context menu instances
|
||||
@@ -22,6 +24,8 @@ export function createPageContextMenu(pageType) {
|
||||
return new CheckpointContextMenu();
|
||||
case 'embeddings':
|
||||
return new EmbeddingContextMenu();
|
||||
case 'misc':
|
||||
return new MiscContextMenu();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ export class HeaderManager {
|
||||
if (path.includes('/checkpoints')) return 'checkpoints';
|
||||
if (path.includes('/embeddings')) return 'embeddings';
|
||||
if (path.includes('/statistics')) return 'statistics';
|
||||
if (path.includes('/misc')) return 'misc';
|
||||
if (path.includes('/loras')) return 'loras';
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
119
static/js/components/controls/MiscControls.js
Normal file
119
static/js/components/controls/MiscControls.js
Normal file
@@ -0,0 +1,119 @@
|
||||
// MiscControls.js - Specific implementation for the Misc (VAE/Upscaler) page
|
||||
import { PageControls } from './PageControls.js';
|
||||
import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js';
|
||||
import { getSessionItem, removeSessionItem } from '../../utils/storageHelpers.js';
|
||||
import { downloadManager } from '../../managers/DownloadManager.js';
|
||||
|
||||
/**
|
||||
* MiscControls class - Extends PageControls for Misc-specific functionality
|
||||
*/
|
||||
export class MiscControls extends PageControls {
|
||||
constructor() {
|
||||
// Initialize with 'misc' page type
|
||||
super('misc');
|
||||
|
||||
// Register API methods specific to the Misc page
|
||||
this.registerMiscAPI();
|
||||
|
||||
// Check for custom filters (e.g., from recipe navigation)
|
||||
this.checkCustomFilters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Misc-specific API methods
|
||||
*/
|
||||
registerMiscAPI() {
|
||||
const miscAPI = {
|
||||
// Core API functions
|
||||
loadMoreModels: async (resetPage = false, updateFolders = false) => {
|
||||
return await getModelApiClient().loadMoreWithVirtualScroll(resetPage, updateFolders);
|
||||
},
|
||||
|
||||
resetAndReload: async (updateFolders = false) => {
|
||||
return await resetAndReload(updateFolders);
|
||||
},
|
||||
|
||||
refreshModels: async (fullRebuild = false) => {
|
||||
return await getModelApiClient().refreshModels(fullRebuild);
|
||||
},
|
||||
|
||||
// Add fetch from Civitai functionality for misc models
|
||||
fetchFromCivitai: async () => {
|
||||
return await getModelApiClient().fetchCivitaiMetadata();
|
||||
},
|
||||
|
||||
// Add show download modal functionality
|
||||
showDownloadModal: () => {
|
||||
downloadManager.showDownloadModal();
|
||||
},
|
||||
|
||||
toggleBulkMode: () => {
|
||||
if (window.bulkManager) {
|
||||
window.bulkManager.toggleBulkMode();
|
||||
} else {
|
||||
console.error('Bulk manager not available');
|
||||
}
|
||||
},
|
||||
|
||||
clearCustomFilter: async () => {
|
||||
await this.clearCustomFilter();
|
||||
}
|
||||
};
|
||||
|
||||
// Register the API
|
||||
this.registerAPI(miscAPI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for custom filters sent from other pages (e.g., recipe modal)
|
||||
*/
|
||||
checkCustomFilters() {
|
||||
const filterMiscHash = getSessionItem('recipe_to_misc_filterHash');
|
||||
const filterRecipeName = getSessionItem('filterMiscRecipeName');
|
||||
|
||||
if (filterMiscHash && filterRecipeName) {
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
const filterText = indicator?.querySelector('.customFilterText');
|
||||
|
||||
if (indicator && filterText) {
|
||||
indicator.classList.remove('hidden');
|
||||
|
||||
const displayText = `Viewing misc model from: ${filterRecipeName}`;
|
||||
filterText.textContent = this._truncateText(displayText, 30);
|
||||
filterText.setAttribute('title', displayText);
|
||||
|
||||
const filterElement = indicator.querySelector('.filter-active');
|
||||
if (filterElement) {
|
||||
filterElement.classList.add('animate');
|
||||
setTimeout(() => filterElement.classList.remove('animate'), 600);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear misc custom filter and reload
|
||||
*/
|
||||
async clearCustomFilter() {
|
||||
removeSessionItem('recipe_to_misc_filterHash');
|
||||
removeSessionItem('recipe_to_misc_filterHashes');
|
||||
removeSessionItem('filterMiscRecipeName');
|
||||
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
if (indicator) {
|
||||
indicator.classList.add('hidden');
|
||||
}
|
||||
|
||||
await resetAndReload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to truncate text with ellipsis
|
||||
* @param {string} text
|
||||
* @param {number} maxLength
|
||||
* @returns {string}
|
||||
*/
|
||||
_truncateText(text, maxLength) {
|
||||
return text.length > maxLength ? `${text.substring(0, maxLength - 3)}...` : text;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,14 @@ import { PageControls } from './PageControls.js';
|
||||
import { LorasControls } from './LorasControls.js';
|
||||
import { CheckpointsControls } from './CheckpointsControls.js';
|
||||
import { EmbeddingsControls } from './EmbeddingsControls.js';
|
||||
import { MiscControls } from './MiscControls.js';
|
||||
|
||||
// Export the classes
|
||||
export { PageControls, LorasControls, CheckpointsControls, EmbeddingsControls };
|
||||
export { PageControls, LorasControls, CheckpointsControls, EmbeddingsControls, MiscControls };
|
||||
|
||||
/**
|
||||
* Factory function to create the appropriate controls based on page type
|
||||
* @param {string} pageType - The type of page ('loras', 'checkpoints', or 'embeddings')
|
||||
* @param {string} pageType - The type of page ('loras', 'checkpoints', 'embeddings', or 'misc')
|
||||
* @returns {PageControls} - The appropriate controls instance
|
||||
*/
|
||||
export function createPageControls(pageType) {
|
||||
@@ -19,6 +20,8 @@ export function createPageControls(pageType) {
|
||||
return new CheckpointsControls();
|
||||
} else if (pageType === 'embeddings') {
|
||||
return new EmbeddingsControls();
|
||||
} else if (pageType === 'misc') {
|
||||
return new MiscControls();
|
||||
} else {
|
||||
console.error(`Unknown page type: ${pageType}`);
|
||||
return null;
|
||||
|
||||
@@ -214,6 +214,52 @@ function handleSendToWorkflow(card, replaceMode, modelType) {
|
||||
missingNodesMessage,
|
||||
missingTargetMessage,
|
||||
});
|
||||
} else if (modelType === MODEL_TYPES.MISC) {
|
||||
const modelPath = card.dataset.filepath;
|
||||
if (!modelPath) {
|
||||
const message = translate('modelCard.sendToWorkflow.missingPath', {}, 'Unable to determine model path for this card');
|
||||
showToast(message, {}, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const subtype = (card.dataset.sub_type || 'vae').toLowerCase();
|
||||
const isVae = subtype === 'vae';
|
||||
const widgetName = isVae ? 'vae_name' : 'model_name';
|
||||
const actionTypeText = translate(
|
||||
isVae ? 'uiHelpers.nodeSelector.vae' : 'uiHelpers.nodeSelector.upscaler',
|
||||
{},
|
||||
isVae ? 'VAE' : 'Upscaler'
|
||||
);
|
||||
const successMessage = translate(
|
||||
isVae ? 'uiHelpers.workflow.vaeUpdated' : 'uiHelpers.workflow.upscalerUpdated',
|
||||
{},
|
||||
isVae ? 'VAE updated in workflow' : 'Upscaler updated in workflow'
|
||||
);
|
||||
const failureMessage = translate(
|
||||
isVae ? 'uiHelpers.workflow.vaeFailed' : 'uiHelpers.workflow.upscalerFailed',
|
||||
{},
|
||||
isVae ? 'Failed to update VAE node' : 'Failed to update upscaler node'
|
||||
);
|
||||
const missingNodesMessage = translate(
|
||||
'uiHelpers.workflow.noMatchingNodes',
|
||||
{},
|
||||
'No compatible nodes available in the current workflow'
|
||||
);
|
||||
const missingTargetMessage = translate(
|
||||
'uiHelpers.workflow.noTargetNodeSelected',
|
||||
{},
|
||||
'No target node selected'
|
||||
);
|
||||
|
||||
sendModelPathToWorkflow(modelPath, {
|
||||
widgetName,
|
||||
collectionType: MODEL_TYPES.MISC,
|
||||
actionTypeText,
|
||||
successMessage,
|
||||
failureMessage,
|
||||
missingNodesMessage,
|
||||
missingTargetMessage,
|
||||
});
|
||||
} else {
|
||||
showToast('modelCard.sendToWorkflow.checkpointNotImplemented', {}, 'info');
|
||||
}
|
||||
@@ -230,6 +276,10 @@ function handleCopyAction(card, modelType) {
|
||||
} else if (modelType === MODEL_TYPES.EMBEDDING) {
|
||||
const embeddingName = card.dataset.file_name;
|
||||
copyToClipboard(embeddingName, 'Embedding name copied');
|
||||
} else if (modelType === MODEL_TYPES.MISC) {
|
||||
const miscName = card.dataset.file_name;
|
||||
const message = translate('modelCard.actions.miscNameCopied', {}, 'Model name copied');
|
||||
copyToClipboard(miscName, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ export class AppCore {
|
||||
initializePageFeatures() {
|
||||
const pageType = this.getPageType();
|
||||
|
||||
if (['loras', 'recipes', 'checkpoints', 'embeddings'].includes(pageType)) {
|
||||
if (['loras', 'recipes', 'checkpoints', 'embeddings', 'misc'].includes(pageType)) {
|
||||
this.initializeContextMenus(pageType);
|
||||
initializeInfiniteScroll(pageType);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,17 @@ export class BulkManager {
|
||||
deleteAll: true,
|
||||
setContentRating: true
|
||||
},
|
||||
[MODEL_TYPES.MISC]: {
|
||||
addTags: true,
|
||||
sendToWorkflow: false,
|
||||
copyAll: false,
|
||||
refreshAll: true,
|
||||
checkUpdates: true,
|
||||
moveAll: true,
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: true
|
||||
},
|
||||
recipes: {
|
||||
addTags: false,
|
||||
sendToWorkflow: false,
|
||||
|
||||
51
static/js/misc.js
Normal file
51
static/js/misc.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { appCore } from './core.js';
|
||||
import { confirmDelete, closeDeleteModal, confirmExclude, closeExcludeModal } from './utils/modalUtils.js';
|
||||
import { createPageControls } from './components/controls/index.js';
|
||||
import { ModelDuplicatesManager } from './components/ModelDuplicatesManager.js';
|
||||
import { MODEL_TYPES } from './api/apiConfig.js';
|
||||
|
||||
// Initialize the Misc (VAE/Upscaler) page
|
||||
export class MiscPageManager {
|
||||
constructor() {
|
||||
// Initialize page controls
|
||||
this.pageControls = createPageControls(MODEL_TYPES.MISC);
|
||||
|
||||
// Initialize the ModelDuplicatesManager
|
||||
this.duplicatesManager = new ModelDuplicatesManager(this, MODEL_TYPES.MISC);
|
||||
|
||||
// Expose only necessary functions to global scope
|
||||
this._exposeRequiredGlobalFunctions();
|
||||
}
|
||||
|
||||
_exposeRequiredGlobalFunctions() {
|
||||
// Minimal set of functions that need to remain global
|
||||
window.confirmDelete = confirmDelete;
|
||||
window.closeDeleteModal = closeDeleteModal;
|
||||
window.confirmExclude = confirmExclude;
|
||||
window.closeExcludeModal = closeExcludeModal;
|
||||
|
||||
// Expose duplicates manager
|
||||
window.modelDuplicatesManager = this.duplicatesManager;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
// Initialize common page features (including context menus)
|
||||
appCore.initializePageFeatures();
|
||||
|
||||
console.log('Misc Manager initialized');
|
||||
}
|
||||
}
|
||||
|
||||
export async function initializeMiscPage() {
|
||||
// Initialize core application
|
||||
await appCore.initialize();
|
||||
|
||||
// Initialize misc page
|
||||
const miscPage = new MiscPageManager();
|
||||
await miscPage.initialize();
|
||||
|
||||
return miscPage;
|
||||
}
|
||||
|
||||
// Initialize everything when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', initializeMiscPage);
|
||||
@@ -177,6 +177,35 @@ export const state = {
|
||||
showFavoritesOnly: false,
|
||||
showUpdateAvailableOnly: false,
|
||||
duplicatesMode: false,
|
||||
},
|
||||
|
||||
[MODEL_TYPES.MISC]: {
|
||||
currentPage: 1,
|
||||
isLoading: false,
|
||||
hasMore: true,
|
||||
sortBy: 'name',
|
||||
activeFolder: getStorageItem(`${MODEL_TYPES.MISC}_activeFolder`),
|
||||
previewVersions: new Map(),
|
||||
searchManager: null,
|
||||
searchOptions: {
|
||||
filename: true,
|
||||
modelname: true,
|
||||
creator: false,
|
||||
recursive: getStorageItem(`${MODEL_TYPES.MISC}_recursiveSearch`, true),
|
||||
},
|
||||
filters: {
|
||||
baseModel: [],
|
||||
tags: {},
|
||||
license: {},
|
||||
modelTypes: []
|
||||
},
|
||||
bulkMode: false,
|
||||
selectedModels: new Set(),
|
||||
metadataCache: new Map(),
|
||||
showFavoritesOnly: false,
|
||||
showUpdateAvailableOnly: false,
|
||||
duplicatesMode: false,
|
||||
subType: 'vae'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ export const MODEL_SUBTYPE_DISPLAY_NAMES = {
|
||||
diffusion_model: "Diffusion Model",
|
||||
// Embedding sub-types
|
||||
embedding: "Embedding",
|
||||
// Misc sub-types
|
||||
vae: "VAE",
|
||||
upscaler: "Upscaler",
|
||||
};
|
||||
|
||||
// Backward compatibility alias
|
||||
@@ -81,6 +84,8 @@ export const MODEL_SUBTYPE_ABBREVIATIONS = {
|
||||
checkpoint: "CKPT",
|
||||
diffusion_model: "DM",
|
||||
embedding: "EMB",
|
||||
vae: "VAE",
|
||||
upscaler: "UP",
|
||||
};
|
||||
|
||||
export function getSubTypeAbbreviation(subType) {
|
||||
|
||||
@@ -28,10 +28,9 @@ async function getCardCreator(pageType) {
|
||||
|
||||
// Function to get the appropriate data fetcher based on page type
|
||||
async function getDataFetcher(pageType) {
|
||||
if (pageType === 'loras' || pageType === 'embeddings' || pageType === 'checkpoints') {
|
||||
if (pageType === 'loras' || pageType === 'embeddings' || pageType === 'checkpoints' || pageType === 'misc') {
|
||||
return (page = 1, pageSize = 100) => getModelApiClient().fetchModelsPage(page, pageSize);
|
||||
} else if (pageType === 'recipes') {
|
||||
// Import the recipeApi module and use the fetchRecipesPage function
|
||||
const { fetchRecipesPage } = await import('../api/recipeApi.js');
|
||||
return fetchRecipesPage;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user