How do you hide buttons after clicking them?

So in my chat bot that I’m creating, I’ve also made it so that when the AI replies to the user it generates some potential prompts in the form of buttons that looks like the screenshot

When I click on one of the prompts, I want all the buttons to disappear and have it start generating the response to that prompt. But right now the buttons remain and the the response is generated after the selected button.

This is how it currently looks like :

My Problem: I just want the buttons to disappear on click, I dont want them to fade as well, I want it to be seamless. I’ve tried using radio buttons and they seemed worse. Another solution could be : When one of the prompt buttons are clicked, the text is set to the chat_input and then the buttons are disappeared.

This is the code im using :

if prompt := st.chat_input("Type your question here..."):
        st.session_state.messages.append({"role": "user", "content": prompt})
        with st.chat_message("user"):
            st.markdown(f'<div class="user-message">{prompt}</div>', unsafe_allow_html=True)

        with st.chat_message("assistant"):
                    stream = client.chat.completions.create(
                        model=st.session_state["openai_model"],
                        messages=[system_message, user_message],
                        stream=True,
                        temperature=0.1
                    )
                    response = st.write_stream(stream)
                st.session_state.messages.append({"role": "assistant", "content": response})
                st.session_state.response_ready = True

if st.session_state.response_ready:
    option_stream = client.chat.completions.create(
                model=st.session_state["openai_model"],
                messages=[response_generation_message, response_prompt],
                stream=False,
                max_tokens=100,
                temperature=0.1
            )
            raw_response = option_stream.choices[0].message.content.strip()
            response_options = [
                line.strip()[3:].strip()  
                for line in raw_response.split("\n")
                if line.strip() and line.strip()[0].isdigit() and line.strip()[1] == "."
            ]
            if response_options:
                st.session_state.response_options = response_options
            else:
                st.session_state.response_options = ["Failed to generate valid options. Please try again."]
            st.session_state.response_ready = False

 if st.session_state.response_options:
        button_container = st.container()
        with button_container:
            for idx, option in enumerate(st.session_state.response_options):
                if st.button(option, key=f"response_option_{idx}"):
                    button_container.empty() 
                    st.session_state.messages.append({"role": "user", "content": option})
                    with st.chat_message("user"):
                        st.markdown(f'<div class="user-message">{option}</div>', unsafe_allow_html=True)
        with st.chat_message("assistant"):
                                stream = client.chat.completions.create(
                                    model=st.session_state["openai_model"],
                                    messages=[system_message, option_message],
                                    stream=True,
                                    temperature=0.1
                                )
                                option_response = st.write_stream(stream)
                            st.session_state.messages.append({"role": "assistant", "content": option_response})
                            st.session_state.response_ready = True
                            st.experimental_rerun()

We can use custom CSS to hide the suggestion buttons while the bot is generating a response. After that, we will trigger st.rerun()to make sure all elements are organized on screen and remove the custom CSS.

import streamlit as st
import asyncio

# Initialize session state for chat messages
if 'chat_messages' not in st.session_state:
    st.session_state.chat_messages = []

# Render the chat messages
for message in st.session_state.chat_messages:
    with st.chat_message(message['role']):
        st.markdown(message['content'])

# Hide the prompt suggestions buttons
def hide_buttons():
    st.markdown(
        """
        <style>
        button[data-testid="stBaseButton-secondary"] {
            display: none;
        }
        </style>
        """,
        unsafe_allow_html=True,
    )

# Mock async function to generate a response
async def generate_response():
    hide_buttons()
    await asyncio.sleep(2)  # Add a 2-second async delay
    return "This is a demo response"

# Handling user input through chat input
if prompt := st.chat_input("Type your message here..."):
    st.session_state.chat_messages.append({"role": "user", "content": prompt})

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

    response = asyncio.run(generate_response())
    st.session_state.chat_messages.append({"role": "assistant", "content": response})

    # Trigger a rerun to update the chat messages
    st.rerun()

# Prompt suggestions
prompt_suggestions = [
    "What is the weather today?",
    "What is the time now?",
    "How are you doing?",
    "What is the weather tomorrow?"
]

# Handling prompt suggestions
for suggestion in prompt_suggestions:
    if st.button(suggestion):
        st.session_state.chat_messages.append({"role": "user", "content": suggestion})

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

        response = asyncio.run(generate_response())
        st.session_state.chat_messages.append({"role": "assistant", "content": response})

        # Trigger a rerun to update the chat messages
        st.rerun()

Hi, So I tried adding your custom css as a hide_buttons function like this:

def hide_buttons():
        st.markdown(
            """
            <style>
            button[data-testid="stBaseButton-secondary"] {
                display: none;
            }
            </style>
            """,
            unsafe_allow_html=True,
        )

    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"], unsafe_allow_html=True)
if st.session_state.response_options:
        button_container = st.container()
        with button_container:
            for idx, option in enumerate(st.session_state.response_options):
                if st.button(option, key=f"response_option_{idx}"):
                    hide_buttons()
                    st.session_state.messages.append({"role": "user", "content": option})
                    with st.chat_message("user"):
                        st.markdown(f'<div class="user-message">{option}</div>', unsafe_allow_html=True)
        with st.chat_message("assistant"):
                                stream = client.chat.completions.create(
                                    model=st.session_state["openai_model"],
                                    messages=[system_message, option_message],
                                    stream=True,
                                    temperature=0.1
                                )
                                option_response = st.write_stream(stream)
                            st.session_state.messages.append({"role": "assistant", "content": option_response})
                            st.session_state.response_ready = True
                            st.rerun()

But as you can see in these attached screenshots, I would like if it the selected button also disappears right now all the buttons till the selected button stays while the buttons below disappears


And also when I enter a new message myself in the chat_input it displays that weird fade to grey you can see in the screenshot. After a few seconds it does the rerun and it disappears but it lingers for a while

On my end, your code is working great! It seems like the problem might be coming from the custom CSS you’re using.

import streamlit as st
import openai
import dotenv
import os

dotenv.load_dotenv()
client = openai.Client(api_key=os.getenv("OPENAI_API_KEY"))

# Initialize session state variables if they don't exist
if "messages" not in st.session_state:
    st.session_state.messages = []

if "response_options" not in st.session_state:
    st.session_state.response_options = [
        'What is the meaning of life?',
        'What is the capital of France?',
        'What is the largest planet in the solar system?',
    ]

if "openai_model" not in st.session_state:
    st.session_state.openai_model = "gpt-4o-mini"

def hide_buttons():
    st.markdown(
        """
        <style>
        button[data-testid="stBaseButton-secondary"] {
            display: none;
        }
        </style>
        """,
        unsafe_allow_html=True,
    )

# Display chat messages
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"], unsafe_allow_html=True)

# Display response options as buttons
if st.session_state.response_options:
    button_container = st.container()
    with button_container:
        for idx, option in enumerate(st.session_state.response_options):
            if st.button(option, key=f"response_option_{idx}"):
                hide_buttons()
                st.session_state.messages.append({"role": "user", "content": option})
                with st.chat_message("user"):
                    st.markdown(f'<div class="user-message">{option}</div>', unsafe_allow_html=True)
                
                # Define system_message and option_message
                system_message = {"role": "system", "content": "You are a helpful assistant."}
                option_message = {"role": "user", "content": option}
                
                with st.chat_message("assistant"):
                    stream = client.chat.completions.create(
                        model=st.session_state["openai_model"],
                        messages=[system_message, option_message],
                        stream=True,
                        temperature=0.1
                    )
                    option_response = st.write_stream(stream)
                
                st.session_state.messages.append({"role": "assistant", "content": option_response})
                st.session_state.response_ready = True
                st.rerun()

if prompt_input := st.chat_input("Enter a message..."):
    hide_buttons()
    st.session_state.messages.append({"role": "user", "content": prompt_input})
    with st.chat_message("user"):
        st.markdown(f'<div class="user-message">{prompt_input}</div>', unsafe_allow_html=True)
    
    # Define system_message and user_message
    system_message = {"role": "system", "content": "You are a helpful assistant."}
    user_message = {"role": "user", "content": prompt_input}
    
    with st.chat_message("assistant"):
        stream = client.chat.completions.create(
            model=st.session_state["openai_model"],
            messages=[system_message, user_message],
            stream=True,
            temperature=0.1
        )
        response = st.write_stream(stream)
    
    st.session_state.messages.append({"role": "assistant", "content": response})
    st.rerun()

Screen Recording 2024-11-30 at 12.43.39 PM

Hi ! Yeah your screen recording is exactly how I pictured it, I think maybe its not seamless for me since I’m using AI to generate the response options which is then displayed as those buttons. Is it possible if you could try that and let me know how it works for you?

Basically Im using one prompt/OpenAI API call for the chatting and a separate one for the response option buttons specifically BASED ON THE AI CHATBOT’s PREVIOUS MESSAGE

So if the AI responded with something about Mumbai, the response options would be Mumbai related