Streamlit desktop 项目的起步

框架

Streamlit 是一个用于机器学习、数据可视化的 Python 框架，它能几行代码就构建出一个精美的在线 app 应用。对于前端小白来说是可以完全不用学习各种困难的前端框架，后端使用 flask 创建各种 api 是相当简单的，而前端想要弄得美观一些则必须学习各种框架并且懂得如何美化，Streamlit 解决了这个痛点。

但是 Streamlit 原生只能部署在服务器上，使用网页端进行浏览，这对于工业软件来说是不行的，有一个日本哥们构建了一个包装后的框架以便于 Streamlit 项目包装成桌面应用。

Streamlit + Wasm + Electron = Desktop app

whitphx/stlite: In-browser Streamlit 🎈🚀

环境安装

[!NOTE]

默认已经了解并安装了 nvm 以及基础的 node.js 环境，没安装的请看另一篇博文 博客前端的二次开发 - 土星环的基地 。

默认已经了解了 python 的虚拟环境创建以及 pip 基本用法，这部分是 python 基础。

依据日本哥们仓库里的教程，新建一个文件夹作为项目文件夹，创建以下 package.json 文件开始一个新的 NPM 项目，编辑 name 字段。

Copy
{
"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 文件为如下。

Copy
registry=https://registry.npmmirror.com
strict-ssl=false
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/

然后执行以下指令清除缓存，再运行 npm install 就没问题了。

Copy
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 应用程序。

一个示例如下

Copy
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 项目里用到哪些文件这里就统统添加进去。

Copy
{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"files": ["app.py", "pages/*.py", "assets"]
}
}
}

指定软件包安装在桌面应用程序里

可以编辑 package.json 中相关配置项 stlite.desktop.dependencies 类似如下，简单来说就是 python 项目里用到哪些包就统统添加进去。

Copy
{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"dependencies": ["altair", "numpy", "pandas", "streamlit"]
}
}
}

也可以编辑 stlite.desktop.requirementsTxtFiles 类似如下，这是 python 的标准依赖指定文件，可以添加一系列依赖指定。

Copy
{
// ...other fields...
"stlite": {
"desktop": {
// ...other fields...
"requirementsTxtFiles": ["requirements.txt"]
}
}
}

开启 node worker 线程

所谓的 worker 线程是什么我也还没弄清楚，现象上来看不开启 worker 线程就不具备 python 代码的运行能力，Pyodide 无法正常启用，Streamlit 应用会无法开启。

编辑 stlite.desktop.nodeJsWorker 类似如下。

Copy
{
// ...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 的老版本。所以整个框架都放弃研究。

此文由 Mix Space 同步更新至 xLog
原始链接为 https://www.yono233.cn/posts/shoot/25_1_15_Streamlit_desktop