jfrery-zama commited on
Commit
5e29d73
·
unverified ·
1 Parent(s): e184d21

add progress bar

Browse files
Files changed (2) hide show
  1. index.html +33 -0
  2. wasm-demo.js +67 -0
index.html CHANGED
@@ -308,6 +308,33 @@
308
  color: #1976d2;
309
  }
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  /* Responsive adjustments */
312
  @media (max-width: 968px) {
313
  .hero {
@@ -403,10 +430,16 @@
403
  <section class="card" aria-labelledby="step3">
404
  <h2 id="step3">3. Send to server</h2>
405
  <div class="card-content">
 
 
 
406
  <div>
407
  <p id="srvStatus" class="status" aria-live="polite">Waiting for encrypted data… (server processing can take several minutes)</p>
408
  <p id="srvComputing" class="status" aria-live="polite" hidden>Server computing…</p>
409
  </div>
 
 
 
410
  <div class="controls" style="margin-top: auto;">
411
  <button id="btnSend" class="btn" disabled>📡 Send</button>
412
  <span id="spin" class="loader" hidden aria-label="Working"></span>
 
308
  color: #1976d2;
309
  }
310
 
311
+ /* Progress bar styling */
312
+ .progress-container {
313
+ width: 100%;
314
+ background: var(--grey-100);
315
+ border-radius: 4px;
316
+ height: 12px;
317
+ margin: calc(var(--spacing-unit) * 2) 0;
318
+ overflow: hidden;
319
+ border: 1px solid var(--grey-200);
320
+ }
321
+
322
+ .progress-bar {
323
+ height: 100%;
324
+ background: var(--black);
325
+ border-radius: 3px;
326
+ transition: width 0.3s ease;
327
+ width: 0%;
328
+ }
329
+
330
+ .processing-note {
331
+ font-size: 0.9rem;
332
+ color: var(--black);
333
+ opacity: 0.7;
334
+ line-height: 1.4;
335
+ margin-bottom: calc(var(--spacing-unit) * 2);
336
+ }
337
+
338
  /* Responsive adjustments */
339
  @media (max-width: 968px) {
340
  .hero {
 
430
  <section class="card" aria-labelledby="step3">
431
  <h2 id="step3">3. Send to server</h2>
432
  <div class="card-content">
433
+ <div class="processing-note" id="processingNote" hidden>
434
+ <strong>Estimated processing time:</strong> <span id="estimatedTime">0</span> seconds
435
+ </div>
436
  <div>
437
  <p id="srvStatus" class="status" aria-live="polite">Waiting for encrypted data… (server processing can take several minutes)</p>
438
  <p id="srvComputing" class="status" aria-live="polite" hidden>Server computing…</p>
439
  </div>
440
+ <div class="progress-container" id="progressContainer" hidden>
441
+ <div class="progress-bar" id="progressBar"></div>
442
+ </div>
443
  <div class="controls" style="margin-top: auto;">
444
  <button id="btnSend" class="btn" disabled>📡 Send</button>
445
  <span id="spin" class="loader" hidden aria-label="Working"></span>
wasm-demo.js CHANGED
@@ -11,6 +11,8 @@ let keygenWorker;
11
  let encryptWorker;
12
  let sessionUid;
13
  let taskId;
 
 
14
 
15
  // Memory-efficient base64 encoding for large Uint8Array
16
  function uint8ToBase64(uint8) {
@@ -188,8 +190,16 @@ $('tokenInput').addEventListener('input', () => {
188
  try {
189
  const tokenIds = llama3Tokenizer.encode(text);
190
  const tokenCount = tokenIds.length;
 
191
  const TOKEN_LIMIT = 16;
192
 
 
 
 
 
 
 
 
193
  if (tokenCount > TOKEN_LIMIT) {
194
  $('encStatus').textContent = `⚠️ ${tokenCount}/${TOKEN_LIMIT} tokens - text too long`;
195
  $('encStatus').style.color = '#d32f2f';
@@ -203,10 +213,12 @@ $('tokenInput').addEventListener('input', () => {
203
  } catch (e) {
204
  // Tokenizer might not be ready yet
205
  $('encStatus').textContent = '';
 
206
  }
207
  } else {
208
  $('encStatus').textContent = '';
209
  $('encStatus').style.color = '';
 
210
  }
211
  });
212
 
@@ -273,8 +285,19 @@ async function pollTaskStatus(currentTaskId, currentUid) {
273
  showComputing = true;
274
  } else if (statusData.status === 'success' || statusData.status === 'completed') {
275
  userMessage = 'Processing complete!';
 
 
 
 
 
 
276
  } else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
277
  userMessage = 'Task failed. Please try again.';
 
 
 
 
 
278
  } else {
279
  // Fallback for any other status
280
  userMessage = `Status: ${statusData.status}`;
@@ -288,6 +311,11 @@ async function pollTaskStatus(currentTaskId, currentUid) {
288
  } else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
289
  console.error('[Poll] Task failed or unrecoverable:', statusData);
290
  show('spin', false);
 
 
 
 
 
291
  return null;
292
  } else {
293
  setTimeout(() => pollTaskStatus(currentTaskId, currentUid).then(finalStatus => {
@@ -301,10 +329,24 @@ async function pollTaskStatus(currentTaskId, currentUid) {
301
  console.error('[Poll] Polling exception:', e);
302
  $('srvStatus').textContent = 'Connection error. Please check your network.';
303
  show('spin', false);
 
 
 
 
 
304
  return null;
305
  }
306
  }
307
 
 
 
 
 
 
 
 
 
 
308
  async function getTaskResult(currentTaskId, currentUid, taskName) {
309
  $('srvStatus').textContent = 'Retrieving results...';
310
  try {
@@ -329,7 +371,12 @@ async function getTaskResult(currentTaskId, currentUid, taskName) {
329
  $('srvStatus').textContent = 'Failed to retrieve results. Please try again.';
330
  } finally {
331
  show('spin', false);
 
332
  $('srvComputing').hidden = true;
 
 
 
 
333
  }
334
  }
335
 
@@ -345,9 +392,19 @@ $('btnSend').onclick = async () => {
345
 
346
  show('encIcon', false);
347
  show('spin', true);
 
 
 
348
  $('srvStatus').textContent = 'Sending encrypted data...';
349
  $('srvComputing').hidden = true; // Ensure it's hidden initially
350
  window.taskStartTime = performance.now();
 
 
 
 
 
 
 
351
 
352
  try {
353
  const formData = new FormData();
@@ -372,6 +429,11 @@ $('btnSend').onclick = async () => {
372
  taskId = newTaskId;
373
  console.log('[Main] Task submitted to server. Task ID:', taskId);
374
  $('srvStatus').textContent = 'Request submitted. Checking status...';
 
 
 
 
 
375
 
376
  pollTaskStatus(taskId, sessionUid).then(finalStatus => {
377
  if (finalStatus && (finalStatus.status === 'success' || finalStatus.status === 'completed')) {
@@ -384,7 +446,12 @@ $('btnSend').onclick = async () => {
384
  console.error(`[Main] Task submission failed after ${duration}s:`, e);
385
  $('srvStatus').textContent = 'Failed to submit request. Please try again.';
386
  show('spin', false);
 
387
  $('srvComputing').hidden = true;
 
 
 
 
388
  }
389
  };
390
 
 
11
  let encryptWorker;
12
  let sessionUid;
13
  let taskId;
14
+ let currentTokenCount = 0;
15
+ let progressTimer;
16
 
17
  // Memory-efficient base64 encoding for large Uint8Array
18
  function uint8ToBase64(uint8) {
 
190
  try {
191
  const tokenIds = llama3Tokenizer.encode(text);
192
  const tokenCount = tokenIds.length;
193
+ currentTokenCount = tokenCount;
194
  const TOKEN_LIMIT = 16;
195
 
196
+ // Update estimated processing time
197
+ const estimatedSeconds = tokenCount * 30;
198
+ const minutes = Math.floor(estimatedSeconds / 60);
199
+ const seconds = estimatedSeconds % 60;
200
+ const timeText = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
201
+ $('estimatedTime').textContent = timeText;
202
+
203
  if (tokenCount > TOKEN_LIMIT) {
204
  $('encStatus').textContent = `⚠️ ${tokenCount}/${TOKEN_LIMIT} tokens - text too long`;
205
  $('encStatus').style.color = '#d32f2f';
 
213
  } catch (e) {
214
  // Tokenizer might not be ready yet
215
  $('encStatus').textContent = '';
216
+ currentTokenCount = 0;
217
  }
218
  } else {
219
  $('encStatus').textContent = '';
220
  $('encStatus').style.color = '';
221
+ currentTokenCount = 0;
222
  }
223
  });
224
 
 
285
  showComputing = true;
286
  } else if (statusData.status === 'success' || statusData.status === 'completed') {
287
  userMessage = 'Processing complete!';
288
+ // Set progress to 100% and clear timer
289
+ $('progressBar').style.width = '100%';
290
+ if (progressTimer) {
291
+ clearInterval(progressTimer);
292
+ progressTimer = null;
293
+ }
294
  } else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
295
  userMessage = 'Task failed. Please try again.';
296
+ // Clear timer on failure
297
+ if (progressTimer) {
298
+ clearInterval(progressTimer);
299
+ progressTimer = null;
300
+ }
301
  } else {
302
  // Fallback for any other status
303
  userMessage = `Status: ${statusData.status}`;
 
311
  } else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
312
  console.error('[Poll] Task failed or unrecoverable:', statusData);
313
  show('spin', false);
314
+ show('progressContainer', false);
315
+ if (progressTimer) {
316
+ clearInterval(progressTimer);
317
+ progressTimer = null;
318
+ }
319
  return null;
320
  } else {
321
  setTimeout(() => pollTaskStatus(currentTaskId, currentUid).then(finalStatus => {
 
329
  console.error('[Poll] Polling exception:', e);
330
  $('srvStatus').textContent = 'Connection error. Please check your network.';
331
  show('spin', false);
332
+ show('progressContainer', false);
333
+ if (progressTimer) {
334
+ clearInterval(progressTimer);
335
+ progressTimer = null;
336
+ }
337
  return null;
338
  }
339
  }
340
 
341
+ function updateProgressBar() {
342
+ if (!window.taskStartTime || !window.expectedDuration) return;
343
+
344
+ const elapsed = performance.now() - window.taskStartTime;
345
+ const progress = Math.min((elapsed / window.expectedDuration) * 100, 95); // Cap at 95% until completion
346
+ $('progressBar').style.width = `${progress}%`;
347
+ console.log(`[Progress] ${progress.toFixed(1)}% (${(elapsed/1000).toFixed(1)}s / ${(window.expectedDuration/1000).toFixed(1)}s)`);
348
+ }
349
+
350
  async function getTaskResult(currentTaskId, currentUid, taskName) {
351
  $('srvStatus').textContent = 'Retrieving results...';
352
  try {
 
371
  $('srvStatus').textContent = 'Failed to retrieve results. Please try again.';
372
  } finally {
373
  show('spin', false);
374
+ show('progressContainer', false);
375
  $('srvComputing').hidden = true;
376
+ if (progressTimer) {
377
+ clearInterval(progressTimer);
378
+ progressTimer = null;
379
+ }
380
  }
381
  }
382
 
 
392
 
393
  show('encIcon', false);
394
  show('spin', true);
395
+ show('processingNote', true);
396
+ show('progressContainer', true); // Show progress container immediately
397
+ $('progressBar').style.width = '0%'; // Reset progress bar
398
  $('srvStatus').textContent = 'Sending encrypted data...';
399
  $('srvComputing').hidden = true; // Ensure it's hidden initially
400
  window.taskStartTime = performance.now();
401
+ window.expectedDuration = currentTokenCount * 30 * 1000; // Convert to milliseconds
402
+
403
+ // Clear any existing progress timer
404
+ if (progressTimer) {
405
+ clearInterval(progressTimer);
406
+ progressTimer = null;
407
+ }
408
 
409
  try {
410
  const formData = new FormData();
 
429
  taskId = newTaskId;
430
  console.log('[Main] Task submitted to server. Task ID:', taskId);
431
  $('srvStatus').textContent = 'Request submitted. Checking status...';
432
+
433
+ // Start progress bar updates
434
+ if (!progressTimer) {
435
+ progressTimer = setInterval(updateProgressBar, 1000);
436
+ }
437
 
438
  pollTaskStatus(taskId, sessionUid).then(finalStatus => {
439
  if (finalStatus && (finalStatus.status === 'success' || finalStatus.status === 'completed')) {
 
446
  console.error(`[Main] Task submission failed after ${duration}s:`, e);
447
  $('srvStatus').textContent = 'Failed to submit request. Please try again.';
448
  show('spin', false);
449
+ show('progressContainer', false);
450
  $('srvComputing').hidden = true;
451
+ if (progressTimer) {
452
+ clearInterval(progressTimer);
453
+ progressTimer = null;
454
+ }
455
  }
456
  };
457