ALYYAN commited on
Commit
26a026a
·
verified ·
1 Parent(s): a274192

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -46
app.py CHANGED
@@ -3,6 +3,7 @@ import os
3
  import cv2
4
  import time
5
 
 
6
  from src.EmotionRecognition.pipeline.hf_predictor import HFPredictor
7
 
8
  # --- INITIALIZE THE MODEL ---
@@ -23,11 +24,13 @@ body {
23
  animation: gradient 15s ease infinite;
24
  }
25
  @keyframes gradient { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
 
26
  /* General Layout & Typography */
27
  .gradio-container { max-width: 1320px !important; margin: auto !important; }
28
  #title { text-align: center; font-size: 3rem !important; font-weight: 700; color: #FFF; margin-bottom: 0.5rem; }
29
  #subtitle { text-align: center; color: #bebebe; margin-top: 0; margin-bottom: 40px; font-size: 1.2rem; font-weight: 300; }
30
  .gr-button { font-weight: bold !important; }
 
31
  /* Prediction Bar Styling */
32
  #predictions-column { background-color: rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 1.5rem; }
33
  #predictions-column > .gr-label { display: none; }
@@ -51,6 +54,7 @@ This entire application, from data processing to training and deployment, was bu
51
  """
52
 
53
  # --- BACKEND LOGIC ---
 
54
  def create_prediction_html(probabilities):
55
  if not probabilities:
56
  return "<div style='padding: 2rem; text-align: center; color: #999;'>Waiting for prediction...</div>"
@@ -67,35 +71,13 @@ def create_prediction_html(probabilities):
67
  html += "</ul>"
68
  return html
69
 
70
- # --- THIS IS THE FIX ---
71
- # The function MUST accept the 'stream_state' argument that Gradio sends to it.
72
- def live_detection_stream(stream_state):
73
- if stream_state != "Start":
74
- yield None, create_prediction_html({})
75
- return
76
-
77
- cap = cv2.VideoCapture(0)
78
- if not cap.isOpened():
79
- print("[ERROR] Cannot open webcam")
80
- return
81
 
82
- try:
83
- while True:
84
- # We need to check the state inside the loop as well for the 'cancels' to work
85
- if gr.State.is_yield_break():
86
- break
87
- ret, frame = cap.read()
88
- if not ret:
89
- time.sleep(0.01)
90
- continue
91
-
92
- frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
93
- annotated_frame, probabilities = predictor.process_frame(frame_rgb)
94
- yield annotated_frame, create_prediction_html(probabilities)
95
- finally:
96
- print("[INFO] Live feed stopped. Releasing webcam.")
97
- cap.release()
98
- # --- END FIX ---
99
 
100
  def process_image(image):
101
  if image is None: return None, create_prediction_html({})
@@ -103,8 +85,29 @@ def process_image(image):
103
  return annotated_frame, create_prediction_html(probabilities)
104
 
105
  def process_video(video_path, progress=gr.Progress(track_tqdm=True)):
106
- # ... (this function is correct)
107
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
  # --- GRADIO UI ---
110
  with gr.Blocks(css=CSS, theme=gr.themes.Base()) as demo:
@@ -115,41 +118,45 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base()) as demo:
115
  with gr.TabItem("Live Detection"):
116
  with gr.Row(equal_height=True):
117
  with gr.Column(scale=3):
118
- live_output = gr.Image(label="Live Feed", interactive=False, height=550)
 
119
  with gr.Column(scale=2, elem_id="predictions-column"):
120
  gr.Markdown("### Emotion Probabilities")
121
  live_predictions = gr.HTML()
122
- with gr.Row():
123
- start_button = gr.Button("Start Webcam", variant="primary", scale=1)
124
- stop_button = gr.Button("Stop Webcam", variant="secondary", scale=1)
125
- stream_state = gr.State("Start") # Default to Start, will be triggered by button
126
-
127
- # ... (Other tabs are correct)
128
  with gr.TabItem("Upload Image"):
129
  with gr.Row(equal_height=True):
130
  with gr.Column(scale=3):
131
  image_input = gr.Image(type="numpy", label="Upload an Image", height=550)
132
  with gr.Column(scale=2, elem_id="predictions-column"):
133
  image_predictions = gr.HTML()
134
- # This line needs to be indented to be part of the "Upload Image" TabItem
135
  image_button = gr.Button("Analyze Image", variant="primary")
136
 
 
 
 
 
 
 
 
 
 
137
  # --- EVENT LISTENERS ---
138
- # We assign the event to a variable so we can cancel it
139
- live_event = start_button.click(
 
 
140
  fn=live_detection_stream,
141
- inputs=stream_state,
142
- outputs=[live_output, live_predictions],
143
- # No 'cancels' on the start event
144
  )
145
- # The stop button's only job is to cancel the running live_event
146
- stop_button.click(fn=None, inputs=None, outputs=None, cancels=[live_event])
147
 
148
  image_button.click(process_image, [image_input], [image_input, image_predictions])
 
149
 
150
  # --- LAUNCH THE APP ---
151
  if predictor:
152
- # Remove share=True as it's not needed and causes a warning on Spaces
153
  demo.queue().launch(debug=True)
154
  else:
155
  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 ---
 
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
+
28
  /* General Layout & Typography */
29
  .gradio-container { max-width: 1320px !important; margin: auto !important; }
30
  #title { text-align: center; font-size: 3rem !important; font-weight: 700; color: #FFF; margin-bottom: 0.5rem; }
31
  #subtitle { text-align: center; color: #bebebe; margin-top: 0; margin-bottom: 40px; font-size: 1.2rem; font-weight: 300; }
32
  .gr-button { font-weight: bold !important; }
33
+
34
  /* Prediction Bar Styling */
35
  #predictions-column { background-color: rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 1.5rem; }
36
  #predictions-column > .gr-label { display: none; }
 
54
  """
55
 
56
  # --- BACKEND LOGIC ---
57
+
58
  def create_prediction_html(probabilities):
59
  if not probabilities:
60
  return "<div style='padding: 2rem; text-align: center; color: #999;'>Waiting for prediction...</div>"
 
71
  html += "</ul>"
72
  return html
73
 
74
+ def live_detection_stream(frame):
75
+ """The main function for the live feed. Receives a frame, returns annotated frame and predictions."""
76
+ if frame is None:
77
+ return None, create_prediction_html({})
 
 
 
 
 
 
 
78
 
79
+ annotated_frame, probabilities = predictor.process_frame(frame)
80
+ return annotated_frame, create_prediction_html(probabilities)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  def process_image(image):
83
  if image is None: return None, create_prediction_html({})
 
85
  return annotated_frame, create_prediction_html(probabilities)
86
 
87
  def process_video(video_path, progress=gr.Progress(track_tqdm=True)):
88
+ if video_path is None: return None
89
+ try:
90
+ cap = cv2.VideoCapture(video_path)
91
+ frame_count = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
92
+ output_path = "processed_video.mp4"
93
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
94
+ fps = cap.get(cv2.CAP_PROP_FPS)
95
+ width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
96
+ height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
97
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
98
+ for _ in progress.tqdm(range(frame_count), desc="Processing Video"):
99
+ ret, frame = cap.read()
100
+ if not ret: break
101
+ frame_rgb = cv2.cvtColor(frame, cv.COLOR_BGR2RGB)
102
+ annotated_frame, _ = predictor.process_frame(frame_rgb)
103
+ if annotated_frame is not None:
104
+ out.write(cv2.cvtColor(annotated_frame, cv.COLOR_RGB2BGR))
105
+ cap.release()
106
+ out.release()
107
+ return output_path
108
+ except Exception as e:
109
+ print(f"[ERROR] Video processing failed: {e}")
110
+ return None
111
 
112
  # --- GRADIO UI ---
113
  with gr.Blocks(css=CSS, theme=gr.themes.Base()) as demo:
 
118
  with gr.TabItem("Live Detection"):
119
  with gr.Row(equal_height=True):
120
  with gr.Column(scale=3):
121
+ # The definitive, simple, and correct way to do a live feed in Gradio v3
122
+ live_feed = gr.Image(source="webcam", streaming=True, type="numpy", label="Live Feed", interactive=False, height=550)
123
  with gr.Column(scale=2, elem_id="predictions-column"):
124
  gr.Markdown("### Emotion Probabilities")
125
  live_predictions = gr.HTML()
126
+
 
 
 
 
 
127
  with gr.TabItem("Upload Image"):
128
  with gr.Row(equal_height=True):
129
  with gr.Column(scale=3):
130
  image_input = gr.Image(type="numpy", label="Upload an Image", height=550)
131
  with gr.Column(scale=2, elem_id="predictions-column"):
132
  image_predictions = gr.HTML()
 
133
  image_button = gr.Button("Analyze Image", variant="primary")
134
 
135
+ with gr.TabItem("Upload Video"):
136
+ with gr.Row(equal_height=True):
137
+ video_input = gr.Video(label="Upload a Video File")
138
+ video_output = gr.Video(label="Processed Video")
139
+ video_button = gr.Button("Analyze Video", variant="primary")
140
+
141
+ with gr.TabItem("About"):
142
+ gr.Markdown(ABOUT_MARKDOWN)
143
+
144
  # --- EVENT LISTENERS ---
145
+
146
+ # The .stream() event is the correct way to link a streaming input.
147
+ # It automatically handles starting and stopping. There is no need for separate buttons.
148
+ live_feed.stream(
149
  fn=live_detection_stream,
150
+ inputs=[live_feed],
151
+ outputs=[live_feed, live_predictions],
 
152
  )
 
 
153
 
154
  image_button.click(process_image, [image_input], [image_input, image_predictions])
155
+ video_button.click(process_video, [video_input], [video_output])
156
 
157
  # --- LAUNCH THE APP ---
158
  if predictor:
159
+ # Enabling the queue is essential for the video processing progress bar
160
  demo.queue().launch(debug=True)
161
  else:
162
  print("\n[FATAL ERROR] Could not start the application.")