File size: 7,630 Bytes
bd97f47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import torch
import numpy as np
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import logging
import re

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


class ToxicityScorer:
    def __init__(self, model=None, tokenizer=None):
        """
        Toxicity Scorer sınıfını başlatır.

        Args:
            model: Zararlılık modeli
            tokenizer: Model için tokenizer
        """
        self.model = model
        self.tokenizer = tokenizer
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        self.is_turkish_model = False

        if model is None or tokenizer is None:
            logging.warning("No toxicity model provided. Using default model.")
            self.load_default_model()

    def load_default_model(self):
        """
        Varsayılan zararlılık modelini yükler
        """
        try:
            # Öncelikle Türkçe duygu analizi modeli deneyelim
            model_name = "savasy/bert-base-turkish-sentiment"
            logging.info(f"Loading Turkish sentiment model: {model_name}")
            self.tokenizer = AutoTokenizer.from_pretrained(model_name)
            self.model = AutoModelForSequenceClassification.from_pretrained(model_name)
            self.model.to(self.device)
            self.is_turkish_model = True
            logging.info("Turkish sentiment model loaded successfully")
        except Exception as e:
            logging.error(f"Error loading Turkish model: {str(e)}")
            try:
                # Yedek olarak genel model yükleyelim
                backup_model = "dbmdz/bert-base-turkish-cased"
                logging.info(f"Trying Turkish BERT model: {backup_model}")
                self.tokenizer = AutoTokenizer.from_pretrained(backup_model)
                self.model = AutoModelForSequenceClassification.from_pretrained(backup_model)
                self.model.to(self.device)
                self.is_turkish_model = True
                logging.info("Turkish BERT model loaded successfully")
            except Exception as e2:
                logging.error(f"Error loading Turkish BERT model: {str(e2)}")
                try:
                    # Son çare olarak İngilizce model kullanalım
                    english_model = "distilbert/distilbert-base-uncased-finetuned-sst-2-english"
                    logging.info(f"Trying English sentiment model: {english_model}")
                    self.tokenizer = AutoTokenizer.from_pretrained(english_model)
                    self.model = AutoModelForSequenceClassification.from_pretrained(english_model)
                    self.model.to(self.device)
                    self.is_turkish_model = False
                    logging.info("English sentiment model loaded successfully")
                except Exception as e3:
                    logging.error(f"Error loading English model: {str(e3)}")
                    raise e3

    def _contains_turkish_profanity(self, text):
        """
        Temel Türkçe küfür ve hakaret kontrolü yapar
        """
        # Türkçede yaygın küfür/hakaret içeren kelimelerin listesi
        turkish_profanity = [
            'aptal', 'salak', 'gerizekalı', 'ahmak', 'enayi', 'mal', 'geri zekalı',
            'beyinsiz', 'budala', 'adi', 'ahlaksız', 'şerefsiz', 'haysiyetsiz',
            'orospu', 'piç', 'yavşak', 'sürtük', 'sürtüğü', 'gavat', 'şerefsiz',
            'siktir', 'pezevenk', 'namussuz'
        ]

        # Noktalama işaretlerini ve sayıları kaldır
        text = re.sub(r'[^\w\s]', '', text.lower())
        text = re.sub(r'\d+', '', text)
        words = text.split()

        # Metinde küfür/hakaret var mı kontrol et
        for word in turkish_profanity:
            if word in words:
                return True

        return False

    def _contains_negative_words(self, text):
        """
        Temel Türkçe olumsuz kelime kontrolü yapar
        """
        # Türkçede yaygın olumsuz kelimeler
        negative_words = [
            'kötü', 'berbat', 'rezalet', 'korkunç', 'iğrenç', 'üzücü', 'acı',
            'başarısız', 'yetersiz', 'düşük', 'zayıf', 'korkutucu', 'tehlikeli',
            'nefret', 'öfke', 'saldırgan', 'yanlış', 'hata', 'hayal kırıklığı'
        ]

        text = text.lower()
        count = sum(1 for word in negative_words if word in text.split())

        # Olumsuz kelime yoğunluğunu hesapla
        return count / len(text.split()) if text.split() else 0

    def score_text(self, text):
        """
        Metin için zararlılık skoru hesaplar.

        Args:
            text: Değerlendirilecek metin

        Returns:
            float: 0 ile 1 arasında zararlılık skoru (1 = çok zararlı)
        """
        if not text or len(text.strip()) == 0:
            return 0.0

        # Temel kural tabanlı kontroller
        profanity_detected = self._contains_turkish_profanity(text)
        negative_ratio = self._contains_negative_words(text)

        if profanity_detected:
            base_score = 0.8  # Küfür/hakaret varsa yüksek başlangıç skoru
        else:
            base_score = negative_ratio * 0.5  # Olumsuz kelime yoğunluğuna göre skor

        try:
            # Model tabanlı skorlama
            inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
            inputs = {key: val.to(self.device) for key, val in inputs.items()}

            with torch.no_grad():
                outputs = self.model(**inputs)

            # Modele göre doğru şekilde skoru alalım
            if self.is_turkish_model:
                # Türkçe duygu analizi modeli için özel işlem
                probs = torch.softmax(outputs.logits, dim=1).cpu().numpy()[0]

                # savasy/bert-base-turkish-sentiment için:
                # 0: negative, 1: neutral, 2: positive
                if len(probs) >= 3:
                    # Negatif olasılığını zararlılık skoru olarak kullan ama çok yüksek değerler üretmemesi için 0.7 ile çarp
                    model_score = probs[0] * 0.7
                else:
                    # İki sınıflı model için
                    model_score = probs[0] * 0.6
            else:
                # İngilizce model için
                probs = torch.softmax(outputs.logits, dim=1).cpu().numpy()[0]
                # İngilizce modeller genellikle Türkçe için çok yüksek sonuçlar verir, bu yüzden 0.5 ile çarp
                model_score = probs[0] * 0.5

            # Kural tabanlı skor ve model skor birleşimi
            final_score = (base_score * 0.4) + (model_score * 0.6)

            # 0-1 aralığına sınırla
            final_score = max(0.0, min(1.0, final_score))

            return final_score

        except Exception as e:
            logging.error(f"Error scoring toxicity: {str(e)}")
            # Hata durumunda sadece kural tabanlı skoru döndür
            return min(base_score, 1.0)

    def batch_score(self, texts, batch_size=16):
        """
        Bir metin listesi için toplu zararlılık skoru hesaplar.

        Args:
            texts: Değerlendirilecek metin listesi
            batch_size: İşlenecek grup boyutu

        Returns:
            list: Zararlılık skorları listesi
        """
        results = []

        for i in range(0, len(texts), batch_size):
            batch_texts = texts[i:i + batch_size]
            batch_scores = [self.score_text(text) for text in batch_texts]
            results.extend(batch_scores)

        return results