PoskoLog / sentiment_app.py
Ferdinann's picture
Update sentiment_app.py
6e4bbc4 verified
import gradio as gr
import torch
from transformers import pipeline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
# --- SETUP MODEL ---
# Menggunakan model RoBERTa Bahasa Indonesia untuk analisis sentimen
MODEL_NAME = "w11wo/indonesian-roberta-base-sentiment-classifier"
device = 0 if torch.cuda.is_available() else -1
sentiment_pipeline = pipeline("sentiment-analysis", model=MODEL_NAME, device=device)
# --- DATABASE SEDERHANA (In-Memory) ---
all_messages = []
# Mapping Label untuk Tampilan UI agar lebih mudah dipahami manusia
label_map = {
"POSITIVE": "Pujian/Apresiasi",
"NEGATIVE": "Keluhan/Kritik",
"NEUTRAL": "Pertanyaan/Info"
}
def process_submission(text):
if not text or text.strip() == "":
return "⚠️ Mohon isi komentar Anda terlebih dahulu.", gr.update()
# 1. Analisis Sentimen menggunakan Pipeline Hugging Face
result = sentiment_pipeline(text)[0]
label = result['label'].upper()
# 2. Simpan ke Database Lokal dengan Timestamp
new_entry = {
"Waktu": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"Pesan": text.strip(),
"Sentimen": label
}
all_messages.append(new_entry)
# 3. Respons untuk User
thanks_msg = "### πŸ™ Terima kasih atas pesan Anda!\nMasukan Anda telah kami terima dan akan segera ditinjau oleh tim admin posko."
return thanks_msg, gr.update(value="")
def get_admin_dashboard(filter_val):
if not all_messages:
return None, pd.DataFrame(columns=["Waktu", "Pesan", "Sentimen"]), "Belum ada data."
df_all = pd.DataFrame(all_messages)
# --- LOGIKA FILTER ---
if filter_val != "SEMUA":
# Balik mapping untuk mencari label asli (POSITIVE/NEGATIVE/NEUTRAL)
rev_map = {v: k for k, v in label_map.items()}
target = rev_map.get(filter_val)
df_filtered = df_all[df_all['Sentimen'] == target]
else:
df_filtered = df_all
if df_filtered.empty:
return None, pd.DataFrame(columns=["Waktu", "Pesan", "Sentimen"]), f"Tidak ada data untuk kategori: {filter_val}"
# --- VISUALISASI TOTAL (Pie Chart atau Bar Plot) ---
fig, ax = plt.subplots(figsize=(8, 5))
counts = df_all['Sentimen'].value_counts()
# Mengubah index angka/label asli ke label buatan kita (Pujian/Keluhan/dll)
counts.index = [label_map.get(i, i) for i in counts.index]
sns.barplot(x=counts.index, y=counts.values, palette="viridis", ax=ax)
ax.set_title("Proporsi Pesan Masuk (Total)", fontsize=12, fontweight='bold')
ax.set_ylabel("Jumlah Pesan")
# --- TABEL DENGAN KOLOM WAKTU/TANGGAL ---
display_df = df_filtered[["Waktu", "Pesan", "Sentimen"]].copy()
display_df['Sentimen'] = display_df['Sentimen'].map(label_map) # Percantik label di tabel
display_df = display_df.sort_values(by="Waktu", ascending=False) # Urutkan: Terbaru di atas
return fig, display_df, f"Menampilkan {len(df_filtered)} pesan ({filter_val})"
# --- INTERFACE GRADIO ---
with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald"), title="PoskoLog Dashboard") as demo:
gr.Markdown("# πŸ“¦ PoskoLog: Suara Pengungsi")
gr.Markdown("Sistem analisis sentimen otomatis untuk memprioritaskan laporan darurat pasca-bencana.")
with gr.Tabs():
# --- TAB USER ---
with gr.Tab("πŸ“ Sampaikan Pesan"):
with gr.Column(variant="panel"):
gr.Markdown("### Laporkan kondisi atau berikan masukan Anda")
user_input = gr.Textbox(
label="Komentar Anda",
placeholder="Contoh: Bantuan air bersih belum sampai di tenda C...",
lines=4
)
submit_btn = gr.Button("Kirim Pesan", variant="primary")
user_feedback = gr.Markdown("")
# --- TAB ADMIN ---
with gr.Tab("πŸ“Š Dashboard Admin"):
with gr.Row():
sentiment_filter = gr.Dropdown(
choices=["SEMUA"] + list(label_map.values()),
value="SEMUA",
label="Filter Sentimen"
)
refresh_btn = gr.Button("πŸ”„ Refresh & Filter Data", variant="secondary")
with gr.Row():
with gr.Column(scale=1):
plot_output = gr.Plot(label="Grafik Distribusi")
with gr.Column(scale=2):
gr.Markdown("#### Daftar Laporan Masuk")
# Tabel diperbarui dengan kolom Waktu
table_output = gr.Dataframe(
headers=["Waktu", "Pesan", "Sentimen"],
interactive=False,
wrap=True
)
status_txt = gr.Markdown("Klik 'Refresh' untuk memuat data terbaru.")
# --- BINDING EVENTS ---
# Saat klik kirim: proses teks, beri feedback, dan kosongkan textbox
submit_btn.click(
fn=process_submission,
inputs=user_input,
outputs=[user_feedback, user_input]
)
# Saat klik refresh: update grafik dan tabel berdasarkan filter
refresh_btn.click(
fn=get_admin_dashboard,
inputs=sentiment_filter,
outputs=[plot_output, table_output, status_txt]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)