395 lines
20 KiB
Markdown
395 lines
20 KiB
Markdown
# 本地优先(Local-first)Win 客户端改造方案(不依赖客户端 Docker)
|
||||
|
|
|
|||
|
|
## 1. 背景与目标
|
|||
|
|
|
|||
|
|
你已明确选择“方案 2”:以 **丝滑体验** 为第一优先级,把主要交互(新建/删除/打开/编辑/附件管理/文件树)尽可能做成 **本地零延迟**;在线能力只承担 **多设备同步、鉴权、RAG/OCR 结果回传** 等“不需要即时展示”的部分。
|
|||
|
|
|
|||
|
|
同时你希望:
|
|||
|
|
|
|||
|
|
- **Windows 客户端可打包分发**(家人/同事无需安装 Docker)
|
|||
|
|
- 后续可扩展:安卓端可以继续使用网页版(或再做安卓壳/客户端)
|
|||
|
|
- 现有服务端栈(Supabase/LightRAG/Redis/MinerU/OnlyOffice)在需要时仍可使用,但不强制落到每个客户端
|
|||
|
|
|
|||
|
|
## 2. 现状盘点(基于当前仓库)
|
|||
|
|
|
|||
|
|
- 当前仓库根目录的 `pnpm run desktop` / `pnpm run desktop:hot` 本质是“一键启动脚本”,会启动:
|
|||
|
|
- `wolai-frontend`(Next.js)
|
|||
|
|
- `wolai-backend`(FastAPI)
|
|||
|
|
- `services/ingest_service`(自动入库/清理/触发)
|
|||
|
|
- `services/rag_gateway`(RAG 查询网关)
|
|||
|
|
- 这不是可分发的“桌面客户端”:仍依赖 Node/Python 环境、端口服务、配置文件,且前端资源与 API 仍走 HTTP。
|
|||
|
|
|
|||
|
|
结论:要实现你要的“丝滑 + 易安装”,需要把“桌面壳 + 本地数据层 + 后台任务/同步”做成独立产品形态,而不是继续依赖 Cloudflare 反代公网访问。
|
|||
|
|
|
|||
|
|
## 3. 推荐总体架构(分层 + 可演进)
|
|||
|
|
|
|||
|
|
### 3.1 角色划分
|
|||
|
|
|
|||
|
|
**A. 桌面客户端(Windows,主力)**
|
|||
|
|
|
|||
|
|
- UI:本地窗口(WebView/Electron)加载本地页面(不经公网)
|
|||
|
|
- 本地数据层:本地数据库(建议 SQLite)+ 本地文件目录(附件/导入文件)
|
|||
|
|
- 本地任务队列:后台线程/进程异步执行(避免 UI 卡顿)
|
|||
|
|
- 网络:只做“同步/索引请求/鉴权”,且尽量后台化
|
|||
|
|
|
|||
|
|
**B. 家庭/办公室“轻服务端”(可选,但强烈建议)**
|
|||
|
|
|
|||
|
|
你目前已有 Docker 相关服务,更适合放到一台“常开机器”(NAS/迷你主机/家用服务器)上,而不是每个客户端:
|
|||
|
|
|
|||
|
|
- Supabase(鉴权/同步/共享数据/存储桶/pgvector)
|
|||
|
|
- Redis(队列/后台任务)
|
|||
|
|
- LightRAG(入库/检索)
|
|||
|
|
- MinerU(OCR)
|
|||
|
|
- OnlyOffice Document Server(如仍需要网页内编辑 Office)
|
|||
|
|
|
|||
|
|
**C. 公网访问(可选)**
|
|||
|
|
|
|||
|
|
- 安卓端/外网访问时,继续使用网页版(可走 Cloudflare、或 VPN/IPv6)
|
|||
|
|
- 但桌面端的“主要交互体验”不再依赖公网链路
|
|||
|
|
|
|||
|
|
### 3.2 本地优先的数据归属
|
|||
|
|
|
|||
|
|
核心原则:**“能本地完成的操作,绝不阻塞在网络请求上。”**
|
|||
|
|
|
|||
|
|
- 文档/思维导图的“当前版本内容”:本地可用(SQLite + 文件)
|
|||
|
|
- 附件文件本体:本地可用(本地目录),需要时再同步/上传
|
|||
|
|
- 远端(Supabase)只承担:
|
|||
|
|
- 多设备同步与共享(最终一致)
|
|||
|
|
- RAG/OCR 的产物存储与检索
|
|||
|
|
- 登录鉴权(如你希望跨设备一致账号体系)
|
|||
|
|
|
|||
|
|
## 4. 技术路线:桌面壳怎么做(不跑 Docker)
|
|||
|
|
|
|||
|
|
你现在的前端是 Next.js(含 Server Components + API Routes),要做桌面客户端通常有两条路线:
|
|||
|
|
|
|||
|
|
### 路线 1(推荐落地优先):桌面壳 + 本地 HTTP(保持现有 Next/FastAPI)
|
|||
|
|
|
|||
|
|
- 桌面壳:Tauri 2 或 Electron(两者都能)
|
|||
|
|
- 客户端启动时:
|
|||
|
|
1) 启动本机 `wolai-frontend`(生产模式)到 `127.0.0.1:3000`
|
|||
|
|
2) 启动本机 `wolai-backend`(或逐步把关键 API 收敛到一个本地服务)
|
|||
|
|
3) 桌面壳打开 `http://127.0.0.1:3000`(同源、零公网)
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
- 改造小:最大复用当前 Next/FastAPI
|
|||
|
|
- 体验立刻提升:不再经过 Cloudflare/Tunnel
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
- “安装体积/依赖”需要进一步工程化(见第 8 节分阶段)
|
|||
|
|
|
|||
|
|
### 路线 2(长期更优雅):本地壳 + 静态前端 + 本地 API(逐步去 Next Server 依赖)
|
|||
|
|
|
|||
|
|
- 把前端逐步改成更“纯前端”的形态(或迁 Vite/React SPA)
|
|||
|
|
- 本地 API 用一个可打包的二进制提供(Rust/Go)+ SQLite
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
- 最终安装最轻、启动更快、可控性最好
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
- 改造量大,不建议作为第一阶段目标
|
|||
|
|
|
|||
|
|
**建议决策**:先走“路线 1”把体验做顺,再按收益逐步往“路线 2”靠拢。
|
|||
|
|
|
|||
|
|
## 5. “丝滑”的关键:本地任务队列 + 最终一致同步
|
|||
|
|
|
|||
|
|
### 5.1 本地操作必须立刻返回
|
|||
|
|
|
|||
|
|
把下列操作改为“本地先完成,后台再同步”:
|
|||
|
|
|
|||
|
|
- 新建/重命名/移动/删除(进入回收站)
|
|||
|
|
- 打开文档(本地读)
|
|||
|
|
- 编辑器保存(本地落盘 + 去抖)
|
|||
|
|
- 附件导入(本地复制到附件目录,立即可用)
|
|||
|
|
|
|||
|
|
### 5.2 同步模型(建议:Oplog/变更日志)
|
|||
|
|
|
|||
|
|
为避免“每次都全量上传大字段”导致卡顿,建议本地维护一个 `oplog`:
|
|||
|
|
|
|||
|
|
- 每个操作写入:`op_id、entity_type、entity_id、op_type、payload、created_at、synced_at`
|
|||
|
|
- 后台同步器按顺序上传到 Supabase(或服务端)
|
|||
|
|
- 冲突策略(第一阶段先简单):
|
|||
|
|
- 同一文档若出现冲突:保留双方版本(生成“冲突副本”),避免覆盖丢数据
|
|||
|
|
|
|||
|
|
### 5.3 建议的本地 SQLite 最小表结构(用于落地与排期)
|
|||
|
|
|
|||
|
|
> 目标:先把“本地秒开 + 不依赖网络”的体验做出来;同步与协作逐步增强。
|
|||
|
|
|
|||
|
|
- `local_documents`
|
|||
|
|
- `id`(uuid)、`parent_id`、`title`、`content_json`(或文件路径)、`updated_at`、`deleted_at`
|
|||
|
|
- `local_media_assets`
|
|||
|
|
- `id`、`document_id`、`file_path`、`mime`、`sha256`、`size`、`created_at`、`deleted_at`
|
|||
|
|
- `local_mindmaps`
|
|||
|
|
- `id`、`document_id`(可选)、`data_json`、`updated_at`、`deleted_at`
|
|||
|
|
- `local_trash_jobs`
|
|||
|
|
- `entity_type`、`entity_id`、`purge_after`(时间戳)、`canceled_at`
|
|||
|
|
- `local_oplog`
|
|||
|
|
- `op_id`、`entity_type`、`entity_id`、`op_type`、`payload_json`、`created_at`、`synced_at`、`retry_count`
|
|||
|
|
- `local_sync_state`
|
|||
|
|
- `remote_cursor`(用于增量拉取)、`last_pull_at`、`last_push_at`
|
|||
|
|
|
|||
|
|
### 5.4 与当前 Supabase 表的映射(基于 supabase_local 现有表)
|
|||
|
|
|
|||
|
|
你当前 Supabase(`public` schema)已经有这些关键表:`documents`、`media_assets`、`mindmap_meta`/`mindmap_nodes`、`rag_index_sources`、`lightrag_*`、`document_embeddings` 等。
|
|||
|
|
|
|||
|
|
建议映射策略(第一阶段):
|
|||
|
|
|
|||
|
|
- 本地 `local_documents` <-> 远端 `public.documents`
|
|||
|
|
- 远端作为“同步与共享的汇聚层”,本地为“即时交互层”
|
|||
|
|
- 本地 `local_media_assets` <-> 远端 `public.media_assets` + `storage.objects`
|
|||
|
|
- 远端文件本体尽量走 Storage(签名 URL/直传),避免经 API 中转
|
|||
|
|
- 思维导图:本地 `local_mindmaps` <-> 远端 `mindmap_meta`/`mindmap_nodes`
|
|||
|
|
- 目前“思维导图删除后垃圾桶没有出现”,本质是缺少统一的 `deleted_at` 与回收站视图
|
|||
|
|
- 建议把 mindmap 也纳入统一软删体系(与 documents/media_assets 同标准)
|
|||
|
|
|
|||
|
|
## 6. 回收站 + 延迟删除(解决误删与垃圾堆积)
|
|||
|
|
|
|||
|
|
你提出的需求非常关键:误删后 `Ctrl+Z` 可恢复,所以“删文件”不应立即删 OCR/RAG 资源。
|
|||
|
|
|
|||
|
|
建议统一成两段式删除:
|
|||
|
|
|
|||
|
|
1) **软删(立刻)**:进入回收站
|
|||
|
|
- 本地:移动到 `.trash/`(或打标 `deleted_at`),UI 可见
|
|||
|
|
- 服务端:对应记录打 `deleted_at`(不做物理删除)
|
|||
|
|
|
|||
|
|
2) **延迟清理(例如 10 分钟后)**:后台任务执行硬删除
|
|||
|
|
- 若用户在延迟窗口内恢复:取消清理任务
|
|||
|
|
- 手动“清空垃圾桶”:触发立即清理(仍建议带二次确认)
|
|||
|
|
|
|||
|
|
注意:你现有的报错 `rag_index_sources` 外键约束,说明服务端“删除顺序/级联规则”需要统一:
|
|||
|
|
|
|||
|
|
- 设计层面建议:对 RAG 相关表引入 `ON DELETE CASCADE` 或“先删子表再删父表”的硬规则
|
|||
|
|
- 实现层面建议:垃圾桶清理走同一个 `purge` 流程,确保顺序一致
|
|||
|
|
|
|||
|
|
基于你当前的约束信息:`rag_index_sources_document_id_fkey` 的 `ON DELETE` 是 `NO ACTION`(也就是不会级联删除),因此“清空垃圾桶”若直接删 `documents` 就必然触发外键错误。这里推荐两条修复路径(二选一):
|
|||
|
|
|
|||
|
|
1) **保留外键 NO ACTION**:清理时严格按顺序删除子表(例如先删 `rag_index_sources`、再删 `documents`)
|
|||
|
|
2) **改为 ON DELETE CASCADE**:允许删除 `documents` 时自动清理 `rag_index_sources`(更省心,但要确认不会误删共享/审计数据)
|
|||
|
|
|
|||
|
|
## 7. RAG/OCR(MinerU)在本地优先架构中的位置
|
|||
|
|
|
|||
|
|
你的期望是:客户端体验优先,OCR/RAG 可以后台慢慢做。因此推荐:
|
|||
|
|
|
|||
|
|
- **客户端只负责触发与展示结果**(不在客户端跑 Docker)
|
|||
|
|
- **OCR/RAG 在“轻服务端”执行**(可继续用你现有 Docker/服务)
|
|||
|
|
|
|||
|
|
### 7.1 触发策略(建议)
|
|||
|
|
|
|||
|
|
当本地文件发生变化(导入/更新):
|
|||
|
|
|
|||
|
|
- 计算 `content_hash`(用于去重与增量)
|
|||
|
|
- 将任务写入本地队列(或远端队列)
|
|||
|
|
- 后台上传文件到服务端(或 Supabase Storage)
|
|||
|
|
- 服务端按文件类型处理:
|
|||
|
|
- PDF/图片型 PDF:MinerU OCR -> 结构化文本
|
|||
|
|
- docx/pptx/xlsx:提取文本(必要时转 pdf 再 OCR)
|
|||
|
|
- 图片:OCR + 元数据
|
|||
|
|
- 最终写入:标准化 chunk + embedding + 元数据(Supabase/pgvector)
|
|||
|
|
|
|||
|
|
### 7.2 Embedding 建议(中英混合 + 化学语料,尽量免费)
|
|||
|
|
|
|||
|
|
优先推荐“可自托管/本地跑”的 embedding(服务端跑即可):
|
|||
|
|
|
|||
|
|
- `bge-m3`:多语种通用表现稳定,适合中英混合
|
|||
|
|
- `multilingual-e5-large`(或同系):检索向 embedding 生态成熟
|
|||
|
|
- 你现有 `Ollama` 方案里预拉的 `qwen3-embedding:8b`:可作为可用基线(但模型较大,CPU 可能慢,建议服务端有 GPU 或更强 CPU)
|
|||
|
|
|
|||
|
|
第一阶段建议先选 1 个跑通“自动入库闭环”,再用你提供的化学书籍片段做小规模对比评测(Recall@k + 人工判读)。
|
|||
|
|
|
|||
|
|
### 7.3 任务编排建议(复用现有 Supabase 表)
|
|||
|
|
|
|||
|
|
你当前 Supabase 已有两张非常适合做“可观测后台任务”的表:
|
|||
|
|
|
|||
|
|
- `public.rag_index_sources`:有 `status/attempts/last_error/source_updated_at/last_enqueued_at/last_processed_at`
|
|||
|
|
- `public.background_tasks`:有 `task_type/status/progress/message/updated_at`
|
|||
|
|
|
|||
|
|
建议用法:
|
|||
|
|
|
|||
|
|
1) **入库入口统一**:任何“需要入库/重建索引”的源(documents/media_assets/mindmap/ocr_text)都落一条 `rag_index_sources`
|
|||
|
|
2) **执行过程可视化**:真正跑 OCR/切块/embedding/入库时,同步写 `background_tasks`(用于前端显示进度条/日志)
|
|||
|
|
3) **幂等与去重**:
|
|||
|
|
- 用 `source_updated_at` + `content_hash`(可在 payload 里存)判断是否需要重跑
|
|||
|
|
- 同一 `source_id` 新任务到来时,若已有 `RUNNING` 则只更新 `last_enqueued_at`,避免并发重复跑
|
|||
|
|
|
|||
|
|
### 7.4 OCR 决策(PDF 有文本 vs 图片型 PDF)
|
|||
|
|
|
|||
|
|
针对你提供的两类测试 PDF(“已 OCR 过含文本”与“图片型 PDF”),建议服务端在入库前做一个轻量判断:
|
|||
|
|
|
|||
|
|
- 先尝试“抽取文本”(例如每页抽样、统计可抽取字符数)
|
|||
|
|
- 若字符数/覆盖率低于阈值,再走 MinerU OCR
|
|||
|
|
- OCR 产物建议保留:
|
|||
|
|
- `raw_text`(纯文本,用于检索)
|
|||
|
|
- `layout`(段落/页码/坐标等,用于引用定位与高亮)
|
|||
|
|
|
|||
|
|
这样可以避免对“本来就有文本层的 PDF”重复 OCR,节省大量时间。
|
|||
|
|
|
|||
|
|
### 7.5 LightRAG 版本对齐(你提到的 v1.4.9.10)
|
|||
|
|
|
|||
|
|
当前仓库内的 `LightRAG` 代码与其自带虚拟环境显示版本为 `1.4.9.9`(`LightRAG/lightrag/__init__.py` 与 `LightRAG/.venv` 一致)。
|
|||
|
|
|
|||
|
|
建议策略:
|
|||
|
|
|
|||
|
|
- **先稳**:在“本地优先客户端”主线落地前,LightRAG 不做大范围升级,避免把变量叠加到体验问题上
|
|||
|
|
- **再对齐**:单独开一个“LightRAG 升级分支计划”(仅改 LightRAG 目录/服务启动脚本/兼容性),升级到你说的 `v1.4.9.10` 后,用你提供的两份测试 PDF 跑一遍入库回归(含 OCR 分支)
|
|||
|
|
|
|||
|
|
## 8. 分阶段落地路线(建议按收益/难度)
|
|||
|
|
|
|||
|
|
### P0(最小可用,立刻变丝滑)
|
|||
|
|
|
|||
|
|
- 明确“桌面端默认走本机”:`127.0.0.1` / 局域网 IP
|
|||
|
|
- 桌面端不经过 Cloudflare(Cloudflare 仅保留给“手机/外网”)
|
|||
|
|
- 这一步不解决“安装依赖”,但先把“体验问题”排除在公网链路之外
|
|||
|
|
|
|||
|
|
### P1(可分发 Win 客户端:无需 Docker)
|
|||
|
|
|
|||
|
|
目标:家人/同事拿到安装包即可用(最多只安装一次 VC 运行库/WebView2)。
|
|||
|
|
|
|||
|
|
- 引入桌面壳(Tauri 或 Electron)
|
|||
|
|
- 把必要服务以“sidecar”方式随客户端分发并由壳统一拉起/关闭:
|
|||
|
|
- Next 前端(建议 next standalone 输出 + 内置 Node)
|
|||
|
|
- 后端 API(优先收敛成一个本地服务;Python 可先保留,后续再二进制化)
|
|||
|
|
- 本地数据层落地:SQLite + 本地文件目录
|
|||
|
|
|
|||
|
|
### P2(减少依赖与体积)
|
|||
|
|
|
|||
|
|
- Python 服务逐步二进制化(PyInstaller/Nuitka 或重写关键路径为 Rust/Go)
|
|||
|
|
- 能迁到本地 API 的 Next `app/api/*` 逐步迁移,减少 Next server 负担
|
|||
|
|
|
|||
|
|
### P3(多端)
|
|||
|
|
|
|||
|
|
- 安卓端继续用网页版(外网可用 VPN/IPv6/Cloudflare 其一)
|
|||
|
|
- 桌面端与网页版共享同一套“同步协议/数据模型”,但桌面端以本地为主
|
|||
|
|
|
|||
|
|
## 9. 你需要做的关键取舍(我建议的默认值)
|
|||
|
|
|
|||
|
|
1) **OnlyOffice 的定位**
|
|||
|
|
- 如果你追求“打开速度极致”:Windows 客户端对 docx/xlsx/pptx 优先“用本机 Office/OnlyOffice Desktop 打开”,应用内只做预览/管理/版本
|
|||
|
|
- OnlyOffice Document Server 保留给:手机端/外网网页端
|
|||
|
|
|
|||
|
|
2) **服务端部署位置**
|
|||
|
|
- 若你有一台常开机器:把 Supabase/LightRAG/MinerU/Redis/OnlyOffice 放到 LAN 里,桌面端访问延迟会非常低
|
|||
|
|
- 外网访问建议优先 VPN(你是小范围用户),避免 Cloudflare 造成的不可控绕路
|
|||
|
|
|
|||
|
|
## 10. 下一步我建议你先确认的 5 个问题(确认后我再给出更“可执行”的工程拆分)
|
|||
|
|
|
|||
|
|
1) Windows 客户端你更偏好:`Tauri`(小体积)还是 `Electron`(生态成熟)?
|
|||
|
|
2) 你是否接受“第一阶段仍需要安装 Node/Python”,还是必须“一键安装无运行时依赖”?
|
|||
|
|
3) 你希望本地数据目录放哪:`%USERPROFILE%\\Documents\\MNOTE` 还是跟仓库同级?
|
|||
|
|
4) 多人同时编辑是否重要?(决定是否引入 Yjs 协作服务端/冲突策略)
|
|||
|
|
5) 你的“轻服务端”准备放在哪台机器(家用主机/NAS/云服务器)?
|
|||
|
|
|
|||
|
|
## 11. 你已确认的项目决策(已记录,后续按此推进)
|
|||
|
|
|
|||
|
|
你已明确选择:
|
|||
|
|
|
|||
|
|
1) 桌面壳:`Electron`
|
|||
|
|
2) 依赖:可以安装任何东西,但希望“安装后即可启动客户端”(减少手工配置)
|
|||
|
|
3) 本地数据:放在**安装目录**(用户上传文件先落到该目录,再与远程 Supabase 同步)
|
|||
|
|
4) 协作:暂不做多人同时编辑
|
|||
|
|
5) 轻服务端:当前家用主机(先这样)
|
|||
|
|
|
|||
|
|
### 11.1 关键风险提醒:Windows 的“安装目录”通常不可写
|
|||
|
|
|
|||
|
|
如果你用的是常见的安装方式(MSI/NSIS 默认装到 `C:\\Program Files\\...`),Windows 会对普通用户进程启用 UAC/权限限制,**安装目录默认不可写**,会导致:
|
|||
|
|
|
|||
|
|
- 上传文件/本地数据库写入失败或变成“时好时坏”
|
|||
|
|
- 需要管理员权限运行(体验差、也不安全)
|
|||
|
|
|
|||
|
|
你已进一步明确:**标准安装**,但安装位置必须可选且尽量不在 C 盘(数据会越来越大)。
|
|||
|
|
|
|||
|
|
这里的关键点不在“C 盘 vs 非 C 盘”,而在“是否安装在受保护目录(如 Program Files)”。即使装到 `D:\\Program Files\\...`,也可能同样不可写。
|
|||
|
|
|
|||
|
|
为满足“标准安装 + 数据放安装目录 + 不在 C 盘”,我建议按下面规则实现(作为默认方案):
|
|||
|
|
|
|||
|
|
- **安装路径强约束**:安装器允许用户自选安装目录,但**禁止选择 C 盘**,并且默认推荐路径形如 `D:\\Apps\\MNOTE`(而不是 `D:\\Program Files\\...`)。
|
|||
|
|
- **数据目录固定在安装目录内**:例如 `D:\\Apps\\MNOTE\\data`(满足“数据跟安装目录走”)。
|
|||
|
|
- **安装时设置 data 目录 ACL**:安装器在安装阶段为 `data` 目录授予当前用户(或 Users 组)可写权限,避免运行时写入失败。
|
|||
|
|
|
|||
|
|
> 如果你希望“强制必须装到非 C 盘”,这是可做的;但如果同事机器没有 D 盘,也需要允许选择 E/F 等其它盘符。
|
|||
|
|
|
|||
|
|
结论:你不需要做“绿色版”,也不需要把数据放到 `userData`;但必须在安装器层面把“安装目录可写”这件事做成默认成立。
|
|||
|
|
|
|||
|
|
## 12. Electron 客户端落地方案(不让客户端跑 Docker)
|
|||
|
|
|
|||
|
|
### 12.1 本地优先的最小形态(推荐作为第一阶段实现)
|
|||
|
|
|
|||
|
|
Electron 只做三件事:
|
|||
|
|
|
|||
|
|
- 提供 UI(窗口内渲染网页)
|
|||
|
|
- 提供本地数据目录与 SQLite(零延迟读写)
|
|||
|
|
- 后台做“同步/上传/触发服务端入库”(不阻塞 UI)
|
|||
|
|
|
|||
|
|
客户端**不运行 Docker**,也不强制在客户端跑 LightRAG / MinerU / Supabase。
|
|||
|
|
|
|||
|
|
### 12.2 与现有代码的衔接方式(尽量少改,先跑通)
|
|||
|
|
|
|||
|
|
第一阶段建议继续复用你现有的 HTTP 形态,但把链路从“公网 Cloudflare”改为“本机/局域网”:
|
|||
|
|
|
|||
|
|
- Electron 启动时拉起本机服务(作为 sidecar):
|
|||
|
|
- `wolai-frontend`:Next production(本机 `127.0.0.1:3000`)
|
|||
|
|
- `wolai-backend`:FastAPI(本机 `127.0.0.1:8000`)
|
|||
|
|
- Electron 窗口直接打开 `http://127.0.0.1:3000`
|
|||
|
|
|
|||
|
|
这样 UI 完全不走公网,页面切换/打开文档会立刻变“本地速度”。
|
|||
|
|
|
|||
|
|
> 说明:你仓库根目录的 `pnpm run desktop` 目前更像“开发者一键启动”;后续我们会新增专用的“Electron sidecar 启动器”,把端口探测、日志、崩溃重启、退出清理做成稳定产品级行为。
|
|||
|
|
|
|||
|
|
### 12.3 依赖与打包策略(让“安装后可启动”)
|
|||
|
|
|
|||
|
|
你允许安装任何东西,但希望安装后可启动。我建议用“两阶段”逐步降低门槛:
|
|||
|
|
|
|||
|
|
**阶段 1(最快落地)**
|
|||
|
|
- 安装前置:Node、Python(以及必要的 VC 运行库、WebView2)
|
|||
|
|
- Electron installer 在首次启动时做自检(缺什么就引导安装)
|
|||
|
|
|
|||
|
|
**阶段 2(更像产品)**
|
|||
|
|
- 把后端打成单文件/少量文件的可执行程序(PyInstaller/Nuitka)
|
|||
|
|
- 把前端打成 Next standalone(或更进一步变成静态 + 本地 API)
|
|||
|
|
- Electron 安装包内置所有运行时(用户无需额外安装 Node/Python)
|
|||
|
|
|
|||
|
|
## 13. 轻服务端(家用主机)承担什么
|
|||
|
|
|
|||
|
|
鉴于你暂时不做多人实时协作,且优先“本地丝滑”,建议家用主机只承担:
|
|||
|
|
|
|||
|
|
- Supabase:鉴权 + 多端同步汇聚层 + Storage + pgvector
|
|||
|
|
- ingest_service:监听/轮询需要入库的源(`rag_index_sources`),做切块/embedding/入库
|
|||
|
|
- MinerU:OCR 工作负载(图片/图片型 PDF)
|
|||
|
|
- LightRAG:统一入库/检索(或作为 ingest_service 内部依赖)
|
|||
|
|
- Redis:任务队列/限流(可选)
|
|||
|
|
- OnlyOffice Document Server:主要给“网页/手机端”使用;Windows 客户端可优先走本机 Office/OnlyOffice Desktop 提升打开速度
|
|||
|
|
|
|||
|
|
## 14. 下一步里程碑(可直接开工的任务清单)
|
|||
|
|
|
|||
|
|
### M0:确定安装与数据目录规则(必须先定)
|
|||
|
|
|
|||
|
|
- 标准安装(NSIS/MSI),允许用户选择安装路径
|
|||
|
|
- 默认路径推荐 `D:\\Apps\\MNOTE`
|
|||
|
|
- 禁止安装到 C 盘(可配置为硬限制或安装器强提示)
|
|||
|
|
- 数据目录固定为 `$INSTDIR\\data` 并在安装时设置写权限
|
|||
|
|
|
|||
|
|
### M1:Electron 外壳 + 本机服务启动(体验立竿见影)
|
|||
|
|
|
|||
|
|
- 新增 `electron-app/`(主进程 + 渲染进程)
|
|||
|
|
- 主进程实现:
|
|||
|
|
- 启动前端(Next production)到 `127.0.0.1:3000`
|
|||
|
|
- 启动后端(FastAPI)到 `127.0.0.1:8000`
|
|||
|
|
- 进程托管:崩溃重启、退出清理、日志落盘(UTF-8)
|
|||
|
|
- 渲染进程直接加载 `http://127.0.0.1:3000`
|
|||
|
|
|
|||
|
|
### M2:本地数据目录与 SQLite(真正 local-first)
|
|||
|
|
|
|||
|
|
- 选定数据根目录(绿色版:`./data`;标准版:`userData`)
|
|||
|
|
- 引入 SQLite(文档/附件索引/oplog/回收站任务)
|
|||
|
|
- 把“创建/删除/打开”的关键路径改为本地优先(网络失败也能操作)
|
|||
|
|
|
|||
|
|
### M3:同步(最终一致)
|
|||
|
|
|
|||
|
|
- 本地 `local_oplog` 推送到 Supabase
|
|||
|
|
- 从 Supabase 拉取增量变更,更新本地 SQLite
|
|||
|
|
- 冲突先采用“生成冲突副本”的保守策略
|
|||
|
|
|
|||
|
|
### M4:入库/OCR 后台化(不阻塞 UI)
|
|||
|
|
|
|||
|
|
- 客户端只负责:上传文件 + 写 `rag_index_sources`(或触发 API)
|
|||
|
|
- 家用主机跑 ingest_service/MinerU/LightRAG 完成入库
|
|||
|
|
- 客户端订阅/轮询 `background_tasks` 显示进度(可选)
|