File size: 7,197 Bytes
0ac9264
 
 
 
 
 
 
 
b968a85
a8cc4f6
 
 
0ac9264
 
 
 
 
 
 
b968a85
 
 
 
 
 
0ac9264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b968a85
 
 
 
 
 
 
 
 
0ac9264
 
4349862
0ac9264
 
 
 
b968a85
0ac9264
 
 
 
a8cc4f6
 
 
 
 
4349862
0ac9264
b968a85
 
0ac9264
 
 
 
 
 
 
a8cc4f6
 
 
 
b968a85
 
 
 
0ac9264
 
b968a85
0ac9264
a8cc4f6
0ac9264
 
 
a8cc4f6
 
 
0ac9264
b968a85
 
0ac9264
 
 
 
 
 
 
 
 
 
 
 
 
 
b968a85
 
 
 
 
 
 
 
 
 
0ac9264
 
 
 
 
 
 
2fd93e8
0ac9264
 
2fd93e8
0ac9264
 
2fd93e8
0ac9264
 
 
b968a85
 
a8cc4f6
0ac9264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a8cc4f6
0ac9264
a8cc4f6
0ac9264
 
 
 
a8cc4f6
0ac9264
 
 
 
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
import streamlit as st
import pandas as pd
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch.nn.functional as F
import torch
import io
import base64
from stqdm import stqdm

import matplotlib.pyplot as plt
import numpy as np


# Define the model and tokenizer
model_name = 'nlptown/bert-base-multilingual-uncased-sentiment'
model = AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
st.set_page_config(layout="wide")

# Import the new model and tokenizer
class_model_name = 'facebook/bart-large-mnli'
class_model = AutoModelForSequenceClassification.from_pretrained(class_model_name)
class_tokenizer = AutoTokenizer.from_pretrained(class_model_name)


#defs
def classify_reviews(reviews):
    inputs = tokenizer(reviews, return_tensors='pt', truncation=True, padding=True, max_length=512)
    outputs = model(**inputs)
    probabilities = F.softmax(outputs.logits, dim=1).tolist()  
    return probabilities

def top_rating(scores):
    return scores.index(max(scores)) + 1  

def top_prob(scores):
    return max(scores)

def get_table_download_link(df):
    csv = df.to_csv(index=False)
    b64 = base64.b64encode(csv.encode()).decode()
    return f'<a href="data:file/csv;base64,{b64}" download="data.csv">Download csv file</a>'


# Function for classifying with the new model
def classify_with_new_classes(reviews, class_name):
    inputs = class_tokenizer(reviews, return_tensors='pt', truncation=True, padding=True, max_length=512)
    outputs = class_model(**inputs)
    probabilities = F.softmax(outputs.logits, dim=1).tolist()  
    class_scores = [prob[1] for prob in probabilities]  # Assuming binary classification
    return class_scores

def main():
    st.title('Sentiment Analysis')
    st.markdown('Upload an Excel file to get sentiment analytics')

    file = st.file_uploader("Upload an excel file", type=['xlsx'])
    review_column = None
    df = None
    class_names = None  # New variable for class names

    if file is not None:
        try:
            df = pd.read_excel(file)
            # Drop rows where all columns are NaN
            df = df.dropna(how='all')
            # Replace blank spaces with NaN, then drop rows where all columns are NaN again
            df = df.replace(r'^\s*$', np.nan, regex=True)
            df = df.dropna(how='all')
            review_column = st.selectbox('Select the column from your excel file containing text', df.columns)
            df[review_column] = df[review_column].astype(str)

            class_names = st.text_input('Enter the possible class names separated by comma')  # New input field for class names
        except Exception as e:
            st.write("An error occurred while reading the uploaded file. Please make sure it's a valid Excel file.")
            return

    start_button = st.button('Start Analysis')

    if start_button and df is not None:
        # Drop rows with NaN or blank values in the review_column
        df = df[df[review_column].notna()]
        df = df[df[review_column].str.strip() != '']

        class_names = [name.strip() for name in class_names.split(',')]  # Split class names into a list
        for name in class_names:  # Add a new column for each class name
            df[name] = 0.0

        if review_column in df.columns:
            with st.spinner('Performing sentiment analysis...'):
                df, df_display = process_reviews(df, review_column, class_names)

            display_ratings(df, review_column)  # updated this line
            display_dataframe(df, df_display)
        else:
            st.write(f'No column named "{review_column}" found in the uploaded file.')





def process_reviews(df, review_column, class_names):
    with st.spinner('Classifying reviews...'):
        progress_bar = st.progress(0)
        total_reviews = len(df[review_column].tolist())
        review_counter = 0

        batch_size = 50
        raw_scores = []
        reviews = df[review_column].tolist()
        for i in range(0, len(reviews), batch_size):
            batch_reviews = reviews[i:i+batch_size]
            batch_scores = classify_reviews(batch_reviews)
            raw_scores.extend(batch_scores)
            review_counter += len(batch_reviews)
            progress_bar.progress(review_counter / total_reviews)
            
    class_scores_dict = {}  # New dictionary to store class scores
    for name in class_names:
        with st.spinner(f'Generating classes for {name}...'):
            class_scores = classify_with_new_classes(df[review_column].tolist(), name)
            df[name] = class_scores
            class_scores_dict[name] = class_scores  # Store class scores in the dictionary

    # Add a new column with the class that has the highest score
    df['Highest Class'] = df[class_names].idxmax(axis=1)

    df_new = df.copy()
    df_new['raw_scores'] = raw_scores
    scores_to_df(df_new)
    df_display = scores_to_percent(df_new.copy())

    # Get all columns excluding the created ones and the review_column
    remaining_columns = [col for col in df.columns if col not in [review_column, 'raw_scores', 'Weighted Rating', 'Rating', 'Probability', '1 Star', '2 Star', '3 Star', '4 Star', '5 Star', 'Highest Class']]

    # Reorder the dataframe with selected columns first, created columns next, then the remaining columns
    df_new = df_new[[review_column, 'Weighted Rating', 'Rating', 'Probability', '1 Star', '2 Star', '3 Star', '4 Star', '5 Star'] + class_names + ['Highest Class'] + remaining_columns]

    # Reorder df_display as well
    df_display = df_display[[review_column, 'Weighted Rating', 'Rating', 'Probability', '1 Star', '2 Star', '3 Star', '4 Star', '5 Star'] + class_names + ['Highest Class'] + remaining_columns]

    return df_new, df_display





def scores_to_df(df):
    for i in range(1, 6):
        df[f'{i} Star'] = df['raw_scores'].apply(lambda scores: scores[i-1]).round(2)

    df['Rating'] = df['raw_scores'].apply(top_rating)
    df['Probability'] = df['raw_scores'].apply(top_prob).round(2)
    # Compute the Weighted Rating
    df['Weighted Rating'] = sum(df[f'{i} Star']*i for i in range(1, 6))
    
    df.drop(columns=['raw_scores'], inplace=True)

def scores_to_percent(df):
    for i in range(1, 6):
        df[f'{i} Star'] = df[f'{i} Star'].apply(lambda x: f'{x*100:.0f}%')

    df['Probability'] = df['Probability'].apply(lambda x: f'{x*100:.0f}%')

    return df

def convert_df_to_csv(df):
   return df.to_csv(index=False).encode('utf-8')

def display_dataframe(df, df_display):
    csv = convert_df_to_csv(df)

    col1, col2, col3, col4, col5, col6, col7, col8, col9 = st.columns(9)

    with col1:
        st.download_button(
            "Download CSV",
            csv,
            "data.csv",
            "text/csv",
            key='download-csv'
        )

    st.dataframe(df_display)

def display_ratings(df, review_column):
    cols = st.columns(5)
    
    for i in range(1, 6):
        rating_counts = df[df['Rating'] == i].shape[0]
        cols[i-1].markdown(f"### {rating_counts}")
        cols[i-1].markdown(f"{'⭐' * i}")
        


if __name__ == "__main__":
    main()