Spaces:
Sleeping
Sleeping
| import io | |
| import pandas as pd | |
| import streamlit as st | |
| import plotly.express as px | |
| from utils.model_loader import predict_batch, model_is_available | |
| st.markdown("## 📊 Analisis Batch") | |
| st.caption("Unggah file CSV berisi ulasan produk untuk memproses sentimen secara massal.") | |
| with st.container(border=True): | |
| uploaded = st.file_uploader( | |
| "Seret & letakkan file CSV di sini, atau klik untuk memilih file dari komputer", | |
| type=["csv"], | |
| help="Format: CSV · Maks: 20MB · Kolom teks harus ada", | |
| ) | |
| st.caption("📄 Format: CSV · Maks: 20MB · Kolom teks (Butuh 1 kolom berisi teks ulasan)") | |
| st.caption("Belum ada file? [unduh contoh data](https://example.com) — atau gunakan `sample_data/contoh_ulasan.csv` di repo ini.") | |
| if uploaded is not None: | |
| try: | |
| df = pd.read_csv(uploaded) | |
| except Exception as e: | |
| st.error(f"Gagal membaca CSV: {e}") | |
| st.stop() | |
| if df.empty: | |
| st.warning("File CSV kosong.") | |
| st.stop() | |
| st.write("") | |
| text_col = st.selectbox( | |
| "Pilih kolom yang berisi teks ulasan:", | |
| options=list(df.columns), | |
| index=0, | |
| ) | |
| max_rows = st.slider("Jumlah baris yang diproses (batasi untuk demo cepat)", 1, len(df), min(len(df), 200)) | |
| run = st.button("🚀 Jalankan Analisis Batch", type="primary") | |
| if run: | |
| subset = df.head(max_rows).copy() | |
| texts = subset[text_col].astype(str).tolist() | |
| progress_bar = st.progress(0.0, text="Memproses ulasan...") | |
| def _cb(frac): | |
| progress_bar.progress(frac, text=f"Memproses ulasan... {int(frac*100)}%") | |
| results = predict_batch(texts, progress_callback=_cb) | |
| progress_bar.empty() | |
| subset["Sentimen"] = [r[0] for r in results] | |
| subset["Confidence"] = [round(r[1] * 100, 2) for r in results] | |
| st.success(f"Selesai! {len(subset)} ulasan berhasil dianalisis.") | |
| st.markdown("#### Hasil Analisis") | |
| st.dataframe(subset, use_container_width=True, height=320) | |
| st.write("") | |
| col_pie, col_bar = st.columns(2) | |
| sent_counts = subset["Sentimen"].value_counts().reindex(["Positive", "Negative"]).fillna(0) | |
| with col_pie: | |
| fig_pie = px.pie( | |
| names=sent_counts.index, values=sent_counts.values, | |
| color=sent_counts.index, | |
| color_discrete_map={"Positive": "#2ecc71", "Negative": "#e74c3c"}, | |
| title="Proporsi Sentimen", | |
| hole=0.35, | |
| ) | |
| st.plotly_chart(fig_pie, use_container_width=True) | |
| with col_bar: | |
| fig_bar = px.bar( | |
| x=sent_counts.index, y=sent_counts.values, | |
| color=sent_counts.index, | |
| color_discrete_map={"Positive": "#2ecc71", "Negative": "#e74c3c"}, | |
| labels={"x": "Sentimen", "y": "Jumlah Ulasan"}, | |
| title="Distribusi Sentimen", | |
| ) | |
| fig_bar.update_layout(showlegend=False) | |
| st.plotly_chart(fig_bar, use_container_width=True) | |
| csv_buffer = io.StringIO() | |
| subset.to_csv(csv_buffer, index=False) | |
| st.download_button( | |
| "⬇️ Unduh Hasil Analisis (CSV)", | |
| data=csv_buffer.getvalue(), | |
| file_name="hasil_analisis_sentimen.csv", | |
| mime="text/csv", | |
| ) | |
| else: | |
| st.info("Unggah file CSV untuk mulai menganalisis banyak ulasan sekaligus.") | |
| if not model_is_available(): | |
| st.caption( | |
| "⚠️ Model IndoBERT belum ditemukan — hasil batch di atas menggunakan mode demo " | |
| "(heuristik kata kunci). Lihat README.md untuk cara memasang model asli." | |
| ) | |