File size: 10,112 Bytes
310dade
6145bc0
79d193c
19b059b
 
e9c724f
864b488
310dade
 
19b059b
310dade
 
 
 
19b059b
0b77233
 
19b059b
864b488
8d6f871
0b77233
 
e9c724f
0b77233
 
 
864b488
8d6f871
19b059b
0b77233
 
19b059b
0b77233
 
0a2437f
19b059b
79d193c
 
 
 
0b77233
 
19b059b
0b77233
19b059b
 
0a2437f
19b059b
 
 
 
 
 
 
310dade
0b77233
 
19b059b
 
 
0b77233
 
19b059b
 
0b77233
64f8a92
0b77233
79d193c
19b059b
310dade
19b059b
04ae885
19b059b
310dade
 
04ae885
19b059b
 
79d193c
 
19b059b
04ae885
79d193c
310dade
19b059b
8d6f871
 
 
 
04ae885
19b059b
8d6f871
19b059b
8d6f871
19b059b
 
8d6f871
19b059b
04ae885
19b059b
 
8d6f871
19b059b
04ae885
19b059b
79d193c
 
 
8d6f871
0b77233
 
e9c724f
64f8a92
0b77233
19b059b
 
0b77233
 
19b059b
 
 
 
0b77233
 
19b059b
 
 
0b77233
19b059b
310dade
0b77233
310dade
8d6f871
0b77233
19b059b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b77233
19b059b
0b77233
19b059b
310dade
 
 
19b059b
 
 
8d6f871
19b059b
310dade
19b059b
 
8d6f871
19b059b
79d193c
8d6f871
19b059b
 
 
 
 
0b77233
 
8d6f871
19b059b
 
 
 
 
 
 
8d6f871
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# /home/user/app/app.py
import streamlit as st
from pathlib import Path
from datetime import datetime
from sqlmodel import select

from config.settings import settings
from models import (
    create_db_and_tables,
    get_session_context,
    User,
    ChatMessage,
    ChatSession
)
from models.user import UserCreate
from services.auth import create_user_in_db, authenticate_user
from services.logger import app_logger
from assets.logo import get_logo_path

# --- Page Configuration ---
st.set_page_config(
    page_title=settings.APP_TITLE,
    page_icon="⚕️",
    layout="wide",
    initial_sidebar_state="expanded"
)

# --- Database Initialization ---
@st.cache_resource
def init_db():
    app_logger.info("Initializing database and tables...")
    create_db_and_tables()
    app_logger.info("Database initialized.")
init_db()

# --- Session State Initialization ---
if 'authenticated_user_id' not in st.session_state:
    st.session_state.authenticated_user_id = None
if 'authenticated_username' not in st.session_state:
    st.session_state.authenticated_username = None
if 'current_chat_session_id' not in st.session_state:
    st.session_state.current_chat_session_id = None
if 'chat_messages' not in st.session_state:
    st.session_state.chat_messages = []
if 'user_understands_disclaimer' not in st.session_state:
    st.session_state.user_understands_disclaimer = False

# --- Disclaimer Function ---
def display_disclaimer():
    st.warning(f"**Important Disclaimer:** {settings.MAIN_DISCLAIMER_LONG}")
    st.info(settings.SIMULATION_DISCLAIMER)
    if st.button("I Understand and Agree to Proceed", key="disclaimer_agree_btn"):
        st.session_state.user_understands_disclaimer = True
        st.rerun()

# --- Authentication Logic ---
def display_login_form():
    # (This function remains the same as the last full app.py provided, which had the fix for
    #  `Instance '<ChatSession ...>' is not persistent within this Session`.
    #  Ensure that version is used here for robustness.)
    with st.form("login_form"):
        st.subheader("Login")
        username_input = st.text_input("Username", key="login_username_input_main_app")
        password_input = st.text_input("Password", type="password", key="login_password_input_main_app")
        submit_button = st.form_submit_button("Login")

        if submit_button:
            user_object_from_auth = authenticate_user(username_input, password_input)
            if user_object_from_auth:
                st.success(f"Welcome back, {username_input}!")
                app_logger.info(f"User '{username_input}' authenticated successfully.")
                try:
                    with get_session_context() as db_session:
                        statement = select(User).where(User.username == username_input)
                        live_user = db_session.exec(statement).first()
                        if not live_user:
                            st.error("Auth inconsistency. User not found post-login.")
                            app_logger.error(f"CRITICAL: User '{username_input}' auth OK but NOT FOUND in DB.")
                            st.session_state.authenticated_user_id = None
                            st.session_state.authenticated_username = None
                            st.rerun()
                            return
                        st.session_state.authenticated_user_id = live_user.id
                        st.session_state.authenticated_username = live_user.username
                        app_logger.info(f"Stored user ID {live_user.id} and username '{live_user.username}' in session state.")
                        new_chat_session = ChatSession(
                            user_id=live_user.id,
                            title=f"Session for {live_user.username} - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
                        )
                        db_session.add(new_chat_session)
                        app_logger.debug("New ChatSession added to SQLModel session.")
                        db_session.flush()
                        app_logger.debug(f"Session flushed. new_chat_session ID: {new_chat_session.id}")
                        if new_chat_session.id is None:
                            app_logger.error("CRITICAL: new_chat_session.id is None after flush.")
                            raise Exception("Failed to obtain ID for new chat session after flush.")
                        db_session.refresh(new_chat_session)
                        app_logger.debug("new_chat_session refreshed.")
                        st.session_state.current_chat_session_id = new_chat_session.id
                        st.session_state.chat_messages = []
                        app_logger.info(f"New chat session (ID: {new_chat_session.id}) created for user '{live_user.username}'.")
                    app_logger.info(f"Post-login setup complete for '{username_input}'. Rerunning app.")
                    st.rerun()
                except Exception as e:
                    app_logger.error(f"Error during post-login session setup for '{username_input}': {e}", exc_info=True)
                    st.error(f"Could not complete login process: {e}")
                    st.session_state.authenticated_user_id = None
                    st.session_state.authenticated_username = None
                    st.session_state.current_chat_session_id = None
            else:
                st.error("Invalid username or password.")
                app_logger.warning(f"Failed login attempt for username: {username_input}")

def display_signup_form():
    # (This function remains largely the same as the last full app.py provided.
    #  Ensure it correctly calls your `create_user_in_db` which handles hashing and DB commit.)
    with st.form("signup_form"):
        st.subheader("Sign Up")
        new_username = st.text_input("Choose a Username", key="signup_username_input_main_app")
        new_email = st.text_input("Email (Optional)", key="signup_email_input_main_app")
        new_password = st.text_input("Choose a Password", type="password", key="signup_password_input_main_app")
        confirm_password = st.text_input("Confirm Password", type="password", key="signup_confirm_password_input_main_app")
        submit_button = st.form_submit_button("Sign Up")
        if submit_button:
            if not new_username or not new_password: st.error("Username and password are required.")
            elif len(new_password) < 6: st.error("Password must be at least 6 characters long.")
            elif new_password != confirm_password: st.error("Passwords do not match.")
            else:
                user_data = UserCreate(username=new_username, password=new_password, email=new_email if new_email else None)
                user = create_user_in_db(user_data)
                if user:
                    st.success(f"Account created for {new_username}. Please log in.")
                    app_logger.info(f"Account created for '{new_username}'.")
                else:
                    st.error("Username/Email might be taken, or another error occurred. Check logs or try different credentials.")
                    app_logger.warning(f"Signup failed for '{new_username}'. create_user_in_db returned None.")

# --- Main App Logic ---
if not st.session_state.get("authenticated_user_id"): # Not logged in
    if not st.session_state.user_understands_disclaimer:
        st.title(f"Welcome to {settings.APP_TITLE}")
        st.markdown("Your AI-powered partner for advanced healthcare insights.")
        st.markdown("---")
        display_disclaimer()
        st.stop() # Stop further execution until disclaimer is agreed to
    else:
        # Disclaimer agreed, show login/signup
        st.title(f"Welcome to {settings.APP_TITLE}")
        st.caption(settings.MAIN_DISCLAIMER_SHORT) # Short disclaimer always visible on login page
        login_tab, signup_tab = st.tabs(["Login", "Sign Up"])
        with login_tab:
            display_login_form()
        with signup_tab:
            display_signup_form()
else:
    # --- User is Authenticated ---
    with st.sidebar:
        logo_path_str_sidebar = get_logo_path()
        if logo_path_str_sidebar:
            logo_file_sidebar = Path(logo_path_str_sidebar)
            if logo_file_sidebar.exists():
                try: st.image(str(logo_file_sidebar), width=100)
                except Exception as e: app_logger.warning(f"Could not display sidebar logo: {e}")
        elif settings.APP_TITLE: st.sidebar.markdown(f"#### {settings.APP_TITLE}")

        username_for_display = st.session_state.get("authenticated_username", "User")
        st.sidebar.markdown(f"### Welcome, {username_for_display}!")
        st.sidebar.info(settings.MAIN_DISCLAIMER_SHORT) # Constant reminder
        st.sidebar.markdown("---")

        if st.sidebar.button("Logout", key="sidebar_logout_button_main_app"):
            logged_out_username = st.session_state.get("authenticated_username", "UnknownUser")
            app_logger.info(f"User '{logged_out_username}' logging out.")
            # Clear all session state, or selectively
            for key in list(st.session_state.keys()): # Clear most session state keys on logout
                if key not in ['query_params']: # Keep essential Streamlit keys if needed
                    del st.session_state[key]
            st.session_state.user_understands_disclaimer = False # Require disclaimer agreement again
            st.success("You have been logged out.")
            st.rerun()

    # Main content area: Streamlit MPA handles this by showing the selected page
    # from the `pages/` directory.
    # If on app.py itself, give a pointer.
    current_page = st.session_state.get('page_script_hash', None)
    if not current_page or current_page == st.elements.utils.calc_page_script_hash('app.py'):
         st.sidebar.success("Select a page from the navigation.")
         st.info("Please select a page from the sidebar (e.g., Home, Consult, Reports) to begin.")


app_logger.info(f"Streamlit app '{settings.APP_TITLE}' (app.py) processed.")