CrazyRyan
解決Streamlit下載後按鈕消失問題,附加下載後再觸發功能

在初次使用Streamlit的時候,使用者應該都有遇過如筆者這樣的問題

走了一段程式碼,按了下載之後,檔案下載了但是整個畫面也跳掉了,主要原因是

當點擊「下載」按鈕時,Streamlit 會觸發應用程式的重新執行。

因此,為了避免這的情況,需要加入streamlit的狀態變數,以利執行。如下圖所示之結果

為了達成以上結果,以以下程式碼當作範例

在這個重新執行過程中:

  1. 程式碼從頭執行。
  2. submit7 可能仍然為 True (取決於其來源)。
  3. 複製zip檔案處理部分執行完成。
  4. st.session_state.processed_file_path 和相關資訊被儲存到 session state。
  5. st.download_button 被渲染。由於這次重新執行是由下載按鈕的點擊觸發的,st.download_button 會返回 True,並觸發下載。同時,st.session_state.downloaded 被設定為 True。
  6. 程式碼繼續執行到 if st.session_state.downloaded: 區塊。由於 st.session_state.downloaded 現在是 True,這個區塊內的程式碼會被執行,包括打印 print(“downloaded 狀態為 True,顯示同步按鈕”) 和顯示「同步」按鈕。
def main():
    st.title("ST")
    function = st.sidebar.selectbox('脈衝啥?', ('請選擇','99) TEST'))
    if function == '99) CrazyRyan':
        st.subheader("99) CrazyRyan")
        if 'processing_done' not in st.session_state:
            st.session_state.processing_done = False # 表示檔案處理是否完成
        if 'downloaded' not in st.session_state:
            st.session_state.downloaded = False # 表示檔案是否已經被下載(點擊了下載按鈕)
        if 'ori_file_path' not in st.session_state:
            st.session_state.ori_file_path = None
        if 'processed_file_path' not in st.session_state:
            st.session_state.processed_file_path = None
        if 'json_info_data' not in st.session_state:
            st.session_state.json_info_data = None
        if 'new_zip_name' not in st.session_state:
            st.session_state.new_zip_name = None
        directory = './TEST/'
        file_list = [f for f in os.listdir(directory) 
             if f.endswith('.zip') 
             and os.path.isfile(os.path.join(directory, f))]
        file_list.sort()
        selected_file = st.selectbox("zip清單", file_list, key="selectbox_01")
        submit7 = st.button("開始運算")
        if submit7:
            file_path = os.path.join(directory, selected_file) # 要被編輯的zip
            create_file_path, new_zip_name = generate_new_file_path_C300_v2(file_path)
            print(create_file_path) # 新的要被編輯的zip
            shutil.copy(file_path, create_file_path)
            with ZipFile(file_path, 'r') as zip_ref:  # 讀取原始 ZIP 檔案
                with ZipFile(create_file_path, 'w', compression=ZIP_DEFLATED) as new_zip_file:
                    zip_file_list = zip_ref.namelist()
                    with zip_ref.open('INFO/order.json') as json_file:
                        json_info_data = json.load(json_file)
                    for file in zip_file_list:
                        new_zip_file.writestr(file, zip_ref.read(file))

            # 狀態變數,用於追蹤是否已經下載文件
            st.session_state.ori_file_path = file_path
            st.session_state.processed_file_path = create_file_path
            st.session_state.json_info_data = json_info_data
            st.session_state.new_zip_name = new_zip_name
            st.session_state.processing_done = True # 檔案處理完成

        if st.session_state.processing_done:
            if st.download_button(
                label="下載",
                data=open(st.session_state.processed_file_path, 'rb').read(),  # 讀取並傳遞檔案內容
                file_name=os.path.basename(st.session_state.processed_file_path),  # 使用檔案名稱
                mime="application/zip"  # 設定 MIME 類型
            ):
                st.session_state.downloaded = True  # 設置下載狀態為 True
                st.success("下載按鈕被點擊,已設定 downloaded = True")

        if st.session_state.processing_done and st.session_state.downloaded:
            if st.button("我已確定下載內容正確,要讓雙系統同步"):
                # 使用儲存在 session state 中的資訊
                sync_db_TEST(st.session_state.processed_file_path, st.session_state.json_info_data, st.session_state.new_zip_name)
                st.success("同步按鈕被點擊,已完成同步指令")
        pass

if __name__ == '__main__':
    main()