295 lines
13 KiB
Markdown
295 lines
13 KiB
Markdown
# Mindmap AI v2 实施计划(文档大纲 / 小结带引用 / 搜索补全)
|
||
|
||
> 目标:把当前“仅能对话并返回 Markdown 列表”的 AI,升级为**可读可用**的“文档驱动思维导图”能力:
|
||
> 1) PDF/Word/PPT 按目录与大纲生成思维导图,并且节点可跳转到对应页/幻灯片;
|
||
> 2) 基于文档内容生成小结/知识点,并附带可点击引用(页码/链接);
|
||
> 3) 支持在节点上“搜索/查询后补完内容”(RAG + 可选联网检索)。
|
||
|
||
---
|
||
|
||
## 0. 现状与问题
|
||
|
||
### 0.1 当前实现(代码落点)
|
||
|
||
- `wolai-frontend/src/components/editor/blocks/MindmapSidebar.tsx`:AI 面板目前是“本地 Ollama /api/chat 流式输出 + Markdown 解析为节点”。
|
||
- `services/ingest_service`:已具备 **Supabase -> MinerU -> LightRAG** 的自动入库链路(用于全文检索/RAG)。
|
||
- `services/rag_gateway`:封装了对 LightRAG 的 HTTP 调用(`/query`、`/query/data`),可作为统一 RAG 网关。
|
||
- `wolai-frontend/src/app/onlyoffice/page.tsx`:OnlyOffice 文档查看/编辑入口(目前用于 docx/pptx/xlsx 等)。
|
||
- `wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`:节点超链接通过 `SET_NODE_HYPERLINK` 直接写入 URL。
|
||
|
||
### 0.2 为什么“离想象差很远”
|
||
|
||
当前 AI 只有“生成文本 -> 解析成节点”的能力,缺少:
|
||
|
||
- **与文档绑定**:没有把 PDF/Word/PPT 的结构(目录/标题层级)变成导图;
|
||
- **可验证的引用**:没有“这句话来自第几页/哪一段”,因此难以沉浸式阅读与回溯;
|
||
- **补全的检索依据**:没有把“补完节点”变成“基于检索结果 + 引用”输出,容易胡编;
|
||
- **工程化形态**:没有任务、进度、缓存、失败重试、可复用数据结构。
|
||
|
||
---
|
||
|
||
## 1. 用户故事与验收标准(以你的测试文件为准)
|
||
|
||
### 1.1 文档按目录/大纲生成导图(PDF/Word/PPT)
|
||
|
||
**用户故事**
|
||
|
||
- 我上传(或选中)一个文档(PDF/Word/PPT),点击“按大纲生成思维导图”,自动生成多级节点。
|
||
- 我点击任意节点,可以跳转到该文档对应页(PDF)或对应位置(Word/PPT 至少能定位页/提示页码,理想是直接跳转)。
|
||
|
||
**验收**
|
||
|
||
- 对 `wolai-frontend/test/卤化反应原理_1-9.pdf`:
|
||
- 能生成至少 2 级结构(中心主题 -> 章节 -> 小节)。
|
||
- 至少章节级节点带可点击引用(页码/链接)。
|
||
- 点击节点后打开的 URL 包含 `#page=<n>`(PDF 以浏览器内建查看器为准)。
|
||
|
||
### 1.2 小结/知识点生成(带链接引用)
|
||
|
||
**用户故事**
|
||
|
||
- 我选中“生成小结”,AI 输出“关键结论/反应机理/注意点”,每条结论附带引用(页码链接或文档片段来源)。
|
||
|
||
**验收**
|
||
|
||
- 对 `wolai-frontend/test/卤化反应原理测试.pdf`:
|
||
- 生成不少于 N(建议 8)条要点;
|
||
- 每条要点至少 1 个引用(页码/链接);
|
||
- 引用能点击打开对应 PDF 页。
|
||
|
||
### 1.3 搜索/查询后补完节点内容
|
||
|
||
**用户故事**
|
||
|
||
- 我选中一个/多个节点,输入“补完方向/问题”,AI 基于检索结果补充子节点或备注,附带引用。
|
||
|
||
**验收**
|
||
|
||
- 对同一 PDF 文档:
|
||
- “补完”后的内容至少包含 3 个子节点或 1 段结构化备注;
|
||
- 结论带引用(页码/链接);
|
||
- 不允许“无引用的长篇自由发挥”(默认强制引用)。
|
||
|
||
---
|
||
|
||
## 2. 总体方案(推荐架构)
|
||
|
||
核心原则:**先结构化,再生成**;**先检索证据,再写结论**;**引用是第一公民**。
|
||
|
||
### 2.1 三层能力拆分
|
||
|
||
1) **文档解析层(Document -> Outline/Chunks)**
|
||
- 输出:`DocOutline`(层级标题 + 页码/位置)与 `DocChunks`(可引用文本块)。
|
||
2) **RAG/生成层(Outline/Chunks -> Mindmap/Summary/Expansion)**
|
||
- 输出:思维导图节点树(含引用)、小结节点(含引用)、补全子节点(含引用)。
|
||
3) **渲染/交互层(Mindmap UI)**
|
||
- 节点点击:打开引用的文档页/位置;支持“查看引用”“展开更多证据”。
|
||
|
||
### 2.2 数据来源优先级(PDF)
|
||
|
||
按可靠性排序:
|
||
|
||
1) PDF 自带书签/目录(`pypdf` outline)→ **最靠谱**(本次 `卤化反应原理_1-9.pdf` 没有 outline)
|
||
2) MinerU 解析结果(建议开启 `return_content_list`/`return_middle_json`)→ 可拿到更结构化的块,并可能带页信息
|
||
3) `pypdf` 分页提取文本 + 标题检测(规则 + LLM 辅助)→ 兜底方案
|
||
|
||
---
|
||
|
||
## 3. 关键数据结构(建议新增/统一)
|
||
|
||
### 3.1 引用结构 `NodeRef`
|
||
|
||
用于节点的“可点击跳转”和“可追溯引用”:
|
||
|
||
```ts
|
||
export type NodeRef = {
|
||
kind: "pdf" | "docx" | "pptx" | "url";
|
||
assetId?: string; // 优先用 assetId,避免 URL 过期
|
||
fileUrl?: string; // public URL 或 signed URL(兜底)
|
||
page?: number; // PDF 页码(1-based)
|
||
slide?: number; // PPT 页码/幻灯片序号(1-based)
|
||
title?: string; // 引用标题(例如“2.1 卤化机理”)
|
||
snippet?: string; // 可选:引用片段
|
||
};
|
||
```
|
||
|
||
### 3.2 节点存储方式
|
||
|
||
- **短链**(推荐):`node.data.refs: NodeRef[]`(自定义字段)
|
||
- **展示用超链接**:仍使用 `SET_NODE_HYPERLINK` 写入一个可点击 URL(例如 PDF `...#page=3`)
|
||
- **引用详情**:写入 `node.data.note` 或 `node.data.data.note`(保持兼容)为 Markdown:
|
||
- `- [p3] 证据片段...`
|
||
- `- [p5] ...`
|
||
|
||
说明:simple-mind-map 对 `data` 的自定义字段容忍度较高,但要确保序列化/反序列化后不丢字段。
|
||
|
||
---
|
||
|
||
## 4. 具体功能方案
|
||
|
||
### 4.1 “按目录/大纲生成思维导图”
|
||
|
||
#### 4.1.1 API(建议新增)
|
||
|
||
新增 Next Route(前端同域,避免跨域/鉴权麻烦):
|
||
|
||
- `POST /api/mindmap-ai/outline-to-mindmap`
|
||
- 入参:`{ assetId, documentId?, prefer: "bookmark" | "mineru" | "heuristic" }`
|
||
- 出参:`{ mindmapData, outline, refsSummary }`
|
||
|
||
后台实现可以优先走 `services/ingest_service` 或直接复用其逻辑(后续可沉到 `wolai-backend`)。
|
||
|
||
#### 4.1.2 解析策略(对测试 PDF 友好)
|
||
|
||
因为 `卤化反应原理_1-9.pdf` 没有书签:
|
||
|
||
1) 使用 `pypdf` 逐页提取文本(已有代码可参考 `services/ingest_service/app/services/auto_indexer.py`);
|
||
2) 对每页文本做标题候选抽取(规则:编号标题如 `1.` `1.1` `(一)` 等 + 行长/标点密度);
|
||
3) 用 LLM(可走 Ollama)把候选标题整理为层级结构,并返回 `{title, level, page}`;
|
||
4) 转换为 mindmap:中心主题=文件名/第一页大标题,子节点=章节;每个章节节点写入 hyperlink `fileUrl#page=<page>`。
|
||
|
||
#### 4.1.3 Word/PPT
|
||
|
||
阶段 1 先保证:
|
||
|
||
- Word/PPT 也能“生成大纲导图”,但跳转能力允许降级:
|
||
- 若 OnlyOffice 支持跳转 API:实现真实跳转;
|
||
- 若不支持:点击节点打开文档,并弹出“建议跳转页码/幻灯片序号”的提示(至少可用)。
|
||
|
||
(后续再把 Word/PPT 的“位置”提升为可跳转锚点)
|
||
|
||
---
|
||
|
||
### 4.2 “小结/知识点生成(带引用)”
|
||
|
||
#### 4.2.1 证据来源:优先 LightRAG,其次本地分页文本
|
||
|
||
优先走 `services/rag_gateway`:
|
||
|
||
- `POST /rag/query`:拿到 `response + references`(LightRAG 会返回引用列表)
|
||
- `POST /rag/graph`:拿结构化分块/引用(用于“点开看证据/更多片段”)
|
||
|
||
如果 LightRAG 返回引用信息不足以映射到页码,需要补齐“页码映射”:
|
||
|
||
- 方案 A(推荐):在入库时把“每页”作为 chunk,并把 `file_source + page` 写入可回传字段(需要改 ingest_service 装饰文本或分块入库方式)
|
||
- 方案 B(兜底):在本地用 `pypdf` 重新做“分页文本”,对引用片段做模糊匹配定位页码
|
||
|
||
#### 4.2.2 输出形态
|
||
|
||
在 Mindmap 里提供两种落地方式:
|
||
|
||
- 生成到“备注”(适合长文本 + 引用列表)
|
||
- 生成到“子节点”(每条要点一个子节点,子节点携带 `refs` 和 hyperlink)
|
||
|
||
默认要求:**每条要点至少 1 个引用**(无引用则标记为“待核验”,并提示用户继续检索)。
|
||
|
||
---
|
||
|
||
### 4.3 “搜索/查询后补完节点内容”
|
||
|
||
#### 4.3.1 两种检索源(可配置)
|
||
|
||
1) **本地文档库检索**:LightRAG(默认)
|
||
2) **联网检索**:SearxNG(本仓库已存在 Docker 服务,可直接用)
|
||
|
||
##### 4.3.1.1 SearxNG 接入约定(基于仓库现状)
|
||
|
||
仓库已存在 `services/searxng-docker/.env`,其中包含:
|
||
|
||
- `SEARXNG_BASE_URL=http://127.0.0.1:8889`
|
||
- `SEARXNG_API_TOKEN=...`
|
||
|
||
建议接入方式:
|
||
|
||
- 前端**不要**直连 searxng(避免 token 暴露),通过 Next Route 代理:
|
||
- `POST /api/search/searxng`
|
||
- 入参:`{ q: string, count?: number, lang?: string }`
|
||
- 出参:`{ results: Array<{ title: string, url: string, snippet?: string, engine?: string }>} `
|
||
|
||
SearxNG 查询接口(推荐 JSON):
|
||
|
||
- `GET ${SEARXNG_BASE_URL}/search?q=<query>&format=json&language=zh-CN&categories=general&safesearch=1`
|
||
|
||
鉴权策略(需要实际跑通后确定,做成可配置):
|
||
|
||
- 方案 A:不加鉴权(本地内网服务)
|
||
- 方案 B:携带 token(例如 `X-API-Key` / `Authorization: Bearer` 之一;以你当前 searxng 配置为准)
|
||
|
||
> 注意:SearxNG 返回结果字段不同版本略有差异,后端代理层要做一次“结果归一化”和去重(按 url)。
|
||
|
||
#### 4.3.2 交互与输出
|
||
|
||
- 输入:用户选中节点 + “补完问题/方向”
|
||
- 系统 prompt 固定:强制输出结构化(Markdown 列表)+ 引用
|
||
- 输出策略:
|
||
- 子节点补全:把回答拆成 3~8 个子节点追加
|
||
- 备注补全:写入 note,并附引用列表
|
||
|
||
---
|
||
|
||
## 5. 前端 UI 改造建议(MindmapSidebar 的 AI 面板)
|
||
|
||
把当前“模型/地址/系统提示”改为“面向功能的工作流”,保留“高级设置”折叠:
|
||
|
||
1) **从文档生成**
|
||
- 选择文档资产(assetId)+ 生成按钮 + 进度(解析中/生成中/完成)
|
||
2) **生成小结**
|
||
- 可选:作用范围(整篇/选中节点对应章节)+ 要点数量 + 输出到(子节点/备注)
|
||
3) **补完节点**
|
||
- 输入框 + 检索源选择 + 输出到(子节点/备注)
|
||
|
||
同时在节点右键/工具栏增加:
|
||
|
||
- “打开引用”
|
||
- “查看引用(弹窗列出页码/片段)”
|
||
|
||
---
|
||
|
||
## 6. 工程落地步骤(里程碑)
|
||
|
||
> 建议按“先可用,再做强”的顺序推进。
|
||
|
||
### M1(1~2 天):PDF 大纲导图(可跳页)
|
||
|
||
- [ ] 新增 `/api/mindmap-ai/outline-to-mindmap`(仅支持 PDF)
|
||
- [ ] 实现 “pypdf 分页文本 + 标题候选 + LLM 整理层级”
|
||
- [ ] MindmapSidebar 增加“从 PDF 生成导图”入口(基于 assetId)
|
||
- [ ] 节点写入 hyperlink:`publicFileUrl#page=<n>`
|
||
- [ ] pw-tests:导入 `卤化反应原理_1-9.pdf`,断言生成节点数与 `#page=` 链接存在,并截图
|
||
|
||
### M2(2~3 天):小结生成(强制引用)
|
||
|
||
- [ ] 接入 `services/rag_gateway` 的 `/rag/query`(前端通过 Next Route 代理)
|
||
- [ ] 让小结输出“要点 + 引用”
|
||
- [ ] 引用映射到 `#page=`(先用本地分页匹配兜底)
|
||
- [ ] pw-tests:对 `卤化反应原理测试.pdf` 生成 N 条小结并截图
|
||
|
||
### M3(2~4 天):搜索补全节点(RAG)
|
||
|
||
- [ ] AI 面板增加“补完节点”模式
|
||
- [ ] 选中节点作为上下文,拼接检索 query:LightRAG(文档内)+ SearxNG(联网)
|
||
- [ ] 新增 `POST /api/search/searxng` 作为代理(隐藏 token + 统一返回格式)
|
||
- [ ] 将 searxng 的 `title/url/snippet` 作为“外部证据”,与 LightRAG 引用一起喂给模型生成
|
||
- [ ] 防胡编:无引用则提示“需要更多证据/换关键词”
|
||
- [ ] pw-tests:选中某节点补完,校验新增子节点与引用
|
||
|
||
### M4(可选):Word/PPT 真跳转
|
||
|
||
- [ ] 调研 OnlyOffice 是否支持跳页/跳幻灯片 API(不支持则维持降级)
|
||
- [ ] 若支持:在 `/onlyoffice` 页面接收 `page/slide` 参数并调用 DocsAPI 跳转
|
||
|
||
---
|
||
|
||
## 7. 风险与对策
|
||
|
||
- **PDF 无书签(当前测试文件就是)**:必须做“文本标题抽取 + LLM 结构化”的兜底。
|
||
- **页码引用难**:短期先用“本地分页匹配”;中期把“页级分块”纳入入库,引用直接带页码。
|
||
- **URL 过期/权限**:优先存 `assetId`,点击时再换取可用 URL(必要时扩展 `/api/media/signed-url` 支持 assetId)。
|
||
- **性能**:解析/生成尽量放到后端(Next Route 或 wolai-backend),前端只跑轻量 UI;长任务使用 job 表/轮询。
|
||
|
||
---
|
||
|
||
## 8. 与 BlockNote 的集成点(后续)
|
||
|
||
- Slash Menu 可加入口(例如 `/mind ai`、`/mind from pdf`),插入/更新块可用 BlockNote 的 `insertOrUpdateBlockForSlashMenu` 与 `editor.updateBlock`(见 BlockNote 官方文档的 Suggestion Menus 示例)。
|