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:
@@ -0,0 +1,56 @@
|
||||
package office
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRenderReportValidDocx(t *testing.T) {
|
||||
data, err := NewRenderer().RenderReport(context.Background(), "测试报告 <X&Y>", []Section{
|
||||
{Heading: "第一章 背景", Body: "这是第一段。\n这是第二段,含特殊字符 < > &。"},
|
||||
{Heading: "第二章 分析", Body: "结论行。"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatalf("not a valid zip: %v", err)
|
||||
}
|
||||
want := map[string]bool{"[Content_Types].xml": false, "_rels/.rels": false, "word/document.xml": false}
|
||||
var docXML string
|
||||
for _, f := range zr.File {
|
||||
if _, ok := want[f.Name]; ok {
|
||||
want[f.Name] = true
|
||||
}
|
||||
if f.Name == "word/document.xml" {
|
||||
rc, _ := f.Open()
|
||||
var b strings.Builder
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, e := rc.Read(buf)
|
||||
b.Write(buf[:n])
|
||||
if e != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
rc.Close()
|
||||
docXML = b.String()
|
||||
}
|
||||
}
|
||||
for name, found := range want {
|
||||
if !found {
|
||||
t.Errorf("missing part %s", name)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(docXML, "< > &") {
|
||||
t.Errorf("xml not escaped properly: %s", docXML)
|
||||
}
|
||||
if !strings.Contains(docXML, "第一章 背景") {
|
||||
t.Errorf("heading missing")
|
||||
}
|
||||
t.Logf("docx ok: %d bytes, %d parts", len(data), len(zr.File))
|
||||
}
|
||||
Reference in New Issue
Block a user