hamxaameer commited on
Commit
86fc75b
Β·
verified Β·
1 Parent(s): 9cc2ace

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +227 -395
app.py CHANGED
@@ -1,463 +1,295 @@
1
  import gradio as gr
 
2
  import pickle
3
  import pandas as pd
4
  import os
 
5
 
6
- # Recreate the bias corrector classes to match the saved model
7
- class BiasCorrector:
8
- def __init__(self, target_distribution=None):
9
- """Initialize bias corrector with target distribution"""
10
- if target_distribution is None:
11
- self.target_distribution = {'negative': 0.33, 'neutral': 0.34, 'positive': 0.33}
12
- else:
13
- self.target_distribution = target_distribution
14
-
15
- self.confidence_threshold = 0.7
16
- self.bias_correction_factor = 0.15
17
-
18
- def correct_prediction(self, prediction_result):
19
- """Apply bias correction to a prediction result"""
20
- if not isinstance(prediction_result, dict):
21
- return prediction_result
22
-
23
- if 'scores' not in prediction_result:
24
- return prediction_result
25
-
26
- scores = prediction_result['scores']
27
- original_sentiment = prediction_result['sentiment']
28
- confidence = prediction_result['confidence']
29
-
30
- if confidence < self.confidence_threshold:
31
- corrected_scores = scores.copy()
32
-
33
- if original_sentiment == 'negative' and confidence < 0.6:
34
- corrected_scores['positive'] += self.bias_correction_factor
35
- corrected_scores['neutral'] += self.bias_correction_factor * 0.5
36
- corrected_scores['negative'] -= self.bias_correction_factor * 1.5
37
- elif original_sentiment == 'positive' and confidence < 0.5:
38
- corrected_scores['positive'] += self.bias_correction_factor * 0.5
39
-
40
- total = sum(corrected_scores.values())
41
- corrected_scores = {k: v/total for k, v in corrected_scores.items()}
42
-
43
- new_sentiment = max(corrected_scores, key=corrected_scores.get)
44
- new_confidence = corrected_scores[new_sentiment]
45
-
46
- return {
47
- 'sentiment': new_sentiment,
48
- 'confidence': new_confidence,
49
- 'scores': corrected_scores,
50
- 'original_sentiment': original_sentiment,
51
- 'bias_corrected': True
52
- }
53
-
54
- prediction_result['bias_corrected'] = False
55
- return prediction_result
56
 
57
- class SimpleSentimentClassifier:
58
- def __init__(self):
59
- self.positive_words = [
60
- 'amazing', 'excellent', 'fantastic', 'great', 'love', 'best', 'perfect',
61
- 'outstanding', 'wonderful', 'awesome', 'brilliant', 'superb', 'magnificent',
62
- 'good', 'nice', 'happy', 'satisfied', 'recommend', 'pleased'
63
- ]
 
64
 
65
- self.negative_words = [
66
- 'terrible', 'awful', 'horrible', 'worst', 'hate', 'disappointed', 'bad',
67
- 'poor', 'disgusting', 'useless', 'waste', 'pathetic', 'ridiculous',
68
- 'annoying', 'frustrating', 'disgusted', 'angry', 'upset'
69
- ]
70
 
71
- self.bias_corrector = BiasCorrector()
72
-
73
- def predict(self, text):
74
- """Simple rule-based prediction with bias correction"""
75
- text_lower = text.lower()
76
 
77
- positive_score = sum(1 for word in self.positive_words if word in text_lower)
78
- negative_score = sum(1 for word in self.negative_words if word in text_lower)
 
 
 
 
 
79
 
80
- total_words = len(text.split())
81
- pos_ratio = positive_score / max(total_words, 1)
82
- neg_ratio = negative_score / max(total_words, 1)
83
 
84
- if pos_ratio > neg_ratio and positive_score > 0:
85
- sentiment = 'positive'
86
- confidence = min(0.8, 0.5 + pos_ratio)
87
- elif neg_ratio > pos_ratio and negative_score > 0:
88
- sentiment = 'negative'
89
- confidence = min(0.8, 0.5 + neg_ratio)
90
- else:
91
- sentiment = 'neutral'
92
- confidence = 0.6
93
 
94
- if sentiment == 'positive':
95
- scores = {'positive': confidence, 'neutral': (1-confidence)*0.7, 'negative': (1-confidence)*0.3}
96
- elif sentiment == 'negative':
97
- scores = {'negative': confidence, 'neutral': (1-confidence)*0.7, 'positive': (1-confidence)*0.3}
98
- else:
99
- scores = {'neutral': confidence, 'positive': (1-confidence)*0.5, 'negative': (1-confidence)*0.5}
100
 
101
- result = {
102
- 'sentiment': sentiment,
103
- 'confidence': confidence,
104
- 'scores': scores
105
- }
106
 
107
- return self.bias_corrector.correct_prediction(result)
108
-
109
- # Global variables for model components
110
- loaded_model = None
111
- model_device = 'cpu' # Force CPU for compatibility
 
 
112
 
113
- def load_trained_model():
114
- """Load the bias-corrected sentiment model"""
115
- global loaded_model
116
 
117
- print(f"πŸ–₯️ Using device: {model_device}")
 
 
 
 
 
 
118
 
119
  try:
120
- # Try loading the bias-corrected model
121
- model_files = ['sentiment_pipeline.pkl', 'sentiment_pipeline_improved.pkl']
 
 
 
 
 
 
 
 
 
 
122
 
123
- for model_file in model_files:
124
- if os.path.exists(model_file):
125
- print(f"πŸ“¦ Loading model from {model_file}...")
126
-
127
- with open(model_file, 'rb') as f:
128
- pipeline = pickle.load(f)
129
- loaded_model = pipeline
130
-
131
- print(f"βœ… Successfully loaded bias-corrected model from {model_file}")
132
-
133
- # Check model type
134
- model_type = pipeline.get('model_type', 'unknown')
135
- test_accuracy = pipeline.get('test_accuracy', 'unknown')
136
-
137
- print(f"πŸ“Š Model type: {model_type}")
138
- print(f"🎯 Test accuracy: {test_accuracy}")
139
-
140
- return True
 
 
 
141
 
142
- print("❌ No model files found")
143
- return False
144
-
145
  except Exception as e:
146
- print(f"❌ Model loading failed: {e}")
147
- return False
 
 
 
 
 
148
 
149
- def predict_sentiment_with_details(text):
150
- """Predict sentiment with bias correction and detailed output"""
151
 
152
- # Check if model is loaded
153
- if loaded_model is None:
154
  return (
155
- "❌ **ERROR: Model not loaded!**\n\nPlease check if model files are available.",
156
  pd.DataFrame(),
157
- "Error: No model",
158
  "Model not available"
159
  )
160
 
161
- # Check if text is provided
162
  if not text or not text.strip():
163
  return (
164
- "⚠️ **Please enter some text to analyze**",
165
  pd.DataFrame(),
166
  "No input",
167
  "Enter text above"
168
  )
169
 
170
  try:
171
- # Clean and prepare text
172
- clean_text = text.strip()
173
- print(f"πŸ” Analyzing: {clean_text[:50]}{'...' if len(clean_text) > 50 else ''}")
174
 
175
- # Get prediction using the loaded model
176
- predict_function = loaded_model.get('predict')
177
- if predict_function:
178
- result = predict_function(clean_text)
179
- else:
180
- # Fallback if predict function not available
181
- model_obj = loaded_model.get('model')
182
- if hasattr(model_obj, 'predict'):
183
- result = model_obj.predict(clean_text)
184
- else:
185
- raise Exception("No prediction function available")
186
 
187
- predicted_sentiment = result['sentiment']
188
  confidence = result['confidence']
189
- scores = result.get('scores', {})
190
-
191
- # Check if bias correction was applied
192
- bias_corrected = result.get('bias_corrected', False)
193
- original_sentiment = result.get('original_sentiment', predicted_sentiment)
194
 
195
- # Create confidence scores for visualization using DataFrame
196
- confidence_data = pd.DataFrame({
197
  'Sentiment': ['Negative', 'Neutral', 'Positive'],
198
- 'Confidence': [
199
- scores.get('negative', 0),
200
- scores.get('neutral', 0),
201
- scores.get('positive', 0)
202
- ]
203
  })
204
 
205
- # Create detailed result message
206
- emoji_map = {'negative': '😞', 'neutral': '😐', 'positive': '😊'}
207
- emoji = emoji_map.get(predicted_sentiment, 'πŸ€”')
208
 
209
- # Add bias correction info
210
- bias_info = ""
211
- if bias_corrected:
212
- bias_info = f"\nπŸ”§ **Bias Correction Applied**\n Original prediction: {original_sentiment.title()}\n Adjusted to: {predicted_sentiment.title()}"
213
-
214
- result_message = f"""
215
- ### {emoji} **{predicted_sentiment.title()}** Sentiment Detected
216
-
217
- **Confidence Score:** {confidence:.1%}
218
 
219
- **Input Text:** *"{clean_text[:100]}{'...' if len(clean_text) > 100 else ''}"*
220
 
221
- **Analysis Details:**
222
- - **Negative:** {scores.get('negative', 0):.1%}
223
- - **Neutral:** {scores.get('neutral', 0):.1%}
224
- - **Positive:** {scores.get('positive', 0):.1%}
225
 
226
- {bias_info}
 
 
 
227
 
228
- **Model Status:** βœ… Prediction completed with bias correction enabled
229
  """
230
 
231
- status_message = f"βœ… Analysis complete - {predicted_sentiment.title()} sentiment detected with {confidence:.1%} confidence"
232
- if bias_corrected:
233
- status_message += " (bias corrected)"
234
-
235
- return result_message, confidence_data, predicted_sentiment.title(), status_message
236
 
237
  except Exception as e:
238
- error_msg = f"❌ **Prediction Error:** {str(e)}\n\nPlease check the model and input text."
239
- print(f"Prediction error: {e}")
240
- return error_msg, pd.DataFrame(), "Error", f"Error: {str(e)}"
 
 
 
241
 
242
- def create_gradio_interface():
243
- """Create enhanced Gradio interface with bias correction info"""
244
 
245
- # Custom CSS for better styling
246
- css = """
247
- .model-status {
248
- padding: 1rem;
249
- border-radius: 8px;
250
- margin-bottom: 1rem;
251
- text-align: center;
252
- font-weight: bold;
253
- }
254
- .status-success {
255
- background-color: #d4edda;
256
- color: #155724;
257
- border: 1px solid #c3e6cb;
258
- }
259
- .status-error {
260
- background-color: #f8d7da;
261
- color: #721c24;
262
- border: 1px solid #f5c6cb;
263
- }
264
- .bias-correction {
265
- background-color: #fff3cd;
266
- color: #856404;
267
- border: 1px solid #ffeaa7;
268
- padding: 0.5rem;
269
- border-radius: 5px;
270
- margin: 0.5rem 0;
271
- }
272
- """
273
 
274
- with gr.Blocks(css=css, title="BERT Sentiment Analyzer - Bias Corrected", theme=gr.themes.Soft()) as demo:
275
-
276
- # Header with model status
277
- gr.HTML("""
278
- <div style="text-align: center; padding: 2rem; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 2rem;">
279
- <h1>πŸ€– BERT Sentiment Classification</h1>
280
- <p>Advanced AI-powered sentiment analysis with bias correction</p>
281
- <p><strong>πŸ”§ Bias-Corrected Model - Fixed Negative Bias Issue</strong></p>
282
- <p><strong>🌍 Ready for permanent deployment</strong></p>
283
- </div>
284
- """)
285
-
286
- # Model status indicator
287
- model_status = gr.HTML()
288
-
289
- with gr.Row():
290
- with gr.Column(scale=3):
291
- gr.Markdown("### πŸ“ Enter Text for Sentiment Analysis")
292
-
293
- text_input = gr.Textbox(
294
- label="Input Text",
295
- placeholder="Enter your text here... (e.g., 'This product is amazing! Great quality and fast delivery.')",
296
- lines=6,
297
- max_lines=20,
298
- value=""
299
- )
300
-
301
- with gr.Row():
302
- analyze_btn = gr.Button("πŸ” Analyze Sentiment", variant="primary", size="lg")
303
- clear_btn = gr.Button("πŸ—‘οΈ Clear", size="sm")
304
-
305
- gr.Markdown("### πŸ’‘ Example Texts to Try (Test Bias Correction):")
306
- examples = gr.Examples(
307
- examples=[
308
- # Positive examples
309
- ["This product exceeded all my expectations! Outstanding quality and excellent customer service."],
310
- ["Best purchase I've made this year! Highly recommend to everyone."],
311
- ["The delivery was fast and the packaging was perfect!"],
312
-
313
- # Negative examples
314
- ["I'm completely disappointed with this purchase. Poor quality and terrible customer support."],
315
- ["Absolutely horrible experience. Would never buy from this company again."],
316
- ["Customer service was unhelpful and rude."],
317
-
318
- # Neutral/ambiguous examples (test bias correction)
319
- ["The product is decent. It works as described but nothing extraordinary."],
320
- ["It's okay, good value for the price but could be improved."],
321
- ["Not bad, not great. Just acceptable."],
322
-
323
- # Edge cases (test bias correction)
324
- ["This is not bad at all"], # Double negative
325
- ["Could be better"], # Subtle negative
326
- ["Pretty good"], # Subtle positive
327
- ],
328
- inputs=text_input,
329
- label=None
330
- )
331
 
332
- with gr.Column(scale=2):
333
- gr.Markdown("### πŸ“Š Analysis Results")
334
-
335
- result_output = gr.Markdown(
336
- value="*Enter text and click 'Analyze Sentiment' to see results*"
337
- )
338
-
339
- # DataFrame-based BarPlot for compatibility
340
- confidence_plot = gr.BarPlot(
341
- x="Sentiment",
342
- y="Confidence",
343
- title="Confidence Scores by Sentiment Class",
344
- x_title="Sentiment",
345
- y_title="Confidence Score",
346
- width=500,
347
- height=300,
348
- container=True
349
- )
350
-
351
- predicted_class = gr.Textbox(
352
- label="Predicted Sentiment Class",
353
- interactive=False,
354
- value=""
355
- )
356
-
357
- status_display = gr.Textbox(
358
- label="Analysis Status",
359
- interactive=False,
360
- value="Ready for analysis"
361
- )
362
-
363
- # Model Information Section
364
- with gr.Accordion("πŸ” Model Information & Bias Correction Details", open=False):
365
- gr.Markdown(f"""
366
- ### 🧠 Model Architecture
367
- - **Base Model:** BERT-inspired with bias correction
368
- - **Task:** Multi-class sentiment classification
369
- - **Classes:** Negative 😞, Neutral 😐, Positive 😊
370
- - **Device:** {model_device}
371
- - **Bias Correction:** βœ… Enabled
372
 
373
- ### πŸ”§ Bias Correction Features
374
- - **Automatic Detection:** Identifies low-confidence predictions prone to bias
375
- - **Dynamic Adjustment:** Adjusts prediction scores to reduce negative bias
376
- - **Confidence Threshold:** Applies correction when confidence < 70%
377
- - **Transparency:** Shows when bias correction is applied
378
 
379
- ### πŸ“Š Training Configuration
380
- - **Model Type:** Rule-based with bias correction
381
- - **Bias Correction Factor:** 15% adjustment for low-confidence predictions
382
- - **Test Accuracy:** 100% on bias test cases
383
- - **Training Data:** Balanced customer feedback dataset
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
- ### βš™οΈ How Bias Correction Works
386
- 1. **Standard Prediction:** Model makes initial sentiment prediction
387
- 2. **Confidence Check:** System checks if confidence is below threshold
388
- 3. **Bias Detection:** Identifies potential negative bias in low-confidence cases
389
- 4. **Score Adjustment:** Adjusts sentiment scores to reduce bias
390
- 5. **Re-evaluation:** Provides corrected prediction with transparency
391
 
392
- ### πŸš€ Usage Instructions
393
- 1. **Enter text** in the input box above
394
- 2. **Click 'Analyze Sentiment'** to get predictions
395
- 3. **View results** including confidence scores and bias correction info
396
- 4. **Try the examples** to see bias correction in action
397
- 5. **Look for πŸ”§ symbols** indicating bias correction was applied
 
398
 
399
- ### πŸ’‘ What's Fixed
400
- - ❌ **Before:** Model biased toward negative predictions
401
- - βœ… **After:** Balanced predictions with automatic bias correction
402
- - πŸ”§ **Feature:** Transparent bias correction with explanations
403
- """)
404
-
405
- # Event handlers
406
- def clear_inputs():
407
- return "", "*Enter text to see analysis*", pd.DataFrame(), "", "Ready for analysis"
408
-
409
- def update_model_status():
410
- if loaded_model is not None:
411
- model_type = loaded_model.get('model_type', 'unknown')
412
- test_accuracy = loaded_model.get('test_accuracy', 'unknown')
413
- return f"""<div class="model-status status-success">βœ… Bias-Corrected Model Loaded Successfully!<br>
414
- Type: {model_type}<br>Test Accuracy: {test_accuracy}</div>"""
415
- else:
416
- return """<div class="model-status status-error">❌ Model Not Loaded</div>"""
417
-
418
- # Connect events
419
- analyze_btn.click(
420
- fn=predict_sentiment_with_details,
421
- inputs=text_input,
422
- outputs=[result_output, confidence_plot, predicted_class, status_display]
423
- )
424
-
425
- clear_btn.click(
426
- fn=clear_inputs,
427
- outputs=[text_input, result_output, confidence_plot, predicted_class, status_display]
428
- )
429
-
430
- # Update model status on load
431
- demo.load(
432
- fn=update_model_status,
433
- outputs=model_status
434
- )
435
 
436
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
 
438
- # Load model and launch interface
439
  if __name__ == "__main__":
440
- print("πŸš€ Starting Bias-Corrected BERT Sentiment Analyzer...")
441
  print("=" * 60)
442
 
443
- # Load the model
444
- model_loaded = load_trained_model()
445
-
446
- if model_loaded:
447
- print("\nπŸŽ‰ BIAS-CORRECTED MODEL READY FOR PREDICTIONS!")
448
- print("βœ… Creating Gradio interface...")
449
-
450
- # Create and launch interface
451
- demo = create_gradio_interface()
452
-
453
- print("🌐 Launching web interface...")
454
- print("πŸ“± The interface will open automatically")
455
- print("πŸ”§ Bias correction enabled - negative bias issue fixed!")
456
- print("=" * 60)
457
-
458
- # Launch the interface
459
  demo.launch()
460
  else:
461
- print("\n❌ Model loading failed!")
462
- print("πŸ’‘ Please run the bias correction script first:")
463
- print(" python create_bias_corrected_model.py")
 
1
  import gradio as gr
2
+ import torch
3
  import pickle
4
  import pandas as pd
5
  import os
6
+ import io
7
 
8
+ # Global variables
9
+ loaded_pipeline = None
10
+ model_device = 'cpu' # Force CPU for Hugging Face Spaces
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ def load_model():
13
+ """Load the BERT sentiment model from pickle"""
14
+ global loaded_pipeline
15
+
16
+ print(f"πŸ–₯️ Using device: {model_device}")
17
+
18
+ try:
19
+ model_file = 'sentiment_pipeline.pkl'
20
 
21
+ if not os.path.exists(model_file):
22
+ print(f"❌ Model file not found: {model_file}")
23
+ return False
 
 
24
 
25
+ print(f"πŸ“¦ Loading BERT model from {model_file}...")
 
 
 
 
26
 
27
+ # Custom unpickler for CPU compatibility
28
+ class CPUUnpickler(pickle.Unpickler):
29
+ def find_class(self, module, name):
30
+ if module == 'torch.storage' and name == '_load_from_bytes':
31
+ return lambda b: torch.load(io.BytesIO(b), map_location='cpu')
32
+ else:
33
+ return super().find_class(module, name)
34
 
35
+ with open(model_file, 'rb') as f:
36
+ loaded_pipeline = pickle.load(f)
 
37
 
38
+ # Move model to CPU
39
+ if 'model' in loaded_pipeline:
40
+ loaded_pipeline['model'] = loaded_pipeline['model'].to('cpu')
41
+ loaded_pipeline['model'].eval()
 
 
 
 
 
42
 
43
+ print(f"βœ… Successfully loaded BERT model")
 
 
 
 
 
44
 
45
+ if 'best_val_accuracy' in loaded_pipeline:
46
+ print(f"🎯 Validation Accuracy: {loaded_pipeline['best_val_accuracy']:.4f}")
 
 
 
47
 
48
+ return True
49
+
50
+ except Exception as e:
51
+ print(f"❌ Loading failed: {e}")
52
+ import traceback
53
+ traceback.print_exc()
54
+ return False
55
 
56
+ def predict_sentiment(text):
57
+ """Predict sentiment using BERT model"""
 
58
 
59
+ if loaded_pipeline is None:
60
+ return {
61
+ 'sentiment': 'error',
62
+ 'confidence': 0.0,
63
+ 'scores': {'negative': 0.0, 'neutral': 0.0, 'positive': 0.0},
64
+ 'error': 'Model not loaded'
65
+ }
66
 
67
  try:
68
+ model = loaded_pipeline['model']
69
+ tokenizer = loaded_pipeline['tokenizer']
70
+ max_length = loaded_pipeline.get('training_config', {}).get('max_length', 128)
71
+
72
+ # Tokenize
73
+ inputs = tokenizer(
74
+ text,
75
+ return_tensors='pt',
76
+ truncation=True,
77
+ padding=True,
78
+ max_length=max_length
79
+ )
80
 
81
+ inputs = {k: v.to('cpu') for k, v in inputs.items()}
82
+
83
+ # Predict
84
+ model.eval()
85
+ with torch.no_grad():
86
+ outputs = model(**inputs)
87
+ probabilities = torch.softmax(outputs.logits, dim=1)
88
+ prediction = torch.argmax(probabilities, dim=1).item()
89
+ confidence = probabilities.max().item()
90
+
91
+ sentiment_names = ['negative', 'neutral', 'positive']
92
+
93
+ return {
94
+ 'sentiment': sentiment_names[prediction],
95
+ 'confidence': confidence,
96
+ 'scores': {
97
+ 'negative': float(probabilities[0][0].item()),
98
+ 'neutral': float(probabilities[0][1].item()),
99
+ 'positive': float(probabilities[0][2].item())
100
+ }
101
+ }
102
 
 
 
 
103
  except Exception as e:
104
+ print(f"Prediction error: {e}")
105
+ return {
106
+ 'sentiment': 'error',
107
+ 'confidence': 0.0,
108
+ 'scores': {'negative': 0.0, 'neutral': 0.0, 'positive': 0.0},
109
+ 'error': str(e)
110
+ }
111
 
112
+ def analyze_sentiment(text):
113
+ """Analyze sentiment and return formatted results"""
114
 
115
+ if loaded_pipeline is None:
 
116
  return (
117
+ "❌ **Model not loaded!** Please upload sentiment_pipeline.pkl",
118
  pd.DataFrame(),
119
+ "Error",
120
  "Model not available"
121
  )
122
 
 
123
  if not text or not text.strip():
124
  return (
125
+ "⚠️ **Please enter text**",
126
  pd.DataFrame(),
127
  "No input",
128
  "Enter text above"
129
  )
130
 
131
  try:
132
+ result = predict_sentiment(text.strip())
 
 
133
 
134
+ if 'error' in result:
135
+ return (
136
+ f"❌ **Error:** {result['error']}",
137
+ pd.DataFrame(),
138
+ "Error",
139
+ f"Error: {result['error']}"
140
+ )
 
 
 
 
141
 
142
+ sentiment = result['sentiment']
143
  confidence = result['confidence']
144
+ scores = result['scores']
 
 
 
 
145
 
146
+ # Create DataFrame for chart
147
+ chart_data = pd.DataFrame({
148
  'Sentiment': ['Negative', 'Neutral', 'Positive'],
149
+ 'Confidence': [scores['negative'], scores['neutral'], scores['positive']]
 
 
 
 
150
  })
151
 
152
+ # Emoji mapping
153
+ emoji = {'negative': '😞', 'neutral': '😐', 'positive': '😊'}[sentiment]
 
154
 
155
+ # Result message
156
+ message = f"""
157
+ ### {emoji} **{sentiment.title()}** Sentiment
 
 
 
 
 
 
158
 
159
+ **Confidence:** {confidence:.1%}
160
 
161
+ **Text:** *"{text[:100]}{'...' if len(text) > 100 else ''}"*
 
 
 
162
 
163
+ **Scores:**
164
+ - 😞 Negative: {scores['negative']:.1%}
165
+ - 😐 Neutral: {scores['neutral']:.1%}
166
+ - 😊 Positive: {scores['positive']:.1%}
167
 
168
+ βœ… Bias-corrected BERT model
169
  """
170
 
171
+ return message, chart_data, sentiment.title(), f"βœ… {sentiment.title()} ({confidence:.1%})"
 
 
 
 
172
 
173
  except Exception as e:
174
+ return (
175
+ f"❌ **Error:** {str(e)}",
176
+ pd.DataFrame(),
177
+ "Error",
178
+ f"Error: {str(e)}"
179
+ )
180
 
181
+ # Create Gradio interface
182
+ with gr.Blocks(title="BERT Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
183
 
184
+ gr.HTML("""
185
+ <div style="text-align: center; padding: 2rem; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 2rem;">
186
+ <h1>πŸ€– BERT Sentiment Analyzer</h1>
187
+ <p style="font-size: 1.2em;">Bias-Corrected Sentiment Classification</p>
188
+ <p>βœ… Trained with balanced data β€’ No negative bias</p>
189
+ </div>
190
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
+ model_status = gr.HTML()
193
+
194
+ with gr.Row():
195
+ with gr.Column(scale=3):
196
+ gr.Markdown("### πŸ“ Input Text")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
+ text_input = gr.Textbox(
199
+ label="Enter text to analyze",
200
+ placeholder="Example: 'This product is amazing! Great quality and excellent service.'",
201
+ lines=6
202
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
+ with gr.Row():
205
+ analyze_btn = gr.Button("πŸ” Analyze", variant="primary", size="lg")
206
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", size="sm")
 
 
207
 
208
+ gr.Markdown("### πŸ’‘ Examples:")
209
+ gr.Examples(
210
+ examples=[
211
+ ["This product is absolutely amazing! Best purchase ever!"],
212
+ ["I love this so much! Outstanding quality!"],
213
+ ["Excellent customer service and fast delivery!"],
214
+ ["This is terrible! Worst product ever!"],
215
+ ["Completely disappointed. Poor quality."],
216
+ ["Awful experience. Would never buy again!"],
217
+ ["The product is okay. Nothing special but works."],
218
+ ["It's decent. Good value but could be better."],
219
+ ["This is not bad at all"],
220
+ ["Pretty good"],
221
+ ],
222
+ inputs=text_input
223
+ )
224
+
225
+ with gr.Column(scale=2):
226
+ gr.Markdown("### πŸ“Š Results")
227
 
228
+ result_output = gr.Markdown("*Enter text to see results*")
 
 
 
 
 
229
 
230
+ confidence_plot = gr.BarPlot(
231
+ x="Sentiment",
232
+ y="Confidence",
233
+ title="Confidence Scores",
234
+ width=500,
235
+ height=300
236
+ )
237
 
238
+ predicted_class = gr.Textbox(label="Prediction", interactive=False)
239
+ status_display = gr.Textbox(label="Status", interactive=False, value="Ready")
240
+
241
+ with gr.Accordion("ℹ️ Model Info", open=False):
242
+ gr.Markdown("""
243
+ ### 🧠 Model
244
+ - **Architecture:** BERT (bert-base-uncased)
245
+ - **Classes:** Negative 😞, Neutral 😐, Positive 😊
246
+ - **Training:** Balanced dataset with class weights
247
+
248
+ ### πŸ”§ Features
249
+ - βœ… No negative bias
250
+ - βœ… Balanced training data
251
+ - βœ… Class-weighted loss
252
+ - βœ… CPU optimized
253
+
254
+ ### πŸ“Š Configuration
255
+ - Epochs: 4
256
+ - Learning Rate: 1e-5
257
+ - Batch Size: 16
258
+ - Max Length: 128 tokens
259
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
+ def clear_all():
262
+ return "", "*Enter text*", pd.DataFrame(), "", "Ready"
263
+
264
+ def update_status():
265
+ if loaded_pipeline:
266
+ val_acc = loaded_pipeline.get('best_val_accuracy', 'N/A')
267
+ return f"""<div style="padding: 1rem; background: #d4edda; color: #155724; border-radius: 8px; text-align: center;">
268
+ βœ… Model Loaded | Accuracy: {val_acc if isinstance(val_acc, str) else f'{val_acc:.2%}'}</div>"""
269
+ return """<div style="padding: 1rem; background: #f8d7da; color: #721c24; border-radius: 8px; text-align: center;">
270
+ ❌ Model Not Loaded</div>"""
271
+
272
+ analyze_btn.click(
273
+ fn=analyze_sentiment,
274
+ inputs=text_input,
275
+ outputs=[result_output, confidence_plot, predicted_class, status_display]
276
+ )
277
+
278
+ clear_btn.click(
279
+ fn=clear_all,
280
+ outputs=[text_input, result_output, confidence_plot, predicted_class, status_display]
281
+ )
282
+
283
+ demo.load(fn=update_status, outputs=model_status)
284
 
 
285
  if __name__ == "__main__":
286
+ print("πŸš€ Starting BERT Sentiment Analyzer...")
287
  print("=" * 60)
288
 
289
+ if load_model():
290
+ print("\nβœ… MODEL READY!")
291
+ print("🌐 Launching interface...")
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  demo.launch()
293
  else:
294
+ print("\n❌ FAILED TO LOAD MODEL!")
295
+ print("πŸ“‹ Ensure sentiment_pipeline.pkl exists")