File size: 13,599 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from transformers import pipeline
import logging
import os
import json
import time
from typing import List, Dict, Any, Tuple, Optional, Union
from models.model_selector import ModelSelector

# Loglama yapılandırması
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)


class ModelManager:
    """
    Metin kalitesi ve zararlılık değerlendirmesi için NLP modellerini yöneten sınıf.
    Bu sınıf, modellerin yüklenmesi, değerlendirilmesi ve seçilmesinden sorumludur.
    """

    def __init__(self, cache_dir: Optional[str] = None, use_cache: bool = True) -> None:
        """
        Model Yöneticisi sınıfını başlatır.

        Args:
            cache_dir: Modellerin önbelleğe alınacağı dizin
            use_cache: Önbellek kullanımını etkinleştir/devre dışı bırak
        """
        self.toxicity_model = None
        self.toxicity_tokenizer = None
        self.quality_pipeline = None
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        self.cache_dir = cache_dir or os.path.join(os.path.expanduser("~"), ".text_quality_toxicity_cache")
        self.use_cache = use_cache
        self.model_selector = ModelSelector(cache_dir=self.cache_dir, use_cache=self.use_cache)
        self.model_info = {
            "toxicity": {
                "name": "Bilinmeyen Model",
                "description": "Model henüz yüklenmedi",
                "language": "unknown"
            },
            "quality": {
                "name": "Bilinmeyen Model",
                "description": "Model henüz yüklenmedi",
                "language": "unknown"
            }
        }

        # Önbellek dizinini oluştur
        if self.use_cache and not os.path.exists(self.cache_dir):
            os.makedirs(self.cache_dir, exist_ok=True)

        logger.info(
            f"ModelManager başlatıldı. Cihaz: {self.device}, Önbellek: {'Etkin' if use_cache else 'Devre dışı'}")

    def load_models_auto_select(self, sample_texts: Optional[List[str]] = None) -> bool:
        """
        En iyi modelleri otomatik olarak seçerek yükler.

        Args:
            sample_texts: Model seçimi için örnek metinler

        Returns:
            bool: Yükleme başarılı mı?
        """
        if sample_texts is None or len(sample_texts) == 0:
            # Örnek metinler yoksa varsayılan örnekler kullan
            sample_texts = [
                "Türkiye, zengin tarihi ve kültürel mirası ile güzel bir ülkedir.",
                "Bu ürün tam bir hayal kırıklığı! Paramı geri istiyorum!",
                "Bugün hava çok güzel. Parkta yürüyüş yaptım ve kuşları izledim.",
                "Sen ne anlarsın ki bu konudan? Boş konuşma artık!"
            ]

        try:
            logger.info("Otomatik model seçimi başlatılıyor...")
            start_time = time.time()

            success = self.model_selector.select_best_models(sample_texts)

            if success:
                best_models = self.model_selector.get_best_models()
                self.toxicity_model = best_models["toxicity_model"]
                self.toxicity_tokenizer = best_models["toxicity_tokenizer"]
                self.quality_pipeline = best_models["quality_pipeline"]
                self.model_info["toxicity"] = best_models["toxicity_model_info"]
                self.model_info["quality"] = best_models["quality_model_info"]

                selection_time = time.time() - start_time
                logger.info(f"Otomatik model seçimi {selection_time:.2f} saniyede tamamlandı")
                logger.info(f"Seçilen zararlılık modeli: {self.model_info['toxicity']['name']}")
                logger.info(f"Seçilen kalite modeli: {self.model_info['quality']['name']}")

                # Kullanılan modelleri önbelleğe kaydet
                if self.use_cache:
                    self._save_models_to_cache()

                return True
            else:
                logger.error("Otomatik model seçimi başarısız oldu, varsayılan modellere dönülüyor")
                return self.load_default_models()

        except Exception as e:
            logger.error(f"Otomatik model seçimi sırasında hata: {str(e)}")
            return self.load_default_models()

    def load_default_models(self) -> bool:
        """
        Varsayılan modelleri yükler (otomatik seçim başarısız olursa).

        Returns:
            bool: Yükleme başarılı mı?
        """
        logger.info("Varsayılan modeller yükleniyor...")

        # Önce önbellekten yüklemeyi dene
        if self.use_cache and self._load_models_from_cache():
            logger.info("Modeller önbellekten başarıyla yüklendi")
            return True

        success_toxicity = self.load_toxicity_model()
        success_quality = self.load_quality_model()

        overall_success = success_toxicity and success_quality

        if overall_success and self.use_cache:
            self._save_models_to_cache()

        return overall_success

    def load_toxicity_model(self, model_name: str = "savasy/bert-base-turkish-sentiment") -> bool:
        """
        Zararlılık tespiti için model yükleme.

        Args:
            model_name: Yüklenecek model ismi

        Returns:
            bool: Yükleme başarılı mı?
        """
        try:
            logger.info(f"Zararlılık modeli yükleniyor: {model_name}")
            self.toxicity_tokenizer = AutoTokenizer.from_pretrained(model_name)
            self.toxicity_model = AutoModelForSequenceClassification.from_pretrained(model_name)
            self.model_info["toxicity"]["name"] = model_name
            self.model_info["toxicity"]["description"] = "Türkçe duygu analizi modeli"
            self.model_info["toxicity"]["language"] = "tr"
            logger.info("Zararlılık modeli başarıyla yüklendi")
            return True
        except Exception as e:
            logger.error(f"Zararlılık modeli yüklenirken hata: {str(e)}")
            # Alternatif model deneyelim
            try:
                backup_model = "dbmdz/bert-base-turkish-cased"
                logger.info(f"Yedek Türkçe model deneniyor: {backup_model}")
                self.toxicity_tokenizer = AutoTokenizer.from_pretrained(backup_model)
                self.toxicity_model = AutoModelForSequenceClassification.from_pretrained(backup_model)
                self.model_info["toxicity"]["name"] = backup_model
                self.model_info["toxicity"]["description"] = "Genel amaçlı Türkçe BERT modeli"
                self.model_info["toxicity"]["language"] = "tr"
                logger.info("Yedek Türkçe model başarıyla yüklendi")
                return True
            except Exception as e2:
                logger.error(f"Yedek Türkçe model yüklenirken hata: {str(e2)}")
                try:
                    fallback_model = "distilbert/distilbert-base-uncased-finetuned-sst-2-english"
                    logger.info(f"İngilizce duygu analizi modeli deneniyor: {fallback_model}")
                    self.toxicity_tokenizer = AutoTokenizer.from_pretrained(fallback_model)
                    self.toxicity_model = AutoModelForSequenceClassification.from_pretrained(fallback_model)
                    self.model_info["toxicity"]["name"] = fallback_model
                    self.model_info["toxicity"]["description"] = "İngilizce duygu analizi modeli"
                    self.model_info["toxicity"]["language"] = "en"
                    logger.info("İngilizce duygu analizi modeli başarıyla yüklendi")
                    return True
                except Exception as e3:
                    logger.error(f"İngilizce model yüklenirken hata: {str(e3)}")
                    return False

    def load_quality_model(self, model_name: str = "sshleifer/distilbart-cnn-6-6") -> bool:
        """
        Metin kalitesi değerlendirmesi için model yükleme.

        Args:
            model_name: Yüklenecek model ismi

        Returns:
            bool: Yükleme başarılı mı?
        """
        try:
            logger.info(f"Kalite modeli yükleniyor: {model_name}")
            self.quality_pipeline = pipeline(
                "text2text-generation",
                model=model_name,
                tokenizer=model_name,
                device=0 if self.device == "cuda" else -1
            )
            self.model_info["quality"]["name"] = model_name
            self.model_info["quality"]["description"] = "İngilizce metin özetleme modeli"
            self.model_info["quality"]["language"] = "en"
            logger.info("Kalite modeli başarıyla yüklendi")
            return True
        except Exception as e:
            logger.error(f"Kalite modeli yüklenirken hata: {str(e)}")

            # Daha hafif bir model deneyelim
            try:
                backup_model = "Helsinki-NLP/opus-mt-tr-en"
                logger.info(f"Türkçe çeviri modeli deneniyor: {backup_model}")
                self.quality_pipeline = pipeline(
                    "translation",
                    model=backup_model,
                    device=0 if self.device == "cuda" else -1
                )
                self.model_info["quality"]["name"] = backup_model
                self.model_info["quality"]["description"] = "Türkçe-İngilizce çeviri modeli"
                self.model_info["quality"]["language"] = "tr"
                logger.info("Türkçe çeviri modeli başarıyla yüklendi")
                return True
            except Exception as e2:
                logger.error(f"Türkçe çeviri modeli yüklenirken hata: {str(e2)}")
                try:
                    light_model = "sshleifer/distilbart-xsum-12-6"
                    logger.info(f"Daha hafif özetleme modeli deneniyor: {light_model}")
                    self.quality_pipeline = pipeline(
                        "text2text-generation",
                        model=light_model,
                        device=0 if self.device == "cuda" else -1
                    )
                    self.model_info["quality"]["name"] = light_model
                    self.model_info["quality"]["description"] = "Hafif İngilizce özetleme modeli"
                    self.model_info["quality"]["language"] = "en"
                    logger.info("Hafif özetleme modeli başarıyla yüklendi")
                    return True
                except Exception as e3:
                    logger.error(f"Hafif özetleme modeli yüklenirken hata: {str(e3)}")
                    return False

    def _save_models_to_cache(self) -> None:
        """Kullanılan modellerin bilgilerini önbelleğe kaydeder."""
        if not self.use_cache:
            return

        try:
            cache_file = os.path.join(self.cache_dir, "model_manager_state.json")

            cache_data = {
                "timestamp": time.time(),
                "model_info": self.model_info
            }

            with open(cache_file, 'w', encoding='utf-8') as f:
                json.dump(cache_data, f, ensure_ascii=False, indent=2)

            logger.info(f"Model bilgileri önbelleğe kaydedildi: {cache_file}")
        except Exception as e:
            logger.error(f"Önbelleğe kaydetme hatası: {str(e)}")

    def _load_models_from_cache(self) -> bool:
        """
        Önbellekten model bilgilerini yükler.

        Returns:
            bool: Yükleme başarılı mı?
        """
        if not self.use_cache:
            return False

        try:
            cache_file = os.path.join(self.cache_dir, "model_manager_state.json")

            if not os.path.exists(cache_file):
                return False

            # Önbellek dosyasının yaşını kontrol et (24 saatten eskiyse yok say)
            file_age = time.time() - os.path.getmtime(cache_file)
            if file_age > 86400:  # 24 saat = 86400 saniye
                logger.info(f"Önbellek dosyası çok eski ({file_age / 3600:.1f} saat), yeniden yükleme yapılacak")
                return False

            with open(cache_file, 'r', encoding='utf-8') as f:
                cache_data = json.load(f)

            # Model bilgilerini önbellekten al
            self.model_info = cache_data.get("model_info", self.model_info)

            # Önbellekteki bilgilerle yeniden yükleme yap
            toxicity_name = self.model_info["toxicity"].get("name")
            quality_name = self.model_info["quality"].get("name")

            toxicity_success = self.load_toxicity_model(toxicity_name) if toxicity_name else False
            quality_success = self.load_quality_model(quality_name) if quality_name else False

            return toxicity_success and quality_success

        except Exception as e:
            logger.error(f"Önbellekten model yükleme hatası: {str(e)}")
            return False

    def get_models(self) -> Dict[str, Any]:
        """
        Yüklenen modelleri ve bilgilerini döndürür.

        Returns:
            Dict[str, Any]: Model, tokenizer, pipeline ve model bilgileri
        """
        return {
            "toxicity_model": self.toxicity_model,
            "toxicity_tokenizer": self.toxicity_tokenizer,
            "quality_pipeline": self.quality_pipeline,
            "model_info": self.model_info
        }