trendyol-review-summarizer / scripts /review_summarizer.py
enesmanan's picture
fix gradio
b833f77 verified
import os
import re
import warnings
from collections import Counter
import google.generativeai as genai
import nltk
import numpy as np
import pandas as pd
import requests
import torch
from nltk.tokenize import word_tokenize
from transformers import AutoModelForSequenceClassification, AutoTokenizer
warnings.filterwarnings("ignore")
nltk.download("stopwords", quiet=True)
nltk.download("punkt", quiet=True)
class ReviewAnalyzer:
def __init__(self, gemini_api_key):
self.turkish_stopwords = self.get_turkish_stopwords()
self.setup_sentiment_model()
self.setup_gemini_model(gemini_api_key)
self.logistics_seller_words = {
"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ı",
"mağaza",
"sipariş",
"trendyol",
"tedarik",
"stok",
"garanti",
"fatura",
"iade",
"geri",
"müşteri",
"hizmet",
"destek",
"iletişim",
"şikayet",
"sorun",
"çözüm",
"hediye",
"fiyat",
"ücret",
"para",
"bedava",
"ücretsiz",
"indirim",
"kampanya",
"taksit",
"ödeme",
"bütçe",
"hesap",
"kur",
"bugün",
"yarın",
"dün",
"hafta",
"gün",
"saat",
"süre",
"bekleme",
"gecikme",
"erken",
"geç",
}
def get_turkish_stopwords(self):
"""Türkçe stop words listesi oluştur"""
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):
if isinstance(text, str):
text = text.lower()
text = re.sub(r"[^\w\s]", "", text)
text = re.sub(r"\d+", "", text)
text = re.sub(r"\s+", " ", text).strip()
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):
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 setup_gemini_model(self, api_key):
genai.configure(api_key=api_key)
self.gemini_model = genai.GenerativeModel("gemini-pro")
def filter_reviews(self, df):
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):
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):
text = " ".join(text_series.astype(str))
words = self.preprocess_text(text).split()
word_freq = Counter(words)
return {
word: count
for word, count in word_freq.items()
if count >= 3 and len(word) > 2
}
def generate_summary(self, df):
# en onemli yorumları sec
high_rated = df[df["Yıldız Sayısı"] >= 4]
low_rated = df[df["Yıldız Sayısı"] <= 2]
# onemli kelimleri ve yorumlari al
positive_features = self.get_key_phrases(high_rated["cleaned_text"])
negative_features = self.get_key_phrases(low_rated["cleaned_text"])
top_positive = (
high_rated.sort_values("sentiment_score", ascending=False)["Yorum"]
.head(3)
.tolist()
)
top_negative = (
low_rated.sort_values("sentiment_score")["Yorum"].head(2).tolist()
)
summary_prompt = f"""Bu ürünün genel değerlendirmesini doğal bir dille özetleyeceksin.
Veriler:
- Toplam {len(df)} değerlendirme var
- Ortalama puan: {df['Yıldız Sayısı'].mean():.1f}/5
- Pozitif yorum oranı: {(len(df[df['sentiment_label'] == 'Pozitif']) / len(df) * 100):.1f}%
En çok tekrar eden olumlu ifadeler: {', '.join(list(positive_features.keys())[:5])}
En çok tekrar eden olumsuz ifadeler: {', '.join(list(negative_features.keys())[:5])}
Örnek olumlu yorumlar:
{' '.join(top_positive)}
Örnek olumsuz yorumlar:
{' '.join(top_negative)}
Lütfen bu bilgileri kullanarak, ürünle ilgili kullanıcı deneyimlerini tek bir paragrafta, sohbet eder gibi doğal bir dille özetle.
İstatistikleri direkt verme, onları cümlelerin içine yerleştir. Olumlu ve olumsuz yönleri dengeli bir şekilde aktar."""
response = self.gemini_model.generate_content(summary_prompt)
return response.text
def analyze_reviews(file_path, api_key):
print("Analiz başlatılıyor...")
df = pd.read_csv(file_path)
analyzer = ReviewAnalyzer(api_key)
filtered_df = analyzer.filter_reviews(df)
analyzed_df = analyzer.analyze_sentiment(filtered_df)
summary = analyzer.generate_summary(analyzed_df)
return summary, analyzed_df