"""Lab Administrator persona. Features: - Lab turnaround time analytics - Specimen volume tracking - Positivity rate monitoring - AI Diagnostics Lab (Vision, Audio) - Administrative OCR form digitizer - Lab Intelligence chatbot """ import os import streamlit as st import plotly.express as px from data.synthetic import get_lab_results, get_polypharmacy_alerts from services.diagnostics import analyze_wound_image, analyze_respiratory_audio, process_ocr_form from components.chatbot import render_chatbot # Path to sample assets _ASSETS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "assets", "samples") def render(): """Render the Lab Admin dashboard.""" st.title("Laboratory Intelligence Center") lab_data = get_lab_results() # Top KPI row avg_tat = lab_data["TAT_Hours"].mean() total_specimens = lab_data["Specimens_Processed"].sum() avg_positivity = lab_data["Positivity_Rate"].mean() total_critical = lab_data["Critical_Values_Reported"].sum() total_rejected = lab_data["Rejected_Specimens"].sum() c1, c2, c3, c4, c5 = st.columns(5) with c1: st.metric("Avg TAT", f"{avg_tat:.1f} hrs", "-12%") with c2: st.metric("Specimens (30d)", f"{total_specimens:,}") with c3: st.metric("Avg Positivity", f"{avg_positivity:.1%}") with c4: st.metric("Critical Values", total_critical) with c5: st.metric("Rejected", total_rejected, delta_color="inverse") st.divider() tab_analytics, tab_medintel, tab_vision, tab_audio, tab_ocr, tab_chat = st.tabs([ "Lab Analytics", "💊 Medication Intelligence", "Wound Vision AI", "Respiratory Audio AI", "Form Digitizer (OCR)", "🔬 Lab Intelligence", ]) # --- TAB: LAB ANALYTICS --- with tab_analytics: col1, col2 = st.columns(2) with col1: fig_tat = px.line( lab_data, x="Date", y="TAT_Hours", title="Lab Result Turnaround Time Trend", template="plotly_white", ) fig_tat.add_hline(y=4.0, line_dash="dash", line_color="orange", annotation_text="SLA Target: 4h") fig_tat.update_traces(line_color="#3b82f6") st.plotly_chart(fig_tat, use_container_width=True) with col2: fig_pos = px.bar( lab_data, x="Date", y="Positivity_Rate", title="Infection Positivity Rate", template="plotly_white", color="Positivity_Rate", color_continuous_scale="OrRd", ) st.plotly_chart(fig_pos, use_container_width=True) col3, col4 = st.columns(2) with col3: fig_spec = px.area( lab_data, x="Date", y="Specimens_Processed", title="Daily Specimen Volume", template="plotly_white", ) fig_spec.update_traces(line_color="#10b981", fillcolor="rgba(16,185,129,0.1)") st.plotly_chart(fig_spec, use_container_width=True) with col4: fig_crit = px.bar( lab_data, x="Date", y="Critical_Values_Reported", title="Critical Values Reported", template="plotly_white", color="Critical_Values_Reported", color_continuous_scale="Reds", ) st.plotly_chart(fig_crit, use_container_width=True) # --- TAB: MEDICATION INTELLIGENCE --- with tab_medintel: st.subheader("Medication Interaction Intelligence") st.caption( "AI-powered pharmaceutical surveillance across all residents. " "Detects polypharmacy risks, duplicate classes, and drug-lab correlations." ) med_alerts = get_polypharmacy_alerts() # Summary metrics mi1, mi2, mi3 = st.columns(3) with mi1: st.metric("Active Alerts", len(med_alerts)) with mi2: high_count = sum(1 for a in med_alerts if a["severity"] == "High") st.metric("High Severity", high_count, delta_color="inverse") with mi3: total_meds = sum(len(a["medications_involved"]) for a in med_alerts) st.metric("Medications Flagged", total_meds) st.divider() # Alert detail cards for alert in med_alerts: severity_color = {"High": "#ef4444", "Moderate": "#f59e0b", "Low": "#10b981"}.get( alert["severity"], "#64748b" ) with st.expander( f"{'🔴' if alert['severity'] == 'High' else '🟡'} " f"{alert['resident']} — {alert['alert_type']}", expanded=(alert["severity"] == "High"), ): st.markdown( f"""
{alert['alert_type']} — Severity: {alert['severity']} — Confidence: {alert['confidence']:.0%}
""", unsafe_allow_html=True, ) st.markdown(alert["description"]) st.markdown("**Medications Involved:**") for med in alert["medications_involved"]: st.markdown(f"- 💊 `{med}`") lab_col, rec_col = st.columns(2) with lab_col: st.markdown("**Lab Correlation:**") if "diuretic" in alert["description"].lower(): st.markdown( "- **K+:** Monitor q24h (risk: hypo/hyperkalemia)\n" "- **Na+:** Monitor q24h (risk: hyponatremia)\n" "- **Cr/BUN:** Check within 24h (renal function)\n" "- **Orthostatic BP:** TID checks" ) elif "metformin" in alert["description"].lower(): st.markdown( "- **eGFR:** Trending 62 → 48 over 3 months\n" "- **Lactate:** Check if eGFR < 45\n" "- **HbA1c:** Due for recheck\n" "- **BMP:** Next scheduled draw" ) else: st.markdown( "- **CBC:** Monitor for bleeding (bruising)\n" "- **PT/INR:** If on anticoagulant\n" "- **Fall risk assessment:** Ongoing" ) with rec_col: st.markdown("**Recommendation:**") st.info(alert["recommendation"]) # --- TAB: WOUND VISION AI --- with tab_vision: st.subheader("Wound / Skin Vision Analysis") st.caption("Upload a wound photograph for AI-powered staging and assessment.") # Sample demo option use_sample_wound = st.checkbox( "Use built-in sample image (Sacral Pressure Ulcer - Demo)", key="use_sample_wound", ) if use_sample_wound: sample_path = os.path.join(_ASSETS_DIR, "sample_wound.jpg") if os.path.exists(sample_path): st.image(sample_path, width=400, caption="Sample: Sacral Pressure Ulcer (Synthetic Demo)") if st.button("Run Vision Diagnostics", type="primary", key="btn_vision_sample"): with st.spinner("Vision agent analyzing image..."): result = analyze_wound_image(None) st.success("Analysis complete!") st.markdown(result["summary"]) with st.expander("Detailed Results (JSON)"): st.json(result["result"]) with st.expander("FHIR Observation (auto-generated)"): st.code( '{\n' ' "resourceType": "Observation",\n' ' "status": "final",\n' ' "category": [{"coding": [{"code": "exam", "display": "Exam"}]}],\n' f' "code": {{"text": "Wound Assessment - {result["result"]["stage"]}"}},\n' f' "bodySite": {{"text": "{result["result"]["location"]}"}},\n' f' "valueString": "{result["result"]["size_cm"]} cm, {result["result"]["stage"]}",\n' ' "interpretation": [{"text": "AI Vision Analysis"}],\n' f' "note": [{{"text": "{result["result"]["recommendation"]}"}}]\n' '}', language="json", ) else: st.warning("Sample file not found. Please upload an image instead.") else: img_file = st.file_uploader("Upload Wound Photo", type=["jpg", "jpeg", "png"], key="wound_upload") if img_file: st.image(img_file, width=350, caption="Uploaded Image") if st.button("Run Vision Diagnostics", type="primary", key="btn_vision"): with st.spinner("Vision agent analyzing image..."): result = analyze_wound_image(img_file) st.success("Analysis complete!") st.markdown(result["summary"]) with st.expander("Detailed Results (JSON)"): st.json(result["result"]) with st.expander("FHIR Observation (auto-generated)"): st.code( '{\n' ' "resourceType": "Observation",\n' ' "status": "final",\n' ' "category": [{"coding": [{"code": "exam", "display": "Exam"}]}],\n' f' "code": {{"text": "Wound Assessment - {result["result"]["stage"]}"}},\n' f' "bodySite": {{"text": "{result["result"]["location"]}"}},\n' f' "valueString": "{result["result"]["size_cm"]} cm, {result["result"]["stage"]}",\n' ' "interpretation": [{"text": "AI Vision Analysis"}],\n' f' "note": [{{"text": "{result["result"]["recommendation"]}"}}]\n' '}', language="json", ) # --- TAB: RESPIRATORY AUDIO AI --- with tab_audio: st.subheader("Respiratory Bioacoustic Analysis") st.caption("Upload a lung sound or cough recording for AI-powered respiratory assessment.") use_sample_audio = st.checkbox( "Use built-in sample audio (Simulated Respiratory Recording - Demo)", key="use_sample_audio", ) if use_sample_audio: sample_path = os.path.join(_ASSETS_DIR, "sample_respiratory.wav") if os.path.exists(sample_path): st.audio(sample_path, format="audio/wav") st.caption("Sample: Simulated lung sounds with cough events at ~1.2s and ~2.8s") if st.button("Run Audio Bioacoustics", type="primary", key="btn_audio_sample"): with st.spinner("Audio agent analyzing recording..."): result = analyze_respiratory_audio(None) st.success("Analysis complete!") st.markdown(result["summary"]) # Visual analysis display col_a, col_b = st.columns(2) with col_a: st.markdown("**Detection Summary:**") st.markdown( f"- **Cough Rate:** {result['result']['cough_rate_per_hr']} coughs/hour\n" f"- **Cough Type:** {result['result']['cough_type']}\n" f"- **Trend:** {result['result']['trend']}\n" f"- **Pneumonia Risk:** {result['result']['pneumonia_risk_pct']}%" ) with col_b: st.markdown("**AI Recommendation:**") st.info(result["result"]["recommendation"]) with st.expander("Detailed Results (JSON)"): st.json(result["result"]) else: st.warning("Sample file not found. Please upload an audio file instead.") else: audio_file = st.file_uploader("Upload Audio Recording", type=["mp3", "wav"], key="audio_upload") if audio_file: st.audio(audio_file) if st.button("Run Audio Bioacoustics", type="primary", key="btn_audio"): with st.spinner("Audio agent analyzing recording..."): result = analyze_respiratory_audio(audio_file) st.success("Analysis complete!") st.markdown(result["summary"]) col_a, col_b = st.columns(2) with col_a: st.markdown("**Detection Summary:**") st.markdown( f"- **Cough Rate:** {result['result']['cough_rate_per_hr']} coughs/hour\n" f"- **Cough Type:** {result['result']['cough_type']}\n" f"- **Trend:** {result['result']['trend']}\n" f"- **Pneumonia Risk:** {result['result']['pneumonia_risk_pct']}%" ) with col_b: st.markdown("**AI Recommendation:**") st.info(result["result"]["recommendation"]) with st.expander("Detailed Results (JSON)"): st.json(result["result"]) # --- TAB: ADMINISTRATIVE OCR --- with tab_ocr: st.subheader("Administrative Form Digitizer") st.caption("Convert paper orders, lab reports, and invoices into structured HL7/FHIR-ready data.") use_sample_form = st.checkbox( "Use built-in sample form (Lab Order - Margaret Chen - Demo)", key="use_sample_form", ) if use_sample_form: sample_path = os.path.join(_ASSETS_DIR, "sample_lab_order.jpg") if os.path.exists(sample_path): st.image(sample_path, width=450, caption="Sample: Laboratory Order Form (Synthetic Demo)") if st.button("Digitize Form", type="primary", key="btn_ocr_sample"): with st.spinner("OCR agent processing document..."): result = process_ocr_form(None) st.success( f"Form digitized successfully. Type: **{result['result']['form_type']}**. " f"Confidence: **{result['result'].get('confidence', 'N/A')}**. " f"Output format: HL7 {result['hl7_version']} / FHIR R4." ) col_o1, col_o2 = st.columns(2) with col_o1: st.markdown("**Extracted Fields:**") st.json(result["result"]) with col_o2: st.markdown("**FHIR ServiceRequest (auto-generated):**") st.code( '{\n' ' "resourceType": "ServiceRequest",\n' ' "status": "active",\n' ' "intent": "order",\n' f' "subject": {{"reference": "Patient/{result["result"].get("mrn", "MC-402")}"}},\n' f' "requester": {{"display": "{result["result"].get("ordering_physician", "Dr. Sarah Kim")}"}},\n' ' "code": {"text": "Laboratory Tests"},\n' ' "priority": "routine",\n' ' "authoredOn": "2026-03-26"\n' '}', language="json", ) st.markdown("**HL7 v2.5.1 Message (auto-generated):**") st.code( "MSH|^~\\&|SENIORCARE|LAB|EHR|FACILITY|20260326||ORM^O01|MSG001|P|2.5.1\n" f"PID|1||{result['result'].get('mrn', 'MC-402')}||{result['result'].get('patient', 'Chen^Margaret')}||\n" "ORC|NW|ORD001||||||20260326|||Dr. Sarah Kim\n" "OBR|1|ORD001||CBC^Complete Blood Count|||20260326\n" "OBR|2|ORD001||CMP^Comprehensive Metabolic Panel|||20260326\n" "OBR|3|ORD001||UA^Urinalysis with Culture|||20260326", language="text", ) else: st.warning("Sample file not found. Please upload a form instead.") else: admin_doc = st.file_uploader("Upload Form (Image/PDF)", type=["jpg", "jpeg", "png", "pdf"], key="ocr_upload") if admin_doc: if admin_doc.type and "image" in admin_doc.type: st.image(admin_doc, width=300, caption="Uploaded Form") else: st.info(f"Uploaded: {admin_doc.name}") if st.button("Digitize Form", type="primary", key="btn_ocr"): with st.spinner("OCR agent processing document..."): result = process_ocr_form(admin_doc) st.success( f"Form digitized successfully. Type: **{result['result']['form_type']}**. " f"Confidence: **{result['result'].get('confidence', 'N/A')}**. " f"Output format: HL7 {result['hl7_version']} / FHIR R4." ) with st.expander("Extracted Data"): st.json(result["result"]) # --- TAB: LAB INTELLIGENCE CHATBOT --- with tab_chat: st.subheader("Lab Intelligence Assistant") st.caption( "AI-powered lab Q&A. Ask about turnaround times, specimen tracking, " "critical values, infection surveillance, and diagnostic AI modules." ) render_chatbot(persona="lab_admin")