Enable tiled_vae to prevent OOM on portrait images
Some checks failed
Build and Push Docker Image / build (push) Failing after 29m0s
Some checks failed
Build and Push Docker Image / build (push) Failing after 29m0s
Also add async polling to HTML test page for long-running jobs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
138
test-runpod.html
138
test-runpod.html
@@ -456,6 +456,107 @@
|
|||||||
document.getElementById('status').classList.remove('show');
|
document.getElementById('status').classList.remove('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function pollForCompletion(endpointId, jobId, apiKey, startTime) {
|
||||||
|
const statusUrl = `https://api.runpod.ai/v2/${endpointId}/status/${jobId}`;
|
||||||
|
const maxPolls = 120; // 10 minutes with 5s intervals
|
||||||
|
let pollCount = 0;
|
||||||
|
|
||||||
|
while (pollCount < maxPolls) {
|
||||||
|
pollCount++;
|
||||||
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
||||||
|
showStatus(`⏳ Generating video... (${elapsed}s elapsed, poll #${pollCount})`, 'info');
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(statusUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${apiKey}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
// Update JSON output
|
||||||
|
document.getElementById('jsonOutput').innerHTML =
|
||||||
|
'<strong>Raw Response:</strong><pre>' +
|
||||||
|
JSON.stringify(result, null, 2) +
|
||||||
|
'</pre>';
|
||||||
|
|
||||||
|
if (result.status === 'COMPLETED' || result.status === 'FAILED') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still in progress, continue polling
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Poll error:', error);
|
||||||
|
// Continue polling despite errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Timeout: Job did not complete within 10 minutes');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleResult(result, startTime, endpointId, apiKey) {
|
||||||
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
||||||
|
|
||||||
|
// If still in progress, poll for completion
|
||||||
|
if (result.status === 'IN_PROGRESS' || result.status === 'IN_QUEUE') {
|
||||||
|
showStatus(`⏳ Job ${result.id} is ${result.status}. Polling for completion...`, 'info');
|
||||||
|
result = await pollForCompletion(endpointId, result.id, apiKey, startTime);
|
||||||
|
|
||||||
|
// Update JSON output with final result
|
||||||
|
document.getElementById('jsonOutput').innerHTML =
|
||||||
|
'<strong>Raw Response:</strong><pre>' +
|
||||||
|
JSON.stringify(result, null, 2) +
|
||||||
|
'</pre>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalElapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
||||||
|
|
||||||
|
if (result.status === 'COMPLETED' && result.output) {
|
||||||
|
showStatus(`✅ Video generated successfully in ${finalElapsed}s`, 'success');
|
||||||
|
|
||||||
|
const outputContainer = document.getElementById('outputContainer');
|
||||||
|
|
||||||
|
if (result.output.video) {
|
||||||
|
// Base64 video
|
||||||
|
const videoElem = document.createElement('video');
|
||||||
|
videoElem.className = 'output-video';
|
||||||
|
videoElem.controls = true;
|
||||||
|
videoElem.autoplay = true;
|
||||||
|
videoElem.loop = true;
|
||||||
|
videoElem.src = 'data:video/mp4;base64,' + result.output.video;
|
||||||
|
outputContainer.appendChild(videoElem);
|
||||||
|
} else if (result.output.image) {
|
||||||
|
// Base64 image
|
||||||
|
const imgElem = document.createElement('img');
|
||||||
|
imgElem.className = 'output-video';
|
||||||
|
imgElem.src = 'data:image/png;base64,' + result.output.image;
|
||||||
|
outputContainer.appendChild(imgElem);
|
||||||
|
} else if (result.output.file_path) {
|
||||||
|
// File path (large output)
|
||||||
|
const fileInfo = document.createElement('div');
|
||||||
|
fileInfo.className = 'status info show';
|
||||||
|
fileInfo.innerHTML = `
|
||||||
|
<strong>Large output saved to:</strong><br>
|
||||||
|
<code>${result.output.file_path}</code><br><br>
|
||||||
|
<em>File is too large to display (>10MB). Access it on your RunPod volume.</em>
|
||||||
|
`;
|
||||||
|
outputContainer.appendChild(fileInfo);
|
||||||
|
}
|
||||||
|
} else if (result.status === 'FAILED') {
|
||||||
|
showStatus('❌ Generation failed: ' + (result.error || 'Unknown error'), 'error');
|
||||||
|
} else {
|
||||||
|
showStatus('⚠️ Unexpected response status: ' + result.status, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function submitRequest() {
|
async function submitRequest() {
|
||||||
// Validation
|
// Validation
|
||||||
const endpointId = document.getElementById('endpointId').value.trim();
|
const endpointId = document.getElementById('endpointId').value.trim();
|
||||||
@@ -531,42 +632,7 @@
|
|||||||
'</pre>';
|
'</pre>';
|
||||||
|
|
||||||
// Handle response
|
// Handle response
|
||||||
if (result.status === 'COMPLETED' && result.output) {
|
await handleResult(result, startTime, endpointId, apiKey);
|
||||||
showStatus(`✅ Video generated successfully in ${elapsed}s`, 'success');
|
|
||||||
|
|
||||||
const outputContainer = document.getElementById('outputContainer');
|
|
||||||
|
|
||||||
if (result.output.video) {
|
|
||||||
// Base64 video
|
|
||||||
const videoElem = document.createElement('video');
|
|
||||||
videoElem.className = 'output-video';
|
|
||||||
videoElem.controls = true;
|
|
||||||
videoElem.autoplay = true;
|
|
||||||
videoElem.loop = true;
|
|
||||||
videoElem.src = 'data:video/mp4;base64,' + result.output.video;
|
|
||||||
outputContainer.appendChild(videoElem);
|
|
||||||
} else if (result.output.image) {
|
|
||||||
// Base64 image
|
|
||||||
const imgElem = document.createElement('img');
|
|
||||||
imgElem.className = 'output-video';
|
|
||||||
imgElem.src = 'data:image/png;base64,' + result.output.image;
|
|
||||||
outputContainer.appendChild(imgElem);
|
|
||||||
} else if (result.output.file_path) {
|
|
||||||
// File path (large output)
|
|
||||||
const fileInfo = document.createElement('div');
|
|
||||||
fileInfo.className = 'status info show';
|
|
||||||
fileInfo.innerHTML = `
|
|
||||||
<strong>Large output saved to:</strong><br>
|
|
||||||
<code>${result.output.file_path}</code><br><br>
|
|
||||||
<em>File is too large to display (>10MB). Access it on your RunPod volume.</em>
|
|
||||||
`;
|
|
||||||
outputContainer.appendChild(fileInfo);
|
|
||||||
}
|
|
||||||
} else if (result.status === 'FAILED') {
|
|
||||||
showStatus('❌ Generation failed: ' + (result.error || 'Unknown error'), 'error');
|
|
||||||
} else {
|
|
||||||
showStatus('⚠️ Unexpected response status: ' + result.status, 'error');
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showStatus('❌ Error: ' + error.message, 'error');
|
showStatus('❌ Error: ' + error.message, 'error');
|
||||||
|
|||||||
@@ -362,7 +362,7 @@
|
|||||||
"end_latent_strength": 1,
|
"end_latent_strength": 1,
|
||||||
"force_offload": true,
|
"force_offload": true,
|
||||||
"fun_or_fl2v_model": false,
|
"fun_or_fl2v_model": false,
|
||||||
"tiled_vae": false,
|
"tiled_vae": true,
|
||||||
"augment_empty_frames": 0,
|
"augment_empty_frames": 0,
|
||||||
"vae": [
|
"vae": [
|
||||||
"157",
|
"157",
|
||||||
|
|||||||
Reference in New Issue
Block a user