File size: 4,391 Bytes
709db90
 
2f17ed7
 
 
 
 
709db90
2f17ed7
709db90
 
 
 
 
 
 
 
 
 
 
2f17ed7
 
 
 
 
 
 
709db90
2f17ed7
709db90
2f17ed7
64ddc44
 
2f17ed7
 
 
 
 
709db90
2f17ed7
 
64ddc44
2f17ed7
64ddc44
2f17ed7
 
 
64ddc44
2f17ed7
 
709db90
64ddc44
 
 
 
 
 
2f17ed7
64ddc44
709db90
2f17ed7
 
64ddc44
 
 
2f17ed7
709db90
64ddc44
 
 
2f17ed7
709db90
 
 
 
64ddc44
 
709db90
 
 
64ddc44
 
709db90
 
 
 
 
2f17ed7
709db90
 
 
 
 
64ddc44
709db90
 
 
 
 
 
 
64ddc44
 
 
 
 
 
 
 
 
709db90
64ddc44
709db90
 
 
64ddc44
 
709db90
 
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
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import joblib
import re
from sentence_transformers import SentenceTransformer
from threading import Lock
import os
import sys

# Pydantic: Gelen JSON verisini doğrulamak için model
class MakaleBasligi(BaseModel):
    """API'ye gelen JSON gövdesinin yapısını tanımlar ve veri doğrulamasını yapar."""
    baslik: str

# FastAPI uygulamasını başlat
app = FastAPI(
    title="Makale Kategorize Etme API",
    description="Hugging Face üzerinde barındırılan metin gömme ve SVC ile kategori tahmin hizmeti.",
    version="1.0.0"
)

# Model yükleme işlemini sadece bir kez yapmak için global değişkenler
MODEL_LOADED = False
MODEL_LOCK = Lock()
classifier = None
embedding_model = None


# Metin ön işleme fonksiyonu
def metin_temizle(metin: str) -> str:
    """Metni küçük harfe dönüştürür, noktalama işaretlerini ve sayıları kaldırır."""
    if not isinstance(metin, str):
        return ""
    metin = metin.lower()
    metin = re.sub(r'[^\w\s]', '', metin)
    metin = re.sub(r'\d+', '', metin)
    return metin


# Modeli yükleme fonksiyonu (Sadece bir kez çalışacak)
def load_models():
    """Modelleri ilk çalıştırmada yükler ve kilit mekanizması kullanır."""
    global classifier, embedding_model, MODEL_LOADED
    
    with MODEL_LOCK:
        if MODEL_LOADED:
            return

        print("Modeller ilk kez yükleniyor...")
        try:
            # 1. SVC sınıflandırma modelini yükle
            classifier_path = 'siniflandirma_modeli.pkl'
            if not os.path.exists(classifier_path):
                 print(f"HATA: '{classifier_path}' bulunamadı. Lütfen Spaces dosya yapısını kontrol edin.", file=sys.stderr)
                 raise FileNotFoundError(f"Model dosyası '{classifier_path}' bulunamadı.")
            
            classifier = joblib.load(classifier_path)
            print("SVC modeli başarıyla yüklendi.")
            
            # 2. Gömme modelini yükle
            embedding_model = SentenceTransformer('distiluse-base-multilingual-cased-v2')
            print("Sentence-Transformer modeli başarıyla indirildi/yüklendi.")

            MODEL_LOADED = True
            print("Model yükleme tamamlandı. API hazır.")
        except Exception as e:
            # Model yükleme hatası olursa, uygulamanın çökmesi ve Spaces'in yeniden başlatması beklenir
            print(f"KRİTİK HATA: Model yüklenirken bir sorun oluştu: {e}", file=sys.stderr)
            raise e


# Uygulama başlatıldığında modelleri yükle
@app.on_event("startup")
async def startup_event():
    """Uygulama başladığında modelleri yükler."""
    try:
        load_models()
    except Exception:
        # Hata fırlatılmazsa uygulama başlatılamaz.
        pass


# API'nin makale başlığını alıp kategoriyi tahmin edeceği uç nokta (endpoint)
@app.post('/kategorize-et')
async def kategorize_et_api(data: MakaleBasligi):
    """
    Gelen makale başlığını kategorize eder ve sonucu döndürür.
    
    Beklenen JSON gövdesi: {"baslik": "makale başlığı metni"}
    """
    if not MODEL_LOADED:
        raise HTTPException(status_code=503, detail="Hizmet kullanılamıyor: Modeller henüz yüklenmedi veya yüklenirken hata oluştu.")
        
    try:
        makale_basligi = data.baslik
        
        # Basit bir kontrol ekleyelim
        if not makale_basligi or len(makale_basligi.strip()) == 0:
             raise HTTPException(status_code=400, detail="Makale başlığı boş veya geçersiz.")


        temizlenmis_baslik = metin_temizle(makale_basligi)

        # Başlığı vektöre dönüştür
        tahmin_vektoru = embedding_model.encode([temizlenmis_baslik])

        # Sınıflandırma modelini kullanarak kategoriyi tahmin et
        tahmin_sonucu = classifier.predict(tahmin_vektoru)[0]

        # Sonucu JSON formatında döndür
        return {"kategori": tahmin_sonucu}

    except HTTPException as http_e:
        # Pydantic veya kendi fırlattığımız HTTP hatalarını döndür
        raise http_e
    except Exception as e:
        # Tahmin sırasında oluşan diğer hatalar
        print(f"TAHMİN SIRASINDA BEKLENMEYEN HATA: {e}", file=sys.stderr)
        raise HTTPException(status_code=500, detail=f"Tahmin işlemi sırasında beklenmeyen bir hata oluştu: {e}")