feat(report): 报告生成端到端 — 规划→分章并行检索撰写→渲染真实 Word

- shared: 新增 intent=report 任务约定 + ReportPath(跨进程共享落盘目录,零配置对齐)
- dispatcher: handleReport 专用编排(DeepSeek 规划大纲 → 各章并行 RAG 检索+撰写
  → 汇聚 → report_render),Pool.Chat 非流式聚合;进度与正文经 Token 流实时回流
- mcp-go: 用标准库 archive/zip + OOXML 拼出真实可打开的 .docx(零额外依赖),
  report_render 工具落盘到共享目录;附 docx 有效性测试
- gateway: POST /reports 触发;GET /reports/:id/download 下发 Word
- desktop: 新增「报告」页(主题→实时编排进度→下载 Word),左导航置为就绪

实测:DeepSeek 生成 5 章报告 → 渲染 5KB docx → file 识别为 Microsoft Word 2007+
→ textutil 提取标题/各章正文完整。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-12 14:02:21 +08:00
parent 8469cfc0db
commit ba8c6b3c43
15 changed files with 744 additions and 10 deletions
+22
View File
@@ -131,6 +131,28 @@ export async function searchKb(kb: string, q: string, topK = 5): Promise<KbHit[]
return data.hits ?? [];
}
// generateReport: POST /api/v1/reports —— 触发报告生成,返回 task_id。
// 用 streamTokens(task_id) 看实时进度,完成后用 reportDownloadUrl(task_id) 下载 Word。
export async function generateReport(id: Identity, topic: string, kb?: string): Promise<string> {
const res = await fetch(`${GATEWAY}/api/v1/reports`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-User-ID": id.userId,
"X-Session-ID": id.sessionId,
},
body: JSON.stringify({ topic, kb: kb ?? "" }),
});
const data = (await res.json()) as { task_id?: string; error?: string };
if (!res.ok || !data.task_id) throw new Error(data.error ?? `report failed: ${res.status}`);
return data.task_id;
}
// reportDownloadUrl: 渲染好的 Word(.docx) 下载地址。
export function reportDownloadUrl(taskId: string): string {
return `${GATEWAY}/api/v1/reports/${taskId}/download`;
}
// setMemory: PUT /api/v1/memory,登记一条用户偏好(→ mcp-go memory_upsert)。
export async function setMemory(
id: Identity,