Streamlit中使用st.chat_input后session_state.file_contents丢失文件夹选中文件内容的问题求助
Streamlit中使用st.chat_input后session_state.file_contents丢失文件夹选中文件内容的问题求助
兄弟,我来帮你拆解下这个问题的根源,其实是Streamlit的脚本重跑机制和你对st.session_state的初始化方式不当导致的!
问题核心原因
首先得明确:Streamlit的每一次交互(比如点击按钮、输入聊天内容、上传文件)都会从头重新运行整个Python脚本。
看你原来的代码开头直接写了:
st.session_state.file_contents = ""
这就意味着每次页面重跑,都会把file_contents强制清空成空字符串!
之前没加st.chat_input时看起来正常,是因为:
- 上传
file1后,脚本重跑,清空file_contents,然后把file1的内容加入; - 点击「Browse Folder」选择含
file2的文件夹时,脚本再次重跑:先清空file_contents,再执行按钮逻辑添加file2内容,最后又把uploaded_files里保留的file1内容加入,所以最终两者内容都存在。
但触发st.chat_input输入内容后,脚本再次重跑:
- 这次「Browse Folder」按钮没被点击,
clicked为False,不会执行添加file2内容的逻辑; - 但开头的清空代码依然会把
file_contents置空,之后只执行了添加uploaded_files(即file1)的逻辑,所以file2的内容就丢失了!
解决方案
核心就是不要每次重跑都重置file_contents,只在第一次初始化时设置为空。把开头的初始化代码改成判断式:
# 仅当session_state中没有file_contents时才初始化 if "file_contents" not in st.session_state: st.session_state.file_contents = ""
另外还有两个优化建议:
- 处理文件夹选择时,可以根据需求决定是否清空之前的内容,避免多次点击按钮重复累加内容;
- 用tkinter做文件夹选择在Streamlit里不是最优解,Streamlit 1.11+版本支持直接用
st.file_uploader的type="folder"参数选择文件夹,更贴合框架交互逻辑,无需额外引入tkinter:
folder = st.file_uploader("Select a folder", type="folder") if folder is not None: for file in folder.files: st.session_state.file_contents += file.read().decode('utf-8') + "\n"
修改后的核心代码示例:
import streamlit as st import os import pandas as pd from pathlib import Path # 初始化session_state,避免每次重跑清空内容 if "file_contents" not in st.session_state: st.session_state.file_contents = "" if "messages" not in st.session_state: st.session_state.messages = [] uploaded_files = st.file_uploader("Upload your Python/SQL/C file", type=["py","sql","c"], accept_multiple_files=True) # 处理上传的文件,避免重复添加 for uploaded_file in uploaded_files: content = uploaded_file.read().decode('utf-8') + "\n" if content not in st.session_state.file_contents: st.session_state.file_contents += content # 处理文件夹选择(保留tkinter版本) st.write('Please select a folder:') clicked = st.button('Browse Folder') if clicked: # 可根据需求选择是否清空之前的内容 # st.session_state.file_contents = "" import tkinter as tk from tkinter import filedialog root = tk.Tk() root.withdraw() root.wm_attributes('-topmost', 1) dirname = str(filedialog.askdirectory(master=root)) files = [file for file in os.listdir(dirname)] output = pd.DataFrame({"File Name": files}) st.table(output) for file in files: content = Path(os.path.join(dirname, file)).read_text() if content not in st.session_state.file_contents: st.session_state.file_contents += content # 聊天框逻辑 if uploaded_files or st.session_state.file_contents or st.session_state.messages: for message in st.session_state.messages: if message["role"] == "user": st.chat_message("human").markdown(message["content"]) if message["role"] == "ai": st.chat_message("ai").markdown(message["content"]) if prompt := st.chat_input("Generate test cases for the attached file(s)"): st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) print("File content before calling a function:",st.session_state.file_contents)
这样修改后,不管是点击文件夹按钮还是触发聊天输入,file_contents都不会被无故清空,之前添加的内容都会保留啦!
备注:内容来源于stack exchange,提问作者ankit




