textqualtox / models /model_manager.py
sarizeybekk
Remove venv from Git tracking and add to .gitignore
bd97f47
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
}