studfaceval / app5_selectbox /evaluation_analysis.py
MENG21's picture
7f80a20
# import gspread
import pandas as pd
# from oauth2client.service_account import ServiceAccountCredentials
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
import re
import streamlit as st
import hydralit_components as hc
from matplotlib import pyplot as plt
# import numpy as np
from wordcloud import WordCloud
import plotly.graph_objs as go
# import plotly.express as px
# import plotly.figure_factory as ff
# from PIL import ImageFont
# from app5_selectbox.langchain_llama_gpu import llm_chain
from app5_selectbox.g4f_prompt import g4f_prompt
# from app5_selectbox.llama2_prompt import llama_prompt
from app5_selectbox.naive_bayes_cl import nb_clf
# from HF_inference import analyze_sintement
from HF_pipeline import analyze_sintement
models = ['BERT-BASE MODEL', 'BERT-LARGE MODEL', 'DISTILIBERT MODEL', 'NAIVE BAYES MODEL']
# old path
# model_list = [
# r"/home/aibo/prototype_v1/BERT_BASE/bert_sentiment_model",
# r"/home/aibo/prototype_v1/BERT_LARGE/bert_sentiment_model",
# r"/home/aibo/prototype_v1/DISTILIBERT/bert_sentiment_model"
# ]
# new path
model_list = [
r"/home/aibo/prototype_v1/HF_MODELS/HUB/stud-fac-eval-bert-base-uncased",
r"/home/aibo/prototype_v1/HF_MODELS/HUB/stud-fac-eval-bert-large-uncased",
r"/home/aibo/prototype_v1/HF_MODELS/HUB/stud-fac-eval-distilbert-base-uncased",
]
model_tokenizer_list = ['bert-base-uncased', 'bert-large-uncased', 'distilbert-base-uncased']
selected_model = 0
llama2_g4f = False # true == llama2
# if 'chkbx_selected_model' in st.session_state:
# st.write("selected model: ",models.index(st.session_state.chkbx_selected_model))
# if 'chkbx_selected_model' not in st.session_state:
# st.write("no selected!")
def clean_text(text_list):
cleaned_samples = []
for text_sample in text_list:
# Case folding and normalization
cleaned_text = str(text_sample).lower()
# Removing non-alphabetic characters
cleaned_text = re.sub(r'[^a-zA-Z\s]', '', cleaned_text)
cleaned_samples.append(cleaned_text)
return cleaned_samples
# # local model
# def classify_sentiments(text_samples, tokenizer, model):
# instructor_comments = []
# predicted_sentiments = []
# predicted_sentiments_scores = []
# # Iterate through the text samples and classify the sentiment
# for idx, text_sample in enumerate(text_samples):
# # Tokenize the text sample
# inputs = tokenizer(text_sample, return_tensors="pt")
# # Perform sentiment classification
# outputs = model(**inputs)
# # Get the predicted sentiment (positive/negative)
# predicted_class = torch.argmax(outputs.logits, dim=1).item()
# # Get the probabilities for each class
# probabilities = torch.softmax(outputs.logits, dim=1).tolist()[0]
# # Store results
# instructor_comments.append(text_sample)
# predicted_sentiments.append("positive" if predicted_class == 1 else "negative")
# predicted_sentiments_scores.append({"positive": probabilities[1]*100, "negative": probabilities[0]*100})
# return instructor_comments, predicted_sentiments, predicted_sentiments_scores
# inference
def classify_sentiments(text_samples, model):
instructor_comments = []
predicted_sentiments = []
predicted_sentiments_scores = []
# text = ["i love this", "nice one!", "happy!"]
selected_model = model
results = [analyze_sintement(t, selected_model) for t in text_samples]
for idx, result in enumerate(results):
# st.text(result[0])
# predicted_class, probabilities = analyze_sintement(text_sample, model)
# Store results
instructor_comments.append(text_samples[idx])
predicted_sentiments.append("positive" if result[0] == "LABEL_1" else "negative")
predicted_sentiments_scores.append({"positive": result[1]*100, "negative": 100-(result[1]*100)})
# st.write(instructor_comments)
return instructor_comments, predicted_sentiments, predicted_sentiments_scores
def calculate_average_scores(probability_list):
total_comments = len(probability_list)
total_positive = 0
total_negative = 0
for prob_dict in probability_list:
total_positive += prob_dict['positive']
total_negative += prob_dict['negative']
average_positive = total_positive / total_comments
average_negative = total_negative / total_comments
return average_positive, average_negative
def eval_analysis(instructor, instructor_comment, criteria_results, selected_model):
if selected_model < 3:
## local model
# model = model_list[selected_model]
# model_tokenizer = model_tokenizer_list[selected_model]
# model_tokenizer = model_list[selected_model]
# loaded_model = AutoModelForSequenceClassification.from_pretrained(model)
# tokenizer = AutoTokenizer.from_pretrained(model_tokenizer)
clean_instructor_comment = clean_text(instructor_comment)
# print(models[selected_model])
# predicted_sentiments_transformer = classify_sentiments(clean_instructor_comment, tokenizer, loaded_model) # local model
predicted_sentiments_transformer = classify_sentiments(clean_instructor_comment, models[selected_model]) # inference
predicted_sentiments = predicted_sentiments_transformer[1]
scores = predicted_sentiments_transformer[2]
elif selected_model == 3:
try:
instructor_comment, predicted_sentiments, scores = nb_clf(instructor_comment)
# scores = scores[1]
except Exception as e:
st.exception(e)
else: pass
sample_predictions = []
comments_data = []
negative_count = 0
neutral_count = 0
positive_count = 0
# average_sintement_score = np.average(scores['positive'])
average_positive, average_negative = calculate_average_scores(scores)
# st.text(calculate_average_scores(scores))
for text, prediction, score in zip(instructor_comment, predicted_sentiments, scores):
sample_predictions.append(prediction)
comments_data.append((text, prediction, score['positive']))
if prediction == "negative":
negative_count += 1
elif prediction == "neutral":
neutral_count += 1
else:
positive_count += 1
sentiment_texts = {
'positive': [],
'negative': []
}
for text, sentiment in zip(instructor_comment, sample_predictions):
sentiment_texts[sentiment].append(text)
text_for_llama = ""
def sentiment_tbl():
# Create DataFrame
comments_df = pd.DataFrame(instructor_comment, columns=["Comments"])
# Drop index
comments_df_display = comments_df.copy()
comments_df_display.reset_index(drop=True, inplace=True)
# Create DataFrame
comments_data_df = pd.DataFrame(comments_data, columns=["Comments", "Sentiment", "Score"])
# Define a function to apply row-wise styling
def highlight_row(row):
if row["Sentiment"] == "positive":
return ['background-color: lightgreen'] * len(row)
elif row["Sentiment"] == "negative":
return ['background-color: lightcoral'] * len(row)
else:
return [''] * len(row)
# Set index to start at 1
comments_data_df.index += 1
# Apply styling
styled_df = comments_data_df.style.apply(highlight_row, axis=1)
# Display styled DataFrame
st.table(styled_df)
theme_bad = {'bgcolor': '#FFF0F0','title_color': 'red','content_color': 'red','icon_color': 'red', 'icon': 'fa fa-times-circle'}
theme_good = {'bgcolor': '#EFF8F7','title_color': 'green','content_color': 'green','icon_color': 'green', 'icon': 'fa fa-check-circle'}
st.write(f"### SENTIMENTS/RECOMENDATION INSIGHTS")
with st.expander("Sentiment Analysis"):
st.title("Sentiment Analysis Dashboard")
st.write(f"## Using {models[selected_model]}")
st.write("### Sentiment Rating")
cc = st.columns(2)
with cc[0]:
# can just use 'good', 'bad', 'neutral' sentiment to auto color the card
hc.info_card(title='Positive', content=str(round(average_positive,6))+ '%', sentiment='good', bar_value=round(average_positive,6))
with cc[1]:
hc.info_card(title='Negative', content=str(round(average_negative,6))+ '%', sentiment='bad', bar_value=round(average_negative,6))
# st.write(f"#### Positive: {positive_count} - {round(average_positive,6)} %")
# st.write(f"#### Negative: {negative_count} - {round(average_negative,6)} %")
# st.write("### Sentiment Rating")
# st.write(f"#### Positive: {round(average_positive*100,2)} %")
# st.write(f"#### Negative: {round(average_negative*100,2)} %")
sentiment_counts = pd.Series(sample_predictions).value_counts()
desired_order = ['positive', 'negative']
sentiment_counts = sentiment_counts.reindex(desired_order, fill_value=0)
percentage_distribution = sentiment_counts / len(sample_predictions) * 100
sentiment_tbl()
st.write("### Sentiment Distribution")
fig = go.Figure(layout=dict(
autosize=True, # Set autosize to True for automatic adjustment
))
fig.add_trace(go.Bar(
x=percentage_distribution.index,
y=sentiment_counts.values,
marker_color=['green', 'red'],
text=[f'{percentage:.2f}% {des_order.upper()}' for percentage, des_order in zip(percentage_distribution, desired_order)],
textposition='auto'
))
fig.update_layout(
width=600,
height=500,
xaxis=dict(title='Sentiment', tickangle=45),
yaxis=dict(title='Count'),
title='Sentiment Distribution in Sample Predictions',
)
st.plotly_chart(fig)
for sentiment, texts in sentiment_texts.items():
combined_texts = ' '.join(texts)
combined_texts = combined_texts.split()
filtered_words = [word for word in combined_texts if len(word) > 2]
combined_texts = ' '.join(filtered_words)
if combined_texts == "":
continue
font_path = "/home/aibo/prototype_v1/prototype/app5_selectbox/QuartzoBold-W9lv.ttf"
wordcloud = WordCloud(font_path=font_path, width=800, height=600, background_color='white', max_words=15, min_word_length=3, stopwords={}).generate(combined_texts)
st.write(f"### Word Cloud for {sentiment.capitalize()} Sentiment")
plt.figure(figsize=(10, 6))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
wordcloud_fig = plt.gcf()
st.pyplot(wordcloud_fig)
if sentiment == "negative":
text_for_llama = sentiment_texts[sentiment]
# Generate a word cloud from all the text data
all_text = ' '.join(instructor_comment)
all_text = all_text.split()
filtered_words = [word for word in all_text if len(word) > 2]
all_text = ' '.join(filtered_words)
st.write("### Word Cloud for All Sentiments")
wordcloud = WordCloud(font_path=font_path, width=800, height=800, background_color='white', max_words=200, min_word_length=3, stopwords={}).generate(all_text)
# Create a Matplotlib figure
plt.figure(figsize=(8, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
wordcloud_fig = plt.gcf()
st.pyplot(wordcloud_fig)
if text_for_llama == "":
with st.expander("Expressing Gratitude and Dedication"):
st.title("Expressing Gratitude and Dedication")
text_for_llama = f"""
There's no negative feedback or comment for the instructor; give him or her a short letter to say.
[Your Name] = The Management
[Instructor's Name] = {instructor}
"""
prompt = text_for_llama
while True:
try:
with st.spinner("Generating...."):
# if not llama2_g4f: st.write(g4f_prompt(prompt)) #################
# else: st.write(llama_prompt(prompt)) #################
st.success("Generation Complete!")
break
except Exception as e:
pass
else:
with st.expander("Recommendation"):
# st.title('Recommendation:')
# text_for_llama = text_for_llama.split()
text_for_llama = ", ".join(text_for_llama)
text_for_llama = f"""
Based on these students' feedback: {str(text_for_llama)}. \n
Please generate a short letter to the instructor with ten recommendations in bullet format. Make it in sentence type and English only.
Define the best letter's subject based on the recommendation.
Subject is Recommendations for Effective Teaching
Sender's Name is 'The Management'
receiver's or Instructor's Name is {instructor}
"""
prompt = text_for_llama
while True:
try:
with st.spinner("Generating...."):
# if not llama2_g4f: st.write(g4f_prompt(prompt)) #################
# else: st.write(llama_prompt(prompt)) #################
st.success("Generation Complete!")
break
except Exception as e:
pass