isha0110 commited on
Commit
5a72acd
·
verified ·
1 Parent(s): 43b9c59

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +278 -63
app.py CHANGED
@@ -9,6 +9,7 @@ MODEL_NAME = "roberta-base"
9
  MAX_LEN = 200
10
  EMOTIONS = ["anger", "fear", "joy", "sadness", "surprise"]
11
  EMOTION_EMOJIS = ["😠", "😨", "😊", "😢", "😲"]
 
12
 
13
  # Model Architecture (MUST MATCH TRAINING)
14
  class RobertaEmotion(nn.Module):
@@ -30,7 +31,7 @@ class RobertaEmotion(nn.Module):
30
  return logits
31
 
32
  # Load model and tokenizer
33
- print("🔄 Loading model and tokenizer...")
34
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
35
  print(f"📱 Device: {device}")
36
 
@@ -44,7 +45,7 @@ try:
44
  model = model.to(device)
45
  model.eval()
46
 
47
- print("✅ Model loaded successfully!")
48
  except Exception as e:
49
  print(f"⚠️ Error loading model: {e}")
50
  raise e
@@ -53,9 +54,15 @@ except Exception as e:
53
  BEST_THRESHOLDS = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
54
 
55
  def predict_emotions(text):
56
- """Predict emotions from text"""
57
  if not text or not text.strip():
58
- return "⚠️ Please enter some text to analyze"
 
 
 
 
 
 
59
 
60
  try:
61
  # Tokenize
@@ -78,29 +85,118 @@ def predict_emotions(text):
78
  # Apply thresholds
79
  predictions = (probs > BEST_THRESHOLDS).astype(int)
80
 
81
- # Format results
82
- detected = []
83
- output = "## 🎯 Detected Emotions:\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- for emotion, emoji, prob, pred in zip(EMOTIONS, EMOTION_EMOJIS, probs, predictions):
86
- if pred == 1:
87
- detected.append(f"{emoji} **{emotion.capitalize()}**")
88
 
89
  if detected:
90
- output += ", ".join(detected) + "\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  else:
92
- output += "*No strong emotions detected (all below threshold)*\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
- output += "## 📊 All Probabilities:\n\n"
95
- for emotion, emoji, prob in zip(EMOTIONS, EMOTION_EMOJIS, probs):
96
- bar_length = int(prob * 20)
97
- bar = "█" * bar_length + "░" * (20 - bar_length)
98
- output += f"{emoji} **{emotion.capitalize()}**: {bar} {prob:.1%}\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
- return output
 
 
101
 
102
  except Exception as e:
103
- return f"⚠️ Error: {str(e)}"
 
 
 
 
 
 
 
104
 
105
  # Example texts
106
  examples = [
@@ -112,67 +208,186 @@ examples = [
112
  ["I'm excited but also nervous about starting my new job next week."],
113
  ]
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  # Create Gradio Interface
116
- with gr.Blocks() as demo:
117
- gr.Markdown(
118
- """
119
- # 😊 Multi-Label Emotion Classification
120
-
121
- Detect **multiple emotions** in text using a fine-tuned RoBERTa transformer.
122
-
123
- **Emotions:** 😠 Anger | 😨 Fear | 😊 Joy | 😢 Sadness | 😲 Surprise
124
- """
125
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  with gr.Row():
128
- with gr.Column():
129
  text_input = gr.Textbox(
130
- label="Enter your text",
131
- placeholder="Type or paste text here to analyze emotions...",
132
- lines=5
 
133
  )
134
- analyze_btn = gr.Button("🔮 Analyze Emotions", variant="primary")
135
- clear_btn = gr.Button("🗑️ Clear")
 
136
 
137
- with gr.Column():
138
- output = gr.Markdown(label="Analysis Results")
 
 
 
 
 
 
 
139
 
140
  gr.Examples(
141
  examples=examples,
142
  inputs=text_input,
143
  outputs=output,
144
  fn=predict_emotions,
145
- cache_examples=False
 
146
  )
147
 
148
- gr.Markdown(
149
- """
150
- ---
151
- ## 📈 How It Works
152
-
153
- This is a **multi-label classification** model - each text can have multiple emotions!
154
-
155
- ### 🎯 Model Details
156
- - **Architecture**: RoBERTa-base (125M parameters)
157
- - **Max Length**: 200 tokens
158
- - **Training**: BCE Loss + Label Smoothing (0.05)
159
- - **Evaluation**: Macro F1-Score with per-class threshold tuning
160
-
161
- ### 🏗️ Architecture Flow
162
- ```
163
- Input Text Tokenizer RoBERTa Encoder → [CLS] Pooling →
164
- Dropout (0.35) → Linear (768→5) → Sigmoid → 5 Emotion Probabilities
165
- ```
166
-
167
- ---
168
- **Project**: 2025 Sep DLGenAI Course | **Built with**: PyTorch + Transformers + Gradio
169
- """
170
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  # Event handlers
173
  analyze_btn.click(fn=predict_emotions, inputs=text_input, outputs=output)
174
- clear_btn.click(fn=lambda: ("", ""), inputs=None, outputs=[text_input, output])
 
 
 
 
 
 
 
 
 
 
 
175
  text_input.submit(fn=predict_emotions, inputs=text_input, outputs=output)
176
 
177
  if __name__ == "__main__":
178
- demo.launch()
 
9
  MAX_LEN = 200
10
  EMOTIONS = ["anger", "fear", "joy", "sadness", "surprise"]
11
  EMOTION_EMOJIS = ["😠", "😨", "😊", "😢", "😲"]
12
+ EMOTION_COLORS = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6"]
13
 
14
  # Model Architecture (MUST MATCH TRAINING)
15
  class RobertaEmotion(nn.Module):
 
31
  return logits
32
 
33
  # Load model and tokenizer
34
+ print("🔄 Loading EmotiScan model...")
35
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
36
  print(f"📱 Device: {device}")
37
 
 
45
  model = model.to(device)
46
  model.eval()
47
 
48
+ print("✅ EmotiScan ready!")
49
  except Exception as e:
50
  print(f"⚠️ Error loading model: {e}")
51
  raise e
 
54
  BEST_THRESHOLDS = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
55
 
56
  def predict_emotions(text):
57
+ """Predict emotions from text with enhanced visualization"""
58
  if not text or not text.strip():
59
+ return """
60
+ <div style="text-align: center; padding: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 16px; color: white;">
61
+ <div style="font-size: 48px; margin-bottom: 16px;">🤔</div>
62
+ <div style="font-size: 20px; font-weight: 600;">Waiting for your text...</div>
63
+ <div style="font-size: 14px; opacity: 0.9; margin-top: 8px;">Enter some text above to analyze emotions</div>
64
+ </div>
65
+ """
66
 
67
  try:
68
  # Tokenize
 
85
  # Apply thresholds
86
  predictions = (probs > BEST_THRESHOLDS).astype(int)
87
 
88
+ # Build beautiful HTML output
89
+ html = """
90
+ <style>
91
+ @keyframes fadeIn {
92
+ from { opacity: 0; transform: translateY(10px); }
93
+ to { opacity: 1; transform: translateY(0); }
94
+ }
95
+ @keyframes pulse {
96
+ 0%, 100% { transform: scale(1); }
97
+ 50% { transform: scale(1.05); }
98
+ }
99
+ .emotion-card {
100
+ animation: fadeIn 0.5s ease-out;
101
+ transition: all 0.3s ease;
102
+ }
103
+ .emotion-card:hover {
104
+ transform: translateY(-4px);
105
+ box-shadow: 0 8px 24px rgba(0,0,0,0.15);
106
+ }
107
+ .detected-badge {
108
+ animation: pulse 2s infinite;
109
+ }
110
+ .progress-bar {
111
+ transition: width 0.8s ease-out;
112
+ }
113
+ </style>
114
+ """
115
 
116
+ # Detected emotions section
117
+ detected = [(emotion, emoji, prob, color) for emotion, emoji, prob, pred, color
118
+ in zip(EMOTIONS, EMOTION_EMOJIS, probs, predictions, EMOTION_COLORS) if pred == 1]
119
 
120
  if detected:
121
+ html += """
122
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
123
+ padding: 24px; border-radius: 16px; margin-bottom: 24px; text-align: center;">
124
+ <div style="color: white; font-size: 18px; font-weight: 600; margin-bottom: 16px;">
125
+ 🎯 Detected Emotions
126
+ </div>
127
+ <div style="display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;">
128
+ """
129
+ for emotion, emoji, prob, color in detected:
130
+ html += f"""
131
+ <div class="detected-badge" style="background: white; padding: 12px 20px;
132
+ border-radius: 24px; display: flex; align-items: center; gap: 8px;
133
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
134
+ <span style="font-size: 24px;">{emoji}</span>
135
+ <span style="font-weight: 600; color: {color}; text-transform: capitalize;">
136
+ {emotion}
137
+ </span>
138
+ <span style="background: {color}; color: white; padding: 2px 8px;
139
+ border-radius: 12px; font-size: 12px; font-weight: 600;">
140
+ {prob:.0%}
141
+ </span>
142
+ </div>
143
+ """
144
+ html += "</div></div>"
145
  else:
146
+ html += """
147
+ <div style="background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
148
+ padding: 24px; border-radius: 16px; margin-bottom: 24px; text-align: center; color: white;">
149
+ <div style="font-size: 32px; margin-bottom: 8px;">😐</div>
150
+ <div style="font-size: 16px; font-weight: 600;">No Strong Emotions Detected</div>
151
+ <div style="font-size: 14px; opacity: 0.8; margin-top: 4px;">All emotions below threshold</div>
152
+ </div>
153
+ """
154
+
155
+ # All emotions with progress bars
156
+ html += """
157
+ <div style="background: white; padding: 24px; border-radius: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
158
+ <div style="font-size: 18px; font-weight: 600; margin-bottom: 20px; color: #1f2937;">
159
+ 📊 Emotion Breakdown
160
+ </div>
161
+ <div style="display: flex; flex-direction: column; gap: 16px;">
162
+ """
163
 
164
+ for emotion, emoji, prob, color in zip(EMOTIONS, EMOTION_EMOJIS, probs, EMOTION_COLORS):
165
+ html += f"""
166
+ <div class="emotion-card" style="background: #f9fafb; padding: 16px; border-radius: 12px;
167
+ border-left: 4px solid {color};">
168
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
169
+ <div style="display: flex; align-items: center; gap: 10px;">
170
+ <span style="font-size: 28px;">{emoji}</span>
171
+ <span style="font-weight: 600; color: #374151; text-transform: capitalize; font-size: 16px;">
172
+ {emotion}
173
+ </span>
174
+ </div>
175
+ <span style="font-weight: 700; color: {color}; font-size: 18px;">
176
+ {prob:.1%}
177
+ </span>
178
+ </div>
179
+ <div style="background: #e5e7eb; height: 12px; border-radius: 6px; overflow: hidden;">
180
+ <div class="progress-bar" style="background: linear-gradient(90deg, {color}, {color}dd);
181
+ height: 100%; width: {prob*100}%; border-radius: 6px;
182
+ box-shadow: 0 0 8px {color}66;"></div>
183
+ </div>
184
+ </div>
185
+ """
186
 
187
+ html += "</div></div>"
188
+
189
+ return html
190
 
191
  except Exception as e:
192
+ return f"""
193
+ <div style="background: #fef2f2; border: 2px solid #ef4444; padding: 20px;
194
+ border-radius: 12px; color: #991b1b;">
195
+ <div style="font-size: 24px; margin-bottom: 8px;">⚠️</div>
196
+ <div style="font-weight: 600; margin-bottom: 4px;">Analysis Error</div>
197
+ <div style="font-size: 14px;">{str(e)}</div>
198
+ </div>
199
+ """
200
 
201
  # Example texts
202
  examples = [
 
208
  ["I'm excited but also nervous about starting my new job next week."],
209
  ]
210
 
211
+ # Custom CSS
212
+ custom_css = """
213
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
214
+
215
+ * {
216
+ font-family: 'Inter', sans-serif !important;
217
+ }
218
+
219
+ .gradio-container {
220
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%) !important;
221
+ }
222
+
223
+ #component-0 {
224
+ max-width: 1200px !important;
225
+ margin: auto !important;
226
+ }
227
+
228
+ .app-header {
229
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
230
+ padding: 40px;
231
+ border-radius: 20px;
232
+ margin-bottom: 30px;
233
+ text-align: center;
234
+ color: white;
235
+ box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
236
+ }
237
+
238
+ button {
239
+ border-radius: 12px !important;
240
+ font-weight: 600 !important;
241
+ transition: all 0.3s ease !important;
242
+ }
243
+
244
+ button:hover {
245
+ transform: translateY(-2px) !important;
246
+ box-shadow: 0 6px 20px rgba(0,0,0,0.15) !important;
247
+ }
248
+
249
+ .primary-btn {
250
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
251
+ }
252
+
253
+ textarea {
254
+ border-radius: 12px !important;
255
+ border: 2px solid #e5e7eb !important;
256
+ transition: all 0.3s ease !important;
257
+ }
258
+
259
+ textarea:focus {
260
+ border-color: #667eea !important;
261
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
262
+ }
263
+ """
264
+
265
  # Create Gradio Interface
266
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
267
+ gr.HTML("""
268
+ <div class="app-header">
269
+ <div style="font-size: 56px; margin-bottom: 16px;">🎭</div>
270
+ <h1 style="font-size: 48px; font-weight: 700; margin: 0 0 12px 0; text-shadow: 0 2px 4px rgba(0,0,0,0.1);">
271
+ EmotiScan
272
+ </h1>
273
+ <p style="font-size: 20px; opacity: 0.95; margin: 0; font-weight: 500;">
274
+ AI-Powered Multi-Emotion Detection
275
+ </p>
276
+ <div style="margin-top: 20px; display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;">
277
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 14px;">
278
+ 😠 Anger
279
+ </span>
280
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 14px;">
281
+ 😨 Fear
282
+ </span>
283
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 14px;">
284
+ 😊 Joy
285
+ </span>
286
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 14px;">
287
+ 😢 Sadness
288
+ </span>
289
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 14px;">
290
+ 😲 Surprise
291
+ </span>
292
+ </div>
293
+ </div>
294
+ """)
295
 
296
  with gr.Row():
297
+ with gr.Column(scale=1):
298
  text_input = gr.Textbox(
299
+ label="📝 Your Text",
300
+ placeholder="Type or paste your text here to discover the emotions within...",
301
+ lines=8,
302
+ max_lines=12
303
  )
304
+ with gr.Row():
305
+ analyze_btn = gr.Button("🔮 Analyze Emotions", variant="primary", size="lg")
306
+ clear_btn = gr.Button("🗑️ Clear", size="lg")
307
 
308
+ with gr.Column(scale=1):
309
+ output = gr.HTML(label="Analysis Results", value="""
310
+ <div style="text-align: center; padding: 60px 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
311
+ border-radius: 16px; color: white; height: 100%;">
312
+ <div style="font-size: 64px; margin-bottom: 20px;">🎭</div>
313
+ <div style="font-size: 24px; font-weight: 700; margin-bottom: 12px;">Welcome to EmotiScan</div>
314
+ <div style="font-size: 16px; opacity: 0.9;">Enter text to begin emotional analysis</div>
315
+ </div>
316
+ """)
317
 
318
  gr.Examples(
319
  examples=examples,
320
  inputs=text_input,
321
  outputs=output,
322
  fn=predict_emotions,
323
+ cache_examples=False,
324
+ label="💡 Try These Examples"
325
  )
326
 
327
+ gr.HTML("""
328
+ <div style="background: white; padding: 32px; border-radius: 16px; margin-top: 30px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
329
+ <h2 style="color: #1f2937; margin-bottom: 20px; font-size: 24px; font-weight: 700;">
330
+ 🧠 About EmotiScan
331
+ </h2>
332
+ <p style="color: #4b5563; line-height: 1.8; margin-bottom: 24px; font-size: 15px;">
333
+ EmotiScan uses state-of-the-art deep learning to detect multiple emotions simultaneously in text.
334
+ Unlike traditional single-emotion classifiers, our model recognizes that human expression is complex
335
+ and nuanced—one piece of text can convey multiple emotions at once.
336
+ </p>
337
+
338
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-top: 24px;">
339
+ <div style="background: linear-gradient(135deg, #667eea22 0%, #764ba222 100%); padding: 20px; border-radius: 12px;">
340
+ <div style="font-size: 32px; margin-bottom: 8px;">🤖</div>
341
+ <div style="font-weight: 600; color: #1f2937; margin-bottom: 4px;">Model</div>
342
+ <div style="color: #6b7280; font-size: 14px;">RoBERTa-base (125M params)</div>
343
+ </div>
344
+ <div style="background: linear-gradient(135deg, #10b98122 0%, #059669 22 100%); padding: 20px; border-radius: 12px;">
345
+ <div style="font-size: 32px; margin-bottom: 8px;">🎯</div>
346
+ <div style="font-weight: 600; color: #1f2937; margin-bottom: 4px;">Accuracy</div>
347
+ <div style="color: #6b7280; font-size: 14px;">Optimized F1-Score per class</div>
348
+ </div>
349
+ <div style="background: linear-gradient(135deg, #f59e0b22 0%, #d9770622 100%); padding: 20px; border-radius: 12px;">
350
+ <div style="font-size: 32px; margin-bottom: 8px;">⚡</div>
351
+ <div style="font-weight: 600; color: #1f2937; margin-bottom: 4px;">Speed</div>
352
+ <div style="color: #6b7280; font-size: 14px;">Real-time inference</div>
353
+ </div>
354
+ </div>
355
+
356
+ <div style="margin-top: 32px; padding: 20px; background: #f9fafb; border-radius: 12px; border-left: 4px solid #667eea;">
357
+ <div style="font-weight: 600; color: #1f2937; margin-bottom: 12px; font-size: 16px;">
358
+ 📚 Technical Details
359
+ </div>
360
+ <ul style="color: #4b5563; line-height: 2; margin: 0; padding-left: 20px; font-size: 14px;">
361
+ <li><strong>Architecture:</strong> Transformer encoder with classification head</li>
362
+ <li><strong>Training:</strong> BCE Loss with label smoothing (0.05)</li>
363
+ <li><strong>Max Tokens:</strong> 200 tokens per input</li>
364
+ <li><strong>Dropout:</strong> 0.35 for regularization</li>
365
+ <li><strong>Multi-Label:</strong> Each emotion is independently predicted</li>
366
+ </ul>
367
+ </div>
368
+
369
+ <div style="margin-top: 24px; text-align: center; color: #9ca3af; font-size: 14px;">
370
+ <p style="margin: 0;">Built with PyTorch • Transformers • Gradio</p>
371
+ <p style="margin: 4px 0 0 0;">2025 Sep DLGenAI Course Project</p>
372
+ </div>
373
+ </div>
374
+ """)
375
 
376
  # Event handlers
377
  analyze_btn.click(fn=predict_emotions, inputs=text_input, outputs=output)
378
+ clear_btn.click(
379
+ fn=lambda: ("", """
380
+ <div style="text-align: center; padding: 60px 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
381
+ border-radius: 16px; color: white; height: 100%;">
382
+ <div style="font-size: 64px; margin-bottom: 20px;">🎭</div>
383
+ <div style="font-size: 24px; font-weight: 700; margin-bottom: 12px;">Welcome to EmotiScan</div>
384
+ <div style="font-size: 16px; opacity: 0.9;">Enter text to begin emotional analysis</div>
385
+ </div>
386
+ """),
387
+ inputs=None,
388
+ outputs=[text_input, output]
389
+ )
390
  text_input.submit(fn=predict_emotions, inputs=text_input, outputs=output)
391
 
392
  if __name__ == "__main__":
393
+ demo.launch(share=True, server_name="0.0.0.0")