Streamlit聊天应用Spinner不显示,任务完成后才更新UI
Streamlit聊天应用Spinner不显示问题修复
问题原因
st.rerun()时机错误:原代码在st.spinner块内直接调用st.rerun(),导致Spinner还未完成前端渲染就触发页面重载,用户看不到加载状态。- UI批量更新机制:Streamlit会在脚本执行完毕或遇到特定交互时才批量更新UI,阻塞式的
time.sleep()会让整个脚本暂停,直到休眠结束才一次性渲染所有UI变化,包括Spinner和新消息,因此用户看不到中间的加载动画。
修复方案
调整代码流程,确保Spinner先渲染完成再执行阻塞操作,同时避免不必要的提前页面重载:
修改后的主应用代码
import streamlit as st import time from sensei.ui import text, utils # 处理用户输入 if user_response := st.chat_input(placeholder="Your response..."): st.session_state.messages.append({"name": "user", "avatar": "user", "content": user_response}) # 初始化聊天会话 if "messages" not in st.session_state: st.session_state["messages"] = [ {"name": "Sensei", "avatar": "🥷", "content": message, "translated": True, "printed": False} for message in text.ONBOARDING_START_MESSAGES[st.session_state.source_language] ] # 添加处理状态标记,防止重复执行响应生成逻辑 if "processing_response" not in st.session_state: st.session_state.processing_response = False # 渲染历史聊天消息 for message in st.session_state.messages: with st.chat_message(name=message["name"], avatar=message["avatar"]): if message["name"] == "Sensei" and not message["printed"]: utils.stream_message(message=message["content"]) message["printed"] = True else: st.markdown(body=message["content"]) # 生成Sensei的响应 if st.session_state.messages[-1]["name"] == "user" and not st.session_state.processing_response: st.session_state.processing_response = True with st.spinner("Thinking..."): # 模拟LLM响应生成 sensei_response = utils.temp_get_response() # 添加响应到会话 st.session_state.messages.append( {"name": "Sensei", "avatar": "🥷", "content": sensei_response, "translated": True, "printed": False} ) st.session_state.processing_response = False # 刷新页面显示新消息 st.rerun()
关键修改点
- 移除重复的
st.chat_input,避免组件冲突。 - 添加
processing_response状态标记,防止Streamlit脚本重复执行响应生成逻辑(因为Streamlit会多次重跑脚本)。 - 将
st.rerun()移至st.spinner块外部,确保Spinner在休眠期间正常显示,完成响应生成后再触发页面刷新。 - 调整代码顺序,让用户输入处理、会话初始化、消息渲染、响应生成的流程更清晰。
可选优化:使用st.status增强加载体验
如果需要更灵活的状态提示,可以替换st.spinner为st.status,支持状态更新:
if st.session_state.messages[-1]["name"] == "user" and not st.session_state.processing_response: st.session_state.processing_response = True with st.status("Thinking...", expanded=True) as status: sensei_response = utils.temp_get_response() status.update(label="Response ready!", state="complete", expanded=False) st.session_state.messages.append( {"name": "Sensei", "avatar": "🥷", "content": sensei_response, "translated": True, "printed": False} ) st.session_state.processing_response = False st.rerun()
内容的提问来源于stack exchange,提问作者KOB
相关产品推荐
相关产品推荐

