indo-bert-sentiment / src /streamlit_app.py
JefriS3lf's picture
Update src/streamlit_app.py
06fbe8d verified
Raw
History Blame Contribute Delete
5.04 kB
import numpy as np
import streamlit as st
from inference import load_model, predict_sentiment
# Konfigurasi halaman
st.set_page_config(
page_title="Analisis Sentimen Kesehatan Mental Ibu Hamil di Indonesia🧠",
page_icon="🧠",
layout="centered",
)
@st.cache_resource(show_spinner="Sedang memuat model IndoBERT, tunggu sebentar...")
def get_model():
tokenizer, model, device = load_model()
return tokenizer, model, device
def format_prob(p: float) -> str:
"""Ubah probabilitas jadi persen rapi, misal 0.873 → '87.3%'."""
return f"{p * 100:.1f}%"
def main():
st.markdown("## 🧠 Analisis Sentimen Teks (Kesehatan Mental Ibu Hamil di Indonesia🧠)")
st.markdown(
"""
Aplikasi ini membaca **teks berbahasa Indonesia** lalu mencoba
menebak apakah isi kalimat tersebut bernada **positif** atau **negatif**.
Cukup tulis kalimat di bawah, lalu tekan tombol **Analisis Sentimen**.
"""
)
st.divider()
# Kolom utama: input di kiri, penjelasan singkat di kanan
col_input, col_info = st.columns([2, 1])
with col_input:
st.markdown("### ✍️ Tulis teks di sini")
default_text = "mertua saya selalu bikin saya sedih dan suami saya lagi kerja di luar kota"
text = st.text_area(
"Teks yang ingin dianalisis",
value=default_text,
height=140,
placeholder="Contoh: saya bahagia karena selama saya hamil suami saya peduli dengan saya",
)
with col_info:
st.markdown("### ℹ️ Petunjuk singkat")
st.markdown(
"""
- Tulis kalimat yang **alami**, seperti ulasan, komentar, atau opini.
- Model hanya mengenali dua jenis sentimen:
- 😊 **Positif**
- 😞 **Negatif**
- Hasil bukan “benar-salah mutlak”, tapi **perkiraan model**.
"""
)
# Pengaturan teknis kita sembunyikan di expander
with st.expander("⚙️ Pengaturan lanjutan (opsional)"):
max_len = st.slider(
"Panjang maksimal teks yang diproses model (dalam token)",
min_value=64,
max_value=256,
value=128,
step=16,
help="Untuk kebanyakan kasus, 128 sudah cukup. Naikkan hanya jika teks sangat panjang.",
)
# default jika expander tidak dibuka
if "max_len" not in locals():
max_len = 128
st.divider()
# Tombol aksi
analyze = st.button("🔍 Analisis Sentimen", use_container_width=True)
if analyze:
if not text or text.strip() == "":
st.warning("Teks masih kosong. Silakan isi kalimat terlebih dahulu.")
return
tokenizer, model, device = get_model()
with st.spinner("Model sedang membaca teks kamu..."):
result = predict_sentiment(
text=text,
tokenizer=tokenizer,
model=model,
device=device,
max_length=max_len,
)
label = result["label_name"] # "Negatif" / "Positif"
probs = result["probs"] # [p_neg, p_pos]
p_neg, p_pos = float(probs[0]), float(probs[1])
# Blok hasil utama: dibuat sangat "manusiawi"
if label.lower().startswith("positif"):
st.success(
f"**Perkiraan model: Sentimen POSITIF 😊**\n\n"
f"Model cukup yakin bahwa kalimat ini bernada **positif**.\n"
f"• Perkiraan positif: **{format_prob(p_pos)}**\n"
f"• Perkiraan negatif: {format_prob(p_neg)}",
icon="✅",
)
else:
st.error(
f"**Perkiraan model: Sentimen NEGATIF 😞**\n\n"
f"Model membaca kalimat ini cenderung bernada **negatif**.\n"
f"• Perkiraan negatif: **{format_prob(p_neg)}**\n"
f"• Perkiraan positif: {format_prob(p_pos)}",
icon="⚠️",
)
st.markdown("---")
# Visual probabilitas versi sederhana
st.markdown("### 🎯 Tingkat keyakinan model")
chart_data = {
"Sentimen": ["Negatif (0)", "Positif (1)"],
"Probabilitas": [p_neg, p_pos],
}
st.bar_chart(
data={
"Negatif (0)": [p_neg],
"Positif (1)": [p_pos],
}
)
# Detail teknis disembunyikan, hanya untuk user yang penasaran
with st.expander("🔍 Detail teknis (opsional)"):
st.write("Logits (sebelum softmax):", result["logits"])
st.write(
"Probabilitas mentah:",
{
"negatif (0)": p_neg,
"positif (1)": p_pos,
},
)
st.caption(
"Bagian ini lebih bersifat teknis dan biasanya hanya dipakai untuk debugging atau analisis model."
)
if __name__ == "__main__":
main()