はじめに
Streamlit in Snowflakeでexcelで開けるCSVにダウンロードしたい、と要望がありました。なかなか手こずったので、同じようなお困りごとをお抱えの方の一助になればと思い、記します。
ソースコード
なにはともあれソースコードです。
注)以下を実行してからプログラムを走らせてください。
CREATE OR REPLACE STAGE database.schema.TEMP_STAGE_DOWNLOAD
# Import python packages
import pandas as pd
import streamlit as st
from snowflake.snowpark.context import get_active_session
#---------------------------------------
def get_excel_download_url(df: pd.DataFrame, filename: str) -> str:
from io import BytesIO
db = session.get_current_database()
schema = session.get_current_schema()
temp_stage = "TEMP_STAGE_DOWNLOAD"
full_temp_stage = f"{db}.{schema}.{temp_stage}"
session.sql(f"CREATE OR REPLACE STAGE {full_temp_stage} ENCRYPTION = (TYPE = 'SNOWFLAKE_SSE')").collect()
in_stream = BytesIO(str.encode(df.to_csv(), encoding='SJIS'))
session.file.put_stream(in_stream, f'{full_temp_stage}/{filename}', auto_compress=False)
res = session.sql(f"select get_presigned_url(@{full_temp_stage},'{filename}', 3600) as url").collect()
url = res[0]["URL"]
return f"[Download {filename} 📥]({url})"
#---------------------------------------
session = get_active_session()
st.title("📥 Download Dataframe as Excel(csv)")
st.write(
"Try editing the dataframe below, and then click the button to download it as a excel(csv)"
)
df = pd.DataFrame(
{
"a": ['か', 'き', 'け'],
"b": [4, 5, 3],
"c": [7, 8, 9],
}
)
if st.button("Get download link"):
st.write("Generating url...")
st.write(get_excel_download_url(df, "test.csv"))
st.info("Right click and choose 'Open in new tab'")
下記頁を参考にさせていただきました。ありがとうございました。
https://github.com/Snowflake-Labs/sf-samples/tree/main/samples/streamlit-in-snowflake/download
https://community.snowflake.com/s/question/0D5Do000017uhhSKAQ/how-can-i-trigger-a-local-data-download-from-a-streamlit-app-hosted-on-the-snowsight-ui
奮闘記
ここからは私の奮闘記なので、ご興味のある方のみお読みください。
1度目の「いける!」
最初は snowpark_df.write.copy_into_location() を使いました。
パラメータのFILE FORMATにENCODING = SHIFTJIS; を指定して、いける!と思ったのですが
ENCODINGの指定はデータロードのときのみ指定できるようです。ダメでした。
2度目の「いける!」
社内から「csvkit」使えばいけるんじゃない?のアドバイスを頂きチャレンジ。
csvkit の UnicodeCSVWriter をimportしたところで怒られました。
ならば、と UnicodeCSVWriter をソースに直書き。いける!と思いました。
ステージの読み込みでエラーになりました…。
n度目の・・・
SnowflakeFile を使えばステージを読める!いける!
SnowflakeFile はstreamlitでは直接使えないので、一旦Snowsightで関数を準備して、streamlitから呼ぶようにしました。
・・・読めたけど、書けませんでした。
(この辺りからおかしくなる・・・)
♬~消せないタブが増えていく
セリフ「消したら二度と巡り合えない…そんな気がする」
マシンを落とせない夜~Ah~♪
このあとも/tmpに書いてみたり(これが出来た発見は嬉しい。また後日に報告しますね)いろいろあって
「昔は1行ずつバッファに読み込んでnバイトずつコード変換したよなぁ」と思いながらコードを書き、
n止めの「・・・もぅ、お願いします・・・」で、表示された 「 か・き・け」!
おわりに
最後まで読んでいただき、ありがとうございます。
今回は うまくいったので良かったです。粘ってもうまくいかない事の方が多いので。。。
他の方法もあるのでしょうが、今は力尽きて…うまい方法があったら、是非、教えて頂けると助かります。