|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
all_messages = [] |
|
|
|
|
|
|
|
|
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() |
|
|
|
|
|
|
|
|
result = sentiment_pipeline(text)[0] |
|
|
label = result['label'].upper() |
|
|
|
|
|
|
|
|
new_entry = { |
|
|
"Waktu": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), |
|
|
"Pesan": text.strip(), |
|
|
"Sentimen": label |
|
|
} |
|
|
all_messages.append(new_entry) |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
if filter_val != "SEMUA": |
|
|
|
|
|
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}" |
|
|
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(8, 5)) |
|
|
counts = df_all['Sentimen'].value_counts() |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
display_df = df_filtered[["Waktu", "Pesan", "Sentimen"]].copy() |
|
|
display_df['Sentimen'] = display_df['Sentimen'].map(label_map) |
|
|
display_df = display_df.sort_values(by="Waktu", ascending=False) |
|
|
|
|
|
return fig, display_df, f"Menampilkan {len(df_filtered)} pesan ({filter_val})" |
|
|
|
|
|
|
|
|
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(): |
|
|
|
|
|
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("") |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
table_output = gr.Dataframe( |
|
|
headers=["Waktu", "Pesan", "Sentimen"], |
|
|
interactive=False, |
|
|
wrap=True |
|
|
) |
|
|
|
|
|
status_txt = gr.Markdown("Klik 'Refresh' untuk memuat data terbaru.") |
|
|
|
|
|
|
|
|
|
|
|
submit_btn.click( |
|
|
fn=process_submission, |
|
|
inputs=user_input, |
|
|
outputs=[user_feedback, user_input] |
|
|
) |
|
|
|
|
|
|
|
|
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) |