Multiple bug fixes.

This commit is contained in:
Aodhan Collins
2026-03-06 19:28:50 +00:00
parent ec08eb5d31
commit d95b81dde5
24 changed files with 601 additions and 133 deletions

View File

@@ -160,7 +160,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
itemNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {

View File

@@ -115,53 +115,68 @@
regenAllBtn.disabled = true;
container.classList.remove('d-none');
let completed = 0;
for (const ckpt of missing) {
const percent = Math.round((completed / missing.length) * 100);
progressBar.style.width = `${percent}%`;
progressBar.textContent = `${percent}%`;
statusText.textContent = `Batch Generating: ${completed + 1} / ${missing.length}`;
ckptNameText.textContent = `Current: ${ckpt.name}`;
nodeStatus.textContent = 'Queuing…';
taskProgressBar.style.width = '100%';
taskProgressBar.textContent = '';
taskProgressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
// Phase 1: Queue all jobs upfront
progressBar.style.width = '100%';
progressBar.textContent = '';
progressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
nodeStatus.textContent = 'Queuing…';
const jobs = [];
for (const ckpt of missing) {
statusText.textContent = `Queuing ${jobs.length + 1} / ${missing.length}`;
try {
const genResp = await fetch(`/checkpoint/${ckpt.slug}/generate`, {
method: 'POST',
body: new URLSearchParams({ 'character_slug': '__random__' }),
body: new URLSearchParams({ character_slug: '__random__' }),
headers: { 'X-Requested-With': 'XMLHttpRequest' }
});
const genData = await genResp.json();
currentJobId = genData.job_id;
if (genData.job_id) jobs.push({ item: ckpt, jobId: genData.job_id });
} catch (err) {
console.error(`Failed to queue ${ckpt.name}:`, err);
}
}
const jobResult = await waitForJob(currentJobId);
currentJobId = null;
// Phase 2: Poll all concurrently
progressBar.classList.remove('progress-bar-striped', 'progress-bar-animated');
progressBar.style.width = '0%';
progressBar.textContent = '0%';
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
ckptNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {
const img = document.getElementById(`img-${ckpt.slug}`);
const noImgSpan = document.getElementById(`no-img-${ckpt.slug}`);
const img = document.getElementById(`img-${item.slug}`);
const noImgSpan = document.getElementById(`no-img-${item.slug}`);
if (img) { img.src = jobResult.result.image_url; img.classList.remove('d-none'); }
if (noImgSpan) noImgSpan.classList.add('d-none');
}
} catch (err) {
console.error(`Failed for ${ckpt.name}:`, err);
currentJobId = null;
console.error(`Failed for ${item.name}:`, err);
}
completed++;
}
const pct = Math.round((completed / jobs.length) * 100);
progressBar.style.width = `${pct}%`;
progressBar.textContent = `${pct}%`;
statusText.textContent = `${completed} / ${jobs.length} done`;
}));
progressBar.style.width = '100%';
progressBar.textContent = '100%';
statusText.textContent = 'Batch Generation Complete!';
statusText.textContent = 'Batch Checkpoint Generation Complete!';
ckptNameText.textContent = '';
nodeStatus.textContent = 'Done';
stepProgressText.textContent = '';
taskProgressBar.style.width = '0%';
taskProgressBar.textContent = '';
batchBtn.disabled = false;
regenAllBtn.disabled = false;
setTimeout(() => { container.classList.add('d-none'); }, 5000);
setTimeout(() => container.classList.add('d-none'), 5000);
}
batchBtn.addEventListener('click', async () => {

View File

@@ -162,7 +162,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
detailerNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {

View File

@@ -161,7 +161,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
charNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {

View File

@@ -45,6 +45,10 @@
<span class="status-dot status-checking"></span>
<span class="status-label d-none d-xl-inline">MCP</span>
</span>
<span id="status-llm" class="service-status" title="LLM" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="LLM: checking…">
<span class="status-dot status-checking"></span>
<span class="status-label d-none d-xl-inline">LLM</span>
</span>
</div>
</div>
</nav>
@@ -343,6 +347,7 @@
const services = [
{ id: 'status-comfyui', url: '/api/status/comfyui', label: 'ComfyUI' },
{ id: 'status-mcp', url: '/api/status/mcp', label: 'Danbooru MCP' },
{ id: 'status-llm', url: '/api/status/llm', label: 'LLM' },
];
function setStatus(id, label, ok) {

View File

@@ -59,6 +59,9 @@
<img id="img-{{ look.slug }}" src="" alt="{{ look.name }}" class="d-none">
<span id="no-img-{{ look.slug }}" class="text-muted">No Image</span>
{% endif %}
{% if look_assignments.get(look.look_id, 0) > 0 %}
<span class="assignment-badge" title="Assigned to {{ look_assignments.get(look.look_id, 0) }} character(s)">{{ look_assignments.get(look.look_id, 0) }}</span>
{% endif %}
</div>
<div class="card-body">
<h5 class="card-title text-center">{{ look.name }}</h5>
@@ -106,6 +109,22 @@
const stepProgressText = document.getElementById('current-step-progress');
let currentJobId = null;
let queuePollInterval = null;
async function updateCurrentJobLabel() {
try {
const resp = await fetch('/api/queue');
const data = await resp.json();
const processingJob = data.jobs.find(j => j.status === 'processing');
if (processingJob) {
itemNameText.textContent = `Processing: ${processingJob.label}`;
} else {
itemNameText.textContent = '';
}
} catch (err) {
console.error('Failed to fetch queue:', err);
}
}
async function waitForJob(jobId) {
return new Promise((resolve, reject) => {
@@ -136,30 +155,42 @@
regenAllBtn.disabled = true;
container.classList.remove('d-none');
let completed = 0;
for (const item of missing) {
const percent = Math.round((completed / missing.length) * 100);
progressBar.style.width = `${percent}%`;
progressBar.textContent = `${percent}%`;
statusText.textContent = `Batch Generating Looks: ${completed + 1} / ${missing.length}`;
itemNameText.textContent = `Current: ${item.name}`;
nodeStatus.textContent = "Queuing…";
taskProgressBar.style.width = '100%';
taskProgressBar.textContent = '';
taskProgressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
// Phase 1: Queue all jobs upfront
progressBar.style.width = '100%';
progressBar.textContent = '';
progressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
nodeStatus.textContent = 'Queuing…';
const jobs = [];
for (const item of missing) {
statusText.textContent = `Queuing ${jobs.length + 1} / ${missing.length}`;
try {
const genResp = await fetch(`/look/${item.slug}/generate`, {
method: 'POST',
body: new URLSearchParams({ 'action': 'replace' }),
body: new URLSearchParams({ action: 'replace' }),
headers: { 'X-Requested-With': 'XMLHttpRequest' }
});
const genData = await genResp.json();
currentJobId = genData.job_id;
if (genData.job_id) jobs.push({ item, jobId: genData.job_id });
} catch (err) {
console.error(`Failed to queue ${item.name}:`, err);
}
}
const jobResult = await waitForJob(currentJobId);
currentJobId = null;
// Phase 2: Poll all concurrently
progressBar.classList.remove('progress-bar-striped', 'progress-bar-animated');
progressBar.style.width = '0%';
progressBar.textContent = '0%';
statusText.textContent = `0 / ${jobs.length} done`;
// Start polling queue for current job label
queuePollInterval = setInterval(updateCurrentJobLabel, 1000);
updateCurrentJobLabel(); // Initial update
let completed = 0;
await Promise.all(jobs.map(async ({ item, jobId }) => {
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {
const img = document.getElementById(`img-${item.slug}`);
const noImgSpan = document.getElementById(`no-img-${item.slug}`);
@@ -168,22 +199,31 @@
}
} catch (err) {
console.error(`Failed for ${item.name}:`, err);
currentJobId = null;
}
completed++;
const pct = Math.round((completed / jobs.length) * 100);
progressBar.style.width = `${pct}%`;
progressBar.textContent = `${pct}%`;
statusText.textContent = `${completed} / ${jobs.length} done`;
}));
// Stop polling queue
if (queuePollInterval) {
clearInterval(queuePollInterval);
queuePollInterval = null;
}
progressBar.style.width = '100%';
progressBar.textContent = '100%';
statusText.textContent = "Batch Look Generation Complete!";
itemNameText.textContent = "";
nodeStatus.textContent = "Done";
stepProgressText.textContent = "";
statusText.textContent = 'Batch Look Generation Complete!';
itemNameText.textContent = '';
nodeStatus.textContent = 'Done';
stepProgressText.textContent = '';
taskProgressBar.style.width = '0%';
taskProgressBar.textContent = '';
batchBtn.disabled = false;
regenAllBtn.disabled = false;
setTimeout(() => { container.classList.add('d-none'); }, 5000);
setTimeout(() => container.classList.add('d-none'), 5000);
}
batchBtn.addEventListener('click', async () => {

View File

@@ -59,6 +59,9 @@
<img id="img-{{ outfit.slug }}" src="" alt="{{ outfit.name }}" class="d-none">
<span id="no-img-{{ outfit.slug }}" class="text-muted">No Image</span>
{% endif %}
{% if outfit.data.lora and outfit.data.lora.lora_name and lora_assignments.get(outfit.data.lora.lora_name, 0) > 0 %}
<span class="assignment-badge" title="Assigned to {{ lora_assignments.get(outfit.data.lora.lora_name, 0) }} character(s)">{{ lora_assignments.get(outfit.data.lora.lora_name, 0) }}</span>
{% endif %}
</div>
<div class="card-body">
<h5 class="card-title text-center">{{ outfit.name }}</h5>
@@ -160,7 +163,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
itemNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {

View File

@@ -160,7 +160,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
itemNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {

View File

@@ -160,7 +160,10 @@
statusText.textContent = `0 / ${jobs.length} done`;
let completed = 0;
let currentItem = '';
await Promise.all(jobs.map(async ({ item, jobId }) => {
currentItem = item.name;
styleNameText.textContent = `Processing: ${currentItem}`;
try {
const jobResult = await waitForJob(jobId);
if (jobResult.result && jobResult.result.image_url) {