ALYYAN commited on
Commit
f0293fd
·
verified ·
1 Parent(s): 15ee904

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -40
app.py CHANGED
@@ -3,11 +3,10 @@ import os
3
  import cv2
4
  import time
5
 
6
- # Ensure the correct predictor class is imported from your MLOps pipeline
7
  from src.EmotionRecognition.pipeline.hf_predictor import HFPredictor
8
 
9
  # --- INITIALIZE THE MODEL ---
10
- # This happens only once when the application starts
11
  print("[INFO] Initializing predictor...")
12
  try:
13
  predictor = HFPredictor()
@@ -23,63 +22,45 @@ body {
23
  background: linear-gradient(-45deg, #0b0f19, #131a2d, #2a2a72, #522a72);
24
  background-size: 400% 400%;
25
  animation: gradient 15s ease infinite;
26
- color: #e0e0e0;
27
  }
28
  @keyframes gradient { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
29
-
30
  /* General Layout & Typography */
31
  .gradio-container { max-width: 1320px !important; margin: auto !important; }
32
  #title { text-align: center; font-size: 3rem !important; font-weight: 700; color: #FFF; margin-bottom: 0.5rem; }
33
  #subtitle { text-align: center; color: #bebebe; margin-top: 0; margin-bottom: 40px; font-size: 1.2rem; font-weight: 300; }
34
  .gr-button { font-weight: bold !important; }
35
-
36
- /* Main Content Card "Glassmorphism" effect */
37
  #main-card {
38
  background: rgba(22, 22, 34, 0.65);
39
  border-radius: 16px;
40
  box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
41
- backdrop-filter: blur(12px);
42
- -webkit-backdrop-filter: blur(12px);
43
  border: 1px solid rgba(255, 255, 255, 0.18);
44
  padding: 1rem;
45
  }
46
-
47
  /* Prediction Bar Styling */
48
  #predictions-column { background-color: transparent !important; padding: 1.5rem; }
49
- #predictions-column > .gr-label { display: none; } /* Hide the default Gradio label */
50
  .prediction-list { list-style-type: none; padding: 0; margin-top: 1.5rem; }
51
  .prediction-list li { display: flex; align-items: center; margin-bottom: 12px; font-size: 1.1rem; }
52
  .prediction-list .label { width: 100px; text-transform: capitalize; color: #e0e0e0; }
53
  .prediction-list .bar-container { flex-grow: 1; height: 24px; background-color: rgba(255,255,255,0.1); border-radius: 12px; margin: 0 15px; overflow: hidden; }
54
- .prediction-list .bar { height: 100%; background: linear-gradient(90deg, #8A2BE2, #C71585); border-radius: 12px; transition: width 0.1s linear; }
55
  .prediction-list .percent { width: 60px; text-align: right; font-weight: bold; color: #FFF; }
56
  footer { display: none !important; }
57
  """
58
 
59
  ABOUT_MARKDOWN = """
60
- ## 🚀 About This Project
61
-
62
- This application is a demonstration of a complete, end-to-end MLOps pipeline for facial emotion recognition. It showcases a full lifecycle from data research and model selection to deployment as a professional, interactive web application.
63
-
64
- ### Key Technical Features:
65
-
66
- * **State-of-the-Art AI Model:** Utilizes a **Swin Transformer**, a powerful Vision Transformer (ViT) architecture, pre-trained on the massive **AffectNet** dataset. This ensures high accuracy and robust generalization to real-world, "in the wild" facial expressions.
67
- * **Reproducible MLOps Pipeline:** The original model training and data processing workflows were built using **DVC (Data Version Control)**, ensuring that every experiment is versioned and reproducible.
68
- * **Full-Stack Architecture:** The initial project was built with a decoupled **FastAPI (Python) backend** and a **React (JavaScript) frontend**, demonstrating professional full-stack development practices. This Gradio app serves as the final, streamlined deployment.
69
- * **Containerized for Deployment:** The entire application is packaged with **Docker** and deployed via a **CI/CD pipeline using GitHub Actions**, enabling automated testing and deployment to cloud platforms like Hugging Face Spaces.
70
-
71
- ### Skills Demonstrated:
72
-
73
- * **Data Science:** Dataset research, analysis (CK+, FER+), and advanced data preparation techniques.
74
- * **Deep Learning:** Transfer learning, fine-tuning, and inference with modern architectures (MobileNetV2, Swin Transformer) using TensorFlow/Keras and Hugging Face `transformers`.
75
- * **MLOps:** Pipeline orchestration (DVC), experiment tracking (MLflow), and CI/CD automation (GitHub Actions).
76
- * **Software Engineering:** Python, UI/UX development (Gradio, React), API design (FastAPI), and containerization (Docker).
77
-
78
- This project represents a comprehensive understanding of building and productionizing modern AI systems.
79
  """
80
 
81
  # --- BACKEND LOGIC ---
82
-
83
  def create_prediction_html(probabilities):
84
  if not probabilities:
85
  return "<div style='padding: 2rem; text-align: center; color: #999;'>Waiting for prediction...</div>"
@@ -100,16 +81,13 @@ def unified_prediction_function(frame):
100
  """A single, unified function to process any frame (live or uploaded)."""
101
  if frame is None:
102
  return None, create_prediction_html({})
103
-
104
  # The predictor class handles all annotation and prediction logic
105
  annotated_frame, probabilities = predictor.process_frame(frame)
106
-
107
  return annotated_frame, create_prediction_html(probabilities)
108
 
109
  def process_video(video_path, progress=gr.Progress(track_tqdm=True)):
110
  """Processes an uploaded video file frame-by-frame."""
111
- if video_path is None:
112
- return None
113
  try:
114
  cap = cv2.VideoCapture(video_path)
115
  frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
@@ -143,7 +121,12 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base()) as demo:
143
  with gr.TabItem("Live Detection"):
144
  with gr.Row(equal_height=False):
145
  with gr.Column(scale=3):
146
- live_feed = gr.Image(source="webcam", streaming=True, type="numpy", label="Live Feed", height=550, mirror_webcam=True)
 
 
 
 
 
147
  with gr.Column(scale=2, elem_id="predictions-column"):
148
  live_predictions = gr.HTML()
149
 
@@ -165,13 +148,28 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base()) as demo:
165
  gr.Markdown(ABOUT_MARKDOWN)
166
 
167
  # --- EVENT LISTENERS ---
168
- live_feed.stream(fn=unified_prediction_function, inputs=live_feed, outputs=[live_feed, live_predictions])
169
- image_button.click(fn=unified_prediction_function, inputs=[image_input], outputs=[image_input, image_predictions])
170
- video_button.click(fn=process_video, inputs=[video_input], outputs=[video_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  # --- LAUNCH THE APP ---
173
  if predictor:
174
- # Enabling the queue is essential for the video processing progress bar and smooth operation
175
  demo.queue().launch(debug=True)
176
  else:
177
  print("\n[FATAL ERROR] Could not start the application.")
 
3
  import cv2
4
  import time
5
 
6
+ # Ensure the correct predictor class is imported
7
  from src.EmotionRecognition.pipeline.hf_predictor import HFPredictor
8
 
9
  # --- INITIALIZE THE MODEL ---
 
10
  print("[INFO] Initializing predictor...")
11
  try:
12
  predictor = HFPredictor()
 
22
  background: linear-gradient(-45deg, #0b0f19, #131a2d, #2a2a72, #522a72);
23
  background-size: 400% 400%;
24
  animation: gradient 15s ease infinite;
 
25
  }
26
  @keyframes gradient { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
 
27
  /* General Layout & Typography */
28
  .gradio-container { max-width: 1320px !important; margin: auto !important; }
29
  #title { text-align: center; font-size: 3rem !important; font-weight: 700; color: #FFF; margin-bottom: 0.5rem; }
30
  #subtitle { text-align: center; color: #bebebe; margin-top: 0; margin-bottom: 40px; font-size: 1.2rem; font-weight: 300; }
31
  .gr-button { font-weight: bold !important; }
32
+ /* Main Content Card */
 
33
  #main-card {
34
  background: rgba(22, 22, 34, 0.65);
35
  border-radius: 16px;
36
  box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
37
+ backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
 
38
  border: 1px solid rgba(255, 255, 255, 0.18);
39
  padding: 1rem;
40
  }
 
41
  /* Prediction Bar Styling */
42
  #predictions-column { background-color: transparent !important; padding: 1.5rem; }
43
+ #predictions-column > .gr-label { display: none; }
44
  .prediction-list { list-style-type: none; padding: 0; margin-top: 1.5rem; }
45
  .prediction-list li { display: flex; align-items: center; margin-bottom: 12px; font-size: 1.1rem; }
46
  .prediction-list .label { width: 100px; text-transform: capitalize; color: #e0e0e0; }
47
  .prediction-list .bar-container { flex-grow: 1; height: 24px; background-color: rgba(255,255,255,0.1); border-radius: 12px; margin: 0 15px; overflow: hidden; }
48
+ .prediction-list .bar { height: 100%; background: linear-gradient(90deg, #8A2BE2, #C71585); border-radius: 12px; transition: width: 0.1s linear; }
49
  .prediction-list .percent { width: 60px; text-align: right; font-weight: bold; color: #FFF; }
50
  footer { display: none !important; }
51
  """
52
 
53
  ABOUT_MARKDOWN = """
54
+ ### Model: Vision Transformer (ViT)
55
+ This application uses a Vision Transformer model, fine-tuned for facial emotion recognition.
56
+ ### Dataset
57
+ The model was fine-tuned on the **Emotion Recognition Dataset** from Kaggle, a large, curated collection of labeled facial images. This diverse dataset allows the model to generalize to a wide variety of real-world faces and expressions.
58
+ *Dataset Link:* [https://www.kaggle.com/datasets/sujaykapadnis/emotion-recognition-dataset](https://www.kaggle.com/datasets/sujaykapadnis/emotion-recognition-dataset)
59
+ ### MLOps Pipeline
60
+ This entire application, from data processing to training and deployment, was built using a reproducible MLOps pipeline, ensuring consistency and quality at every step.
 
 
 
 
 
 
 
 
 
 
 
 
61
  """
62
 
63
  # --- BACKEND LOGIC ---
 
64
  def create_prediction_html(probabilities):
65
  if not probabilities:
66
  return "<div style='padding: 2rem; text-align: center; color: #999;'>Waiting for prediction...</div>"
 
81
  """A single, unified function to process any frame (live or uploaded)."""
82
  if frame is None:
83
  return None, create_prediction_html({})
 
84
  # The predictor class handles all annotation and prediction logic
85
  annotated_frame, probabilities = predictor.process_frame(frame)
 
86
  return annotated_frame, create_prediction_html(probabilities)
87
 
88
  def process_video(video_path, progress=gr.Progress(track_tqdm=True)):
89
  """Processes an uploaded video file frame-by-frame."""
90
+ if video_path is None: return None
 
91
  try:
92
  cap = cv2.VideoCapture(video_path)
93
  frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
121
  with gr.TabItem("Live Detection"):
122
  with gr.Row(equal_height=False):
123
  with gr.Column(scale=3):
124
+ # --- THIS IS THE DEFINITIVE FIX ---
125
+ # We use TWO components. One is an INVISIBLE input to capture the stream.
126
+ # The other is a VISIBLE output to display the result.
127
+ webcam_capture = gr.Image(source="webcam", streaming=True, type="numpy", visible=False, mirror_webcam=True)
128
+ live_output = gr.Image(label="Live Feed", interactive=False, height=550)
129
+ # --- END FIX ---
130
  with gr.Column(scale=2, elem_id="predictions-column"):
131
  live_predictions = gr.HTML()
132
 
 
148
  gr.Markdown(ABOUT_MARKDOWN)
149
 
150
  # --- EVENT LISTENERS ---
151
+ # The .stream() event is attached to the INVISIBLE capture component.
152
+ # Its outputs are the VISIBLE components.
153
+ webcam_capture.stream(
154
+ fn=unified_prediction_function,
155
+ inputs=[webcam_capture],
156
+ outputs=[live_output, live_predictions]
157
+ )
158
+
159
+ image_button.click(
160
+ fn=unified_prediction_function,
161
+ inputs=[image_input],
162
+ outputs=[image_input, image_predictions]
163
+ )
164
+
165
+ video_button.click(
166
+ fn=process_video,
167
+ inputs=[video_input],
168
+ outputs=[video_output]
169
+ )
170
 
171
  # --- LAUNCH THE APP ---
172
  if predictor:
 
173
  demo.queue().launch(debug=True)
174
  else:
175
  print("\n[FATAL ERROR] Could not start the application.")