import gradio as gr from google_play_scraper import Sort, reviews from transformers import pipeline from collections import Counter import matplotlib import threading # <--- Tambahan Penting import base64 from io import BytesIO import torch # =============================== # 1. SETUP BACKEND & LOCK # =============================== # Set backend ke 'Agg' AGAR TIDAK ERROR DI SERVER matplotlib.use('Agg') import matplotlib.pyplot as plt # Kunci untuk mencegah Matplotlib crash saat diakses banyak user/thread plot_lock = threading.Lock() # =============================== # 2. SETUP MODEL # =============================== device = 0 if torch.cuda.is_available() else -1 MODEL_NAME = "Aardiiiiy/indobertweet-base-Indonesian-sentiment-analysis" print("⏳ Sedang memuat model... Harap tunggu sebentar.") try: sentiment_model = pipeline( "text-classification", model=MODEL_NAME, tokenizer=MODEL_NAME, device=device ) print("✅ Model siap digunakan!") except Exception as e: print(f"Error loading model: {e}") # =============================== # 3. LOGIC FUNCTIONS # =============================== def scrape_reviews(app_id, max_reviews, language): try: result, _ = reviews( app_id, lang=language, country="id", sort=Sort.NEWEST, count=max_reviews ) return [r["content"].strip() for r in result if r.get("content")] except Exception as e: print(f"Error scraping: {e}") return [] def analyze_sentiment_batch(texts): if not texts: return Counter(), 0 try: results = sentiment_model(texts, batch_size=16, truncation=True, max_length=512) labels = [res["label"].lower() for res in results] return Counter(labels), len(labels) except Exception as e: print(f"Error analyzing: {e}") return Counter(), 0 def generate_plot(pos, neu, neg, total): # Gunakan LOCK agar thread tidak bertabrakan saat menggambar with plot_lock: try: colors = ['#4ade80', '#fbbf24', '#f87171'] labels = ["Positif", "Netral", "Negatif"] sizes = [pos, neu, neg] fig = plt.figure(figsize=(6, 4)) fig.patch.set_alpha(0.0) plt.pie( sizes, labels=labels, autopct="%1.1f%%", startangle=140, colors=colors, # Pastikan teks hitam textprops={'color':"#000000", 'weight':'bold', 'fontsize': 10}, wedgeprops={'edgecolor': 'white', 'linewidth': 2} ) plt.axis('equal') plt.tight_layout() buf = BytesIO() plt.savefig(buf, format="png", bbox_inches='tight', transparent=True) # Bersihkan memori segera plt.close(fig) plt.close('all') return base64.b64encode(buf.getvalue()).decode() except Exception as e: print(f"Error generating plot: {e}") return "" def generate_html_dashboard(pos, neu, neg, total, img_base64): # HTML dengan CSS '!important' agar teks tetap HITAM di tema gelap html = f"""
Berdasarkan {total} ulasan terbaru
| 🟢 Positif | {pos} |
| 🟡 Netral | {neu} |
| 🔴 Negatif | {neg} |
| Total Data | {total} |