File size: 6,015 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
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import numpy as np
import logging

logger = logging.getLogger(__name__)


class SentimentAnalyzer:
    """
    Türkçe metinler için duygu analizi yapan sınıf.
    Pozitif, negatif ve nötr duygu skorları üreterek metnin duygusal tonunu analiz eder.
    """

    def __init__(self, model=None, tokenizer=None):
        """
        Duygu analizi modülünü başlatır.

        Args:
            model: Duygu analizi modeli (isteğe bağlı)
            tokenizer: Model için tokenizer (isteğe bağlı)
        """
        self.model = model
        self.tokenizer = tokenizer
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        self.model_info = {"name": "Bilinmeyen Model", "language": "unknown"}

        if model is None or tokenizer is None:
            logger.info("Duygu analizi için varsayılan model yükleniyor...")
            self.load_default_model()

    def load_default_model(self):
        """Varsayılan duygu analizi modelini yükler"""
        try:
            # Türkçe duygu analizi modeli
            model_name = "savasy/bert-base-turkish-sentiment"
            logger.info(f"Türkçe duygu analizi modeli yükleniyor: {model_name}")

            self.tokenizer = AutoTokenizer.from_pretrained(model_name)
            self.model = AutoModelForSequenceClassification.from_pretrained(model_name)
            self.model.to(self.device)

            self.model_info = {
                "name": model_name,
                "description": "Türkçe duygu analizi modeli",
                "language": "tr"
            }

            logger.info("Duygu analizi modeli başarıyla yüklendi")
            return True
        except Exception as e:
            logger.error(f"Duygu analizi modeli yüklenemedi: {str(e)}")

            # Yedek model dene
            try:
                backup_model = "dbmdz/bert-base-turkish-cased"
                logger.info(f"Yedek Türkçe model deneniyor: {backup_model}")

                self.tokenizer = AutoTokenizer.from_pretrained(backup_model)
                self.model = AutoModelForSequenceClassification.from_pretrained(backup_model)
                self.model.to(self.device)

                self.model_info = {
                    "name": backup_model,
                    "description": "Genel amaçlı Türkçe BERT modeli",
                    "language": "tr"
                }

                logger.info("Yedek model başarıyla yüklendi")
                return True
            except Exception as e2:
                logger.error(f"Yedek model yüklenemedi: {str(e2)}")
                raise e2

    def analyze_sentiment(self, text):
        """
        Metindeki duygu tonunu analiz eder.

        Args:
            text: Analiz edilecek metin

        Returns:
            dict: {
                'positive': float,  # Pozitif duygu skoru (0-1)
                'neutral': float,   # Nötr duygu skoru (0-1)
                'negative': float,  # Negatif duygu skoru (0-1)
                'dominant': str     # Baskın duygu (positive, neutral, negative)
                'score': float      # -1 (çok negatif) ile 1 (çok pozitif) arasında genel skor
            }
        """
        if not text or len(text.strip()) == 0:
            return {
                'positive': 0.0,
                'neutral': 1.0,
                'negative': 0.0,
                'dominant': 'neutral',
                'score': 0.0
            }

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

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

            # Sonuçları işle
            logits = outputs.logits
            probabilities = torch.softmax(logits, dim=1).cpu().numpy()[0]

            # Model çıktısının formatına göre işlem yap
            if len(probabilities) >= 3:
                # 3 sınıflı model (negatif, nötr, pozitif)
                result = {
                    'negative': float(probabilities[0]),
                    'neutral': float(probabilities[1]),
                    'positive': float(probabilities[2])
                }
            else:
                # 2 sınıflı model (negatif, pozitif)
                result = {
                    'negative': float(probabilities[0]),
                    'neutral': 0.0,
                    'positive': float(probabilities[1])
                }

            # Baskın duyguyu belirle
            dominant_sentiment = max(result, key=result.get)
            result['dominant'] = dominant_sentiment

            # -1 ile 1 arasında genel bir skor hesapla
            # -1: çok negatif, 0: nötr, 1: çok pozitif
            weighted_score = result['positive'] - result['negative']
            result['score'] = float(weighted_score)

            return result

        except Exception as e:
            logger.error(f"Duygu analizi sırasında hata: {str(e)}")
            # Hata durumunda nötr sonuç döndür
            return {
                'positive': 0.0,
                'neutral': 1.0,
                'negative': 0.0,
                'dominant': 'neutral',
                'score': 0.0
            }

    def batch_analyze(self, texts, batch_size=8):
        """
        Bir metin listesi için toplu duygu analizi yapar.

        Args:
            texts: Analiz edilecek metin listesi
            batch_size: İşlenecek grup boyutu

        Returns:
            list: Her metin için duygu analizi sonuçları
        """
        results = []

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

        return results