enesmanan's picture
updade app.py
422c973 verified
raw
history blame
6.87 kB
import os
import time
import requests
import re
import pandas as pd
import plotly.express as px
import gradio as gr
from dotenv import load_dotenv
from scripts.review_summarizer import analyze_reviews
load_dotenv()
GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
if not os.path.exists("data"):
os.makedirs("data")
def create_sentiment_plot(df):
"""Creates a pie chart visualization for sentiment distribution"""
sentiment_counts = df["sentiment_label"].value_counts()
fig = px.pie(
values=sentiment_counts.values,
names=sentiment_counts.index,
title="Duygu Analizi Dağılımı",
color_discrete_map={
"Pozitif": "#2ecc71",
"Nötr": "#95a5a6",
"Negatif": "#e74c3c",
},
)
return fig
def create_star_plot(df):
"""Creates a bar chart visualization for star rating distribution"""
star_counts = df["Yıldız Sayısı"].value_counts().sort_index()
fig = px.bar(
x=star_counts.index,
y=star_counts.values,
title="Yıldız Dağılımı",
labels={"x": "Yıldız Sayısı", "y": "Yorum Sayısı"},
color_discrete_sequence=["#f39c12"],
)
fig.update_layout(
xaxis=dict(
tickmode="array",
ticktext=["⭐", "⭐⭐", "⭐⭐⭐", "⭐⭐⭐⭐", "⭐⭐⭐⭐⭐"],
)
)
return fig
def scrape_product_comments_v2(url):
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "en-US,en;q=0.9",
"cache-control": "max-age=0",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (iPad; CPU OS 14_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/129.0 Mobile/15E148 Safari/605.1.15"
}
# Extract product_id using regex
match = re.search(r"-p-(\d+)", url)
if not match:
raise ValueError("Product ID not found in URL")
product_id = match.group(1)
api_url = f"https://apigw.trendyol.com/discovery-web-websfxsocialreviewrating-santral/product-reviews-detailed?contentId={product_id}&page=1&order=DESC&orderBy=Score&channelId=1"
def fetch_reviews(api_url, headers):
all_reviews = []
response = requests.get(api_url, headers=headers)
if response.status_code != 200:
raise ConnectionError(f"Initial request failed: {response.status_code}")
data = response.json()
total_pages = data["result"]["productReviews"]["totalPages"]
all_reviews.extend(data["result"]["productReviews"]["content"])
for page in range(2, total_pages + 1):
paginated_url = api_url.replace("page=1", f"page={page}")
response = requests.get(paginated_url, headers=headers)
if response.status_code == 200:
page_data = response.json()
all_reviews.extend(page_data["result"]["productReviews"]["content"])
else:
print(f"Failed to fetch page {page}: {response.status_code}")
return all_reviews
reviews = fetch_reviews(api_url, headers)
reviews_df = pd.DataFrame(reviews)
reviews_df = reviews_df.rename(columns={
"id": "Kullanıcı_id",
"userFullName": "Kullanıcı Adı",
"comment": "Yorum",
"lastModifiedDate": "Tarih",
"rate": "Yıldız Sayısı"
})
reviews_df = reviews_df[["Kullanıcı_id", "Kullanıcı Adı", "Yorum", "Tarih", "Yıldız Sayısı"]]
return reviews_df
def analyze_product(url, progress=gr.Progress()):
try:
# Fetch reviews
progress(0.1, desc="Yorumlar çekiliyor...")
df = scrape_product_comments_v2(url)
if df is None or len(df) == 0:
return None, None, None, None, None, None, None, "Yorumlar çekilemedi. URL'yi kontrol edin."
# Save to CSV
data_path = os.path.join("data", "product_comments.csv")
df.to_csv(data_path, index=False, encoding="utf-8-sig")
# Analyze reviews
progress(0.4, desc="Yorumlar analiz ediliyor...")
summary, analyzed_df = analyze_reviews(data_path, GEMINI_API_KEY)
progress(0.7, desc="Sonuçlar hazırlanıyor...")
# Calculate metrics
total_reviews = len(df)
total_analyzed = len(analyzed_df)
avg_rating = f"{analyzed_df['Yıldız Sayısı'].mean():.1f}⭐"
positive_ratio = len(analyzed_df[analyzed_df["sentiment_label"] == "Pozitif"]) / len(analyzed_df) * 100
positive_ratio_str = f"%{positive_ratio:.1f}"
# Create plots
sentiment_plot = create_sentiment_plot(analyzed_df)
star_plot = create_star_plot(analyzed_df)
# Create info message for removed reviews
removed_reviews = total_reviews - total_analyzed
info_message = ""
if removed_reviews > 0:
info_message = f"Not: Toplam {removed_reviews} adet kargo, teslimat ve satıcı ile ilgili yorum analiz dışı bırakılmıştır."
progress(1.0, desc="Analiz tamamlandı!")
return (
str(total_reviews),
str(total_analyzed),
avg_rating,
positive_ratio_str,
sentiment_plot,
star_plot,
summary,
info_message
)
except Exception as e:
return None, None, None, None, None, None, None, f"Bir hata oluştu: {str(e)}"
# Create Gradio interface
with gr.Blocks(title="Trendyol Yorum Analizi") as demo:
gr.Markdown("""
# Trendyol Yorum Analizi
Bu uygulama, Trendyol ürün sayfasındaki yorumları çeker, analiz eder ve özetler.
""")
with gr.Row():
url_input = gr.Textbox(
label="Trendyol Ürün Yorumları URL",
placeholder="ürünün linki"
)
analyze_btn = gr.Button("Analiz Et")
with gr.Row():
total_reviews = gr.Textbox(label="Toplam Yorum")
total_analyzed = gr.Textbox(label="Ürün Değerlendirme Sayısı")
avg_rating = gr.Textbox(label="Ortalama Puan")
positive_ratio = gr.Textbox(label="Olumlu Yorum Oranı")
summary = gr.Markdown(label="📝 Genel Değerlendirme")
info_message = gr.Markdown()
with gr.Row():
sentiment_plot = gr.Plot()
star_plot = gr.Plot()
error_message = gr.Markdown()
analyze_btn.click(
analyze_product,
inputs=[url_input],
outputs=[
total_reviews,
total_analyzed,
avg_rating,
positive_ratio,
sentiment_plot,
star_plot,
summary,
error_message
]
)
if __name__ == "__main__":
demo.launch()