Spaces:
Running
Running
Add pod generation progress polling with live status in UI
Browse files
src/content_engine/api/ui.html
CHANGED
|
@@ -2387,8 +2387,9 @@ async function doGenerate() {
|
|
| 2387 |
const data = await res.json();
|
| 2388 |
if (!res.ok) throw new Error(data.detail || 'Pod not running - start it first');
|
| 2389 |
|
|
|
|
| 2390 |
toast('Generating on RunPod GPU...', 'info');
|
| 2391 |
-
await
|
| 2392 |
return;
|
| 2393 |
}
|
| 2394 |
|
|
@@ -2440,6 +2441,45 @@ async function doGenerate() {
|
|
| 2440 |
}
|
| 2441 |
}
|
| 2442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2443 |
async function pollForNewImage(startTime) {
|
| 2444 |
for (let i = 0; i < 60; i++) {
|
| 2445 |
await new Promise(r => setTimeout(r, 3000));
|
|
|
|
| 2387 |
const data = await res.json();
|
| 2388 |
if (!res.ok) throw new Error(data.detail || 'Pod not running - start it first');
|
| 2389 |
|
| 2390 |
+
const podJobId = data.job_id;
|
| 2391 |
toast('Generating on RunPod GPU...', 'info');
|
| 2392 |
+
await pollPodJob(podJobId, startTime);
|
| 2393 |
return;
|
| 2394 |
}
|
| 2395 |
|
|
|
|
| 2441 |
}
|
| 2442 |
}
|
| 2443 |
|
| 2444 |
+
async function pollPodJob(jobId, startTime) {
|
| 2445 |
+
const preview = document.getElementById('preview-body');
|
| 2446 |
+
for (let i = 0; i < 180; i++) { // 180 × 5s = 15 min max
|
| 2447 |
+
await new Promise(r => setTimeout(r, 5000));
|
| 2448 |
+
try {
|
| 2449 |
+
const res = await fetch(API + `/api/pod/jobs/${jobId}`);
|
| 2450 |
+
if (!res.ok) continue;
|
| 2451 |
+
const job = await res.json();
|
| 2452 |
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
| 2453 |
+
const progressMsg = job.progress_msg || `${elapsed}s elapsed...`;
|
| 2454 |
+
preview.innerHTML = `<div class="preview-placeholder"><p>Generating on RunPod GPU...</p><p style="font-size:12px;color:var(--text-secondary)">${progressMsg}</p></div>`;
|
| 2455 |
+
|
| 2456 |
+
if (job.status === 'completed' && job.output_path) {
|
| 2457 |
+
document.getElementById('gen-time').textContent = `${elapsed}s`;
|
| 2458 |
+
// Fetch latest image from gallery
|
| 2459 |
+
const imgRes = await fetch(API + '/api/images?limit=1');
|
| 2460 |
+
const images = await imgRes.json();
|
| 2461 |
+
if (images.length > 0) {
|
| 2462 |
+
showPreviewImage(images[0]);
|
| 2463 |
+
} else {
|
| 2464 |
+
preview.innerHTML = `<div class="preview-placeholder"><p>Image saved to: ${job.output_path}</p></div>`;
|
| 2465 |
+
}
|
| 2466 |
+
toast('Image generated!', 'success');
|
| 2467 |
+
return;
|
| 2468 |
+
}
|
| 2469 |
+
if (job.status === 'failed') {
|
| 2470 |
+
throw new Error(job.error || 'Generation failed');
|
| 2471 |
+
}
|
| 2472 |
+
} catch(e) {
|
| 2473 |
+
if (e.message && e.message !== 'Failed to fetch') {
|
| 2474 |
+
preview.innerHTML = `<div class="preview-placeholder"><p style="color:var(--error)">Error: ${e.message}</p></div>`;
|
| 2475 |
+
toast(e.message, 'error');
|
| 2476 |
+
return;
|
| 2477 |
+
}
|
| 2478 |
+
}
|
| 2479 |
+
}
|
| 2480 |
+
preview.innerHTML = `<div class="preview-placeholder"><p>Timed out waiting for image (15 min)</p></div>`;
|
| 2481 |
+
}
|
| 2482 |
+
|
| 2483 |
async function pollForNewImage(startTime) {
|
| 2484 |
for (let i = 0; i < 60; i++) {
|
| 2485 |
await new Promise(r => setTimeout(r, 3000));
|