webapp1 commited on
Commit
332cede
·
verified ·
1 Parent(s): 4ce42a8

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +38 -13
templates/index.html CHANGED
@@ -5,7 +5,6 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
  <title>CrashVision AI - Accident Detection</title>
7
 
8
- <!-- 📱 MOBILE APP & HOME SCREEN ICONS SETUP 📱 -->
9
  <meta name="apple-mobile-web-app-capable" content="yes">
10
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
11
  <meta name="apple-mobile-web-app-title" content="CrashVision">
@@ -170,7 +169,7 @@
170
  <div class="ios-glass p-6 rounded-[32px] hover:-translate-y-1 transition-transform duration-300 shadow-sm cursor-default">
171
  <div class="w-12 h-12 rounded-2xl bg-rose-100 dark:bg-white/10 flex items-center justify-center mb-5 border border-rose-200/50 dark:border-white/10 shadow-sm"><i class="fas fa-bolt text-rose-600 dark:text-rose-300 text-xl"></i></div>
172
  <h4 class="text-sm font-black uppercase tracking-wider text-indigo-950 dark:text-purple-50 mb-2">Automated SOS</h4>
173
- <p class="text-xs text-indigo-800/70 dark:text-purple-100 leading-relaxed font-bold">HTTP Push Dispatch via ntfy.sh.</p>
174
  </div>
175
  </div>
176
  </div>
@@ -422,7 +421,11 @@
422
 
423
  themeToggleBtn.addEventListener('click', () => {
424
  htmlElement.classList.toggle('dark');
425
- localStorage.theme = htmlElement.classList.contains('dark') ? 'dark' : 'light';
 
 
 
 
426
  });
427
 
428
  window.addEventListener('load', () => {
@@ -431,7 +434,9 @@
431
  if(splash) {
432
  splash.style.opacity = '0';
433
  splash.style.transform = 'scale(1.05)';
434
- setTimeout(() => { splash.style.display = 'none'; }, 700);
 
 
435
  }
436
  }, 1800);
437
  });
@@ -447,12 +452,14 @@
447
  document.getElementById('predictiveModal').classList.remove('hidden');
448
  document.body.style.overflow = 'hidden';
449
  }
 
450
  function closePredictModal() {
451
  document.getElementById('predictiveModal').classList.add('hidden');
452
  document.body.style.overflow = '';
453
  document.getElementById('tabularForm').reset();
454
  resetPredictModal();
455
  }
 
456
  function resetPredictModal() {
457
  document.getElementById('predictiveResultView').classList.add('hidden');
458
  document.getElementById('predictiveFormView').classList.remove('hidden');
@@ -460,30 +467,41 @@
460
  }
461
 
462
  async function connectIpCam() {
463
- const url = document.getElementById('ipCamUrl').value;
464
  if(!url) return;
465
  closeIpCamModal();
466
- startSession({url: url}, '/init_stream');
 
 
 
 
 
 
 
 
 
 
467
  }
468
 
469
  document.getElementById('fileInput').addEventListener('change', async (e) => {
470
  if(!e.target.files.length) return;
471
  const fd = new FormData();
472
  fd.append('file', e.target.files[0]);
473
- startSession(fd, '/init_upload', true);
474
- });
475
-
476
- async function startSession(payload, endpoint, isFormData=false) {
477
  document.getElementById('uploadSection').classList.add('hidden');
478
  document.getElementById('results').classList.remove('hidden');
 
479
 
480
- document.getElementById('labelText').innerText = "Initializing Stream...";
 
481
 
 
482
  const opts = { method: 'POST' };
483
  if(isFormData) { opts.body = payload; }
484
  else { opts.headers = {'Content-Type': 'application/json'}; opts.body = JSON.stringify(payload); }
485
 
486
  const res = await fetch(endpoint, opts);
 
487
  const data = await res.json();
488
  streamId = data.stream_id;
489
 
@@ -505,7 +523,8 @@
505
  document.getElementById('playPauseIcon').className = 'fas fa-pause text-sm';
506
 
507
  if(poller) clearInterval(poller);
508
- poller = setInterval(update, 1000);
 
509
  }
510
 
511
  async function goTracking() {
@@ -599,6 +618,9 @@
599
  try {
600
  const res = await fetch(`/stream_status/${streamId}`);
601
  const data = await res.json();
 
 
 
602
  if(!data || Object.keys(data).length === 0) return;
603
 
604
  document.getElementById('labelText').innerText = data.label || "Monitoring...";
@@ -650,12 +672,15 @@
650
 
651
  function resetApp() {
652
  if(poller) clearInterval(poller);
653
- streamId = null;
 
654
  document.getElementById('previewImg').src = "";
655
  document.getElementById('uploadSection').classList.remove('hidden');
656
  document.getElementById('results').classList.add('hidden');
 
657
  document.getElementById('emergencyBanner').classList.add('hidden');
658
  document.getElementById('alprSection').classList.add('hidden');
 
659
  document.getElementById('progressFill').style.width = "0%";
660
  document.getElementById('playerControlsOverlay').classList.add('hidden');
661
  document.getElementById('playerControlsOverlay').classList.remove('flex');
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
  <title>CrashVision AI - Accident Detection</title>
7
 
 
8
  <meta name="apple-mobile-web-app-capable" content="yes">
9
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
10
  <meta name="apple-mobile-web-app-title" content="CrashVision">
 
169
  <div class="ios-glass p-6 rounded-[32px] hover:-translate-y-1 transition-transform duration-300 shadow-sm cursor-default">
170
  <div class="w-12 h-12 rounded-2xl bg-rose-100 dark:bg-white/10 flex items-center justify-center mb-5 border border-rose-200/50 dark:border-white/10 shadow-sm"><i class="fas fa-bolt text-rose-600 dark:text-rose-300 text-xl"></i></div>
171
  <h4 class="text-sm font-black uppercase tracking-wider text-indigo-950 dark:text-purple-50 mb-2">Automated SOS</h4>
172
+ <p class="text-xs text-indigo-800/70 dark:text-purple-100 leading-relaxed font-bold">Real-time Emergency Email Dispatch.</p>
173
  </div>
174
  </div>
175
  </div>
 
421
 
422
  themeToggleBtn.addEventListener('click', () => {
423
  htmlElement.classList.toggle('dark');
424
+ if (htmlElement.classList.contains('dark')) {
425
+ localStorage.theme = 'dark';
426
+ } else {
427
+ localStorage.theme = 'light';
428
+ }
429
  });
430
 
431
  window.addEventListener('load', () => {
 
434
  if(splash) {
435
  splash.style.opacity = '0';
436
  splash.style.transform = 'scale(1.05)';
437
+ setTimeout(() => {
438
+ splash.style.display = 'none';
439
+ }, 700);
440
  }
441
  }, 1800);
442
  });
 
452
  document.getElementById('predictiveModal').classList.remove('hidden');
453
  document.body.style.overflow = 'hidden';
454
  }
455
+
456
  function closePredictModal() {
457
  document.getElementById('predictiveModal').classList.add('hidden');
458
  document.body.style.overflow = '';
459
  document.getElementById('tabularForm').reset();
460
  resetPredictModal();
461
  }
462
+
463
  function resetPredictModal() {
464
  document.getElementById('predictiveResultView').classList.add('hidden');
465
  document.getElementById('predictiveFormView').classList.remove('hidden');
 
467
  }
468
 
469
  async function connectIpCam() {
470
+ const url = document.getElementById('ipCamUrl').value.trim();
471
  if(!url) return;
472
  closeIpCamModal();
473
+
474
+ document.getElementById('uploadSection').classList.add('hidden');
475
+ document.getElementById('results').classList.remove('hidden');
476
+ document.getElementById('labelText').innerText = "Resolving URL...";
477
+
478
+ try {
479
+ await startSession({url: url}, '/init_stream');
480
+ } catch (err) {
481
+ alert("Failed to connect to the camera. Please check the URL.");
482
+ resetApp();
483
+ }
484
  }
485
 
486
  document.getElementById('fileInput').addEventListener('change', async (e) => {
487
  if(!e.target.files.length) return;
488
  const fd = new FormData();
489
  fd.append('file', e.target.files[0]);
490
+
 
 
 
491
  document.getElementById('uploadSection').classList.add('hidden');
492
  document.getElementById('results').classList.remove('hidden');
493
+ document.getElementById('labelText').innerText = "Uploading Media...";
494
 
495
+ startSession(fd, '/init_upload', true);
496
+ });
497
 
498
+ async function startSession(payload, endpoint, isFormData=false) {
499
  const opts = { method: 'POST' };
500
  if(isFormData) { opts.body = payload; }
501
  else { opts.headers = {'Content-Type': 'application/json'}; opts.body = JSON.stringify(payload); }
502
 
503
  const res = await fetch(endpoint, opts);
504
+ if (!res.ok) throw new Error("Backend error");
505
  const data = await res.json();
506
  streamId = data.stream_id;
507
 
 
523
  document.getElementById('playPauseIcon').className = 'fas fa-pause text-sm';
524
 
525
  if(poller) clearInterval(poller);
526
+ // Polling increased to 500ms to make UI highly responsive!
527
+ poller = setInterval(update, 500);
528
  }
529
 
530
  async function goTracking() {
 
618
  try {
619
  const res = await fetch(`/stream_status/${streamId}`);
620
  const data = await res.json();
621
+
622
+ if(!streamId) return; // Prevent ghost updates if ended mid-fetch
623
+
624
  if(!data || Object.keys(data).length === 0) return;
625
 
626
  document.getElementById('labelText').innerText = data.label || "Monitoring...";
 
672
 
673
  function resetApp() {
674
  if(poller) clearInterval(poller);
675
+ streamId = null;
676
+
677
  document.getElementById('previewImg').src = "";
678
  document.getElementById('uploadSection').classList.remove('hidden');
679
  document.getElementById('results').classList.add('hidden');
680
+
681
  document.getElementById('emergencyBanner').classList.add('hidden');
682
  document.getElementById('alprSection').classList.add('hidden');
683
+
684
  document.getElementById('progressFill').style.width = "0%";
685
  document.getElementById('playerControlsOverlay').classList.add('hidden');
686
  document.getElementById('playerControlsOverlay').classList.remove('flex');