4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Streamlit in Snowflakeとは

Streamlitは簡単に機械学習/LLM向けのウェブアプリを簡単に作成できるオープンソースのPythonライブラリで、Streamlit in Snowflake(通称SiS)はSnowflakeのプラットフォーム上でStreamlitアプリを構築できる機能です。
SnowflakeのWeb UIであるSnowsight上でStreamlitアプリを開発・動作させることが可能です。

image.png

外部パッケージ(Stage Package)の基本

Streamlit in SnowflakeではAnacondaがメンテナンスしている独自のパッケージリポジトリを参照することができますが、以下のような手順で外部パッケージを利用することもできます。

  1. ステージを作成する(既にあるステージを使ってもいい)
  2. 作成したステージにPythonファイルをアップロードする
  3. EDIT 画面の Packages > Stage Packages から、アップロードしたPythonファイルを所定のフォーマットで指定する
  4. Streamlitアプリの画面をリロードする
  5. Streamlitプログラムから import する

具体的な指定ですが、例えばステージ名が mymodule 、Pythonファイル名が hogehoge.py であれば、以下のようになります。

  • Stage Packages で指定するPythonファイル名:@mymodule/hogehoge.py
  • import コマンド:import hogehoge

image.png

image.png

image.png

上記の場合は hogehoge.py に以下のようなプログラムを書きました。

hogehoge.py
def hello(name: str) -> str:
    return f'Hello, {name}!'

なお、Truestar社のオザワさんの記事に記載されているように、Streamlitアプリそのものが格納されているステージにPythonファイルをアップロードする方法もあります。

外部パッケージ上級編

外部パッケージにはzipファイルを指定することができます。
zipファイルをステージにアップロードして Stage Packages で指定すると、そのzipファイルに含まれているPythonファイルをimportすることができます。

以降、以下のような構造のzipファイルをサンプルを想定して記載します。

mycat.zip
 ├ mycat.py
 ├ hogehoge.py
 ├ sub/
 │ ├ __init__.py
 │ └ foobar.py
 └ static/
   └ images/
     └ cat1.jpg

Pythonファイル単体の場合と同様に、以下のような手順でzipファイルを外部パッケージとして利用することができます。

  1. ステージを作成する(既にあるステージを使ってもいい)
  2. 作成したステージにzipファイルをアップロードする
  3. EDIT 画面の Packages > Stage Packages から、アップロードしたzipファイルを所定のフォーマットで指定する
  4. Streamlitアプリの画面をリロードする
  5. Streamlitプログラムから import する

image.png

image.png

zipファイルの直下にあるPythonファイルは何もしなくても import できるのですが、サブディレクトリ配下にあるPythonファイルを import するときは、中身が空でもいいので __init__.py を含めておく必要があります。
(toru_hiyamaさんに教えていただきました。ありがとうございます!)
Pythonプログラムからは from サブディレクトリ名 importimport できます。

streamlit_app.py
import streamlit as st

# 外部パッケージをimportする
import hogehoge
from sub import foobar

message = hogehoge.hello("Kumataro")
st.write(message)

message = foobar.hello("Polar")
st.write(message)

zipファイルに含まれる他のファイルを使いたい

Pythonファイルは上記のように import できるのですが、それ以外のファイルはそのままだとアクセスできません。
例えば上記のサンプルではstatic/images/cat1.jpgというファイルが含まれていますが、外部パッケージがこのファイルを使う処理をしているとエラーが発生します。
リソースファイルや機械学習モデルがセットになっているモジュールを扱いたいときに困りますね。
これはzipファイルをすべて解凍しているのではなく、Snowflake Python UDFsの機能でzipファイルに含まれるPythonファイルだけを一時的に解凍していることに起因するようです。

以下のINSIGHT LAB様の記事では使っているのはSnowflake Python UDFsですが、これと同様の挙動になります。

解決策は、Stage Packagesで指定したzipファイルを/tmp配下に解凍することです。
Snowsight上で動かすPythonプログラムあるいは外部パッケージのいずれかで、例えば以下のような処理を書けばOKです。

mycat.py
import streamlit as st
import os
import zipfile
import glob
import random

DEFAULT_PATH: str = "/tmp/mycat"
is_deployed = False

def deploy(path=DEFAULT_PATH) -> str:
    # "/tmp/appRoot"の直下にあるzipファイルを展開する
    # os.getcwd()は呼び出すタイミングによって異なるディレクトリ("/home/udf")を返すことに注意
    # zipファイル名は__file__から取得する
    dirname = "/tmp/appRoot"
    basename = os.path.basename(os.path.dirname(__file__))
    archive_path = os.path.join(dirname, basename)
    if archive_path.endswith(".zip"):
        # 本当はロックした方がいい
        with zipfile.ZipFile(archive_path) as z:
            z.extractall(path)

    # 本当はデプロイ済みかどうかはファイルの存在で判断する
    global is_deployed
    is_deployed = True

    return path

# モジュールを読み込んだときにデプロイする
if not is_deployed:
    deploy()

# ランダムな画像をStreamlitで表示する
def show_cat(path=DEFAULT_PATH):
    lst = glob.glob(path + "/static/images/*.jpg", recursive=True)
    # ランダムで選ぶ
    img_path = random.choice(lst)
    # 画像を表示
    st.image(img_path)

上記ではモジュールを読み込んだとき( import したとき)にzipファイルを解凍する処理を書いたので、リソースファイルを参照する関数をサッと呼び出せました。
解凍する先が/tmp配下に限定されているため、パスを解決できるものに限られますが、外部パッケージの幅が広がりそうですね!

image.png

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?