ghost-love-you
chore: Update app.py with new translation and sentiment analysis models
a66c985
raw
history blame contribute delete
No virus
8.87 kB
import streamlit as st
from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM, AutoModelForSequenceClassification
from GoogleNews import GoogleNews
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import plotly.express as px
import os
import datetime
from dotenv import load_dotenv
import requests
load_dotenv()
st.title('NLP系统展示:sunglasses:')
# ------------------------- 新闻分类 -------------------------
# 本来打算做推特帖子情感分析, 发现官方获取帖子的free API限制较多, 改为GoogleNews做新闻搜索
st.subheader("新闻搜索和情感分类")
def get_news(query):
googlenews = GoogleNews(lang='en', region='US', period='1d')
number_of_pages = 5
final_list = []
googlenews.search(query)
print("Total Pages: ", googlenews.total_count())
for page in range(1, number_of_pages + 1):
page_result = googlenews.page_at(page)
final_list = final_list + page_result
return final_list
query = st.text_input("输入关键字")
if st.button("搜索"):
with st.spinner("正在加载模型 ..."):
classifier = pipeline(task="text-classification", model="SamLowe/roberta-base-go_emotions", top_k=None)
with st.spinner("正在加载最新新闻 ..."):
allnews = get_news(query)
with st.spinner("最新新闻已收到, 分析情绪中 ..."):
df = pd.DataFrame(columns=["sentence", "date","best","second"])
for curnews in allnews:
cur_sentence = curnews["title"]
cur_date = curnews["date"]
model_outputs = classifier(cur_sentence)
cur_result = model_outputs[0]
# label 1
label = cur_result[0]['label']
score = cur_result[0]['score']
percentage = round(score * 100, 2)
str1 = label + " (" + str(percentage) + ")%"
# label 2
label = cur_result[1]['label']
score = cur_result[1]['score']
percentage = round(score * 100, 2)
str2 = label + " (" + str(percentage) + ")%"
df.loc[len(df.index)] = [cur_sentence, cur_date, str1, str2]
st.dataframe(df)
# 统计每个情绪标签的出现频次
emotion_counts = df['best'].apply(lambda x: x.split(" ")[0]).value_counts()
# 绘制柱状图
st.subheader("情绪分析柱状图")
fig, ax = plt.subplots()
sns.barplot(x=emotion_counts.index, y=emotion_counts.values, ax=ax)
plt.xticks(rotation=45, ha='right')
plt.ylabel('Frequency')
plt.xlabel('Emotions')
st.pyplot(fig)
# 绘制饼状图
st.subheader("情绪分析饼状图")
fig, ax = plt.subplots()
ax.pie(emotion_counts.values, labels=emotion_counts.index, autopct='%1.1f%%', startangle=90)
ax.axis('equal')
st.pyplot(fig)
# ----------------------------------------------------------------
# ------------------------- 论坛情感统计 -------------------------
# 数据来源byrbbs, 为了防止滥用, 不提供公用API, 原项目也会在验收后删除
st.subheader("论坛情感统计")
# Cache
@st.cache_resource
def load_model_and_tokenizer():
tokenizer = AutoTokenizer.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
model = AutoModelForSeq2SeqLM.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
return tokenizer, model
tokenizer, model_zh_en = load_model_and_tokenizer()
@st.cache_data(show_spinner=False)
def get_comments(time, max_comments=99999):
url = os.getenv("API_URL") + f"?day={time}"
token = os.getenv("API_TOKEN")
headers = {"Authorization": f"token {token}"}
response = requests.get(url, headers=headers)
# 检查请求是否成功
if response.status_code == 200:
comments = response.json()
df = pd.DataFrame(comments)
df = df.head(max_comments)
return df
else:
print(f"Failed to retrieve data: {response.status_code}")
st.error("Failed to load comments.")
return None
@st.cache_data(show_spinner=False)
def batch_translate(batch_texts, _model, _tokenizer):
inputs = _tokenizer(batch_texts, return_tensors="pt", padding=True, truncation=True, max_length=512)
outputs = _model.generate(**inputs, max_length=512, num_beams=5, early_stopping=True)
batch_translations = [_tokenizer.decode(output, skip_special_tokens=True) for output in outputs]
return batch_translations
def display_translations(comments, batch_size=16):
if comments is not None:
# 创建一个占位符
placeholder = st.empty()
for i in range(0, len(comments['content']), batch_size):
batch_texts = comments['content'][i:i+batch_size].tolist()
translations = batch_translate(batch_texts, model_zh_en, tokenizer)
comments.loc[i:i+batch_size-1, 'content_en'] = translations
# 使用占位符显示数据框
placeholder.dataframe(comments[['content', 'content_en']][:i+batch_size])
return comments[['content', 'content_en']]
else:
st.error("Failed to load comments.")
@st.cache_data(show_spinner=False)
def batch_sentiment_analysis(batch_texts, _classifier):
model_outputs = _classifier(batch_texts)
return model_outputs
def display_sentiments(translate_comments, batch_size=16):
if translate_comments is not None:
# 创建一个占位符
placeholder = st.empty()
df_sentiments = pd.DataFrame(columns=["content", "translation", "emotion", "score"])
for i in range(0, len(translate_comments), batch_size):
batch_texts = translate_comments['content_en'][i:i+batch_size].tolist()
model_outputs = batch_sentiment_analysis(batch_texts, classifier)
for j, output in enumerate(model_outputs):
# 获取最高分数的情绪标签
best_emotion = output[0]['label']
best_score = output[0]['score']
df_sentiments.loc[len(df_sentiments.index)] = [translate_comments['content'][i+j], translate_comments['content_en'][i+j], best_emotion, best_score]
# 使用占位符显示数据框
placeholder.dataframe(df_sentiments)
# 统计每个情绪标签的出现频次
emotion_counts = df_sentiments['emotion'].value_counts()
# 绘制柱状图
emotion_counts = df_sentiments['emotion'].value_counts()
bar_fig = px.bar(emotion_counts, x=emotion_counts.index, y=emotion_counts.values,
labels={'index': 'Emotions', 'value': 'Frequency'},
title="论坛情感分析柱状图")
st.plotly_chart(bar_fig, use_container_width=True)
# 绘制饼状图
pie_fig = px.pie(emotion_counts, names=emotion_counts.index, values=emotion_counts.values,
title="论坛情感分析饼状图", hole=.3)
st.plotly_chart(pie_fig, use_container_width=True)
else:
st.error("Failed to analyze sentiments.")
# 选择日期
cur_date = datetime.datetime.now().strftime("%Y-%m-%d")
selected_date = st.date_input("选择日期", value=pd.to_datetime(cur_date))
model_translate = [
"Helsinki-NLP/opus-mt-zh-en"
]
model_emo_analysis = [
"orlco/google-bert-base-cased-fine-tune",
"SamLowe/roberta-base-go_emotions"
]
settings = {
"max_comments": 99999,
"translate_batch_size": 16,
"sentiment_batch_size": 16,
"model_translate": model_translate[0],
"model_emo_analysis": model_emo_analysis[0]
}
with st.sidebar:
st.title("设置")
st.header("翻译模型")
settings["model_translate"] = st.selectbox("Model", model_translate)
st.header("情感分析模型")
settings["model_emo_analysis"] = st.selectbox("Model", model_emo_analysis)
st.header("最大获取帖子数")
settings["max_comments"] = st.number_input("Max Comments", 1, 99999, 99999)
st.header("翻译批处理大小")
settings["translate_batch_size"] = st.number_input("Translate Batch Size", 1, 64, 16)
st.header("情感分析批处理大小")
settings["sentiment_batch_size"] = st.number_input("Sentiment Analysis Batch Size", 1, 64, 16)
if st.button("统计"):
with st.spinner("正在加载模型 ..."):
classifier = pipeline(task="text-classification", model=settings["model_emo_analysis"], top_k=None)
with st.spinner("正在获取当天的帖子 ..."):
comments = get_comments(selected_date, settings["max_comments"])
st.dataframe(comments)
with st.spinner("正在翻译帖子 ..."):
translate_comments = display_translations(comments, settings["translate_batch_size"])
with st.spinner("正在分析评论的情感倾向 ..."):
display_sentiments(translate_comments, settings["sentiment_batch_size"])