Add Checkpoints Gallery with per-checkpoint generation settings
- New Checkpoint model (slug, name, checkpoint_path, data JSON, image_path) - sync_checkpoints() loads metadata from data/checkpoints/*.json and falls back to template defaults for models without a JSON file - _apply_checkpoint_settings() applies per-checkpoint steps, CFG, sampler, base positive/negative prompts, and VAE (with dynamic VAELoader node injection for non-integrated VAEs) to the ComfyUI workflow - Bulk Create from Checkpoints: scans Illustrious/Noob model directories, reads matching HTML files, uses LLM to populate metadata, falls back to template defaults when no HTML is present - Gallery index with batch cover generation and WebSocket progress bar - Detail page showing Generation Settings and Base Prompts cards - Checkpoints nav link added to layout - New data/prompts/checkpoint_system.txt LLM system prompt - Updated README with all current galleries and file structure - Also includes accumulated action/scene JSON updates, new actions, and other template/generator improvements from prior sessions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -250,23 +250,37 @@
|
||||
const clientId = 'action_detail_' + Math.random().toString(36).substring(2, 15);
|
||||
|
||||
// ComfyUI WebSocket
|
||||
const socket = new WebSocket(`ws://127.0.0.1:8188/ws?clientId=${clientId}`);
|
||||
const socket = new WebSocket('{{ COMFYUI_WS_URL }}?clientId=' + clientId);
|
||||
|
||||
const nodeNames = {
|
||||
"3": "Sampling",
|
||||
"11": "Face Detailing",
|
||||
"13": "Hand Detailing",
|
||||
"4": "Loading Models",
|
||||
"16": "Character LoRA",
|
||||
"17": "Outfit LoRA",
|
||||
"18": "Action LoRA",
|
||||
"19": "Style/Detailer LoRA",
|
||||
"8": "Decoding Image",
|
||||
"9": "Saving Image"
|
||||
};
|
||||
|
||||
let currentPromptId = null;
|
||||
let currentAction = null;
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
if (!currentPromptId) return;
|
||||
|
||||
const msg = JSON.parse(event.data);
|
||||
|
||||
if (msg.type === 'status') {
|
||||
const queueRemaining = msg.data.status.exec_info.queue_remaining;
|
||||
if (queueRemaining > 0) {
|
||||
progressLabel.textContent = `Queue position: ${queueRemaining}`;
|
||||
if (!currentPromptId) {
|
||||
const queueRemaining = msg.data.status.exec_info.queue_remaining;
|
||||
if (queueRemaining > 0) {
|
||||
progressLabel.textContent = `Queue position: ${queueRemaining}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg.type === 'progress') {
|
||||
if (msg.data.prompt_id !== currentPromptId) return;
|
||||
const value = msg.data.value;
|
||||
const max = msg.data.max;
|
||||
const percent = Math.round((value / max) * 100);
|
||||
@@ -274,10 +288,16 @@
|
||||
progressBar.textContent = `${percent}%`;
|
||||
}
|
||||
else if (msg.type === 'executing') {
|
||||
if (msg.data.node === null && msg.data.prompt_id === currentPromptId) {
|
||||
if (msg.data.prompt_id !== currentPromptId) return;
|
||||
|
||||
const nodeId = msg.data.node;
|
||||
if (nodeId === null) {
|
||||
// Execution finished via WebSocket
|
||||
console.log('Finished via WebSocket');
|
||||
if (resolveCompletion) resolveCompletion();
|
||||
} else {
|
||||
const nodeName = nodeNames[nodeId] || `Processing...`;
|
||||
progressLabel.textContent = nodeName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -344,6 +364,9 @@
|
||||
|
||||
currentPromptId = data.prompt_id;
|
||||
progressLabel.textContent = 'Queued...';
|
||||
progressBar.style.width = '100%';
|
||||
progressBar.textContent = 'Queued';
|
||||
progressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
|
||||
|
||||
// Wait for completion (WebSocket or Polling)
|
||||
await waitForCompletion(currentPromptId);
|
||||
|
||||
Reference in New Issue
Block a user