Update pages/3_Reports.py
Browse files- 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
|
6 |
|
7 |
from config.settings import settings
|
8 |
-
from models import ChatMessage, ChatSession #
|
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 |
-
# --- 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")
|
22 |
-
except st.errors.StreamlitAPIException
|
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()
|
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")
|
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
|
38 |
-
# @st.cache_data(ttl=300) #
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
|
|
|
|
44 |
try:
|
45 |
-
with get_session_context() as db_session:
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
except Exception as e:
|
51 |
-
app_logger.error(f"Error fetching chat
|
52 |
st.error("Could not load your chat sessions. Please try again later.")
|
53 |
-
return
|
54 |
|
55 |
-
# Fetch
|
56 |
-
|
57 |
|
58 |
-
|
59 |
-
if not chat_sessions:
|
60 |
st.info("You have no past consultation sessions recorded.")
|
61 |
-
st.stop()
|
62 |
|
|
|
63 |
# Prepare options for the selectbox: (Display String, Session ID)
|
64 |
session_options = []
|
65 |
-
for
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
selected_option_tuple = st.selectbox(
|
74 |
"Select a Consultation Session:",
|
75 |
options=session_options,
|
76 |
-
format_func=lambda x: x[0],
|
77 |
-
index=0
|
78 |
)
|
79 |
|
80 |
if selected_option_tuple:
|
81 |
-
selected_session_id = selected_option_tuple[1]
|
82 |
app_logger.info(f"User '{authenticated_username}' selected session ID: {selected_session_id} for report viewing.")
|
83 |
|
84 |
-
# Find the
|
85 |
-
|
86 |
|
87 |
-
if
|
88 |
-
st.markdown("---")
|
89 |
-
st.subheader(f"Details for Session ID: {
|
90 |
|
91 |
-
|
92 |
-
|
93 |
-
st.write(f"**
|
|
|
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 |
-
|
116 |
-
st.markdown(f"> ```\n{msg.content}\n```") # Markdown code block
|
117 |
if msg_idx < len(messages_for_report) - 1:
|
118 |
-
st.markdown("---")
|
119 |
|
120 |
-
|
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}",
|
135 |
on_click=log_report_generated,
|
136 |
-
|
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 |
-
|
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.")
|