-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_app.py
393 lines (340 loc) · 15.1 KB
/
test_app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# importing dependencies
import folium
from streamlit_folium import st_folium
import streamlit as st
import numpy as np
import mysql.connector as ms
from transformers import BertTokenizer, BertForSequenceClassification
import torch
import textwrap
import google.generativeai as genai
from IPython.display import Markdown
import os
from dotenv import load_dotenv
from PIL import Image
import base64
# Custom connection functions
from connection import is_connected, get_database_connection
# ALWAYS MUST BE THE FIRST COMMAND
# Set page configuration
st.set_page_config(
page_title="Sahaj",
page_icon="🥘", # rasode mein kaun tha
layout="wide",
initial_sidebar_state="expanded",
)
# Path to your image
background_image_path = r"E:\Sentiment_Analysis_Using_NLP\background.jpg"
# Function to convert an image file to a base64 string
def image_to_base64(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode()
# Define the CSS for the background image
background_css = f"""
<style>
.stApp {{
background-image: url("data:image/jpeg;base64,{image_to_base64(background_image_path)}");
background-size: cover;
background-position: center;
}}
</style>
"""
# Inject CSS into the Streamlit app
st.markdown(background_css, unsafe_allow_html=True)
st.title("Welcome to Restaurant Review Analysis System!")
sidebar_options = ["Home", "Reviews", "Analysis", "Image Analysis", "About Us", "Contact Us"]
choice = st.sidebar.selectbox("Menu", sidebar_options)
# Home Page
if choice == "Home":
st.write("## RESTAURANT")
st.write("Welcome to our platform, where we review delicious dishes from around the world.")
st.write("## Why We're Making This Project")
st.write(
"""
Many restaurant owners struggle to understand what is working and what needs improvement in their establishments.
Our project aims to bridge this gap by providing comprehensive reviews and actionable insights. Unlike typical reviews
on Google or Yelp, which often highlight only the extremes, our analysis delves deeper into the nuances of customer feedback.
"""
)
st.write("## Our Unique Approach")
st.write(
"""
- Detailed analysis of customer reviews to uncover hidden trends.
- Clear reasoning behind the ratings provided.
- Suggestions for improvement tailored to each restaurant's unique challenges.
"""
)
st.write("## Features")
st.write(
"""
- Comprehensive rating system based on sentiment analysis.
- Insightful breakdown of strengths and weaknesses.
- Actionable advice for restaurant owners to improve their services.
"""
)
st.write("## How We Differ from Google or Yelp Reviews")
st.write(
"""
Our reviews are not just about star ratings or brief comments. We provide:
- In-depth analysis using advanced natural language processing techniques.
- A balanced view that considers both positive and negative feedback.
- Professional recommendations for enhancing the dining experience.
"""
)
# Function to get restaurant names and IDs from the database
def get_restaurant_names():
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT restaurant_id, name FROM Restaurants")
restaurants = cursor.fetchall()
cursor.close()
return {name: restaurant_id for restaurant_id, name in restaurants}
except ms.Error as e:
print(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
print("Failed to connect to MySQL")
return {}
# Function to get reviews for a specific restaurant from the database
def get_reviews_for_restaurant(restaurant_id):
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT customer_id, review_text, rating FROM RatingsReviews WHERE restaurant_id = %s", (restaurant_id,))
reviews = cursor.fetchall()
cursor.close()
return reviews
except ms.Error as e:
print(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
print("Failed to connect to MySQL")
return []
# Function to get contact info for a specific restaurant from the database
def get_contact_info_for_restaurant(restaurant_id):
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT phone_number, website, email FROM RestrauContactInfo WHERE restaurant_id = %s", (restaurant_id,))
contact_info = cursor.fetchone()
cursor.close()
return contact_info
except ms.Error as e:
print(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
print("Failed to connect to MySQL")
return None
# Function to get address and plus code for a specific restaurant from the database
def get_address_pluscode_for_restaurant(restaurant_id):
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT address, plus_code FROM Restaurants WHERE restaurant_id = %s", (restaurant_id,))
address_pluscode = cursor.fetchone()
cursor.close()
return address_pluscode
except ms.Error as e:
print(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
print("Failed to connect to MySQL")
return None
# Reviews Page
if choice == "Reviews":
st.header("Select a Restaurant")
restaurants = get_restaurant_names()
if restaurants:
selected_restaurant = st.selectbox("Choose a restaurant", list(restaurants.keys()))
if selected_restaurant:
restaurant_id = restaurants[selected_restaurant]
st.header("Recent Reviews")
reviews = get_reviews_for_restaurant(restaurant_id)
if reviews:
for customer_id, review_text, rating in reviews:
st.write(f"**Customer ID:** {customer_id} | **Rating:** {rating}")
st.write(f"- {review_text}")
else:
st.write("No reviews found.")
st.header("Contact Information")
contact_info = get_contact_info_for_restaurant(restaurant_id)
if contact_info:
phone_number, website, email = contact_info
st.write(f"**Phone Number:** {phone_number}")
st.write(f"**Website:** {website}")
st.write(f"**Email:** {email}")
else:
st.write("No contact information found.")
st.header("Address and Location")
address_pluscode = get_address_pluscode_for_restaurant(restaurant_id)
if address_pluscode:
address, plus_code = address_pluscode
st.write(f"**Address:** {address}")
st.write(f"**Plus Code:** {plus_code}")
# Display map
# Replace with accurate latitude and longitude from your database
location_map = folium.Map(location=[12.9716, 77.5946], zoom_start=12)
folium.Marker([12.9716, 77.5946], tooltip="Restaurant Location").add_to(location_map)
st_folium(location_map, width=700, height=500)
else:
st.write("No address information found.")
else:
st.write("No restaurants found.")
# About Us Page
elif choice == "About Us":
st.write(
"""
## About Us
Welcome to **Restaurant Reviews Analysis System**! We are passionate about food and dedicated to helping people discover the best dining experiences. Our mission is to provide valuable insights and information about restaurants to empower users in making informed decisions when choosing where to dine.
At Restaurant Reviews Analysis System, we gather reviews from various sources, analyze them to extract meaningful insights, and present them to you in a user-friendly format.
Whether you're searching for the top-rated restaurants in your city or exploring new dining options, we've got you covered.
We believe that good food brings people together and creates unforgettable memories. Join us on our journey to explore the culinary world and discover your next favorite restaurant!
*If you have any questions or feedback, please don't hesitate to reach out to us. We would love to hear from you!*
**Happy dining!**
*The Restaurant Reviews Analysis System Team*
"""
)
# Contact Us Page
elif choice == "Contact Us":
st.write(
"""
## Contact Us
Have questions or feedback? We're here to help!
- **Address:** Somewhere in Bangalore
- **Phone:** +91 98076-XXXXX
- **Email:** restraunt-reviews.com
Feel free to reach out to us for any inquiries. We look forward to hearing from you!
"""
)
# Analysis Page
elif choice == "Analysis":
st.title("Restaurant Review Analysis System")
st.header("Analysis")
# Function to fetch restaurant names from the database
def get_restaurant_names():
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT restaurant_id, name FROM Restaurants")
restaurants = cursor.fetchall()
cursor.close()
return {name: restaurant_id for restaurant_id, name in restaurants}
except ms.Error as e:
st.error(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
st.error("Failed to connect to MySQL")
return {}
# Function to fetch reviews for a specific restaurant from the database
def get_reviews_for_restaurant(restaurant_id):
flag = is_connected()
db = "restaurantreviewdb"
if flag:
try:
connection = get_database_connection()
cursor = connection.cursor()
cursor.execute(f"USE {db};")
cursor.execute("SELECT review_text FROM RatingsReviews WHERE restaurant_id = %s", (restaurant_id,))
reviews = cursor.fetchall()
cursor.close()
return [review[0] for review in reviews]
except ms.Error as e:
st.error(f"Error: {e}")
finally:
if connection.is_connected():
connection.close()
else:
st.error("Failed to connect to MySQL")
return []
# Function to load BERT model and tokenizer
def load_bert_model():
model_name = "bert-base-uncased"
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
return tokenizer, model
# Function to perform sentiment analysis using BERT
def analyze_sentiment(tokenizer, model, review):
inputs = tokenizer(review, return_tensors="pt", truncation=True, padding=True)
outputs = model(**inputs)
probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
positive_prob = probabilities[0][1].item()
return positive_prob
# Function to calculate average sentiment rating for reviews
def calculate_average_sentiment(reviews, tokenizer, model):
sentiments = [analyze_sentiment(tokenizer, model, review) for review in reviews]
return np.mean(sentiments) if sentiments else None
# Function to generate content using Gemini API
def generate_reviews_of_restaurants(reviews, integer_rating):
try:
model = genai.GenerativeModel('gemini-pro')
# Joining reviews into a single prompt
full_reviews = " ".join(reviews)
additional_info = (" according to these reviews, tell what is good in the restaurant, what is bad, "
"and how can we improve it. If data is not given, just improvise and give something.")
bert_rating_review = (f"{integer_rating} out of 5 is the rating given by BERT model on the reviews. "
"Explain why BERT gave this rating and what can be done to improve it.")
word_cloud = "make a word cloud like highlighting the most important things in the reviews.just state highlights and keywords"
prompt = full_reviews + additional_info + bert_rating_review + word_cloud
response = model.generate_content(prompt)
return response.text
except Exception as e:
return f"Error generating content: {e}"
# Fetch restaurant names from the database
restaurants = get_restaurant_names()
if restaurants:
restaurant_names = list(restaurants.keys())
selected_restaurant = st.selectbox("Select a Restaurant", restaurant_names)
# Fetch reviews for selected restaurant
restaurant_id = restaurants[selected_restaurant]
reviews = get_reviews_for_restaurant(restaurant_id)
if reviews:
# Load BERT model and tokenizer
tokenizer, model = load_bert_model()
# Calculate average sentiment rating
average_sentiment = calculate_average_sentiment(reviews, tokenizer, model)
if average_sentiment is not None:
# Normalize sentiment score to range 1-5
normalized_score = np.interp(average_sentiment, [0, 1], [1, 5])
integer_rating = round(normalized_score, 1)
st.subheader(f"Average Sentiment Rating for {selected_restaurant}: {integer_rating}/5")
# Button to generate insights using Gemini API
if st.button("Generate Gemini Insights"):
rating_content = generate_reviews_of_restaurants(reviews, integer_rating)
st.markdown(textwrap.indent(rating_content, '> ', predicate=lambda _: True))
else:
st.subheader(f"Average Sentiment Rating for {selected_restaurant}: N/A")
else:
st.write("No reviews found for this restaurant.")
else:
st.write("No restaurants found in the database.")