Spaces:
Sleeping
Sleeping
minor change
Browse files
app.py
CHANGED
@@ -1,48 +1,48 @@
|
|
|
|
1 |
import streamlit as st
|
2 |
import pandas as pd
|
|
|
|
|
3 |
import plotly.express as px
|
4 |
import matplotlib.pyplot as plt
|
5 |
import plotly.graph_objs as go
|
6 |
from wordcloud import WordCloud
|
7 |
-
from transformers import pipeline
|
8 |
|
9 |
# Load the pre-trained sentiment analysis model
|
10 |
sentiment_model = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
|
11 |
|
12 |
-
# Define the Streamlit app's user interface
|
13 |
-
# Set page title and favicon
|
14 |
-
st.set_page_config(page_title="Hotel Reviews Sentiment", page_icon=":hotel:",layout='wide')
|
15 |
|
16 |
-
#
|
17 |
-
st.image("Header.png", use_column_width=True)
|
18 |
|
|
|
|
|
|
|
|
|
|
|
19 |
st.write("<br>", unsafe_allow_html=True)
|
20 |
file_format_link = "https://drive.google.com/file/d/1B6Glpna9kZsakgjpWStfhbxI20EoGsnv/view?usp=sharing"
|
21 |
message = f"⚠️ㅤPlease stick to the given layout when uploading the file. You can download the sample file layout from [here]({file_format_link})."
|
22 |
st.write(message)
|
|
|
|
|
23 |
|
24 |
-
file = st.file_uploader(" ",type=["csv"])
|
25 |
-
|
26 |
-
# Define the app's functionality
|
27 |
if file is not None:
|
28 |
# Read the CSV file into a Pandas DataFrame
|
29 |
df = pd.read_csv(file)
|
30 |
-
|
|
|
31 |
|
32 |
-
# Write the total number of records
|
33 |
st.markdown(
|
34 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; border-radius: 1rem;margin-top: 10px"> Distribution of Reviews </div>',
|
35 |
unsafe_allow_html=True
|
36 |
)
|
37 |
-
|
38 |
-
# Apply the sentiment analysis model to each review and store the results in a new column
|
39 |
df["Sentiment"] = df["Review"].apply(lambda x: sentiment_model(x)[0]["label"])
|
40 |
|
|
|
|
|
41 |
# Generate pie chart
|
42 |
-
# Define custom colors
|
43 |
colors = ['#30C3C4', '#D1DDDE']
|
44 |
-
|
45 |
-
# Generate pie chart
|
46 |
sentiment_counts = df["Sentiment"].value_counts()
|
47 |
fig = px.pie(sentiment_counts, values=sentiment_counts.values, names=sentiment_counts.index,
|
48 |
color_discrete_sequence=colors)
|
@@ -51,10 +51,8 @@ if file is not None:
|
|
51 |
# Create word clouds for positive and negative reviews
|
52 |
positive_reviews = " ".join(df[df["Sentiment"] == "POSITIVE"]["Review"].tolist())
|
53 |
negative_reviews = " ".join(df[df["Sentiment"] == "NEGATIVE"]["Review"].tolist())
|
54 |
-
|
55 |
-
# Center-align the word clouds
|
56 |
col1, col2 = st.columns(2)
|
57 |
-
|
58 |
with col1:
|
59 |
st.markdown(
|
60 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 40px; border-radius: 1rem">Positive Reviews</div>',
|
@@ -62,7 +60,6 @@ if file is not None:
|
|
62 |
)
|
63 |
wc_pos = WordCloud(width=800, height=600, background_color="white", colormap="winter").generate(positive_reviews)
|
64 |
st.image(wc_pos.to_array(),use_column_width=True)
|
65 |
-
|
66 |
with col2:
|
67 |
st.markdown(
|
68 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 40px;border-radius: 1rem">Negative Reviews</div>',
|
@@ -71,23 +68,20 @@ if file is not None:
|
|
71 |
wc_neg = WordCloud(width=800, height=600, background_color="white", colormap="winter").generate(negative_reviews)
|
72 |
st.image(wc_neg.to_array(),use_column_width=True)
|
73 |
|
74 |
-
# Display the sentiment of each review as
|
75 |
st.markdown(
|
76 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-top: 60px; border-radius: 1rem"> Reviews in depth </div>',
|
77 |
unsafe_allow_html=True
|
78 |
)
|
79 |
-
|
80 |
-
# Add the selectbox to filter sentiments
|
81 |
filter_sentiment = st.selectbox("", ["ALL", "POSITIVE", "NEGATIVE"])
|
82 |
-
|
83 |
-
# Filter the dataframe based on the selected sentiment
|
84 |
if filter_sentiment != "ALL":
|
85 |
df = df[df['Sentiment'] == filter_sentiment]
|
86 |
-
|
87 |
-
# Set the max number of rows to display at a time
|
88 |
max_rows = 10
|
89 |
|
90 |
-
#
|
91 |
table_html = (df.style
|
92 |
.set_properties(**{'text-align': 'left'})
|
93 |
.set_table_styles([{'selector': 'th', 'props': [('border', '0px')]},
|
@@ -95,22 +89,23 @@ if file is not None:
|
|
95 |
.set_table_attributes('style="position: sticky; top: 0;"')
|
96 |
.to_html(index=False, escape=False))
|
97 |
|
98 |
-
#
|
99 |
st.write(f'<div style="height: {max_rows*30}px; overflow-y: scroll;">{table_html}</div>', unsafe_allow_html=True,header=True,sticky_header=True)
|
100 |
|
|
|
101 |
def convert_df(df):
|
102 |
# IMPORTANT: Cache the conversion to prevent computation on every rerun
|
103 |
return df.to_csv().encode('utf-8')
|
104 |
-
|
105 |
csv = convert_df(df)
|
106 |
|
107 |
-
#
|
108 |
st.write("<br>", unsafe_allow_html=True)
|
109 |
-
|
110 |
st.download_button(
|
111 |
label="Download data as CSV",
|
112 |
data=csv,
|
113 |
file_name='Review Sentiments.csv'
|
114 |
)
|
|
|
|
|
115 |
st.write("<br>", unsafe_allow_html=True)
|
116 |
st.caption('<div style="text-align:center; background-color:#CFEDFF;padding: 6px">crafted with ❤️</div>', unsafe_allow_html=True)
|
|
|
1 |
+
# import essential libraraies
|
2 |
import streamlit as st
|
3 |
import pandas as pd
|
4 |
+
from transformers import pipeline #for pre-trained model
|
5 |
+
# for graphing
|
6 |
import plotly.express as px
|
7 |
import matplotlib.pyplot as plt
|
8 |
import plotly.graph_objs as go
|
9 |
from wordcloud import WordCloud
|
|
|
10 |
|
11 |
# Load the pre-trained sentiment analysis model
|
12 |
sentiment_model = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
|
13 |
|
|
|
|
|
|
|
14 |
|
15 |
+
# Define user interface
|
|
|
16 |
|
17 |
+
# Set page title
|
18 |
+
st.set_page_config(page_title="Hotel Reviews Sentiment", page_icon=":hotel:",layout='wide')
|
19 |
+
# Add a header
|
20 |
+
st.image("Header.png", use_column_width=True)
|
21 |
+
# Define the format of the file to be uploaded
|
22 |
st.write("<br>", unsafe_allow_html=True)
|
23 |
file_format_link = "https://drive.google.com/file/d/1B6Glpna9kZsakgjpWStfhbxI20EoGsnv/view?usp=sharing"
|
24 |
message = f"⚠️ㅤPlease stick to the given layout when uploading the file. You can download the sample file layout from [here]({file_format_link})."
|
25 |
st.write(message)
|
26 |
+
# Uploading the file
|
27 |
+
file = st.file_uploader("",type=["csv"])
|
28 |
|
|
|
|
|
|
|
29 |
if file is not None:
|
30 |
# Read the CSV file into a Pandas DataFrame
|
31 |
df = pd.read_csv(file)
|
32 |
+
# Print total number of reviews to analyse
|
33 |
+
st.markdown(f"<h5 style='font-family: sans-serif;margin-top:40px'>Total reviews: {len(df)} </h5>", unsafe_allow_html=True)
|
34 |
|
|
|
35 |
st.markdown(
|
36 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; border-radius: 1rem;margin-top: 10px"> Distribution of Reviews </div>',
|
37 |
unsafe_allow_html=True
|
38 |
)
|
39 |
+
# Apply the sentiment analysis model
|
|
|
40 |
df["Sentiment"] = df["Review"].apply(lambda x: sentiment_model(x)[0]["label"])
|
41 |
|
42 |
+
# Building the dashboard
|
43 |
+
|
44 |
# Generate pie chart
|
|
|
45 |
colors = ['#30C3C4', '#D1DDDE']
|
|
|
|
|
46 |
sentiment_counts = df["Sentiment"].value_counts()
|
47 |
fig = px.pie(sentiment_counts, values=sentiment_counts.values, names=sentiment_counts.index,
|
48 |
color_discrete_sequence=colors)
|
|
|
51 |
# Create word clouds for positive and negative reviews
|
52 |
positive_reviews = " ".join(df[df["Sentiment"] == "POSITIVE"]["Review"].tolist())
|
53 |
negative_reviews = " ".join(df[df["Sentiment"] == "NEGATIVE"]["Review"].tolist())
|
54 |
+
# Diplay wordcloud in two columns
|
|
|
55 |
col1, col2 = st.columns(2)
|
|
|
56 |
with col1:
|
57 |
st.markdown(
|
58 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 40px; border-radius: 1rem">Positive Reviews</div>',
|
|
|
60 |
)
|
61 |
wc_pos = WordCloud(width=800, height=600, background_color="white", colormap="winter").generate(positive_reviews)
|
62 |
st.image(wc_pos.to_array(),use_column_width=True)
|
|
|
63 |
with col2:
|
64 |
st.markdown(
|
65 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 40px;border-radius: 1rem">Negative Reviews</div>',
|
|
|
68 |
wc_neg = WordCloud(width=800, height=600, background_color="white", colormap="winter").generate(negative_reviews)
|
69 |
st.image(wc_neg.to_array(),use_column_width=True)
|
70 |
|
71 |
+
# Display the sentiment of each review as a dataframe
|
72 |
st.markdown(
|
73 |
f'<div style="background-color: #4AA6DD; color: #ffffff; padding: 6px; font-size: 20px; font-weight: bold; text-align: center; margin-top: 60px; border-radius: 1rem"> Reviews in depth </div>',
|
74 |
unsafe_allow_html=True
|
75 |
)
|
76 |
+
# Add a filter for sentiments
|
|
|
77 |
filter_sentiment = st.selectbox("", ["ALL", "POSITIVE", "NEGATIVE"])
|
78 |
+
# Filter the dataframe
|
|
|
79 |
if filter_sentiment != "ALL":
|
80 |
df = df[df['Sentiment'] == filter_sentiment]
|
81 |
+
# Max number of rows to display at a time
|
|
|
82 |
max_rows = 10
|
83 |
|
84 |
+
# Table generation
|
85 |
table_html = (df.style
|
86 |
.set_properties(**{'text-align': 'left'})
|
87 |
.set_table_styles([{'selector': 'th', 'props': [('border', '0px')]},
|
|
|
89 |
.set_table_attributes('style="position: sticky; top: 0;"')
|
90 |
.to_html(index=False, escape=False))
|
91 |
|
92 |
+
# Scrollable content
|
93 |
st.write(f'<div style="height: {max_rows*30}px; overflow-y: scroll;">{table_html}</div>', unsafe_allow_html=True,header=True,sticky_header=True)
|
94 |
|
95 |
+
#save output as csv
|
96 |
def convert_df(df):
|
97 |
# IMPORTANT: Cache the conversion to prevent computation on every rerun
|
98 |
return df.to_csv().encode('utf-8')
|
|
|
99 |
csv = convert_df(df)
|
100 |
|
101 |
+
# Download button
|
102 |
st.write("<br>", unsafe_allow_html=True)
|
|
|
103 |
st.download_button(
|
104 |
label="Download data as CSV",
|
105 |
data=csv,
|
106 |
file_name='Review Sentiments.csv'
|
107 |
)
|
108 |
+
|
109 |
+
# Footnote
|
110 |
st.write("<br>", unsafe_allow_html=True)
|
111 |
st.caption('<div style="text-align:center; background-color:#CFEDFF;padding: 6px">crafted with ❤️</div>', unsafe_allow_html=True)
|