Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 70 additions & 28 deletions TalkHeal.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@
)

import google.generativeai as genai
from core.db import init_db, create_user, get_user_by_username, create_chat, add_message, get_messages

# --- ENSURE TABLES EXIST BEFORE ANY DB USAGE ---
init_db()

from core.utils import save_conversations, load_conversations
from core.config import configure_gemini, PAGE_CONFIG
from core.utils import get_current_time, create_new_conversation
from core.utils import get_current_time,get_ai_response
from css.styles import apply_custom_css
from components.header import render_header
from components.sidebar import render_sidebar
from components.chat_interface import render_chat_interface, handle_chat_input
from components.chat_interface import render_chat_interface
from components.emergency_page import render_emergency_page

from core.db import init_db, get_messages, add_message, create_chat
from core.db import get_user_by_username, create_user # <-- Add this line, adjust module if needed
# --- ENSURE TABLES EXIST BEFORE ANY DB USAGE ---
init_db()

# --- 1. INITIALIZE SESSION STATE ---
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
if "conversations" not in st.session_state:
st.session_state.conversations = load_conversations()
if "active_conversation" not in st.session_state:
st.session_state.active_conversation = -1
if "show_emergency_page" not in st.session_state:
st.session_state.show_emergency_page = False
if "sidebar_state" not in st.session_state:
Expand All @@ -37,8 +39,10 @@
"Substance Use Disorders", "ADHD & Neurodevelopmental", "Personality Disorders",
"Sleep Disorders"
]
if "selected_tone" not in st.session_state:
st.session_state.selected_tone = "Compassionate Listener"
if "user_id" not in st.session_state:
st.session_state.user_id = None
if "active_chat_id" not in st.session_state:
st.session_state.active_chat_id = None

# --- 2. SET PAGE CONFIG ---

Expand Down Expand Up @@ -70,34 +74,72 @@ def get_tone_prompt():
return TONE_OPTIONS.get(st.session_state.get("selected_tone", "Compassionate Listener"), TONE_OPTIONS["Compassionate Listener"])

# --- 6. RENDER SIDEBAR ---
render_sidebar()
def render_sidebar():
from core.db import get_chats_for_user, create_chat
if "user_id" in st.session_state and st.session_state.user_id:
chats = get_chats_for_user(st.session_state.user_id)
for chat in chats:
if st.button(chat["title"], key=f"chat_{chat['id']}"):
st.session_state.active_chat_id = chat["id"]
st.rerun()
if st.button("βž• New Chat"):
chat_id = create_chat(st.session_state.user_id, "Untitled Chat")
st.session_state.active_chat_id = chat_id
st.rerun()

# --- 7. PAGE ROUTING ---
main_area = st.container()

if not st.session_state.conversations:
saved_conversations = load_conversations()
if saved_conversations:
st.session_state.conversations = saved_conversations
if st.session_state.active_conversation == -1:
st.session_state.active_conversation = 0
else:
create_new_conversation()
st.session_state.active_conversation = 0
st.rerun()

# --- 8. RENDER PAGE ---
if st.session_state.get("show_emergency_page"):
with main_area:
render_emergency_page()
else:
with main_area:
render_header()
st.subheader(f"πŸ—£οΈ Current Chatbot Tone: **{st.session_state['selected_tone']}**")
render_chat_interface()
handle_chat_input(model, system_prompt=get_tone_prompt())
render_chat_interface(model)

# User login/register
from core.db import create_user, get_user_by_username

if "user_id" not in st.session_state or st.session_state.user_id is None:
st.title("Login / Register")
username = st.text_input("Username")
email = st.text_input("Email")
if st.button("Register/Login"):
user = get_user_by_username(username)
# Add this block to check for existing email
from core.db import get_user_by_email
existing_email_user = get_user_by_email(email)
if existing_email_user and (not user or existing_email_user["id"] != (user["id"] if user else None)):
st.error("This email is already registered. Please use another email or log in with the existing username.")
else:
if not user:
create_user(username, email)
user = get_user_by_username(username)
st.session_state.user_id = user["id"]
st.success(f"Logged in as {username}")
st.rerun()
st.stop()

# Start new chat
if st.button("βž• New Chat"):
chat_id = create_chat(st.session_state.user_id, "Untitled Chat")
st.session_state.active_chat_id = chat_id
st.experimental_rerun()

# Send message
user_input = st.text_input("Message", key="message_input")
if st.button("Send") and user_input.strip() and st.session_state.get("active_chat_id"):
add_message(st.session_state.active_chat_id, "user", user_input.strip())
st.experimental_rerun()

# Display chat history
if st.session_state.get("active_chat_id"):
messages = get_messages(st.session_state.active_chat_id)
for msg in messages:
st.write(f"{msg['sender']}: {msg['message']}")

# --- 9. SCROLL SCRIPT ---
st.markdown("""
<script>
function scrollToBottom() {
Expand All @@ -108,4 +150,4 @@ def get_tone_prompt():
}
setTimeout(scrollToBottom, 100);
</script>
""", unsafe_allow_html=True)
""", unsafe_allow_html=True)
159 changes: 31 additions & 128 deletions components/chat_interface.py
Original file line number Diff line number Diff line change
@@ -1,144 +1,47 @@
import streamlit as st
import streamlit.components.v1 as components
from datetime import datetime
from core.utils import get_current_time, get_ai_response, save_conversations
import requests
from core.db import get_messages, add_message
from core.utils import get_current_time, get_ai_response

# Inject JS to get user's local time zone
def set_user_time_in_session():
if "user_time_offset" not in st.session_state:
components.html("""
<script>
const offset = new Date().getTimezoneOffset();
const time = new Date().toLocaleString();
const data = {offset: offset, time: time};
window.parent.postMessage({type: 'USER_TIME', data: data}, '*');
</script>
""", height=0)
def render_chat_interface(model):
chat_id = st.session_state.get("active_chat_id")
if not chat_id:
st.info("Start a new chat to begin.")
return

messages = get_messages(chat_id)
if not messages:
st.markdown("""
<script>
window.addEventListener("message", (event) => {
if (event.data.type === "USER_TIME") {
const payload = JSON.stringify(event.data.data);
fetch("/", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: payload
}).then(() => location.reload());
}
});
</script>
<div class="welcome-message">
<strong>Hello! I'm TalkHeal, your mental health companion</strong><br>
How are you feeling today? You can write it down below or for a fresh start click on "βž• New Chat" 😊
</div>
""", unsafe_allow_html=True)

set_user_time_in_session()

# Display chat messages
def render_chat_interface():
if st.session_state.active_conversation >= 0:
active_convo = st.session_state.conversations[st.session_state.active_conversation]

if not active_convo["messages"]:
for msg in messages:
if msg["sender"] == "user":
st.markdown(f"""
<div class="welcome-message">
<strong>Hello! I'm TalkHeal, your mental health companion πŸ€—</strong><br>
How are you feeling today? You can write below or start a new topic.
<div class="message-time">{get_current_time()}</div>
<div class="user-message">
{msg["message"]}
<div class="message-time">{msg["timestamp"]}</div>
</div>
""", unsafe_allow_html=True)

for msg in active_convo["messages"]:
css_class = "user-message" if msg["sender"] == "user" else "bot-message"
else:
st.markdown(f"""
<div class="{css_class}">
<div class="bot-message">
{msg["message"]}
<div class="message-time">{msg["time"]}</div>
<div class="message-time">{msg["timestamp"]}</div>
</div>
""", unsafe_allow_html=True)

# Handle chat input and generate AI response
def handle_chat_input(model, system_prompt):
if "pre_filled_chat_input" not in st.session_state:
st.session_state.pre_filled_chat_input = ""
initial_value = st.session_state.pre_filled_chat_input
st.session_state.pre_filled_chat_input = ""

with st.form(key="chat_form", clear_on_submit=True):
col1, col2 = st.columns([5, 1])
with col1:
user_input = st.text_input(
"Share your thoughts...",
key="message_input",
label_visibility="collapsed",
placeholder="Type your message here...",
value=initial_value
)
with col2:
send_pressed = st.form_submit_button("Send", use_container_width=True)

if (send_pressed or st.session_state.get("send_chat_message", False)) and user_input.strip():
if 'send_chat_message' in st.session_state:
st.session_state.send_chat_message = False

if st.session_state.active_conversation >= 0:
current_time = get_current_time()
active_convo = st.session_state.conversations[st.session_state.active_conversation]

# Save user message
active_convo["messages"].append({
"sender": "user",
"message": user_input.strip(),
"time": current_time
})

# Set title if it's the first message
if len(active_convo["messages"]) == 1:
title = user_input[:30] + "..." if len(user_input) > 30 else user_input
active_convo["title"] = title

save_conversations(st.session_state.conversations)

# Format memory
def format_memory(convo_history, max_turns=10):
context = ""
for msg in convo_history[-max_turns*2:]: # user + bot per turn
sender = "User" if msg["sender"] == "user" else "Bot"
context += f"{sender}: {msg['message']}\n"
return context

try:
with st.spinner("TalkHeal is thinking..."):
memory = format_memory(active_convo["messages"])
prompt = f"{system_prompt}\n\n{memory}\nUser: {user_input.strip()}\nBot:"
ai_response = get_ai_response(prompt, model)

active_convo["messages"].append({
"sender": "bot",
"message": ai_response,
"time": get_current_time()
})

except ValueError as e:
st.error("I'm having trouble understanding your message. Could you please rephrase it?")
active_convo["messages"].append({
"sender": "bot",
"message": "I'm having trouble understanding your message. Could you please rephrase it?",
"time": get_current_time()
})
except requests.RequestException as e:
st.error("Network connection issue. Please check your internet connection.")
active_convo["messages"].append({
"sender": "bot",
"message": "I'm having trouble connecting to my services. Please check your internet connection and try again.",
"time": get_current_time()
})
except Exception as e:
st.error(f"An unexpected error occurred. Please try again.")
active_convo["messages"].append({
"sender": "bot",
"message": "I'm having trouble responding right now. Please try again in a moment.",
"time": get_current_time()
})
user_input = st.text_input("Share your thoughts...", key="message_input", label_visibility="collapsed")
send_pressed = st.form_submit_button("Send")
if send_pressed and user_input.strip():
add_message(chat_id, "user", user_input.strip())
with st.spinner("TalkHeal is thinking..."):
context = "\n".join([f"{m['sender'].capitalize()}: {m['message']}" for m in get_messages(chat_id)])
prompt = context + f"\nUser: {user_input.strip()}\nBot:"
ai_response = get_ai_response(prompt, model)
add_message(chat_id, "bot", ai_response)
st.rerun()

save_conversations(st.session_state.conversations)
st.rerun()
Loading