英文:
Streamlit input to chat via button does not persist
问题
我有一个Streamlit应用程序,可以在文件上构建聊天机器人。
有两种上传文件的方式。从文件夹中上传("使用文件夹中的数据"按钮)和从"拖放"框中上传。
与"拖放"框的选项正常工作,但对于"使用文件夹中的数据"按钮的选项,聊天出现一次,但当我在聊天中放入问题并点击"发送"时,聊天出现了一些问题。
这是主应用程序中按钮的代码:
use_example_file = st.sidebar.button("使用文件夹中的数据")
uploaded_file = utils.handle_upload(["pdf", "txt", "csv"], use_example_file)
handle_upload函数如下:
@staticmethod
def handle_upload(file_types, use_example_file):
处理并显示已上传的文件
:param file_types: 接受的文件类型列表,例如 ["csv", "pdf", "txt"]
if use_example_file is False:
uploaded_file = st.sidebar.file_uploader("上传", type=file_types, label_visibility="collapsed")
else:
uploaded_file = open("example.csv", "rb")
if uploaded_file is not None:
以下为处理不同文件类型的函数:
- show_csv_file(显示CSV文件)
- show_pdf_file(显示PDF文件)
- show_txt_file(显示TXT文件)
根据文件扩展名显示文件内容
elif file_extension== ".pdf" :
show_pdf_file(uploaded_file)
elif file_extension== ".txt" :
show_txt_file(uploaded_file)
else:
st.session_state["reset_chat"] = True
返回已上传的文件
完整的应用程序代码如下:
加载所需库和模块的代码已省略。
设置页面配置为"wide"布局,页面图标为".",页面标题为"AI Assistant"。
初始化主要组件,并显示标题"PDF, TXT, CSV"。
加载用户API密钥,如果不存在则显示API密钥丢失信息。
如果API密钥存在,设置环境变量,然后处理文件上传。
如果文件已上传,配置侧边栏选项,显示关于信息,并初始化聊天历史。
设置聊天机器人,并根据准备就绪状态创建聊天响应和用户提示的容器。在用户输入问题后,将用户输入附加到聊天历史中,并更新显示聊天消息。
清理并显示助手的想法。生成聊天消息。
英文:
I have a streamlit app that takes a file and builds a chat bot on top of it.
There are two ways to upload files. From folder ("Use Data from folder" button) and from the "drag and drop" box.
The option with the "drag and drop" box works fine, but for the option with the "Use Data from folder" button, chat appears once, but when I put a question in chat and click "send", chat disappears for some reason.
Here code for buttons from main app:
use_example_file = st.sidebar.button("Use Data from folder")
uploaded_file = utils.handle_upload(["pdf", "txt", "csv"], use_example_file)
if uploaded_file:
[do something]
Where handle_upload
is the following function:
@staticmethod
def handle_upload(file_types, use_example_file):
"""
Handles and display uploaded_file
:param file_types: List of accepted file types, e.g., ["csv", "pdf", "txt"]
"""
if use_example_file is False:
uploaded_file = st.sidebar.file_uploader("upload", type=file_types, label_visibility="collapsed")
else:
# uploaded_file = use_example_file
# use_example_file = st.sidebar.button(use_example_file)
uploaded_file = open("example.csv", "rb")
if uploaded_file is not None:
def show_csv_file(uploaded_file):
file_container = st.expander("Your CSV file :")
uploaded_file.seek(0)
shows = pd.read_csv(uploaded_file)
file_container.write(shows)
def show_pdf_file(uploaded_file):
file_container = st.expander("Your PDF file :")
with pdfplumber.open(uploaded_file) as pdf:
pdf_text = ""
for page in pdf.pages:
pdf_text += page.extract_text() + "\n\n"
file_container.write(pdf_text)
def show_txt_file(uploaded_file):
file_container = st.expander("Your TXT file:")
uploaded_file.seek(0)
content = uploaded_file.read().decode("utf-8")
file_container.write(content)
def get_file_extension(uploaded_file):
return os.path.splitext(uploaded_file)[1].lower()
file_extension = get_file_extension(uploaded_file.name)
# Show the contents of the file based on its extension
#if file_extension == ".csv" :
# show_csv_file(uploaded_file)
if file_extension== ".pdf" :
show_pdf_file(uploaded_file)
elif file_extension== ".txt" :
show_txt_file(uploaded_file)
else:
st.session_state["reset_chat"] = True
#print(uploaded_file)
return uploaded_file
Full code for app is:
import os
import streamlit as st
from io import StringIO
import re
import sys
from modules.history import ChatHistory
from modules.layout import Layout
from modules.utils import Utilities
from modules.sidebar import Sidebar
import traceback
# load .env
from dotenv import load_dotenv
load_dotenv()
#To be able to update the changes made to modules in localhost (press r)
def reload_module(module_name):
import importlib
import sys
if module_name in sys.modules:
importlib.reload(sys.modules[module_name])
return sys.modules[module_name]
history_module = reload_module('modules.history')
layout_module = reload_module('modules.layout')
utils_module = reload_module('modules.utils')
sidebar_module = reload_module('modules.sidebar')
ChatHistory = history_module.ChatHistory
Layout = layout_module.Layout
Utilities = utils_module.Utilities
Sidebar = sidebar_module.Sidebar
st.set_page_config(layout="wide", page_icon=".", page_title="AI Assistant")
# Instantiate the main components
layout, sidebar, utils = Layout(), Sidebar(), Utilities()
layout.show_header("PDF, TXT, CSV")
user_api_key = utils.load_api_key()
# user_api_key = '.'
if not user_api_key:
layout.show_api_key_missing()
else:
os.environ["OPENAI_API_KEY"] = user_api_key
os.environ["OPENAI_API_TYPE"] = "azure"
os.environ["OPENAI_API_BASE"] = 'https://testingchat.openai.azure.com/'
os.environ["OPENAI_API_VERSION"] = "2023-05-15"
# os.environ["OPENAI_API_DEPLOYMENT_NAME"] = 'Petes-Test'
# uploaded_file = utils.handle_upload(["pdf", "txt", "csv"])
use_example_file = st.sidebar.button("Use Data from folder")
# st.write(f"use_example_file: {use_example_file}")
uploaded_file = utils.handle_upload(["pdf", "txt", "csv"], use_example_file)
# if use_example_file:
# uploaded_file = open("example.csv", "rb")
# st.write(uploaded_file)
if uploaded_file:
# Configure the sidebar
sidebar.show_options()
sidebar.about()
# Initialize chat history
history = ChatHistory()
chatbot = utils.setup_chatbot(
uploaded_file, st.session_state["model"], st.session_state["temperature"]
)
st.session_state["chatbot"] = chatbot
if st.session_state["ready"]:
# Create containers for chat responses and user prompts
response_container, prompt_container = st.container(), st.container()
with prompt_container:
# Display the prompt form
is_ready, user_input = layout.prompt_form()
# Initialize the chat history
history.initialize(uploaded_file)
# Reset the chat history if button clicked
if st.session_state["reset_chat"]:
history.reset(uploaded_file)
if is_ready:
# Update the chat history and display the chat messages
history.append("user", user_input)
old_stdout = sys.stdout
sys.stdout = captured_output = StringIO()
output = st.session_state["chatbot"].conversational_chat(user_input)
sys.stdout = old_stdout
history.append("assistant", output)
# Clean up the agent's thoughts to remove unwanted characters
thoughts = captured_output.getvalue()
cleaned_thoughts = re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', thoughts)
cleaned_thoughts = re.sub(r'\[1m>', '', cleaned_thoughts)
# Display the agent's thoughts
with st.expander("Display the agent's thoughts"):
st.write(cleaned_thoughts)
history.generate_messages(response_container)
答案1
得分: 1
根据您的描述,当您使用“从文件夹使用数据”按钮时,聊天似乎会消失,因为每次重新运行Streamlit应用程序时,文件都会被重新加载。
为了可能修复此问题,您可以使用Streamlit的会话状态来存储已上传的文件。这样,文件将在重新运行时保持不变。
以下是您可以修改的handle_upload函数的方式:
@staticmethod
def handle_upload(file_types, use_example_file):
"""
处理和显示已上传的文件
:param file_types: 接受的文件类型列表,例如,["csv", "pdf", "txt"]
"""
# 更改:检查上传的文件是否已存在于会话状态中
if "uploaded_file" not in st.session_state or st.session_state["uploaded_file"] is None:
if use_example_file is False:
# 更改:将上传的文件存储在会话状态中
st.session_state["uploaded_file"] = st.sidebar.file_uploader("上传", type=file_types, label_visibility="collapsed")
else:
st.session_state["uploaded_file"] = use_example_file
# 更改:从会话状态中使用已上传的文件
uploaded_file = st.session_state["uploaded_file"]
def show_pdf_file(uploaded_file):
file_container = st.expander("您的PDF文件:")
with pdfplumber.open(uploaded_file) as pdf:
pdf_text = ""
for page in pdf.pages:
pdf_text += page.extract_text() + "\n\n"
file_container.write(pdf_text)
def show_txt_file(uploaded_file):
file_container = st.expander("您的TXT文件:")
uploaded_file.seek(0)
content = uploaded_file.read().decode("utf-8")
file_container.write(content)
def get_file_extension(uploaded_file):
return os.path.splitext(uploaded_file)[1].lower()
# 更改:从会话状态中使用已上传的文件
file_extension = get_file_extension(st.session_state["uploaded_file"].name)
if file_extension == ".pdf":
show_pdf_file(st.session_state["uploaded_file"])
elif file_extension == ".txt":
show_txt_file(st.session_state["uploaded_file"])
P.S. 无法测试脚本。
英文:
From your description, it seems like the chat disappears when you use the "Use Data from folder" button because the file is being reloaded every time the Streamlit app reruns.
To potentially fix this, you can use Streamlit's session state to store the uploaded file. This way, the file will persist across reruns.
Here's how you can modify your handle_upload function:
P.S. Couldn't test the script out.
@staticmethod
def handle_upload(file_types, use_example_file):
"""
Handles and display uploaded_file
:param file_types: List of accepted file types, e.g., ["csv", "pdf", "txt"]
"""
# CHANGE: Check if the uploaded_file is already in the session state
if "uploaded_file" not in st.session_state or st.session_state["uploaded_file"] is None:
if use_example_file is False:
# CHANGE: Store the uploaded file in the session state
st.session_state["uploaded_file"] = st.sidebar.file_uploader("upload", type=file_types, label_visibility="collapsed")
else:
st.session_state["uploaded_file"] = use_example_file
# CHANGE: Use the uploaded file from the session state
uploaded_file = st.session_state["uploaded_file"]
def show_pdf_file(uploaded_file):
file_container = st.expander("Your PDF file:")
with pdfplumber.open(uploaded_file) as pdf:
pdf_text = ""
for page in pdf.pages:
pdf_text += page.extract_text() + "\n\n"
file_container.write(pdf_text)
def show_txt_file(uploaded_file):
file_container = st.expander("Your TXT file:")
uploaded_file.seek(0)
content = uploaded_file.read().decode("utf-8")
file_container.write(content)
def get_file_extension(uploaded_file):
return os.path.splitext(uploaded_file)[1].lower()
# CHANGE: Use the uploaded file from the session state
file_extension = get_file_extension(st.session_state["uploaded_file"].name)
if file_extension == ".pdf":
show_pdf_file(st.session_state["uploaded_file"])
elif file_extension == ".txt":
show_txt_file(st.session_state["uploaded_file"])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论