djwugee commited on
Commit
297a5ae
·
verified ·
1 Parent(s): 6a8bd1c

Add real image input audio input and output for any media inferencing models

Browse files
Files changed (1) hide show
  1. index.html +392 -27
index.html CHANGED
@@ -373,7 +373,6 @@
373
  <label class="block text-slate-300 mb-2">Selected File</label>
374
  <div id="previewContent" class="bg-slate-800 rounded-lg p-4"></div>
375
  </div>
376
-
377
  <!-- Media Controls -->
378
  <div class="mb-6 hidden" id="mediaControls">
379
  <label class="block text-slate-300 mb-3">Media Controls</label>
@@ -381,21 +380,68 @@
381
  <div class="flex items-center justify-between">
382
  <span>Auto-play</span>
383
  <label class="relative inline-flex items-center cursor-pointer">
384
- <input type="checkbox" class="sr-only peer">
385
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
386
  </label>
387
  </div>
388
  <div class="flex items-center justify-between">
389
  <span>Loop</span>
390
  <label class="relative inline-flex items-center cursor-pointer">
391
- <input type="checkbox" class="sr-only peer" checked>
392
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
393
  </label>
394
  </div>
395
  </div>
396
  </div>
397
 
398
- <!-- Preprocessing Options -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  <div class="mb-6" id="preprocessingSection">
400
  <label class="block text-slate-300 mb-2">Preprocessing</label>
401
  <div class="space-y-3" id="preprocessingOptions">
@@ -503,10 +549,20 @@
503
  let currentInputType = 'image';
504
  let modelInfo = {};
505
 
 
 
 
 
 
 
 
 
 
 
 
506
  // Initialize Feather Icons
507
  feather.replace();
508
-
509
- // DOM Elements
510
  const modelTypeCards = document.querySelectorAll('[data-model-type]');
511
  const uploadSection = document.getElementById('uploadSection');
512
  const uploadTitle = document.getElementById('uploadTitle');
@@ -531,6 +587,24 @@
531
  const preprocessingSection = document.getElementById('preprocessingSection');
532
  const preprocessingOptions = document.getElementById('preprocessingOptions');
533
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  // Output elements
535
  const inferenceTime = document.getElementById('inferenceTime');
536
  const outputProgress = document.getElementById('outputProgress');
@@ -625,6 +699,136 @@
625
  modelFileInput.click();
626
  });
627
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  // Input type selection
629
  inputTypeGrid.addEventListener('click', (e) => {
630
  const btn = e.target.closest('.input-type-btn');
@@ -662,6 +866,10 @@
662
  });
663
 
664
  function selectInputSource(source) {
 
 
 
 
665
  // Update button styles
666
  document.querySelectorAll('.input-source-btn').forEach(btn => {
667
  btn.classList.remove('bg-indigo-600');
@@ -674,6 +882,15 @@
674
  textInputArea.classList.toggle('hidden', source !== 'text');
675
  filePreview.classList.toggle('hidden', source !== 'upload');
676
  mediaControls.classList.toggle('hidden', !['audio', 'video'].includes(currentInputType));
 
 
 
 
 
 
 
 
 
677
 
678
  logMessage(`Selected ${source} input source`);
679
  }
@@ -704,22 +921,22 @@
704
  function updatePreprocessingOptions(inputType) {
705
  const options = {
706
  image: [
707
- { id: 'resize', label: 'Resize', checked: true },
708
- { id: 'normalize', label: 'Normalize', checked: true },
709
- { id: '裁剪', label: 'Crop', checked: false },
710
- { id: 'rotate', label: 'Rotate', checked: false },
711
- { id: 'flip', label: 'Flip', checked: false }
712
  ],
713
  audio: [
714
- { id: 'resample', label: 'Resample', checked: true },
715
- { id: 'normalize', label: 'Normalize', checked: true },
716
- { id: 'denoise', label: 'Denoise', checked: false },
717
  { id: 'trim', label: 'Trim Silence', checked: false },
718
- { id: 'augment', label: 'Augment', checked: false }
719
  ],
720
  text: [
721
- { id: 'tokenize', label: 'Tokenize', checked: true },
722
- { id: 'lowercase', label: 'Lowercase', checked: false },
723
  { id: 'remove_punct', label: 'Remove Punctuation', checked: false },
724
  { id: 'stop_words', label: 'Remove Stop Words', checked: false },
725
  { id: 'stem', label: 'Stemming', checked: false }
@@ -768,6 +985,43 @@
768
  analysisSection.scrollIntoView({ behavior: 'smooth' });
769
  }
770
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
  // Populate analysis data based on model type
772
  function populateAnalysisData(file) {
773
  modelInfo = {
@@ -851,6 +1105,10 @@
851
  // Simulate inference process
852
  logMessage('Starting inference...');
853
 
 
 
 
 
854
  // Simulate processing steps
855
  const steps = [
856
  'Preprocessing input data...',
@@ -869,7 +1127,7 @@
869
  inferenceTime.textContent = (endTime - startTime) + 'ms';
870
 
871
  // Display results
872
- displayResults();
873
 
874
  executeBtn.disabled = false;
875
  executeBtn.innerHTML = '<i data-feather="play" class="mr-2"></i>Execute Inference';
@@ -877,18 +1135,57 @@
877
  logMessage('Inference completed successfully');
878
  });
879
 
880
- function displayResults() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
881
  const outputType = currentInputType;
882
  let outputHTML = '';
883
 
884
  switch (outputType) {
885
  case 'image':
 
 
 
 
 
 
 
 
 
886
  outputHTML = `
887
  <div class="text-center">
888
- <div class="w-48 h-48 bg-gradient-to-br from-purple-400 to-pink-400 rounded-lg mx-auto mb-4 flex items-center justify-center">
 
889
  <i data-feather="image" class="text-white w-16 h-16"></i>
890
- </div>
891
- <p class="text-slate-300">Generated Image Output</p>
892
  <p class="text-sm text-slate-400 mt-2">224x224 RGB</p>
893
  </div>
894
  `;
@@ -896,8 +1193,18 @@
896
  break;
897
 
898
  case 'audio':
 
 
 
 
 
 
 
 
 
899
  outputHTML = `
900
  <div class="text-center">
 
901
  <div class="bg-slate-700 rounded-lg p-6 mb-4">
902
  <div class="flex items-center justify-center mb-4">
903
  <i data-feather="play" class="text-emerald-400 w-8 h-8 mr-2"></i>
@@ -908,22 +1215,25 @@
908
  `<div class="bg-emerald-400 w-2 rounded-t" style="height: ${Math.random() * 80 + 20}%"></div>`
909
  ).join('')}
910
  </div>
911
- </div>
912
- <p class="text-slate-300">Audio Output (44.1kHz, 16-bit)</p>
913
- <p class="text-sm text-slate-400 mt-2">Duration: 3.2s</p>
914
  </div>
915
  `;
916
  downloadOptions.classList.remove('hidden');
917
  break;
918
 
919
  case 'text':
 
920
  outputHTML = `
921
  <div class="text-left">
922
  <div class="bg-slate-800 rounded-lg p-4 mb-4">
923
- <p class="text-slate-300">This is a sample generated text output from the ONNX model. The text processing model has successfully processed the input and generated meaningful content based on the model capabilities.</p>
 
 
924
  </div>
925
  <div class="flex items-center space-x-4">
926
- <button class="px-3 py-1 bg-slate-700 hover:bg-slate-600 rounded text-sm">
927
  <i data-feather="copy" class="w-4 h-4 mr-1 inline"></i>Copy
928
  </button>
929
  <button class="px-3 py-1 bg-slate-700 hover:bg-slate-600 rounded text-sm">
@@ -943,6 +1253,55 @@
943
  outputDisplay.classList.remove('hidden');
944
  }
945
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946
  // Log messages to console
947
  function logMessage(message) {
948
  const timestamp = new Date().toLocaleTimeString();
@@ -992,6 +1351,12 @@
992
  loadModelBtn.addEventListener('click', () => {
993
  modelFileInput.click();
994
  });
 
 
 
 
 
 
995
  </script>
996
  </body>
997
  </html>
 
373
  <label class="block text-slate-300 mb-2">Selected File</label>
374
  <div id="previewContent" class="bg-slate-800 rounded-lg p-4"></div>
375
  </div>
 
376
  <!-- Media Controls -->
377
  <div class="mb-6 hidden" id="mediaControls">
378
  <label class="block text-slate-300 mb-3">Media Controls</label>
 
380
  <div class="flex items-center justify-between">
381
  <span>Auto-play</span>
382
  <label class="relative inline-flex items-center cursor-pointer">
383
+ <input type="checkbox" id="autoPlayToggle" class="sr-only peer">
384
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
385
  </label>
386
  </div>
387
  <div class="flex items-center justify-between">
388
  <span>Loop</span>
389
  <label class="relative inline-flex items-center cursor-pointer">
390
+ <input type="checkbox" id="loopToggle" class="sr-only peer" checked>
391
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
392
  </label>
393
  </div>
394
  </div>
395
  </div>
396
 
397
+ <!-- Camera Stream -->
398
+ <div class="mb-6 hidden" id="cameraSection">
399
+ <label class="block text-slate-300 mb-2">Camera Stream</label>
400
+ <video id="cameraStream" class="w-full max-h-48 bg-black rounded-lg" autoplay muted playsinline></video>
401
+ <div class="flex space-x-2 mt-3">
402
+ <button id="captureBtn" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 rounded-lg text-sm transition flex items-center">
403
+ <i data-feather="camera" class="mr-2"></i>Capture
404
+ </button>
405
+ <button id="stopCameraBtn" class="px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg text-sm transition flex items-center">
406
+ <i data-feather="stop-circle" class="mr-2"></i>Stop
407
+ </button>
408
+ </div>
409
+ </div>
410
+
411
+ <!-- Microphone Stream -->
412
+ <div class="mb-6 hidden" id="microphoneSection">
413
+ <label class="block text-slate-300 mb-2">Audio Recording</label>
414
+ <div id="audioLevel" class="bg-slate-800 rounded-lg p-4">
415
+ <div class="flex items-center justify-between mb-2">
416
+ <span class="text-sm text-slate-400">Recording Level</span>
417
+ <span id="audioLevelValue" class="text-sm text-slate-300">0%</span>
418
+ </div>
419
+ <div class="h-2 bg-slate-700 rounded-full overflow-hidden">
420
+ <div id="audioLevelBar" class="h-full bg-emerald-400 rounded-full transition-all duration-200" style="width: 0%"></div>
421
+ </div>
422
+ </div>
423
+ <div class="flex space-x-2 mt-3">
424
+ <button id="startRecordingBtn" class="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 rounded-lg text-sm transition flex items-center">
425
+ <i data-feather="mic" class="mr-2"></i>Start Recording
426
+ </button>
427
+ <button id="stopRecordingBtn" class="px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg text-sm transition flex items-center">
428
+ <i data-feather="square" class="mr-2"></i>Stop
429
+ </button>
430
+ </div>
431
+ </div>
432
+
433
+ <!-- Captured Image -->
434
+ <div class="mb-6 hidden" id="capturedImageSection">
435
+ <label class="block text-slate-300 mb-2">Captured Image</label>
436
+ <canvas id="capturedCanvas" class="w-full max-h-48 border border-slate-600 rounded-lg"></canvas>
437
+ </div>
438
+
439
+ <!-- Recorded Audio -->
440
+ <div class="mb-6 hidden" id="recordedAudioSection">
441
+ <label class="block text-slate-300 mb-2">Recorded Audio</label>
442
+ <audio id="recordedAudio" class="w-full" controls></audio>
443
+ </div>
444
+ <!-- Preprocessing Options -->
445
  <div class="mb-6" id="preprocessingSection">
446
  <label class="block text-slate-300 mb-2">Preprocessing</label>
447
  <div class="space-y-3" id="preprocessingOptions">
 
549
  let currentInputType = 'image';
550
  let modelInfo = {};
551
 
552
+ // Media streams
553
+ let cameraStream = null;
554
+ let microphoneStream = null;
555
+ let mediaRecorder = null;
556
+ let recordedChunks = [];
557
+ let audioContext = null;
558
+ let audioAnalyzer = null;
559
+ let audioLevelInterval = null;
560
+ let currentCapturedImage = null;
561
+ let currentRecordedAudioBlob = null;
562
+
563
  // Initialize Feather Icons
564
  feather.replace();
565
+ // DOM Elements
 
566
  const modelTypeCards = document.querySelectorAll('[data-model-type]');
567
  const uploadSection = document.getElementById('uploadSection');
568
  const uploadTitle = document.getElementById('uploadTitle');
 
587
  const preprocessingSection = document.getElementById('preprocessingSection');
588
  const preprocessingOptions = document.getElementById('preprocessingOptions');
589
 
590
+ // New media elements
591
+ const cameraSection = document.getElementById('cameraSection');
592
+ const microphoneSection = document.getElementById('microphoneSection');
593
+ const capturedImageSection = document.getElementById('capturedImageSection');
594
+ const recordedAudioSection = document.getElementById('recordedAudioSection');
595
+ const cameraStream = document.getElementById('cameraStream');
596
+ const audioLevel = document.getElementById('audioLevel');
597
+ const audioLevelBar = document.getElementById('audioLevelBar');
598
+ const audioLevelValue = document.getElementById('audioLevelValue');
599
+ const capturedCanvas = document.getElementById('capturedCanvas');
600
+ const recordedAudio = document.getElementById('recordedAudio');
601
+ const captureBtn = document.getElementById('captureBtn');
602
+ const stopCameraBtn = document.getElementById('stopCameraBtn');
603
+ const startRecordingBtn = document.getElementById('startRecordingBtn');
604
+ const stopRecordingBtn = document.getElementById('stopRecordingBtn');
605
+ const autoPlayToggle = document.getElementById('autoPlayToggle');
606
+ const loopToggle = document.getElementById('loopToggle');
607
+
608
  // Output elements
609
  const inferenceTime = document.getElementById('inferenceTime');
610
  const outputProgress = document.getElementById('outputProgress');
 
699
  modelFileInput.click();
700
  });
701
 
702
+ // Camera functions
703
+ async function startCamera() {
704
+ try {
705
+ cameraStream = await navigator.mediaDevices.getUserMedia({
706
+ video: { width: 640, height: 480 }
707
+ });
708
+ cameraStream.srcObject = cameraStream;
709
+ cameraSection.classList.remove('hidden');
710
+ logMessage('Camera started successfully');
711
+ } catch (error) {
712
+ console.error('Error accessing camera:', error);
713
+ logMessage('Error: Could not access camera - ' + error.message);
714
+ alert('Could not access camera. Please check permissions.');
715
+ }
716
+ }
717
+
718
+ function stopCamera() {
719
+ if (cameraStream) {
720
+ cameraStream.getTracks().forEach(track => track.stop());
721
+ cameraStream = null;
722
+ cameraStream.srcObject = null;
723
+ cameraSection.classList.add('hidden');
724
+ logMessage('Camera stopped');
725
+ }
726
+ }
727
+
728
+ function captureImage() {
729
+ if (!cameraStream) return;
730
+
731
+ const canvas = capturedCanvas;
732
+ const ctx = canvas.getContext('2d');
733
+ canvas.width = 640;
734
+ canvas.height = 480;
735
+
736
+ ctx.drawImage(cameraStream, 0, 0, canvas.width, canvas.height);
737
+ currentCapturedImage = canvas.toDataURL('image/jpeg');
738
+ capturedImageSection.classList.remove('hidden');
739
+
740
+ logMessage('Image captured from camera');
741
+ }
742
+
743
+ // Microphone functions
744
+ async function startRecording() {
745
+ try {
746
+ microphoneStream = await navigator.mediaDevices.getUserMedia({
747
+ audio: true
748
+ });
749
+
750
+ // Set up audio context and analyzer
751
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
752
+ const source = audioContext.createMediaStreamSource(microphoneStream);
753
+ audioAnalyzer = audioContext.createAnalyser();
754
+ audioAnalyzer.fftSize = 256;
755
+ source.connect(audioAnalyzer);
756
+
757
+ // Start recording
758
+ mediaRecorder = new MediaRecorder(microphoneStream);
759
+ recordedChunks = [];
760
+
761
+ mediaRecorder.ondataavailable = (event) => {
762
+ if (event.data.size > 0) {
763
+ recordedChunks.push(event.data);
764
+ }
765
+ };
766
+
767
+ mediaRecorder.onstop = () => {
768
+ const blob = new Blob(recordedChunks, { type: 'audio/wav' });
769
+ currentRecordedAudioBlob = blob;
770
+ recordedAudio.src = URL.createObjectURL(blob);
771
+ recordedAudioSection.classList.remove('hidden');
772
+ logMessage('Audio recording completed');
773
+ };
774
+
775
+ mediaRecorder.start();
776
+ microphoneSection.classList.remove('hidden');
777
+ startAudioLevelMonitoring();
778
+
779
+ logMessage('Recording started');
780
+ } catch (error) {
781
+ console.error('Error accessing microphone:', error);
782
+ logMessage('Error: Could not access microphone - ' + error.message);
783
+ alert('Could not access microphone. Please check permissions.');
784
+ }
785
+ }
786
+
787
+ function startAudioLevelMonitoring() {
788
+ const dataArray = new Uint8Array(audioAnalyzer.frequencyBinCount);
789
+
790
+ audioLevelInterval = setInterval(() => {
791
+ audioAnalyzer.getByteFrequencyData(dataArray);
792
+ const average = dataArray.reduce((sum, value) => sum + value) / dataArray.length;
793
+ const percentage = Math.min((average / 255) * 100, 100);
794
+
795
+ audioLevelBar.style.width = percentage + '%';
796
+ audioLevelValue.textContent = Math.round(percentage) + '%';
797
+
798
+ if (percentage > 70) {
799
+ audioLevelBar.classList.add('bg-red-400');
800
+ audioLevelBar.classList.remove('bg-emerald-400');
801
+ } else {
802
+ audioLevelBar.classList.add('bg-emerald-400');
803
+ audioLevelBar.classList.remove('bg-red-400');
804
+ }
805
+ }, 100);
806
+ }
807
+
808
+ function stopRecording() {
809
+ if (mediaRecorder && mediaRecorder.state === 'recording') {
810
+ mediaRecorder.stop();
811
+ }
812
+
813
+ if (microphoneStream) {
814
+ microphoneStream.getTracks().forEach(track => track.stop());
815
+ microphoneStream = null;
816
+ }
817
+
818
+ if (audioContext) {
819
+ audioContext.close();
820
+ audioContext = null;
821
+ }
822
+
823
+ if (audioLevelInterval) {
824
+ clearInterval(audioLevelInterval);
825
+ audioLevelInterval = null;
826
+ }
827
+
828
+ microphoneSection.classList.add('hidden');
829
+ logMessage('Recording stopped');
830
+ }
831
+
832
  // Input type selection
833
  inputTypeGrid.addEventListener('click', (e) => {
834
  const btn = e.target.closest('.input-type-btn');
 
866
  });
867
 
868
  function selectInputSource(source) {
869
+ // Stop any active streams when changing source
870
+ if (source !== 'camera') stopCamera();
871
+ if (source !== 'microphone') stopRecording();
872
+
873
  // Update button styles
874
  document.querySelectorAll('.input-source-btn').forEach(btn => {
875
  btn.classList.remove('bg-indigo-600');
 
882
  textInputArea.classList.toggle('hidden', source !== 'text');
883
  filePreview.classList.toggle('hidden', source !== 'upload');
884
  mediaControls.classList.toggle('hidden', !['audio', 'video'].includes(currentInputType));
885
+ cameraSection.classList.toggle('hidden', source !== 'camera');
886
+ microphoneSection.classList.toggle('hidden', source !== 'microphone');
887
+
888
+ // Start appropriate media source
889
+ if (source === 'camera') {
890
+ startCamera();
891
+ } else if (source === 'microphone') {
892
+ // Don't auto-start recording, let user click the button
893
+ }
894
 
895
  logMessage(`Selected ${source} input source`);
896
  }
 
921
  function updatePreprocessingOptions(inputType) {
922
  const options = {
923
  image: [
924
+ { id: 'resize', label: 'Resize to 224x224', checked: true },
925
+ { id: 'normalize', label: 'Normalize (0-1)', checked: true },
926
+ { id: '裁剪', label: 'Center Crop', checked: false },
927
+ { id: 'rotate', label: 'Random Rotate', checked: false },
928
+ { id: 'flip', label: 'Horizontal Flip', checked: false }
929
  ],
930
  audio: [
931
+ { id: 'resample', label: 'Resample to 16kHz', checked: true },
932
+ { id: 'normalize', label: 'Normalize Audio', checked: true },
933
+ { id: 'denoise', label: 'Noise Reduction', checked: false },
934
  { id: 'trim', label: 'Trim Silence', checked: false },
935
+ { id: 'augment', label: 'Data Augmentation', checked: false }
936
  ],
937
  text: [
938
+ { id: 'tokenize', label: 'Tokenize Text', checked: true },
939
+ { id: 'lowercase', label: 'Convert to Lowercase', checked: false },
940
  { id: 'remove_punct', label: 'Remove Punctuation', checked: false },
941
  { id: 'stop_words', label: 'Remove Stop Words', checked: false },
942
  { id: 'stem', label: 'Stemming', checked: false }
 
985
  analysisSection.scrollIntoView({ behavior: 'smooth' });
986
  }
987
 
988
+ // Handle media file uploads (images/audio)
989
+ function handleMediaFileUpload(file) {
990
+ if (currentInputType === 'image' && file.type.startsWith('image/')) {
991
+ const reader = new FileReader();
992
+ reader.onload = (e) => {
993
+ previewContent.innerHTML = `
994
+ <img src="${e.target.result}" class="w-full max-h-48 object-contain rounded" alt="Preview">
995
+ <p class="text-sm text-slate-400 mt-2">${file.name} (${(file.size / 1024).toFixed(1)} KB)</p>
996
+ `;
997
+ filePreview.classList.remove('hidden');
998
+ };
999
+ reader.readAsDataURL(file);
1000
+ } else if (currentInputType === 'audio' && file.type.startsWith('audio/')) {
1001
+ const url = URL.createObjectURL(file);
1002
+ previewContent.innerHTML = `
1003
+ <audio controls class="w-full">
1004
+ <source src="${url}" type="${file.type}">
1005
+ Your browser does not support the audio element.
1006
+ </audio>
1007
+ <p class="text-sm text-slate-400 mt-2">${file.name} (${(file.size / 1024).toFixed(1)} KB)</p>
1008
+ `;
1009
+ filePreview.classList.remove('hidden');
1010
+ }
1011
+ }
1012
+
1013
+ // Update model file input to handle both ONNX and media files
1014
+ modelFileInput.addEventListener('change', (e) => {
1015
+ const file = e.target.files[0];
1016
+ if (!file) return;
1017
+
1018
+ if (file.name.endsWith('.onnx')) {
1019
+ handleFileUpload(file);
1020
+ } else if (currentInputType && ['image', 'audio'].includes(currentInputType)) {
1021
+ handleMediaFileUpload(file);
1022
+ }
1023
+ });
1024
+
1025
  // Populate analysis data based on model type
1026
  function populateAnalysisData(file) {
1027
  modelInfo = {
 
1105
  // Simulate inference process
1106
  logMessage('Starting inference...');
1107
 
1108
+ // Get current input data
1109
+ const inputData = await getInputData();
1110
+ logMessage('Input data prepared for inference');
1111
+
1112
  // Simulate processing steps
1113
  const steps = [
1114
  'Preprocessing input data...',
 
1127
  inferenceTime.textContent = (endTime - startTime) + 'ms';
1128
 
1129
  // Display results
1130
+ await displayResults();
1131
 
1132
  executeBtn.disabled = false;
1133
  executeBtn.innerHTML = '<i data-feather="play" class="mr-2"></i>Execute Inference';
 
1135
  logMessage('Inference completed successfully');
1136
  });
1137
 
1138
+ async function getInputData() {
1139
+ const source = document.querySelector('.input-source-btn.bg-indigo-600')?.dataset.source;
1140
+
1141
+ switch (source) {
1142
+ case 'upload':
1143
+ const file = modelFileInput.files[0];
1144
+ if (file && !file.name.endsWith('.onnx')) {
1145
+ return { type: currentInputType, file: file };
1146
+ }
1147
+ break;
1148
+ case 'camera':
1149
+ if (currentCapturedImage) {
1150
+ return { type: 'image', data: currentCapturedImage };
1151
+ }
1152
+ break;
1153
+ case 'microphone':
1154
+ if (currentRecordedAudioBlob) {
1155
+ return { type: 'audio', blob: currentRecordedAudioBlob };
1156
+ }
1157
+ break;
1158
+ case 'text':
1159
+ const text = document.getElementById('textInput').value;
1160
+ return { type: 'text', data: text };
1161
+ }
1162
+
1163
+ return null;
1164
+ }
1165
+
1166
+ async function displayResults() {
1167
+ const inputData = await getInputData();
1168
  const outputType = currentInputType;
1169
  let outputHTML = '';
1170
 
1171
  switch (outputType) {
1172
  case 'image':
1173
+ let imageSource = '';
1174
+ if (inputData?.type === 'image') {
1175
+ if (inputData.data) {
1176
+ imageSource = inputData.data; // captured image
1177
+ } else if (inputData.file) {
1178
+ imageSource = URL.createObjectURL(inputData.file); // uploaded file
1179
+ }
1180
+ }
1181
+
1182
  outputHTML = `
1183
  <div class="text-center">
1184
+ ${imageSource ? `<img src="${imageSource}" class="w-full max-h-64 object-contain rounded-lg mx-auto mb-4" alt="Processed Image">` : `
1185
+ <div class="w-full h-64 bg-gradient-to-br from-purple-400 to-pink-400 rounded-lg mx-auto mb-4 flex items-center justify-center">
1186
  <i data-feather="image" class="text-white w-16 h-16"></i>
1187
+ </div>`}
1188
+ <p class="text-slate-300">Processed Image Output</p>
1189
  <p class="text-sm text-slate-400 mt-2">224x224 RGB</p>
1190
  </div>
1191
  `;
 
1193
  break;
1194
 
1195
  case 'audio':
1196
+ let audioElement = '';
1197
+ if (inputData?.type === 'audio') {
1198
+ const audioUrl = inputData.blob ? URL.createObjectURL(inputData.blob) : URL.createObjectURL(inputData.file);
1199
+ audioElement = `<audio controls class="w-full mb-4" ${autoPlayToggle.checked ? 'autoplay' : ''} ${loopToggle.checked ? 'loop' : ''}>
1200
+ <source src="${audioUrl}" type="audio/wav">
1201
+ Your browser does not support the audio element.
1202
+ </audio>`;
1203
+ }
1204
+
1205
  outputHTML = `
1206
  <div class="text-center">
1207
+ ${audioElement || `
1208
  <div class="bg-slate-700 rounded-lg p-6 mb-4">
1209
  <div class="flex items-center justify-center mb-4">
1210
  <i data-feather="play" class="text-emerald-400 w-8 h-8 mr-2"></i>
 
1215
  `<div class="bg-emerald-400 w-2 rounded-t" style="height: ${Math.random() * 80 + 20}%"></div>`
1216
  ).join('')}
1217
  </div>
1218
+ </div>`}
1219
+ <p class="text-slate-300">Processed Audio Output</p>
1220
+ <p class="text-sm text-slate-400 mt-2">44.1kHz, 16-bit</p>
1221
  </div>
1222
  `;
1223
  downloadOptions.classList.remove('hidden');
1224
  break;
1225
 
1226
  case 'text':
1227
+ const inputText = inputData?.data || 'Sample text for processing';
1228
  outputHTML = `
1229
  <div class="text-left">
1230
  <div class="bg-slate-800 rounded-lg p-4 mb-4">
1231
+ <p class="text-slate-300 mb-2"><strong>Input:</strong> ${inputText}</p>
1232
+ <hr class="border-slate-600 my-3">
1233
+ <p class="text-slate-300"><strong>Output:</strong> This is a sample generated text output from the ONNX model. The text processing model has successfully processed the input "${inputText}" and generated meaningful content based on the model capabilities and preprocessing options selected.</p>
1234
  </div>
1235
  <div class="flex items-center space-x-4">
1236
+ <button class="px-3 py-1 bg-slate-700 hover:bg-slate-600 rounded text-sm" onclick="navigator.clipboard.writeText(this.closest('.text-left').querySelector('p:last-child').textContent)">
1237
  <i data-feather="copy" class="w-4 h-4 mr-1 inline"></i>Copy
1238
  </button>
1239
  <button class="px-3 py-1 bg-slate-700 hover:bg-slate-600 rounded text-sm">
 
1253
  outputDisplay.classList.remove('hidden');
1254
  }
1255
 
1256
+ // Event listeners for media controls
1257
+ captureBtn.addEventListener('click', captureImage);
1258
+ stopCameraBtn.addEventListener('click', stopCamera);
1259
+ startRecordingBtn.addEventListener('click', startRecording);
1260
+ stopRecordingBtn.addEventListener('click', stopRecording);
1261
+
1262
+ // Download functionality
1263
+ downloadOptions.addEventListener('click', (e) => {
1264
+ if (e.target.closest('button')) {
1265
+ const button = e.target.closest('button');
1266
+ if (button.textContent.includes('Download')) {
1267
+ downloadResults();
1268
+ }
1269
+ }
1270
+ });
1271
+
1272
+ function downloadResults() {
1273
+ const outputType = currentInputType;
1274
+
1275
+ switch (outputType) {
1276
+ case 'image':
1277
+ if (currentCapturedImage) {
1278
+ const link = document.createElement('a');
1279
+ link.href = currentCapturedImage;
1280
+ link.download = 'processed_image.jpg';
1281
+ link.click();
1282
+ }
1283
+ break;
1284
+ case 'audio':
1285
+ if (currentRecordedAudioBlob) {
1286
+ const link = document.createElement('a');
1287
+ link.href = URL.createObjectURL(currentRecordedAudioBlob);
1288
+ link.download = 'processed_audio.wav';
1289
+ link.click();
1290
+ }
1291
+ break;
1292
+ case 'text':
1293
+ const textContent = outputContent.querySelector('p:last-child').textContent;
1294
+ const blob = new Blob([textContent], { type: 'text/plain' });
1295
+ const link = document.createElement('a');
1296
+ link.href = URL.createObjectURL(blob);
1297
+ link.download = 'processed_text.txt';
1298
+ link.click();
1299
+ break;
1300
+ }
1301
+
1302
+ logMessage('Results downloaded successfully');
1303
+ }
1304
+
1305
  // Log messages to console
1306
  function logMessage(message) {
1307
  const timestamp = new Date().toLocaleTimeString();
 
1351
  loadModelBtn.addEventListener('click', () => {
1352
  modelFileInput.click();
1353
  });
1354
+
1355
+ // Clean up media streams when page unloads
1356
+ window.addEventListener('beforeunload', () => {
1357
+ stopCamera();
1358
+ stopRecording();
1359
+ });
1360
  </script>
1361
  </body>
1362
  </html>