Elliot89 commited on
Commit
8afe425
Β·
verified Β·
1 Parent(s): 55f8f35

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -136
app.py CHANGED
@@ -1,136 +1,215 @@
1
- ## 🌐 Section 16: Gradio Web Application (Corrected & Improved)
2
-
3
- import gradio as gr
4
- import warnings
5
- warnings.filterwarnings('ignore')
6
-
7
- # Ensure the required variables are defined from previous cells:
8
- # - final_best_model
9
- # - tfidf_vectorizer
10
- # - preprocessor
11
- # - final_best_model_name
12
- # - results_df
13
-
14
- def create_gradio_app(model, vectorizer, preprocessor_obj, model_name, metrics_df):
15
- """
16
- Creates and launches a Gradio web application for sentiment analysis.
17
-
18
- Args:
19
- model: The trained machine learning model.
20
- vectorizer: The fitted TF-IDF vectorizer.
21
- preprocessor_obj: The text preprocessor instance.
22
- model_name (str): The name of the best model.
23
- metrics_df (pd.DataFrame): DataFrame with model performance metrics.
24
- """
25
-
26
- def gradio_predict(review_text):
27
- """
28
- Prediction function for the Gradio interface. It uses the model
29
- and preprocessors passed to the outer function.
30
- """
31
- if not review_text.strip():
32
- return "⚠️ Please enter a review!", "", "", "", ""
33
-
34
- # Use the existing predict_sentiment function, passing all required arguments
35
- result = predict_sentiment(
36
- review=review_text,
37
- model=model,
38
- vectorizer=vectorizer,
39
- preprocessor=preprocessor_obj
40
- )
41
-
42
- sentiment = result['sentiment']
43
- confidence = f"{result['confidence']:.2%}" if result['confidence'] is not None else "N/A"
44
- prob_neg = f"{result['probability_negative']:.2%}" if result['probability_negative'] is not None else "N/A"
45
- prob_pos = f"{result['probability_positive']:.2%}" if result['probability_positive'] is not None else "N/A"
46
- cleaned = result['cleaned_review']
47
-
48
- return sentiment, confidence, prob_neg, prob_pos, cleaned
49
-
50
- # Create the Gradio interface
51
- with gr.Blocks(theme=gr.themes.Soft(), title="Restaurant Review Sentiment Analyzer") as demo:
52
- gr.Markdown(f"""
53
- # 🍽️ Restaurant Review Sentiment Analyzer
54
- ### Powered by Machine Learning
55
-
56
- Enter a restaurant review to analyze its sentiment. The model will predict whether
57
- the review is **Positive** or **Negative**.
58
-
59
- **Model:** {model_name}
60
- **Accuracy:** {metrics_df.iloc[0]['Test_Accuracy']:.2%}
61
- """)
62
-
63
- with gr.Row():
64
- with gr.Column(scale=2):
65
- input_text = gr.Textbox(
66
- label="Enter Restaurant Review",
67
- placeholder="e.g., The food was absolutely amazing! Best restaurant ever!",
68
- lines=5
69
- )
70
- with gr.Row():
71
- submit_btn = gr.Button("πŸ” Analyze Sentiment", variant="primary", size="lg")
72
- clear_btn = gr.ClearButton([input_text], value="πŸ—‘οΈ Clear", size="lg")
73
-
74
- with gr.Column(scale=2):
75
- sentiment_output = gr.Textbox(label="🎯 Predicted Sentiment", interactive=False)
76
- confidence_output = gr.Textbox(label="πŸ“Š Confidence Score", interactive=False)
77
- with gr.Row():
78
- neg_prob = gr.Textbox(label="😞 Negative Probability", interactive=False)
79
- pos_prob = gr.Textbox(label="😊 Positive Probability", interactive=False)
80
-
81
- with gr.Accordion("πŸ” Preprocessing Details", open=False):
82
- cleaned_output = gr.Textbox(label="Cleaned Review Text", interactive=False, lines=3)
83
-
84
- gr.Examples(
85
- examples=[
86
- ["The food was absolutely amazing! Best restaurant I've ever been to!"],
87
- ["Terrible service and the food was cold. Never coming back."],
88
- ["Outstanding experience! The staff was friendly and attentive."],
89
- ["Worst meal I've ever had. Complete waste of money."],
90
- ],
91
- inputs=input_text,
92
- label="Click to try an example"
93
- )
94
-
95
- # Connect the button to the prediction function
96
- submit_btn.click(
97
- fn=gradio_predict,
98
- inputs=input_text,
99
- outputs=[sentiment_output, confidence_output, neg_prob, pos_prob, cleaned_output]
100
- )
101
-
102
- return demo
103
-
104
- # --- LAUNCH THE APP ---
105
- print('='*70)
106
- print('πŸš€ LAUNCHING GRADIO WEB APPLICATION')
107
- print('='*70)
108
-
109
- try:
110
- # Get the final best model and preprocessors from your notebook
111
- # Ensure these variable names match what you have in your notebook
112
- final_model = trained_models[final_best_model_name]
113
-
114
- # Create the app instance by passing the required objects
115
- gradio_app = create_gradio_app(
116
- model=final_model,
117
- vectorizer=tfidf_vectorizer,
118
- preprocessor_obj=preprocessor,
119
- model_name=final_best_model_name,
120
- metrics_df=results_df
121
- )
122
-
123
- # Launch the Gradio app
124
- # share=True creates a public link and keeps the server running
125
- gradio_app.launch(share=True, debug=True)
126
-
127
- print("\nβœ… Gradio app is running!")
128
- print("πŸ“± Access the app at the public URL provided above.")
129
-
130
- except NameError as e:
131
- print(f"❌ NameError: {e}")
132
- print("Please make sure all previous cells in the notebook have been run successfully.")
133
- print("Required variables: 'final_best_model_name', 'trained_models', 'tfidf_vectorizer', 'preprocessor', 'results_df'")
134
- except Exception as e:
135
- print(f"❌ An unexpected error occurred: {e}")
136
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pickle
3
+ import numpy as np
4
+ import pandas as pd
5
+ import nltk
6
+ from nltk.corpus import stopwords
7
+ from nltk.stem import WordNetLemmatizer
8
+ import re
9
+ import warnings
10
+ warnings.filterwarnings('ignore')
11
+
12
+ # Download NLTK data
13
+ print("Downloading NLTK resources...")
14
+ nltk.download('stopwords', quiet=True)
15
+ nltk.download('wordnet', quiet=True)
16
+ nltk.download('omw-1.4', quiet=True)
17
+ nltk.download('punkt', quiet=True)
18
+ print("βœ… NLTK resources downloaded")
19
+
20
+ # Load models
21
+ print("Loading models...")
22
+ try:
23
+ with open('best_model.pkl', 'rb') as f:
24
+ model = pickle.load(f)
25
+ print("βœ… Model loaded")
26
+
27
+ with open('tfidf_vectorizer.pkl', 'rb') as f:
28
+ vectorizer = pickle.load(f)
29
+ print("βœ… Vectorizer loaded")
30
+
31
+ with open('preprocessor.pkl', 'rb') as f:
32
+ preprocessor = pickle.load(f)
33
+ print("βœ… Preprocessor loaded")
34
+
35
+ except Exception as e:
36
+ print(f"❌ Error loading models: {e}")
37
+ raise
38
+
39
+ # Feature extraction function
40
+ def extract_features(texts, original_texts):
41
+ """Extract statistical features from texts."""
42
+ features = {
43
+ 'review_length': [len(text) for text in original_texts],
44
+ 'word_count': [len(text.split()) for text in texts],
45
+ 'avg_word_length': [
46
+ np.mean([len(word) for word in text.split()]) if text else 0
47
+ for text in texts
48
+ ],
49
+ 'exclamation_count': [text.count('!') for text in original_texts],
50
+ 'question_count': [text.count('?') for text in original_texts],
51
+ 'capital_ratio': [
52
+ sum(1 for c in text if c.isupper()) / len(text) if len(text) > 0 else 0
53
+ for text in original_texts
54
+ ]
55
+ }
56
+ return pd.DataFrame(features)
57
+
58
+ # Prediction function
59
+ def predict_sentiment(review_text):
60
+ """Predict sentiment for a review."""
61
+ if not review_text or not review_text.strip():
62
+ return "⚠️ Please enter a review!", "", "", "", ""
63
+
64
+ try:
65
+ # Preprocess
66
+ cleaned = preprocessor.clean_text(review_text)
67
+
68
+ # Vectorize
69
+ vectorized = vectorizer.transform([cleaned]).toarray()
70
+
71
+ # Extract additional features
72
+ add_features = extract_features([cleaned], [review_text])
73
+
74
+ # Combine features
75
+ X_new = np.concatenate([vectorized, add_features.values], axis=1)
76
+
77
+ # Predict
78
+ prediction = model.predict(X_new)[0]
79
+
80
+ # Get probabilities if available
81
+ if hasattr(model, 'predict_proba'):
82
+ proba = model.predict_proba(X_new)[0]
83
+ confidence = max(proba)
84
+ prob_neg = proba[0]
85
+ prob_pos = proba[1]
86
+ else:
87
+ confidence = None
88
+ prob_neg = None
89
+ prob_pos = None
90
+
91
+ # Format output
92
+ sentiment = "βœ… Positive 😊" if prediction == 1 else "❌ Negative 😞"
93
+ conf_str = f"{confidence:.2%}" if confidence else "N/A"
94
+ neg_str = f"{prob_neg:.2%}" if prob_neg else "N/A"
95
+ pos_str = f"{prob_pos:.2%}" if prob_pos else "N/A"
96
+
97
+ return sentiment, conf_str, neg_str, pos_str, cleaned
98
+
99
+ except Exception as e:
100
+ return f"❌ Error: {str(e)}", "", "", "", ""
101
+
102
+ # Create Gradio interface
103
+ print("Creating Gradio interface...")
104
+
105
+ with gr.Blocks(
106
+ theme=gr.themes.Soft(),
107
+ title="Restaurant Review Sentiment Analyzer",
108
+ css="""
109
+ .gradio-container {font-family: 'Arial', sans-serif;}
110
+ """
111
+ ) as demo:
112
+
113
+ gr.Markdown("""
114
+ # 🍽️ Restaurant Review Sentiment Analyzer
115
+ ### AI-Powered Sentiment Analysis with Machine Learning
116
+
117
+ Enter a restaurant review to analyze its sentiment in real-time!
118
+
119
+ **Model:** Random Forest Classifier
120
+ **Accuracy:** 85%+
121
+ **Features:** TF-IDF + Statistical Text Features
122
+ """)
123
+
124
+ with gr.Row():
125
+ with gr.Column(scale=2):
126
+ gr.Markdown("### πŸ“ Enter Your Review")
127
+ input_text = gr.Textbox(
128
+ label="Restaurant Review",
129
+ placeholder="e.g., The food was amazing and the service was excellent!",
130
+ lines=6,
131
+ max_lines=10
132
+ )
133
+
134
+ with gr.Row():
135
+ submit_btn = gr.Button("πŸ” Analyze Sentiment", variant="primary", size="lg")
136
+ clear_btn = gr.ClearButton([input_text], value="πŸ—‘οΈ Clear", size="lg")
137
+
138
+ with gr.Column(scale=2):
139
+ gr.Markdown("### πŸ“Š Analysis Results")
140
+ sentiment_output = gr.Textbox(label="🎯 Predicted Sentiment", interactive=False)
141
+ confidence_output = gr.Textbox(label="πŸ“ˆ Confidence Score", interactive=False)
142
+
143
+ with gr.Row():
144
+ neg_prob = gr.Textbox(label="😞 Negative Probability", interactive=False)
145
+ pos_prob = gr.Textbox(label="😊 Positive Probability", interactive=False)
146
+
147
+ with gr.Accordion("πŸ” Preprocessing Details", open=False):
148
+ cleaned_output = gr.Textbox(
149
+ label="Cleaned Review Text (After Preprocessing)",
150
+ interactive=False,
151
+ lines=3
152
+ )
153
+ gr.Markdown("""
154
+ **Preprocessing Steps Applied:**
155
+ 1. Convert to lowercase
156
+ 2. Remove special characters and numbers
157
+ 3. Remove stopwords (preserving negations)
158
+ 4. Apply lemmatization
159
+ 5. Extract statistical features
160
+ """)
161
+
162
+ gr.Markdown("---")
163
+ gr.Markdown("### πŸ’‘ Try These Example Reviews")
164
+
165
+ gr.Examples(
166
+ examples=[
167
+ ["The food was absolutely amazing! Best restaurant I've ever been to! The service was impeccable."],
168
+ ["Terrible service and the food was cold. The waiter was rude. Never coming back!"],
169
+ ["Outstanding experience from start to finish! Every dish was cooked to perfection. Highly recommended!"],
170
+ ["Worst meal I've ever had. Complete waste of money. Very disappointing experience."],
171
+ ["Good food but the portions were quite small. Reasonable prices. Service was okay."],
172
+ ["Fantastic! The ambiance was perfect and the food was delicious. Will definitely return!"],
173
+ ["Not impressed at all. The quality has really gone downhill. Won't be going back."],
174
+ ["Absolutely loved everything! Great variety and excellent presentation. Five stars!"]
175
+ ],
176
+ inputs=input_text,
177
+ label="Click any example to try it"
178
+ )
179
+
180
+ gr.Markdown("""
181
+ ---
182
+ ### πŸ“š About This Model
183
+
184
+ **Machine Learning Pipeline:**
185
+ - **Preprocessing:** Lemmatization, stopword removal, text cleaning
186
+ - **Feature Engineering:** TF-IDF vectorization (1500 features, bigrams) + 6 statistical features
187
+ - **Algorithm:** Random Forest Classifier
188
+ - **Training:** 6 different models compared, best one deployed
189
+ - **Evaluation:** Cross-validation, multiple metrics (Accuracy, F1, ROC-AUC)
190
+
191
+ **Technologies Used:**
192
+ - Python, Scikit-learn, NLTK, Gradio, Pandas, NumPy
193
+
194
+ **Developer:** Einstein Ellandala | Project: ML-06-BML11
195
+
196
+ πŸ““ **Full Project:** [View on GitHub](https://github.com/MrEinsteinE/sentiment-analysis-restaurant)
197
+ """)
198
+
199
+ # Connect button to prediction function
200
+ submit_btn.click(
201
+ fn=predict_sentiment,
202
+ inputs=input_text,
203
+ outputs=[sentiment_output, confidence_output, neg_prob, pos_prob, cleaned_output]
204
+ )
205
+
206
+ print("βœ… Gradio interface created")
207
+ print("πŸš€ Launching application...")
208
+
209
+ # Launch the app
210
+ if __name__ == "__main__":
211
+ demo.launch(
212
+ server_name="0.0.0.0",
213
+ server_port=7860,
214
+ show_error=True
215
+ )