mgbam commited on
Commit
310dade
·
verified ·
1 Parent(s): 41dbcc2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -61
app.py CHANGED
@@ -1,14 +1,22 @@
 
1
  import streamlit as st
2
  from pathlib import Path
3
- from sqlalchemy.orm.exc import DetachedInstanceError as SQLAlchemyDetachedInstanceError # For specific error catching if needed
4
 
5
  from config.settings import settings
6
- from models import create_db_and_tables, get_session_context, User, ChatMessage, ChatSession
 
 
 
 
 
 
7
  from models.user import UserCreate
8
  from services.auth import create_user_in_db, authenticate_user
9
  from services.logger import app_logger
 
10
 
11
- # --- Page Configuration ---
12
  st.set_page_config(
13
  page_title=settings.APP_TITLE,
14
  page_icon="⚕️",
@@ -16,16 +24,15 @@ st.set_page_config(
16
  initial_sidebar_state="expanded"
17
  )
18
 
19
- # --- Database Initialization ---
20
  @st.cache_resource
21
  def init_db():
22
  app_logger.info("Initializing database and tables...")
23
- create_db_and_tables()
24
  app_logger.info("Database initialized.")
25
-
26
  init_db()
27
 
28
- # --- Session State Initialization (Using new keys) ---
29
  if 'authenticated_user_id' not in st.session_state:
30
  st.session_state.authenticated_user_id = None
31
  if 'authenticated_username' not in st.session_state:
@@ -35,6 +42,7 @@ if 'current_chat_session_id' not in st.session_state:
35
  if 'chat_messages' not in st.session_state:
36
  st.session_state.chat_messages = []
37
 
 
38
  # --- Authentication Logic ---
39
  def display_login_form():
40
  with st.form("login_form"):
@@ -44,61 +52,61 @@ def display_login_form():
44
  submit_button = st.form_submit_button("Login")
45
 
46
  if submit_button:
47
- # authenticate_user should ideally return a User object with at least ID loaded,
48
- # or be robust enough that its session handling doesn't cause immediate detachment issues
49
- # if we were to access its attributes directly (though we now avoid that for long-term storage).
50
  user_object_from_auth = authenticate_user(username_input, password_input)
51
 
52
  if user_object_from_auth:
53
- st.success(f"Welcome back, {username_input}!") # Use form input for immediate message
54
  app_logger.info(f"User {username_input} authenticated successfully.")
55
 
56
  try:
57
- with get_session_context() as db_session:
58
- # Fetch the "live" user to get definite ID and current username,
59
- # and to ensure it's attached to *this* session for creating the chat session.
60
- # The primary fix for 'authenticate_user' is still for it to return a usable object,
61
- # but re-fetching here ensures data for st.session_state is from a controlled point.
62
- live_user = db_session.query(User).filter(User.username == username_input).first()
63
 
64
  if not live_user:
65
  st.error("Authentication inconsistency. User details not found after login. Please contact support.")
66
  app_logger.error(f"CRITICAL: User '{username_input}' authenticated but then not found in DB by username.")
67
- # Clear any potentially partially set auth state from previous attempts
68
  st.session_state.authenticated_user_id = None
69
  st.session_state.authenticated_username = None
70
  st.rerun()
71
  return
72
 
73
- # IMPORTANT: Store primitive data in st.session_state
74
- # Do this *before* the commit for new_chat_session, as commit might expire 'live_user' attributes.
75
  st.session_state.authenticated_user_id = live_user.id
76
- st.session_state.authenticated_username = live_user.username # Username from DB
77
  app_logger.info(f"Stored user ID {live_user.id} and username '{live_user.username}' in session state.")
78
 
79
- # Now create the chat session using the live_user's ID
80
- new_chat_session = ChatSession(user_id=live_user.id, title=f"Session for {live_user.username}")
81
  db_session.add(new_chat_session)
82
- db_session.commit() # This commit is for new_chat_session
83
- # After commit, live_user attributes might be expired if expire_on_commit=True.
84
- # But we've already stored the primitives we need.
85
- db_session.refresh(new_chat_session) # Get ID for new_chat_session
86
  st.session_state.current_chat_session_id = new_chat_session.id
87
  st.session_state.chat_messages = []
88
  app_logger.info(f"New chat session (ID: {new_chat_session.id}) created for user {live_user.username}.")
89
-
90
- st.rerun() # Rerun to reflect login state and navigate
91
 
92
  except Exception as e:
93
  app_logger.error(f"Error during post-login session setup for user {username_input}: {e}", exc_info=True)
94
  st.error(f"Could not complete login process: {e}")
95
- # Clear auth state on error
96
  st.session_state.authenticated_user_id = None
97
  st.session_state.authenticated_username = None
98
  else:
99
  st.error("Invalid username or password.")
100
  app_logger.warning(f"Failed login attempt for username: {username_input}")
101
 
 
 
 
 
 
 
 
 
 
 
 
102
  def display_signup_form():
103
  with st.form("signup_form"):
104
  st.subheader("Sign Up")
@@ -111,6 +119,8 @@ def display_signup_form():
111
  if submit_button:
112
  if not new_username or not new_password:
113
  st.error("Username and password are required.")
 
 
114
  elif new_password != confirm_password:
115
  st.error("Passwords do not match.")
116
  else:
@@ -119,61 +129,44 @@ def display_signup_form():
119
  password=new_password,
120
  email=new_email if new_email else None
121
  )
122
- user = create_user_in_db(user_data) # Should handle its own session and return User or None
123
  if user:
124
- st.success(f"Account created for {new_username}. Please log in.") # Use form input
125
  app_logger.info(f"Account created for {new_username}.")
126
  else:
127
  st.error("Username might already be taken or another error occurred during signup.")
128
  app_logger.warning(f"Signup failed for username: {new_username}")
129
 
130
- # --- Main App Logic (Checks for authenticated_user_id) ---
131
- if not st.session_state.get("authenticated_user_id"): # Check if user_id is set
132
  st.title(f"Welcome to {settings.APP_TITLE}")
133
  st.markdown("Your AI-powered partner for advanced healthcare insights.")
134
-
135
  login_tab, signup_tab = st.tabs(["Login", "Sign Up"])
136
  with login_tab:
137
  display_login_form()
138
  with signup_tab:
139
  display_signup_form()
140
  else:
141
- # User is authenticated (authenticated_user_id is present)
142
  with st.sidebar:
143
- # Use the stored primitive username
144
- username_for_display = st.session_state.get("authenticated_username", "User")
145
- st.markdown(f"### Welcome, {username_for_display}!")
146
-
147
- logo_path_str = getattr(settings, "LOGO_PATH", None)
148
- if logo_path_str:
149
- logo_path = Path(logo_path_str)
150
- if logo_path.exists():
151
  try:
152
- st.image(str(logo_path), width=100)
153
  except Exception as e:
154
- app_logger.warning(f"Could not load logo from {logo_path_str}: {e}")
155
- else:
156
- app_logger.warning(f"Logo path specified but does not exist: {logo_path_str}")
157
  elif settings.APP_TITLE:
158
- st.markdown(f"#### {settings.APP_TITLE}")
159
-
160
- st.markdown("---")
161
-
162
- if st.button("Logout"):
163
  logged_out_username = st.session_state.get("authenticated_username", "UnknownUser")
164
  app_logger.info(f"User {logged_out_username} logging out.")
165
- # Clear authentication state
166
  st.session_state.authenticated_user_id = None
167
  st.session_state.authenticated_username = None
168
  st.session_state.current_chat_session_id = None
169
  st.session_state.chat_messages = []
170
  st.success("You have been logged out.")
171
  st.rerun()
172
-
173
- st.sidebar.success("Select a page from the navigation.")
174
- st.header(f"Dashboard - {settings.APP_TITLE}")
175
- st.markdown("Navigate using the sidebar to consult with the AI or view your reports.")
176
- st.markdown("---")
177
- st.info("This is the main application area. If you have pages in a `pages/` directory, Streamlit will show the selected page here. Otherwise, this content is shown.")
178
-
179
  app_logger.info(f"Streamlit app '{settings.APP_TITLE}' initialized and running.")
 
1
+ # /home/user/app/app.py
2
  import streamlit as st
3
  from pathlib import Path
4
+ from sqlmodel import select # <--- IMPORT SELECT FOR SQLMODEL QUERIES
5
 
6
  from config.settings import settings
7
+ from models import (
8
+ create_db_and_tables,
9
+ get_session_context, # Your SQLModel session context manager
10
+ User,
11
+ ChatMessage,
12
+ ChatSession
13
+ )
14
  from models.user import UserCreate
15
  from services.auth import create_user_in_db, authenticate_user
16
  from services.logger import app_logger
17
+ from assets.logo import get_logo_path
18
 
19
+ # --- Page Configuration --- (Assuming this is already correct)
20
  st.set_page_config(
21
  page_title=settings.APP_TITLE,
22
  page_icon="⚕️",
 
24
  initial_sidebar_state="expanded"
25
  )
26
 
27
+ # --- Database Initialization --- (Assuming this is already correct)
28
  @st.cache_resource
29
  def init_db():
30
  app_logger.info("Initializing database and tables...")
31
+ create_db_and_tables() # This uses SQLModel.metadata.create_all(engine)
32
  app_logger.info("Database initialized.")
 
33
  init_db()
34
 
35
+ # --- Session State Initialization --- (Assuming this is already correct)
36
  if 'authenticated_user_id' not in st.session_state:
37
  st.session_state.authenticated_user_id = None
38
  if 'authenticated_username' not in st.session_state:
 
42
  if 'chat_messages' not in st.session_state:
43
  st.session_state.chat_messages = []
44
 
45
+
46
  # --- Authentication Logic ---
47
  def display_login_form():
48
  with st.form("login_form"):
 
52
  submit_button = st.form_submit_button("Login")
53
 
54
  if submit_button:
 
 
 
55
  user_object_from_auth = authenticate_user(username_input, password_input)
56
 
57
  if user_object_from_auth:
58
+ st.success(f"Welcome back, {username_input}!")
59
  app_logger.info(f"User {username_input} authenticated successfully.")
60
 
61
  try:
62
+ with get_session_context() as db_session: # db_session is a SQLModel Session
63
+ # --- SQLMODEL QUERY ---
64
+ statement = select(User).where(User.username == username_input)
65
+ live_user = db_session.exec(statement).first()
66
+ # --------------------
 
67
 
68
  if not live_user:
69
  st.error("Authentication inconsistency. User details not found after login. Please contact support.")
70
  app_logger.error(f"CRITICAL: User '{username_input}' authenticated but then not found in DB by username.")
 
71
  st.session_state.authenticated_user_id = None
72
  st.session_state.authenticated_username = None
73
  st.rerun()
74
  return
75
 
 
 
76
  st.session_state.authenticated_user_id = live_user.id
77
+ st.session_state.authenticated_username = live_user.username
78
  app_logger.info(f"Stored user ID {live_user.id} and username '{live_user.username}' in session state.")
79
 
80
+ new_chat_session = ChatSession(user_id=live_user.id, title=f"Session for {live_user.username} ({Path(settings.APP_TITLE).name})")
 
81
  db_session.add(new_chat_session)
82
+ # db_session.commit() # Handled by get_session_context manager
83
+ db_session.refresh(new_chat_session) # Refresh after add, before commit if ID needed
 
 
84
  st.session_state.current_chat_session_id = new_chat_session.id
85
  st.session_state.chat_messages = []
86
  app_logger.info(f"New chat session (ID: {new_chat_session.id}) created for user {live_user.username}.")
87
+ # Session commit and close handled by get_session_context
88
+ st.rerun()
89
 
90
  except Exception as e:
91
  app_logger.error(f"Error during post-login session setup for user {username_input}: {e}", exc_info=True)
92
  st.error(f"Could not complete login process: {e}")
 
93
  st.session_state.authenticated_user_id = None
94
  st.session_state.authenticated_username = None
95
  else:
96
  st.error("Invalid username or password.")
97
  app_logger.warning(f"Failed login attempt for username: {username_input}")
98
 
99
+ # display_signup_form() remains largely the same as it calls create_user_in_db,
100
+ # which should internally use SQLModel syntax if it interacts with the DB.
101
+
102
+ # --- Main App Logic --- (Remains the same, using updated session state keys)
103
+ # ... (rest of app.py as previously provided, ensuring it uses authenticated_user_id and authenticated_username)
104
+ # For brevity, I'm omitting the parts of app.py that don't change due to SQLModel query syntax.
105
+ # The signup form and the main structure checking st.session_state.get("authenticated_user_id")
106
+ # and the sidebar display are correct from the previous version.
107
+ # Ensure any other direct DB queries in app.py (if any were added) are also updated.
108
+
109
+ # (Make sure the rest of your app.py from the previous good version is here)
110
  def display_signup_form():
111
  with st.form("signup_form"):
112
  st.subheader("Sign Up")
 
119
  if submit_button:
120
  if not new_username or not new_password:
121
  st.error("Username and password are required.")
122
+ elif len(new_password) < 6:
123
+ st.error("Password must be at least 6 characters long.")
124
  elif new_password != confirm_password:
125
  st.error("Passwords do not match.")
126
  else:
 
129
  password=new_password,
130
  email=new_email if new_email else None
131
  )
132
+ user = create_user_in_db(user_data)
133
  if user:
134
+ st.success(f"Account created for {new_username}. Please log in.")
135
  app_logger.info(f"Account created for {new_username}.")
136
  else:
137
  st.error("Username might already be taken or another error occurred during signup.")
138
  app_logger.warning(f"Signup failed for username: {new_username}")
139
 
140
+ if not st.session_state.get("authenticated_user_id"):
 
141
  st.title(f"Welcome to {settings.APP_TITLE}")
142
  st.markdown("Your AI-powered partner for advanced healthcare insights.")
 
143
  login_tab, signup_tab = st.tabs(["Login", "Sign Up"])
144
  with login_tab:
145
  display_login_form()
146
  with signup_tab:
147
  display_signup_form()
148
  else:
 
149
  with st.sidebar:
150
+ logo_path_str_sidebar = get_logo_path()
151
+ if logo_path_str_sidebar:
152
+ logo_file_sidebar = Path(logo_path_str_sidebar)
153
+ if logo_file_sidebar.exists():
 
 
 
 
154
  try:
155
+ st.image(str(logo_file_sidebar), width=100)
156
  except Exception as e:
157
+ app_logger.warning(f"Could not display logo in sidebar from path '{logo_path_str_sidebar}': {e}")
 
 
158
  elif settings.APP_TITLE:
159
+ st.sidebar.markdown(f"#### {settings.APP_TITLE}")
160
+ username_for_display = st.session_state.get("authenticated_username", "User")
161
+ st.sidebar.markdown(f"### Welcome, {username_for_display}!")
162
+ st.sidebar.markdown("---")
163
+ if st.sidebar.button("Logout", key="sidebar_logout_button"):
164
  logged_out_username = st.session_state.get("authenticated_username", "UnknownUser")
165
  app_logger.info(f"User {logged_out_username} logging out.")
 
166
  st.session_state.authenticated_user_id = None
167
  st.session_state.authenticated_username = None
168
  st.session_state.current_chat_session_id = None
169
  st.session_state.chat_messages = []
170
  st.success("You have been logged out.")
171
  st.rerun()
 
 
 
 
 
 
 
172
  app_logger.info(f"Streamlit app '{settings.APP_TITLE}' initialized and running.")