import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import {
Upload, Play, BarChart3, Users, Clock, ArrowRight,
Activity, CheckCircle2, RotateCcw, Download, ChevronRight,
LayoutDashboard, Globe, Settings, FileText,
Bell, Search, Navigation, Layers,
Zap, ArrowUpRight, TrendingUp,
Video, Eye, EyeOff, Info, HelpCircle,
Sliders, Flame
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import {
ResponsiveContainer, AreaChart, Area,
PieChart, Pie, Cell, Tooltip, Legend, XAxis, YAxis, CartesianGrid
} from 'recharts';
const API = import.meta.env.VITE_API_URL || "http://localhost:8001";
const StatCard = ({ icon: Icon, label, value, suffix, trend, color, bg, delay }) => (
{value}{suffix}
{label}
);
const NavItem = ({ icon: Icon, label, active, onClick, badge }) => (
);
const App = () => {
const [file, setFile] = useState(null);
const [fileName, setFileName] = useState('');
const [taskId, setTaskId] = useState(null);
const [status, setStatus] = useState('idle');
const [progress, setProgress] = useState(0);
const [results, setResults] = useState(null);
const [activeNav, setActiveNav] = useState('dashboard');
const [showIDs, setShowIDs] = useState(true);
const [showTrails, setShowTrails] = useState(true);
const fileRef = useRef(null);
useEffect(() => {
let interval;
if (status === 'processing' && taskId) {
interval = setInterval(async () => {
try {
const res = await axios.get(`${API}/status/${taskId}`);
if (res.data.progress !== undefined) {
// Keep percentage at 99% until results are fully loaded
setProgress(res.data.status === 'completed' ? 100 : Math.min(res.data.progress, 99));
}
if (res.data.status === 'completed' && res.data.results) {
setResults(res.data.results);
setStatus('completed');
clearInterval(interval);
} else if (res.data.status === 'failed') {
setStatus('error');
clearInterval(interval);
}
} catch(err) {
console.error("Polling error:", err);
}
}, 800);
}
return () => clearInterval(interval);
}, [status, taskId]);
const handleFileSelect = (e) => {
const selected = e.target.files[0];
if (selected) { setFile(selected); setFileName(selected.name); }
};
const handleUpload = async () => {
if (!file) return;
setStatus('uploading'); setProgress(1); setResults(null); setTaskId(null);
const formData = new FormData();
formData.append('file', file);
try {
const res = await axios.post(`${API}/analyze`, formData);
setTaskId(res.data.task_id); setStatus('processing');
} catch { setStatus('error'); }
};
const downloadCSV = (data, filename, type) => {
if (!results) return;
let csvContent = "";
if (type === 'density' && data) {
csvContent = "Frame,Count\n" + data.map(r => `${r.Frame},${r.Count}`).join("\n");
} else if (type === 'directions' && data) {
csvContent = "Direction,Count\n" + Object.entries(data).map(([k, v]) => `${k},${v}`).join("\n");
} else {
csvContent = `Metric,Value\nUnique IDs,${results.unique_count}\nAvg Dwell Time,${results.avg_dwell_time?.toFixed(2)}s\nTimestamp,${new Date().toLocaleString()}`;
}
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url; a.download = `${filename}.csv`; a.click();
};
const isReady = status === 'completed' && results;
const PIE_COLORS = ['#3B82F6', '#10B981', '#F59E0B', '#6366F1', '#DC2626'];
return (
Crowd Intelligence
Live AI Monitoring System
Abhishek Singh
System Admin
A
{activeNav === 'dashboard' && (
Dashboard
Real-time crowd intelligence and tracking dashboard
{isReady &&
}
Live Surveillance Analysis
{status === 'idle' && (
fileRef.current?.click()} className="flex flex-col items-center cursor-pointer group">
{fileName || "Click or drop video to analyze"}
MP4, AVI, MOV up to 100MB
)}
{(status === 'uploading' || status === 'processing' || (status === 'completed' && !results)) && (
{progress}%
AI Pattern Recognition
Streaming frames to YOLOv8m core...
)}
{isReady && (
)}
{status === 'error' && (
Analysis Engine Failed
The video codec might be unsupported or an internal error occurred.
)}
Spatial Metrics
{isReady ? (
Object.values(results.directions).reduce((a, b) => a + b, 0) > 0 ? (
v > 0).map(([name, value]) => ({ name, value }))}
innerRadius={50} outerRadius={75} paddingAngle={4} dataKey="value" stroke="none"
>
{Object.entries(results.directions).filter(([, v]) => v > 0).map((_, i) => ( | ))}
) : (
No Movement Trajectories
Objects were stationary or video was too short
)
) :
Awaiting Analysis
}
Flow Timeline
{isReady ? (
`${Math.floor(t)}s`} tick={{fontSize: 9, fill: '#9CA3AF', fontWeight: 'bold'}} tickLine={false} axisLine={false} minTickGap={20} />
`Time: ${Number(l).toFixed(1)}s`} />
) :
Awaiting Analysis
}
{isReady &&
}
)}
{activeNav === 'reports' && (
Intelligence Reports
Export detailed datasets and raw metrics
{isReady ? (
{[
{ t: 'Flow Timeline (Density)', d: results.density_data, tp: 'density', i: BarChart3, c: 'text-orange-600', b: 'bg-orange-50' },
{ t: 'Directional Vectors', d: results.directions, tp: 'directions', i: Navigation, c: 'text-violet-600', b: 'bg-violet-50' },
{ t: 'Metrics Summary', d: null, tp: 'general', i: FileText, c: 'text-blue-600', b: 'bg-blue-50' },
].map((r, i) => (
{r.t}
Export raw data to CSV for external analysis.
))}
) : (
No Intelligence Data
Run an analysis on the dashboard to generate reports.
)}
)}
{activeNav === 'config' && (
System Configuration
Adjust AI capabilities and performance settings
Model Parameters
Applies to the next uploaded surveillance stream.
Auto-Generate CSV Reports on Completion
)}
);
};
export default App;