Persist memory and answer

Summary

Hi, I want to make a q and q app using Streamlit.

Steps to reproduce

Code snippet:

import streamlit as st
import random
import time

st.title("Simple chat")

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

# Display chat messages from history on app rerun
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# Accept user input
if prompt := st.chat_input("What is up?"):
    # Add user message to chat history
    st.session_state.messages.append({"role": "user", "content": prompt})
    # Display user message in chat message container
    with st.chat_message("user"):
        st.markdown(prompt)

    # Display assistant response in chat message container
    with st.chat_message("assistant"):
        message_placeholder = st.empty()
        full_response = ""
        assistant_response = random.choice(
            [
                "Hello there! How can I assist you today?",
                "Hi, human! Is there anything I can help you with?",
                "Do you need help?",
            ]
        )
        # Simulate stream of response with milliseconds delay
        for chunk in assistant_response.split():
            full_response += chunk + " "
            time.sleep(0.05)
            # Add a blinking cursor to simulate typing
            message_placeholder.markdown(full_response + "▌")
        message_placeholder.markdown(full_response)
    # Add assistant response to chat history
    st.session_state.messages.append({"role": "assistant", "content": full_response})

If applicable, please provide the steps we should take to reproduce the error or specified behavior.

Expected behavior:

The questions and answers should be preserved if I refresh the page. Also if I refresh the page while an answer is being generated, the chat box should be blocked so I have to wait until the current answer is generated.

Actual behavior:

Just the opposite of the expected behaviour

1 Like

Hi @Erica,

Thanks for posting! So st.session_state is designed to maintain the state across reruns of the app within the same browser session. When you refresh the app, it starts a new session and that’s why the content refreshes as well. There’s no browser/cookie-based storage yet. Also, if you refresh while the assistant is “typing,” the message won’t complete since the state has been reset.

You can consider connecting to a database and saving the responses and prompts there then calling them upon refreshes.

Let me know if this helps.

  1. Session State always resets on page refresh. You will need to use a simple database to store the resoponses.
  2. Behavior of blocking further chat when one response / continuing on response is kinda complex.

Implementing on @tonykip 's explanation:
I have used tinydb here. (do pip install tinydb to resolve missing dependency)

import streamlit as st
import random
import time
from tinydb import TinyDB

# Initialize chat history
db = TinyDB('chat_history.json')

st.title("Simple chat")

# Initialize chat history from previous sessions
chat_history = db.all()

# Display chat messages from history on app rerun
for message in chat_history:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# Disable text input when assistant is responding
if "disabled" not in st.session_state:
    st.session_state["disabled"] = False

# Toggle disabled state
def disable_toggle():
    st.session_state["disabled"] = not(st.session_state["disabled"])

# Button to to test disable
if st.button('toggle'):
    disable_toggle()

# Accept user input if assistant is not responding
# if not st.session_state.disabled:  # Check if the text input is not disabled
prompt = st.chat_input("What is up?", disabled=st.session_state["disabled"])

if prompt:
    # Add user message to chat history
    user_message = {"role": "user", "content": prompt}
    chat_history.append(user_message)
    db.insert(user_message)

    # Display user message in chat message container
    with st.chat_message("user"):
        st.markdown(prompt)

    
    # Simulate assistant response
    with st.chat_message("assistant"):
        message_placeholder = st.empty()
        full_response = ""
        assistant_response = random.choice([
            "Hello there! How can I assist you today?",
            "Hi, human! Is there anything I can help you with?",
            "Do you need help?",
        ])
        for chunk in assistant_response.split():
            full_response += chunk + " "
            time.sleep(0.05)
            # Add a blinking cursor to simulate typing
            message_placeholder.markdown(full_response + "▌")
        message_placeholder.markdown(full_response)

        # Add assistant response to chat history
        assistant_message = {"role": "assistant", "content": full_response}
        chat_history.append(assistant_message)
        db.insert(assistant_message)

# Reset chat history button
if len(db.all()) > 0:
    # Show button if Chat history not empty
    if st.button("Reset Chat"):
        # Delete all entries in Database
        db.truncate()
        # Reload Page
        st.experimental_rerun()

This will cover some of your functionalities.

1 Like

Hi @tonykip, thanks for replying. Is there a good way to check if the page was refreshed? I could not find a function or something that is made for that sadly.

There’s no specific function to check if was refreshed. The refresh is related to manually hitting the refresh/reload button on your browser which creates a new session and wipes the session state.

Alright, thank you very much :). This topic may be closed.

1 Like

Glad it is resolved! Happy Streamlit-ing! :balloon:

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.