File size: 4,661 Bytes
048b72d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | """Reusable chatbot component for all personas.
Renders a styled chat interface with persona-specific context.
Uses st.session_state for message persistence within a session.
"""
import streamlit as st
from services.chat import get_chat_response, get_bot_name, get_greeting
def render_chatbot(
persona: str,
resident_name: str = "",
container_key: str = "",
):
"""Render a full chatbot UI for the given persona.
Args:
persona: One of 'caregiver', 'family', 'executive', 'lab_admin'.
resident_name: Optional resident name for family persona context.
container_key: Optional unique key suffix to prevent Streamlit widget conflicts.
"""
bot_name = get_bot_name(persona)
session_key = f"chat_{persona}_{container_key}" if container_key else f"chat_{persona}"
# ββ Header ββ
icon_map = {
"caregiver": "π©Ί",
"family": "π",
"executive": "π",
"lab_admin": "π¬",
}
icon = icon_map.get(persona, "π¬")
st.markdown(
f"""<div class="chat-header">
<span class="chat-header-icon">{icon}</span>
<span class="chat-header-title">{bot_name}</span>
<span class="chat-header-badge">AI-Powered</span>
</div>""",
unsafe_allow_html=True,
)
# ββ Initialize messages ββ
if session_key not in st.session_state:
greeting = get_greeting(persona, resident_name)
st.session_state[session_key] = [
{"role": "assistant", "content": greeting}
]
# ββ Render message history ββ
chat_container = st.container(height=420)
with chat_container:
for msg in st.session_state[session_key]:
with st.chat_message(
msg["role"],
avatar=icon if msg["role"] == "assistant" else None,
):
st.markdown(msg["content"])
# ββ Chat input ββ
family_label = f"Ask about {resident_name}'s care..." if resident_name else "Ask about your loved one's care..."
placeholder_map = {
"caregiver": "Ask about vitals, medications, fall risk, handoffs...",
"family": family_label,
"executive": "Ask about occupancy, costs, staffing, compliance...",
"lab_admin": "Ask about TAT, specimens, critical values, infections...",
}
placeholder = placeholder_map.get(persona, "Type your question...")
if prompt := st.chat_input(placeholder, key=f"input_{session_key}"):
# Add user message
st.session_state[session_key].append({"role": "user", "content": prompt})
# Get AI response
response = get_chat_response(prompt, persona=persona)
st.session_state[session_key].append({"role": "assistant", "content": response})
# Rerun to show new messages
st.rerun()
# ββ Quick suggestion chips ββ
suggestions_map = {
"caregiver": [
"Current vitals",
"Shift handoff",
"Fall risk",
"UTI alert status",
"Sleep analysis",
"Outstanding tasks",
],
"family": [
"How did they eat today?",
"How did they sleep?",
"How's their mood?",
"Visiting info",
"Medications",
],
"executive": [
"Occupancy trend",
"Financial impact",
"Staffing metrics",
"Fall prevention ROI",
"Compliance score",
"Family satisfaction",
],
"lab_admin": [
"TAT performance",
"Specimen report",
"Critical values",
"Infection rates",
"Wound AI status",
],
}
suggestions = suggestions_map.get(persona, [])
if suggestions:
st.markdown('<div class="suggestion-chips">', unsafe_allow_html=True)
cols = st.columns(len(suggestions))
for i, suggestion in enumerate(suggestions):
with cols[i]:
if st.button(
suggestion,
key=f"chip_{session_key}_{i}",
use_container_width=True,
):
st.session_state[session_key].append(
{"role": "user", "content": suggestion}
)
response = get_chat_response(suggestion, persona=persona)
st.session_state[session_key].append(
{"role": "assistant", "content": response}
)
st.rerun()
st.markdown("</div>", unsafe_allow_html=True)
|