mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
Enhance Checkpoints Manager: Implement API integration for checkpoints, add filtering and sorting options, and improve UI components for better user experience
This commit is contained in:
247
static/js/api/checkpointApi.js
Normal file
247
static/js/api/checkpointApi.js
Normal file
@@ -0,0 +1,247 @@
|
||||
import { state, getCurrentPageState } from '../state/index.js';
|
||||
import { showToast } from '../utils/uiHelpers.js';
|
||||
import { confirmDelete } from '../utils/modalUtils.js';
|
||||
import { createCheckpointCard } from '../components/CheckpointCard.js';
|
||||
|
||||
// Load more checkpoints with pagination
|
||||
export async function loadMoreCheckpoints(resetPagination = true) {
|
||||
try {
|
||||
const pageState = getCurrentPageState();
|
||||
|
||||
// Don't load if we're already loading or there are no more items
|
||||
if (pageState.isLoading || (!resetPagination && !pageState.hasMore)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set loading state
|
||||
pageState.isLoading = true;
|
||||
document.body.classList.add('loading');
|
||||
|
||||
// Reset pagination if requested
|
||||
if (resetPagination) {
|
||||
pageState.currentPage = 1;
|
||||
const grid = document.getElementById('checkpointGrid');
|
||||
if (grid) grid.innerHTML = '';
|
||||
}
|
||||
|
||||
// Build API URL with parameters
|
||||
const params = new URLSearchParams({
|
||||
page: pageState.currentPage,
|
||||
page_size: pageState.pageSize || 20,
|
||||
sort: pageState.sortBy || 'name'
|
||||
});
|
||||
|
||||
// Add folder filter if active
|
||||
if (pageState.activeFolder) {
|
||||
params.append('folder', pageState.activeFolder);
|
||||
}
|
||||
|
||||
// Add search if available
|
||||
if (pageState.filters && pageState.filters.search) {
|
||||
params.append('search', pageState.filters.search);
|
||||
|
||||
// Add search options
|
||||
if (pageState.searchOptions) {
|
||||
params.append('search_filename', pageState.searchOptions.filename.toString());
|
||||
params.append('search_modelname', pageState.searchOptions.modelname.toString());
|
||||
params.append('recursive', pageState.searchOptions.recursive.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Add base model filters
|
||||
if (pageState.filters && pageState.filters.baseModel && pageState.filters.baseModel.length > 0) {
|
||||
pageState.filters.baseModel.forEach(model => {
|
||||
params.append('base_model', model);
|
||||
});
|
||||
}
|
||||
|
||||
// Add tags filters
|
||||
if (pageState.filters && pageState.filters.tags && pageState.filters.tags.length > 0) {
|
||||
pageState.filters.tags.forEach(tag => {
|
||||
params.append('tag', tag);
|
||||
});
|
||||
}
|
||||
|
||||
// Execute fetch
|
||||
const response = await fetch(`/api/checkpoints?${params.toString()}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load checkpoints: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Update state with response data
|
||||
pageState.hasMore = data.page < data.total_pages;
|
||||
|
||||
// Update UI with checkpoints
|
||||
const grid = document.getElementById('checkpointGrid');
|
||||
if (!grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear grid if this is the first page
|
||||
if (resetPagination) {
|
||||
grid.innerHTML = '';
|
||||
}
|
||||
|
||||
// Check for empty result
|
||||
if (data.items.length === 0 && resetPagination) {
|
||||
grid.innerHTML = `
|
||||
<div class="placeholder-message">
|
||||
<p>No checkpoints found</p>
|
||||
<p>Add checkpoints to your models folders to see them here.</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Render checkpoint cards
|
||||
data.items.forEach(checkpoint => {
|
||||
const card = createCheckpointCard(checkpoint);
|
||||
grid.appendChild(card);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading checkpoints:', error);
|
||||
showToast('Failed to load checkpoints', 'error');
|
||||
} finally {
|
||||
// Clear loading state
|
||||
const pageState = getCurrentPageState();
|
||||
pageState.isLoading = false;
|
||||
document.body.classList.remove('loading');
|
||||
}
|
||||
}
|
||||
|
||||
// Reset and reload checkpoints
|
||||
export async function resetAndReload() {
|
||||
const pageState = getCurrentPageState();
|
||||
pageState.currentPage = 1;
|
||||
pageState.hasMore = true;
|
||||
await loadMoreCheckpoints(true);
|
||||
}
|
||||
|
||||
// Refresh checkpoints
|
||||
export async function refreshCheckpoints() {
|
||||
try {
|
||||
showToast('Scanning for checkpoints...', 'info');
|
||||
const response = await fetch('/api/checkpoints/scan');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to scan checkpoints: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
await resetAndReload();
|
||||
showToast('Checkpoints refreshed successfully', 'success');
|
||||
} catch (error) {
|
||||
console.error('Error refreshing checkpoints:', error);
|
||||
showToast('Failed to refresh checkpoints', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a checkpoint
|
||||
export function deleteCheckpoint(filePath) {
|
||||
confirmDelete('Are you sure you want to delete this checkpoint?', () => {
|
||||
_performDelete(filePath);
|
||||
});
|
||||
}
|
||||
|
||||
// Private function to perform the delete operation
|
||||
async function _performDelete(filePath) {
|
||||
try {
|
||||
showToast('Deleting checkpoint...', 'info');
|
||||
|
||||
const response = await fetch('/api/model/delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
file_path: filePath,
|
||||
model_type: 'checkpoint'
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to delete checkpoint: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Remove the card from UI
|
||||
const card = document.querySelector(`.lora-card[data-filepath="${filePath}"]`);
|
||||
if (card) {
|
||||
card.remove();
|
||||
}
|
||||
|
||||
showToast('Checkpoint deleted successfully', 'success');
|
||||
} else {
|
||||
throw new Error(data.error || 'Failed to delete checkpoint');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting checkpoint:', error);
|
||||
showToast(`Failed to delete checkpoint: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Replace checkpoint preview
|
||||
export function replaceCheckpointPreview(filePath) {
|
||||
// Open file picker
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = 'image/*';
|
||||
input.onchange = async (e) => {
|
||||
if (!e.target.files.length) return;
|
||||
|
||||
const file = e.target.files[0];
|
||||
await _uploadPreview(filePath, file);
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
|
||||
// Upload a preview image
|
||||
async function _uploadPreview(filePath, file) {
|
||||
try {
|
||||
showToast('Uploading preview...', 'info');
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('file_path', filePath);
|
||||
formData.append('model_type', 'checkpoint');
|
||||
|
||||
const response = await fetch('/api/model/preview', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to upload preview: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Update the preview in UI
|
||||
const card = document.querySelector(`.lora-card[data-filepath="${filePath}"]`);
|
||||
if (card) {
|
||||
const img = card.querySelector('.card-preview img');
|
||||
if (img) {
|
||||
// Add timestamp to prevent caching
|
||||
const timestamp = new Date().getTime();
|
||||
if (data.preview_url) {
|
||||
img.src = `${data.preview_url}?t=${timestamp}`;
|
||||
} else {
|
||||
img.src = `/api/model/preview_image?path=${encodeURIComponent(filePath)}&t=${timestamp}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showToast('Preview updated successfully', 'success');
|
||||
} else {
|
||||
throw new Error(data.error || 'Failed to update preview');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating preview:', error);
|
||||
showToast(`Failed to update preview: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user