themehmi's picture
Upload 9 files
c3383a4 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DriveSafe — AI Safety HUD & Conversational SLM</title>
<!-- Google Fonts for High-Tech Dashboard Aesthetic -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<!-- Chart.js for High-Performance EKG Graph -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--bg-color: #08090e;
--panel-bg: rgba(15, 18, 28, 0.7);
--border-glow: rgba(0, 255, 128, 0.15);
--safe-color: #00ff80;
--warn-color: #ffaa00;
--danger-color: #ff2850;
--accent-color: #00bfff;
--text-color: #e2e8f0;
--text-muted: #64748b;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Outfit', sans-serif;
-webkit-font-smoothing: antialiased;
}
body {
background-color: var(--bg-color);
background-image:
radial-gradient(at 0% 0%, rgba(0, 191, 255, 0.05) 0px, transparent 50%),
radial-gradient(at 100% 0%, rgba(0, 255, 128, 0.05) 0px, transparent 50%),
radial-gradient(at 50% 100%, rgba(255, 40, 80, 0.03) 0px, transparent 50%);
color: var(--text-color);
min-height: 100vh;
overflow-x: hidden;
display: flex;
flex-direction: column;
}
/* --- Header --- */
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px;
background: rgba(8, 9, 14, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
position: sticky;
top: 0;
z-index: 100;
}
.logo-section {
display: flex;
align-items: center;
gap: 15px;
}
.logo-section h1 {
font-size: 24px;
font-weight: 800;
letter-spacing: 2px;
background: linear-gradient(to right, #00ff80, #00bfff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.logo-section span {
font-family: 'Share Tech Mono', monospace;
font-size: 11px;
background: rgba(0, 191, 255, 0.1);
color: var(--accent-color);
padding: 2px 8px;
border: 1px solid rgba(0, 191, 255, 0.2);
border-radius: 4px;
}
.connection-status {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 600;
color: var(--safe-color);
}
.pulse-dot {
width: 8px;
height: 8px;
background-color: var(--safe-color);
border-radius: 50%;
box-shadow: 0 0 10px var(--safe-color);
animation: pulse 1.5s infinite;
}
/* --- Main Dashboard Container --- */
.dashboard-container {
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 30px;
padding: 30px 40px;
flex-grow: 1;
max-width: 1800px;
margin: 0 auto;
width: 100%;
}
.glass-panel {
background: var(--panel-bg);
backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 24px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
overflow: hidden;
}
.glass-panel::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, transparent, var(--border-glow), transparent);
transition: all 0.4s ease;
}
/* --- LEFT COLUMN: CAMERA & VISUAL HUD --- */
.left-column {
display: flex;
flex-direction: column;
gap: 30px;
}
.video-panel {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.video-container {
width: 100%;
aspect-ratio: 4/3;
background-color: #050608;
border-radius: 12px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.08);
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.video-stream {
width: 100%;
height: 100%;
object-fit: cover;
}
.video-placeholder {
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
color: var(--text-muted);
text-align: center;
}
.video-placeholder svg {
width: 60px;
height: 60px;
stroke: var(--text-muted);
animation: rotate-sync 4s linear infinite;
}
.hud-overlay-badge {
position: absolute;
top: 15px;
right: 15px;
background: rgba(0, 0, 0, 0.7);
border: 1px solid var(--safe-color);
padding: 4px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 600;
color: var(--safe-color);
text-transform: uppercase;
letter-spacing: 1px;
box-shadow: 0 0 10px rgba(0, 255, 128, 0.2);
transition: all 0.3s ease;
}
/* --- Indicators Panel --- */
.indicators-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.metric-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.04);
border-radius: 14px;
padding: 18px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
}
.metric-title {
font-size: 12px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 8px;
}
.metric-value {
font-size: 32px;
font-weight: 800;
font-family: 'Share Tech Mono', monospace;
}
/* Gauge Meter styling */
.gauge-container {
width: 100px;
height: 100px;
position: relative;
margin-bottom: 5px;
}
.radial-gauge {
width: 100%;
height: 100%;
transform: rotate(-90deg);
}
.gauge-circle {
fill: none;
stroke-width: 4;
stroke: rgba(255, 255, 255, 0.05);
}
.gauge-bar {
fill: none;
stroke-width: 6;
stroke-dasharray: 251.2;
stroke-dashoffset: 251.2;
stroke: var(--safe-color);
stroke-linecap: round;
transition: stroke-dashoffset 0.1s ease, stroke 0.3s ease;
}
.gauge-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
font-weight: 800;
font-family: 'Share Tech Mono', monospace;
color: var(--text-color);
}
/* --- RIGHT COLUMN: SLM TERMINAL & DIAGNOSTICS --- */
.right-column {
display: flex;
flex-direction: column;
gap: 30px;
}
/* Chart Panel */
.chart-container {
height: 180px;
width: 100%;
}
/* SLM Conversation terminal */
.terminal-panel {
display: flex;
flex-direction: column;
height: 380px;
}
.terminal-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
padding-bottom: 12px;
margin-bottom: 15px;
}
.terminal-title {
font-size: 14px;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
color: var(--accent-color);
display: flex;
align-items: center;
gap: 8px;
}
.terminal-body {
flex-grow: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
padding-right: 5px;
font-family: 'Outfit', sans-serif;
scroll-behavior: smooth;
}
/* Scrollbar custom styling */
.terminal-body::-webkit-scrollbar {
width: 4px;
}
.terminal-body::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
}
/* Chat bubbles */
.chat-bubble {
max-width: 80%;
padding: 12px 16px;
border-radius: 12px;
font-size: 14px;
line-height: 1.5;
animation: slide-up 0.3s ease;
}
.driver-bubble {
align-self: flex-end;
background: rgba(0, 191, 255, 0.08);
border: 1px solid rgba(0, 191, 255, 0.15);
color: #dbeafe;
border-bottom-right-radius: 2px;
}
.slm-bubble {
align-self: flex-start;
background: rgba(0, 255, 128, 0.05);
border: 1px solid rgba(0, 255, 128, 0.12);
color: #dcfce7;
border-bottom-left-radius: 2px;
}
.system-bubble {
align-self: center;
background: rgba(255, 40, 80, 0.08);
border: 1px solid rgba(255, 40, 80, 0.15);
color: #ffe4e6;
max-width: 90%;
font-family: 'Share Tech Mono', monospace;
font-size: 12px;
text-transform: uppercase;
text-align: center;
border-radius: 6px;
padding: 6px 12px;
}
.bubble-label {
font-size: 10px;
font-weight: 800;
letter-spacing: 1px;
text-transform: uppercase;
margin-bottom: 4px;
display: block;
}
.driver-bubble .bubble-label {
color: var(--accent-color);
}
.slm-bubble .bubble-label {
color: var(--safe-color);
}
/* --- Control Desk Buttons --- */
.control-desk {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.cyber-btn {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 10px;
padding: 12px;
font-size: 13px;
font-weight: 600;
color: var(--text-color);
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
transition: all 0.2s ease;
}
.cyber-btn:hover {
background: rgba(255, 255, 255, 0.06);
border-color: rgba(255, 255, 255, 0.15);
transform: translateY(-2px);
}
.cyber-btn:active {
transform: translateY(0);
}
.cyber-btn svg {
width: 20px;
height: 20px;
stroke: var(--text-color);
transition: all 0.2s ease;
}
.cyber-btn.active {
background: rgba(0, 255, 128, 0.08);
border-color: var(--safe-color);
color: var(--safe-color);
}
.cyber-btn.active svg {
stroke: var(--safe-color);
}
.cyber-btn.danger {
background: rgba(255, 40, 80, 0.05);
border-color: rgba(255, 40, 80, 0.2);
}
.cyber-btn.danger:hover {
background: rgba(255, 40, 80, 0.12);
border-color: var(--danger-color);
color: var(--danger-color);
}
.cyber-btn.danger:hover svg {
stroke: var(--danger-color);
}
/* --- DYNAMIC STATE OVERLAYS (WARNING SHADOWS) --- */
.glass-panel.state-normal::before {
background: linear-gradient(90deg, transparent, var(--safe-color), transparent);
}
.glass-panel.state-warn::before {
background: linear-gradient(90deg, transparent, var(--warn-color), transparent);
}
.glass-panel.state-warn {
border-color: rgba(255, 170, 0, 0.15);
box-shadow: 0 0 20px rgba(255, 170, 0, 0.1);
}
.glass-panel.state-danger::before {
background: linear-gradient(90deg, transparent, var(--danger-color), transparent);
}
.glass-panel.state-danger {
border-color: rgba(255, 40, 80, 0.3);
box-shadow: 0 0 30px rgba(255, 40, 80, 0.2);
animation: pulse-border 1.5s infinite;
}
/* --- Animations --- */
@keyframes pulse {
0% { transform: scale(1); opacity: 1; box-shadow: 0 0 10px var(--safe-color); }
50% { transform: scale(1.1); opacity: 0.7; box-shadow: 0 0 20px var(--safe-color); }
100% { transform: scale(1); opacity: 1; box-shadow: 0 0 10px var(--safe-color); }
}
@keyframes pulse-border {
0% { border-color: rgba(255, 40, 80, 0.2); }
50% { border-color: rgba(255, 40, 80, 0.6); }
100% { border-color: rgba(255, 40, 80, 0.2); }
}
@keyframes rotate-sync {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes slide-up {
0% { transform: translateY(10px); opacity: 0; }
100% { transform: translateY(0); opacity: 1; }
}
/* Responsive */
@media (max-width: 1200px) {
.dashboard-container {
grid-template-columns: 1fr;
padding: 20px;
}
}
</style>
</head>
<body>
<header>
<div class="logo-section">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="url(#logo-grad)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<svg style="width:0;height:0;position:absolute">
<linearGradient id="logo-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#00ff80"/>
<stop offset="100%" stop-color="#00bfff"/>
</linearGradient>
</svg>
<h1>DRIVESAFE</h1>
<span>LOCAL SLM V1.0</span>
</div>
<div class="connection-status">
<div class="pulse-dot"></div>
HUD SYSTEM RUNNING
</div>
</header>
<div class="dashboard-container">
<!-- LEFT COLUMN: VIDEO FEED & METRIC READOUTS -->
<div class="left-column">
<!-- Video feed Panel -->
<div class="glass-panel video-panel state-normal" id="main-panel">
<div class="video-container">
<img src="/video_feed" class="video-stream" id="video-feed" onerror="showPlaceholder()">
<div class="hud-overlay-badge" id="hud-state-badge">NORMAL</div>
<div class="video-placeholder" id="video-placeholder" style="display:none;">
<svg viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<line x1="1" y1="1" x2="23" y2="23"></line>
<path d="M21 21H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3m3-3h6l2 3h4a2 2 0 0 1 2 2v9.34"></path>
<path d="M10.02 4.35L8.06 6H3"></path>
<circle cx="12" cy="13" r="4"></circle>
</svg>
<p>Awaiting Safe Driving Camera Stream...</p>
</div>
</div>
</div>
<!-- Core Indicators grid -->
<div class="indicators-grid">
<!-- Eye Aspect Ratio (EAR) Gauge -->
<div class="metric-card">
<div class="metric-title">Eye Aspect Ratio</div>
<div class="gauge-container">
<svg class="radial-gauge" viewBox="0 0 100 100">
<circle class="gauge-circle" cx="50" cy="50" r="40"></circle>
<circle class="gauge-bar" id="ear-gauge" cx="50" cy="50" r="40"></circle>
</svg>
<div class="gauge-text" id="ear-val">0.00</div>
</div>
</div>
<!-- Event counter -->
<div class="metric-card">
<div class="metric-title">Drowsy Detections</div>
<div class="metric-value" id="drowsiness-count" style="color: var(--safe-color);">0</div>
</div>
<!-- System FPS -->
<div class="metric-card">
<div class="metric-title">Core Engine Speed</div>
<div class="metric-value" id="engine-fps" style="color: var(--accent-color);">0 FPS</div>
</div>
</div>
</div>
<!-- RIGHT COLUMN: CHAT LOG, CHART & DESK CONTROLS -->
<div class="right-column">
<!-- Real-time Line Graph Panel -->
<div class="glass-panel">
<div class="metric-title" style="margin-bottom:12px;">Active EKG Eye Waveform</div>
<div class="chart-container">
<canvas id="earChart"></canvas>
</div>
</div>
<!-- DriveSafe Conversational Terminal -->
<div class="glass-panel terminal-panel">
<div class="terminal-header">
<div class="terminal-title">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
COGNITIVE VOICE ASSISTANT
</div>
<span id="slm-indicator" style="font-size:10px; font-family:'Share Tech Mono', monospace; color: var(--safe-color);">SLM ONLINE</span>
</div>
<div class="terminal-body" id="chat-box">
<div class="chat-bubble slm-bubble">
<span class="bubble-label">DriveSafe SLM</span>
Hello driver! I am active. Let's drive safely today. Ask me any question, or say "play music"!
</div>
</div>
</div>
<!-- Cyber Control Desk -->
<div class="control-desk">
<button class="cyber-btn active" id="toggle-tracking-btn" onclick="toggleTracking()">
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<span>ACTIVE TRACKING</span>
</button>
<button class="cyber-btn" onclick="triggerReset()">
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67"></path>
</svg>
<span>SYSTEM RESET</span>
</button>
<button class="cyber-btn danger" onclick="triggerMusic()">
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
<span>PLAY BEATS</span>
</button>
</div>
</div>
</div>
<!-- Script file mapping -->
<script src="/static/js/app.js"></script>
<script>
function showPlaceholder() {
document.getElementById('video-feed').style.display = 'none';
document.getElementById('video-placeholder').style.display = 'flex';
}
</script>
</body>
</html>