epic98's picture
Upload folder using huggingface_hub
78792cd verified
Raw
History Blame Contribute Delete
6.05 kB
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('genForm');
const runBtn = document.getElementById('runBtn');
const fileInput = document.getElementById('image');
const dropZone = document.getElementById('dropZone');
const fileNameDisplay = document.getElementById('fileName');
const jobsList = document.getElementById('jobsList');
const refreshBtn = document.getElementById('refreshBtn');
// File Upload Drag & Drop
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#8a2be2';
dropZone.style.background = 'rgba(138, 43, 226, 0.15)';
});
dropZone.addEventListener('dragleave', () => {
dropZone.style.borderColor = 'rgba(255, 255, 255, 0.2)';
dropZone.style.background = 'rgba(15, 23, 42, 0.4)';
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.style.borderColor = 'rgba(255, 255, 255, 0.2)';
dropZone.style.background = 'rgba(15, 23, 42, 0.4)';
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
updateFileName();
}
});
fileInput.addEventListener('change', updateFileName);
function updateFileName() {
if (fileInput.files.length > 0) {
fileNameDisplay.textContent = fileInput.files[0].name;
fileNameDisplay.style.color = '#34d399';
} else {
fileNameDisplay.textContent = 'No file chosen';
fileNameDisplay.style.color = '#00d2ff';
}
}
// Form Submission
form.addEventListener('submit', async (e) => {
e.preventDefault();
runBtn.disabled = true;
runBtn.innerHTML = `<span class="btn-icon">⏳</span><span class="btn-text">DISPATCHING TO KAGGLE...</span>`;
const formData = new FormData(form);
try {
const response = await fetch('/api/run', {
method: 'POST',
body: formData
});
const data = await response.json();
if (response.ok) {
alert(`🎉 Job successfully dispatched to Kaggle!\nJob ID: ${data.job_id}\n\nYou can safely close this browser or go offline. Your video is being generated in the cloud!`);
form.reset();
fileNameDisplay.textContent = 'No file chosen';
fileNameDisplay.style.color = '#00d2ff';
fetchJobs();
} else {
alert(`❌ Error sending job to Kaggle:\n${data.error || 'Unknown error'}`);
}
} catch (err) {
alert(`❌ Network error:\n${err.message}`);
} finally {
runBtn.disabled = false;
runBtn.innerHTML = `<span class="btn-icon">🚀</span><span class="btn-text">RUN CLOUD GENERATION</span>`;
}
});
// Fetch & Render Jobs
async function fetchJobs() {
refreshBtn.innerHTML = '⏳ Checking...';
try {
const res = await fetch('/api/jobs');
const jobs = await res.json();
renderJobs(jobs);
} catch (err) {
jobsList.innerHTML = `<div class="empty-state">Failed to load jobs. Cloud backend unreachable.</div>`;
} finally {
refreshBtn.innerHTML = '🔄 Refresh';
}
}
refreshBtn.addEventListener('click', fetchJobs);
function renderJobs(jobs) {
if (!jobs || jobs.length === 0) {
jobsList.innerHTML = `
<div class="empty-state">
<div class="empty-icon">📂</div>
<h3>No Generations Yet</h3>
<p style="margin-top: 0.5rem; font-size: 0.85rem;">Submit your first script above to start generating videos on Kaggle.</p>
</div>`;
return;
}
// Sort reverse chronological
jobs.reverse();
jobsList.innerHTML = jobs.map(job => {
let statusClass = 'status-running';
let statusIcon = '⚙️';
if (job.status === 'Completed') {
statusClass = 'status-completed';
statusIcon = '✅';
} else if (job.status === 'Failed') {
statusClass = 'status-failed';
statusIcon = '❌';
}
const downloadSection = job.status === 'Completed' ? `
<a href="/api/download/${job.id}" class="download-btn" target="_blank" download>
<span>⬇️ Download Stitched Video (.mp4)</span>
</a>
` : (job.status === 'Failed' ? `
<div style="color: #ef4444; font-size: 0.8rem; text-align: center; padding: 0.5rem; background: rgba(239,68,68,0.1); border-radius: 8px;">
⚠️ Kaggle kernel failed or timed out. Check Kaggle logs.
</div>
` : `
<div style="color: #fbbf24; font-size: 0.85rem; text-align: center; padding: 0.8rem; background: rgba(245,158,11,0.1); border-radius: 10px;">
🔄 Processing on Kaggle GPU... You can close this tab!
</div>
`);
return `
<div class="job-card">
<div class="job-top">
<div>
<div class="job-id">🎬 ${job.id}</div>
<div class="job-time">${job.created_at || 'Recently'}</div>
</div>
<span class="job-status ${statusClass}">${statusIcon} ${job.status}</span>
</div>
<div class="job-preview">"${job.script_preview || 'No script text'}"</div>
${downloadSection}
</div>
`;
}).join('');
}
// Auto load on startup and poll every 30s
fetchJobs();
setInterval(fetchJobs, 30000);
});