127 lines
4.1 KiB
HTML
127 lines
4.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Stream Monitor</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
<!-- Bootstrap 5 -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
<style>
|
|
body {
|
|
background-color: #f8f9fa;
|
|
}
|
|
.video-frame {
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
background: black;
|
|
}
|
|
.gif-preview {
|
|
width: 100%;
|
|
border-radius: 5px;
|
|
}
|
|
.detection-list {
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
}
|
|
.section-title {
|
|
margin-top: 1rem;
|
|
margin-bottom: 1rem;
|
|
font-weight: bold;
|
|
}
|
|
.small-text {
|
|
font-size: 0.85rem;
|
|
color: #666;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container-fluid mt-4">
|
|
<div class="row">
|
|
|
|
<!-- Live Stream -->
|
|
<div class="col-md-6">
|
|
<h4 class="section-title">Live Stream</h4>
|
|
<div class="video-frame">
|
|
<!-- Placeholder RTSP (replace with actual player integration) -->
|
|
<video controls autoplay muted width="100%" height="100%">
|
|
<source src="{{stream_url}}" type="video/mp4">
|
|
RTSP playback not supported.
|
|
</video>
|
|
</div>
|
|
<p class="mt-2 small-text">Frame queue length: <span id="queue-length-f">...</span></p>
|
|
<p class="mt-2 small-text">Inference Queue length: <span id="queue-length-i">...</span></p>
|
|
</div>
|
|
|
|
<!-- Negative Detections -->
|
|
<div class="col-md-3">
|
|
<h4 class="section-title text-danger">Negative Detections</h4>
|
|
<div class="detection-list" id="negatives">
|
|
<p class="text-muted small">Waiting for data...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Positive Detections -->
|
|
<div class="col-md-3">
|
|
<h4 class="section-title text-success">Positive Detections</h4>
|
|
<div class="detection-list" id="positives">
|
|
<p class="text-muted small">Waiting for data...</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bootstrap JS + Fetch -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
async function fetchStatus() {
|
|
try {
|
|
const response = await fetch('/status');
|
|
const data = await response.json();
|
|
|
|
// Update queue length
|
|
document.getElementById('queue-length-f').textContent = data.stream_1_queue;
|
|
document.getElementById('queue-length-i').textContent = data.stream_2_queue;
|
|
|
|
// Update negatives
|
|
const negContainer = document.getElementById('negatives');
|
|
negContainer.innerHTML = '';
|
|
data.negatives.forEach(item => {
|
|
negContainer.innerHTML += `
|
|
<div class="card mb-2">
|
|
<img src="/gifs/${item.gif}" class="gif-preview" alt="negative">
|
|
<div class="card-body p-2">
|
|
<small class="text-muted">${item.timestamp}</small>
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
// Update positives
|
|
const posContainer = document.getElementById('positives');
|
|
posContainer.innerHTML = '';
|
|
data.positives.forEach(item => {
|
|
posContainer.innerHTML += `
|
|
<div class="card mb-2">
|
|
<img src="/gifs/${item.gif}" class="gif-preview" alt="positive">
|
|
<div class="card-body p-2">
|
|
<small class="text-muted">${item.timestamp}</small>
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error('Error fetching status:', err);
|
|
}
|
|
}
|
|
|
|
// Fetch every 2 seconds
|
|
setInterval(fetchStatus, 2000);
|
|
fetchStatus(); // Initial call
|
|
</script>
|
|
</body>
|
|
</html>
|