St.button and st.chat_message not working together

Hello. I’m making a chatbot using OpenAI api and streamlit cloud.
And I wanted to make a button to rerun the script and show another responses to the user if that user did not like the previous one.
So I made a small button, right side of the assistant’s message, and wanna see whether it’s working or not.
But it is not working as it supposed to be. It doesn’t write ‘maybe’.
Can you figure out what is the problem of my code?

from openai import OpenAI
import streamlit as st
import time

st.set_page_config(
    page_title="Some AI website",
    page_icon="🧊",
    layout="wide",
    initial_sidebar_state="collapsed"
)

if 'client' not in st.session_state:
  st.session_state.client = OpenAI(api_key=st.secrets['api_key'])

if "messages" not in st.session_state:
    st.session_state["messages"] = [{"role": "assistant", "content": "Hi! How can I help you?"}]

for msg in st.session_state.messages:
    st.chat_message('assistant').write(msg["content"])

if prompt := st.chat_input():
    st.session_state.messages.append({"role": "user", "content": prompt})
    st.chat_message("user").write(prompt)
    progress_text='thinking...'
    my_bar=st.progress(0,text=progress_text)
    
    system_prompt='Some weird prompt'
    
    user_prompt_1="also some weird prompt"
    
    response = st.session_state.client.chat.completions.create(
  model="gpt-3.5-turbo-0125",
  messages=[
    {
      "role": "system",
      "content": f"{system_prompt}"
    },
    {
      "role": "user",
      "content": f"{user_prompt_1}"
    }
  ],
  temperature=1,
  max_tokens=1028,
  top_p=0.9,
  frequency_penalty=1,
  presence_penalty=1
)
    my_bar.progress(75,text=progress_text)
    msg = response.choices[0].message.content
    st.session_state.messages.append({"role": "assistant", "content": msg})
    my_bar.progress(100,text=progress_text)
    my_bar.empty()
    
    col1,col2=st.columns([9,1])
    with col1:
      st.chat_message("assistant").write(msg)
      if 'reset_response' not in st.session_state:
        st.write('not sure')
      if 'reset_response' in st.session_state:
         st.write('maybe')
    with col2:
       if st.button('🔄'):
          st.session_state.reset_response=True

1 Like

I like that intention.

Looking at the code, your rerun button if st.button('🔄'): is under the if prompt := st.chat_input(): condition and the moment we click that button, the code is re-run yes but we cannot pass through the condition"

if prompt := st.chat_input():

why? because that prompt is empty or None now, hence we cannot reach the code,

response = st.session_state.client.chat.completions.create()

The user needs to input again the same prompt send it for the bot to reply.

There can be many ways to work around on it. Let us think about it.

2 Likes

One approach, press the button (use callback function in the button), rerun the code, input back the last prompt.

if 'repeat' not in st.session_state:
    st.session_state.repeat = False

def reply_again_cb():
    st.session_state.repeat = True

if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

    # Get the last user prompt in the msg history.
    if st.session_state.repeat:
        prompt = st.session_state.messages[-2]['content']
        st.session_state.repeat = False  # reset

    st.session_state.messages.append({"role": "user", "content": prompt})

    ...

    st.button('Give me another answwer', on_click=reply_again_cb)

This is our new prompt line to allow us to enter the bot response line.

if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

Full code

from openai import OpenAI
import streamlit as st


# variables
if "messages" not in st.session_state:
    st.session_state.messages = []

if 'repeat' not in st.session_state:
    st.session_state.repeat = False


# functions
def reply_again_cb():
    st.session_state.repeat = True


def main():
    model = 'gpt-3.5-turbo'
    st.title(f"Chat with {model}")

    client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

    if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

        # Get the last user prompt in the msg history.
        if st.session_state.repeat:
            prompt = st.session_state.messages[-2]['content']
            st.session_state.repeat = False  # reset

        st.session_state.messages.append({"role": "user", "content": prompt})

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

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

            response = st.write_stream(stream)

        st.session_state.messages.append({"role": "assistant", "content": response})

        st.button('Give me another answwer', on_click=reply_again_cb)


if __name__ == '__main__':
    main()
2 Likes

@ferdy

First of all, thank you so much for helping me sir.
I read carefully about your suggestion, found out it works marvelously and could see what was missing in my previous codes.

But I couldn’t figure out how to change ‘only’ the last reply that chatbot gave to the user.
In this example that you gave to me, this also adds the user prompt over and over.
How can I change the chatbot’s reply after pressing the button while not adding the user’s latest reply to the conversation?

@fendy

This is my attempt to do it but I could not figure out how to nail it tho

from openai import OpenAI
import streamlit as st


# variables
if "messages" not in st.session_state:
    st.session_state.messages = []

if 'repeat' not in st.session_state:
    st.session_state.repeat = False

if 'append_prompt' not in st.session_state:
    st.session_state.append_prompt = True

# functions
def reply_again_cb():    
    st.session_state.repeat = True
    st.session_state.append_prompt = False

def main():
    model = 'gpt-3.5-turbo'
    st.title(f"Chat with {model}")

    client = OpenAI(api_key=st.secrets['api_key'])

    for message in st.session_state.messages:
        if len(st.session_state.messages)==2:
            if st.session_state.append_prompt==False:
                st.session_state.messages=st.session_state.messages[:-1]
        if len(st.session_state.messages)>2:
            if st.session_state.append_prompt==False:
                st.session_state.messages=st.session_state.messages[:-1]
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

    if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

        # Get the last user prompt in the msg history.
        if st.session_state.repeat:
            if st.session_state.append_prompt==False:
                if len(st.session_state.messages)==1:
                    prompt = st.session_state.messages[0]['content']
                    st.session_state.repeat = False  # reset
                    st.session_state.append_prompt = False
            if st.session_state.append_prompt==False:
                if len(st.session_state.messages)>1:
                    prompt = st.session_state.messages[-1]['content']
                    st.session_state.repeat = False  # reset
                    st.session_state.append_prompt = False

        if st.session_state.append_prompt==False:
            pass         
        if st.session_state.append_prompt==True:
            st.session_state.messages.append({"role": "user", "content": prompt})
            st.session_state.append_prompt=False
            with st.chat_message("user"):
                st.markdown(prompt)

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

            response = st.write_stream(stream)

        st.session_state.messages.append({"role": "assistant", "content": response})

        st.button('Give me another answwer', on_click=reply_again_cb)


if __name__ == '__main__':
    main()

@ferdy

I did another try and it works bit better, but after few conversations when I press button, it erases all the dialogue and restart from my very last reply. Idk what is happening.

from openai import OpenAI
import streamlit as st


# variables
if "messages" not in st.session_state:
    st.session_state.messages = []

if 'repeat' not in st.session_state:
    st.session_state.repeat = False


# functions
def reply_again_cb():
    st.session_state.repeat = True


def main():
    model = 'gpt-3.5-turbo'
    st.title(f"Chat with {model}")

    client = OpenAI(api_key=st.secrets["api_key"])

    for message in st.session_state.messages:
        if st.session_state.repeat == True:
            pass
        if st.session_state.repeat == False:
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

    if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

        # Get the last user prompt in the msg history.
        if st.session_state.repeat:
            prompt = st.session_state.messages[-2]['content']
            st.session_state.messages=st.session_state.messages[:-2]
            st.session_state.repeat = False  # reset
        if st.session_state.repeat==False:
            st.session_state.messages.append({"role": "user", "content": prompt})
            with st.chat_message("user"):
                st.markdown(prompt)

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

            response = st.write_stream(stream)

        st.session_state.messages.append({"role": "assistant", "content": response})

        st.button('Give me another answwer', on_click=reply_again_cb)


if __name__ == '__main__':
    main()

Here is the modification to the code I posted to not print repeated prompt from the user.

We still store the repeated user prompt in the msg history, but we will not print it.

There are two locations where the msgs are printed, first in the whole history printing and second right after the prompt.

In the first part we try to detect the repetition, if there is we will not print it.

    # Print msg history.
    last_user_message = None
    for message in st.session_state.messages:

        # Print the user msg if it is not repeating successively.
        if (last_user_message is not None and
            message['role'] == 'user' and
            last_user_message == message["content"]
        ):
            pass
        else:
            # Print both msgs from user and assistant
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        # Backup last user msg used to identify successive same user content.
        if message['role'] == 'user':
            last_user_message = message["content"]

In the second part, we only print if repeat is false.

    if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

        # Get the last user prompt in the msg history.
        if st.session_state.repeat:
            prompt = st.session_state.messages[-2]['content']
            st.session_state.repeat = False  # reset
        else:
            # Only print the user msg if repeat is false.
            with st.chat_message("user"):
                st.markdown(prompt)

        # Always backup the conversation.
        st.session_state.messages.append({"role": "user", "content": prompt})

Complete code

from openai import OpenAI
import streamlit as st


# variables
if "messages" not in st.session_state:
    st.session_state.messages = []

if 'repeat' not in st.session_state:
    st.session_state.repeat = False


# functions
def reply_again_cb():
    st.session_state.repeat = True


def main():
    model = 'gpt-3.5-turbo'
    st.title(f"Chat with {model}")

    client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

    # Print msg history.
    last_user_message = None
    for message in st.session_state.messages:

        # Print the user msg if it is not repeating successively.
        if (last_user_message is not None and
            message['role'] == 'user' and
            last_user_message == message["content"]
        ):
            pass
        else:
            # Print both msgs from user and assistant
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        # Backup last user msg used to identify successive same user content.
        if message['role'] == 'user':
            last_user_message = message["content"]

    if prompt := st.chat_input("enter your prompt") or st.session_state.repeat:

        # Get the last user prompt in the msg history.
        if st.session_state.repeat:
            prompt = st.session_state.messages[-2]['content']
            st.session_state.repeat = False  # reset
        else:
            # Only print the user msg if repeat is false.
            with st.chat_message("user"):
                st.markdown(prompt)

        # Always backup the conversation.
        st.session_state.messages.append({"role": "user", "content": prompt})

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

            response = st.write_stream(stream)

        st.session_state.messages.append({"role": "assistant", "content": response})

        st.button('Give me another answwer', on_click=reply_again_cb)


if __name__ == '__main__':
    main()

Test output

@ferdy

I fiddled with my code quite a bit to use this into my code and finally I think it works!
Thank you so much

1 Like

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