KennethTM commited on
Commit
9a64f23
·
verified ·
1 Parent(s): 44a5da3

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +105 -21
index.html CHANGED
@@ -280,17 +280,28 @@
280
 
281
  <!-- Performance Stats -->
282
  <div class="bg-gray-800/30 rounded-xl p-3 text-xs space-y-1 border border-gray-700/50">
283
- <!-- <div class="flex justify-between">
284
- <span class="text-gray-500">Similarity Score:</span>
285
- <span id="similarityScore" class="font-mono text-emerald-400"></span>
286
- </div> -->
 
 
 
 
 
 
 
287
  <div class="flex justify-between">
288
- <span class="text-gray-500">Prediction Time:</span>
289
- <span id="predictionTime" class="font-mono text-blue-400"></span>
290
  </div>
291
  <div class="flex justify-between">
292
- <span class="text-gray-500">Total Time:</span>
293
- <span id="totalTime" class="font-mono text-violet-400"></span>
 
 
 
 
294
  </div>
295
  </div>
296
  </div>
@@ -311,6 +322,7 @@
311
  <!-- Hidden canvas for processing -->
312
  <canvas id="processingCanvas" class="hidden" width="224" height="224"></canvas>
313
  <canvas id="processedCanvas" class="hidden" width="224" height="224"></canvas>
 
314
 
315
  <script>
316
  document.addEventListener('DOMContentLoaded', () => {
@@ -350,15 +362,48 @@
350
  let currentStream = null;
351
  let startTime = null;
352
  const FINAL_SIZE = 224;
 
 
 
 
 
 
 
 
 
 
353
 
354
  // --- View Navigation ---
355
 
356
- function showView(viewId) {
357
  // Hide all views
358
  Object.values(views).forEach(view => view.classList.add('hidden'));
359
  // Show the target view
360
  if (views[viewId]) {
361
  views[viewId].classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  }
363
  }
364
 
@@ -422,6 +467,8 @@
422
  // --- Image Processing ---
423
 
424
  function processImage(source, sourceWidth, sourceHeight) {
 
 
425
  // 1. Find the smallest dimension to create a square crop
426
  const size = Math.min(sourceWidth, sourceHeight);
427
 
@@ -469,11 +516,16 @@
469
 
470
  async function callPredictAPI() {
471
  try {
472
- // Convert canvas to blob
 
 
473
  const blob = await new Promise(resolve => {
474
  processedCanvas.toBlob(resolve, 'image/png');
475
  });
476
 
 
 
 
477
  // Create form data
478
  const formData = new FormData();
479
  formData.append('file', blob, 'image.png');
@@ -490,6 +542,10 @@
490
  }
491
 
492
  const result = await response.json();
 
 
 
 
493
  return result;
494
 
495
  } catch (error) {
@@ -501,11 +557,18 @@
501
 
502
  async function fetchCardDetails(cardId) {
503
  try {
 
 
504
  const response = await fetch(`https://api.scryfall.com/cards/${cardId}`);
505
  if (!response.ok) {
506
  throw new Error('Failed to fetch card details');
507
  }
508
- return await response.json();
 
 
 
 
 
509
  } catch (error) {
510
  console.error('Scryfall API Error:', error);
511
  showMessage('Error fetching card details from Scryfall');
@@ -531,8 +594,6 @@
531
 
532
  // Call the prediction API
533
  const apiResult = await callPredictAPI();
534
- const endTime = Date.now();
535
- const totalTime = endTime - startTime;
536
 
537
  if (!apiResult) {
538
  showMessage('Failed to identify card');
@@ -642,10 +703,27 @@
642
  `;
643
  }
644
 
 
 
 
 
 
 
 
645
  // Performance stats
646
- //document.getElementById('similarityScore').textContent = apiResult.similarity.toFixed(4);
647
- document.getElementById('predictionTime').textContent = `${apiResult.prediction_time}ms`;
648
- document.getElementById('totalTime').textContent = `${totalTime}ms`;
 
 
 
 
 
 
 
 
 
 
649
  }
650
 
651
  // --- Event Listeners ---
@@ -661,9 +739,15 @@
661
 
662
  backButtons.forEach(button => {
663
  button.addEventListener('click', () => {
664
- stopCamera();
665
- fileInput.value = null; // Clear file input
666
- showView('landing');
 
 
 
 
 
 
667
  });
668
  });
669
 
@@ -673,7 +757,7 @@
673
  return;
674
  }
675
 
676
- startTime = Date.now();
677
 
678
  // Process the current video frame
679
  processImage(video, video.videoWidth, video.videoHeight);
@@ -691,7 +775,7 @@
691
  return;
692
  }
693
 
694
- startTime = Date.now();
695
 
696
  const reader = new FileReader();
697
  reader.onload = (e) => {
 
280
 
281
  <!-- Performance Stats -->
282
  <div class="bg-gray-800/30 rounded-xl p-3 text-xs space-y-1 border border-gray-700/50">
283
+ <div class="flex justify-between items-center mb-2 pb-2 border-b border-gray-700/50">
284
+ <span class="text-gray-400 font-semibold">Performance Breakdown</span>
285
+ </div>
286
+ <div class="flex justify-between">
287
+ <span class="text-gray-500">Client Processing:</span>
288
+ <span id="clientProcessingTime" class="font-mono text-cyan-400"></span>
289
+ </div>
290
+ <div class="flex justify-between">
291
+ <span class="text-gray-500">Server Prediction: 🚀</span>
292
+ <span id="predictionTime" class="font-mono text-emerald-400 font-bold"></span>
293
+ </div>
294
  <div class="flex justify-between">
295
+ <span class="text-gray-500">Scryfall API:</span>
296
+ <span id="scryfallTime" class="font-mono text-orange-400"></span>
297
  </div>
298
  <div class="flex justify-between">
299
+ <span class="text-gray-500">Remainder (network, UI, etc.):</span>
300
+ <span id="remainderTime" class="font-mono text-gray-400"></span>
301
+ </div>
302
+ <div class="flex justify-between pt-2 border-t border-gray-700/50">
303
+ <span class="text-gray-400 font-semibold">Total Time:</span>
304
+ <span id="totalTime" class="font-mono text-violet-400 font-semibold"></span>
305
  </div>
306
  </div>
307
  </div>
 
322
  <!-- Hidden canvas for processing -->
323
  <canvas id="processingCanvas" class="hidden" width="224" height="224"></canvas>
324
  <canvas id="processedCanvas" class="hidden" width="224" height="224"></canvas>
325
+
326
 
327
  <script>
328
  document.addEventListener('DOMContentLoaded', () => {
 
362
  let currentStream = null;
363
  let startTime = null;
364
  const FINAL_SIZE = 224;
365
+ let viewHistory = ['landing']; // Track navigation history
366
+
367
+ // Timing variables
368
+ let timings = {
369
+ clientProcessing: 0,
370
+ serverPrediction: 0,
371
+ scryfallApi: 0,
372
+ remainder: 0,
373
+ total: 0
374
+ };
375
 
376
  // --- View Navigation ---
377
 
378
+ function showView(viewId, addToHistory = true) {
379
  // Hide all views
380
  Object.values(views).forEach(view => view.classList.add('hidden'));
381
  // Show the target view
382
  if (views[viewId]) {
383
  views[viewId].classList.remove('hidden');
384
+ // Add to history if specified
385
+ if (addToHistory) {
386
+ viewHistory.push(viewId);
387
+ }
388
+ }
389
+ }
390
+
391
+ function goBack() {
392
+ // Remove current view from history
393
+ if (viewHistory.length > 1) {
394
+ viewHistory.pop();
395
+ // Get previous view
396
+ const previousView = viewHistory[viewHistory.length - 1];
397
+ showView(previousView, false); // Don't add to history when going back
398
+
399
+ // Restart camera if going back to live scan
400
+ if (previousView === 'liveScan' && !currentStream) {
401
+ startCamera();
402
+ }
403
+ } else {
404
+ // Fallback to landing if history is empty
405
+ viewHistory = ['landing'];
406
+ showView('landing', false);
407
  }
408
  }
409
 
 
467
  // --- Image Processing ---
468
 
469
  function processImage(source, sourceWidth, sourceHeight) {
470
+ // Timing will be completed in callPredictAPI after blob conversion
471
+
472
  // 1. Find the smallest dimension to create a square crop
473
  const size = Math.min(sourceWidth, sourceHeight);
474
 
 
516
 
517
  async function callPredictAPI() {
518
  try {
519
+ const clientStart = performance.now();
520
+
521
+ // Convert canvas to blob (includes preprocessing time from processImage)
522
  const blob = await new Promise(resolve => {
523
  processedCanvas.toBlob(resolve, 'image/png');
524
  });
525
 
526
+ const clientEnd = performance.now();
527
+ timings.clientProcessing = Math.round(clientEnd - clientStart);
528
+
529
  // Create form data
530
  const formData = new FormData();
531
  formData.append('file', blob, 'image.png');
 
542
  }
543
 
544
  const result = await response.json();
545
+
546
+ // Server prediction time comes from the API response
547
+ timings.serverPrediction = result.prediction_time;
548
+
549
  return result;
550
 
551
  } catch (error) {
 
557
 
558
  async function fetchCardDetails(cardId) {
559
  try {
560
+ const scryfallStart = performance.now();
561
+
562
  const response = await fetch(`https://api.scryfall.com/cards/${cardId}`);
563
  if (!response.ok) {
564
  throw new Error('Failed to fetch card details');
565
  }
566
+ const data = await response.json();
567
+
568
+ const scryfallEnd = performance.now();
569
+ timings.scryfallApi = Math.round(scryfallEnd - scryfallStart);
570
+
571
+ return data;
572
  } catch (error) {
573
  console.error('Scryfall API Error:', error);
574
  showMessage('Error fetching card details from Scryfall');
 
594
 
595
  // Call the prediction API
596
  const apiResult = await callPredictAPI();
 
 
597
 
598
  if (!apiResult) {
599
  showMessage('Failed to identify card');
 
703
  `;
704
  }
705
 
706
+ // Calculate total time and remainder
707
+ const endTime = performance.now();
708
+ timings.total = Math.round(endTime - startTime);
709
+
710
+ // Calculate remainder (everything not explicitly tracked)
711
+ timings.remainder = timings.total - timings.clientProcessing - timings.serverPrediction - timings.scryfallApi;
712
+
713
  // Performance stats
714
+ document.getElementById('clientProcessingTime').textContent = `${timings.clientProcessing}ms`;
715
+ document.getElementById('predictionTime').textContent = `${timings.serverPrediction}ms`;
716
+ document.getElementById('scryfallTime').textContent = `${timings.scryfallApi}ms`;
717
+ document.getElementById('remainderTime').textContent = `${timings.remainder}ms`;
718
+ document.getElementById('totalTime').textContent = `${timings.total}ms`;
719
+
720
+ // Log timing breakdown for debugging
721
+ console.log('Performance Breakdown:');
722
+ console.log(` Client Processing (crop+resize+blob): ${timings.clientProcessing}ms`);
723
+ console.log(` 🚀 Server Prediction: ${timings.serverPrediction}ms`);
724
+ console.log(` Scryfall API: ${timings.scryfallApi}ms`);
725
+ console.log(` Remainder (network, UI, etc.): ${timings.remainder}ms`);
726
+ console.log(` Total: ${timings.total}ms`);
727
  }
728
 
729
  // --- Event Listeners ---
 
739
 
740
  backButtons.forEach(button => {
741
  button.addEventListener('click', () => {
742
+ // Stop camera if currently active
743
+ if (currentStream) {
744
+ stopCamera();
745
+ }
746
+ // Clear file input if in upload view
747
+ if (!views.upload.classList.contains('hidden')) {
748
+ fileInput.value = null;
749
+ }
750
+ goBack();
751
  });
752
  });
753
 
 
757
  return;
758
  }
759
 
760
+ startTime = performance.now();
761
 
762
  // Process the current video frame
763
  processImage(video, video.videoWidth, video.videoHeight);
 
775
  return;
776
  }
777
 
778
+ startTime = performance.now();
779
 
780
  const reader = new FileReader();
781
  reader.onload = (e) => {