Streamlit (python) 应用程序按钮问题:单击按钮后显示上一个数字而不是新的随机数

问题描述 投票:0回答:1

我正在构建一个简单的 Streamlit 应用程序,作为我正在从事的更大项目的演示。目标是显示 0-100 之间的随机数字,并让用户选择是否“喜欢”该数字。用户单击“是”或“否”后,应用程序应以 JSON 格式存储该数字及其响应,然后立即显示一个新的随机数。

但是,用户点击按钮后,仍然会显示旧数字以进行另一轮选择,而不是显示下一个随机数字。只有再次单击按钮后才会出现一个新号码,但最终会将响应与新号码而不是旧号码相关联。下面是我正在使用的简化示例代码:

import streamlit as st
import random
import json

# Initialize session state to store numbers and user responses in JSON format
if "data" not in st.session_state:
    st.session_state.data = []

# Function to generate the next random number
def get_next_number():
    return random.randint(0, 100)

# Initialize the first number when the app starts
if "current_number" not in st.session_state:
    st.session_state.current_number = get_next_number()

# Function to handle the user response
def store_response(response):
    current_number = st.session_state.current_number
    st.session_state.data.append({"Number": current_number, "Response": response})
    # Generate the next random number immediately after response
    st.session_state.current_number = get_next_number()

st.title("Random Number Preference App")

# Display the current number
st.write(f"Do you like the number **{st.session_state.current_number}**?")

# Layout for the response buttons
col1, col2 = st.columns(2)

# Handling "Yes" button click
with col1:
    if st.button("Yes"):
        store_response("Yes")

# Handling "No" button click
with col2:
    if st.button("No"):
        store_response("No")

# Display the stored responses in JSON format
if len(st.session_state.data) > 0:
    st.subheader("User Responses (JSON Format)")
    st.json(st.session_state.data)

    # Allow the user to download the results as a JSON file
    json_data = json.dumps(st.session_state.data)
    st.download_button(label="Download as JSON", data=json_data, file_name="responses.json", mime="application/json")

问题:

  • 显示第一个数字后,如果用户选择“是”或“否”,则会再次显示相同的数字。
    • 最终显示下一个随机数时,之前记录的响应(例如“是”或“否”)将应用于新生成的数字,而不是用户在做出选择时看到的数字。

重现问题的步骤(带屏幕截图):

  1. 初始屏幕:
    当应用程序启动时,它会立即显示一个随机数字(例如 65)。用户会看到两个按钮“是”和“否”,以选择他们是否喜欢该号码。 enter image description here

  2. 选择“是”后:
    按“是”按钮后,应用程序仍然显示相同的数字(65)。用户可以再次点击“是”或“否”,但似乎新的随机数还没有出现。 ![Same Number After Click](attachment link)

  3. 下一个随机数出现,但响应错误:
    再次按“是”后,最终会显示一个新的随机数(在本例中为 44),但先前选择的响应(是)现在与新数字相关联,这不是预期的行为。 ![New Number with Wrong Response](attachment link)

我的期望: - 当用户单击按钮(“是”或“否”)时,应立即出现下一个数字,并且应记录当前数字的响应,而不是下一个数字。

我尝试过使用

st.session_state
管理状态并尝试过
st.experimental_rerun()
(尽管我的 Streamlit 版本不支持它),但我似乎无法让应用程序在单击按钮后立即显示新数字.

问题: - 如何让应用程序在用户选择响应后立即显示下一个随机数字,同时正确地将记录的响应与显示的数字相关联?

任何关于我所缺少的内容或替代方法的见解将不胜感激!

python button streamlit
1个回答
0
投票

您在使用 Streamlit 应用程序时遇到的问题主要是由于 Streamlit 执行脚本的顺序以及每次重新运行期间的状态管理方式造成的。让我们分解根本原因并提供解决方案以确保您的应用程序按预期运行。

根本原因

1 - Streamlit 的执行模型:

  • 每次交互时都会重新运行脚本:每次用户与应用程序交互(例如,单击按钮)时,Streamlit 都会从上到下重新运行整个脚本。

  • 操作顺序:在原始代码中,在处理按钮单击之前初始化并显示当前数字。这会导致同步问题,显示的数字在响应后不会立即更新。

2 - 状态管理时序:

显示后更新状态:当用户单击“是”或“否”时,应用程序会在该交互的显示逻辑运行后更新 current_number 。因此: 立即再次显示相同的数字。 在后续交互中,响应会错误地与下一个数字相关联。 解决方案

要解决此问题,请在初始化或显示当前号码之前处理用户交互(按钮单击)。这可确保响应与显示的数字正确关联,并在响应后立即生成新数字。

逐步修复

重新排列脚本:

  • 首先处理按钮点击:将按钮处理逻辑移至当前号码的初始化和显示上方。

  • 显示前更新状态:确保在将号码呈现给用户之前发生任何状态更改(例如更新 current_number)。

修改后的代码示例:

import streamlit as st
import random
import json

# Initialize session state to store numbers and user responses in JSON format
if "data" not in st.session_state:
    st.session_state.data = []

# Function to generate the next random number
def get_next_number():
    return random.randint(0, 100)

# Function to handle the user response
def store_response(response):
    current_number = st.session_state.current_number
    st.session_state.data.append({"Number": current_number, "Response": response})
    # Generate the next random number immediately after response
    st.session_state.current_number = get_next_number()

st.title("Random Number Preference App")

# Handle button clicks BEFORE initializing or displaying the current number
col1, col2 = st.columns(2)

with col1:
    if st.button("Yes"):
        store_response("Yes")

with col2:
    if st.button("No"):
        store_response("No")

# Initialize the current number AFTER handling button clicks
if "current_number" not in st.session_state:
    st.session_state.current_number = get_next_number()

# Display the current number
st.write(f"Do you like the number **{st.session_state.current_number}**?")

# Display the stored responses in JSON format
if st.session_state.data:
    st.subheader("User Responses (JSON Format)")
    st.json(st.session_state.data)

    # Allow the user to download the results as a JSON file
    json_data = json.dumps(st.session_state.data)
    st.download_button(
        label="Download as JSON",
        data=json_data,
        file_name="responses.json",
        mime="application/json"
    )
© www.soinside.com 2019 - 2024. All rights reserved.