用 PyWebView + React 造了一个 ChromaDB 桌面客户端

0 阅读4分钟

用 PyWebView + React 造了一个 ChromaDB 桌面客户端

背景

在用 ChromaDB 做本地向量数据库开发时,调试过程相当繁琐——要么写脚本查数据,要么对着 HTTP 接口手敲 curl。官方没有提供图形化管理界面,社区里的 Web 方案又需要额外起服务、开浏览器,体验割裂。

所以我用业余时间做了 Chroma Walnut UI:一个基于 PyWebView + React 的原生桌面客户端,支持 Windows / macOS / Linux,无需安装 Python 环境即可直接运行。

GitHub:github.com/[your-githu…


功能一览

  • 多连接管理:同时管理多个 ChromaDB 连接(本地目录 / HTTP 服务),支持 Bearer Token 认证,一键测试连通性
  • 集合管理:创建、重命名、编辑 Metadata、删除集合
  • 文档浏览:分页展示(10 / 20 / 30 条可选),Metadata 彩色标签,支持查看完整 JSON 和框选复制
  • 向量搜索:配置嵌入模型后输入文本即可进行语义相似度搜索,支持多条件过滤
  • 向量模型配置:集合级别配置,兼容 OpenAI Embeddings 格式,内置 Ollama / OpenAI / LM Studio / 通义千问快速填充
  • 一键生成测试数据:内置 50 条中文示例文档,配置好模型后一键插入
  • 国际化 + 主题切换:中文 / English 随时切换,支持亮色 / 暗色 / 跟随系统

screenshot-welcome.png

screenshot-overview.png


技术选型

选择原因
桌面容器PyWebView 6用系统原生 WebView 渲染,无需 Electron,包体极小
后端Python 3.12 + ChromaDB 0.6ChromaDB 官方 Python SDK,直接调用,无 HTTP 中转
前端框架React 19 + TypeScript生态成熟,类型安全
UI 组件库Ant Design 6开箱即用的企业级组件,内置暗色主题
状态管理Zustand 5轻量,不需要 Redux 那么重
国际化i18next + react-i18next标准方案,切换零刷新
构建工具Vite 8开发热更新快,构建产物小
Python 包管理uv比 pip 快 10-100 倍,lockfile 可靠
打包PyInstaller三平台统一打包脚本

为什么选 PyWebView 而不是 Electron?

Electron 打包出来动辄 150MB+,本质上是把 Chromium 塞进去。PyWebView 直接调用操作系统已有的 WebView:

  • Windows:Edge WebView2(Windows 10 1803+ 内置)
  • macOS:WKWebView(系统内置)
  • Linux:WebKitGTK

最终打包产物 Windows 约 40MB,用户无需安装 Python 或 Node.js,解压即用。


架构设计

┌─────────────────────────────────────┐
│           PyWebView 窗口             │
│  ┌──────────────────────────────┐   │
│  │    React 前端(TypeScript)   │   │
│  │   Ant Design / Zustand       │   │
│  └──────────┬───────────────────┘   │
│             │ window.pywebview.api  │
│  ┌──────────▼───────────────────┐   │
│  │     Python API 层 (api.py)   │   │
│  │   ChromaManager              │   │
│  │   Embedding 配置管理          │   │
│  └──────────┬───────────────────┘   │
│             │                       │
│  ┌──────────▼───────────────────┐   │
│  │         ChromaDB SDK         │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘

前后端通信走 PyWebView 的 js_api 机制:Python 类的公开方法自动暴露为 window.pywebview.api.*,前端通过 TypeScript 封装的 bridge 调用,类型安全有保障。

// frontend/src/api/bridge.ts(精简示例)
export const api = {
  listConnections: () =>
    window.pywebview.api.list_connections() as Promise<Connection[]>,
  queryDocuments: (connId: string, collection: string, params: QueryParams) =>
    window.pywebview.api.query_documents(connId, collection, params),
}

几个实现细节

单实例锁

用绑定本地端口的方式实现单实例,进程退出时端口自动释放,跨平台无需平台特定 API:

_INSTANCE_PORT = 19527

def _acquire_instance_lock() -> bool:
    global _instance_sock
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)
        s.bind(("127.0.0.1", _INSTANCE_PORT))
        s.listen(1)
        _instance_sock = s
        return True
    except OSError:
        return False

开发模式 vs 生产模式

# 开发模式:前端走 Vite 热更新
uv run python main.py --dev

# 生产模式:先 npm run build,再加载 dist/index.html
uv run python main.py

main.py 启动时检测 --dev 参数,自动拉起 Vite dev server 并等待端口就绪后再创建窗口,开发体验与纯前端项目一致。

响应式布局

窗口宽度 < 1100px 时侧边栏自动折叠,字体和间距用 CSS clamp() 自适应缩放,适配从 900px 到 1920px 的各种分辨率。

向量模型兼容设计

Chroma Walnut UI 不绑定任何特定的向量服务,只要接口兼容 OpenAI Embeddings 格式(POST /v1/embeddings)就可以接入:

服务地址示例
Ollamahttp://localhost:11434/v1/embeddings
OpenAIhttps://api.openai.com/v1/embeddings
LM Studiohttp://localhost:1234/v1/embeddings
通义千问https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings

配置保存在 ~/.chroma_walnut_ui/collection_embeddings.json,每个集合独立配置,不写注册表,不污染系统目录。


CI/CD:三平台自动发布

.github/workflows/release.yml 在推送版本 tag 时触发,三个平台并行构建:

git tag v1.0.0
git push origin v1.0.0

工作流分别在 windows-latestmacos-latestubuntu-24.04 上运行同一个 build.py 脚本,完成后将三个压缩包上传至 GitHub Release,无需手动在各系统上分别打包。

Linux 构建需要预装 WebKitGTK 头文件,这部分在 CI 里用 apt-get 解决:

- name: Install system dependencies
  run: |
    sudo apt-get install -y \
      libgirepository-2.0-dev gcc \
      libcairo2-dev pkg-config python3-dev \
      gir1.2-gtk-3.0 gir1.2-webkit2-4.1 \
      libwebkit2gtk-4.1-dev

本地运行

git clone https://github.com/[your-github-username]/chroma-walnut-ui.git
cd chroma-walnut-ui

# 安装 Python 依赖(推荐 uv)
uv sync

# 安装前端依赖
cd frontend && npm install && cd ..

# 启动(生产模式)
uv run python main.py

# 开发模式(前端热更新)
cd frontend && npm run dev &
uv run python main.py --dev

打包为可执行文件

uv run python build.py          # 正式包
uv run python build.py --debug  # 调试包(保留控制台)

脚本自动完成:检查依赖 → 构建前端 → 生成图标 → PyInstaller 打包 → 压缩分发文件。

平台输出
WindowsChromaWalnutUI-Windows.zip
macOSChromaWalnutUI-macOS.dmg
LinuxChromaWalnutUI-Linux.tar.gz

小结

PyWebView + React 这个组合对于需要桌面原生窗口但又不想放弃 Web 前端生态的项目是个不错的选择。相比 Electron,它轻量很多;相比纯 Web 应用,它不需要用户开浏览器,体验更接近原生应用。

ChromaDB 生态里的工具目前还不多,欢迎 Star、提 Issue 或 PR,一起把这个工具做得更完善。

GitHubgithub.com/a605204746/…