Streamlit_feedback store to s3

streamlit_feedback(feedback_type=“thumbs”,optional_text_label=“[Optional] Please provide an explanation”)

How to store the input feed to this to a S3 bucket. I have an input and response generated my model. I would like to store the user input, model response, thums feedback and text feedback to s3 as json. Please advise

Hi @rameshch16195, welcome to our community! :raised_hands:

Could you please share your code with us?

Thank you,
Charly

I would recommend using GitHub - streamlit/files-connection – you can see an example script with reading and writing here https://github.com/streamlit/files-connection/blob/main/example/streamlit_app.py

1 Like

Here is my code

s3_client = boto3.client('s3', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, aws_session_token=aws_session_token)

def on_submit(feedback_response, s3_bucket_name, s3_key_prefix):
    feedback_type = feedback_response.get("feedback_type", "")
    explanation = feedback_response.get("explanation", "")
    feedback_data = {
        "feedback_type": feedback_type,
        "explanation": explanation,
        "item": feedback_response.get("item", ""),
        "model_name": feedback_response.get("model_name", ""),
        "generated_content": feedback_response.get("generated_content", ""),
    }

    # Define the S3 object key where you want to save the feedback
    s3_key = f"{s3_key_prefix}/{feedback_data['item']}.json"

    # Upload the feedback data to the specified S3 bucket
    s3_client.put_object(Bucket=s3_bucket_name, Key=s3_key, 
    Body=json.dumps(feedback_data))

def claude_query_endpoint(model_name, prompt, params):
    body = json.dumps({"prompt": f"{anthropic.HUMAN_PROMPT} {prompt} \ {anthropic.AI_PROMPT}",
                       "max_tokens_to_sample": 6000,
                       "temperature": params['temp'],
                       "top_k": 50,
                       "top_p": params['top_p'],
                       "stop_sequences": [anthropic.HUMAN_PROMPT]})

    response = boto3_bedrock.invoke_model(body=body, modelId=model_name, accept='application/json', contentType='application/json')
    response_body = json.loads(response.get('body').read())
    claude_output_answer_raw = response_body.get('completion')
    lines = claude_output_answer_raw.split('\n')
    last_line = lines[-1]
    claude_output_answer = re.sub(r"[;.]$", "", last_line)
    return claude_output_answer

def claude_short_title(data, input_item, params, prompt, model_name='anthropic.claude-v2'):
    item = str(input_item)
    long_title = data[data['item'] == item]['item_name'].values[0]
    claude_prompt = prompt.replace("{title}", str(long_title))
    return claude_query_endpoint(model_name, claude_prompt, params)

def generate_short_title_content(model_display_name, model_function, data, input_item, prompt, params):
    st.write(f'**Model Name:** {model_display_name}')
    try:
        output_answer = model_function(data, input_item, params, prompt)
        st.text_area('**Short Title:**', output_answer, key=f'{model_display_name}st')
    except Exception as e:
        st.write(f"Failed to generate short title using {model_display_name}: {str(e)}")

def main():

    tab1 = st.tabs(["**Short Titles**"])

    with st.sidebar:
        params = app_sidebar()

    with tab1:
        st.subheader('Generate Short Product Titles ')
        input_item = st.text_input('Please input Item number:', '', key='Titles input')

        if st.button('Submit item', key='Titles button') and len(input_item) > 5:
            st.write('---')
            item = str(input_item)
            if is_item_present(item):
                long_title = df[df['item'] == item]['item_name'].values[0]
                st.write(f"**Current item Title:** {long_title}")
                st.write('---')

                # Generate content here
                generated_content = generate_content.generate_short_title_content('Anthropic Claude-v2', short_titles.claude_short_title, df, input_item, gpt_st_prompt, params)
                
                # Collect user feedback
                feedback = streamlit_feedback(feedback_type="thumbs", optional_text_label="[Optional] Please provide an explanation", on_submit=on_submit)
                
                # Get user feedback and store it
                if feedback is not None:
                    on_submit(feedback)

Please help write a code to store the thumbs and optional text feedback provided by user on the UI along with input_item and model response generated together as a JSON to S3. Any other feedback for the same input_item should get appended to the same JSON file going forward such that one JSON file is maintained per input_item in S3 bucket.

I am quite new to Streamlit and finding it difficult to achieve this functionality

@Charly_Wargnier @blackary please advise

Did you try files-connection? I think you would fine that much easier than boto3.

contents = json.loads(conn.open(json_file).read())
contents["data"].append({"new_data": "something"})
with conn.open(json_file, "wt") as f:
      json.dump(contents, f)

If that doesn’t work, could you please provide a snippet that is reproducible and as simplified as possible which shows what you have tried, and what exactly isn’t working?

I dont think the issue here is writing to s3. The issue is not being able to write the feedback coming from streamlit_feedback to S3. It must have something to with nest sted buttons or logic inside buttons. If you can help me, please check my code and suggest on what blurb i need to change

# Collect user feedback
                feedback = streamlit_feedback(feedback_type="thumbs", optional_text_label="[Optional] Please provide an explanation", on_submit=on_submit)
                
                # Get user feedback and store it
                if feedback is not None:
                    on_submit(feedback)

At a glance, the fact that you’re doing on_submit, and ALSO if feedback is not None will end up running on_submit() twice.

I would not do the if, and just rely on the on_submit=on_submit.

the on_submit function also takes too many arguments – where is it getting the s3 bucket name and s3 key prefix? Are those global constants? If they are not, and you need to pass them in, streamlit_feedback has an args argument you can pass to pass them into the function when it is called.

More importantly, you don’t seem to actually be loading the json file FIRST, and then adding the new feedback to it. Unless every single piece of feedback ends up in a different file, you will need to do that.

Hope that’s helpful.

If that doesn’t work, could you please provide a snippet that is reproducible and as simplified as possible which shows what you have tried, and what exactly isn’t working?