PrashanthB461 commited on
Commit
18a517b
Β·
verified Β·
1 Parent(s): b1f120c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +389 -389
app.py CHANGED
@@ -3,456 +3,456 @@ import cv2
3
  import numpy as np
4
  import pandas as pd
5
  from datetime import datetime, date
6
- import os
7
- import sqlite3
8
  import face_recognition
9
- import io
 
 
 
10
  from PIL import Image
11
  import json
12
 
13
- # Initialize database
14
- def init_database():
15
- conn = sqlite3.connect('attendance.db')
16
- cursor = conn.cursor()
17
-
18
- # Create users table
19
- cursor.execute('''
20
- CREATE TABLE IF NOT EXISTS users (
21
- id INTEGER PRIMARY KEY AUTOINCREMENT,
22
- name TEXT NOT NULL,
23
- employee_id TEXT UNIQUE NOT NULL,
24
- face_encoding TEXT NOT NULL,
25
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
26
- )
27
- ''')
28
-
29
- # Create attendance table
30
- cursor.execute('''
31
- CREATE TABLE IF NOT EXISTS attendance (
32
- id INTEGER PRIMARY KEY AUTOINCREMENT,
33
- employee_id TEXT NOT NULL,
34
- name TEXT NOT NULL,
35
- date DATE NOT NULL,
36
- time_in TIME,
37
- time_out TIME,
38
- status TEXT DEFAULT 'Present',
39
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
40
- FOREIGN KEY (employee_id) REFERENCES users (employee_id)
41
- )
42
- ''')
43
-
44
- conn.commit()
45
- conn.close()
46
-
47
- # Load known faces from database
48
- def load_known_faces():
49
- conn = sqlite3.connect('attendance.db')
50
- cursor = conn.cursor()
51
- cursor.execute("SELECT name, employee_id, face_encoding FROM users")
52
- users = cursor.fetchall()
53
- conn.close()
54
-
55
- known_faces = []
56
- known_names = []
57
- known_ids = []
58
-
59
- for user in users:
60
- name, emp_id, encoding_str = user
61
- encoding = json.loads(encoding_str)
62
- known_faces.append(np.array(encoding))
63
- known_names.append(name)
64
- known_ids.append(emp_id)
65
 
66
- return known_faces, known_names, known_ids
67
-
68
- # Register new face
69
- def register_face(image, name, employee_id):
70
- if image is None:
71
- return "Please upload an image", None
 
 
72
 
73
- if not name or not employee_id:
74
- return "Please provide both name and employee ID", None
 
 
75
 
76
- try:
 
 
 
 
77
  # Convert PIL image to RGB array
78
- img_array = np.array(image)
 
79
 
80
  # Find face encodings
81
- face_locations = face_recognition.face_locations(img_array)
 
82
 
83
- if len(face_locations) == 0:
84
- return "No face detected in the image. Please upload a clear image with a visible face.", None
85
-
86
- if len(face_locations) > 1:
87
- return "Multiple faces detected. Please upload an image with only one face.", None
88
-
89
- face_encodings = face_recognition.face_encodings(img_array, face_locations)
90
- face_encoding = face_encodings[0]
91
 
92
- # Check if employee ID already exists
93
- conn = sqlite3.connect('attendance.db')
94
- cursor = conn.cursor()
95
- cursor.execute("SELECT * FROM users WHERE employee_id = ?", (employee_id,))
96
- existing_user = cursor.fetchone()
97
 
98
- if existing_user:
99
- conn.close()
100
- return f"Employee ID {employee_id} already exists!", None
 
101
 
102
- # Save to database
103
- encoding_str = json.dumps(face_encoding.tolist())
104
- cursor.execute(
105
- "INSERT INTO users (name, employee_id, face_encoding) VALUES (?, ?, ?)",
106
- (name, employee_id, encoding_str)
107
- )
108
- conn.commit()
109
- conn.close()
110
 
111
- return f"Successfully registered {name} with Employee ID: {employee_id}", get_registered_users()
112
-
113
- except Exception as e:
114
- return f"Error during registration: {str(e)}", None
115
-
116
- # Mark attendance
117
- def mark_attendance(image):
118
- if image is None:
119
- return "Please upload an image", None, None
120
 
121
- try:
122
- # Convert PIL image to RGB array
123
- img_array = np.array(image)
 
124
 
125
- # Load known faces
126
- known_faces, known_names, known_ids = load_known_faces()
127
 
128
- if len(known_faces) == 0:
129
- return "No registered users found. Please register users first.", None, None
 
130
 
131
- # Find faces in the uploaded image
132
- face_locations = face_recognition.face_locations(img_array)
133
- face_encodings = face_recognition.face_encodings(img_array, face_locations)
134
 
135
  if len(face_encodings) == 0:
136
- return "No face detected in the image.", None, None
137
 
138
- results = []
139
- annotated_image = img_array.copy()
 
140
 
141
- for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
142
  # Compare with known faces
143
- matches = face_recognition.compare_faces(known_faces, face_encoding, tolerance=0.6)
144
- face_distances = face_recognition.face_distance(known_faces, face_encoding)
145
 
146
  if len(face_distances) > 0:
147
  best_match_index = np.argmin(face_distances)
148
 
149
- if matches[best_match_index]:
150
- name = known_names[best_match_index]
151
- emp_id = known_ids[best_match_index]
152
- confidence = 1 - face_distances[best_match_index]
153
-
154
- # Mark attendance in database
155
- conn = sqlite3.connect('attendance.db')
156
- cursor = conn.cursor()
157
-
158
- today = date.today()
159
- current_time = datetime.now().strftime("%H:%M:%S")
160
 
161
- # Check if already marked for today
162
- cursor.execute(
163
- "SELECT * FROM attendance WHERE employee_id = ? AND date = ?",
164
- (emp_id, today)
 
165
  )
166
- existing_record = cursor.fetchone()
167
 
168
- if existing_record:
169
- # Update time_out if time_in exists
170
- if existing_record[4]: # time_in exists
171
- cursor.execute(
172
- "UPDATE attendance SET time_out = ? WHERE employee_id = ? AND date = ?",
173
- (current_time, emp_id, today)
174
- )
175
- status = "Time Out Updated"
176
- else:
177
- status = "Already marked for today"
178
  else:
179
- # Create new attendance record
180
- cursor.execute(
181
- "INSERT INTO attendance (employee_id, name, date, time_in) VALUES (?, ?, ?, ?)",
182
- (emp_id, name, today, current_time)
183
- )
184
- status = "Attendance Marked"
185
-
186
- conn.commit()
187
- conn.close()
188
-
189
- results.append(f"{name} ({emp_id}) - {status} - Confidence: {confidence:.2f}")
190
-
191
- # Draw rectangle and label on image
192
- cv2.rectangle(annotated_image, (left, top), (right, bottom), (0, 255, 0), 2)
193
- cv2.putText(annotated_image, f"{name} ({confidence:.2f})",
194
- (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
195
  else:
196
- results.append("Unknown person detected")
197
- cv2.rectangle(annotated_image, (left, top), (right, bottom), (0, 0, 255), 2)
198
- cv2.putText(annotated_image, "Unknown",
199
- (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
200
  else:
201
- results.append("Unknown person detected")
202
 
203
- result_text = "\n".join(results)
204
- return result_text, Image.fromarray(annotated_image), get_attendance_records()
205
 
206
- except Exception as e:
207
- return f"Error during attendance marking: {str(e)}", None, None
208
-
209
- # Get registered users
210
- def get_registered_users():
211
- try:
212
- conn = sqlite3.connect('attendance.db')
213
- df = pd.read_sql_query("SELECT name, employee_id, created_at FROM users ORDER BY created_at DESC", conn)
214
- conn.close()
215
- return df
216
- except:
217
- return pd.DataFrame(columns=['name', 'employee_id', 'created_at'])
218
-
219
- # Get attendance records
220
- def get_attendance_records():
221
- try:
222
- conn = sqlite3.connect('attendance.db')
223
- df = pd.read_sql_query("""
224
- SELECT name, employee_id, date, time_in, time_out, status
225
- FROM attendance
226
- ORDER BY date DESC, time_in DESC
227
- """, conn)
228
- conn.close()
229
- return df
230
- except:
231
- return pd.DataFrame(columns=['name', 'employee_id', 'date', 'time_in', 'time_out', 'status'])
232
-
233
- # Get today's attendance
234
- def get_todays_attendance():
235
- try:
236
- conn = sqlite3.connect('attendance.db')
237
- today = date.today()
238
- df = pd.read_sql_query("""
239
- SELECT name, employee_id, time_in, time_out, status
240
- FROM attendance
241
- WHERE date = ?
242
- ORDER BY time_in DESC
243
- """, conn, params=(today,))
244
- conn.close()
245
- return df
246
- except:
247
- return pd.DataFrame(columns=['name', 'employee_id', 'time_in', 'time_out', 'status'])
248
-
249
- # Delete user
250
- def delete_user(employee_id):
251
- if not employee_id:
252
- return "Please enter an employee ID", get_registered_users()
253
 
254
- try:
255
- conn = sqlite3.connect('attendance.db')
256
- cursor = conn.cursor()
 
257
 
258
- # Check if user exists
259
- cursor.execute("SELECT name FROM users WHERE employee_id = ?", (employee_id,))
260
- user = cursor.fetchone()
 
 
 
 
 
 
261
 
262
- if not user:
263
- conn.close()
264
- return f"Employee ID {employee_id} not found", get_registered_users()
265
 
266
- # Delete user and their attendance records
267
- cursor.execute("DELETE FROM attendance WHERE employee_id = ?", (employee_id,))
268
- cursor.execute("DELETE FROM users WHERE employee_id = ?", (employee_id,))
269
 
270
- conn.commit()
271
- conn.close()
 
 
 
 
272
 
273
- return f"Successfully deleted user {user[0]} ({employee_id})", get_registered_users()
 
 
 
 
274
 
275
- except Exception as e:
276
- return f"Error deleting user: {str(e)}", get_registered_users()
277
-
278
- # Initialize database on startup
279
- init_database()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
- # Custom CSS
282
- css = """
283
- .gradio-container {
284
- max-width: 1200px !important;
285
- }
286
- .tab-nav {
287
- background: linear-gradient(90deg, #667eea 0%, #764ba2 100%) !important;
288
- }
289
- .tab-nav button {
290
- color: white !important;
291
- font-weight: bold !important;
292
- }
293
- .tab-nav button.selected {
294
- background: rgba(255,255,255,0.2) !important;
295
- }
296
- """
297
 
298
  # Create Gradio interface
299
- with gr.Blocks(css=css, title="Attendance Analyzer - Face Detection", theme=gr.themes.Soft()) as app:
300
- gr.Markdown(
 
 
 
 
 
 
 
 
 
301
  """
302
- # 🎯 Attendance Analyzer Using Face Detection
303
-
304
- **Advanced AI-powered attendance management system with real-time face recognition**
305
 
306
- ---
307
- """,
308
- elem_classes="header"
309
- )
310
-
311
- with gr.Tabs():
312
- # Tab 1: Mark Attendance
313
- with gr.Tab("πŸ“Έ Mark Attendance"):
314
- gr.Markdown("### Mark attendance by uploading an image or using webcam")
315
 
316
- with gr.Row():
317
- with gr.Column(scale=1):
318
- attendance_image = gr.Image(
319
- type="pil",
320
- label="Upload Image for Attendance",
321
- height=400
322
- )
323
- mark_btn = gr.Button("Mark Attendance", variant="primary", size="lg")
324
-
325
- with gr.Column(scale=1):
326
- attendance_result = gr.Textbox(
327
- label="Attendance Result",
328
- lines=5,
329
- placeholder="Results will appear here..."
330
- )
331
- annotated_output = gr.Image(
332
- label="Detected Faces",
333
- height=400
334
- )
335
 
336
- with gr.Row():
337
- attendance_df = gr.Dataframe(
338
- label="πŸ“Š Today's Attendance Records",
339
- headers=["Name", "Employee ID", "Time In", "Time Out", "Status"],
340
- datatype=["str", "str", "str", "str", "str"],
341
- value=get_todays_attendance()
342
- )
343
 
344
- # Tab 2: Register New User
345
- with gr.Tab("πŸ‘€ Register User"):
346
- gr.Markdown("### Register a new user for face recognition")
347
-
348
- with gr.Row():
349
- with gr.Column(scale=1):
350
- register_image = gr.Image(
351
- type="pil",
352
- label="Upload User Photo",
353
- height=400
354
- )
355
-
356
- with gr.Column(scale=1):
357
- user_name = gr.Textbox(
358
- label="Full Name",
359
- placeholder="Enter full name..."
360
- )
361
- emp_id = gr.Textbox(
362
- label="Employee ID",
363
- placeholder="Enter unique employee ID..."
364
- )
365
- register_btn = gr.Button("Register User", variant="primary", size="lg")
366
 
367
- register_result = gr.Textbox(
368
- label="Registration Result",
369
- lines=3,
370
- placeholder="Registration status will appear here..."
371
- )
372
-
373
- with gr.Row():
374
- users_df = gr.Dataframe(
375
- label="πŸ‘₯ Registered Users",
376
- headers=["Name", "Employee ID", "Registration Date"],
377
- datatype=["str", "str", "str"],
378
- value=get_registered_users()
 
 
 
379
  )
380
-
381
- # Tab 3: Manage Users
382
- with gr.Tab("βš™οΈ Manage Users"):
383
- gr.Markdown("### Manage registered users")
384
 
385
- with gr.Row():
386
- with gr.Column(scale=1):
387
- delete_emp_id = gr.Textbox(
388
- label="Employee ID to Delete",
389
- placeholder="Enter employee ID to delete..."
390
- )
391
- delete_btn = gr.Button("Delete User", variant="stop", size="lg")
392
- delete_result = gr.Textbox(
393
- label="Delete Result",
394
- lines=2,
395
- placeholder="Delete status will appear here..."
396
- )
397
 
398
- with gr.Column(scale=2):
399
- manage_users_df = gr.Dataframe(
400
- label="πŸ‘₯ All Registered Users",
401
- headers=["Name", "Employee ID", "Registration Date"],
402
- datatype=["str", "str", "str"],
403
- value=get_registered_users()
404
- )
405
-
406
- # Tab 4: Attendance Reports
407
- with gr.Tab("πŸ“ˆ Reports"):
408
- gr.Markdown("### View attendance reports and analytics")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
 
410
- with gr.Row():
411
- refresh_btn = gr.Button("Refresh Reports", variant="secondary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
- with gr.Row():
414
- all_attendance_df = gr.Dataframe(
415
- label="πŸ“‹ All Attendance Records",
416
- headers=["Name", "Employee ID", "Date", "Time In", "Time Out", "Status"],
417
- datatype=["str", "str", "str", "str", "str", "str"],
418
- value=get_attendance_records(),
419
- height=500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  )
 
 
 
 
 
 
 
 
 
421
 
422
- # Event handlers
423
- mark_btn.click(
424
- fn=mark_attendance,
425
- inputs=[attendance_image],
426
- outputs=[attendance_result, annotated_output, attendance_df]
427
- )
428
-
429
- register_btn.click(
430
- fn=register_face,
431
- inputs=[register_image, user_name, emp_id],
432
- outputs=[register_result, users_df]
433
- )
434
-
435
- delete_btn.click(
436
- fn=delete_user,
437
- inputs=[delete_emp_id],
438
- outputs=[delete_result, manage_users_df]
439
- )
440
-
441
- refresh_btn.click(
442
- fn=lambda: get_attendance_records(),
443
- outputs=[all_attendance_df]
444
- )
445
-
446
- # Auto-refresh today's attendance
447
- mark_btn.click(
448
- fn=lambda: get_todays_attendance(),
449
- outputs=[attendance_df]
450
- )
451
 
 
452
  if __name__ == "__main__":
453
- app.launch(
454
- share=True,
455
  server_name="0.0.0.0",
456
  server_port=7860,
457
- show_api=False
 
458
  )
 
3
  import numpy as np
4
  import pandas as pd
5
  from datetime import datetime, date
 
 
6
  import face_recognition
7
+ import pickle
8
+ import os
9
+ from io import BytesIO
10
+ import base64
11
  from PIL import Image
12
  import json
13
 
14
+ class AttendanceAnalyzer:
15
+ def __init__(self):
16
+ self.known_face_encodings = []
17
+ self.known_face_names = []
18
+ self.attendance_records = []
19
+ self.load_known_faces()
20
+
21
+ def load_known_faces(self):
22
+ """Load known faces from storage"""
23
+ if os.path.exists("known_faces.pkl"):
24
+ try:
25
+ with open("known_faces.pkl", "rb") as f:
26
+ data = pickle.load(f)
27
+ self.known_face_encodings = data.get("encodings", [])
28
+ self.known_face_names = data.get("names", [])
29
+ except:
30
+ self.known_face_encodings = []
31
+ self.known_face_names = []
32
+
33
+ if os.path.exists("attendance_records.json"):
34
+ try:
35
+ with open("attendance_records.json", "r") as f:
36
+ self.attendance_records = json.load(f)
37
+ except:
38
+ self.attendance_records = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ def save_known_faces(self):
41
+ """Save known faces to storage"""
42
+ data = {
43
+ "encodings": self.known_face_encodings,
44
+ "names": self.known_face_names
45
+ }
46
+ with open("known_faces.pkl", "wb") as f:
47
+ pickle.dump(data, f)
48
 
49
+ def save_attendance_records(self):
50
+ """Save attendance records to storage"""
51
+ with open("attendance_records.json", "w") as f:
52
+ json.dump(self.attendance_records, f, indent=2)
53
 
54
+ def register_face(self, image, name):
55
+ """Register a new face for attendance tracking"""
56
+ if image is None or not name.strip():
57
+ return "❌ Please provide both image and name!", self.get_registered_faces_info()
58
+
59
  # Convert PIL image to RGB array
60
+ if isinstance(image, Image.Image):
61
+ image = np.array(image)
62
 
63
  # Find face encodings
64
+ face_locations = face_recognition.face_locations(image)
65
+ face_encodings = face_recognition.face_encodings(image, face_locations)
66
 
67
+ if len(face_encodings) == 0:
68
+ return "❌ No face detected in the image! Please try again with a clear face image.", self.get_registered_faces_info()
 
 
 
 
 
 
69
 
70
+ if len(face_encodings) > 1:
71
+ return "❌ Multiple faces detected! Please upload an image with only one face.", self.get_registered_faces_info()
 
 
 
72
 
73
+ # Check if person already exists
74
+ name = name.strip().title()
75
+ if name in self.known_face_names:
76
+ return f"❌ {name} is already registered!", self.get_registered_faces_info()
77
 
78
+ # Add the face encoding and name
79
+ self.known_face_encodings.append(face_encodings[0])
80
+ self.known_face_names.append(name)
81
+ self.save_known_faces()
 
 
 
 
82
 
83
+ return f"βœ… {name} has been successfully registered!", self.get_registered_faces_info()
 
 
 
 
 
 
 
 
84
 
85
+ def mark_attendance(self, image):
86
+ """Mark attendance for detected faces"""
87
+ if image is None:
88
+ return "❌ Please provide an image!", self.get_today_attendance()
89
 
90
+ if len(self.known_face_encodings) == 0:
91
+ return "❌ No registered faces found! Please register faces first.", self.get_today_attendance()
92
 
93
+ # Convert PIL image to RGB array
94
+ if isinstance(image, Image.Image):
95
+ image = np.array(image)
96
 
97
+ # Find faces in the image
98
+ face_locations = face_recognition.face_locations(image)
99
+ face_encodings = face_recognition.face_encodings(image, face_locations)
100
 
101
  if len(face_encodings) == 0:
102
+ return "❌ No faces detected in the image!", self.get_today_attendance()
103
 
104
+ # Process each face
105
+ recognized_faces = []
106
+ unknown_faces = 0
107
 
108
+ for face_encoding in face_encodings:
109
  # Compare with known faces
110
+ matches = face_recognition.compare_faces(self.known_face_encodings, face_encoding, tolerance=0.6)
111
+ face_distances = face_recognition.face_distance(self.known_face_encodings, face_encoding)
112
 
113
  if len(face_distances) > 0:
114
  best_match_index = np.argmin(face_distances)
115
 
116
+ if matches[best_match_index] and face_distances[best_match_index] < 0.6:
117
+ name = self.known_face_names[best_match_index]
 
 
 
 
 
 
 
 
 
118
 
119
+ # Check if already marked today
120
+ today = date.today().isoformat()
121
+ already_marked = any(
122
+ record["name"] == name and record["date"] == today
123
+ for record in self.attendance_records
124
  )
 
125
 
126
+ if not already_marked:
127
+ # Mark attendance
128
+ self.attendance_records.append({
129
+ "name": name,
130
+ "date": today,
131
+ "time": datetime.now().strftime("%H:%M:%S"),
132
+ "status": "Present"
133
+ })
134
+ recognized_faces.append(name)
 
135
  else:
136
+ recognized_faces.append(f"{name} (Already marked)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  else:
138
+ unknown_faces += 1
 
 
 
139
  else:
140
+ unknown_faces += 1
141
 
142
+ # Save attendance records
143
+ self.save_attendance_records()
144
 
145
+ # Prepare result message
146
+ result_parts = []
147
+ if recognized_faces:
148
+ result_parts.append(f"βœ… Attendance marked for: {', '.join(recognized_faces)}")
149
+ if unknown_faces > 0:
150
+ result_parts.append(f"❓ {unknown_faces} unknown face(s) detected")
151
+
152
+ result = "\n".join(result_parts) if result_parts else "❌ No faces could be processed!"
153
+
154
+ return result, self.get_today_attendance()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ def get_registered_faces_info(self):
157
+ """Get information about registered faces"""
158
+ if not self.known_face_names:
159
+ return "No faces registered yet."
160
 
161
+ info = f"**Registered Faces ({len(self.known_face_names)}):**\n"
162
+ for i, name in enumerate(self.known_face_names, 1):
163
+ info += f"{i}. {name}\n"
164
+ return info
165
+
166
+ def get_today_attendance(self):
167
+ """Get today's attendance records"""
168
+ today = date.today().isoformat()
169
+ today_records = [r for r in self.attendance_records if r["date"] == today]
170
 
171
+ if not today_records:
172
+ return f"**Today's Attendance ({today}):**\nNo attendance marked yet."
 
173
 
174
+ info = f"**Today's Attendance ({today}):**\n"
175
+ for record in today_records:
176
+ info += f"β€’ {record['name']} - {record['time']} ({record['status']})\n"
177
 
178
+ return info
179
+
180
+ def get_attendance_report(self, start_date, end_date):
181
+ """Generate attendance report for date range"""
182
+ if not start_date or not end_date:
183
+ return "Please select both start and end dates."
184
 
185
+ # Filter records by date range
186
+ filtered_records = [
187
+ r for r in self.attendance_records
188
+ if start_date <= r["date"] <= end_date
189
+ ]
190
 
191
+ if not filtered_records:
192
+ return f"No attendance records found between {start_date} and {end_date}."
193
+
194
+ # Create DataFrame for better presentation
195
+ df = pd.DataFrame(filtered_records)
196
+
197
+ # Summary statistics
198
+ total_days = (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days + 1
199
+ unique_people = df['name'].nunique()
200
+ total_attendances = len(df)
201
+
202
+ report = f"**Attendance Report ({start_date} to {end_date})**\n\n"
203
+ report += f"πŸ“Š **Summary:**\n"
204
+ report += f"β€’ Total Days: {total_days}\n"
205
+ report += f"β€’ Unique People: {unique_people}\n"
206
+ report += f"β€’ Total Attendances: {total_attendances}\n\n"
207
+
208
+ # Individual attendance counts
209
+ if not df.empty:
210
+ attendance_counts = df['name'].value_counts()
211
+ report += f"πŸ‘₯ **Individual Attendance:**\n"
212
+ for name, count in attendance_counts.items():
213
+ percentage = (count / total_days) * 100
214
+ report += f"β€’ {name}: {count} days ({percentage:.1f}%)\n"
215
+
216
+ return report
217
+
218
+ def export_attendance_csv(self):
219
+ """Export attendance records to CSV"""
220
+ if not self.attendance_records:
221
+ return None, "No attendance records to export."
222
+
223
+ df = pd.DataFrame(self.attendance_records)
224
+ csv_file = f"attendance_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
225
+ df.to_csv(csv_file, index=False)
226
+
227
+ return csv_file, f"βœ… Attendance exported to {csv_file}"
228
 
229
+ # Initialize the attendance analyzer
230
+ analyzer = AttendanceAnalyzer()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
  # Create Gradio interface
233
+ def create_interface():
234
+ with gr.Blocks(
235
+ title="Attendance Analyzer Using Face Detection",
236
+ theme=gr.themes.Soft(),
237
+ css="""
238
+ .gradio-container {
239
+ max-width: 1200px !important;
240
+ }
241
+ .tab-nav {
242
+ font-weight: bold;
243
+ }
244
  """
245
+ ) as demo:
 
 
246
 
247
+ gr.Markdown(
248
+ """
249
+ # πŸ‘€ Attendance Analyzer Using Face Detection
 
 
 
 
 
 
250
 
251
+ **A comprehensive face recognition system for attendance management**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
+ πŸ“‹ **Features:**
254
+ - Register new faces for attendance tracking
255
+ - Automatic attendance marking via face detection
256
+ - Real-time attendance reports and analytics
257
+ - Export attendance data to CSV
258
+ """
259
+ )
260
 
261
+ with gr.Tabs():
262
+ # Face Registration Tab
263
+ with gr.Tab("πŸ‘₯ Register Face", elem_classes="tab-nav"):
264
+ gr.Markdown("### Register New Person for Attendance Tracking")
265
+
266
+ with gr.Row():
267
+ with gr.Column(scale=1):
268
+ register_image = gr.Image(
269
+ label="Upload Person's Photo",
270
+ type="pil",
271
+ height=300
272
+ )
273
+ register_name = gr.Textbox(
274
+ label="Person's Name",
275
+ placeholder="Enter full name...",
276
+ lines=1
277
+ )
278
+ register_btn = gr.Button(
279
+ "πŸ” Register Face",
280
+ variant="primary",
281
+ size="lg"
282
+ )
283
 
284
+ with gr.Column(scale=1):
285
+ register_output = gr.Textbox(
286
+ label="Registration Status",
287
+ lines=3,
288
+ interactive=False
289
+ )
290
+ registered_faces_info = gr.Markdown(
291
+ value=analyzer.get_registered_faces_info(),
292
+ label="Registered Faces"
293
+ )
294
+
295
+ register_btn.click(
296
+ fn=analyzer.register_face,
297
+ inputs=[register_image, register_name],
298
+ outputs=[register_output, registered_faces_info]
299
  )
 
 
 
 
300
 
301
+ # Attendance Marking Tab
302
+ with gr.Tab("βœ… Mark Attendance", elem_classes="tab-nav"):
303
+ gr.Markdown("### Mark Attendance via Face Recognition")
 
 
 
 
 
 
 
 
 
304
 
305
+ with gr.Row():
306
+ with gr.Column(scale=1):
307
+ attendance_image = gr.Image(
308
+ label="Upload Photo for Attendance",
309
+ type="pil",
310
+ height=300
311
+ )
312
+ mark_attendance_btn = gr.Button(
313
+ "πŸ“‹ Mark Attendance",
314
+ variant="primary",
315
+ size="lg"
316
+ )
317
+
318
+ with gr.Column(scale=1):
319
+ attendance_output = gr.Textbox(
320
+ label="Attendance Status",
321
+ lines=4,
322
+ interactive=False
323
+ )
324
+ today_attendance = gr.Markdown(
325
+ value=analyzer.get_today_attendance(),
326
+ label="Today's Attendance"
327
+ )
328
+
329
+ mark_attendance_btn.click(
330
+ fn=analyzer.mark_attendance,
331
+ inputs=[attendance_image],
332
+ outputs=[attendance_output, today_attendance]
333
+ )
334
 
335
+ # Reports Tab
336
+ with gr.Tab("πŸ“Š Reports & Analytics", elem_classes="tab-nav"):
337
+ gr.Markdown("### Attendance Reports and Data Export")
338
+
339
+ with gr.Row():
340
+ with gr.Column():
341
+ gr.Markdown("#### πŸ“… Generate Report")
342
+ start_date = gr.Date(
343
+ label="Start Date",
344
+ value=date.today().replace(day=1).isoformat()
345
+ )
346
+ end_date = gr.Date(
347
+ label="End Date",
348
+ value=date.today().isoformat()
349
+ )
350
+ generate_report_btn = gr.Button(
351
+ "πŸ“Š Generate Report",
352
+ variant="primary"
353
+ )
354
+
355
+ gr.Markdown("#### πŸ’Ύ Export Data")
356
+ export_btn = gr.Button(
357
+ "πŸ“₯ Export to CSV",
358
+ variant="secondary"
359
+ )
360
+ export_status = gr.Textbox(
361
+ label="Export Status",
362
+ lines=2,
363
+ interactive=False
364
+ )
365
+ export_file = gr.File(
366
+ label="Download File",
367
+ visible=False
368
+ )
369
+
370
+ with gr.Column():
371
+ report_output = gr.Markdown(
372
+ value="Select date range and click 'Generate Report' to view attendance analytics.",
373
+ label="Attendance Report"
374
+ )
375
+
376
+ generate_report_btn.click(
377
+ fn=analyzer.get_attendance_report,
378
+ inputs=[start_date, end_date],
379
+ outputs=[report_output]
380
+ )
381
+
382
+ def export_and_show(analyzer=analyzer):
383
+ file_path, status = analyzer.export_attendance_csv()
384
+ if file_path:
385
+ return status, gr.update(visible=True, value=file_path)
386
+ else:
387
+ return status, gr.update(visible=False)
388
+
389
+ export_btn.click(
390
+ fn=export_and_show,
391
+ outputs=[export_status, export_file]
392
+ )
393
 
394
+ # Instructions Tab
395
+ with gr.Tab("ℹ️ Instructions", elem_classes="tab-nav"):
396
+ gr.Markdown(
397
+ """
398
+ ## πŸ“– How to Use the Attendance Analyzer
399
+
400
+ ### 1. πŸ‘₯ Register Faces
401
+ - Go to the **"Register Face"** tab
402
+ - Upload a clear photo of the person (one face per image)
403
+ - Enter the person's full name
404
+ - Click **"Register Face"** to add them to the system
405
+
406
+ ### 2. βœ… Mark Attendance
407
+ - Go to the **"Mark Attendance"** tab
408
+ - Upload a photo containing one or more registered faces
409
+ - Click **"Mark Attendance"** to automatically detect and mark attendance
410
+ - The system will show which people were recognized and marked present
411
+
412
+ ### 3. πŸ“Š View Reports
413
+ - Go to the **"Reports & Analytics"** tab
414
+ - Select a date range to generate attendance reports
415
+ - Export attendance data to CSV for external analysis
416
+
417
+ ### πŸ’‘ Tips for Best Results:
418
+ - Use high-quality, well-lit photos
419
+ - Ensure faces are clearly visible and not obscured
420
+ - For registration, use photos with the person looking directly at camera
421
+ - The system works best with front-facing photos
422
+ - Multiple people can be detected in a single attendance photo
423
+
424
+ ### πŸ”§ Technical Features:
425
+ - **Face Detection**: Automatically locates faces in images
426
+ - **Face Recognition**: Matches detected faces with registered users
427
+ - **Duplicate Prevention**: Prevents multiple attendance marks for the same person on the same day
428
+ - **Data Persistence**: All data is saved and persists between sessions
429
+ - **Export Capability**: Generate CSV reports for external analysis
430
+
431
+ ### 🚨 Troubleshooting:
432
+ - **"No face detected"**: Ensure the image contains a clear, visible face
433
+ - **"Multiple faces detected"** (during registration): Use images with only one person
434
+ - **"Unknown face"**: The person needs to be registered first
435
+ - **Poor recognition**: Try re-registering with a clearer photo
436
+ """
437
  )
438
+
439
+ # Footer
440
+ gr.Markdown(
441
+ """
442
+ ---
443
+ **πŸ”’ Privacy Note:** All face data is processed locally and securely stored.
444
+ No personal data is transmitted to external servers.
445
+ """
446
+ )
447
 
448
+ return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
 
450
+ # Create and launch the interface
451
  if __name__ == "__main__":
452
+ demo = create_interface()
453
+ demo.launch(
454
  server_name="0.0.0.0",
455
  server_port=7860,
456
+ share=False,
457
+ show_error=True
458
  )