# 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 示例）。
