You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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时看起来正常,是因为:

  1. 上传file1后,脚本重跑,清空file_contents,然后把file1的内容加入;
  2. 点击「Browse Folder」选择含file2的文件夹时,脚本再次重跑:先清空file_contents,再执行按钮逻辑添加file2内容,最后又把uploaded_files里保留的file1内容加入,所以最终两者内容都存在。

但触发st.chat_input输入内容后,脚本再次重跑:

  • 这次「Browse Folder」按钮没被点击,clickedFalse,不会执行添加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 = ""

另外还有两个优化建议:

  1. 处理文件夹选择时,可以根据需求决定是否清空之前的内容,避免多次点击按钮重复累加内容;
  2. 用tkinter做文件夹选择在Streamlit里不是最优解,Streamlit 1.11+版本支持直接用st.file_uploadertype="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

火山引擎 最新活动