Sentiment_2.0 / app.py
Viktorya031's picture
Update app.py
318ea53 verified
Raw
History Blame Contribute Delete
8.07 kB
import gradio as gr
from collections import Counter
import nltk
import torch
import numpy as np
import pandas as pd
import re
import string
import json
from typing import Tuple
from dataclasses import dataclass
from nltk.corpus import stopwords
from pymystem3 import Mystem
from torch import nn
# Загрузка необходимых ресурсов NLTK
nltk.download('stopwords', quiet=True)
# Регулярное выражение для поиска стандартных эмодзи и текстовых смайлов
emoji_pattern = re.compile(
u"(["
u"\U0001F600-\U0001F64F" # смайлики
u"\U0001F300-\U0001F5FF" # символы и пиктограммы
u"\U0001F680-\U0001F6FF" # транспортные и маппинг символы
u"\U0001F1E0-\U0001F1FF" # флаги
u"]+)|"
r"(:\)|:\(|;\)|:\-\)|:\-\(|\(:|\):|:D|:P|:\]|O_O|XD|\^\^|<3|:\*|\(\(|\)\))" # текстовые смайлы
)
# Функция для извлечения смайлов
def extract_emojis(text):
matches = emoji_pattern.findall(text)
return ' '.join([match[0] if match[0] else match[1] for match in matches])
# Предобработка текста
mystem = Mystem()
stop_words = set(stopwords.words('russian')) - {'не', 'ни'}
# Загрузка списка матерных слов
with open('list.txt', 'r', encoding='utf-8') as f:
swear_words = set(f.read().splitlines())
# Загрузка данных
data = pd.read_csv('data.csv')
# Функция для извлечения смайлов
data['emojis'] = data['text'].apply(extract_emojis)
print(data[['text', 'emojis']].head(10))
# Подсчет наиболее часто используемых смайлов
positive_emojis = ' '.join(data[data['sentiment'] == 1]['emojis'])
negative_emojis = ' '.join(data[data['sentiment'] == 0]['emojis'])
positive_emojis_count = Counter(positive_emojis.split())
negative_emojis_count = Counter(negative_emojis.split())
print("Most common emojis in positive tweets:", positive_emojis_count.most_common(10))
print("Most common emojis in negative tweets:", negative_emojis_count.most_common(10))
# Паттерн для поиска имен пользователей (если нужен)
username_pattern = re.compile(r"@\w+")
def data_preprocessing(text: str, positive_emoji_placeholder: str = 'отлично', negative_emoji_placeholder: str = 'плохо') -> Tuple[str, int]:
"""Preprocessing string: lowercase, removing html-tags, punctuation, stopwords, and replacing emojis.
Also calculates the count of swear words.
"""
def replace_emoji(match):
emoji = match.group()
if emoji in positive_emojis:
return f" {positive_emoji_placeholder} "
elif emoji in negative_emojis:
return f" {negative_emoji_placeholder} "
return emoji
text = emoji_pattern.sub(replace_emoji, text.lower())
text = re.sub(r"<.*?>", "", text)
text = "".join([c if c not in string.punctuation else ' ' for c in text])
text = re.sub(r'\b[a-zA-Z]+\b', '', text)
text = username_pattern.sub('', text)
text = re.sub(r'\s+', ' ', text).strip()
text = "".join(mystem.lemmatize(text)).strip()
text = re.sub(r'\b\w*\d\w*\b', '', text)
text = " ".join(word for word in text.split() if word not in stop_words)
swear_count = sum(1 for word in text.split() if word in swear_words)
return text, swear_count
# Преобразование текста в числовое представление
def preprocess_for_model(text: str, vocab_to_int: dict, seq_len: int) -> np.array:
"""Convert cleaned text to padded numerical representation."""
words = text.split()
indices = [vocab_to_int.get(word, 0) for word in words]
if len(indices) < seq_len:
indices = [0] * (seq_len - len(indices)) + indices
else:
indices = indices[:seq_len]
return np.array(indices)
# Инициализация конфигурации и модели
@dataclass
class ConfigRNN:
vocab_size: int
device: str
n_layers: int
embedding_dim: int
hidden_size: int
seq_len: int
bidirectional: bool
# Сначала создаем конфигурацию
net_config = ConfigRNN(
vocab_size=10000, # Placeholder, так как vocab_to_int еще не загружен
device='cpu',
n_layers=1,
embedding_dim=8,
hidden_size=16,
seq_len=110,
bidirectional=False
)
# Загрузка модели и словаря
class RNNNet(nn.Module):
def __init__(self, rnn_conf):
super().__init__()
self.rnn_conf = rnn_conf
self.embedding = nn.Embedding(self.rnn_conf.vocab_size, self.rnn_conf.embedding_dim)
self.rnn_cell = nn.RNN(
input_size=self.rnn_conf.embedding_dim,
hidden_size=self.rnn_conf.hidden_size,
batch_first=True,
bidirectional=self.rnn_conf.bidirectional,
num_layers=self.rnn_conf.n_layers
)
self.bidirect_factor = 2 if self.rnn_conf.bidirectional else 1
self.linear = nn.Sequential(
nn.Linear(self.rnn_conf.hidden_size * self.bidirect_factor, 16),
nn.Tanh(),
nn.Linear(16, 1)
)
def forward(self, x):
x = self.embedding(x.to(self.rnn_conf.device))
output, hidden = self.rnn_cell(x)
hidden = torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim=1) if self.rnn_conf.bidirectional else hidden[-1,:,:]
out = self.linear(hidden)
return out
def load_vocab_and_model():
# Загрузка словаря
try:
with open('vocab_to_int.json', 'r', encoding='utf-8') as f:
vocab_to_int = json.load(f)
except FileNotFoundError:
raise RuntimeError("Файл vocab_to_int.json не найден.")
# Обновление конфигурации с реальным размером словаря
net_config.vocab_size = len(vocab_to_int) + 1
# Загрузка модели
model = RNNNet(net_config)
try:
model.load_state_dict(torch.load("model_rnn.pth", map_location=torch.device('cpu')))
except FileNotFoundError:
raise RuntimeError("Файл модели model_rnn.pth не найден.")
model.eval()
return model, vocab_to_int
# Теперь загружаем модель и словарь
model, vocab_to_int = load_vocab_and_model()
def predict(text: str):
cleaned_text, _ = data_preprocessing(text)
numerical_representation = preprocess_for_model(cleaned_text, vocab_to_int, net_config.seq_len)
input_tensor = torch.from_numpy(numerical_representation).unsqueeze(0) # Add batch dimension
with torch.no_grad():
output = model(input_tensor)
prediction = torch.sigmoid(output).item()
return "Positive 👍" if prediction > 0.45 else "Negative 👎"
# Создание интерфейса с кнопкой Submit и другими элементами
interface = gr.Interface(
fn=predict,
inputs=gr.Textbox(lines=2, placeholder="Введите текст здесь..."),
outputs=gr.Textbox(label="Предсказание"),
title="Текстовый Анализатор Настроений",
description="Введите текст, чтобы узнать, является ли он положительным или отрицательным. Попробуйте добавить эмодзи для более интересного анализа!",
theme="compact",
examples=[
["Сегодня был отличный день! 🌟 Прекрасное настроение и много позитивных эмоций! 😊 Спасибо всем за поддержку и вдохновение!"],
["Не могу поверить, как всё пошло не так сегодня. все очень плохо((#тяжелыйдень #"]
]
)
# Запуск приложения
interface.launch(share=True)