Files
arcum42-ComfyUI_SageUtils/js/shared/dataProcessors.js
T

277 lines
8.1 KiB
JavaScript

/**
* Data processing utilities for Models tab
* Handles filtering, sorting, and processing of model data
*/
import {
getFileType,
supportsPreview,
FILE_TYPES
} from "./config.js";
/**
* Processes raw model data combining hash data with info data
* @param {Object} hashData - Hash data from cache
* @param {Object} infoData - Info data from cache
* @param {Object} filters - Current filter settings
* @returns {Array} Processed model data array
*/
export function processModelData(hashData, infoData, filters = {}) {
if (!hashData || !infoData) {
return [];
}
const processedData = [];
// Combine hash data with info data
for (const [filename, hashInfo] of Object.entries(hashData)) {
const info = infoData[hashInfo.hash] || {};
const modelData = {
filename,
hash: hashInfo.hash,
lastUsed: hashInfo.lastUsed,
filePath: hashInfo.filePath,
fileSize: hashInfo.fileSize,
...info // Spread info data (name, description, baseModel, etc.)
};
processedData.push(modelData);
}
return processedData;
}
/**
* Filters model data based on filter criteria
* @param {Array} models - Array of model data objects
* @param {Object} filters - Filter criteria
* @returns {Array} Filtered model data array
*/
export function filterModels(models, filters = {}) {
if (!Array.isArray(models)) {
return [];
}
return models.filter(model => {
// Type filter
if (filters.type && filters.type !== 'all') {
const modelType = (model.type || '').toLowerCase();
if (modelType !== filters.type.toLowerCase()) {
return false;
}
}
// Search filter
if (filters.search && filters.search.trim()) {
const searchTerm = filters.search.toLowerCase().trim();
const searchableText = [
model.filename || '',
model.name || '',
model.description || '',
model.baseModel || '',
...(model.trainedWords || [])
].join(' ').toLowerCase();
if (!searchableText.includes(searchTerm)) {
return false;
}
}
// Last used filter
if (filters.lastUsed && filters.lastUsed !== 'all') {
const lastUsed = model.lastUsed;
const now = Date.now();
const day = 24 * 60 * 60 * 1000;
switch (filters.lastUsed) {
case 'today':
if (!lastUsed || now - lastUsed > day) return false;
break;
case 'week':
if (!lastUsed || now - lastUsed > 7 * day) return false;
break;
case 'month':
if (!lastUsed || now - lastUsed > 30 * day) return false;
break;
case 'never':
if (lastUsed) return false;
break;
}
}
// Update available filter
if (filters.updates && filters.updates !== 'all') {
const hasUpdate = model.update_available;
if (filters.updates === 'available' && !hasUpdate) return false;
if (filters.updates === 'none' && hasUpdate) return false;
}
// NSFW filter
if (!filters.showNSFW && model.nsfw === true) {
return false;
}
return true;
});
}
/**
* Sorts model data based on sort criteria
* @param {Array} models - Array of model data objects
* @param {string} sortBy - Sort criteria
* @returns {Array} Sorted model data array
*/
export function sortModels(models, sortBy = 'name') {
if (!Array.isArray(models)) {
return [];
}
const sortedModels = [...models];
sortedModels.sort((a, b) => {
switch (sortBy) {
case 'name':
return (a.name || a.filename || '').localeCompare(b.name || b.filename || '');
case 'filename':
return (a.filename || '').localeCompare(b.filename || '');
case 'lastUsed':
return (b.lastUsed || 0) - (a.lastUsed || 0);
case 'fileSize':
return (b.fileSize || 0) - (a.fileSize || 0);
case 'type':
return (a.type || '').localeCompare(b.type || '');
case 'baseModel':
return (a.baseModel || '').localeCompare(b.baseModel || '');
default:
return 0;
}
});
return sortedModels;
}
/**
* Groups models by folder structure
* @param {Array} models - Array of model data objects
* @returns {Object} Grouped model data by folders
*/
export function groupModelsByFolder(models) {
if (!Array.isArray(models)) {
return {};
}
const grouped = {};
models.forEach(model => {
const filePath = model.filePath || '';
const pathParts = filePath.split('/').filter(part => part.length > 0);
// Remove filename from path
pathParts.pop();
const folderPath = pathParts.length > 0 ? pathParts.join('/') : 'root';
if (!grouped[folderPath]) {
grouped[folderPath] = [];
}
grouped[folderPath].push(model);
});
return grouped;
}
/**
* Finds other versions of the same model by modelId
* @param {Array} models - Array of all model data
* @param {string} modelId - The model ID to find versions for
* @param {string} currentHash - Current model hash to exclude
* @returns {Array} Array of other model versions
*/
export function findOtherModelVersions(models, modelId, currentHash) {
if (!Array.isArray(models) || !modelId) {
return [];
}
return models.filter(model => {
return model.modelId === modelId && model.hash !== currentHash;
});
}
/**
* Extracts and formats metadata for display
* @param {Object} modelData - Model data object
* @returns {Object} Formatted metadata object
*/
export function formatModelMetadata(modelData) {
if (!modelData) {
return {};
}
return {
name: modelData.name || modelData.filename || 'Unknown',
type: modelData.type || 'Unknown',
baseModel: modelData.baseModel || 'Unknown',
description: modelData.description || '',
trainedWords: modelData.trainedWords || [],
hash: modelData.hash || '',
fileSize: formatFileSize(modelData.fileSize || 0),
lastUsed: formatLastUsed(modelData.lastUsed),
updateAvailable: modelData.update_available || false,
nsfw: modelData.nsfw || false,
external_url: modelData.external_url || '',
notes: modelData.notes || ''
};
}
/**
* Formats file size in human readable format
* @param {number} bytes - File size in bytes
* @returns {string} Formatted file size
*/
function formatFileSize(bytes) {
if (!bytes || bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
/**
* Formats last used timestamp
* @param {number} timestamp - Unix timestamp
* @returns {string} Formatted last used string
*/
function formatLastUsed(timestamp) {
if (!timestamp) return 'Never';
const date = new Date(timestamp);
const now = new Date();
const diffMs = now - date;
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffDays === 0) {
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
if (diffHours === 0) {
const diffMinutes = Math.floor(diffMs / (1000 * 60));
return diffMinutes <= 1 ? 'Just now' : `${diffMinutes} minutes ago`;
}
return diffHours === 1 ? '1 hour ago' : `${diffHours} hours ago`;
} else if (diffDays === 1) {
return 'Yesterday';
} else if (diffDays < 7) {
return `${diffDays} days ago`;
} else {
return date.toLocaleDateString();
}
}