mgbam commited on
Commit
b8aec8c
·
verified ·
1 Parent(s): 8d6f871

Update pages/3_Reports.py

Browse files
Files changed (1) hide show
  1. pages/3_Reports.py +69 -71
pages/3_Reports.py CHANGED
@@ -1,98 +1,103 @@
1
  # /home/user/app/pages/3_Reports.py
2
  import streamlit as st
3
  from datetime import datetime
4
- from typing import List
5
- from sqlmodel import select # For SQLModel queries
6
 
7
  from config.settings import settings
8
- from models import ChatMessage, ChatSession # User model not directly needed here if ID is sufficient
9
- from models.db import get_session_context # SQLModel session context
10
  from services.pdf_report import generate_pdf_report
11
  from services.logger import app_logger
12
- from services.metrics import log_report_generated # Assuming this function exists and is set up
13
-
14
- # --- Page Configuration (Typically set in main app.py) ---
15
- # st.set_page_config(page_title=f"Reports - {settings.APP_TITLE}", layout="wide")
16
 
17
  # --- Authentication Check ---
18
  if not st.session_state.get("authenticated_user_id"):
19
  st.warning("Please log in to access reports.")
20
  try:
21
- st.switch_page("app.py") # Redirect to the main login page
22
- except st.errors.StreamlitAPIException as e:
23
- # Handle cases where switch_page might not work (e.g., not in MPA mode during dev)
24
- app_logger.warning(f"Reports: Could not switch page (maybe not in MPA mode or other issue): {e}")
25
  st.info("Please navigate to the main login page manually.")
26
- st.stop() # Halt script execution for unauthenticated users
27
 
28
- # --- Get Authenticated User Info ---
29
  authenticated_user_id = st.session_state.get("authenticated_user_id")
30
- authenticated_username = st.session_state.get("authenticated_username", "User") # Default to "User"
31
  app_logger.info(f"User '{authenticated_username}' (ID: {authenticated_user_id}) accessed Reports page.")
32
 
33
- # --- Page Title and Description ---
34
  st.title("Consultation Reports")
35
  st.markdown("View and download your past consultation sessions.")
36
 
37
- # --- Helper Function to Load User's Chat Sessions ---
38
- # @st.cache_data(ttl=300) # Cache for 5 minutes. Invalidate if session titles change or new sessions added frequently.
39
- # For caching to work correctly, arguments to the cached function must be hashable. user_id (int) is.
40
- def get_user_chat_sessions(user_id: int) -> List[ChatSession]:
41
- """Fetches all chat sessions for a given user ID, ordered by start time descending."""
42
- app_logger.debug(f"Fetching chat sessions for user_id: {user_id}")
43
- sessions: List[ChatSession] = []
 
 
44
  try:
45
- with get_session_context() as db_session: # db_session is a SQLModel Session
46
- statement = select(ChatSession).where(ChatSession.user_id == user_id).order_by(ChatSession.start_time.desc())
47
- results = db_session.exec(statement)
48
- sessions = results.all()
49
- app_logger.debug(f"Found {len(sessions)} sessions for user_id: {user_id}")
 
 
 
 
 
 
 
 
 
50
  except Exception as e:
51
- app_logger.error(f"Error fetching chat sessions for user_id {user_id}: {e}", exc_info=True)
52
  st.error("Could not load your chat sessions. Please try again later.")
53
- return sessions
54
 
55
- # Fetch the chat sessions for the current authenticated user
56
- chat_sessions = get_user_chat_sessions(authenticated_user_id)
57
 
58
- # --- Display Logic ---
59
- if not chat_sessions:
60
  st.info("You have no past consultation sessions recorded.")
61
- st.stop() # No further processing if no sessions
62
 
 
63
  # Prepare options for the selectbox: (Display String, Session ID)
64
  session_options = []
65
- for s in chat_sessions:
66
- start_time_display = s.start_time.strftime('%Y-%m-%d %H:%M') if s.start_time else "Date N/A"
67
- # Use a more descriptive title if the session title is None
68
- title_display = s.title if s.title else f"Consultation on {start_time_display}"
69
- display_string = f"ID: {s.id} | Started: {start_time_display} | Title: {title_display}"
70
- session_options.append((display_string, s.id)) # Store (display_text, actual_id)
71
-
72
- # Let the user select a session
73
  selected_option_tuple = st.selectbox(
74
  "Select a Consultation Session:",
75
  options=session_options,
76
- format_func=lambda x: x[0], # Show only the display string in the selectbox
77
- index=0 # Default to the first (most recent) session
78
  )
79
 
80
  if selected_option_tuple:
81
- selected_session_id = selected_option_tuple[1] # Extract the session ID
82
  app_logger.info(f"User '{authenticated_username}' selected session ID: {selected_session_id} for report viewing.")
83
 
84
- # Find the full ChatSession object from the already fetched list
85
- selected_session_object = next((s for s in chat_sessions if s.id == selected_session_id), None)
86
 
87
- if selected_session_object:
88
- st.markdown("---") # Visual separator
89
- st.subheader(f"Details for Session ID: {selected_session_object.id}")
90
 
91
- start_time_detail = selected_session_object.start_time.strftime('%Y-%m-%d %H:%M:%S UTC') if selected_session_object.start_time else "Not recorded"
92
- st.write(f"**Started:** {start_time_detail}")
93
- st.write(f"**Title:** {selected_session_object.title or 'Untitled Session'}")
 
94
 
95
- # Fetch messages for the selected session
96
  messages_for_report: List[ChatMessage] = []
97
  try:
98
  with get_session_context() as db_session:
@@ -106,35 +111,30 @@ if selected_option_tuple:
106
  if messages_for_report:
107
  with st.expander("View Chat Transcript", expanded=False):
108
  for msg_idx, msg in enumerate(messages_for_report):
 
 
 
109
  icon = "🧑‍⚕️" if msg.role == "assistant" else "👤"
110
  if msg.role == "tool": icon = "🛠️"
111
  timestamp_display = msg.timestamp.strftime('%Y-%m-%d %H:%M:%S') if msg.timestamp else "Time N/A"
112
-
113
- # Displaying role and timestamp
114
  st.markdown(f"**{icon} {msg.role.capitalize()}** ({timestamp_display})")
115
- # Displaying content in a blockquote or code block for better readability
116
- st.markdown(f"> ```\n{msg.content}\n```") # Markdown code block
117
  if msg_idx < len(messages_for_report) - 1:
118
- st.markdown("---") # Separator between messages
119
 
120
- # PDF Download Button
121
- st.markdown("---") # Visual separator before download button
122
  try:
123
- # Use the authenticated username as the patient name for the report
124
  pdf_bytes = generate_pdf_report(messages_for_report, patient_name=authenticated_username)
125
-
126
  current_time_str = datetime.now().strftime('%Y%m%d_%H%M%S')
127
  pdf_file_name = f"Consultation_Report_Session{selected_session_id}_{current_time_str}.pdf"
128
-
129
  st.download_button(
130
  label="Download Report as PDF",
131
  data=pdf_bytes,
132
  file_name=pdf_file_name,
133
  mime="application/pdf",
134
- key=f"download_pdf_btn_{selected_session_id}", # Unique key for the button
135
  on_click=log_report_generated,
136
- # Pass necessary arguments to the on_click callback if it needs them
137
- args=(authenticated_user_id, selected_session_id), # Example arguments
138
  help="Click to download the consultation transcript as a PDF file."
139
  )
140
  except Exception as e:
@@ -143,9 +143,7 @@ if selected_option_tuple:
143
  else:
144
  st.info("This session has no messages recorded.")
145
  else:
146
- # This case should ideally not happen if selected_session_id comes from chat_sessions
147
- app_logger.error(f"Selected session ID {selected_session_id} not found in fetched sessions for user '{authenticated_username}'.")
148
  st.error("Selected session could not be found. Please try again.")
149
  else:
150
- # This case handles if session_options is empty, though the earlier check for `if not chat_sessions` should catch it.
151
  st.info("Please select a session from the dropdown menu to view details.")
 
1
  # /home/user/app/pages/3_Reports.py
2
  import streamlit as st
3
  from datetime import datetime
4
+ from typing import List, Dict, Any # For type hinting the dictionary
5
+ from sqlmodel import select
6
 
7
  from config.settings import settings
8
+ from models import ChatMessage, ChatSession # ChatSession model still needed for query
9
+ from models.db import get_session_context
10
  from services.pdf_report import generate_pdf_report
11
  from services.logger import app_logger
12
+ from services.metrics import log_report_generated
 
 
 
13
 
14
  # --- Authentication Check ---
15
  if not st.session_state.get("authenticated_user_id"):
16
  st.warning("Please log in to access reports.")
17
  try:
18
+ st.switch_page("app.py")
19
+ except st.errors.StreamlitAPIException:
 
 
20
  st.info("Please navigate to the main login page manually.")
21
+ st.stop()
22
 
 
23
  authenticated_user_id = st.session_state.get("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 Reports page.")
26
 
 
27
  st.title("Consultation Reports")
28
  st.markdown("View and download your past consultation sessions.")
29
 
30
+ # --- Helper Function to Load User's Chat Session Data (Primitives) ---
31
+ # @st.cache_data(ttl=300) # If caching, ensure it works well with this primitive data structure
32
+ def get_user_chat_session_display_data(user_id: int) -> List[Dict[str, Any]]:
33
+ """
34
+ Fetches essential data for chat sessions for display, not full ORM objects.
35
+ Returns a list of dictionaries.
36
+ """
37
+ app_logger.debug(f"Fetching chat session display data for user_id: {user_id}")
38
+ session_data_list: List[Dict[str, Any]] = []
39
  try:
40
+ with get_session_context() as db_session:
41
+ # Select specific columns needed for display
42
+ statement = select(ChatSession.id, ChatSession.title, ChatSession.start_time)\
43
+ .where(ChatSession.user_id == user_id)\
44
+ .order_by(ChatSession.start_time.desc())
45
+ results = db_session.exec(statement).all() # results will be list of Rows/Tuples
46
+
47
+ for row in results:
48
+ session_data_list.append({
49
+ "id": row.id,
50
+ "title": row.title,
51
+ "start_time": row.start_time # Store the datetime object, format it later
52
+ })
53
+ app_logger.debug(f"Found {len(session_data_list)} session display entries for user_id: {user_id}")
54
  except Exception as e:
55
+ app_logger.error(f"Error fetching chat session display data for user_id {user_id}: {e}", exc_info=True)
56
  st.error("Could not load your chat sessions. Please try again later.")
57
+ return session_data_list
58
 
59
+ # Fetch session display data for the current authenticated user
60
+ chat_session_display_items = get_user_chat_session_display_data(authenticated_user_id)
61
 
62
+ if not chat_session_display_items:
 
63
  st.info("You have no past consultation sessions recorded.")
64
+ st.stop()
65
 
66
+ # --- Display Sessions and Download Option ---
67
  # Prepare options for the selectbox: (Display String, Session ID)
68
  session_options = []
69
+ for s_data in chat_session_display_items:
70
+ # Access data from the dictionary
71
+ start_time_obj = s_data["start_time"]
72
+ start_time_display = start_time_obj.strftime('%Y-%m-%d %H:%M') if start_time_obj else "Date N/A"
73
+ title_display = s_data["title"] if s_data["title"] else f"Consultation on {start_time_display}"
74
+ display_string = f"ID: {s_data['id']} | Started: {start_time_display} | Title: {title_display}"
75
+ session_options.append((display_string, s_data['id']))
76
+
77
  selected_option_tuple = st.selectbox(
78
  "Select a Consultation Session:",
79
  options=session_options,
80
+ format_func=lambda x: x[0],
81
+ index=0
82
  )
83
 
84
  if selected_option_tuple:
85
+ selected_session_id = selected_option_tuple[1]
86
  app_logger.info(f"User '{authenticated_username}' selected session ID: {selected_session_id} for report viewing.")
87
 
88
+ # Find the selected session's data from the list of dictionaries
89
+ selected_session_data = next((s_data for s_data in chat_session_display_items if s_data['id'] == selected_session_id), None)
90
 
91
+ if selected_session_data:
92
+ st.markdown("---")
93
+ st.subheader(f"Details for Session ID: {selected_session_data['id']}")
94
 
95
+ start_time_obj_detail = selected_session_data["start_time"]
96
+ start_time_detail_display = start_time_obj_detail.strftime('%Y-%m-%d %H:%M:%S UTC') if start_time_obj_detail else "Not recorded"
97
+ st.write(f"**Started:** {start_time_detail_display}")
98
+ st.write(f"**Title:** {selected_session_data['title'] or 'Untitled Session'}")
99
 
100
+ # Fetch messages ONLY for the selected session when needed
101
  messages_for_report: List[ChatMessage] = []
102
  try:
103
  with get_session_context() as db_session:
 
111
  if messages_for_report:
112
  with st.expander("View Chat Transcript", expanded=False):
113
  for msg_idx, msg in enumerate(messages_for_report):
114
+ # Accessing msg.role, msg.timestamp, msg.content should be fine here
115
+ # as `messages_for_report` are newly fetched ORM objects within an active (though soon to close) session.
116
+ # The key is that their attributes are accessed while their session is implicitly active or just before it closes.
117
  icon = "🧑‍⚕️" if msg.role == "assistant" else "👤"
118
  if msg.role == "tool": icon = "🛠️"
119
  timestamp_display = msg.timestamp.strftime('%Y-%m-%d %H:%M:%S') if msg.timestamp else "Time N/A"
 
 
120
  st.markdown(f"**{icon} {msg.role.capitalize()}** ({timestamp_display})")
121
+ st.markdown(f"> ```\n{msg.content}\n```")
 
122
  if msg_idx < len(messages_for_report) - 1:
123
+ st.markdown("---")
124
 
125
+ st.markdown("---")
 
126
  try:
 
127
  pdf_bytes = generate_pdf_report(messages_for_report, patient_name=authenticated_username)
 
128
  current_time_str = datetime.now().strftime('%Y%m%d_%H%M%S')
129
  pdf_file_name = f"Consultation_Report_Session{selected_session_id}_{current_time_str}.pdf"
 
130
  st.download_button(
131
  label="Download Report as PDF",
132
  data=pdf_bytes,
133
  file_name=pdf_file_name,
134
  mime="application/pdf",
135
+ key=f"download_pdf_btn_{selected_session_id}",
136
  on_click=log_report_generated,
137
+ args=(authenticated_user_id, selected_session_id),
 
138
  help="Click to download the consultation transcript as a PDF file."
139
  )
140
  except Exception as e:
 
143
  else:
144
  st.info("This session has no messages recorded.")
145
  else:
146
+ app_logger.error(f"Selected session ID {selected_session_id} not found in fetched display data for user '{authenticated_username}'.")
 
147
  st.error("Selected session could not be found. Please try again.")
148
  else:
 
149
  st.info("Please select a session from the dropdown menu to view details.")