Spaces:
Sleeping
Sleeping
Update templates/index.html
Browse files- templates/index.html +83 -120
templates/index.html
CHANGED
|
@@ -156,7 +156,6 @@
|
|
| 156 |
<h1 class="text-4xl font-black tracking-tight text-indigo-950 dark:text-white drop-shadow-sm">CrashVision AI</h1>
|
| 157 |
<p class="text-xs font-black uppercase tracking-[0.3em] text-indigo-500 mt-3">Initializing Systems</p>
|
| 158 |
|
| 159 |
-
<!-- Loading Animation with Jiggle Physics -->
|
| 160 |
<div class="mt-8 flex gap-3">
|
| 161 |
<div class="w-3 h-3 rounded-md bg-fuchsia-500 animate-jiggle" style="animation-delay: 0s;"></div>
|
| 162 |
<div class="w-3 h-3 rounded-md bg-indigo-500 animate-jiggle" style="animation-delay: 0.15s;"></div>
|
|
@@ -317,10 +316,8 @@
|
|
| 317 |
|
| 318 |
<!-- Interactive Media Player Area -->
|
| 319 |
<div class="rounded-[32px] overflow-hidden shadow-2xl border border-white/50 dark:border-white/20 relative bg-black aspect-video flex items-center justify-center group">
|
| 320 |
-
<!-- Display Image (
|
| 321 |
-
<img id="previewImg" src="" class="w-full h-full object-contain z-10 hidden" alt="
|
| 322 |
-
<!-- Raw Video Feed Image -->
|
| 323 |
-
<img id="rawFeedImg" src="" class="w-full h-full object-contain z-10 hidden" alt="Raw View">
|
| 324 |
|
| 325 |
<!-- Snapshot Container Overlay -->
|
| 326 |
<div id="snapshotContainer" class="absolute inset-0 z-30 hidden bg-black flex items-center justify-center">
|
|
@@ -367,17 +364,17 @@
|
|
| 367 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 368 |
<i class="fas fa-location-dot text-rose-500 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 369 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Location</p>
|
| 370 |
-
<p id="vLoc" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center px-1 break-words"></p>
|
| 371 |
</div>
|
| 372 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 373 |
<i class="fas fa-cloud-bolt text-cyan-500 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 374 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Conditions</p>
|
| 375 |
-
<p id="vWx" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center break-words"></p>
|
| 376 |
</div>
|
| 377 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 378 |
<i class="fas fa-stopwatch text-indigo-500 dark:text-purple-300 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 379 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Timeline</p>
|
| 380 |
-
<p id="vTime" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center break-words"></p>
|
| 381 |
</div>
|
| 382 |
</div>
|
| 383 |
</div>
|
|
@@ -584,7 +581,7 @@
|
|
| 584 |
</div>
|
| 585 |
<div>
|
| 586 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Speed Limit</label>
|
| 587 |
-
<input type="number" id="tab_speed"
|
| 588 |
</div>
|
| 589 |
</div>
|
| 590 |
</div>
|
|
@@ -600,11 +597,11 @@
|
|
| 600 |
<div class="space-y-4">
|
| 601 |
<div>
|
| 602 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Density (0-5)</label>
|
| 603 |
-
<input type="number" id="tab_density"
|
| 604 |
</div>
|
| 605 |
<div>
|
| 606 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Vehicles Inv.</label>
|
| 607 |
-
<input type="number" id="tab_vehicles"
|
| 608 |
</div>
|
| 609 |
<div>
|
| 610 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Vehicle Type</label>
|
|
@@ -629,15 +626,18 @@
|
|
| 629 |
<div class="space-y-4">
|
| 630 |
<div>
|
| 631 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Driver Age</label>
|
| 632 |
-
<input type="number" id="tab_age"
|
| 633 |
</div>
|
| 634 |
<div>
|
| 635 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Experience (Yrs)</label>
|
| 636 |
-
<input type="number" id="tab_exp"
|
| 637 |
</div>
|
| 638 |
<div>
|
| 639 |
-
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">
|
| 640 |
-
<
|
|
|
|
|
|
|
|
|
|
| 641 |
</div>
|
| 642 |
</div>
|
| 643 |
</div>
|
|
@@ -665,8 +665,8 @@
|
|
| 665 |
<span id="riskLabelText">Low Risk</span>
|
| 666 |
</div>
|
| 667 |
|
| 668 |
-
<h4 class="text-
|
| 669 |
-
<p class="text-indigo-800/60 dark:text-purple-200 text-[10px] font-black uppercase tracking-widest mt-4">
|
| 670 |
</div>
|
| 671 |
|
| 672 |
<div class="flex gap-4 max-w-sm w-full mt-4">
|
|
@@ -689,7 +689,6 @@
|
|
| 689 |
const themeToggleBtn = document.getElementById('themeToggle');
|
| 690 |
const htmlElement = document.documentElement;
|
| 691 |
|
| 692 |
-
// Force light mode by default on first visit. Only switch if explicitly saved.
|
| 693 |
if (localStorage.theme === 'dark') {
|
| 694 |
htmlElement.classList.add('dark');
|
| 695 |
} else {
|
|
@@ -706,7 +705,6 @@
|
|
| 706 |
}
|
| 707 |
});
|
| 708 |
|
| 709 |
-
// App Splash Screen Removal Logic
|
| 710 |
window.addEventListener('load', () => {
|
| 711 |
setTimeout(() => {
|
| 712 |
const splash = document.getElementById('appSplashScreen');
|
|
@@ -720,43 +718,6 @@
|
|
| 720 |
}, 1800);
|
| 721 |
});
|
| 722 |
|
| 723 |
-
let currentLocationStr = "Unknown Location";
|
| 724 |
-
|
| 725 |
-
async function fetchRealLocationData() {
|
| 726 |
-
if ("geolocation" in navigator) {
|
| 727 |
-
navigator.geolocation.getCurrentPosition(async (position) => {
|
| 728 |
-
const lat = position.coords.latitude;
|
| 729 |
-
const lon = position.coords.longitude;
|
| 730 |
-
|
| 731 |
-
try {
|
| 732 |
-
const geoRes = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`);
|
| 733 |
-
const geoData = await geoRes.json();
|
| 734 |
-
const city = geoData.address.city || geoData.address.town || geoData.address.village || geoData.address.county || "Unknown Region";
|
| 735 |
-
currentLocationStr = `${city}, ${geoData.address.country_code.toUpperCase()}`;
|
| 736 |
-
if(document.getElementById('vLoc')) document.getElementById('vLoc').innerText = currentLocationStr;
|
| 737 |
-
} catch(e) {
|
| 738 |
-
if(document.getElementById('vLoc')) document.getElementById('vLoc').innerText = "Location API Error";
|
| 739 |
-
}
|
| 740 |
-
|
| 741 |
-
try {
|
| 742 |
-
const wxRes = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t_weather=true`);
|
| 743 |
-
const wxData = await wxRes.json();
|
| 744 |
-
const temp = wxData.current_weather.temperature;
|
| 745 |
-
if(document.getElementById('vWx')) document.getElementById('vWx').innerText = `${temp}°C, Active`;
|
| 746 |
-
} catch(e) {
|
| 747 |
-
if(document.getElementById('vWx')) document.getElementById('vWx').innerText = "--";
|
| 748 |
-
}
|
| 749 |
-
}, (error) => {
|
| 750 |
-
if(document.getElementById('vLoc')) document.getElementById('vLoc').innerText = "Location Denied";
|
| 751 |
-
if(document.getElementById('vWx')) document.getElementById('vWx').innerText = "--";
|
| 752 |
-
});
|
| 753 |
-
} else {
|
| 754 |
-
if(document.getElementById('vLoc')) document.getElementById('vLoc').innerText = "Not Supported";
|
| 755 |
-
}
|
| 756 |
-
const now = new Date();
|
| 757 |
-
if(document.getElementById('vTime')) document.getElementById('vTime').innerText = now.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'});
|
| 758 |
-
}
|
| 759 |
-
|
| 760 |
let streamId = null;
|
| 761 |
let poller = null;
|
| 762 |
|
|
@@ -770,6 +731,8 @@
|
|
| 770 |
function closePredictModal() {
|
| 771 |
document.getElementById('predictiveModal').classList.add('hidden');
|
| 772 |
document.body.style.overflow = '';
|
|
|
|
|
|
|
| 773 |
}
|
| 774 |
function resetPredictModal() {
|
| 775 |
document.getElementById('predictiveResultView').classList.add('hidden');
|
|
@@ -780,7 +743,7 @@
|
|
| 780 |
const url = document.getElementById('ipCamUrl').value;
|
| 781 |
if(!url) return;
|
| 782 |
closeIpCamModal();
|
| 783 |
-
startSession({url: url
|
| 784 |
}
|
| 785 |
|
| 786 |
document.getElementById('fileInput').addEventListener('change', async (e) => {
|
|
@@ -804,58 +767,48 @@
|
|
| 804 |
const data = await res.json();
|
| 805 |
streamId = data.stream_id;
|
| 806 |
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
}
|
| 812 |
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
|
| 819 |
-
|
| 820 |
-
document.getElementById('previewImg').src = `/video_feed/${streamId}?loc=${encodeURIComponent(locText)}&t=${Date.now()}`;
|
| 821 |
-
document.getElementById('rawFeedImg').src = `/raw_feed/${streamId}?loc=${encodeURIComponent(locText)}&t=${Date.now()}`;
|
| 822 |
|
| 823 |
if(poller) clearInterval(poller);
|
| 824 |
poller = setInterval(update, 1000);
|
| 825 |
}
|
| 826 |
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
document.getElementById('
|
| 830 |
-
document.getElementById('
|
| 831 |
-
document.getElementById('liveBadgeContainer').classList.remove('hidden');
|
| 832 |
-
|
| 833 |
document.getElementById('liveBadge').innerHTML = '<span class="w-2 h-2 rounded-full bg-red-500 animate-pulse shadow-[0_0_8px_red]"></span> LIVE AI FEED';
|
| 834 |
-
|
| 835 |
-
|
|
|
|
|
|
|
|
|
|
| 836 |
}
|
| 837 |
-
|
| 838 |
-
function goTracking() { activateTrackingUI(); }
|
| 839 |
|
| 840 |
-
function goOriginal() {
|
| 841 |
-
document.getElementById('
|
| 842 |
-
document.getElementById('
|
| 843 |
-
document.getElementById('snapshotContainer').classList.add('hidden');
|
| 844 |
-
document.getElementById('liveBadgeContainer').classList.remove('hidden');
|
| 845 |
-
|
| 846 |
document.getElementById('liveBadge').innerHTML = '<span class="w-2 h-2 rounded-full bg-blue-500 shadow-[0_0_8px_blue]"></span> RAW FEED';
|
| 847 |
-
|
| 848 |
-
|
|
|
|
|
|
|
|
|
|
| 849 |
}
|
| 850 |
|
| 851 |
function takeSnapshot() {
|
| 852 |
-
|
| 853 |
-
if(!document.getElementById('previewImg').classList.contains('hidden')) {
|
| 854 |
-
feed = document.getElementById('previewImg');
|
| 855 |
-
} else if (!document.getElementById('rawFeedImg').classList.contains('hidden')) {
|
| 856 |
-
feed = document.getElementById('rawFeedImg');
|
| 857 |
-
}
|
| 858 |
-
|
| 859 |
if(feed && feed.src) {
|
| 860 |
const c = document.createElement('canvas');
|
| 861 |
c.width = feed.naturalWidth || feed.width || 640;
|
|
@@ -863,20 +816,16 @@
|
|
| 863 |
c.getContext('2d').drawImage(feed, 0, 0, c.width, c.height);
|
| 864 |
|
| 865 |
document.getElementById('snapshotImg').src = c.toDataURL('image/jpeg');
|
| 866 |
-
|
| 867 |
document.getElementById('snapshotContainer').classList.remove('hidden');
|
| 868 |
document.getElementById('previewImg').classList.add('hidden');
|
| 869 |
-
document.getElementById('rawFeedImg').classList.add('hidden');
|
| 870 |
document.getElementById('liveBadgeContainer').classList.add('hidden');
|
| 871 |
}
|
| 872 |
}
|
| 873 |
|
| 874 |
function closeSnapshot() {
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
goOriginal();
|
| 879 |
-
}
|
| 880 |
}
|
| 881 |
|
| 882 |
function fullscreenSnapshot() {
|
|
@@ -906,17 +855,15 @@
|
|
| 906 |
const statusIcon = document.getElementById('statusIcon');
|
| 907 |
const emergencyBanner = document.getElementById('emergencyBanner');
|
| 908 |
|
| 909 |
-
if(data.is_accident) {
|
| 910 |
-
statusCard.
|
| 911 |
-
statusCard.classList.add('border-rose-500', 'bg-rose-50/50', 'dark:bg-rose-900/20');
|
| 912 |
statusIcon.className = "fas fa-exclamation-triangle text-rose-600";
|
| 913 |
|
| 914 |
if(data.severity && (data.severity.toLowerCase() === 'major' || data.severity.toLowerCase() === 'moderate')) {
|
| 915 |
emergencyBanner.classList.remove('hidden');
|
| 916 |
}
|
| 917 |
} else {
|
| 918 |
-
statusCard.
|
| 919 |
-
statusCard.classList.remove('border-rose-500', 'bg-rose-50/50', 'dark:bg-rose-900/20');
|
| 920 |
statusIcon.className = "fas fa-shield-check text-indigo-600";
|
| 921 |
emergencyBanner.classList.add('hidden');
|
| 922 |
}
|
|
@@ -935,15 +882,31 @@
|
|
| 935 |
} catch(e) {}
|
| 936 |
}
|
| 937 |
|
|
|
|
| 938 |
function resetApp() {
|
| 939 |
if(poller) clearInterval(poller);
|
| 940 |
streamId = null;
|
| 941 |
document.getElementById('previewImg').src = "";
|
| 942 |
-
document.getElementById('rawFeedImg').src = "";
|
| 943 |
document.getElementById('uploadSection').classList.remove('hidden');
|
| 944 |
document.getElementById('results').classList.add('hidden');
|
| 945 |
document.getElementById('emergencyBanner').classList.add('hidden');
|
|
|
|
|
|
|
|
|
|
| 946 |
document.getElementById('fileInput').value = "";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 947 |
}
|
| 948 |
|
| 949 |
async function submitPredictiveData(e) {
|
|
@@ -965,7 +928,8 @@
|
|
| 965 |
Vehicle_Type: document.getElementById('tab_vehicle').value,
|
| 966 |
Driver_Age: document.getElementById('tab_age').value,
|
| 967 |
Driver_Experience: document.getElementById('tab_exp').value,
|
| 968 |
-
|
|
|
|
| 969 |
};
|
| 970 |
|
| 971 |
try {
|
|
@@ -979,32 +943,34 @@
|
|
| 979 |
document.getElementById('predictiveFormView').classList.add('hidden');
|
| 980 |
document.getElementById('predictiveResultView').classList.remove('hidden');
|
| 981 |
|
| 982 |
-
const prob = data.risk_probability_percentage || 0;
|
| 983 |
-
document.getElementById('riskProbabilityValue').innerText = prob;
|
| 984 |
-
|
| 985 |
const riskCard = document.getElementById('riskStatusCard');
|
| 986 |
const riskBadge = document.getElementById('riskBadge');
|
| 987 |
const riskIcon = document.getElementById('riskIcon');
|
| 988 |
const riskLabel = document.getElementById('riskLabelText');
|
|
|
|
| 989 |
|
| 990 |
riskCard.className = 'ios-glass-inner p-10 rounded-[32px] shadow-sm dark:shadow-lg relative overflow-hidden w-full max-w-sm border';
|
| 991 |
riskBadge.className = 'inline-flex items-center gap-2 px-5 py-2.5 rounded-xl text-xs font-black mb-6 uppercase tracking-[0.2em] border shadow-sm text-white';
|
| 992 |
|
| 993 |
-
|
|
|
|
| 994 |
riskCard.classList.add('border-red-500', 'bg-red-50/10', 'dark:bg-red-900/20');
|
| 995 |
riskBadge.classList.add('bg-red-500', 'border-red-400');
|
| 996 |
riskIcon.className = 'fas fa-exclamation-triangle';
|
| 997 |
-
riskLabel.innerText = '
|
| 998 |
-
|
|
|
|
| 999 |
riskCard.classList.add('border-amber-500', 'bg-amber-50/10', 'dark:bg-amber-900/20');
|
| 1000 |
riskBadge.classList.add('bg-amber-500', 'border-amber-400');
|
| 1001 |
riskIcon.className = 'fas fa-exclamation-circle';
|
| 1002 |
-
riskLabel.innerText = 'Elevated
|
|
|
|
| 1003 |
} else {
|
| 1004 |
riskCard.classList.add('border-green-500', 'bg-green-50/10', 'dark:bg-green-900/20');
|
| 1005 |
riskBadge.classList.add('bg-green-500', 'border-green-400');
|
| 1006 |
riskIcon.className = 'fas fa-shield-check';
|
| 1007 |
-
riskLabel.innerText = '
|
|
|
|
| 1008 |
}
|
| 1009 |
|
| 1010 |
} catch (e) {
|
|
@@ -1014,9 +980,6 @@
|
|
| 1014 |
spinner.classList.add('hidden');
|
| 1015 |
}
|
| 1016 |
}
|
| 1017 |
-
|
| 1018 |
-
// Setup script initialization call
|
| 1019 |
-
fetchRealLocationData();
|
| 1020 |
</script>
|
| 1021 |
</body>
|
| 1022 |
</html>
|
|
|
|
| 156 |
<h1 class="text-4xl font-black tracking-tight text-indigo-950 dark:text-white drop-shadow-sm">CrashVision AI</h1>
|
| 157 |
<p class="text-xs font-black uppercase tracking-[0.3em] text-indigo-500 mt-3">Initializing Systems</p>
|
| 158 |
|
|
|
|
| 159 |
<div class="mt-8 flex gap-3">
|
| 160 |
<div class="w-3 h-3 rounded-md bg-fuchsia-500 animate-jiggle" style="animation-delay: 0s;"></div>
|
| 161 |
<div class="w-3 h-3 rounded-md bg-indigo-500 animate-jiggle" style="animation-delay: 0.15s;"></div>
|
|
|
|
| 316 |
|
| 317 |
<!-- Interactive Media Player Area -->
|
| 318 |
<div class="rounded-[32px] overflow-hidden shadow-2xl border border-white/50 dark:border-white/20 relative bg-black aspect-video flex items-center justify-center group">
|
| 319 |
+
<!-- Display Image (Single video feed element) -->
|
| 320 |
+
<img id="previewImg" src="" class="w-full h-full object-contain z-10 hidden" alt="Video View">
|
|
|
|
|
|
|
| 321 |
|
| 322 |
<!-- Snapshot Container Overlay -->
|
| 323 |
<div id="snapshotContainer" class="absolute inset-0 z-30 hidden bg-black flex items-center justify-center">
|
|
|
|
| 364 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 365 |
<i class="fas fa-location-dot text-rose-500 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 366 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Location</p>
|
| 367 |
+
<p id="vLoc" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center px-1 break-words">--</p>
|
| 368 |
</div>
|
| 369 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 370 |
<i class="fas fa-cloud-bolt text-cyan-500 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 371 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Conditions</p>
|
| 372 |
+
<p id="vWx" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center break-words">--</p>
|
| 373 |
</div>
|
| 374 |
<div class="ios-glass-inner p-3 sm:p-5 rounded-2xl sm:rounded-3xl flex flex-col items-center text-center gap-1 hover:bg-white/60 dark:hover:bg-white/10 transition-colors">
|
| 375 |
<i class="fas fa-stopwatch text-indigo-500 dark:text-purple-300 text-lg sm:text-xl mb-1 sm:mb-2"></i>
|
| 376 |
<p class="text-[8px] sm:text-[9px] uppercase tracking-widest text-indigo-800/50 dark:text-purple-200 font-black">Timeline</p>
|
| 377 |
+
<p id="vTime" class="text-[10px] sm:text-xs font-black text-indigo-950 dark:text-white w-full tracking-tight leading-tight text-center break-words">--</p>
|
| 378 |
</div>
|
| 379 |
</div>
|
| 380 |
</div>
|
|
|
|
| 581 |
</div>
|
| 582 |
<div>
|
| 583 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Speed Limit</label>
|
| 584 |
+
<input type="number" id="tab_speed" placeholder="e.g. 60" min="10" max="250" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-rose-500 focus:ring-2 focus:ring-rose-500/20 shadow-sm">
|
| 585 |
</div>
|
| 586 |
</div>
|
| 587 |
</div>
|
|
|
|
| 597 |
<div class="space-y-4">
|
| 598 |
<div>
|
| 599 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Density (0-5)</label>
|
| 600 |
+
<input type="number" id="tab_density" placeholder="e.g. 2" min="0" max="5" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-amber-500 focus:ring-2 focus:ring-amber-500/20 shadow-sm">
|
| 601 |
</div>
|
| 602 |
<div>
|
| 603 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Vehicles Inv.</label>
|
| 604 |
+
<input type="number" id="tab_vehicles" placeholder="e.g. 2" min="1" max="20" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-amber-500 focus:ring-2 focus:ring-amber-500/20 shadow-sm">
|
| 605 |
</div>
|
| 606 |
<div>
|
| 607 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Vehicle Type</label>
|
|
|
|
| 626 |
<div class="space-y-4">
|
| 627 |
<div>
|
| 628 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Driver Age</label>
|
| 629 |
+
<input type="number" id="tab_age" placeholder="e.g. 35" min="16" max="99" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/20 shadow-sm">
|
| 630 |
</div>
|
| 631 |
<div>
|
| 632 |
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Experience (Yrs)</label>
|
| 633 |
+
<input type="number" id="tab_exp" placeholder="e.g. 5" min="0" max="80" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/20 shadow-sm">
|
| 634 |
</div>
|
| 635 |
<div>
|
| 636 |
+
<label class="block text-[10px] font-black uppercase tracking-widest text-indigo-900/70 dark:text-purple-200/70 mb-1.5 ml-1">Drunk</label>
|
| 637 |
+
<select id="tab_alcohol" class="predict-input bg-white/60 dark:bg-black/20 focus:bg-white dark:focus:bg-black/40 border border-indigo-200/60 dark:border-white/10 text-indigo-950 dark:text-white focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/20 shadow-sm cursor-pointer">
|
| 638 |
+
<option value="No">No</option>
|
| 639 |
+
<option value="Yes">Yes</option>
|
| 640 |
+
</select>
|
| 641 |
</div>
|
| 642 |
</div>
|
| 643 |
</div>
|
|
|
|
| 665 |
<span id="riskLabelText">Low Risk</span>
|
| 666 |
</div>
|
| 667 |
|
| 668 |
+
<h4 class="text-6xl font-black tracking-tighter text-indigo-950 dark:text-white mb-2 drop-shadow-sm" id="riskLevelResult">--</h4>
|
| 669 |
+
<p class="text-indigo-800/60 dark:text-purple-200 text-[10px] font-black uppercase tracking-widest mt-4">Predicted Accident Severity</p>
|
| 670 |
</div>
|
| 671 |
|
| 672 |
<div class="flex gap-4 max-w-sm w-full mt-4">
|
|
|
|
| 689 |
const themeToggleBtn = document.getElementById('themeToggle');
|
| 690 |
const htmlElement = document.documentElement;
|
| 691 |
|
|
|
|
| 692 |
if (localStorage.theme === 'dark') {
|
| 693 |
htmlElement.classList.add('dark');
|
| 694 |
} else {
|
|
|
|
| 705 |
}
|
| 706 |
});
|
| 707 |
|
|
|
|
| 708 |
window.addEventListener('load', () => {
|
| 709 |
setTimeout(() => {
|
| 710 |
const splash = document.getElementById('appSplashScreen');
|
|
|
|
| 718 |
}, 1800);
|
| 719 |
});
|
| 720 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 721 |
let streamId = null;
|
| 722 |
let poller = null;
|
| 723 |
|
|
|
|
| 731 |
function closePredictModal() {
|
| 732 |
document.getElementById('predictiveModal').classList.add('hidden');
|
| 733 |
document.body.style.overflow = '';
|
| 734 |
+
document.getElementById('tabularForm').reset(); // Wipe Predictor Form Data
|
| 735 |
+
resetPredictModal(); // Push back to form view
|
| 736 |
}
|
| 737 |
function resetPredictModal() {
|
| 738 |
document.getElementById('predictiveResultView').classList.add('hidden');
|
|
|
|
| 743 |
const url = document.getElementById('ipCamUrl').value;
|
| 744 |
if(!url) return;
|
| 745 |
closeIpCamModal();
|
| 746 |
+
startSession({url: url}, '/init_stream');
|
| 747 |
}
|
| 748 |
|
| 749 |
document.getElementById('fileInput').addEventListener('change', async (e) => {
|
|
|
|
| 767 |
const data = await res.json();
|
| 768 |
streamId = data.stream_id;
|
| 769 |
|
| 770 |
+
// Set metadata without browser fallback
|
| 771 |
+
if(document.getElementById('vLoc')) document.getElementById('vLoc').innerText = data.location || "--";
|
| 772 |
+
if(document.getElementById('vWx')) document.getElementById('vWx').innerText = data.weather || "--";
|
| 773 |
+
if(document.getElementById('vTime')) document.getElementById('vTime').innerText = data.time || "--";
|
|
|
|
| 774 |
|
| 775 |
+
// Instantly start UI logic
|
| 776 |
+
document.getElementById('previewImg').classList.remove('hidden');
|
| 777 |
+
document.getElementById('tBtn').classList.add('opacity-50');
|
| 778 |
+
document.getElementById('oBtn').classList.remove('opacity-50');
|
| 779 |
+
document.getElementById('liveBadge').innerHTML = '<span class="w-2 h-2 rounded-full bg-red-500 animate-pulse shadow-[0_0_8px_red]"></span> LIVE AI FEED';
|
| 780 |
|
| 781 |
+
document.getElementById('previewImg').src = `/video_feed/${streamId}?loc=${encodeURIComponent(data.location)}&t=${Date.now()}`;
|
|
|
|
|
|
|
| 782 |
|
| 783 |
if(poller) clearInterval(poller);
|
| 784 |
poller = setInterval(update, 1000);
|
| 785 |
}
|
| 786 |
|
| 787 |
+
// Toggles AI boxes dynamically on backend via API request
|
| 788 |
+
async function goTracking() {
|
| 789 |
+
document.getElementById('tBtn').classList.add('opacity-50');
|
| 790 |
+
document.getElementById('oBtn').classList.remove('opacity-50');
|
|
|
|
|
|
|
| 791 |
document.getElementById('liveBadge').innerHTML = '<span class="w-2 h-2 rounded-full bg-red-500 animate-pulse shadow-[0_0_8px_red]"></span> LIVE AI FEED';
|
| 792 |
+
await fetch(`/toggle_tracking/${streamId}`, {
|
| 793 |
+
method: 'POST',
|
| 794 |
+
headers: {'Content-Type': 'application/json'},
|
| 795 |
+
body: JSON.stringify({track: true})
|
| 796 |
+
});
|
| 797 |
}
|
|
|
|
|
|
|
| 798 |
|
| 799 |
+
async function goOriginal() {
|
| 800 |
+
document.getElementById('oBtn').classList.add('opacity-50');
|
| 801 |
+
document.getElementById('tBtn').classList.remove('opacity-50');
|
|
|
|
|
|
|
|
|
|
| 802 |
document.getElementById('liveBadge').innerHTML = '<span class="w-2 h-2 rounded-full bg-blue-500 shadow-[0_0_8px_blue]"></span> RAW FEED';
|
| 803 |
+
await fetch(`/toggle_tracking/${streamId}`, {
|
| 804 |
+
method: 'POST',
|
| 805 |
+
headers: {'Content-Type': 'application/json'},
|
| 806 |
+
body: JSON.stringify({track: false})
|
| 807 |
+
});
|
| 808 |
}
|
| 809 |
|
| 810 |
function takeSnapshot() {
|
| 811 |
+
const feed = document.getElementById('previewImg');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 812 |
if(feed && feed.src) {
|
| 813 |
const c = document.createElement('canvas');
|
| 814 |
c.width = feed.naturalWidth || feed.width || 640;
|
|
|
|
| 816 |
c.getContext('2d').drawImage(feed, 0, 0, c.width, c.height);
|
| 817 |
|
| 818 |
document.getElementById('snapshotImg').src = c.toDataURL('image/jpeg');
|
|
|
|
| 819 |
document.getElementById('snapshotContainer').classList.remove('hidden');
|
| 820 |
document.getElementById('previewImg').classList.add('hidden');
|
|
|
|
| 821 |
document.getElementById('liveBadgeContainer').classList.add('hidden');
|
| 822 |
}
|
| 823 |
}
|
| 824 |
|
| 825 |
function closeSnapshot() {
|
| 826 |
+
document.getElementById('snapshotContainer').classList.add('hidden');
|
| 827 |
+
document.getElementById('previewImg').classList.remove('hidden');
|
| 828 |
+
document.getElementById('liveBadgeContainer').classList.remove('hidden');
|
|
|
|
|
|
|
| 829 |
}
|
| 830 |
|
| 831 |
function fullscreenSnapshot() {
|
|
|
|
| 855 |
const statusIcon = document.getElementById('statusIcon');
|
| 856 |
const emergencyBanner = document.getElementById('emergencyBanner');
|
| 857 |
|
| 858 |
+
if(data.is_accident || data.final_decision) {
|
| 859 |
+
statusCard.className = "ios-glass-inner p-8 rounded-[32px] mb-8 shadow-sm dark:shadow-lg relative overflow-hidden border-l-4 border-rose-500 bg-rose-50/50 dark:bg-rose-900/20 transition-colors duration-500";
|
|
|
|
| 860 |
statusIcon.className = "fas fa-exclamation-triangle text-rose-600";
|
| 861 |
|
| 862 |
if(data.severity && (data.severity.toLowerCase() === 'major' || data.severity.toLowerCase() === 'moderate')) {
|
| 863 |
emergencyBanner.classList.remove('hidden');
|
| 864 |
}
|
| 865 |
} else {
|
| 866 |
+
statusCard.className = "ios-glass-inner p-8 rounded-[32px] mb-8 shadow-sm dark:shadow-lg relative overflow-hidden border-l-4 border-indigo-500 transition-colors duration-500";
|
|
|
|
| 867 |
statusIcon.className = "fas fa-shield-check text-indigo-600";
|
| 868 |
emergencyBanner.classList.add('hidden');
|
| 869 |
}
|
|
|
|
| 882 |
} catch(e) {}
|
| 883 |
}
|
| 884 |
|
| 885 |
+
// Entire UI is reset completely when leaving
|
| 886 |
function resetApp() {
|
| 887 |
if(poller) clearInterval(poller);
|
| 888 |
streamId = null;
|
| 889 |
document.getElementById('previewImg').src = "";
|
|
|
|
| 890 |
document.getElementById('uploadSection').classList.remove('hidden');
|
| 891 |
document.getElementById('results').classList.add('hidden');
|
| 892 |
document.getElementById('emergencyBanner').classList.add('hidden');
|
| 893 |
+
document.getElementById('alprSection').classList.add('hidden');
|
| 894 |
+
|
| 895 |
+
// Wipe Form and Upload fields completely
|
| 896 |
document.getElementById('fileInput').value = "";
|
| 897 |
+
document.getElementById('uploadForm').reset();
|
| 898 |
+
document.getElementById('ipCamUrl').value = "";
|
| 899 |
+
|
| 900 |
+
// Reset Diagnostics View Default State
|
| 901 |
+
document.getElementById('confVal').innerText = "0";
|
| 902 |
+
document.getElementById('severityLevel').innerText = "--";
|
| 903 |
+
document.getElementById('cnnBar').style.width = "0%";
|
| 904 |
+
document.getElementById('rcnnBar').style.width = "0%";
|
| 905 |
+
document.getElementById('cnnVal').innerText = "0%";
|
| 906 |
+
document.getElementById('rcnnVal').innerText = "0%";
|
| 907 |
+
document.getElementById('labelText').innerText = "Scanning Stream...";
|
| 908 |
+
document.getElementById('statusCard').className = "ios-glass-inner p-8 rounded-[32px] mb-8 shadow-sm dark:shadow-lg relative overflow-hidden border-l-4 border-indigo-500 transition-colors duration-500";
|
| 909 |
+
document.getElementById('statusIcon').className = "fas fa-spinner fa-spin text-indigo-600";
|
| 910 |
}
|
| 911 |
|
| 912 |
async function submitPredictiveData(e) {
|
|
|
|
| 928 |
Vehicle_Type: document.getElementById('tab_vehicle').value,
|
| 929 |
Driver_Age: document.getElementById('tab_age').value,
|
| 930 |
Driver_Experience: document.getElementById('tab_exp').value,
|
| 931 |
+
// Yes=1.0, No=0.0 mapped strictly here for the AI
|
| 932 |
+
Driver_Alcohol: document.getElementById('tab_alcohol').value === "Yes" ? 1.0 : 0.0
|
| 933 |
};
|
| 934 |
|
| 935 |
try {
|
|
|
|
| 943 |
document.getElementById('predictiveFormView').classList.add('hidden');
|
| 944 |
document.getElementById('predictiveResultView').classList.remove('hidden');
|
| 945 |
|
|
|
|
|
|
|
|
|
|
| 946 |
const riskCard = document.getElementById('riskStatusCard');
|
| 947 |
const riskBadge = document.getElementById('riskBadge');
|
| 948 |
const riskIcon = document.getElementById('riskIcon');
|
| 949 |
const riskLabel = document.getElementById('riskLabelText');
|
| 950 |
+
const riskText = document.getElementById('riskLevelResult');
|
| 951 |
|
| 952 |
riskCard.className = 'ios-glass-inner p-10 rounded-[32px] shadow-sm dark:shadow-lg relative overflow-hidden w-full max-w-sm border';
|
| 953 |
riskBadge.className = 'inline-flex items-center gap-2 px-5 py-2.5 rounded-xl text-xs font-black mb-6 uppercase tracking-[0.2em] border shadow-sm text-white';
|
| 954 |
|
| 955 |
+
// Displaying labels directly instead of percentages
|
| 956 |
+
if(data.status === "Major") {
|
| 957 |
riskCard.classList.add('border-red-500', 'bg-red-50/10', 'dark:bg-red-900/20');
|
| 958 |
riskBadge.classList.add('bg-red-500', 'border-red-400');
|
| 959 |
riskIcon.className = 'fas fa-exclamation-triangle';
|
| 960 |
+
riskLabel.innerText = 'High Alert';
|
| 961 |
+
riskText.innerText = 'Major';
|
| 962 |
+
} else if(data.status === "Moderate") {
|
| 963 |
riskCard.classList.add('border-amber-500', 'bg-amber-50/10', 'dark:bg-amber-900/20');
|
| 964 |
riskBadge.classList.add('bg-amber-500', 'border-amber-400');
|
| 965 |
riskIcon.className = 'fas fa-exclamation-circle';
|
| 966 |
+
riskLabel.innerText = 'Elevated Alert';
|
| 967 |
+
riskText.innerText = 'Moderate';
|
| 968 |
} else {
|
| 969 |
riskCard.classList.add('border-green-500', 'bg-green-50/10', 'dark:bg-green-900/20');
|
| 970 |
riskBadge.classList.add('bg-green-500', 'border-green-400');
|
| 971 |
riskIcon.className = 'fas fa-shield-check';
|
| 972 |
+
riskLabel.innerText = 'Safe Zone';
|
| 973 |
+
riskText.innerText = 'Minor';
|
| 974 |
}
|
| 975 |
|
| 976 |
} catch (e) {
|
|
|
|
| 980 |
spinner.classList.add('hidden');
|
| 981 |
}
|
| 982 |
}
|
|
|
|
|
|
|
|
|
|
| 983 |
</script>
|
| 984 |
</body>
|
| 985 |
</html>
|