File size: 10,071 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
import re
import string
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from collections import Counter
import logging

logger = logging.getLogger(__name__)


class KeywordExtractor:
    """
    Metin içindeki anahtar kelimeleri çıkaran sınıf.
    TF-IDF, rakip kelimeler ve diğer metotlarla anahtar kelime çıkarma işlemi yapar.
    """

    def __init__(self):
        """Anahtar kelime çıkarıcıyı başlatır"""
        # Türkçe stopwords (durma kelimeleri)
        self.turkish_stopwords = [
            've', 'veya', 'ile', 'için', 'bu', 'bir', 'ya', 'de', 'da', 'ki', 'ne', 'her', 'çok',
            'daha', 'ama', 'fakat', 'lakin', 'ancak', 'gibi', 'kadar', 'sonra', 'önce', 'göre',
            'nasıl', 'neden', 'şey', 'ben', 'sen', 'o', 'biz', 'siz', 'onlar', 'kendi', 'aynı',
            'ise', 'mi', 'mı', 'mu', 'mü', 'hem', 'değil', 'hiç', 'olarak', 'evet', 'hayır',
            'belki', 'tüm', 'yani', 'hep', 'şu', 'şey', 'tabi', 'tamam', 'bunlar', 'şunlar',
            'böyle', 'öyle', 'şöyle', 'iki', 'üç', 'dört', 'beş', 'altı', 'yedi', 'sekiz', 'dokuz',
            'on', 'yüz', 'bin', 'milyon', 'milyar', 'var', 'yok', 'oldu', 'olur', 'oluyor', 'olacak'
        ]

        # İngilizce stopwords (durma kelimeleri)
        self.english_stopwords = [
            'the', 'and', 'a', 'to', 'of', 'in', 'for', 'with', 'on', 'at', 'by', 'from', 'about',
            'as', 'into', 'like', 'through', 'after', 'over', 'between', 'out', 'against', 'during',
            'without', 'before', 'under', 'around', 'among', 'is', 'are', 'was', 'were', 'be', 'been',
            'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'shall', 'should',
            'may', 'might', 'must', 'can', 'could', 'i', 'you', 'he', 'she', 'it', 'we', 'they',
            'me', 'him', 'her', 'us', 'them', 'who', 'which', 'whose', 'whom', 'this', 'that', 'these',
            'those', 'am', 'is', 'are', 'was', 'were', 'an', 'my', 'your', 'his', 'its', 'our', 'their'
        ]

        # Tüm stopwords listesini birleştir
        self.stopwords = set(self.turkish_stopwords + self.english_stopwords)

        # TF-IDF vektörleyici
        self.tfidf_vectorizer = TfidfVectorizer(
            max_df=0.9,
            min_df=2,
            max_features=200,
            stop_words=self.stopwords,
            ngram_range=(1, 2)  # Tek kelimeler ve ikili kelime grupları
        )

        # Sayısal karakter ve noktalama işaretlerini temizlemek için regex pattern
        self.cleanup_pattern = re.compile(f'[{re.escape(string.punctuation)}]|[0-9]')

        logger.info("Anahtar kelime çıkarıcı başlatıldı")

    def preprocess_text(self, text):
        """
        Metni anahtar kelime çıkarma için ön işleme tabi tutar

        Args:
            text: İşlenecek metin

        Returns:
            str: Temizlenmiş metin
        """
        if not text:
            return ""

        # Küçük harfe çevir
        text = text.lower()

        # Noktalama işaretlerini temizle
        text = self.cleanup_pattern.sub(' ', text)

        # Fazla boşlukları temizle
        text = re.sub(r'\s+', ' ', text).strip()

        return text

    def extract_keywords_tfidf(self, text, num_keywords=5):
        """
        TF-IDF kullanarak metinden anahtar kelimeleri çıkarır

        Args:
            text: Anahtar kelimeleri çıkarılacak metin
            num_keywords: Çıkarılacak anahtar kelime sayısı

        Returns:
            list: [(anahtar_kelime, skor), ...] formatında liste
        """
        try:
            if not text or len(text.strip()) < 10:
                return []

            # Metni ön işle
            processed_text = self.preprocess_text(text)

            # TF-IDF matrix oluştur
            tfidf_matrix = self.tfidf_vectorizer.fit_transform([processed_text])

            # Feature isimleri (kelimeler)
            feature_names = self.tfidf_vectorizer.get_feature_names_out()

            # Kelimelerin TF-IDF skorlarını hesapla ve sırala
            tfidf_scores = zip(feature_names, tfidf_matrix.toarray()[0])
            sorted_scores = sorted(tfidf_scores, key=lambda x: x[1], reverse=True)

            # En yüksek skorlu kelimeleri seç
            top_keywords = sorted_scores[:num_keywords]

            return top_keywords

        except Exception as e:
            logger.error(f"TF-IDF anahtar kelime çıkarma hatası: {str(e)}")
            return []

    def extract_keywords_textrank(self, text, num_keywords=5):
        """
        TextRank benzeri bir algoritma ile anahtar kelimeleri çıkarır

        Args:
            text: Anahtar kelimeleri çıkarılacak metin
            num_keywords: Çıkarılacak anahtar kelime sayısı

        Returns:
            list: [(anahtar_kelime, skor), ...] formatında liste
        """
        try:
            if not text or len(text.strip()) < 10:
                return []

            # Metni ön işle
            processed_text = self.preprocess_text(text)

            # Kelimeleri ayır
            words = processed_text.split()

            # Stopwords olmayan kelimeleri filtrele
            filtered_words = [word for word in words if word not in self.stopwords and len(word) > 2]

            # Kelime frekanslarını hesapla
            word_freq = Counter(filtered_words)

            # En sık geçen kelimeleri seç
            most_common = word_freq.most_common(num_keywords * 2)  # Daha fazla al, sonra filtreleyeceğiz

            # TF-IDF skorlaması ile benzer bir yaklaşım uygula
            # Kelime sıklığının logaritması * kelimenin benzersizliği
            scored_words = []
            for word, count in most_common:
                # Benzersizlik faktörü: Toplam kelime sayısı / kelimenin sıklığı
                uniqueness = len(filtered_words) / (count + 1)
                # Skor hesapla
                score = np.log(count + 1) * uniqueness
                scored_words.append((word, score))

            # Skorlara göre sırala
            scored_words.sort(key=lambda x: x[1], reverse=True)

            return scored_words[:num_keywords]

        except Exception as e:
            logger.error(f"TextRank anahtar kelime çıkarma hatası: {str(e)}")
            return []

    def extract_bigrams(self, text, num_bigrams=3):
        """
        Metinden ikili kelime gruplarını (bigram) çıkarır

        Args:
            text: Anahtar kelimeleri çıkarılacak metin
            num_bigrams: Çıkarılacak bigram sayısı

        Returns:
            list: [(bigram, skor), ...] formatında liste
        """
        try:
            if not text or len(text.strip()) < 10:
                return []

            # Metni ön işle
            processed_text = self.preprocess_text(text)

            # Bigram için vektörleyici
            bigram_vectorizer = CountVectorizer(
                ngram_range=(2, 2),
                stop_words=self.stopwords,
                max_features=100
            )

            # Bigram matrix oluştur
            bigram_matrix = bigram_vectorizer.fit_transform([processed_text])

            # Feature isimleri (bigramlar)
            feature_names = bigram_vectorizer.get_feature_names_out()

            # Bigramların skorlarını hesapla ve sırala
            bigram_scores = zip(feature_names, bigram_matrix.toarray()[0])
            sorted_scores = sorted(bigram_scores, key=lambda x: x[1], reverse=True)

            # En yüksek skorlu bigramları seç
            top_bigrams = sorted_scores[:num_bigrams]

            return top_bigrams

        except Exception as e:
            logger.error(f"Bigram çıkarma hatası: {str(e)}")
            return []

    def extract_keywords(self, text, method='combined', num_keywords=10):
        """
        Metinden anahtar kelimeleri çıkarır

        Args:
            text: Anahtar kelimeleri çıkarılacak metin
            method: Kullanılacak metod ('tfidf', 'textrank', 'combined')
            num_keywords: Toplam çıkarılacak anahtar kelime sayısı

        Returns:
            dict: {
                'keywords': [(anahtar_kelime, skor), ...],
                'bigrams': [(bigram, skor), ...],
                'method': kullanılan metod
            }
        """
        if not text or len(text.strip()) < 10:
            return {
                'keywords': [],
                'bigrams': [],
                'method': method
            }

        try:
            keywords = []

            if method == 'tfidf':
                keywords = self.extract_keywords_tfidf(text, num_keywords)
            elif method == 'textrank':
                keywords = self.extract_keywords_textrank(text, num_keywords)
            else:  # combined
                # TF-IDF ve TextRank sonuçlarını birleştir
                tfidf_keywords = self.extract_keywords_tfidf(text, num_keywords // 2)
                textrank_keywords = self.extract_keywords_textrank(text, num_keywords // 2)

                # İki listeyi birleştir
                combined = {}
                for keyword, score in tfidf_keywords + textrank_keywords:
                    if keyword in combined:
                        combined[keyword] = max(combined[keyword], score)
                    else:
                        combined[keyword] = score

                # En yüksek skorlu kelimeleri seç
                keywords = sorted(combined.items(), key=lambda x: x[1], reverse=True)[:num_keywords]

            # Bigramları da ekle
            bigrams = self.extract_bigrams(text, num_keywords // 3)

            return {
                'keywords': keywords,
                'bigrams': bigrams,
                'method': method
            }

        except Exception as e:
            logger.error(f"Anahtar kelime çıkarma hatası: {str(e)}")
            return {
                'keywords': [],
                'bigrams': [],
                'method': method
            }