File size: 4,047 Bytes
540fe64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import pandas as pd
import pickle
import transformers as tfs
from catboost import CatBoostClassifier
from sklearn.linear_model import LogisticRegression
import numpy as np
import torch as t
from transformers import AutoTokenizer, AutoModelForSequenceClassification

st.set_page_config(page_title="# Выявление негативных комментариев с BERT")

st.markdown('# Выявление негативных комментариев с BERT')

with st.expander("Описание проекта"):
    st.write("""
        Интернет-магазин «Викишоп» запускает новый сервис. 
        Теперь пользователи могут редактировать и дополнять описания товаров, как в вики-сообществах. 
        То есть клиенты предлагают свои правки и комментируют изменения других. 
        Магазину нужен инструмент, который будет искать токсичные комментарии и отправлять их на модерацию. 
    """)


def detect_language(text):
    first_letter = text[0].lower()
    if 'а' <= first_letter <= 'я':
        return 'ru'
    
    
def ru_bert_comments(text):

    model_checkpoint = 'cointegrated/rubert-tiny-toxicity'
    tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
    model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint)
    if t.cuda.is_available():
        model.cuda()
        
    def text2toxicity(text, aggregate=True):
        """ Calculate toxicity of a text (if aggregate=True) or a vector of toxicity aspects (if aggregate=False)"""
        with t.no_grad():
            inputs = tokenizer(text, return_tensors='pt', truncation=True, padding=True).to(model.device)
            proba = t.sigmoid(model(**inputs).logits).cpu().numpy()
        if isinstance(text, str):
            proba = proba[0]
        if aggregate:
            return 1 - proba.T[0] * (1 - proba.T[-1])
        return proba
   
    return round(text2toxicity(text, True))

def preprocessing(text):
    lang = detect_language(text)
    if lang == "ru":
        return ru_bert_comments(str(text))
    else:
        tokenizer = tfs.AutoTokenizer.from_pretrained('unitary/toxic-bert')
        model = tfs.AutoModel.from_pretrained('unitary/toxic-bert')
    tokenized = tokenizer.encode(text, add_special_tokens=True)
    
    if len(tokenized) > 512:
        truncated_tokens = tokenized[:510]  
        truncated_tokens = [101] + truncated_tokens + [102]
        tokenized = truncated_tokens
    
    padded = np.array(tokenized + [0] * (512 - len(tokenized)))
    attention_mask = np.where(padded != 0, 1, 0)
    input_ids = t.tensor(padded)
    attention_mask = t.tensor(attention_mask)

    with t.no_grad():
        embeddings = model(input_ids.unsqueeze(0), attention_mask=attention_mask.unsqueeze(0))[0][:, 0, :].cpu().numpy()

    return embeddings

def query(features):
    model = pickle.load(open('models/toxic_comments_bert.pkl', 'rb'))
    predict = model.predict(features)
    return predict

comment = st.text_area("Введите ваш комментарий, модель работает на английском и русском языках и нажмите Ctrl+Enter", "")
result = None

if comment:
    st.markdown('## Результат:')
    embeddings = preprocessing(comment)
    if isinstance(embeddings, int):
        if embeddings == 0:
            result = 'Комментарий не токсичный'
        else:
            result = 'Комментарий является токсичным'
    else:        
        if query(embeddings) == 0:
            result = 'Комментарий не токсичный'
        else:
            result = 'Комментарий является токсичным'
        
if result is not None:
    st.write(result)