St.feedback with thumbs is not giving results

I’m building a chatbot application for my company. I’m using streamlit 1.39.0 version. I’m trying to capture user feedback, so I implemented below code from “st.feedback - Streamlit Docs” after AI response, but after selecting a response I’m still getting None in ‘selected’ field.

sentiment_mapping = [“:material/thumb_down:”, “:material/thumb_up:”]
selected = st.feedback(“thumbs”)
if selected is not None:
st.markdown(f"You selected: {sentiment_mapping[selected]}")

Can you share a bit more context about how you have st.feedback within your chat app? Since the code works by itself as shown in the example within docs, there should be something else that’s impacting the behavior.

Thanks much for responding.

Here is a bit more code…

I’m able to see the thumps-up and down after AI response, but it’s immediately going to the else condition st.markdown(f"You did not select"), which mean it’s not waiting for user to choose the feedback. Also, upon choosing a feedback, the thumbs up and down are gone without capturing the feedback in ‘selected’ variable.

from dotenv import load_dotenv
from langchain_core.messages import AIMessage, HumanMessage
import streamlit as st
import requests
import os
import logging


# Claude API endpoint and key
url = llm-url
api_key = os.getenv("key")



# Function to handle API call and response formatting
def get_response(api_name, api_inputs, user_query, user_role, chat_history):
    fetch_function = API_CONFIG[api_name]["fetch_function"]

    # Pass the `api_name` (config_key) as the first argument to the fetch function
    api_data = fetch_function(api_name, **api_inputs)

    # Define the template and prompt
    template = """
    template details goes here"""
    formatted_prompt = template.format(api_data=api_data, question=user_query, role=user_role)

    model = "model-name"
    body = {
        "model": model,
        "messages": [
            {"role": "system",
             "content": "You are a helpful assistant that responds to user queries based on provided API data."},
            {"role": "user", "content": formatted_prompt}
        ]
    }

    # Make the API call to Claude
    response = requests.post(url, json=body, headers={
        "Content-Type": "application/json",
        "Authorization": api_key,
    })

        
def handle_ai_response(response):
    """Function to handle displaying AI response and feedback."""
    with st.chat_message("AI", avatar=ai_avatar):
        st.markdown(response)  # Display the AI response
        st.session_state.chat_history.append(AIMessage(content=response))  # Add AI response to chat history

        sentiment_mapping = [":material/thumb_down:", ":material/thumb_up:"]
        selected = st.feedback("thumbs")
        if selected is not None:
            st.markdown(f"You selected: {sentiment_mapping[selected]}")
        else:
            st.markdown(f"You did not select")

# Define paths to the avatar images
human_avatar = "images/human.svg"
ai_avatar = "images/ai.svg"

for message in st.session_state.chat_history:
    if isinstance(message, AIMessage):
        with st.chat_message("AI", avatar=ai_avatar):
            st.markdown(message.content)
    elif isinstance(message, HumanMessage):
        with st.chat_message("Human", avatar=human_avatar):
            st.markdown(f"You: {message.content}")

# Input through chat box
user_query = st.chat_input("Type a message...")
if user_query and user_query.strip():
    st.session_state.chat_history.append(HumanMessage(content=user_query))

    with st.chat_message("Human", avatar=human_avatar):
        st.markdown(user_query)

    # Call the refactored function to handle AI response
    response = get_response(selected_api, api_inputs, user_query, selected_role, st.session_state.chat_history)
    handle_ai_response(response)

Please can you edit your post so that your code is in a code block? Use a triple backtick at the beginning and end, or use the <> icon in the editor toolbar.

Just a quick hint from what I can gather from the unformatted code. (Just a gut guess since I can’t properly see your whitespace yet. )

You’ll likely want to handle feedback separately from the new response.

  1. You have your app ready for user input. User submits a response → Rerun.
  2. The AI response is handled in handle_ai_resonse which adds the response to history and shows the feedback widget (which has value None). If you click the feedback widget → Rerun.
  3. On the rerun where you want to get the value of the feedback, you aren’t in the handle_ai_response function anymore.

Thanks for the reply. I changed my code to appear in code block.

Looking at your code, I think my initial guess is correct: as soon as you click the feedback, the app reruns and now that last response becomes part of the history and I expect the feedback widget to disappear. What are you wanting to do with the feedback information when you receive it? Are you wanting to save it and show it in the history for every AI response in the history, or something else?

I want to save it in a feedback log file.

Here’s a toy example that saves the last user + AI message with feedback to a file. If a user doesn’t give feedback on some response, it’s skipped.

If you want to save then entire conversation, you could write all messages to the file and just append the feedback when given. You could also add the feedback to the message dict in Session State then write the whole conversation to a file when done. If you need to persist the feedback widgets in the conversation throughout, you’ll need to introduce keys (such as the numerical position of the message in the history) and maybe add a third key to the AI messages (“role”,“content”,“feedback”).

import streamlit as st

def bot():
    yield "Hi"

if "messages" not in st.session_state:
    st.session_state.messages = []
if "get_feedback" not in st.session_state:
    st.session_state.get_feedback = False

def save_feedback():
    with  open("myfile.txt", "a") as f:
        f.write(str(st.session_state.messages[-2]["role"])+"\n")
        f.write(str(st.session_state.messages[-2]["content"])+"\n")
        f.write(str(st.session_state.messages[-1]["role"])+"\n")
        f.write(str(st.session_state.messages[-1]["content"])+"\n")
        f.write(str(st.session_state.feedback)+"\n")
    st.session_state.get_feedback = False

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

if prompt := st.chat_input("Say something"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)
    with st.chat_message("assistant"):
        stream = bot() # Shorthand for some AI streamed
        response = st.write_stream(stream)
    st.session_state.messages.append({"role": "assistant", "content": response})
    st.session_state.get_feedback = True

if st.session_state.get_feedback:
    st.feedback("thumbs", key="feedback", on_change=save_feedback)

“on_change=save_feedback” makes all difference. Now it’s working. Thanks a lot for the reply.