# frontend/app.py (Streamlit version) # app.py import gradio as gr import cv2 import numpy as np from datetime import datetime import pandas as pd import plotly.graph_objects as go from plotly.subplots import make_subplots import random import time # Global variables for demo employees = [ {"id": 1, "name": "Alice Johnson", "department": "Engineering", "status": "present"}, {"id": 2, "name": "Bob Smith", "department": "Sales", "status": "present"}, {"id": 3, "name": "Carol White", "department": "HR", "status": "absent"}, {"id": 4, "name": "David Brown", "department": "Engineering", "status": "present"}, {"id": 5, "name": "Eve Davis", "department": "Marketing", "status": "late"}, {"id": 6, "name": "Frank Wilson", "department": "Sales", "status": "present"}, {"id": 7, "name": "Grace Lee", "department": "Engineering", "status": "absent"}, {"id": 8, "name": "Henry Kim", "department": "HR", "status": "present"}, ] # Demo detector class DemoFaceDetector: def __init__(self): self.confidence = 0.95 self.faces_detected = 0 self.last_names = [] def detect(self, image): """Simulate face detection for demo""" if image is None: return [], [] # Simulate processing self.faces_detected += 1 # Mock detection - draw boxes on image img_copy = image.copy() h, w = img_copy.shape[:2] # Draw some fake face boxes import random faces = [] names = [] num_faces = random.randint(2, 4) for i in range(num_faces): # Random positions x = random.randint(50, w-150) y = random.randint(50, h-150) face_w = random.randint(80, 120) face_h = random.randint(80, 120) # Draw rectangle cv2.rectangle(img_copy, (x, y), (x+face_w, y+face_h), (0, 255, 0), 2) # Get random employee emp = random.choice(employees) name = emp['name'] names.append(name) # Add name label cv2.putText(img_copy, name, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) # Add status status_emoji = "â " if emp['status'] == 'present' else "â°" if emp['status'] == 'late' else "â" cv2.putText(img_copy, status_emoji, (x+face_w-30, y+face_h-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) faces.append({'bbox': (x, y, x+face_w, y+face_h), 'name': name}) self.last_names = names return img_copy, names # Initialize detector detector = DemoFaceDetector() def get_attendance_df(): """Get attendance as DataFrame""" return pd.DataFrame(employees) def process_frame(frame): """Process video frame for live feed""" if frame is None: return None # Convert to RGB if needed if len(frame.shape) == 2: frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB) # Detect faces processed_frame, names = detector.detect(frame) # Update status simulation for emp in employees: if emp['name'] in names: emp['status'] = 'present' if random.random() > 0.1 else 'late' return processed_frame def create_dashboard(): """Create analytics dashboard with Plotly""" df = get_attendance_df() # Create subplots fig = make_subplots( rows=2, cols=2, subplot_titles=( 'Attendance by Department', 'Status Distribution', 'Daily Trend', 'Department Coverage' ), specs=[[{'type': 'bar'}, {'type': 'pie'}], [{'type': 'scatter'}, {'type': 'bar'}]] ) # 1. Department breakdown dept_counts = df.groupby('department')['status'].value_counts().unstack().fillna(0) for status in dept_counts.columns: fig.add_trace( go.Bar(name=status, x=dept_counts.index, y=dept_counts[status]), row=1, col=1 ) # 2. Status distribution status_counts = df['status'].value_counts() fig.add_trace( go.Pie(labels=status_counts.index, values=status_counts.values), row=1, col=2 ) # 3. Daily trend (simulated) dates = pd.date_range(end=datetime.now(), periods=7) trend_data = { 'date': dates, 'present': [random.randint(5, 8) for _ in range(7)], 'absent': [random.randint(0, 3) for _ in range(7)], 'late': [random.randint(0, 2) for _ in range(7)] } for key in ['present', 'absent', 'late']: fig.add_trace( go.Scatter(x=dates, y=trend_data[key], name=key, mode='lines+markers'), row=2, col=1 ) # 4. Department coverage total_dept = df.groupby('department').size().reset_index(name='total') present_dept = df[df['status'] == 'present'].groupby('department').size().reset_index(name='present') coverage = total_dept.merge(present_dept, on='department', how='left').fillna(0) coverage['coverage_pct'] = (coverage['present'] / coverage['total'] * 100).round(1) fig.add_trace( go.Bar(x=coverage['department'], y=coverage['coverage_pct'], name='Coverage %', text=coverage['coverage_pct'], textposition='auto'), row=2, col=2 ) fig.update_layout(height=800, showlegend=True, title_text="đ Personnel Analytics Dashboard") fig.update_xaxes(title_text="Department", row=2, col=2) fig.update_yaxes(title_text="Coverage %", row=2, col=2) return fig def get_metrics(): """Get dashboard metrics""" df = get_attendance_df() total = len(df) present = len(df[df['status'] == 'present']) late = len(df[df['status'] == 'late']) absent = len(df[df['status'] == 'absent']) return { 'total': total, 'present': present, 'late': late, 'absent': absent, 'coverage': f"{(present/total*100):.1f}%" } def get_missing_personnel(): """Get list of missing employees""" df = get_attendance_df() absent_emps = df[df['status'] == 'absent']['name'].tolist() late_emps = df[df['status'] == 'late']['name'].tolist() return absent_emps, late_emps def live_feed(): """Gradio interface for live feed""" return gr.Interface( fn=process_frame, inputs=gr.Image(source="webcam", streaming=True, label="Live Feed"), outputs=gr.Image(label="Detection Results", type="numpy"), title="đš Live Personnel Monitoring", description="Real-time face detection and recognition", live=True ) def attendance_table(): """Show attendance table""" df = get_attendance_df() return df def dashboard_view(): """Dashboard view""" metrics = get_metrics() # Create HTML for metrics html = f"""
{metrics['present']}
{metrics['coverage']} coverage{metrics['late']}
{metrics['absent']}
{metrics['coverage']}