Bliss-Ruth commited on
Commit
3ab18de
·
verified ·
1 Parent(s): f4381e1

UPDATED app.PY

Browse files
Files changed (1) hide show
  1. app.py +191 -156
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py
2
  import torch
3
  import torch.nn as nn
4
  from transformers import XCLIPProcessor, XCLIPModel
@@ -6,61 +6,66 @@ import gradio as gr
6
  import cv2
7
  import numpy as np
8
  from PIL import Image
9
- import tempfile
10
- import os
11
  import pandas as pd
12
  from datetime import datetime
 
 
 
13
 
14
- # Your exact model class
15
- class XCLIPSignLanguageClassifier(nn.Module):
16
- def __init__(self, num_classes, feature_dim=512):
 
 
 
17
  super().__init__()
18
- self.xclip = XCLIPModel.from_pretrained("microsoft/xclip-base-patch32")
19
- for param in self.xclip.parameters():
20
- param.requires_grad = False
21
  self.classifier = nn.Sequential(
22
- nn.Dropout(0.5), nn.Linear(feature_dim, 128), nn.LayerNorm(128), nn.ReLU(),
23
- nn.Dropout(0.3), nn.Linear(128, 64), nn.LayerNorm(64), nn.ReLU(),
24
- nn.Dropout(0.2), nn.Linear(64, num_classes)
25
  )
26
 
27
- def forward(self, input_ids, attention_mask, pixel_values):
28
- with torch.no_grad():
29
- outputs = self.xclip(input_ids=input_ids, attention_mask=attention_mask,
30
- pixel_values=pixel_values, return_dict=True)
31
- video_embeds = outputs.video_embeds
32
- return self.classifier(video_embeds)
33
-
34
- print("🚀 Loading Ugandan Sign Language Model...")
35
 
36
- # Initialize
37
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
38
  processor = XCLIPProcessor.from_pretrained("microsoft/xclip-base-patch32")
 
 
39
 
40
  # Load your trained model
41
  try:
42
  checkpoint = torch.load("best_xclip_model.pth", map_location=device, weights_only=False)
43
- model = XCLIPSignLanguageClassifier(num_classes=len(checkpoint["id_to_label"])).to(device)
44
- model.load_state_dict(checkpoint["model_state_dict"])
 
 
 
 
45
  model.eval()
46
- id_to_label = checkpoint["id_to_label"]
 
47
  label_to_id = {v: k for k, v in id_to_label.items()}
48
- print(f"✅ Model loaded! Can recognize {len(id_to_label)} signs: {list(id_to_label.values())}")
 
 
49
  except Exception as e:
50
  print(f"❌ Error loading model: {e}")
51
  exit(1)
52
 
53
- # Feedback system
54
- FEEDBACK_FILE = "user_feedback.csv"
55
- if not os.path.exists(FEEDBACK_FILE):
56
- pd.DataFrame(columns=['timestamp', 'video_path', 'predicted_label', 'correct_label', 'confidence']).to_csv(FEEDBACK_FILE, index=False)
57
 
58
  def extract_frames(video_path, num_frames=8):
59
- """Extract frames from video file"""
60
  try:
61
  cap = cv2.VideoCapture(video_path)
62
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
63
 
 
 
 
 
64
  if total_frames <= num_frames:
65
  indices = list(range(total_frames)) + [total_frames-1] * (num_frames - total_frames)
66
  else:
@@ -77,15 +82,16 @@ def extract_frames(video_path, num_frames=8):
77
  frame = cv2.resize(frame, (224, 224))
78
  frames.append(Image.fromarray(frame))
79
  else:
80
- frames.append(Image.new("RGB", (224, 224), (128, 128, 128)))
 
81
  cap.release()
82
  return frames
 
83
  except Exception as e:
84
- print(f"Frame extraction error: {e}")
85
- return [Image.new("RGB", (224, 224), (128, 128, 128)) for _ in range(num_frames)]
86
 
87
- def predict_sign_enhanced(video_path):
88
- """Enhanced prediction with detailed outputs"""
89
  try:
90
  frames = extract_frames(video_path)
91
 
@@ -97,22 +103,36 @@ def predict_sign_enhanced(video_path):
97
  attention_mask = text_inputs['attention_mask'].to(device)
98
 
99
  with torch.no_grad():
100
- logits = model(input_ids, attention_mask, pixel_values)
 
 
 
 
 
 
 
 
101
  probs = torch.softmax(logits, dim=1)
102
  confidence, pred_class = torch.max(probs, 1)
103
- all_probs = probs.cpu().numpy()[0]
104
 
105
  predicted_label = id_to_label[pred_class.item()]
106
  confidence_value = confidence.item()
107
 
108
- return predicted_label, confidence_value, all_probs
109
 
110
  except Exception as e:
111
- print(f" Prediction error: {e}")
112
- return "Unknown", 0.0, []
 
 
 
 
 
 
 
113
 
114
  def save_feedback(video_path, predicted_label, correct_label, confidence):
115
- """Save user feedback and check if retraining is needed"""
116
  try:
117
  feedback_data = {
118
  'timestamp': datetime.now().isoformat(),
@@ -122,196 +142,211 @@ def save_feedback(video_path, predicted_label, correct_label, confidence):
122
  'confidence': confidence
123
  }
124
 
125
- # Save feedback
126
  df = pd.read_csv(FEEDBACK_FILE)
127
  df = pd.concat([df, pd.DataFrame([feedback_data])], ignore_index=True)
128
  df.to_csv(FEEDBACK_FILE, index=False)
129
 
130
- # Check if retraining is needed (5+ corrections)
131
  corrections = len(df[df['predicted_label'] != df['correct_label']])
132
 
133
  if corrections >= 5:
134
- return f"✅ Feedback saved! 🚀 {corrections} corrections collected - ready for retraining!"
135
  else:
136
- return f"✅ Feedback saved! 📊 {5-corrections} more corrections needed for retraining."
137
 
138
  except Exception as e:
139
  return f"❌ Error saving feedback: {str(e)}"
140
 
141
- def predict_video_enhanced(video_file):
142
- """Enhanced prediction function"""
143
- try:
144
- if video_file is None:
145
- return "## 📹 Please upload a video file", "", gr.update(visible=False), gr.update(value=None)
146
-
147
- predicted_label, confidence, all_probs = predict_sign_enhanced(video_file)
148
-
149
- # Create detailed results
150
- result = f"""
151
- ## 🎯 Sign Language Translation Result:
152
 
153
- ### **Detected Sign:** {predicted_label}
 
 
 
 
 
 
 
154
 
155
- ### **Confidence Level:** {confidence*100:.1f}%
 
 
 
 
156
 
157
- ### **Translation:** This sign means "{predicted_label}" in Ugandan Sign Language
 
 
 
 
158
 
159
- ---
 
 
 
 
 
 
 
 
 
 
 
160
 
161
- ## 📊 Detailed Analysis:
 
 
162
 
163
- **Confidence Breakdown:**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  """
 
 
 
 
 
 
165
 
166
- # Add confidence bars for each class
167
- for i, (label, prob) in enumerate(zip(id_to_label.values(), all_probs)):
168
- bar_length = int(prob * 20)
169
- bar = "█" * bar_length + "░" * (20 - bar_length)
170
- result += f"\n**{label}:** {bar} {prob*100:.1f}%"
171
-
172
- # Check feedback status
173
- try:
174
- feedback_df = pd.read_csv(FEEDBACK_FILE)
175
- corrections = len(feedback_df[feedback_df['predicted_label'] != feedback_df['correct_label']])
176
- result += f"\n\n---\n**📈 Learning Progress:** {corrections}/5 corrections collected for next retraining"
177
- except:
178
- result += f"\n\n---\n**📈 Learning Progress:** 0/5 corrections collected for next retraining"
179
 
180
- result += f"""
 
 
181
 
182
- ---
 
 
183
 
184
- ### 🔧 Model Information:
185
- - **Model:** X-CLIP Fine-tuned on Ugandan Sign Language
186
- - **Supported Signs:** {len(id_to_label)} classes
187
- - **Top Confidence:** {confidence*100:.1f}%
188
 
189
  ---
190
-
191
- **🤔 Was this prediction correct?** Use the feedback section below to help improve the model!
 
 
 
 
 
192
  """
193
 
194
- return result, predicted_label, gr.update(visible=True), video_file, confidence
195
 
196
  except Exception as e:
197
- return f"## ❌ Error Processing Video\n\n**Error:** {str(e)}", "", gr.update(visible=False), None, 0.0
198
 
199
- def submit_feedback_enhanced(predicted_label, user_correction, video_path, confidence):
200
- """Enhanced feedback handling"""
201
  if user_correction == "" or user_correction is None:
202
- return "⚠️ Please select the correct sign label"
203
 
204
  result = save_feedback(video_path, predicted_label, user_correction, confidence)
205
 
206
  if user_correction != predicted_label:
207
- result += f"\n\n🎯 **Correction:** '{predicted_label}''{user_correction}'"
208
- result += f"\n💡 Thank you for helping improve the model accuracy!"
209
 
210
  return result
211
 
212
- def get_feedback_stats():
213
- """Get current feedback statistics"""
214
- try:
215
- feedback_df = pd.read_csv(FEEDBACK_FILE)
216
- total = len(feedback_df)
217
- corrections = len(feedback_df[feedback_df['predicted_label'] != feedback_df['correct_label']])
218
- return f"**Feedback Collected:** {corrections} corrections ({total} total)\n**Retraining Ready:** { '✅' if corrections >= 5 else '❌' }"
219
- except:
220
- return "**Feedback Collected:** 0 corrections\n**Retraining Ready:** ❌"
221
-
222
- # Create the enhanced interface
223
- with gr.Blocks(
224
- theme=gr.themes.Soft(primary_hue="teal"),
225
- title="🤟 Ugandan Sign Language Translator"
226
- ) as demo:
227
 
228
  gr.Markdown("""
229
- # 🤟 Ugandan Sign Language Translation Tool
230
- ### *With Continuous Learning from User Feedback*
 
 
231
  """)
232
 
 
233
  with gr.Row():
 
234
  with gr.Column(scale=1):
235
  gr.Markdown("### 📤 Upload Video")
236
  video_input = gr.Video(
237
- label="Sign Language Video",
238
- sources=["upload"],
239
- height=300
240
  )
241
 
 
242
  with gr.Row():
243
- predict_btn = gr.Button("🚀 Analyze Sign", variant="primary", size="lg")
244
- clear_btn = gr.Button("🔄 Clear", variant="secondary")
245
 
246
- with gr.Column(scale=2):
247
- gr.Markdown("### 🎯 Analysis Results")
 
248
  results_output = gr.Markdown(
249
- value="## 📤 Upload a video to get started..."
250
  )
251
 
252
- # Hidden states
253
- current_prediction = gr.State()
254
- current_video_path = gr.State()
255
- current_confidence = gr.State()
256
-
257
- # Feedback section
258
- with gr.Row(visible=False) as feedback_row:
259
  with gr.Column():
260
- gr.Markdown("## 💡 Help Improve The Model")
261
  with gr.Row():
262
  correction_dropdown = gr.Dropdown(
263
  choices=list(id_to_label.values()),
264
- label="Select Correct Sign",
265
- scale=3
266
  )
267
- feedback_btn = gr.Button("📈 Submit Feedback", variant="primary", scale=1)
268
  feedback_output = gr.Markdown()
269
 
270
- # Statistics section
271
- with gr.Row():
272
- with gr.Column():
273
- gr.Markdown("### 📊 Learning Progress")
274
- stats_display = gr.Markdown()
275
-
276
- # Update stats function
277
- def update_stats():
278
- return get_feedback_stats()
279
 
280
  # Prediction logic
281
  predict_btn.click(
282
- fn=predict_video_enhanced,
283
  inputs=[video_input],
284
- outputs=[results_output, current_prediction, feedback_row, current_video_path, current_confidence]
285
- ).then(
286
- lambda: update_stats(),
287
- outputs=[stats_display]
288
  )
289
 
290
  # Feedback logic
291
  feedback_btn.click(
292
- fn=submit_feedback_enhanced,
293
  inputs=[current_prediction, correction_dropdown, current_video_path, current_confidence],
294
  outputs=[feedback_output]
295
- ).then(
296
- lambda: update_stats(),
297
- outputs=[stats_display]
298
  )
299
 
300
- # Clear button
301
- def clear_all():
302
- return None, "## 📤 Upload a video to get started...", "", gr.update(visible=False), None, 0.0, "", update_stats()
303
 
304
  clear_btn.click(
305
- fn=clear_all,
306
- outputs=[video_input, results_output, current_prediction, feedback_row, current_video_path, current_confidence, feedback_output, stats_display]
307
- )
308
-
309
- # Initialize stats
310
- demo.load(
311
- fn=update_stats,
312
- outputs=[stats_display]
313
  )
314
 
315
  # Launch the app
316
  if __name__ == "__main__":
317
- demo.launch(share=True)
 
 
 
1
+ # app.py - CLEAN MINIMAL INTERFACE (No Confidence Bars/Tabs)
2
  import torch
3
  import torch.nn as nn
4
  from transformers import XCLIPProcessor, XCLIPModel
 
6
  import cv2
7
  import numpy as np
8
  from PIL import Image
 
 
9
  import pandas as pd
10
  from datetime import datetime
11
+ import os
12
+
13
+ print("🚀 Loading Ugandan Sign Language Model...")
14
 
15
+ # ============================================================================
16
+ # MODEL SETUP
17
+ # ============================================================================
18
+
19
+ class MinimalClassifier(nn.Module):
20
+ def __init__(self, input_dim=512, num_classes=85, dropout=0.5):
21
  super().__init__()
 
 
 
22
  self.classifier = nn.Sequential(
23
+ nn.Dropout(dropout),
24
+ nn.Linear(input_dim, num_classes)
 
25
  )
26
 
27
+ def forward(self, x):
28
+ return self.classifier(x)
 
 
 
 
 
 
29
 
 
30
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
31
  processor = XCLIPProcessor.from_pretrained("microsoft/xclip-base-patch32")
32
+ xclip_model = XCLIPModel.from_pretrained("microsoft/xclip-base-patch32").to(device)
33
+ xclip_model.eval()
34
 
35
  # Load your trained model
36
  try:
37
  checkpoint = torch.load("best_xclip_model.pth", map_location=device, weights_only=False)
38
+ model = MinimalClassifier(
39
+ input_dim=512,
40
+ num_classes=checkpoint['num_classes'],
41
+ dropout=0.5
42
+ ).to(device)
43
+ model.load_state_dict(checkpoint['model_state_dict'])
44
  model.eval()
45
+
46
+ id_to_label = checkpoint['id_to_label']
47
  label_to_id = {v: k for k, v in id_to_label.items()}
48
+
49
+ print(f"✅ Model loaded! Can recognize {len(id_to_label)} signs")
50
+
51
  except Exception as e:
52
  print(f"❌ Error loading model: {e}")
53
  exit(1)
54
 
55
+ # ============================================================================
56
+ # CORE FUNCTIONS
57
+ # ============================================================================
 
58
 
59
  def extract_frames(video_path, num_frames=8):
60
+ """Extract frames from video"""
61
  try:
62
  cap = cv2.VideoCapture(video_path)
63
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
64
 
65
+ if total_frames == 0:
66
+ cap.release()
67
+ return [Image.new('RGB', (224, 224), (0, 0, 0)) for _ in range(num_frames)]
68
+
69
  if total_frames <= num_frames:
70
  indices = list(range(total_frames)) + [total_frames-1] * (num_frames - total_frames)
71
  else:
 
82
  frame = cv2.resize(frame, (224, 224))
83
  frames.append(Image.fromarray(frame))
84
  else:
85
+ frames.append(Image.new('RGB', (224, 224), (0, 0, 0)))
86
+
87
  cap.release()
88
  return frames
89
+
90
  except Exception as e:
91
+ return [Image.new('RGB', (224, 224), (0, 0, 0)) for _ in range(num_frames)]
 
92
 
93
+ def predict_sign(video_path):
94
+ """Predict sign from video"""
95
  try:
96
  frames = extract_frames(video_path)
97
 
 
103
  attention_mask = text_inputs['attention_mask'].to(device)
104
 
105
  with torch.no_grad():
106
+ outputs = xclip_model(
107
+ input_ids=input_ids,
108
+ attention_mask=attention_mask,
109
+ pixel_values=pixel_values,
110
+ return_dict=True
111
+ )
112
+ video_embeds = outputs.video_embeds
113
+
114
+ logits = model(video_embeds)
115
  probs = torch.softmax(logits, dim=1)
116
  confidence, pred_class = torch.max(probs, 1)
 
117
 
118
  predicted_label = id_to_label[pred_class.item()]
119
  confidence_value = confidence.item()
120
 
121
+ return predicted_label, confidence_value
122
 
123
  except Exception as e:
124
+ return "Unknown", 0.0
125
+
126
+ # ============================================================================
127
+ # FEEDBACK SYSTEM
128
+ # ============================================================================
129
+
130
+ FEEDBACK_FILE = "user_feedback.csv"
131
+ if not os.path.exists(FEEDBACK_FILE):
132
+ pd.DataFrame(columns=['timestamp', 'video_path', 'predicted_label', 'correct_label', 'confidence']).to_csv(FEEDBACK_FILE, index=False)
133
 
134
  def save_feedback(video_path, predicted_label, correct_label, confidence):
135
+ """Save user feedback"""
136
  try:
137
  feedback_data = {
138
  'timestamp': datetime.now().isoformat(),
 
142
  'confidence': confidence
143
  }
144
 
 
145
  df = pd.read_csv(FEEDBACK_FILE)
146
  df = pd.concat([df, pd.DataFrame([feedback_data])], ignore_index=True)
147
  df.to_csv(FEEDBACK_FILE, index=False)
148
 
 
149
  corrections = len(df[df['predicted_label'] != df['correct_label']])
150
 
151
  if corrections >= 5:
152
+ return f"✅ Thank you! Ready for model improvement ({corrections}/5)"
153
  else:
154
+ return f"✅ Thank you! {5-corrections} more needed for retraining"
155
 
156
  except Exception as e:
157
  return f"❌ Error saving feedback: {str(e)}"
158
 
159
+ # ============================================================================
160
+ # CLEAN GRADIO INTERFACE - MINIMAL
161
+ # ============================================================================
 
 
 
 
 
 
 
 
162
 
163
+ # Custom CSS for clean orange/black theme
164
+ custom_css = """
165
+ .gradio-container {
166
+ background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
167
+ font-family: 'Arial', sans-serif;
168
+ max-width: 900px !important;
169
+ margin: 0 auto !important;
170
+ }
171
 
172
+ h1 {
173
+ color: #ff6b35 !important;
174
+ text-align: center;
175
+ margin-bottom: 10px !important;
176
+ }
177
 
178
+ .gr-markdown p {
179
+ color: #cccccc !important;
180
+ text-align: center;
181
+ font-size: 16px !important;
182
+ }
183
 
184
+ .gr-box {
185
+ border: 2px dashed #ff6b35 !important;
186
+ background: #2d2d2d !important;
187
+ border-radius: 10px !important;
188
+ }
189
+
190
+ .primary {
191
+ background: #ff6b35 !important;
192
+ border: none !important;
193
+ color: white !important;
194
+ font-weight: bold !important;
195
+ }
196
 
197
+ .primary:hover {
198
+ background: #e55a2b !important;
199
+ }
200
 
201
+ .secondary {
202
+ background: #444444 !important;
203
+ border: 1px solid #ff6b35 !important;
204
+ color: white !important;
205
+ }
206
+
207
+ .secondary:hover {
208
+ background: #555555 !important;
209
+ }
210
+
211
+ .gr-dropdown {
212
+ background: #2d2d2d !important;
213
+ color: white !important;
214
+ border: 1px solid #ff6b35 !important;
215
+ }
216
+
217
+ /* Results styling */
218
+ .results-box {
219
+ background: #2d2d2d !important;
220
+ padding: 20px !important;
221
+ border-radius: 10px !important;
222
+ border-left: 4px solid #ff6b35 !important;
223
+ margin-top: 20px !important;
224
+ }
225
  """
226
+
227
+ def predict_video_clean(video_file):
228
+ """Clean prediction function - simple output only"""
229
+ try:
230
+ if video_file is None:
231
+ return "**Please upload a sign language video to get started.**", gr.update(visible=False)
232
 
233
+ predicted_label, confidence = predict_sign(video_file)
 
 
 
 
 
 
 
 
 
 
 
 
234
 
235
+ # SIMPLE CLEAN RESULTS - NO CONFIDENCE BARS
236
+ result = f"""
237
+ ## Sign Language Translation Result
238
 
239
+ **Detected Sign:** {predicted_label}
240
+
241
+ **Confidence:** {confidence*100:.1f}%
242
 
243
+ **Translation:** This sign means "{predicted_label}" in Ugandan Sign Language
 
 
 
244
 
245
  ---
246
+
247
+ **Model Information:**
248
+ - Model: X-CLIP Fine-tuned
249
+ - Classes: {len(id_to_label)} signs
250
+ - Training: Ugandan Sign Language Dataset
251
+
252
+ *Think the prediction is wrong? Help improve the model below.*
253
  """
254
 
255
+ return result, gr.update(visible=True), predicted_label, video_file, confidence
256
 
257
  except Exception as e:
258
+ return f"**Error processing video:** {str(e)}", gr.update(visible=False), "", None, 0.0
259
 
260
+ def submit_feedback_clean(predicted_label, user_correction, video_path, confidence):
261
+ """Clean feedback submission"""
262
  if user_correction == "" or user_correction is None:
263
+ return "Please select what the sign actually was."
264
 
265
  result = save_feedback(video_path, predicted_label, user_correction, confidence)
266
 
267
  if user_correction != predicted_label:
268
+ result += f"\n\nCorrection recorded: **{predicted_label}****{user_correction}**"
 
269
 
270
  return result
271
 
272
+ # ============================================================================
273
+ # CREATE CLEAN MINIMAL INTERFACE
274
+ # ============================================================================
275
+
276
+ with gr.Blocks(css=custom_css, title="Ugandan Sign Language Translator") as demo:
 
 
 
 
 
 
 
 
 
 
277
 
278
  gr.Markdown("""
279
+ # 🤟 Ugandan Sign Language Translator
280
+ *Upload a video of Ugandan Sign Language and get instant translation!*
281
+
282
+ **Supported signs:** hello, how, good, please, sign language, and more...
283
  """)
284
 
285
+ # Main content - simple two column layout
286
  with gr.Row():
287
+ # Left column - Upload
288
  with gr.Column(scale=1):
289
  gr.Markdown("### 📤 Upload Video")
290
  video_input = gr.Video(
291
+ label="",
292
+ sources=["upload"]
 
293
  )
294
 
295
+ # Action buttons
296
  with gr.Row():
297
+ predict_btn = gr.Button("🚀 Analyze Sign", variant="primary", scale=2)
298
+ clear_btn = gr.Button("🗑️ Clear", variant="secondary", scale=1)
299
 
300
+ # Right column - Results
301
+ with gr.Column(scale=1):
302
+ gr.Markdown("### 🎯 Results")
303
  results_output = gr.Markdown(
304
+ value="**Upload a sign language video to begin analysis.**"
305
  )
306
 
307
+ # Feedback section (hidden until needed)
308
+ with gr.Row(visible=False) as feedback_section:
 
 
 
 
 
309
  with gr.Column():
310
+ gr.Markdown("### 💡 Help Improve Accuracy")
311
  with gr.Row():
312
  correction_dropdown = gr.Dropdown(
313
  choices=list(id_to_label.values()),
314
+ label="If the prediction was wrong, select the correct sign:",
315
+ value=""
316
  )
317
+ feedback_btn = gr.Button("📝 Submit Correction", variant="secondary")
318
  feedback_output = gr.Markdown()
319
 
320
+ # Hidden states
321
+ current_prediction = gr.State()
322
+ current_video_path = gr.State()
323
+ current_confidence = gr.State()
 
 
 
 
 
324
 
325
  # Prediction logic
326
  predict_btn.click(
327
+ fn=predict_video_clean,
328
  inputs=[video_input],
329
+ outputs=[results_output, feedback_section, current_prediction, current_video_path, current_confidence]
 
 
 
330
  )
331
 
332
  # Feedback logic
333
  feedback_btn.click(
334
+ fn=submit_feedback_clean,
335
  inputs=[current_prediction, correction_dropdown, current_video_path, current_confidence],
336
  outputs=[feedback_output]
 
 
 
337
  )
338
 
339
+ # Clear button - resets everything
340
+ def clear_interface():
341
+ return None, "**Upload a sign language video to begin analysis.**", gr.update(visible=False), "", None, 0.0, ""
342
 
343
  clear_btn.click(
344
+ fn=clear_interface,
345
+ outputs=[video_input, results_output, feedback_section, current_prediction, current_video_path, current_confidence, feedback_output]
 
 
 
 
 
 
346
  )
347
 
348
  # Launch the app
349
  if __name__ == "__main__":
350
+ demo.launch(
351
+ share=True
352
+ )