""" Human+ — Page 2: AI Analysis Refactored: loading states & biomarker rows pakai Streamlit native. """ import streamlit as st from ui.components import ( render_loading_steps, render_progress_bar, render_section_label, render_error_state, render_biomarker_summary_banner, render_biomarker_row, render_success_banner, ANALYSIS_STEPS, ) from ui.chart_components import ( render_gauge_grid, render_biomarker_bar_chart, render_status_donut, ) def render_analysis_page(): if not st.session_state.get("uploaded_pdf_bytes"): render_error_state( title="Tidak ada file PDF", message="Silakan kembali ke langkah pertama dan upload hasil lab Anda.", ) if st.button("← Kembali ke Upload", use_container_width=True): st.session_state.step = 1 st.rerun() return if st.session_state.get("extracted_biomarkers") is not None: _render_biomarker_results() return _run_analysis() # ── Analysis runner ────────────────────────────────────────────────── def _run_analysis(): render_section_label("MENGANALISIS LAB ANDA", "⚡") status_ph = st.empty() progress_ph = st.empty() steps_ph = st.empty() def _update(step_idx: int, msg: str): with status_ph: st.caption(f"⚙️ {msg}...") with progress_ph: render_progress_bar((step_idx + 0.5) / len(ANALYSIS_STEPS)) with steps_ph: render_loading_steps(ANALYSIS_STEPS, step_idx) # Step 0 — warm up vector store _update(0, ANALYSIS_STEPS[0]) try: from core.rag_engine import get_vector_store get_vector_store() except Exception: pass # Step 1 — Gemini PDF extraction _update(1, ANALYSIS_STEPS[1]) try: from core.pdf_processor import extract_biomarkers biomarkers = extract_biomarkers(st.session_state.uploaded_pdf_bytes) except Exception as e: _clear(steps_ph, status_ph, progress_ph) render_error_state( title="Gagal Menganalisis PDF", message=f"{e}\n\nPastikan PDF berisi hasil lab yang valid dan terbaca.", show_contact=True, ) col1, col2 = st.columns(2) with col1: if st.button("← Upload Lagi", use_container_width=True): st.session_state.step = 1 st.session_state.uploaded_pdf_bytes = None st.rerun() with col2: if st.button("🔄 Coba Lagi", type="primary", use_container_width=True): st.rerun() return # Step 2 & 3 — finalize _update(2, ANALYSIS_STEPS[2]) import time; time.sleep(0.3) _update(3, ANALYSIS_STEPS[3]) import time; time.sleep(0.3) st.session_state.extracted_biomarkers = biomarkers with progress_ph: render_progress_bar(1.0) with status_ph: st.caption("✅ Analisis selesai") import time; time.sleep(0.4) st.rerun() def _clear(*placeholders): for ph in placeholders: ph.empty() # ── Results renderer ───────────────────────────────────────────────── def _render_biomarker_results(): biomarkers = st.session_state.extracted_biomarkers if not biomarkers: render_error_state( title="Tidak ada biomarker terdeteksi", message="Coba upload file PDF yang lebih jelas atau format hasil lab standar.", show_contact=True, ) if st.button("← Upload Ulang", use_container_width=True): for k in ["uploaded_pdf_bytes", "extracted_biomarkers", "generated_protocol"]: st.session_state[k] = None st.session_state.step = 1 st.rerun() return optimal = sum(1 for b in biomarkers if b["status"] == "optimal") warning = sum(1 for b in biomarkers if b["status"] == "warning") danger = sum(1 for b in biomarkers if b["status"] == "danger") render_success_banner( title=f"{len(biomarkers)} biomarker berhasil dianalisis", subtitle="Dibandingkan dengan Human+ optimal ranges — bukan range lab standar", ) render_biomarker_summary_banner(optimal, warning, danger) # ── Charts ──────────────────────────────────────────────────── render_section_label("VISUALISASI BIOMARKER", "📊") col_donut, col_bar = st.columns([1, 2]) with col_donut: render_status_donut(optimal, warning, danger) with col_bar: render_biomarker_bar_chart(biomarkers) render_section_label("GAUGE — MARKER PRIORITAS", "🎯") render_gauge_grid(biomarkers) # ── Biomarker rows ───────────────────────────────────────────── if danger: render_section_label(f"PERLU PERHATIAN — {danger} MARKER", "🔴") for b in biomarkers: if b["status"] == "danger": render_biomarker_row(b["name"], b["value"], b["unit"], b["status"], b.get("reference", "")) if warning: render_section_label(f"SUB-OPTIMAL — {warning} MARKER", "🟡") for b in biomarkers: if b["status"] == "warning": render_biomarker_row(b["name"], b["value"], b["unit"], b["status"], b.get("reference", "")) if optimal: render_section_label(f"SUDAH OPTIMAL — {optimal} MARKER", "🟢") for b in biomarkers: if b["status"] == "optimal": render_biomarker_row(b["name"], b["value"], b["unit"], b["status"], b.get("reference", "")) neutral = [b for b in biomarkers if b["status"] == "neutral"] if neutral: with st.expander(f"📊 {len(neutral)} marker lainnya"): for b in neutral: render_biomarker_row(b["name"], b["value"], b["unit"], "neutral", "") st.write("") if st.button("🔬 Generate Protocol Personal Saya", type="primary", use_container_width=True): st.session_state.step = 3 st.rerun() if st.button("← Upload Lab Lain", use_container_width=True): for k in ["uploaded_pdf_bytes", "extracted_biomarkers", "generated_protocol", "pdf_filename"]: st.session_state[k] = None st.session_state.step = 1 st.rerun()