Streamlit desktop 项目的起步
框架
Streamlit 是一个用于机器学习、数据可视化的 Python 框架,它能几行代码就构建出一个精美的在线 app 应用。对于前端小白来说是可以完全不用学习各种困难的前端框架,后端使用 flask 创建各种 api 是相当简单的,而前端想要弄得美观一些则必须学习各种框架并且懂得如何美化,Streamlit 解决了这个痛点。
但是 Streamlit 原生只能部署在服务器上,使用网页端进行浏览,这对于工业软件来说是不行的,有一个日本哥们构建了一个包装后的框架以便于 Streamlit 项目包装成桌面应用。
Streamlit + Wasm + Electron = Desktop app
环境安装
Note默认已经了解并安装了 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 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])),
))
增加更多的文件或者目录
可以编辑
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"]
}
}
}
{
// ...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
并开始应用程序./build/electron/main.js
,这是指定的"main"
域中的package.json
。将会开启一个事实上的开发服务器,并且打开桌面窗口的预览。使用
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 位系统,而只能使用 0.62.0 的老版本。所以整个框架都放弃研究。