Johnnyyyyy56 commited on
Commit
82db053
·
verified ·
1 Parent(s): 8a514d8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -519
app.py CHANGED
@@ -1,12 +1,4 @@
1
  import os
2
- import csv
3
- import zipfile
4
- import shutil
5
- import re
6
- from datetime import datetime
7
- os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
8
- os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
9
-
10
  import cv2
11
  import gradio as gr
12
  from deepface import DeepFace
@@ -15,6 +7,7 @@ from PIL import Image
15
  import time
16
  from pathlib import Path
17
  import pandas as pd
 
18
 
19
  # Configuration
20
  EMOTION_MAP = {
@@ -48,7 +41,6 @@ def log_emotion(batch_no, emotion, confidence, face_path, annotated_path):
48
  writer.writerow([timestamp, batch_no, emotion, confidence, str(face_path), str(annotated_path)])
49
 
50
  def validate_batch_no(batch_no):
51
- """Validate that batch number contains only digits"""
52
  if not batch_no.strip():
53
  return False, "Batch number cannot be empty"
54
  if not re.match(r'^\d+$', batch_no):
@@ -56,7 +48,6 @@ def validate_batch_no(batch_no):
56
  return True, ""
57
 
58
  def process_frame(batch_no, frame):
59
- """Process a single frame for emotion detection"""
60
  if not batch_no.strip() or frame is None:
61
  return None, None, "Waiting for input...", False, False
62
 
@@ -88,567 +79,142 @@ def process_frame(batch_no, frame):
88
  confidence = result['emotion'][emotion]
89
  region = result['region']
90
 
91
- # Extract face coordinates
92
  x, y, w, h = region['x'], region['y'], region['w'], region['h']
93
 
94
- # Save raw face crop
95
- face_crop = frame[y:y+h, x:x+w]
96
  timestamp = int(time.time())
97
  face_dir = SAVE_DIR / "faces" / emotion
98
  face_path = face_dir / f"{batch_no}_{timestamp}.jpg"
99
- cv2.imwrite(str(face_path), face_crop)
100
 
101
- # Create and save annotated image
102
- annotated_frame = frame.copy()
103
- cv2.rectangle(annotated_frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
104
- cv2.putText(annotated_frame, f"{emotion} {EMOTION_MAP[emotion]} {confidence:.1f}%",
105
- (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
106
 
107
  annotated_dir = SAVE_DIR / "annotated" / emotion
108
  annotated_path = annotated_dir / f"{batch_no}_{timestamp}.jpg"
109
- cv2.imwrite(str(annotated_path), annotated_frame)
110
 
111
- # Log both paths
112
  log_emotion(batch_no, emotion, confidence, face_path, annotated_path)
113
 
114
- # Convert back to PIL format for display
115
- output_img = Image.fromarray(cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB))
116
- return output_img, f"Batch {batch_no}: {emotion.title()} ({confidence:.1f}%)", "", True, True
117
-
118
- except Exception as e:
119
- return None, None, f"Error: {str(e)}", False, False
120
-
121
- def process_batch_input(batch_no):
122
- """Handle batch number input and activate webcam"""
123
- is_valid, validation_msg = validate_batch_no(batch_no)
124
- if not is_valid:
125
  return (
126
- gr.Textbox(interactive=True),
127
- gr.Textbox(value=validation_msg, visible=bool(validation_msg)),
128
- gr.Image(visible=False),
129
- gr.Image(visible=False),
130
- gr.Textbox(visible=False),
131
- gr.Button(visible=False),
132
- gr.Textbox(visible=False) # For trigger
133
  )
134
 
135
- return (
136
- gr.Textbox(interactive=False),
137
- gr.Textbox(value="Webcam activated - position your face", visible=True),
138
- gr.Image(visible=True, streaming=True),
139
- gr.Image(visible=False),
140
- gr.Textbox(visible=False),
141
- gr.Button(visible=False),
142
- gr.Textbox(value=str(time.time()), visible=False) # Initialize trigger
143
- )
144
-
145
- def reset_interface():
146
- """Reset the interface to initial state"""
147
- return (
148
- gr.Textbox(value="", interactive=True),
149
- gr.Textbox(value="", visible=False),
150
- gr.Image(value=None, visible=False),
151
- gr.Image(visible=False),
152
- gr.Textbox(visible=False),
153
- gr.Button(visible=False),
154
- gr.Textbox(visible=False)
155
- )
156
-
157
- def get_image_gallery(emotion, image_type):
158
- """Get image gallery for selected emotion and type"""
159
- if emotion == "All Emotions":
160
- image_dict = {}
161
- for emot in EMOTION_MAP.keys():
162
- folder = SAVE_DIR / image_type / emot
163
- image_dict[emot] = [str(f) for f in folder.glob("*.jpg") if f.exists()]
164
- else:
165
- folder = SAVE_DIR / image_type / emotion
166
- image_dict = {emotion: [str(f) for f in folder.glob("*.jpg") if f.exists()]}
167
- return image_dict
168
-
169
- def create_custom_zip(file_paths):
170
- """Create zip from selected images and return the file path"""
171
- if not file_paths:
172
- return None
173
-
174
- temp_dir = SAVE_DIR / "temp_downloads"
175
- temp_dir.mkdir(exist_ok=True)
176
- zip_path = temp_dir / f"emotion_images_{int(time.time())}.zip"
177
-
178
- if zip_path.exists():
179
- try:
180
- zip_path.unlink()
181
- except Exception as e:
182
- print(f"Error deleting old zip: {e}")
183
-
184
- try:
185
- with zipfile.ZipFile(zip_path, 'w') as zipf:
186
- for file_path in file_paths:
187
- file_path = Path(file_path)
188
- if file_path.exists():
189
- zipf.write(file_path, arcname=file_path.name)
190
- return str(zip_path) if zip_path.exists() else None
191
- except Exception as e:
192
- print(f"Error creating zip file: {e}")
193
- return None
194
-
195
- def download_all_emotions_structured():
196
- """Download all emotions in a structured ZIP with folders for each emotion"""
197
- temp_dir = SAVE_DIR / "temp_downloads"
198
- temp_dir.mkdir(exist_ok=True)
199
- zip_path = temp_dir / f"all_emotions_structured_{int(time.time())}.zip"
200
-
201
- if zip_path.exists():
202
- try:
203
- zip_path.unlink()
204
- except Exception as e:
205
- print(f"Error deleting old zip: {e}")
206
-
207
- try:
208
- with zipfile.ZipFile(zip_path, 'w') as zipf:
209
- for emotion in EMOTION_MAP.keys():
210
- # Add faces
211
- face_dir = SAVE_DIR / "faces" / emotion
212
- for face_file in face_dir.glob("*.jpg"):
213
- if face_file.exists():
214
- arcname = f"faces/{emotion}/{face_file.name}"
215
- zipf.write(face_file, arcname=arcname)
216
-
217
- # Add annotated images
218
- annotated_dir = SAVE_DIR / "annotated" / emotion
219
- for annotated_file in annotated_dir.glob("*.jpg"):
220
- if annotated_file.exists():
221
- arcname = f"annotated/{emotion}/{annotated_file.name}"
222
- zipf.write(annotated_file, arcname=arcname)
223
- return str(zip_path) if zip_path.exists() else None
224
- except Exception as e:
225
- print(f"Error creating structured zip file: {e}")
226
- return None
227
-
228
- def delete_selected_images(selected_images):
229
- """Delete selected images with proper validation"""
230
- if not selected_images:
231
- return "No images selected for deletion"
232
-
233
- deleted_count = 0
234
- failed_deletions = []
235
-
236
- for img_path in selected_images:
237
- img_path = Path(img_path)
238
- try:
239
- if img_path.exists():
240
- img_path.unlink()
241
- deleted_count += 1
242
- else:
243
- failed_deletions.append(str(img_path))
244
- except Exception as e:
245
- print(f"Error deleting {img_path}: {e}")
246
- failed_deletions.append(str(img_path))
247
-
248
- if deleted_count > 0 and LOG_FILE.exists():
249
- try:
250
- df = pd.read_csv(LOG_FILE)
251
- for img_path in selected_images:
252
- img_path = str(img_path)
253
- if "faces" in img_path:
254
- df = df[df.face_path != img_path]
255
- else:
256
- df = df[df.annotated_path != img_path]
257
- df.to_csv(LOG_FILE, index=False)
258
- except Exception as e:
259
- print(f"Error updating logs: {e}")
260
-
261
- status_msg = f"Deleted {deleted_count} images"
262
- if failed_deletions:
263
- status_msg += f"\nFailed to delete {len(failed_deletions)} images"
264
- return status_msg
265
-
266
- def delete_images_in_category(emotion, image_type, confirm=False):
267
- """Delete all images in a specific category with confirmation"""
268
- if not confirm:
269
- return "Please check the confirmation box to delete all images in this category"
270
-
271
- if emotion == "All Emotions":
272
- deleted_count = 0
273
- for emot in EMOTION_MAP.keys():
274
- deleted_count += delete_images_in_category(emot, image_type, confirm=True)
275
- return f"Deleted {deleted_count} images across all emotion categories"
276
-
277
- folder = SAVE_DIR / image_type / emotion
278
- deleted_count = 0
279
- failed_deletions = []
280
-
281
- for file in folder.glob("*"):
282
- if file.is_file():
283
- try:
284
- file.unlink()
285
- deleted_count += 1
286
- except Exception as e:
287
- print(f"Error deleting {file}: {e}")
288
- failed_deletions.append(str(file))
289
-
290
- if deleted_count > 0 and LOG_FILE.exists():
291
- try:
292
- df = pd.read_csv(LOG_FILE)
293
- if image_type == "faces":
294
- df = df[df.emotion != emotion]
295
- else:
296
- df = df[~((df.emotion == emotion) & (df.annotated_path.str.contains(str(folder))))]
297
- df.to_csv(LOG_FILE, index=False)
298
- except Exception as e:
299
- print(f"Error updating logs: {e}")
300
-
301
- status_msg = f"Deleted {deleted_count} images from {emotion}/{image_type}"
302
- if failed_deletions:
303
- status_msg += f"\nFailed to delete {len(failed_deletions)} images"
304
- return status_msg
305
-
306
- def get_logs():
307
- if LOG_FILE.exists():
308
- return pd.read_csv(LOG_FILE)
309
- return pd.DataFrame()
310
-
311
- def view_logs():
312
- df = get_logs()
313
- if not df.empty:
314
- try:
315
- return df.to_markdown()
316
- except ImportError:
317
- return df.to_string()
318
- return "No logs available yet"
319
-
320
- def download_logs():
321
- if LOG_FILE.exists():
322
- temp_dir = SAVE_DIR / "temp_downloads"
323
- temp_dir.mkdir(exist_ok=True)
324
- download_path = temp_dir / "emotion_logs.csv"
325
- shutil.copy2(LOG_FILE, download_path)
326
- return str(download_path)
327
- return None
328
-
329
- def clear_all_data():
330
- """Clear all images and logs"""
331
- deleted_count = 0
332
-
333
- for emotion in EMOTION_MAP.keys():
334
- for img_type in ["faces", "annotated"]:
335
- folder = SAVE_DIR / img_type / emotion
336
- for file in folder.glob("*"):
337
- if file.is_file():
338
- try:
339
- file.unlink()
340
- deleted_count += 1
341
- except Exception as e:
342
- print(f"Error deleting {file}: {e}")
343
-
344
- temp_dir = SAVE_DIR / "temp_downloads"
345
- if temp_dir.exists():
346
- try:
347
- shutil.rmtree(temp_dir)
348
- except Exception as e:
349
- print(f"Error deleting temp directory: {e}")
350
-
351
- if LOG_FILE.exists():
352
- try:
353
- LOG_FILE.unlink()
354
- except Exception as e:
355
- print(f"Error deleting log file: {e}")
356
-
357
- try:
358
- with open(LOG_FILE, 'w', newline='') as f:
359
- writer = csv.writer(f)
360
- writer.writerow(["timestamp", "batch_no", "emotion", "confidence", "face_path", "annotated_path"])
361
  except Exception as e:
362
- print(f"Error recreating log file: {e}")
363
-
364
- empty_df = pd.DataFrame(columns=["timestamp", "batch_no", "emotion", "confidence", "face_path", "annotated_path"])
365
- return f"Deleted {deleted_count} items. All data has been cleared.", empty_df, None
366
 
367
- # Capture Interface
368
- with gr.Blocks(title="Emotion Capture", css="""
369
- .gradio-container { max-width: 800px !important }
370
- .message { color: red; font-weight: bold; }
371
- .status { color: blue; font-weight: bold; }
372
- .gallery { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
373
- .disabled-input { background-color: #f0f0f0; }
374
- """) as capture_interface:
375
-
376
- gr.Markdown("""
377
- # Automatic Emotion Capture
378
- 1. Enter/scan your batch number (numbers only)
379
- 2. Webcam will activate automatically
380
- 3. System detects your face continuously
381
- 4. Results appear instantly
382
- 5. Click "Done" to reset
383
- """)
384
 
385
  with gr.Row():
386
- batch_no = gr.Textbox(
387
  label="Batch Number",
388
- placeholder="Enter or scan numbers only",
389
  interactive=True
390
  )
391
-
392
- status = gr.Textbox(
393
- label="Status",
394
- interactive=False,
395
- elem_classes="status",
396
- visible=False
397
- )
398
 
399
  with gr.Row():
400
  webcam = gr.Image(
401
  sources=["webcam"],
402
- type="pil",
403
- label="Face Capture",
404
  streaming=True,
405
  mirror_webcam=True,
406
  visible=False,
407
  interactive=False
408
  )
409
-
410
- with gr.Row():
411
  result_img = gr.Image(
412
- label="Analysis Result",
413
- interactive=False,
414
  visible=False
415
  )
416
 
417
  with gr.Row():
418
  result_text = gr.Textbox(
419
- label="Emotion Result",
420
- interactive=False,
421
  visible=False
422
  )
423
-
424
- with gr.Row():
425
  done_btn = gr.Button(
426
- "Done",
427
  visible=False
428
  )
429
 
430
  # Hidden trigger for continuous processing
431
  trigger = gr.Textbox(visible=False)
432
 
433
- # Auto-activate webcam on valid batch number
434
- batch_no.change(
435
- process_batch_input,
436
- inputs=batch_no,
437
- outputs=[batch_no, status, webcam, result_img, result_text, done_btn, trigger]
438
- )
439
-
440
- # Continuous face detection processing chain
441
- def process_and_retrigger(batch_no, webcam_img, trigger_val):
442
- # Process current frame
443
- result_img, result_text, msg, show_img, show_text = process_frame(batch_no, webcam_img)
 
444
 
445
- # Return outputs plus updated trigger
446
- return result_img, result_text, msg, show_img, show_text, gr.Textbox.update(value=str(time.time()))
 
 
 
 
 
 
 
447
 
448
- webcam.change(
449
- process_and_retrigger,
450
- inputs=[batch_no, webcam, trigger],
451
- outputs=[result_img, result_text, status, result_img, result_text, trigger]
452
- )
 
 
 
 
 
453
 
454
- # Reset interface
455
- done_btn.click(
456
- reset_interface,
457
- outputs=[batch_no, status, webcam, result_img, result_text, done_btn, trigger]
 
458
  )
459
-
460
- # Data Management Interface
461
- with gr.Blocks(title="Data Management") as data_interface:
462
 
463
- gr.Markdown("# Data Management Interface")
 
 
 
 
 
464
 
465
- with gr.Tab("Image Management"):
466
- with gr.Column():
467
- gr.Markdown("## Select and Manage Images")
468
- with gr.Row():
469
- emotion_selector = gr.Dropdown(
470
- choices=["All Emotions"] + list(EMOTION_MAP.keys()),
471
- label="Emotion Category",
472
- value="All Emotions"
473
- )
474
- image_type_selector = gr.Dropdown(
475
- choices=["faces", "annotated"],
476
- label="Image Type",
477
- value="faces"
478
- )
479
- refresh_btn = gr.Button("Refresh Gallery")
480
-
481
- current_image_paths = gr.State([])
482
-
483
- gallery = gr.Gallery(
484
- label="Image Gallery",
485
- columns=4
486
- )
487
- selected_images = gr.CheckboxGroup(
488
- label="Selected Images",
489
- interactive=True,
490
- value=[]
491
- )
492
-
493
- with gr.Row(variant="panel"):
494
- with gr.Column():
495
- gr.Markdown("### Download Options")
496
- download_btn = gr.Button("Download Selected", variant="primary")
497
- download_all_btn = gr.Button("Download All in Category")
498
- download_structured_btn = gr.Button("Download All (Structured)", variant="primary")
499
- download_output = gr.File(label="Download Result", visible=False)
500
-
501
- with gr.Column():
502
- gr.Markdown("### Delete Options")
503
- delete_btn = gr.Button("Delete Selected", variant="stop")
504
- with gr.Row():
505
- delete_confirm = gr.Checkbox(label="I confirm I want to delete ALL images in this category", value=False)
506
- delete_all_btn = gr.Button("Delete All in Category", variant="stop", interactive=False)
507
- delete_output = gr.Textbox(label="Delete Status")
508
-
509
- def update_gallery_components(emotion, image_type):
510
- image_dict = get_image_gallery(emotion, image_type)
511
- gallery_items = []
512
- image_paths = []
513
- for emotion, images in image_dict.items():
514
- for img_path in images:
515
- gallery_items.append((img_path, f"{emotion}: {Path(img_path).name}"))
516
- image_paths.append(img_path)
517
- return gallery_items, image_paths
518
-
519
- initial_gallery, initial_paths = update_gallery_components("All Emotions", "faces")
520
- gallery.value = initial_gallery
521
- current_image_paths.value = initial_paths
522
- selected_images.choices = initial_paths
523
-
524
- def update_components(emotion, image_type):
525
- gallery_items, image_paths = update_gallery_components(emotion, image_type)
526
- return {
527
- gallery: gallery_items,
528
- current_image_paths: image_paths,
529
- selected_images: gr.CheckboxGroup(choices=image_paths, value=[])
530
- }
531
-
532
- emotion_selector.change(
533
- update_components,
534
- inputs=[emotion_selector, image_type_selector],
535
- outputs=[gallery, current_image_paths, selected_images]
536
- )
537
-
538
- image_type_selector.change(
539
- update_components,
540
- inputs=[emotion_selector, image_type_selector],
541
- outputs=[gallery, current_image_paths, selected_images]
542
- )
543
-
544
- refresh_btn.click(
545
- update_components,
546
- inputs=[emotion_selector, image_type_selector],
547
- outputs=[gallery, current_image_paths, selected_images]
548
- )
549
-
550
- download_btn.click(
551
- lambda selected: create_custom_zip(selected),
552
- inputs=selected_images,
553
- outputs=download_output,
554
- api_name="download_selected"
555
- ).then(
556
- lambda x: gr.File(visible=x is not None),
557
- inputs=download_output,
558
- outputs=download_output
559
- )
560
-
561
- download_all_btn.click(
562
- lambda emotion, img_type: create_custom_zip(
563
- [str(f) for f in (SAVE_DIR / img_type / (emotion if emotion != "All Emotions" else "*")).glob("*.jpg") if f.exists()]
564
- ),
565
- inputs=[emotion_selector, image_type_selector],
566
- outputs=download_output,
567
- api_name="download_all"
568
- ).then(
569
- lambda x: gr.File(visible=x is not None),
570
- inputs=download_output,
571
- outputs=download_output
572
- )
573
-
574
- download_structured_btn.click(
575
- download_all_emotions_structured,
576
- outputs=download_output,
577
- api_name="download_all_structured"
578
- ).then(
579
- lambda x: gr.File(visible=x is not None),
580
- inputs=download_output,
581
- outputs=download_output
582
- )
583
-
584
- delete_btn.click(
585
- lambda selected: {
586
- "delete_output": delete_selected_images(selected),
587
- **update_components(emotion_selector.value, image_type_selector.value)
588
- },
589
- inputs=selected_images,
590
- outputs=[delete_output, gallery, current_image_paths, selected_images]
591
- )
592
-
593
- delete_confirm.change(
594
- lambda x: gr.Button(interactive=x),
595
- inputs=delete_confirm,
596
- outputs=delete_all_btn
597
- )
598
-
599
- delete_all_btn.click(
600
- lambda emotion, img_type, confirm: {
601
- "delete_output": delete_images_in_category(emotion, img_type, confirm),
602
- **update_components(emotion, img_type)
603
- },
604
- inputs=[emotion_selector, image_type_selector, delete_confirm],
605
- outputs=[delete_output, gallery, current_image_paths, selected_images]
606
- )
607
 
608
- with gr.Tab("Emotion Logs"):
609
- with gr.Column():
610
- gr.Markdown("## Emotion Analysis Logs")
611
- with gr.Row():
612
- refresh_logs_btn = gr.Button("Refresh Logs")
613
- download_logs_btn = gr.Button("Download Logs as CSV")
614
- clear_all_btn = gr.Button("Clear All Data", variant="stop")
615
-
616
- logs_display = gr.Markdown()
617
- logs_csv = gr.File(label="Logs Download", visible=False)
618
- clear_message = gr.Textbox(label="Status", interactive=False)
619
-
620
- refresh_logs_btn.click(
621
- view_logs,
622
- outputs=logs_display
623
- )
624
-
625
- download_logs_btn.click(
626
- download_logs,
627
- outputs=logs_csv,
628
- api_name="download_logs"
629
- ).then(
630
- lambda x: gr.File(visible=x is not None),
631
- inputs=logs_csv,
632
- outputs=logs_csv
633
- )
634
-
635
- clear_all_btn.click(
636
- clear_all_data,
637
- outputs=[clear_message, logs_display, logs_csv]
638
- ).then(
639
- lambda: update_components("All Emotions", "faces"),
640
- outputs=[gallery, current_image_paths]
641
- ).then(
642
- lambda: gr.CheckboxGroup(choices=[], value=[]),
643
- outputs=selected_images
644
- )
645
-
646
- # Combine interfaces
647
- demo = gr.TabbedInterface(
648
- [capture_interface, data_interface],
649
- ["Emotion Capture", "Data Management"],
650
- css=".gradio-container { max-width: 1200px !important }"
651
- )
652
 
653
  if __name__ == "__main__":
654
- demo.launch()
 
1
  import os
 
 
 
 
 
 
 
 
2
  import cv2
3
  import gradio as gr
4
  from deepface import DeepFace
 
7
  import time
8
  from pathlib import Path
9
  import pandas as pd
10
+ import re
11
 
12
  # Configuration
13
  EMOTION_MAP = {
 
41
  writer.writerow([timestamp, batch_no, emotion, confidence, str(face_path), str(annotated_path)])
42
 
43
  def validate_batch_no(batch_no):
 
44
  if not batch_no.strip():
45
  return False, "Batch number cannot be empty"
46
  if not re.match(r'^\d+$', batch_no):
 
48
  return True, ""
49
 
50
  def process_frame(batch_no, frame):
 
51
  if not batch_no.strip() or frame is None:
52
  return None, None, "Waiting for input...", False, False
53
 
 
79
  confidence = result['emotion'][emotion]
80
  region = result['region']
81
 
 
82
  x, y, w, h = region['x'], region['y'], region['w'], region['h']
83
 
84
+ # Save files and log data
 
85
  timestamp = int(time.time())
86
  face_dir = SAVE_DIR / "faces" / emotion
87
  face_path = face_dir / f"{batch_no}_{timestamp}.jpg"
88
+ cv2.imwrite(str(face_path), frame[y:y+h, x:x+w])
89
 
90
+ annotated = frame.copy()
91
+ cv2.rectangle(annotated, (x,y), (x+w,y+h), (0,255,0), 2)
92
+ cv2.putText(annotated, f"{emotion} {confidence:.1f}%",
93
+ (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)
 
94
 
95
  annotated_dir = SAVE_DIR / "annotated" / emotion
96
  annotated_path = annotated_dir / f"{batch_no}_{timestamp}.jpg"
97
+ cv2.imwrite(str(annotated_path), annotated)
98
 
 
99
  log_emotion(batch_no, emotion, confidence, face_path, annotated_path)
100
 
 
 
 
 
 
 
 
 
 
 
 
101
  return (
102
+ Image.fromarray(cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)),
103
+ f"Batch {batch_no}: {emotion.title()} ({confidence:.1f}%)",
104
+ "",
105
+ True,
106
+ True
 
 
107
  )
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  except Exception as e:
110
+ return None, None, f"Error: {str(e)}", False, False
 
 
 
111
 
112
+ # Main Interface
113
+ with gr.Blocks(title="Auto Emotion Detection") as interface:
114
+ gr.Markdown("# Automatic Emotion Detection")
115
+ gr.Markdown("1. Enter your batch number\n2. Webcam will activate automatically\n3. System will detect your face\n4. Results will appear")
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  with gr.Row():
118
+ batch_input = gr.Textbox(
119
  label="Batch Number",
120
+ placeholder="Enter numbers only",
121
  interactive=True
122
  )
123
+ status = gr.Textbox(
124
+ label="Status",
125
+ interactive=False,
126
+ visible=False
127
+ )
 
 
128
 
129
  with gr.Row():
130
  webcam = gr.Image(
131
  sources=["webcam"],
 
 
132
  streaming=True,
133
  mirror_webcam=True,
134
  visible=False,
135
  interactive=False
136
  )
 
 
137
  result_img = gr.Image(
138
+ label="Result",
 
139
  visible=False
140
  )
141
 
142
  with gr.Row():
143
  result_text = gr.Textbox(
144
+ label="Analysis",
 
145
  visible=False
146
  )
 
 
147
  done_btn = gr.Button(
148
+ "Done",
149
  visible=False
150
  )
151
 
152
  # Hidden trigger for continuous processing
153
  trigger = gr.Textbox(visible=False)
154
 
155
+ def handle_batch_input(batch_no):
156
+ is_valid, msg = validate_batch_no(batch_no)
157
+ if not is_valid:
158
+ return (
159
+ gr.Textbox(interactive=True),
160
+ gr.Textbox(value=msg, visible=bool(msg)),
161
+ gr.Image(visible=False),
162
+ gr.Image(visible=False),
163
+ gr.Textbox(visible=False),
164
+ gr.Button(visible=False),
165
+ gr.Textbox(visible=False)
166
+ )
167
 
168
+ return (
169
+ gr.Textbox(interactive=False),
170
+ gr.Textbox(value="Webcam activated - position your face", visible=True),
171
+ gr.Image(visible=True),
172
+ gr.Image(visible=False),
173
+ gr.Textbox(visible=False),
174
+ gr.Button(visible=False),
175
+ gr.Textbox(value=str(time.time()), visible=False)
176
+ )
177
 
178
+ def process_and_continue(batch_no, frame, trigger_val):
179
+ result_img, result_text, msg, show_img, show_text = process_frame(batch_no, frame)
180
+ return (
181
+ result_img,
182
+ result_text,
183
+ msg,
184
+ show_img,
185
+ show_text,
186
+ gr.Textbox.update(value=str(time.time()))
187
+ )
188
 
189
+ # Setup event handlers
190
+ batch_input.change(
191
+ handle_batch_input,
192
+ inputs=batch_input,
193
+ outputs=[batch_input, status, webcam, result_img, result_text, done_btn, trigger]
194
  )
 
 
 
195
 
196
+ webcam.change(
197
+ process_and_continue,
198
+ inputs=[batch_input, webcam, trigger],
199
+ outputs=[result_img, result_text, status, result_img, result_text, trigger],
200
+ queue=False
201
+ )
202
 
203
+ def reset_all():
204
+ return (
205
+ gr.Textbox(value="", interactive=True),
206
+ gr.Textbox(value="", visible=False),
207
+ gr.Image(visible=False),
208
+ gr.Image(visible=False),
209
+ gr.Textbox(visible=False),
210
+ gr.Button(visible=False),
211
+ gr.Textbox(visible=False)
212
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
+ done_btn.click(
215
+ reset_all,
216
+ outputs=[batch_input, status, webcam, result_img, result_text, done_btn, trigger]
217
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
  if __name__ == "__main__":
220
+ interface.launch()