import streamlit as st from agent import run_agent from setup import setup setup() st.set_page_config( page_title="SoapBox", page_icon="✦", layout="centered", initial_sidebar_state="collapsed" ) st.markdown(""" """, unsafe_allow_html=True) # ── Session State ───────────────────────────────────────────── if "stage" not in st.session_state: st.session_state.stage = "upload" if "uploaded_text" not in st.session_state: st.session_state.uploaded_text = None if "agent_steps" not in st.session_state: st.session_state.agent_steps = [] if "final_note" not in st.session_state: st.session_state.final_note = None if "evaluation" not in st.session_state: st.session_state.evaluation = None TOOL_LABELS = { "assess_completeness": "Assessed completeness", "retrieve_similar_cases": "Searched knowledge base", "check_medications": "Checked medications", "generate_soap_note": "Generated SOAP note", } # ── Wordmark ────────────────────────────────────────────────── st.markdown("# SoapBox") st.markdown('
Your AI medical scribe
', unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════ # STAGE 1 — UPLOAD # ══════════════════════════════════════════════════════════════ if st.session_state.stage == "upload": st.markdown(""" """, unsafe_allow_html=True) with st.container(): st.markdown("""
Paste your visit transcripts
Type or paste the provider — patient conversation below
""", unsafe_allow_html=True) pasted_text = st.text_area( "transcript", height=220, placeholder="Dr: Good morning, what brings you in today?\nPatient: I've been having neck pain for the past two weeks...", label_visibility="collapsed" ) # Button always visible col1, col2, col3 = st.columns([1, 2, 1]) with col2: clicked = st.button("Begin Scribing", disabled=not pasted_text.strip() ) if clicked and pasted_text.strip(): st.session_state.uploaded_text = pasted_text st.session_state.stage = "processing" st.rerun() # ══════════════════════════════════════════════════════════════ # STAGE 2 — PROCESSING # ══════════════════════════════════════════════════════════════ elif st.session_state.stage == "processing": tools_done = [ s["tool"] for s in st.session_state.agent_steps if s["type"] == "tool_call" ] pills = "".join([ f'✓ {TOOL_LABELS.get(t, t)}' for t in tools_done ]) st.markdown(f"""
Scribing in progress
Processing transcript...
{pills}
""", unsafe_allow_html=True) if not st.session_state.final_note: steps = run_agent(st.session_state.uploaded_text) st.session_state.agent_steps = steps for step in steps: if step["type"] == "final": st.session_state.final_note = step["content"] if step["type"] == "evaluation": st.session_state.evaluation = step["content"] st.session_state.stage = "complete" st.rerun() # ══════════════════════════════════════════════════════════════ # STAGE 3 — COMPLETE # ══════════════════════════════════════════════════════════════ elif st.session_state.stage == "complete": tools_used = len({ s["tool"] for s in st.session_state.agent_steps if s["type"] == "tool_call" }) ev = st.session_state.evaluation tab1, tab2 = st.tabs(["SOAP Note", "Note Quality"]) # ══════════════════════════════════════════════════ # TAB 1 — SOAP Note # ══════════════════════════════════════════════════ with tab1: st.markdown(st.session_state.final_note) col1, col2, col3 = st.columns([1, 2, 1]) with col2: st.download_button( label="↓ Download Note", data=st.session_state.final_note, file_name="soap_note.txt", mime="text/plain" ) if st.button("↩ Scribe another"): for key in ["uploaded_text", "agent_steps", "final_note", "evaluation"]: st.session_state[key] = None st.session_state.stage = "upload" st.rerun() # ══════════════════════════════════════════════════ # TAB 2 — Note Quality (dynamic per session) # ══════════════════════════════════════════════════ with tab2: if not ev: st.info("Evaluation not available for this note.") else: overall = ev.get("overall_score", 0) if overall >= 9: badge_color = "#1B4332" badge_label = "Excellent" elif overall >= 7: badge_color = "#2D6A4F" badge_label = "Good" elif overall >= 5: badge_color = "#B5924C" badge_label = "Moderate" else: badge_color = "#9B1C1C" badge_label = "Needs Review" st.markdown(f"""
Note Quality Report
Evaluated against this transcript
{badge_label} · {overall}/10
Overall note quality
{overall}/10
""", unsafe_allow_html=True) metrics_order = [ "completeness", "accuracy", "medication_capture", "clinical_reasoning", "structure" ] metric_labels = { "completeness": "Completeness", "accuracy": "Accuracy", "medication_capture": "Medication Capture", "clinical_reasoning": "Clinical Reasoning", "structure": "Structure" } for key in metrics_order: if key not in ev: continue m = ev[key] score = m.get("score", 0) reason = m.get("reason", "") description = m.get("description", "") pct = int((score / 10) * 100) if score >= 9: bar_color = "#1B4332" elif score >= 7: bar_color = "#2D6A4F" elif score >= 5: bar_color = "#B5924C" else: bar_color = "#9B1C1C" st.markdown(f"""
{metric_labels[key]}
{description}
{score}/10
{reason}
""", unsafe_allow_html=True) st.markdown("""
For clinical oversight only
""", unsafe_allow_html=True)