pranit144's picture
Upload 3 files
8d1a3c7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live Video Feed with Alerts</title>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #2ecc71;
--primary-dark: #27ae60;
--secondary-color: #1e8449;
--accent-color: #3498db;
--background-color: #f5f5f5;
--card-color: #ffffff;
--text-color: #333333;
--text-light: #7f8c8d;
--border-color: #e0e0e0;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--border-radius: 8px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
background-color: var(--primary-color);
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: var(--shadow);
}
.header h1 {
font-size: 1.5rem;
margin: 0;
font-weight: 600;
}
.container {
display: flex;
flex: 1;
}
.sidebar {
width: 300px;
background-color: var(--card-color);
border-right: 1px solid var(--border-color);
padding: 1.5rem;
overflow-y: auto;
transition: all 0.3s ease;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
}
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding-bottom: 0.75rem;
border-bottom: 2px solid var(--primary-color);
}
.main-content {
flex: 1;
padding: 2rem;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.section-title {
color: var(--primary-dark);
font-size: 1.2rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--primary-color);
}
.card {
background-color: var(--card-color);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 1.5rem;
margin-bottom: 1.5rem;
border-top: 4px solid var(--primary-color);
}
.video-container {
position: relative;
overflow: hidden;
border-radius: var(--border-radius);
background-color: #000;
box-shadow: var(--shadow);
}
.video-feed {
width: 100%;
border-radius: var(--border-radius);
display: block;
border: none;
}
.status {
position: absolute;
top: 15px;
right: 15px;
background-color: rgba(0, 0, 0, 0.6);
color: white;
padding: 0.5rem 0.75rem;
border-radius: 20px;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
height: 10px;
width: 10px;
background-color: var(--primary-color);
border-radius: 50%;
display: inline-block;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.detection-list {
list-style: none;
margin-top: 0.5rem;
}
.detection-item {
display: flex;
justify-content: space-between;
padding: 0.75rem;
border-bottom: 1px solid var(--border-color);
transition: background-color 0.2s ease;
}
.detection-item:hover {
background-color: rgba(46, 204, 113, 0.1);
}
.detection-item:last-child {
border-bottom: none;
}
.detection-count {
background-color: var(--primary-color);
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.9rem;
}
.alert-info {
background-color: rgba(46, 204, 113, 0.1);
border-left: 4px solid var(--primary-color);
padding: 1rem;
margin-top: 1rem;
border-radius: 4px;
display: flex;
align-items: center;
gap: 10px;
}
.alert-info i {
color: var(--primary-color);
font-size: 1.2rem;
}
#graph {
height: 300px;
margin-top: 1rem;
}
/* Responsive styles */
@media (max-width: 992px) {
.container {
flex-direction: column;
}
.sidebar {
width: 100%;
border-right: none;
border-bottom: 1px solid var(--border-color);
}
}
@media (max-width: 576px) {
.header {
padding: 1rem;
}
.main-content, .sidebar {
padding: 1rem;
}
}
</style>
</head>
<body>
<header class="header">
<h1><i class="fas fa-video"></i> Security Monitoring System</h1>
<div>
<span id="current-time"></span>
</div>
</header>
<div class="container">
<div class="sidebar">
<div class="sidebar-header">
<h2>Detection Summary</h2>
</div>
<div class="card">
<div class="section-title">Detected Objects</div>
<ul id="class-list" class="detection-list">
<!-- List of detected classes will be populated here -->
<li class="detection-item">Loading data...</li>
</ul>
</div>
<div class="card">
<div class="section-title">Detection Graph</div>
<div id="graph"></div>
</div>
</div>
<div class="main-content">
<div class="card">
<div class="section-title">Live Camera Feed</div>
<div class="video-container">
<img id="video-feed" class="video-feed" src="{{ url_for('video_feed') }}" alt="Live Video Feed">
<div class="status">
<span class="status-dot"></span>
Live
</div>
</div>
<div class="alert-info">
<i class="fas fa-bell"></i>
<p>If a person is detected, a call will be initiated and an alert will be sent via Telegram.</p>
</div>
</div>
</div>
</div>
<!-- Include Plotly.js for interactive graphs -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
// Display current time
function updateTime() {
const now = new Date();
document.getElementById('current-time').textContent = now.toLocaleTimeString();
}
setInterval(updateTime, 1000);
updateTime();
// Fetch detection data from the server and update the dashboard
async function fetchDetectionData() {
try {
const response = await fetch('/detection_data');
const data = await response.json();
updateClassList(data);
updateGraph(data);
} catch (error) {
console.error("Error fetching detection data:", error);
document.getElementById('class-list').innerHTML = '<li class="detection-item">Error loading data</li>';
}
}
// Update the class list in the sidebar
function updateClassList(data) {
const classList = document.getElementById('class-list');
classList.innerHTML = '';
if (Object.keys(data).length === 0) {
const li = document.createElement('li');
li.className = 'detection-item';
li.textContent = 'No objects detected';
classList.appendChild(li);
return;
}
for (const [cls, count] of Object.entries(data)) {
const li = document.createElement('li');
li.className = 'detection-item';
const className = document.createElement('span');
className.textContent = cls;
const countSpan = document.createElement('span');
countSpan.className = 'detection-count';
countSpan.textContent = count;
li.appendChild(className);
li.appendChild(countSpan);
classList.appendChild(li);
}
}
// Update the detection graph using Plotly
function updateGraph(data) {
const classes = Object.keys(data);
const counts = Object.values(data);
const trace = {
x: classes,
y: counts,
type: 'bar',
marker: {
color: 'rgba(46, 204, 113, 0.7)',
line: {
color: 'rgba(39, 174, 96, 1)',
width: 1.5
}
}
};
const layout = {
margin: { t: 20, r: 20, l: 40, b: 60 },
xaxis: { title: 'Objects' },
yaxis: { title: 'Count' },
font: { family: 'Segoe UI, sans-serif' },
paper_bgcolor: 'rgba(0,0,0,0)',
plot_bgcolor: 'rgba(0,0,0,0)',
};
Plotly.newPlot('graph', [trace], layout, {responsive: true});
}
// Periodically fetch detection data every 5 seconds
setInterval(fetchDetectionData, 5000);
// Initial fetch
fetchDetectionData();
</script>
</body>
</html>