TajWaliKhan's picture
Update app.py
d943e26 verified
Raw
History Blame Contribute Delete
3.69 kB
"""
app.py
Streamlit front-end for the Custom AI Chatbot with Memory (Project 1,
DecodeLabs Generative AI Internship).
Key architectural concept:
Streamlit reruns this ENTIRE script top-to-bottom on every user
interaction (every message sent, every button click). A plain Python
list defined here would be wiped and recreated on every rerun --
which would defeat the whole point of "memory."
The fix is `st.session_state`: a dict-like object Streamlit preserves
across reruns for as long as the browser session stays open. Our
conversation_history list lives there instead of as a bare variable.
"""
import streamlit as st
from chat_engine import get_claude_response
st.set_page_config(page_title="Claude Chatbot with Memory", page_icon="🤖")
st.title("🤖 Custom AI Chatbot with Memory")
st.caption("Project 1 — DecodeLabs Generative AI Internship | Powered by Claude")
# --------------------------------------------------------------------------
# 1. Initialize persistent memory (this block only runs ONCE per session,
# thanks to the "not in st.session_state" guard)
# --------------------------------------------------------------------------
if "conversation_history" not in st.session_state:
st.session_state.conversation_history = []
# --------------------------------------------------------------------------
# 2. Re-render the existing conversation on every rerun
# (Streamlit has no persistent DOM -- we redraw everything, every time)
# --------------------------------------------------------------------------
for message in st.session_state.conversation_history:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# --------------------------------------------------------------------------
# 3. Capture new user input
# --------------------------------------------------------------------------
user_input = st.chat_input("Type your message...")
if user_input:
# --- Structural Validation Gate ---
# Never let an empty/whitespace-only string reach the API: Claude
# returns a 400 Bad Request for it, which would crash the app if
# left unguarded.
cleaned_input = user_input.strip()
if not cleaned_input:
st.warning("Please enter a non-empty message.")
else:
# Step 1: Append the user's turn to memory and display it
st.session_state.conversation_history.append(
{"role": "user", "content": cleaned_input}
)
with st.chat_message("user"):
st.markdown(cleaned_input)
# Step 2: Send the FULL history to Claude and display the reply
with st.chat_message("assistant"):
with st.spinner("Thinking..."):
try:
reply = get_claude_response(
st.session_state.conversation_history
)
except (ValueError, RuntimeError) as exc:
reply = f"⚠️ {exc}"
st.markdown(reply)
# Step 3: Append Claude's reply to memory so the NEXT turn has
# full context of this exchange too.
st.session_state.conversation_history.append(
{"role": "assistant", "content": reply}
)
# --------------------------------------------------------------------------
# 4. Sidebar utility: reset the conversation
# --------------------------------------------------------------------------
with st.sidebar:
st.subheader("Session Controls")
st.write(f"Messages in memory: {len(st.session_state.conversation_history)}")
if st.button("🗑️ Clear conversation"):
st.session_state.conversation_history = []
st.rerun()