import pandas as pd import numpy as np from transformers import ( AutoTokenizer, AutoModelForSequenceClassification ) import torch import os import requests from collections import Counter import warnings from nltk.tokenize import word_tokenize import nltk import re import google.generativeai as genai from dotenv import load_dotenv warnings.filterwarnings('ignore') # NLTK indirmelerini try-except bloğuna alalım try: nltk.download('stopwords', quiet=True) nltk.download('punkt', quiet=True) except: print("NLTK dosyaları indirilemedi, devam ediliyor...") class ReviewAnalyzer: def __init__(self): # Load environment variables load_dotenv() # Configure Gemini API genai.configure(api_key=os.getenv('GOOGLE_API_KEY')) self.model = genai.GenerativeModel('gemini-pro') # Diğer model kurulumları (sentiment analizi için) self.setup_sentiment_model() self.turkish_stopwords = self.get_turkish_stopwords() # Lojistik ve satıcı ile ilgili kelimeleri tanımla self.logistics_seller_words = { # Kargo ve teslimat ile ilgili 'kargo', 'kargocu', 'paket', 'paketleme', 'teslimat', 'teslim', 'gönderi', 'gönderim', 'ulaştı', 'ulaşım', 'geldi', 'kurye', 'dağıtım', 'hasarlı', 'hasar', 'kutu', 'ambalaj', 'zamanında', 'geç', 'hızlı', 'yavaş', 'günde', 'saatte', # Satıcı ve mağaza ile ilgili 'satıcı', 'mağaza', 'sipariş', 'trendyol', 'tedarik', 'stok', 'garanti', 'fatura', 'iade', 'geri', 'müşteri', 'hizmet', 'destek', 'iletişim', 'şikayet', 'sorun', 'çözüm', 'hediye', # Fiyat ve ödeme ile ilgili 'fiyat', 'ücret', 'para', 'bedava', 'ücretsiz', 'indirim', 'kampanya', 'taksit', 'ödeme', 'bütçe', 'hesap', 'kur', # Zaman ile ilgili teslimat kelimeleri 'bugün', 'yarın', 'dün', 'hafta', 'gün', 'saat', 'süre', 'bekleme', 'gecikme', 'erken', 'geç' } def get_turkish_stopwords(self): """Genişletilmiş stop words listesini hazırla""" github_url = "https://raw.githubusercontent.com/sgsinclair/trombone/master/src/main/resources/org/voyanttools/trombone/keywords/stop.tr.turkish-lucene.txt" stop_words = set() try: response = requests.get(github_url) if response.status_code == 200: github_stops = set(word.strip() for word in response.text.split('\n') if word.strip()) stop_words.update(github_stops) except Exception as e: print(f"GitHub'dan stop words çekilirken hata oluştu: {e}") stop_words.update(set(nltk.corpus.stopwords.words('turkish'))) additional_stops = {'bir', 've', 'çok', 'bu', 'de', 'da', 'için', 'ile', 'ben', 'sen', 'o', 'biz', 'siz', 'onlar', 'bu', 'şu', 'ama', 'fakat', 'ancak', 'lakin', 'ki', 'dahi', 'mi', 'mı', 'mu', 'mü', 'var', 'yok', 'olan', 'içinde', 'üzerinde', 'bana', 'sana', 'ona', 'bize', 'size', 'onlara', 'evet', 'hayır', 'tamam', 'oldu', 'olmuş', 'olacak', 'etmek', 'yapmak', 'kez', 'kere', 'defa', 'adet'} stop_words.update(additional_stops) print(f"Toplam {len(stop_words)} adet stop words yüklendi.") return stop_words def preprocess_text(self, text): """Metin ön işleme""" if isinstance(text, str): # Küçük harfe çevir text = text.lower() # Özel karakterleri temizle text = re.sub(r'[^\w\s]', '', text) # Sayıları temizle text = re.sub(r'\d+', '', text) # Fazla boşlukları temizle text = re.sub(r'\s+', ' ', text).strip() # Stop words'leri çıkar words = text.split() words = [word for word in words if word not in self.turkish_stopwords] return ' '.join(words) return '' def setup_sentiment_model(self): """Sentiment analiz modelini hazırla""" self.device = "cuda" if torch.cuda.is_available() else "cpu" print(f"Using device for sentiment: {self.device}") model_name = "savasy/bert-base-turkish-sentiment-cased" self.sentiment_tokenizer = AutoTokenizer.from_pretrained(model_name) self.sentiment_model = ( AutoModelForSequenceClassification.from_pretrained(model_name) .to(self.device) .to(torch.float32) ) def filter_reviews(self, df): """Ürün ile ilgili olmayan yorumları filtrele""" def is_product_review(text): if not isinstance(text, str): return False return not any(word in text.lower() for word in self.logistics_seller_words) filtered_df = df[df['Yorum'].apply(is_product_review)].copy() print(f"\nFiltreleme İstatistikleri:") print(f"Toplam yorum sayısı: {len(df)}") print(f"Ürün yorumu sayısı: {len(filtered_df)}") print(f"Filtrelenen yorum sayısı: {len(df) - len(filtered_df)}") print(f"Filtreleme oranı: {((len(df) - len(filtered_df)) / len(df) * 100):.2f}%") return filtered_df def analyze_sentiment(self, df): """Sentiment analizi yap""" def predict_sentiment(text): if not isinstance(text, str) or len(text.strip()) == 0: return {"label": "Nötr", "score": 0.5} try: cleaned_text = self.preprocess_text(text) inputs = self.sentiment_tokenizer( cleaned_text, return_tensors="pt", truncation=True, max_length=512, padding=True ).to(self.device) with torch.no_grad(): outputs = self.sentiment_model(**inputs) probs = torch.nn.functional.softmax(outputs.logits, dim=1) prediction = probs.cpu().numpy()[0] score = float(prediction[1]) if score > 0.75: label = "Pozitif" elif score < 0.25: label = "Negatif" elif score > 0.55: label = "Pozitif" elif score < 0.45: label = "Negatif" else: label = "Nötr" return {"label": label, "score": score} except Exception as e: print(f"Error in sentiment prediction: {e}") return {"label": "Nötr", "score": 0.5} print("\nSentiment analizi yapılıyor...") results = [predict_sentiment(text) for text in df['Yorum']] df['sentiment_score'] = [r['score'] for r in results] df['sentiment_label'] = [r['label'] for r in results] df['cleaned_text'] = df['Yorum'].apply(self.preprocess_text) return df def get_key_phrases(self, text_series): """En önemli anahtar kelimeleri bul""" text = ' '.join(text_series.astype(str)) words = self.preprocess_text(text).split() word_freq = Counter(words) # En az 3 kez geçen kelimeleri al return {word: count for word, count in word_freq.items() if count >= 3 and len(word) > 2} def generate_summary(self, df): """Yorumları özetle""" # Yorumları ve yıldızları birleştir reviews_with_ratings = [ f"Yıldız: {row['Yıldız Sayısı']}, Yorum: {row['Yorum']}" for _, row in df.iterrows() ] # Prompt hazırla prompt = f""" Aşağıdaki ürün yorumlarını analiz edip özet çıkar: {reviews_with_ratings[:50]} # İlk 50 yorumu al (API limiti için) Lütfen şu başlıklar altında özetle: 1. Genel Değerlendirme 2. Olumlu Yönler 3. Olumsuz Yönler 4. Öneriler Önemli: Yanıtını Türkçe olarak ver ve madde madde listele. """ try: response = self.model.generate_content(prompt) summary = response.text except Exception as e: summary = f"Özet oluşturulurken hata oluştu: {str(e)}" return summary def analyze_reviews(self, df): """Tüm yorumları analiz et""" try: # Yorumları filtrele filtered_df = self.filter_reviews(df) # Sentiment analizi yap analyzed_df = self.analyze_sentiment(filtered_df) return analyzed_df except Exception as e: print(f"Analiz sırasında hata oluştu: {str(e)}") return pd.DataFrame() def analyze_reviews(file_path): df = pd.read_csv(file_path) analyzer = ReviewAnalyzer() filtered_df = analyzer.filter_reviews(df) print("Sentiment analizi başlatılıyor...") analyzed_df = analyzer.analyze_sentiment(filtered_df) analyzed_df.to_csv('sentiment_analyzed_reviews.csv', index=False, encoding='utf-8-sig') print("Sentiment analizi tamamlandı ve kaydedildi.") print("\nÜrün özeti oluşturuluyor...") summary = analyzer.generate_summary(analyzed_df) with open('urun_ozeti.txt', 'w', encoding='utf-8') as f: f.write(summary) print("\nÜrün Özeti:") print("-" * 50) print(summary) print("\nÖzet 'urun_ozeti.txt' dosyasına kaydedildi.") if __name__ == "__main__": analyze_reviews('data/macbook_product_comments_with_ratings.csv')