フレームワーク
Streamlit は、機械学習やデータ可視化のための Python フレームワークで、数行のコードで美しいオンラインアプリを構築できます。フロントエンド初心者なら、難しいフロントエンドフレームワークを一切学ぶ必要はありません。バックエンドで Flask を使って各種 API を作成するのはかなり簡単ですが、フロントエンドをきれいに見せようとすると、さまざまなフレームワークを学び、デザインを整える方法を知る必要があります。Streamlit はこの悩みを解決してくれます。
しかし、Streamlit は標準ではサーバーにデプロイして Web ブラウザで閲覧する形しか取れず、これでは産業用ソフトウェアには向きません。そこで、ある日本のお兄さんが、Streamlit プロジェクトをデスクトップアプリとしてパッケージ化するためのラッパーフレームワークを構築しました。
環境構築
nvm と基本的な Node.js 環境はすでにインストール済みで、使い方を理解している前提です。未インストールの場合は、別のブログ記事 ブログフロントエンドの二次開発 - 土星の環の基地 を参照してください。
Python の仮想環境の作成と pip の基本的な使い方は理解している前提です。このあたりは Python の基礎です。
- 日本のお兄さんのリポジトリのチュートリアルに従って、プロジェクト用の新しいフォルダを作成し、以下の
package.jsonファイルを作成して、新しい NPM プロジェクトを始めます。nameフィールドを編集してください。
{
"name": "xxx",
"version": "0.1.0",
"main": "./build/electron/main.js",
"scripts": {
"dump": "dump-stlite-desktop-artifacts",
"serve": "cross-env NODE_ENV=production electron .",
"app:dir": "electron-builder --dir",
"app:dist": "electron-builder",
"postinstall": "electron-builder install-app-deps"
},
"build": {
"files": ["build/**/*"],
"directories": {
"buildResources": "assets"
}
},
"devDependencies": {
"@stlite/desktop": "^0.69.2",
"cross-env": "^7.0.3",
"electron": "33.3.1",
"electron-builder": "^25.1.7"
},
"stlite": {
"desktop": {
"files": ["app.py"],
"entrypoint": "app.py"
}
}
}
npm installを実行します。このとき、
npm error Cannot read properties of null (reading 'matches')やnpm error RequestError: unable to verify the first certificateといったエラーが発生します。プロジェクトフォルダ内の既存の node_modules フォルダを削除し、npm のミラー(レジストリ)と electron のミラーを設定し、npm キャッシュをクリアする必要があります。electron のミラーを変更するコマンドにはまともな方法がなく(ネット上のコマンドはどれもでたらめでした)、Windows では、C:\Usersあなたのユーザー名 フォルダにある .npmrc ファイルを以下のように変更する必要があります。
registry=https://registry.npmmirror.com
strict-ssl=false
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
その後、以下のコマンドでキャッシュをクリアしてから `npm install` を実行すれば問題ありません。npm cache clean --force
app.pyを作成し、Streamlit アプリケーションのコードを書きます。ここでは、
package.jsonの設定項目stlite.desktop.filesとstlite.desktop.entrypointがapp.pyという名前を指定しているため、ファイル名は必ずapp.pyにする必要があります。stlite.desktop.filesで指定したファイルとフォルダはデスクトップアプリにコピー・同梱され、stlite.desktop.entrypointがエントリポイントとなる Streamlit アプリケーションを指定します。
サンプルは以下のとおりです。
import altair as alt
import numpy as np
import pandas as pd
import streamlit as st
"""
# Welcome to Streamlit!
Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
forums](https://discuss.streamlit.io).
In the meantime, below is an example of what you can do with just a few lines of code:
"""
num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
indices = np.linspace(0, 1, num_points)
theta = 2 * np.pi * num_turns * indices
radius = indices
x = radius * np.cos(theta)
y = radius * np.sin(theta)
df = pd.DataFrame({
"x": x,
"y": y,
"idx": indices,
"rand": np.random.randn(num_points),
})
st.altair_chart(alt.Chart(df, height=700, width=700)
.mark_point(filled=True)
.encode(
x=alt.X("x", axis=None),
y=alt.Y("y", axis=None),
color=alt.Color("idx", legend=None, scale=alt.Scale()),
size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
))
必要な 4 つのパッケージは、新しい仮想環境を作成し、その仮想環境内で `python -m pip install altair` のようなコマンドを実行してインストールすることをお勧めします。ファイルやディレクトリを追加する
package.jsonの設定項目stlite.desktop.filesを以下のように編集できます。これらのディレクトリや py ファイルは、Streamlit アプリのルールに従う必要があります。簡単に言えば、Python プロジェクトで使うファイルをすべてここに追加すればいいということです。
{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"files": ["app.py", "pages/*.py", "assets"]
}
}
}
デスクトップアプリにインストールするパッケージを指定する
package.jsonの設定項目stlite.desktop.dependenciesを以下のように編集できます。簡単に言えば、Python プロジェクトで使うパッケージをすべてここに追加すればいいということです。
{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"dependencies": ["altair", "numpy", "pandas", "streamlit"]
}
}
}
また、`stlite.desktop.requirementsTxtFiles` を以下のように編集することもできます。これは Python の標準的な依存関係指定ファイルで、依存関係の指定をまとめて追加できます。{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"requirementsTxtFiles": ["requirements.txt"]
}
}
}
Node worker スレッドを有効にする
worker スレッドとは何か、私もまだよく分かっていませんが、現象的には、worker スレッドを有効にしないと Python コードの実行能力がなく、Pyodide が正常に起動できず、Streamlit アプリも起動できません。
stlite.desktop.nodeJsWorkerを以下のように編集します。
{
// ...other fields...
"stlite": {
"desktop": {
"nodeJsWorker": true
}
}
}
npm run dumpコマンドを使用する
./build ディレクトリが作成され、大量の雑多なファイルが含まれます。これらはすべてこのアプリケーションフレームワークに必要なものですが、後の開発サーバー用であり、実行可能なプログラムとしてリリースできるものではありません。
npm run serveコマンドを使用する
このコマンドは electron コマンドをラップしただけのもので、実際のコマンドは package.json で確認できます。electron を起動し、package.json の "main" フィールドで指定されている ./build/electron/main.js をアプリケーションとして起動します。実質的な開発サーバーが起動し、デスクトップウィンドウのプレビューが開きます。
npm run app:distコマンドを使用する
これも electron コマンドをラップしたもので、./build ディレクトリ内の諸々をまとめてインストーラを作成し、./dist フォルダに出力します。electron-builder に詳細な説明があります。
- そして、より適切なのは
npm run app:dirコマンドです。これは./buildディレクトリにインストール不要のアプリケーションを生成します。
あとがき
このフレームワークは単純なローカルアプリとしては使えず、しっかりとしたサーバー側のバックエンドサポートが必要です。私の構想では、ローカルのループバックアドレスで socketio の通信ができなかったため、使用を断念しました。
日本のお兄さんの説明 Electron security best practices by whitphx · #445 · whitphx/stlite によると、これは Electron のセキュリティベストプラクティスに適合しません。
また、彼のパッケージ化は、実際には彼が指定した Python バージョンで、私たちの package.json に指定したパッケージをダウンロードし、サンドボックスで実行するというものです。一方、私たちの産業用デスクトップアプリは 32 ビットシステムのサポートが必要ですが、Streamlit の開発計画でも 32 ビットシステムはサポートされておらず、32 ビットで使用できるのは古い 0.62.0 バージョンだけです。そのため、このフレームワーク全体の検討を断念しました。
