mgbam commited on
Commit
743ac85
Β·
verified Β·
1 Parent(s): 29659ac

Update pages/2_Consult.py

Browse files
Files changed (1) hide show
  1. pages/2_Consult.py +128 -128
pages/2_Consult.py CHANGED
@@ -1,12 +1,11 @@
1
- # /home/user/app/pages/2_Consult.py
2
  import streamlit as st
3
- from langchain_core.messages import HumanMessage, AIMessage, SystemMessage # Ensure all are imported
4
  from datetime import datetime
5
- from typing import List, Optional, Dict, Any
6
  from sqlmodel import select
7
 
8
  from config.settings import settings
9
- from agent import get_agent_executor # This now returns the Gemini-based agent
10
  from models import ChatMessage, ChatSession
11
  from models.db import get_session_context
12
  from services.logger import app_logger
@@ -21,181 +20,182 @@ if not st.session_state.get("authenticated_user_id"):
21
  st.info("Please navigate to the main login page.")
22
  st.stop()
23
 
24
- authenticated_user_id = st.session_state.get("authenticated_user_id")
25
  authenticated_username = st.session_state.get("authenticated_username", "User")
26
  app_logger.info(f"User '{authenticated_username}' (ID: {authenticated_user_id}) accessed Consult page.")
27
 
28
  # --- Initialize Agent ---
29
  try:
30
- agent_executor = get_agent_executor() # Gets the Gemini agent executor
31
  app_logger.info("Gemini-based agent executor initialized for Consult page.")
32
  except ValueError as e:
33
  st.error(f"AI Agent Initialization Error: {e}")
34
- app_logger.critical(f"Fatal: AI Agent could not be initialized in Consult page: {e}", exc_info=True)
35
  st.info("Please ensure API keys (e.g., Google API Key for Gemini) are configured.")
36
  st.stop()
37
- except Exception as e: # Catch any other unexpected error during agent init
38
- st.error(f"An unexpected error occurred while initializing the AI Agent: {e}")
39
  app_logger.critical(f"Fatal: Unexpected AI Agent initialization error: {e}", exc_info=True)
40
  st.stop()
41
 
42
- # --- Session State for Consult Page ---
43
- if 'current_consult_patient_context_dict' not in st.session_state: # Renamed for clarity
44
  st.session_state.current_consult_patient_context_dict = {}
45
  if 'consult_context_submitted' not in st.session_state:
46
  st.session_state.consult_context_submitted = False
47
 
48
- # --- Helper Functions ---
49
  @st.cache_data(ttl=30, show_spinner=False)
50
- def load_chat_history_for_agent(session_id: int) -> List:
51
- messages = []
52
- app_logger.debug(f"Loading agent chat history for session_id: {session_id}")
53
  with get_session_context() as db:
54
  statement = select(ChatMessage).where(ChatMessage.session_id == session_id).order_by(ChatMessage.timestamp)
55
- db_messages = db.exec(statement).all()
56
- for msg in db_messages:
57
- if msg.role == "user": messages.append(HumanMessage(content=msg.content))
58
- elif msg.role == "assistant": messages.append(AIMessage(content=msg.content))
59
- elif msg.role == "system": messages.append(SystemMessage(content=msg.content))
60
- app_logger.debug(f"Loaded {len(messages)} LangChain messages for agent history (session {session_id}).")
 
 
61
  return messages
62
 
63
- def save_chat_message_to_db(session_id: int, role: str, content: str, tool_call_id: Optional[str]=None, tool_name: Optional[str]=None):
 
 
 
 
 
 
 
64
  app_logger.debug(f"Saving message to DB for session {session_id}: Role={role}")
65
  with get_session_context() as db:
66
- chat_message_obj = ChatMessage(
67
- session_id=session_id, role=role, content=content, timestamp=datetime.utcnow(),
68
- tool_call_id=tool_call_id, tool_name=tool_name
 
 
 
 
69
  )
70
- db.add(chat_message_obj)
71
  app_logger.info(f"Message saved to DB for session {session_id}. Role: {role}.")
72
 
73
- def update_chat_session_with_context_summary_in_db(session_id: int, context_summary: str):
 
74
  with get_session_context() as db:
75
- session_to_update = db.get(ChatSession, session_id)
76
- if session_to_update:
77
- session_to_update.patient_context_summary = context_summary
78
- db.add(session_to_update)
79
- app_logger.info(f"Updated ChatSession {session_id} with patient context summary in DB.")
80
  else:
81
- app_logger.error(f"Could not find ChatSession {session_id} to update context summary.")
82
 
83
- # --- Page Logic ---
84
  st.title("AI Consultation Room")
85
  st.markdown(f"Interacting as: **{authenticated_username}**")
86
- st.info(f"{settings.MAIN_DISCLAIMER_SHORT} Remember to use only anonymized, simulated data for this demonstration.")
87
 
 
88
  chat_session_id = st.session_state.get("current_chat_session_id")
89
  if not chat_session_id:
90
- st.error("No active chat session ID found. Please try logging out and back in.")
91
- app_logger.error(f"User '{authenticated_username}' on Consult page with NO current_chat_session_id.")
92
  st.stop()
93
 
94
- # --- Patient Context Input Form ---
95
  if not st.session_state.consult_context_submitted:
96
- st.subheader("Step 1: Provide Patient Context (Optional, Simulated Data Only)")
97
- with st.form(key="patient_context_form_consult_page"):
98
- st.markdown("**Reminder: Use only anonymized, simulated data for this demonstration.**")
99
- age_in = st.number_input("Patient Age (Simulated)", min_value=0, max_value=120, step=1, value=None)
100
- gender_in = st.selectbox("Patient Gender (Simulated)", ["Not Specified", "Male", "Female", "Other"], index=0)
101
- cc_in = st.text_area("Chief Complaint / Reason for Consult (Simulated)", height=100, placeholder="e.g., Persistent cough")
102
- hist_in = st.text_area("Key Medical History (Simulated)", height=100, placeholder="e.g., Type 2 Diabetes")
103
- meds_in = st.text_area("Current Medications (Simulated)", height=100, placeholder="e.g., Metformin")
104
- submit_context_btn = st.form_submit_button("Start Consult with this Context")
105
-
106
- if submit_context_btn:
107
- raw_context = {
108
- "age": age_in, "gender": gender_in, "chief_complaint": cc_in,
109
- "key_medical_history": hist_in, "current_medications": meds_in,
110
- }
111
- # Filter out None/empty/"Not Specified" values for cleaner context dictionary
112
- filtered_context_dict = {
113
- k.replace('_', ' ').title(): v for k, v in raw_context.items()
114
- if v is not None and str(v).strip() and str(v) != "Not Specified" and (isinstance(v, int) and v > 0 or isinstance(v, str)) # ensure age is >0
115
- }
116
- st.session_state.current_consult_patient_context_dict = filtered_context_dict
117
-
118
- if filtered_context_dict:
119
- context_summary_str = "; ".join([f"{k}: {v}" for k, v in filtered_context_dict.items()])
120
- else:
121
- context_summary_str = "No specific patient context was provided for this session."
122
-
123
- update_chat_session_with_context_summary_in_db(chat_session_id, context_summary_str)
124
- save_chat_message_to_db(chat_session_id, "system", f"Initial Patient Context Provided: {context_summary_str}")
125
-
126
- st.session_state.consult_context_submitted = True
127
- app_logger.info(f"Patient context submitted for session {chat_session_id}: {context_summary_str}")
128
- st.rerun()
129
  st.stop()
130
 
131
- # --- Chat Interface ---
132
  st.subheader("Step 2: Interact with AI Health Navigator")
133
- agent_history_key = f"agent_chat_history_{chat_session_id}"
134
-
135
- if agent_history_key not in st.session_state:
136
- st.session_state[agent_history_key] = load_chat_history_for_agent(chat_session_id)
137
- if not st.session_state[agent_history_key]: # If history is empty after loading
138
- try: log_consultation_start(user_id=authenticated_user_id, session_id=chat_session_id)
139
- except Exception as e_metric: app_logger.warning(f"Failed to log consultation start metric: {e_metric}")
140
-
141
- initial_ai_msg = "Hello! I am your AI Health Navigator. How can I assist you today?"
142
- if st.session_state.get('current_consult_patient_context_dict'): # Check the renamed key
143
- initial_ai_msg += " I have noted the patient context you provided."
144
-
145
- st.session_state[agent_history_key].append(AIMessage(content=initial_ai_msg))
146
- save_chat_message_to_db(chat_session_id, "assistant", initial_ai_msg)
147
-
148
- # Display chat messages from DB for UI
149
- with st.container(height=400): # Fixed height container for chat, makes it scrollable
150
  with get_session_context() as db:
151
  stmt = select(ChatMessage).where(ChatMessage.session_id == chat_session_id).order_by(ChatMessage.timestamp)
152
- ui_messages = db.exec(stmt).all()
153
- for msg in ui_messages:
154
- if msg.role == "system": continue
155
  avatar = "πŸ§‘β€βš•οΈ" if msg.role == "assistant" else "πŸ‘€"
156
- if msg.role == "tool": avatar = "πŸ› οΈ"
 
157
  with st.chat_message(msg.role, avatar=avatar):
158
  st.markdown(msg.content)
159
 
160
- # Chat input
161
- if user_prompt := st.chat_input("Ask the AI... (e.g., 'What is hypertension?')"):
162
- with st.chat_message("user", avatar="πŸ‘€"): st.markdown(user_prompt)
163
- save_chat_message_to_db(chat_session_id, "user", user_prompt)
164
- st.session_state[agent_history_key].append(HumanMessage(content=user_prompt))
 
165
 
166
  with st.chat_message("assistant", avatar="πŸ§‘β€βš•οΈ"):
167
  with st.spinner("AI is thinking..."):
168
  try:
169
- # Prepare patient context string for the agent
170
- patient_context_dict = st.session_state.get('current_consult_patient_context_dict', {})
171
- if patient_context_dict:
172
- context_parts_for_invoke = [f"{k}: {v}" for k, v in patient_context_dict.items()]
173
- patient_context_str_for_invoke = "; ".join(context_parts_for_invoke)
174
  else:
175
- patient_context_str_for_invoke = "No specific patient context was provided for this interaction."
176
 
177
- invoke_payload = {
178
- "input": user_prompt,
179
- "chat_history": st.session_state[agent_history_key], # List of BaseMessage
180
- "patient_context": patient_context_str_for_invoke
181
  }
182
- app_logger.debug(f"Invoking agent with payload: {invoke_payload}")
183
- response = agent_executor.invoke(invoke_payload)
184
-
185
- ai_response_content = response.get('output', "I could not generate a valid response at this time.")
186
- if not isinstance(ai_response_content, str): ai_response_content = str(ai_response_content)
187
-
188
- app_logger.info(f"Agent response for session {chat_session_id}: '{ai_response_content[:100]}...'")
189
- st.markdown(ai_response_content)
190
- save_chat_message_to_db(chat_session_id, "assistant", ai_response_content)
191
- st.session_state[agent_history_key].append(AIMessage(content=ai_response_content))
192
-
193
- except Exception as e:
194
- app_logger.error(f"Error during agent invocation for session {chat_session_id}: {e}", exc_info=True)
195
- error_type_name = type(e).__name__
196
- user_friendly_error = f"Sorry, an error occurred ({error_type_name}). Please try rephrasing your query or contact support if the issue persists."
197
- st.error(user_friendly_error)
198
- db_error_msg = f"System encountered an error: {error_type_name}. Details logged."
199
- save_chat_message_to_db(chat_session_id, "assistant", db_error_msg)
200
- st.session_state[agent_history_key].append(AIMessage(content=f"Note: Encountered error ({error_type_name})."))
201
- st.rerun() # Rerun to display the new messages immediately
 
 
1
  import streamlit as st
2
+ from langchain.schema import HumanMessage, AIMessage, SystemMessage
3
  from datetime import datetime
4
+ from typing import List, Union, Optional, Dict, Any
5
  from sqlmodel import select
6
 
7
  from config.settings import settings
8
+ from agent import get_agent_executor # Returns the configured Gemini-based agent executor
9
  from models import ChatMessage, ChatSession
10
  from models.db import get_session_context
11
  from services.logger import app_logger
 
20
  st.info("Please navigate to the main login page.")
21
  st.stop()
22
 
23
+ authenticated_user_id = st.session_state["authenticated_user_id"]
24
  authenticated_username = st.session_state.get("authenticated_username", "User")
25
  app_logger.info(f"User '{authenticated_username}' (ID: {authenticated_user_id}) accessed Consult page.")
26
 
27
  # --- Initialize Agent ---
28
  try:
29
+ agent_executor = get_agent_executor()
30
  app_logger.info("Gemini-based agent executor initialized for Consult page.")
31
  except ValueError as e:
32
  st.error(f"AI Agent Initialization Error: {e}")
33
+ app_logger.critical(f"Fatal: AI Agent could not be initialized: {e}", exc_info=True)
34
  st.info("Please ensure API keys (e.g., Google API Key for Gemini) are configured.")
35
  st.stop()
36
+ except Exception as e:
37
+ st.error(f"Unexpected error initializing AI Agent: {e}")
38
  app_logger.critical(f"Fatal: Unexpected AI Agent initialization error: {e}", exc_info=True)
39
  st.stop()
40
 
41
+ # --- Session State Setup ---
42
+ if 'current_consult_patient_context_dict' not in st.session_state:
43
  st.session_state.current_consult_patient_context_dict = {}
44
  if 'consult_context_submitted' not in st.session_state:
45
  st.session_state.consult_context_submitted = False
46
 
47
+ # --- Caching helper to load history ---
48
  @st.cache_data(ttl=30, show_spinner=False)
49
+ def load_chat_history_for_agent(session_id: int) -> List[Union[HumanMessage, AIMessage, SystemMessage]]:
50
+ messages: List[Union[HumanMessage, AIMessage, SystemMessage]] = []
51
+ app_logger.debug(f"Loading agent chat history for session {session_id}")
52
  with get_session_context() as db:
53
  statement = select(ChatMessage).where(ChatMessage.session_id == session_id).order_by(ChatMessage.timestamp)
54
+ for msg in db.exec(statement).all():
55
+ if msg.role == "user":
56
+ messages.append(HumanMessage(content=msg.content))
57
+ elif msg.role == "assistant":
58
+ messages.append(AIMessage(content=msg.content))
59
+ elif msg.role == "system":
60
+ messages.append(SystemMessage(content=msg.content))
61
+ app_logger.debug(f"Loaded {len(messages)} messages for session {session_id}")
62
  return messages
63
 
64
+ # --- Database write helpers ---
65
+ def save_chat_message_to_db(
66
+ session_id: int,
67
+ role: str,
68
+ content: str,
69
+ tool_call_id: Optional[str] = None,
70
+ tool_name: Optional[str] = None,
71
+ ):
72
  app_logger.debug(f"Saving message to DB for session {session_id}: Role={role}")
73
  with get_session_context() as db:
74
+ obj = ChatMessage(
75
+ session_id=session_id,
76
+ role=role,
77
+ content=content,
78
+ timestamp=datetime.utcnow(),
79
+ tool_call_id=tool_call_id,
80
+ tool_name=tool_name,
81
  )
82
+ db.add(obj)
83
  app_logger.info(f"Message saved to DB for session {session_id}. Role: {role}.")
84
 
85
+
86
+ def update_chat_session_with_context_summary_in_db(session_id: int, summary: str):
87
  with get_session_context() as db:
88
+ session = db.get(ChatSession, session_id)
89
+ if session:
90
+ session.patient_context_summary = summary
91
+ db.add(session)
92
+ app_logger.info(f"Updated ChatSession {session_id} with context summary.")
93
  else:
94
+ app_logger.error(f"ChatSession {session_id} not found for updating context.")
95
 
96
+ # --- Page Title & Disclaimer ---
97
  st.title("AI Consultation Room")
98
  st.markdown(f"Interacting as: **{authenticated_username}**")
99
+ st.info(f"{settings.MAIN_DISCLAIMER_SHORT} Remember to use only anonymized, simulated data.")
100
 
101
+ # --- Retrieve or Create Chat Session ---
102
  chat_session_id = st.session_state.get("current_chat_session_id")
103
  if not chat_session_id:
104
+ st.error("No active chat session found. Please logout and login again.")
105
+ app_logger.error("No current_chat_session_id in session_state.")
106
  st.stop()
107
 
108
+ # --- Patient Context Form ---
109
  if not st.session_state.consult_context_submitted:
110
+ st.subheader("Step 1: Provide Patient Context (Optional)")
111
+ with st.form("patient_context_form"):
112
+ age = st.number_input("Patient Age (Simulated)", min_value=0, max_value=120, step=1)
113
+ gender = st.selectbox("Patient Gender (Simulated)", ["Not Specified", "Male", "Female", "Other"], index=0)
114
+ complaint = st.text_area("Chief Complaint", height=80, placeholder="e.g., Persistent cough")
115
+ history = st.text_area("Key Medical History", height=80, placeholder="e.g., Type 2 Diabetes")
116
+ meds = st.text_area("Current Medications", height=80, placeholder="e.g., Metformin")
117
+ submit = st.form_submit_button("Start Consult")
118
+
119
+ if submit:
120
+ raw = {"age": age, "gender": gender, "complaint": complaint, "history": history, "meds": meds}
121
+ filtered = {k.title(): v for k, v in raw.items() if v and not (isinstance(v, str) and v == "Not Specified")}
122
+ st.session_state.current_consult_patient_context_dict = filtered
123
+
124
+ summary = (
125
+ "; ".join(f"{k}: {v}" for k, v in filtered.items())
126
+ if filtered else
127
+ "No specific patient context provided."
128
+ )
129
+ update_chat_session_with_context_summary_in_db(chat_session_id, summary)
130
+ save_chat_message_to_db(chat_session_id, "system", f"Context: {summary}")
131
+ st.session_state.consult_context_submitted = True
132
+ app_logger.info(f"Patient context for session {chat_session_id}: {summary}")
133
+ st.rerun()
 
 
 
 
 
 
 
 
 
134
  st.stop()
135
 
136
+ # --- Chat Interaction ---
137
  st.subheader("Step 2: Interact with AI Health Navigator")
138
+ history_key = f"agent_history_{chat_session_id}"
139
+ if history_key not in st.session_state:
140
+ st.session_state[history_key] = load_chat_history_for_agent(chat_session_id)
141
+ if not st.session_state[history_key]:
142
+ try:
143
+ log_consultation_start(authenticated_user_id, chat_session_id)
144
+ except Exception as e:
145
+ app_logger.warning(f"Metrics log failed: {e}")
146
+ greeting = "Hello! I am your AI Health Navigator. How can I help today?"
147
+ if st.session_state.current_consult_patient_context_dict:
148
+ greeting += " I have noted the patient context provided."
149
+ st.session_state[history_key].append(AIMessage(content=greeting))
150
+ save_chat_message_to_db(chat_session_id, "assistant", greeting)
151
+
152
+ # Display past messages
153
+ with st.container(height=400):
 
154
  with get_session_context() as db:
155
  stmt = select(ChatMessage).where(ChatMessage.session_id == chat_session_id).order_by(ChatMessage.timestamp)
156
+ for msg in db.exec(stmt).all():
157
+ if msg.role == "system":
158
+ continue
159
  avatar = "πŸ§‘β€βš•οΈ" if msg.role == "assistant" else "πŸ‘€"
160
+ if msg.role == "tool":
161
+ avatar = "πŸ› οΈ"
162
  with st.chat_message(msg.role, avatar=avatar):
163
  st.markdown(msg.content)
164
 
165
+ # Capture user input and invoke agent
166
+ if prompt := st.chat_input("Ask the AI... (e.g., 'What is hypertension?')"):
167
+ with st.chat_message("user", avatar="πŸ‘€"):
168
+ st.markdown(prompt)
169
+ save_chat_message_to_db(chat_session_id, "user", prompt)
170
+ st.session_state[history_key].append(HumanMessage(content=prompt))
171
 
172
  with st.chat_message("assistant", avatar="πŸ§‘β€βš•οΈ"):
173
  with st.spinner("AI is thinking..."):
174
  try:
175
+ pctxt = st.session_state.current_consult_patient_context_dict
176
+ if pctxt:
177
+ pc_str = "; ".join(f"{k}: {v}" for k, v in pctxt.items())
 
 
178
  else:
179
+ pc_str = "No specific patient context provided."
180
 
181
+ payload = {
182
+ "input": prompt,
183
+ "chat_history": st.session_state[history_key],
184
+ "patient_context": pc_str,
185
  }
186
+ app_logger.debug(f"Invoking agent with payload: {payload}")
187
+ resp = agent_executor.invoke(payload)
188
+ content = resp.get("output", "I could not generate a response.")
189
+ content = str(content)
190
+
191
+ app_logger.info(f"Agent response session {chat_session_id}: {content[:100]}")
192
+ st.markdown(content)
193
+ save_chat_message_to_db(chat_session_id, "assistant", content)
194
+ st.session_state[history_key].append(AIMessage(content=content))
195
+ except Exception as err:
196
+ app_logger.error(f"Error during agent invocation for session {chat_session_id}: {err}", exc_info=True)
197
+ st.error(f"Sorry, an error occurred: {type(err).__name__}. Please try again.")
198
+ err_msg = f"System encountered an error: {type(err).__name__}."
199
+ save_chat_message_to_db(chat_session_id, "assistant", err_msg)
200
+ st.session_state[history_key].append(AIMessage(content=err_msg))
201
+ st.rerun()