Update sentiment_app.py
Browse files- sentiment_app.py +57 -65
sentiment_app.py
CHANGED
|
@@ -12,8 +12,16 @@ MODEL_NAME = "w11wo/indonesian-roberta-base-sentiment-classifier"
|
|
| 12 |
device = 0 if torch.cuda.is_available() else -1
|
| 13 |
sentiment_pipeline = pipeline("sentiment-analysis", model=MODEL_NAME, device=device)
|
| 14 |
|
|
|
|
| 15 |
all_messages = []
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
def process_submission(text):
|
| 18 |
if not text or text.strip() == "":
|
| 19 |
return "β οΈ Mohon isi komentar Anda terlebih dahulu.", gr.update()
|
|
@@ -22,102 +30,86 @@ def process_submission(text):
|
|
| 22 |
result = sentiment_pipeline(text)[0]
|
| 23 |
label = result['label'].upper()
|
| 24 |
|
| 25 |
-
# 2. Simpan ke
|
| 26 |
new_entry = {
|
| 27 |
-
"Waktu": datetime.now().strftime("%H:%M
|
| 28 |
"Pesan": text.strip(),
|
| 29 |
"Sentimen": label
|
| 30 |
}
|
| 31 |
all_messages.append(new_entry)
|
| 32 |
|
| 33 |
# 3. Respons untuk User
|
| 34 |
-
thanks_msg =
|
| 35 |
-
|
| 36 |
-
Masukan Anda sangat berharga bagi kami di Posko. Pesan Anda telah kami terima dan akan segera diproses oleh tim admin.
|
| 37 |
-
"""
|
| 38 |
-
|
| 39 |
-
return thanks_msg, gr.update(value="") # Clear input box
|
| 40 |
|
| 41 |
-
def get_admin_dashboard():
|
| 42 |
if not all_messages:
|
| 43 |
-
return None, "Belum ada data
|
| 44 |
|
| 45 |
-
|
| 46 |
|
| 47 |
-
# ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
fig, ax = plt.subplots(figsize=(8, 5))
|
| 49 |
color_map = {"POSITIVE": "#4CAF50", "NEGATIVE": "#F44336", "NEUTRAL": "#FFC107"}
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
counts = df['Sentimen'].value_counts()
|
| 53 |
counts.index = [label_map.get(i, i) for i in counts.index]
|
| 54 |
|
| 55 |
-
sns.barplot(x=counts.index, y=counts.values, palette=
|
| 56 |
-
ax.set_title("
|
| 57 |
-
ax.set_ylabel("Jumlah Pesan")
|
| 58 |
-
|
| 59 |
-
# --- TABEL 2: Top 10 Pesan Terbanyak (Informasi Serupa) ---
|
| 60 |
-
# Kita mengelompokkan pesan yang mirip atau identik
|
| 61 |
-
counter = collections.Counter([m['Pesan'].lower() for m in all_messages])
|
| 62 |
-
top_10 = counter.most_common(10)
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
return fig,
|
| 67 |
|
| 68 |
# --- INTERFACE GRADIO ---
|
| 69 |
-
with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald"), title="PoskoLog
|
| 70 |
-
gr.Markdown(""
|
| 71 |
-
# π¦ PoskoLog: Suara Pengungsi
|
| 72 |
-
Selamat datang di layanan aspirasi digital posko. Silakan sampaikan keluhan, kebutuhan, atau pertanyaan Anda.
|
| 73 |
-
""")
|
| 74 |
|
| 75 |
with gr.Tabs():
|
| 76 |
-
#
|
| 77 |
with gr.Tab("π Sampaikan Pesan"):
|
| 78 |
with gr.Column(variant="panel"):
|
| 79 |
-
gr.
|
| 80 |
-
user_input = gr.Textbox(
|
| 81 |
-
label="Komentar / Masukan Anda",
|
| 82 |
-
placeholder="Tuliskan kebutuhan atau keluhan Anda di sini (Contoh: Air bersih habis di tenda C)...",
|
| 83 |
-
lines=4
|
| 84 |
-
)
|
| 85 |
submit_btn = gr.Button("Kirim Pesan", variant="primary")
|
| 86 |
-
|
| 87 |
-
# Output area untuk ucapan terima kasih
|
| 88 |
user_feedback = gr.Markdown("")
|
| 89 |
-
|
| 90 |
-
gr.Markdown("""
|
| 91 |
-
---
|
| 92 |
-
*Catatan: Pesan Anda akan dianalisis secara otomatis untuk memprioritaskan bantuan yang paling mendesak.*
|
| 93 |
-
""")
|
| 94 |
|
| 95 |
-
#
|
| 96 |
-
with gr.Tab("π Dashboard Admin
|
| 97 |
-
gr.
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
with gr.Row():
|
| 101 |
with gr.Column():
|
| 102 |
-
plot_output = gr.Plot(label="Grafik
|
| 103 |
with gr.Column():
|
| 104 |
-
gr.Markdown("#### π Top 10
|
| 105 |
-
table_output = gr.Dataframe(
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
)
|
| 109 |
|
| 110 |
-
#
|
| 111 |
-
submit_btn.click(
|
| 112 |
-
|
| 113 |
-
inputs=user_input,
|
| 114 |
-
outputs=[user_feedback, user_input]
|
| 115 |
-
)
|
| 116 |
-
|
| 117 |
-
refresh_btn.click(
|
| 118 |
-
fn=get_admin_dashboard,
|
| 119 |
-
outputs=[plot_output, table_output]
|
| 120 |
-
)
|
| 121 |
|
| 122 |
if __name__ == "__main__":
|
| 123 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 12 |
device = 0 if torch.cuda.is_available() else -1
|
| 13 |
sentiment_pipeline = pipeline("sentiment-analysis", model=MODEL_NAME, device=device)
|
| 14 |
|
| 15 |
+
# --- DATABASE SEDERHANA (In-Memory) ---
|
| 16 |
all_messages = []
|
| 17 |
|
| 18 |
+
# Mapping Label untuk Tampilan UI
|
| 19 |
+
label_map = {
|
| 20 |
+
"POSITIVE": "Pujian/Apresiasi",
|
| 21 |
+
"NEGATIVE": "Keluhan/Kritik",
|
| 22 |
+
"NEUTRAL": "Pertanyaan/Info"
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
def process_submission(text):
|
| 26 |
if not text or text.strip() == "":
|
| 27 |
return "β οΈ Mohon isi komentar Anda terlebih dahulu.", gr.update()
|
|
|
|
| 30 |
result = sentiment_pipeline(text)[0]
|
| 31 |
label = result['label'].upper()
|
| 32 |
|
| 33 |
+
# 2. Simpan ke Database Lokal
|
| 34 |
new_entry = {
|
| 35 |
+
"Waktu": datetime.now().strftime("%Y-%m-%d %H:%M"),
|
| 36 |
"Pesan": text.strip(),
|
| 37 |
"Sentimen": label
|
| 38 |
}
|
| 39 |
all_messages.append(new_entry)
|
| 40 |
|
| 41 |
# 3. Respons untuk User
|
| 42 |
+
thanks_msg = "### π Terima kasih atas pesan Anda!\nMasukan Anda telah kami terima dan akan segera ditinjau oleh tim admin posko."
|
| 43 |
+
return thanks_msg, gr.update(value="")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
def get_admin_dashboard(filter_val):
|
| 46 |
if not all_messages:
|
| 47 |
+
return None, pd.DataFrame(columns=["Pesan", "Sentimen", "Jumlah"]), "Belum ada data."
|
| 48 |
|
| 49 |
+
df_all = pd.DataFrame(all_messages)
|
| 50 |
|
| 51 |
+
# --- LOGIKA FILTER ---
|
| 52 |
+
if filter_val != "SEMUA":
|
| 53 |
+
# Balik mapping untuk filter data asli
|
| 54 |
+
rev_map = {v: k for k, v in label_map.items()}
|
| 55 |
+
target = rev_map.get(filter_val)
|
| 56 |
+
df_filtered = df_all[df_all['Sentimen'] == target]
|
| 57 |
+
else:
|
| 58 |
+
df_filtered = df_all
|
| 59 |
+
|
| 60 |
+
if df_filtered.empty:
|
| 61 |
+
return None, pd.DataFrame(columns=["Pesan", "Sentimen", "Jumlah"]), f"Tidak ada data untuk kategori: {filter_val}"
|
| 62 |
+
|
| 63 |
+
# --- VISUALISASI TOTAL ---
|
| 64 |
fig, ax = plt.subplots(figsize=(8, 5))
|
| 65 |
color_map = {"POSITIVE": "#4CAF50", "NEGATIVE": "#F44336", "NEUTRAL": "#FFC107"}
|
| 66 |
+
counts = df_all['Sentimen'].value_counts()
|
|
|
|
|
|
|
| 67 |
counts.index = [label_map.get(i, i) for i in counts.index]
|
| 68 |
|
| 69 |
+
sns.barplot(x=counts.index, y=counts.values, palette="viridis", ax=ax)
|
| 70 |
+
ax.set_title("Proporsi Pesan Masuk (Total)", fontsize=12, fontweight='bold')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
# --- TABEL TOP 10 DENGAN KOLOM SENTIMEN ---
|
| 73 |
+
top_df = df_filtered.groupby(['Pesan', 'Sentimen']).size().reset_index(name='Jumlah')
|
| 74 |
+
top_df = top_df.sort_values(by='Jumlah', ascending=False).head(10)
|
| 75 |
+
top_df['Sentimen'] = top_df['Sentimen'].map(label_map) # Percantik label di tabel
|
| 76 |
|
| 77 |
+
return fig, top_df, f"Menampilkan {len(df_filtered)} pesan ({filter_val})"
|
| 78 |
|
| 79 |
# --- INTERFACE GRADIO ---
|
| 80 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald"), title="PoskoLog Dashboard") as demo:
|
| 81 |
+
gr.Markdown("# π¦ PoskoLog: Suara Pengungsi")
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
with gr.Tabs():
|
| 84 |
+
# TAB USER
|
| 85 |
with gr.Tab("π Sampaikan Pesan"):
|
| 86 |
with gr.Column(variant="panel"):
|
| 87 |
+
user_input = gr.Textbox(label="Komentar Anda", placeholder="Tulis masukan di sini...", lines=4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
submit_btn = gr.Button("Kirim Pesan", variant="primary")
|
|
|
|
|
|
|
| 89 |
user_feedback = gr.Markdown("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
+
# TAB ADMIN
|
| 92 |
+
with gr.Tab("π Dashboard Admin"):
|
| 93 |
+
with gr.Row():
|
| 94 |
+
sentiment_filter = gr.Dropdown(
|
| 95 |
+
choices=["SEMUA"] + list(label_map.values()),
|
| 96 |
+
value="SEMUA",
|
| 97 |
+
label="Filter Sentimen"
|
| 98 |
+
)
|
| 99 |
+
refresh_btn = gr.Button("π Refresh & Filter", variant="secondary")
|
| 100 |
|
| 101 |
with gr.Row():
|
| 102 |
with gr.Column():
|
| 103 |
+
plot_output = gr.Plot(label="Grafik Distribusi")
|
| 104 |
with gr.Column():
|
| 105 |
+
gr.Markdown("#### π Top 10 Pesan Berdasarkan Filter")
|
| 106 |
+
table_output = gr.Dataframe(headers=["Pesan", "Sentimen", "Jumlah"], interactive=False)
|
| 107 |
+
|
| 108 |
+
status_txt = gr.Markdown("")
|
|
|
|
| 109 |
|
| 110 |
+
# Binding Events
|
| 111 |
+
submit_btn.click(fn=process_submission, inputs=user_input, outputs=[user_feedback, user_input])
|
| 112 |
+
refresh_btn.click(fn=get_admin_dashboard, inputs=sentiment_filter, outputs=[plot_output, table_output, status_txt])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
|
| 114 |
if __name__ == "__main__":
|
| 115 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|