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()