Button Callback updates session state only once

I want a to create a chatbot as such i type something it fetch from AI and while fetching i want to show inprogress status and finally to show result


when i hit the button on onclick function i am able to show the input and inprogress via session state

and white AI was progressing and later if i update the session i couldnt able to get the updated session

instead on next click it updates the message

Note:

  1. earlier i tried to call everything in same click by giving sleep and spinner even then all the msgs are loaded in a single shot ( no use of typing in progress status)
  2. i have also used textarea on change to store the message and show typing in that case there is no use of send button.
    kindly help me how can i call two call backs of the same button or to acheive the same functionality in some similar way

If I’m understanding the problem correctly, one basic answer is to use a session state flag to keep track of whether the callback has already been run.

import streamlit as st

if "ran_once" not in st.session_state:
    st.session_state.ran_once = False

def callback():
    if not st.session_state.ran_once:
        st.toast("This is the first time you've run this callback")
        st.session_state.ran_once = True
    else:
        st.toast("This is not the first time you've run this callback")

st.chat_input("Enter a message", on_submit=callback)

Hi thanks for your quick reply, i have used session state boolean showtyping and then am trying to call show_chatoutput() could you please review my code. what i need to change in order to achieve this scenario
i want to update session messages once after send button click

  1. while button click loadChat :white_check_mark:
  2. show input message show_chatinput() :white_check_mark:
  3. showing typing message showtyping :white_check_mark:
  4. remove typing message then to return output of AI response show_chatoutput :x: (not working)
class ChatInputContainer:
    @staticmethod
    def show():
        def submit():
            if ss.chat_input and not ss.showtyping:             
                ss.usertext = ss.chat_input
                
        def reset_Messages():
            ss.usertext = ss.chat_input = ''
            ss.messages = []
            ss.showwelcome = True 
        def remove_loader():
            for index, msg in enumerate(ss.messages):
                if msg.content_type == "loader":
                    ss.messages.pop(index)
            ss.showtyping = False
        
        def show_chatinput():
            ss.showwelcome = False  
            ss.chat_input = ''
            ss.messages.append(ChatMessage(role= "user", content= ss.usertext, content_type="text"))
            ss.messages.append(ChatMessage(role= "assistant", content= "Searching for the similar results", content_type="loader"))
            ss.showtyping = True
          
        def show_chatoutput():
             if ss.showtyping:
                bot_response = get_bot_response(ss.usertext)
                ss.usertext = ""
                ss.messages.append(ChatMessage(role= "assistant", content= bot_response, content_type="text")) 
                remove_loader()
        def loadChat():
           show_chatinput()
        
        def get_bot_response(user_input):
            client = ss['model']
            user_message = ChatMessage(role="user", content=user_input, content_type="text")
            msg = [user_message.to_dict()]
            result = client.chat.completions.create(
                model="gpt-4o-mini",
                store=False,
                messages= msg
            )
            response = result.choices[0].message.content
            return f"{response}"

        def applyStyleBasedOnText(input_text):
            print(input_text)
            if input_text:
                st.markdown("""
                    <style>
                       #txt_welcomemsg {
                            visibility: hidden;
                        }
                    </style>
                """, unsafe_allow_html=True)
            else:
                st.markdown("""
                    <style>
                       #txt_welcomemsg {
                            visibility: visible;
                        }
                    </style>
                """, unsafe_allow_html=True)
                
        if(ss.showtyping):
             show_chatoutput()       
        chat_input_container = st.container(key="chat_input_container")                
        clearIconContainer, textContainer, micContainer, sendButtonContainer = chat_input_container.columns(
                [0.5,5.1,0.3,0.3], gap='small')
        with clearIconContainer:
            st.button("", icon=':material/chat_bubble:', key='reset', type='primary', on_click=reset_Messages)
        with textContainer:
           input_text = st.text_area('Chat Message:', value=st.session_state.usertext, placeholder="Ask your question here...", key="chat_input",on_change=submit,label_visibility="collapsed")
           applyStyleBasedOnText(input_text)
        with micContainer:
            st.button(" ", icon=":material/mic:", key='mic', type="tertiary", disabled=True)
        with sendButtonContainer:
            st.button("", icon=':material/send:', key='send', type="tertiary", on_click=loadChat)


this made my day!! it worked finally am not sure i did things correctly… but if they have more events for button and text box it will be too good.

2 Likes