Streamlit通过按钮输入到聊天不会持久保存。

huangapple go评论82阅读模式
英文:

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"])

huangapple
  • 本文由 发表于 2023年6月16日 02:25:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484525.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定