simran0608 commited on
Commit
e040241
Β·
verified Β·
1 Parent(s): 4d98dfb

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +262 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ from transformers import pipeline
4
+ import torch # For GPU checks
5
+ import numpy as np
6
+ from groq import Groq
7
+ import os
8
+ import time
9
+
10
+ # Set page config
11
+ st.set_page_config(
12
+ page_title="Restaurant Review Analyzer 🍽️",
13
+ page_icon="πŸ”",
14
+ layout="wide"
15
+ )
16
+
17
+ # Custom CSS
18
+ st.markdown("""
19
+ <style>
20
+ .main {
21
+ padding: 2rem;
22
+ }
23
+ .stProgress > div > div > div {
24
+ background-color: #1f77b4;
25
+ }
26
+ .metric-card {
27
+ background-color: #f8f9fa;
28
+ padding: 1rem;
29
+ border-radius: 0.5rem;
30
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
31
+ }
32
+ </style>
33
+ """, unsafe_allow_html=True)
34
+
35
+
36
+ def setup_classifier():
37
+ """Initialize the zero-shot classification pipeline with GPU support if available"""
38
+ with st.spinner('Loading classification model... βš™οΈ'):
39
+ device = 0 if torch.cuda.is_available() else -1 # Use GPU if available
40
+ return pipeline(
41
+ "zero-shot-classification",
42
+ model="joeddav/xlm-roberta-large-xnli",
43
+ device=device
44
+ )
45
+
46
+
47
+ def create_aspect_labels():
48
+ """Create labels for all aspects with positive/negative sentiment"""
49
+ aspects = [
50
+ "food quality",
51
+ "service",
52
+ "ambiance",
53
+ "price",
54
+ "cleanliness",
55
+ "portion size",
56
+ "wait time",
57
+ "menu variety"
58
+ ]
59
+
60
+ sentiment_labels = []
61
+ for aspect in aspects:
62
+ sentiment_labels.extend([
63
+ f"positive {aspect}",
64
+ f"negative {aspect}"
65
+ ])
66
+
67
+ return aspects, sentiment_labels
68
+
69
+
70
+ def classify_review(classifier, review, sentiment_labels):
71
+ """Classify a single review across all aspects and sentiments"""
72
+ if pd.isna(review) or not isinstance(review, str):
73
+ return {label: 0 for label in sentiment_labels}
74
+
75
+ try:
76
+ result = classifier(
77
+ review,
78
+ sentiment_labels,
79
+ multi_label=True
80
+ )
81
+ return dict(zip(result['labels'], result['scores']))
82
+ except Exception as e:
83
+ st.error(f"Error processing review: {e}")
84
+ return {label: 0 for label in sentiment_labels}
85
+
86
+ def format_summary_for_llm(summary_df):
87
+ """Format the classification summary into a clear text prompt"""
88
+ summary_text = "Restaurant Reviews Analysis Summary:\n\n"
89
+
90
+ sentiment_analysis = {}
91
+ for aspect in summary_df.index:
92
+ pos = summary_df.loc[aspect, 'positive_mentions']
93
+ neg = summary_df.loc[aspect, 'negative_mentions']
94
+ total = pos + neg
95
+ if total > 0:
96
+ pos_percent = (pos / total) * 100
97
+ neg_percent = (neg / total) * 100
98
+ difference = pos_percent - neg_percent
99
+ sentiment_analysis[aspect] = {
100
+ 'difference': difference,
101
+ 'positive_percent': pos_percent,
102
+ 'negative_percent': neg_percent,
103
+ 'total_mentions': total
104
+ }
105
+
106
+ for aspect, metrics in sentiment_analysis.items():
107
+ summary_text += f"{aspect}:\n"
108
+ summary_text += f"- Total Mentions: {metrics['total_mentions']}\n"
109
+ summary_text += f"- Positive Mentions: {metrics['positive_percent']:.1f}%\n"
110
+ summary_text += f"- Negative Mentions: {metrics['negative_percent']:.1f}%\n"
111
+ summary_text += f"- Sentiment Difference: {metrics['difference']:.1f}%\n"
112
+ summary_text += "\n"
113
+
114
+ return summary_text
115
+
116
+ def generate_insights(groq_client, summary_text):
117
+ """Generate insights using Groq API"""
118
+ prompt = f"""You are an expert restaurant consultant analyzing customer feedback data.
119
+ Based on the following customer review analysis summary, provide actionable insights
120
+ and recommendations for the restaurant owner. When analyzing the data:
121
+
122
+ - If an aspect has a positive difference of 0.5% or more, consider it a strength
123
+ - If an aspect has a negative difference of 0.5% or more, consider it an area for improvement
124
+ - For differences smaller than 0.5%, consider the aspect neutral or mixed
125
+ - Pay special attention to aspects with high total mentions as they represent stronger customer sentiment
126
+
127
+ Analysis Data:
128
+ {summary_text}
129
+
130
+ Please provide:
131
+ 1. Key Strengths: What's working well (aspects with >0.5% positive difference)
132
+ 2. Areas for Improvement: What needs attention (aspects with >0.5% negative difference)
133
+ 3. Mixed Reception Areas: Aspects with minimal difference (<0.5%) between positive and negative
134
+ 4. Actionable Recommendations: Specific steps based on the analysis
135
+ 5. Priority Actions: What should be addressed first, considering both sentiment differences and total mention count
136
+
137
+ Format your response in clear sections with bullet points where appropriate.
138
+ Add relevant emojis to make the response more engaging.
139
+ """
140
+
141
+ try:
142
+ with st.spinner('Generating insights... πŸ€”'):
143
+ chat_completion = groq_client.chat.completions.create(
144
+ messages=[{"role": "user", "content": prompt}],
145
+ model="mixtral-8x7b-32768",
146
+ temperature=0.7,
147
+ max_tokens=1500,
148
+ )
149
+ return chat_completion.choices[0].message.content
150
+ except Exception as e:
151
+ st.error(f"Error generating insights: {str(e)}")
152
+ return None
153
+
154
+ def main():
155
+ # Header
156
+ st.title("🍽️ Restaurant Review Analyzer")
157
+ st.markdown("### Transform your customer feedback into actionable insights! πŸ“Š")
158
+
159
+ # Sidebar
160
+ st.sidebar.header("πŸ“ Configuration")
161
+
162
+ # File upload
163
+ uploaded_file = st.sidebar.file_uploader("Upload your CSV file", type=['csv'])
164
+
165
+ if uploaded_file is not None:
166
+ # Read CSV
167
+ try:
168
+ df = pd.read_csv(uploaded_file)
169
+ df.columns = df.columns.str.strip()
170
+
171
+ # Validate 'Review' column
172
+ if 'Review' not in df.columns:
173
+ st.error("❌ 'Review' column not found in the CSV file!")
174
+ return
175
+
176
+ # Show sample of uploaded data
177
+ st.subheader("πŸ“‹ Sample Reviews")
178
+ st.dataframe(df[['Review']].head(5), use_container_width=True)
179
+
180
+ # Process reviews
181
+ if st.button("πŸš€ Analyze Reviews"):
182
+ # Initialize classifier
183
+ classifier = setup_classifier()
184
+ aspects, sentiment_labels = create_aspect_labels()
185
+
186
+ # Process reviews with progress bar
187
+ results = []
188
+ progress_bar = st.progress(0)
189
+ status_text = st.empty()
190
+
191
+ for idx, review in enumerate(df['Review'].head(30)):
192
+ status_text.text(f"Processing review {idx + 1}/30...")
193
+ scores = classify_review(classifier, review, sentiment_labels)
194
+ results.append(scores)
195
+ progress_bar.progress((idx + 1) / 30)
196
+
197
+ results_df = pd.DataFrame(results)
198
+
199
+ # Analyze results
200
+ summary = pd.DataFrame()
201
+ for aspect in aspects:
202
+ pos_col = f"positive {aspect}"
203
+ neg_col = f"negative {aspect}"
204
+
205
+ summary.loc[aspect, 'positive_mentions'] = (results_df[pos_col] > 0.5).sum()
206
+ summary.loc[aspect, 'negative_mentions'] = (results_df[neg_col] > 0.5).sum()
207
+ summary.loc[aspect, 'avg_positive_score'] = results_df[pos_col].mean()
208
+ summary.loc[aspect, 'avg_negative_score'] = results_df[neg_col].mean()
209
+
210
+ # Display summary in columns
211
+ st.subheader("πŸ“Š Analysis Summary")
212
+ col1, col2 = st.columns(2)
213
+
214
+ with col1:
215
+ st.markdown("#### πŸ“ˆ Positive Mentions")
216
+ for aspect in aspects:
217
+ st.metric(
218
+ label=aspect.title(),
219
+ value=f"{summary.loc[aspect, 'positive_mentions']} reviews",
220
+ delta=f"{summary.loc[aspect, 'avg_positive_score']:.2%} avg. confidence"
221
+ )
222
+
223
+ with col2:
224
+ st.markdown("#### πŸ“‰ Negative Mentions")
225
+ for aspect in aspects:
226
+ st.metric(
227
+ label=aspect.title(),
228
+ value=f"{summary.loc[aspect, 'negative_mentions']} reviews",
229
+ delta=f"{summary.loc[aspect, 'avg_negative_score']:.2%} avg. confidence",
230
+ delta_color="inverse"
231
+ )
232
+
233
+ # Generate insights
234
+ groq_client = Groq(api_key="groq_api_key")
235
+
236
+ summary_text = format_summary_for_llm(summary)
237
+ insights = generate_insights(groq_client, summary_text)
238
+
239
+ if insights:
240
+ st.subheader("πŸ’‘ Key Insights and Recommendations")
241
+ st.markdown(insights)
242
+
243
+ except Exception as e:
244
+ st.error(f"Error processing file: {str(e)}")
245
+
246
+ else:
247
+ # Show welcome message and instructions
248
+ st.markdown("""
249
+ ### πŸ‘‹ Welcome to the Restaurant Review Analyzer!
250
+
251
+ To get started:
252
+ 1. πŸ“ Upload your CSV file containing customer reviews
253
+ 2. πŸ” Make sure your file has a 'Review' column
254
+ 3. πŸš€ Click 'Analyze Reviews' to process the data
255
+ 4. πŸ“Š Get detailed insights and recommendations
256
+
257
+ The analyzer will process the reviews to provide quick insights!
258
+ """)
259
+
260
+
261
+ if __name__ == "__main__":
262
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ pandas
3
+ transformers
4
+ groq
5
+ numpy