File size: 5,416 Bytes
bde8d2f
 
bd99d2b
bde8d2f
 
 
 
 
bd99d2b
6e4bbc4
bd99d2b
 
 
bde8d2f
ab72c0d
bd99d2b
bde8d2f
6e4bbc4
ab72c0d
 
 
 
 
 
bd99d2b
 
 
 
6e4bbc4
bd99d2b
 
 
6e4bbc4
bd99d2b
6e4bbc4
bd99d2b
 
 
 
 
 
dccfab0
ab72c0d
bde8d2f
ab72c0d
bd99d2b
6e4bbc4
bde8d2f
ab72c0d
bde8d2f
ab72c0d
 
6e4bbc4
ab72c0d
 
 
 
 
 
 
6e4bbc4
ab72c0d
6e4bbc4
bd99d2b
ab72c0d
6e4bbc4
bd99d2b
bde8d2f
ab72c0d
 
6e4bbc4
 
 
 
 
 
 
 
bde8d2f
bd99d2b
ab72c0d
 
6e4bbc4
bde8d2f
 
6e4bbc4
bd99d2b
 
6e4bbc4
 
 
 
 
 
bd99d2b
 
 
6e4bbc4
ab72c0d
 
 
 
 
 
 
6e4bbc4
bde8d2f
 
6e4bbc4
ab72c0d
6e4bbc4
 
 
 
 
 
 
 
ab72c0d
6e4bbc4
bd99d2b
6e4bbc4
 
 
 
 
 
 
 
 
 
 
 
 
 
bde8d2f
 
bd99d2b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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)