Update app.py
Browse files
app.py
CHANGED
@@ -1,14 +1,22 @@
|
|
|
|
1 |
import streamlit as st
|
2 |
from pathlib import Path
|
3 |
-
from
|
4 |
|
5 |
from config.settings import settings
|
6 |
-
from models import
|
|
|
|
|
|
|
|
|
|
|
|
|
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 (
|
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}!")
|
54 |
app_logger.info(f"User {username_input} authenticated successfully.")
|
55 |
|
56 |
try:
|
57 |
-
with get_session_context() as db_session:
|
58 |
-
#
|
59 |
-
|
60 |
-
|
61 |
-
#
|
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
|
77 |
app_logger.info(f"Stored user ID {live_user.id} and username '{live_user.username}' in session state.")
|
78 |
|
79 |
-
|
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() #
|
83 |
-
#
|
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()
|
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)
|
123 |
if user:
|
124 |
-
st.success(f"Account created for {new_username}. Please log in.")
|
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 |
-
|
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 |
-
|
144 |
-
|
145 |
-
|
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(
|
153 |
except Exception as e:
|
154 |
-
app_logger.warning(f"Could not
|
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.")
|