Spaces:
Sleeping
Sleeping
Update templates/index.html
Browse files- 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">
|
| 174 |
</div>
|
| 175 |
</div>
|
| 176 |
</div>
|
|
@@ -422,7 +421,11 @@
|
|
| 422 |
|
| 423 |
themeToggleBtn.addEventListener('click', () => {
|
| 424 |
htmlElement.classList.toggle('dark');
|
| 425 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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(() => {
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
| 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');
|