Cannot switch page when using st.chat_input

I run app in local. I use st.chat_input in chat page. My app has multi page and I use st.navigation to switch page. But when I click to Chat page and then move to other page, it get stuck in Chat page. if I want to move to other page, I have to double click to that page. If I remove st.chat_input, everything is ok.
For testing, I use function test(), this function is ok. So I think the error is from using navigation and multi pages.

Lib version:

streamlit==1.36.0
python=3.11

My code:


import re
from openai import OpenAI
import streamlit as st
import django
import sys
import os
import json
import extra_streamlit_components as stx

project_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(project_path)

# Set the DJANGO_SETTINGS_MODULE environment variable
os.environ['DJANGO_SETTINGS_MODULE'] = 'ichallenge.settings'
django.setup()
from project_user.models import ProjectUser
from chatbot.models import Roleplay, GPTConfig, UserRolePlay, ChatHistory, Conversation
from ichallenge.settings import OPENAI_API_KEY
st.title("E-Challenge 2024 Assistant")

# Initialize OpenAI client
client = OpenAI(api_key=OPENAI_API_KEY)

# Get system config
system_config = GPTConfig.objects.first()

# Initialize session state variables


def get_manager():
    return stx.CookieManager()


cookie_manager = get_manager()


def get_user(cookie): 
    if not cookie:
        return False
    email, password = cookie['email'], cookie['password']
    user = ProjectUser.objects.filter(email=email).first()
    if not user:
        return False
    elif user.check_password(password):
        st.session_state.login = True
        st.session_state.user = user
        if current_roleplay := UserRolePlay.get_current_roleplay(user):
            st.session_state.system_prompt = current_roleplay.prompt
    else:
        return False

def init_state():
    get_user(cookie_manager.get('user'))
    if "login" not in st.session_state:
        st.session_state.login = False
    if "user" not in st.session_state:
        st.session_state.user = None
    if st.session_state.login:
        st.session_state.user = ProjectUser.objects.get(
            pk=st.session_state.user.id)
    if "messages" not in st.session_state:
        st.session_state.messages = []
    if "openai_model" not in st.session_state:
        st.session_state.openai_model = system_config.model if system_config.model else 'gpt-3.5-turbo'
    if "system_prompt" not in st.session_state:
        st.session_state.system_prompt = Roleplay.objects.filter(
            default=True).first().prompt
    if "conversation" not in st.session_state:
        st.session_state.conversation = None

    # Set CSS config
    st.markdown(
        """
        <style>
            .st-emotion-cache-janbn0 {
                flex-direction: row-reverse;
                text-align: right;
            }
        </style>
        """,
        unsafe_allow_html=True,
    )


def login():
    st.header("Log in")
    email = st.text_input("Email")
    password = st.text_input("Password", type="password")

    if st.button("Log in"):
        user = ProjectUser.objects.filter(email=email).first()
        if not user:
            st.error("Email is not found!")
        elif user.check_password(password):
            st.success("Logged in successfully!")
            cookie_manager.set('user', json.dumps(dict(email=user.email, 
                                                       password=password)), key='user_info')
            st.session_state.login = True
            st.session_state.user = user
            if current_roleplay := UserRolePlay.get_current_roleplay(user):
                st.session_state.system_prompt = current_roleplay.prompt
            st.rerun()
        else:
            st.error("Incorrect password!")


def logout():
    st.header("Log out")
    if st.button("Log out"):
        st.session_state.login = False
        st.session_state.user = None
        st.success("Logged out successfully!")
        cookie_manager.delete('user')
        st.rerun()


def chat():
    st.title('Chat')
    prompt = st.chat_input("Say something")
    if prompt:
        conversation = st.session_state.conversation
        if not conversation:
            conversation = Conversation.create_new(user=st.session_state.user)
        else:
            conversation = Conversation.objects.get(pk=conversation.id)
        st.session_state.conversation = conversation
        system_message = {"role": "system",
                          "content": st.session_state.system_prompt}
        st.session_state.messages.append(system_message)
        ChatHistory.save_history(
            user=st.session_state.user, content=system_message, conversation=conversation)

        user_message = {"role": "user", "content": prompt}
        st.session_state.messages.append(user_message)
        ChatHistory.save_history(
            user=st.session_state.user, content=user_message, conversation=conversation)

        with st.chat_message("user"):
            st.markdown(prompt)

        with st.chat_message("assistant"):
            stream = client.chat.completions.create(
                model=st.session_state["openai_model"],
                messages=[
                    {"role": m["role"], "content": m["content"]}
                    for m in st.session_state.messages
                ],
                stream=True,
            )
            response = st.write_stream(stream)

        assistant_message = {"role": "assistant", "content": response}
        st.session_state.messages.append(assistant_message)
        ChatHistory.save_history(
            user=st.session_state.user, content=assistant_message, conversation=conversation)

        if not conversation.name:
            conversation.name = create_title_for_conversation(prompt)
            conversation.save()


def roleplay():
    st.title("Roleplays")
    roleplays = Roleplay.objects.filter(
        status='public').prefetch_related('conversation_starters').all()
    data = {item.name: item for item in roleplays}
    selected_item = st.selectbox("Choose one: ", options=list(data.keys()))
    if selected_item:
        st.write("Conversation starters:")
        conversation_starters = data[selected_item].conversation_starters.all()
        for con in conversation_starters:
            st.markdown(
                f"""
                <div style="
                    padding: 10px;
                    border: 1px solid #ddd;
                    border-radius: 5px;
                    margin-top: 0px;
                    margin-bottom: 10px;
                ">
                    {con.content}
                </div>
                """,
                unsafe_allow_html=True
            )
        if st.button("Save"):
            st.success(f"Activated roleplay {selected_item}")
            st.session_state.system_prompt = data[selected_item].prompt
            UserRolePlay.activate_roleplay(
                user=st.session_state.user, roleplay=data[selected_item])


def history():
    """
    Show history of a conversation and let user chat on this conversation
    """
    conversation_uuid = extract_uuid(st.session_state.current_page)
    if conversation_uuid:
        conversation = Conversation.objects.filter(
            uuid=conversation_uuid).first()
        if conversation:
            st.session_state.conversation = conversation
            messages = ChatHistory.objects.filter(
                user=st.session_state.user, conversation=conversation
            ).order_by('created_at')
            st.session_state.messages = []
            for item in messages:
                if item.content["role"] != "system":
                    with st.chat_message(item.content["role"]):
                        st.markdown(item.content["content"])
                    st.session_state.messages.append(item.content)
    #chat()


def show_conversations():
    conversations = Conversation.list_all(user=st.session_state.user)
    pages = []
    for con in conversations:
        pages.append(st.Page(history, title=con.name,
                     url_path=f"history/?conversation={con.uuid}"))
    return pages


def create_title_for_conversation(first_question):
    print('create_title_for_conversation')
    prompt = f"""create short name for a conversation based on input, just return the result.
    Do not use double quote.
    Style: formal.
    Input is: {first_question}
    """
    response = client.chat.completions.create(
        model=st.session_state["openai_model"],
        messages=[
            {"role": "user", "content": prompt}
        ]
    )
    return response.choices[0].message.content


def extract_uuid(url):
    # Define the regex pattern for UUID
    pattern = r'conversation=([a-f0-9\-]+)'

    # Search for the pattern in the URL
    match = re.search(pattern, url)

    # If a match is found, return the UUID, otherwise return None
    if match:
        return match.group(1)
    else:
        return None

def main():
    init_state()
    logout_page = st.Page(logout, title="Log out", icon=":material/logout:")
    chat_page = st.Page(test, title="New conversation", icon=":material/chat:", url_path='chat')
    roleplay_page = st.Page(roleplay, title="Roleplays")
    account_pages = [logout_page]
    chat_pages = [chat_page, roleplay_page]

    if st.session_state.login:
        conversations = show_conversations()
        page_dict = {
            "Chat": chat_pages,
            "History": conversations
        }
    else:
        page_dict = {}

    if page_dict:
        pg = st.navigation({"Account": account_pages} | page_dict)
    else:
        pg = st.navigation([st.Page(login, title='Login')])
    st.session_state.current_page = pg.url_path
    print('Path: ', st.session_state.current_page)
    if st.session_state.current_page == 'chat':
        st.session_state.conversation = None
    pg.run()


def test():
    st.title("Echo Bot")

    # 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"])

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

        response = f"Echo: {prompt}"
        # Display assistant response in chat message container
        with st.chat_message("assistant"):
            st.markdown(response)
        # Add assistant response to chat history
        st.session_state.messages.append(
            {"role": "assistant", "content": response})

if __name__ == "__main__":
    main()

I have also encountered the same problem, have you solved it?

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