|
|
|
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 |
|
|
|
|
|
st.set_page_config( |
|
page_title=settings.APP_TITLE, |
|
page_icon="⚕️", |
|
layout="wide", |
|
initial_sidebar_state="expanded" |
|
) |
|
|
|
|
|
@st.cache_resource |
|
def init_db(): |
|
app_logger.info("Initializing database and tables...") |
|
create_db_and_tables() |
|
app_logger.info("Database initialized.") |
|
|
|
init_db() |
|
|
|
|
|
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 = [] |
|
|
|
|
|
|
|
def display_login_form(): |
|
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 by authenticate_user.") |
|
|
|
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("Authentication inconsistency. User details not found after login. Please contact support or try again.") |
|
app_logger.error(f"CRITICAL: User '{username_input}' authenticated but then NOT FOUND in DB by username query.") |
|
|
|
st.session_state.authenticated_user_id = None |
|
st.session_state.authenticated_username = None |
|
st.rerun() |
|
return |
|
|
|
app_logger.info(f"Live user object for '{live_user.username}' (ID: {live_user.id}) obtained in session.") |
|
|
|
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 Streamlit session state.") |
|
|
|
|
|
app_logger.debug(f"Attempting to create new chat session for user_id: {live_user.id}") |
|
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 ORM object added to SQLModel session.") |
|
|
|
|
|
app_logger.debug("Flushing SQLModel session to assign ID to new_chat_session...") |
|
db_session.flush() |
|
app_logger.debug(f"Session flushed. new_chat_session potential ID: {new_chat_session.id}") |
|
|
|
|
|
if new_chat_session.id is None: |
|
app_logger.error("CRITICAL: new_chat_session.id is None after flush. Cannot proceed with session creation.") |
|
raise Exception("Failed to obtain ID for new chat session after database flush.") |
|
|
|
|
|
app_logger.debug(f"Refreshing new_chat_session (ID: {new_chat_session.id}) from database...") |
|
db_session.refresh(new_chat_session) |
|
app_logger.debug("new_chat_session ORM object 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 and assigned 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 user '{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(): |
|
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 or Email might already be taken, or another error occurred during signup. Please check logs or try different credentials.") |
|
app_logger.warning(f"Signup failed for username: '{new_username}'. create_user_in_db returned None.") |
|
|
|
|
|
if not st.session_state.get("authenticated_user_id"): |
|
st.title(f"Welcome to {settings.APP_TITLE}") |
|
st.markdown("Your AI-powered partner for advanced healthcare insights.") |
|
|
|
login_tab, signup_tab = st.tabs(["Login", "Sign Up"]) |
|
with login_tab: |
|
display_login_form() |
|
with signup_tab: |
|
display_signup_form() |
|
else: |
|
|
|
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 logo in sidebar from path '{logo_path_str_sidebar}': {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.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.") |
|
|
|
st.session_state.authenticated_user_id = None |
|
st.session_state.authenticated_username = None |
|
st.session_state.current_chat_session_id = None |
|
st.session_state.chat_messages = [] |
|
|
|
|
|
|
|
|
|
st.success("You have been logged out.") |
|
st.rerun() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.sidebar.success("Select a page from the navigation.") |
|
|
|
|
|
|
|
|
|
app_logger.info(f"Streamlit app '{settings.APP_TITLE}' (app.py) processed.") |