import os import cv2 import pandas as pd import gradio as gr from ultralytics import YOLO from datetime import datetime, timedelta import numpy as np class AttendanceSystem: def __init__(self, model_path, csv_path): self.model_path = model_path self.csv_path = csv_path self.model = None self.class_names_list = [] self.time_list = [] self.load_previous_attendance() def load_model(self): """Load the YOLO model""" if self.model is None: try: self.model = YOLO(self.model_path) return True, "Model loaded successfully!" except Exception as e: return False, f"Error loading model: {str(e)}" return True, "Model already loaded" def load_previous_attendance(self): """Load previous attendance data if CSV exists""" if os.path.exists(self.csv_path): try: df = pd.read_csv(self.csv_path) if not df.empty: self.class_names_list = df["Class Name"].tolist() self.time_list = df["Time"].tolist() return True, f"Loaded {len(self.class_names_list)} previous attendance records" except Exception as e: return False, f"Error loading previous attendance: {str(e)}" return False, "No previous attendance data found" def process_frame(self, frame): """Process a single frame and update attendance""" if self.model is None: success, message = self.load_model() if not success: return frame, message, [], [] # Create a copy of the frame to draw on display_frame = frame.copy() # Store detected names in this frame detected_names = [] # Detect objects results = self.model(frame) # Check if any results are detected if results: for result in results: boxes = result.boxes for box in boxes: x1, y1, x2, y2 = box.xyxy[0].cpu().numpy().astype(int) class_id = int(box.cls[0]) confidence = float(box.conf[0]) # Get the class name from YOLO class names class_name = self.model.names[class_id] detected_names.append(class_name) # Draw rectangle around detected object cv2.rectangle(display_frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(display_frame, f"{class_name}: {confidence:.2f}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2) # Get the current time current_time = datetime.now() current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S") # Check if the class has been recorded already person_already_recorded = False for idx, name in enumerate(self.class_names_list): if name == class_name: last_recorded_time = datetime.strptime(self.time_list[idx], "%Y-%m-%d %H:%M:%S") # If less than 24 hours have passed since the last recording if (current_time - last_recorded_time) < timedelta(hours=24): person_already_recorded = True break # Record attendance if not already recorded in the last 24 hours if not person_already_recorded: self.class_names_list.append(class_name) self.time_list.append(current_time_str) self.save_attendance() # Create attendance list for display attendance_data = [] for name, time_str in zip(self.class_names_list, self.time_list): attendance_data.append(f"{name} - {time_str}") return display_frame, f"Detected: {', '.join(detected_names) if detected_names else 'None'}", attendance_data, detected_names def save_attendance(self): """Save attendance data to CSV""" if self.class_names_list and self.time_list: df = pd.DataFrame({ "Class Name": self.class_names_list, "Time": self.time_list }) try: df.to_csv(self.csv_path, index=False) return True, "Attendance saved to CSV" except Exception as e: return False, f"Error saving to CSV: {str(e)}" return False, "No attendance data to save" def clear_attendance(self): """Clear attendance records""" self.class_names_list = [] self.time_list = [] if os.path.exists(self.csv_path): try: os.remove(self.csv_path) return True, "Attendance records cleared" except Exception as e: return False, f"Error clearing records: {str(e)}" return True, "No records to clear" # Function for Gradio interface - process images from webcam def process_webcam_image(image, state): if state is None: # Default paths - update these to match your Hugging Face deployment model_path = "best(attendance).pt" # Make sure to upload this model to your Space csv_path = "attendance_data.csv" state = AttendanceSystem(model_path, csv_path) # Load model immediately state.load_model() if image is None: return None, "No image received", "", state # Process the frame processed_frame, message, attendance_data, detected_names = state.process_frame(image) # Format attendance as HTML table for better display if attendance_data: attendance_html = "" attendance_html += "" for record in attendance_data: name, time_str = record.split(" - ", 1) attendance_html += f"" attendance_html += "
NameTime
{name}{time_str}
" else: attendance_html = "No attendance records." return processed_frame, message, attendance_html, state def clear_attendance_records(state): if state is not None: success, message = state.clear_attendance() return message, "
", state return "System not initialized", "
", None def change_model_path(model_path, csv_path, state): if not model_path or not csv_path: return "Please provide both paths", state state = AttendanceSystem(model_path, csv_path) success, message = state.load_model() return message, state # Create Gradio interface that works on Hugging Face with gr.Blocks(title="Attendance System") as app: gr.Markdown("# Automated Attendance System") gr.Markdown("This system uses YOLO to detect and record attendance of individuals.") with gr.Row(): with gr.Column(scale=2): # Fixed: Use sources instead of source for the webcam component input_image = gr.Image(label="Webcam Feed", sources=["webcam"]) process_button = gr.Button("Process Image") output_image = gr.Image(label="Processed Feed") status_text = gr.Textbox(label="Status", value="Capture an image and click 'Process Image'") with gr.Column(scale=1): # Attendance records and controls attendance_display = gr.HTML(label="Attendance Records", value="No records yet.") clear_button = gr.Button("Clear Attendance Records") # Configuration options with gr.Accordion("Configuration", open=False): model_path_input = gr.Textbox(label="Model Path", value="best(attendance).pt") csv_path_input = gr.Textbox(label="CSV Output Path", value="attendance_data.csv") update_paths_button = gr.Button("Update Paths") # State for storing the attendance system object state = gr.State(None) # Set up event handlers process_button.click( process_webcam_image, inputs=[input_image, state], outputs=[output_image, status_text, attendance_display, state] ) clear_button.click( clear_attendance_records, inputs=[state], outputs=[status_text, attendance_display, state] ) update_paths_button.click( change_model_path, inputs=[model_path_input, csv_path_input, state], outputs=[status_text, state] ) # Create a requirements.txt file for Hugging Face with open('requirements.txt', 'w') as f: f.write('opencv-python-headless\npandas\ngradio>=3.32.0\nultralytics') # Launch the app if __name__ == "__main__": app.launch() # Remove share=True for Hugging Face deployment