Spaces:
Running
Running
File size: 5,302 Bytes
3ab82f0 2850a82 3ab82f0 721add8 3ab82f0 2850a82 3ab82f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | const $ = selector => document.querySelector(selector);
let session = null;
let busy = false;
async function api(url, options = {}) {
const response = await fetch(url, { credentials: 'same-origin', ...options });
let data;
try { data = await response.json(); } catch { throw new Error('The submission service is unavailable. Please try again later.'); }
if (!response.ok) throw new Error(typeof data.detail === 'string' ? data.detail : 'Request failed. Please check the form.');
return data;
}
function message(text, error = false) {
$('#submission-message').textContent = text;
$('#submission-message').className = `notice ${error ? 'error' : 'success'}`;
}
async function loadSession() {
if (busy) return;
try {
session = await api('/api/submission-session');
$('#hf-username').value = session.username || '';
$('#identity-status').textContent = session.username ? `Signed in as ${session.username}` : 'Sign in to submit your outputs.';
$('#sign-in').classList.toggle('hidden', Boolean(session.username));
$('#sign-out').classList.toggle('hidden', !session.username);
$('#submission-fields').disabled = !session.username || !session.storage_ready || session.storage_full;
const unavailable = session.storage_full ? session.storage_message : !session.auth_enabled ? 'Hugging Face sign-in has not been configured yet.' : !session.storage_ready ? 'Submissions will open once private persistent storage is configured.' : '';
$('#availability').textContent = unavailable;
$('#availability').classList.toggle('hidden', !unavailable);
$('#sign-in').classList.toggle('unavailable', !session.auth_enabled);
$('#sign-in').setAttribute('aria-disabled', String(!session.auth_enabled));
} catch (error) {
$('#submission-fields').disabled = true;
$('#identity-status').textContent = 'Submission service unavailable.';
message(error.message, true);
}
}
$('#sign-in').addEventListener('click', event => { if (!session?.auth_enabled) event.preventDefault(); });
$('#sign-out').addEventListener('click', async () => {
try { await api('/auth/logout', { method: 'POST', headers: {'X-CSRF-Token': session.csrf} }); await loadSession(); }
catch (error) { message(error.message, true); }
});
function upload(id, file) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('PUT', `/api/submissions/${id}/archive`);
xhr.setRequestHeader('X-CSRF-Token', session.csrf);
xhr.setRequestHeader('Content-Type', 'application/zip');
xhr.upload.onprogress = event => {
if (!event.lengthComputable) return;
const percent = Math.round(event.loaded / event.total * 100);
$('#progress').value = percent;
$('#progress-text').textContent = percent === 100 ? 'Upload complete. Checking ZIP contents; keep this page open…' : `Uploading… ${percent}%`;
};
xhr.onerror = () => reject(new Error(`Connection lost. Submission ID: ${id}. The file has not been confirmed as accepted.`));
xhr.onload = () => {
let data;
try { data = JSON.parse(xhr.responseText); } catch { reject(new Error(`Unexpected server response. Submission ID: ${id}.`)); return; }
if (xhr.status >= 200 && xhr.status < 300) resolve(data);
else reject(new Error(data.detail || `Upload failed (${xhr.status}).`));
};
xhr.send(file);
});
}
$('#archive').addEventListener('change', () => {
$('#archive-name').textContent = $('#archive').files[0]?.name || 'No file selected';
});
$('#submission-form').addEventListener('submit', async event => {
event.preventDefault();
if (busy || !session?.username) return;
const file = $('#archive').files[0];
if (!file || !file.name.toLowerCase().endsWith('.zip') || file.size <= 0 || file.size > session.max_zip_bytes) {
message('Choose a non-empty .zip file no larger than 10 GB.', true); return;
}
const values = Object.fromEntries(new FormData(event.currentTarget));
values.username = session.username;
busy = true;
$('#submission-fields').disabled = true;
$('#sign-out').disabled = true;
$('#submission-message').className = 'notice hidden';
$('#upload-progress').classList.remove('hidden');
$('#progress').value = 0;
$('#progress-text').textContent = 'Verifying model ownership, public access, and license…';
try {
const prepared = await api('/api/submissions', {method:'POST', headers:{'Content-Type':'application/json','X-CSRF-Token':session.csrf}, body:JSON.stringify({...values, filename:file.name, size:file.size})});
const result = await upload(prepared.id, file);
$('#progress-text').textContent = 'Upload and ZIP checks complete.';
message(`Submission received: ${result.id}. ${result.images} images found. Status: pending review.`);
event.target.reset();
$('#archive-name').textContent = 'No file selected';
} catch (error) { message(error.message, true); }
finally { busy = false; $('#sign-out').disabled = false; await loadSession(); }
});
window.addEventListener('focus', loadSession);
window.addEventListener('beforeunload', event => { if (busy) {event.preventDefault(); event.returnValue = '';}});
loadSession();
if (new URLSearchParams(location.search).get("login") === "failed") message("Hugging Face sign-in failed. Please try again.", true);
|