hamxaameer commited on
Commit
90fc598
Β·
verified Β·
1 Parent(s): b37a37a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +340 -0
app.py ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import pickle
4
+ import pandas as pd
5
+ from transformers import BertTokenizer, BertForSequenceClassification
6
+ import numpy as np
7
+ import os
8
+
9
+ # Global variables for model components
10
+ loaded_model = None
11
+ loaded_tokenizer = None
12
+ model_device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
13
+
14
+ def load_trained_model():
15
+ """Load the trained BERT model with comprehensive error handling"""
16
+ global loaded_model, loaded_tokenizer
17
+
18
+ print(f"πŸ–₯️ Using device: {model_device}")
19
+
20
+ try:
21
+ # Method 1: Try loading from pickle (most reliable)
22
+ if os.path.exists('sentiment_pipeline.pkl'):
23
+ print("πŸ“¦ Loading model from pickle file...")
24
+ with open('sentiment_pipeline.pkl', 'rb') as f:
25
+ pipeline = pickle.load(f)
26
+ loaded_model = pipeline['model']
27
+ loaded_tokenizer = pipeline['tokenizer']
28
+ print("βœ… Successfully loaded model from sentiment_pipeline.pkl")
29
+
30
+ # Method 2: Try loading from HuggingFace format
31
+ elif os.path.exists('bert_sentiment_model'):
32
+ print("πŸ€— Loading model from HuggingFace format...")
33
+ loaded_model = BertForSequenceClassification.from_pretrained('bert_sentiment_model')
34
+ loaded_tokenizer = BertTokenizer.from_pretrained('bert_sentiment_model')
35
+ print("βœ… Successfully loaded model from bert_sentiment_model/")
36
+
37
+ else:
38
+ # Method 3: Load pre-trained model if no fine-tuned model exists
39
+ print("⚠️ No fine-tuned model found, loading base BERT model...")
40
+ loaded_model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=3)
41
+ loaded_tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
42
+ print("βœ… Loaded base BERT model (not fine-tuned)")
43
+
44
+ # Verify model is loaded and move to device
45
+ if loaded_model is not None and loaded_tokenizer is not None:
46
+ loaded_model.eval()
47
+ loaded_model.to(model_device)
48
+
49
+ # Test the model with a simple prediction
50
+ test_input = "This is a test"
51
+ inputs = loaded_tokenizer(test_input, return_tensors='pt', truncation=True, padding=True, max_length=128).to(model_device)
52
+ with torch.no_grad():
53
+ outputs = loaded_model(**inputs)
54
+ probabilities = torch.softmax(outputs.logits, dim=1)
55
+ print("βœ… Model test prediction successful!")
56
+ print(f"πŸ“Š Model parameters: {sum(p.numel() for p in loaded_model.parameters()):,}")
57
+ return True
58
+ else:
59
+ print("❌ Model or tokenizer is None after loading")
60
+ return False
61
+
62
+ except Exception as e:
63
+ print(f"❌ Model loading failed: {e}")
64
+ return False
65
+
66
+ def predict_sentiment_with_details(text):
67
+ """Predict sentiment with detailed output and error handling"""
68
+
69
+ # Check if model is loaded
70
+ if loaded_model is None or loaded_tokenizer is None:
71
+ return (
72
+ "❌ **ERROR: Model not loaded!**\n\nPlease check if model files are available.",
73
+ pd.DataFrame(),
74
+ "Error: No model",
75
+ "Model not available"
76
+ )
77
+
78
+ # Check if text is provided
79
+ if not text or not text.strip():
80
+ return (
81
+ "⚠️ **Please enter some text to analyze**",
82
+ pd.DataFrame(),
83
+ "No input",
84
+ "Enter text above"
85
+ )
86
+
87
+ try:
88
+ # Clean and prepare text
89
+ clean_text = text.strip()
90
+ print(f"πŸ” Analyzing: {clean_text[:50]}{'...' if len(clean_text) > 50 else ''}")
91
+
92
+ # Tokenize input
93
+ inputs = loaded_tokenizer(
94
+ clean_text,
95
+ return_tensors='pt',
96
+ truncation=True,
97
+ padding=True,
98
+ max_length=128
99
+ ).to(model_device)
100
+
101
+ # Get prediction
102
+ with torch.no_grad():
103
+ outputs = loaded_model(**inputs)
104
+ probabilities = torch.softmax(outputs.logits, dim=1)
105
+ prediction = torch.argmax(probabilities, dim=1).item()
106
+ confidence = probabilities.max().item()
107
+
108
+ # Map labels
109
+ label_mapping = {0: 'Negative', 1: 'Neutral', 2: 'Positive'}
110
+ predicted_sentiment = label_mapping[prediction]
111
+
112
+ # Create confidence scores for visualization using DataFrame
113
+ confidence_data = pd.DataFrame({
114
+ 'Sentiment': ['Negative', 'Neutral', 'Positive'],
115
+ 'Confidence': [
116
+ float(probabilities[0][0].item()),
117
+ float(probabilities[0][1].item()),
118
+ float(probabilities[0][2].item())
119
+ ]
120
+ })
121
+
122
+ # Create detailed result message
123
+ emoji_map = {'Negative': '😞', 'Neutral': '😐', 'Positive': '😊'}
124
+ emoji = emoji_map[predicted_sentiment]
125
+
126
+ result_message = f"""
127
+ ### {emoji} **{predicted_sentiment}** Sentiment Detected
128
+
129
+ **Confidence Score:** {confidence:.1%}
130
+
131
+ **Input Text:** *"{clean_text[:100]}{'...' if len(clean_text) > 100 else ''}"*
132
+
133
+ **Analysis Details:**
134
+ - **Negative:** {probabilities[0][0].item():.1%}
135
+ - **Neutral:** {probabilities[0][1].item():.1%}
136
+ - **Positive:** {probabilities[0][2].item():.1%}
137
+
138
+ **Model Status:** βœ… Prediction completed successfully
139
+ """
140
+
141
+ status_message = f"βœ… Analysis complete - {predicted_sentiment} sentiment detected with {confidence:.1%} confidence"
142
+
143
+ return result_message, confidence_data, predicted_sentiment, status_message
144
+
145
+ except Exception as e:
146
+ error_msg = f"❌ **Prediction Error:** {str(e)}\n\nPlease check the model and input text."
147
+ print(f"Prediction error: {e}")
148
+ return error_msg, pd.DataFrame(), "Error", f"Error: {str(e)}"
149
+
150
+ def create_gradio_interface():
151
+ """Create enhanced Gradio interface with model status"""
152
+
153
+ # Custom CSS for better styling
154
+ css = """
155
+ .model-status {
156
+ padding: 1rem;
157
+ border-radius: 8px;
158
+ margin-bottom: 1rem;
159
+ text-align: center;
160
+ font-weight: bold;
161
+ }
162
+ .status-success {
163
+ background-color: #d4edda;
164
+ color: #155724;
165
+ border: 1px solid #c3e6cb;
166
+ }
167
+ .status-error {
168
+ background-color: #f8d7da;
169
+ color: #721c24;
170
+ border: 1px solid #f5c6cb;
171
+ }
172
+ """
173
+
174
+ with gr.Blocks(css=css, title="BERT Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
175
+
176
+ # Header with model status
177
+ gr.HTML("""
178
+ <div style="text-align: center; padding: 2rem; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 2rem;">
179
+ <h1>πŸ€– BERT Sentiment Classification</h1>
180
+ <p>Advanced AI-powered sentiment analysis using fine-tuned BERT</p>
181
+ <p><strong>🌍 Permanently hosted on Hugging Face Spaces</strong></p>
182
+ </div>
183
+ """)
184
+
185
+ # Model status indicator
186
+ model_status = gr.HTML()
187
+
188
+ with gr.Row():
189
+ with gr.Column(scale=3):
190
+ gr.Markdown("### πŸ“ Enter Text for Sentiment Analysis")
191
+
192
+ text_input = gr.Textbox(
193
+ label="Input Text",
194
+ placeholder="Enter your text here... (e.g., 'This product is amazing! Great quality and fast delivery.')",
195
+ lines=6,
196
+ max_lines=20,
197
+ value=""
198
+ )
199
+
200
+ with gr.Row():
201
+ analyze_btn = gr.Button("πŸ” Analyze Sentiment", variant="primary", size="lg")
202
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", size="sm")
203
+
204
+ gr.Markdown("### πŸ’‘ Example Texts to Try:")
205
+ examples = gr.Examples(
206
+ examples=[
207
+ ["This product exceeded all my expectations! Outstanding quality and excellent customer service."],
208
+ ["I'm completely disappointed with this purchase. Poor quality and terrible customer support."],
209
+ ["The product is decent. It works as described but nothing extraordinary."],
210
+ ["Best purchase I've made this year! Highly recommend to everyone."],
211
+ ["Absolutely horrible experience. Would never buy from this company again."],
212
+ ["It's okay, good value for the price but could be improved."],
213
+ ["The delivery was fast and the packaging was perfect!"],
214
+ ["Customer service was unhelpful and rude."],
215
+ ["The product I received was damaged. Unacceptable."]
216
+ ],
217
+ inputs=text_input,
218
+ label=None
219
+ )
220
+
221
+ with gr.Column(scale=2):
222
+ gr.Markdown("### πŸ“Š Analysis Results")
223
+
224
+ result_output = gr.Markdown(
225
+ value="*Enter text and click 'Analyze Sentiment' to see results*"
226
+ )
227
+
228
+ # DataFrame-based BarPlot for compatibility
229
+ confidence_plot = gr.BarPlot(
230
+ x="Sentiment",
231
+ y="Confidence",
232
+ title="Confidence Scores by Sentiment Class",
233
+ x_title="Sentiment",
234
+ y_title="Confidence Score",
235
+ width=500,
236
+ height=300,
237
+ container=True
238
+ )
239
+
240
+ predicted_class = gr.Textbox(
241
+ label="Predicted Sentiment Class",
242
+ interactive=False,
243
+ value=""
244
+ )
245
+
246
+ status_display = gr.Textbox(
247
+ label="Analysis Status",
248
+ interactive=False,
249
+ value="Ready for analysis"
250
+ )
251
+
252
+ # Model Information Section
253
+ with gr.Accordion("πŸ” Model Information & Technical Details", open=False):
254
+ gr.Markdown(f"""
255
+ ### 🧠 Model Architecture
256
+ - **Base Model:** BERT (bert-base-uncased)
257
+ - **Task:** Multi-class sentiment classification
258
+ - **Classes:** Negative 😞, Neutral 😐, Positive 😊
259
+ - **Max Sequence Length:** 128 tokens
260
+ - **Device:** {model_device}
261
+
262
+ ### πŸ“Š Training Configuration
263
+ - **Optimizer:** AdamW (Learning Rate: 2e-5)
264
+ - **Epochs:** 3
265
+ - **Batch Size:** 16
266
+ - **Training Data:** Customer feedback dataset
267
+
268
+ ### βš™οΈ How It Works
269
+ 1. **Text Processing:** Input text is tokenized using BERT tokenizer
270
+ 2. **Encoding:** BERT encoder processes the tokens with self-attention
271
+ 3. **Classification:** A classification head outputs probability scores
272
+ 4. **Prediction:** The class with highest probability is selected
273
+
274
+ ### πŸš€ Usage Instructions
275
+ 1. **Enter text** in the input box above
276
+ 2. **Click 'Analyze Sentiment'** to get predictions
277
+ 3. **View results** including confidence scores and detailed breakdown
278
+ 4. **Try the examples** to see how the model performs on different texts
279
+ """)
280
+
281
+ # Event handlers
282
+ def clear_inputs():
283
+ return "", "*Enter text to see analysis*", pd.DataFrame(), "", "Ready for analysis"
284
+
285
+ def update_model_status():
286
+ if loaded_model is not None and loaded_tokenizer is not None:
287
+ return """<div class="model-status status-success">βœ… Model Loaded Successfully - Ready for Analysis!</div>"""
288
+ else:
289
+ return """<div class="model-status status-error">❌ Model Not Loaded - Using base BERT model</div>"""
290
+
291
+ # Connect events
292
+ analyze_btn.click(
293
+ fn=predict_sentiment_with_details,
294
+ inputs=text_input,
295
+ outputs=[result_output, confidence_plot, predicted_class, status_display]
296
+ )
297
+
298
+ clear_btn.click(
299
+ fn=clear_inputs,
300
+ outputs=[text_input, result_output, confidence_plot, predicted_class, status_display]
301
+ )
302
+
303
+ # Update model status on load
304
+ demo.load(
305
+ fn=update_model_status,
306
+ outputs=model_status
307
+ )
308
+
309
+ return demo
310
+
311
+ # Load model and launch interface
312
+ if __name__ == "__main__":
313
+ print("πŸš€ Starting BERT Sentiment Analyzer...")
314
+ print("=" * 60)
315
+
316
+ # Load the model
317
+ model_loaded = load_trained_model()
318
+
319
+ if model_loaded:
320
+ print("\nπŸŽ‰ MODEL READY FOR PREDICTIONS!")
321
+ print("βœ… Creating Gradio interface...")
322
+
323
+ # Create and launch interface
324
+ demo = create_gradio_interface()
325
+
326
+ print("🌐 Launching web interface...")
327
+ print("πŸ“± The interface will open automatically")
328
+ print("=" * 60)
329
+
330
+ # Launch the interface
331
+ demo.launch(
332
+ share=True,
333
+ show_error=True,
334
+ inbrowser=True
335
+ )
336
+ else:
337
+ print("\n❌ Model loading failed, but launching interface anyway...")
338
+ print("πŸ’‘ The app will use base BERT model (not fine-tuned)")
339
+ demo = create_gradio_interface()
340
+ demo.launch(share=True)