feat(export): 多格式文档导出服务(HTML / PDF / DOCX + 函数图像渲染) #41

Closed
yxx wants to merge 0 commits from feat/export-service into main
Collaborator

概述

Export Service:把笔记或未保存的 Markdown 文本导出为 HTML / PDF / DOCX 的完整链路——创建即返回 queued、后台 asyncio.Task 渲染、产物 24h 过期、轮询 GET /api/exports/{job_id} 下载。

范围(相对 main:28 文件 / +4836 行)

  • Document AST:mistune renderer="ast" → DocumentNode 内部协议 + DocumentExporter Protocol。
  • 三种导出器:
    • HtmlExporter:完整 HTML5 + function-plot 静态 SVG 内嵌。
    • PdfExporter:reportlab,function-plot 内嵌矢量 Drawing(与 SVG 同源共享几何),中文字体 STSong-Light,列表/表格/引用/行内语义。
    • DocxExporter:python-docx,标题/列表/链接/表格,中文经 w:eastAsia=宋体。
  • Function Plot:白名单 AST 表达式解析(parser.py)、共享几何 compute_geometry(render.py)、reportlab 矢量后端(render_reportlab.py)、StaticRenderer 内部契约(renderer.py)。
  • 资源上限:输入 200k 字符、单图 ≤16 表达式、文档 ≤16 图、累计 AST 节点预算 8000、并发渲染 2、产物 20MB。
  • HTTP 契约与路由:app/contracts.py + app/routes.py 的 /api/exports*(创建/查询/下载/取消)。
  • 测试与文档:tests/test_export.py、tests/test_plot.py,docs/development/Export开发说明.md、接口契约 §10。

审阅修复记录(多轮)

  • 引用块正文丢失、嵌套列表顺序与排队取消
  • 列表项行内语义丢失与混合嵌套顺序重排
  • 函数图像数量/复杂度预算上限
  • PDF 函数图像矢量内嵌
  • 显式 range 外曲线裁剪 + PDF 纵轴标签旋转修正
  • 渐近点落在采样点之间时断段(避免贯穿绘图区的伪竖线)

验证结果

  • 后端完整测试:720 passed
  • git diff --check:通过
  • 与当前远程 main:无合并冲突
## 概述 Export Service:把笔记或未保存的 Markdown 文本导出为 HTML / PDF / DOCX 的完整链路——创建即返回 `queued`、后台 asyncio.Task 渲染、产物 24h 过期、轮询 `GET /api/exports/{job_id}` 下载。 ## 范围(相对 main:28 文件 / +4836 行) - **Document AST**:mistune `renderer="ast"` → `DocumentNode` 内部协议 + `DocumentExporter` Protocol。 - **三种导出器**: - `HtmlExporter`:完整 HTML5 + function-plot 静态 SVG 内嵌。 - `PdfExporter`:reportlab,function-plot 内嵌矢量 `Drawing`(与 SVG 同源共享几何),中文字体 STSong-Light,列表/表格/引用/行内语义。 - `DocxExporter`:python-docx,标题/列表/链接/表格,中文经 `w:eastAsia=宋体`。 - **Function Plot**:白名单 AST 表达式解析(`parser.py`)、共享几何 `compute_geometry`(`render.py`)、reportlab 矢量后端(`render_reportlab.py`)、`StaticRenderer` 内部契约(`renderer.py`)。 - **资源上限**:输入 200k 字符、单图 ≤16 表达式、文档 ≤16 图、累计 AST 节点预算 8000、并发渲染 2、产物 20MB。 - **HTTP 契约与路由**:`app/contracts.py` + `app/routes.py` 的 `/api/exports*`(创建/查询/下载/取消)。 - **测试与文档**:`tests/test_export.py`、`tests/test_plot.py`,`docs/development/Export开发说明.md`、接口契约 §10。 ## 审阅修复记录(多轮) - 引用块正文丢失、嵌套列表顺序与排队取消 - 列表项行内语义丢失与混合嵌套顺序重排 - 函数图像数量/复杂度预算上限 - PDF 函数图像矢量内嵌 - 显式 range 外曲线裁剪 + PDF 纵轴标签旋转修正 - 渐近点落在采样点之间时断段(避免贯穿绘图区的伪竖线) ## 验证结果 - 后端完整测试:`720 passed` - `git diff --check`:通过 - 与当前远程 `main`:无合并冲突
Owner

审阅结论

暂不建议合并,当前仍有 1 个 P2 问题。

P2:渐近线判断会误删正常的陡峭连续曲线

当前实现将“相邻采样值分别低于 ymin 和高于 ymax”直接判断为中间存在渐近线并断开曲线。

但正常的连续函数也可能在两个采样点之间快速穿过可见范围。例如:

domain: -1, 1
range: -1, 1
y = 1000*(x-0.0025)

实测该函数最终生成 0 个曲线段,整条本应穿过绘图区的直线完全消失。

建议:

  • 对疑似不连续的采样区间进行中点求值或自适应细分。
  • 如果细分过程中找到位于可见范围内的有限点,则说明曲线连续,应保留并使用细分点绘制。
  • 达到细分深度或精度上限后仍无法找到范围内的有限点,再将该区间断开。
  • 增加陡峭连续函数的回归测试,确保修复渐近线问题时不会误删正常曲线。

已确认内容

  • 上一轮的渐近线伪竖线问题已消除。
  • PR 标题和描述已经准确覆盖整个 Export Service。
  • 后端完整测试:720 passed
  • git diff --check:通过
  • 与当前远程 main:无合并冲突
## 审阅结论 暂不建议合并,当前仍有 1 个 P2 问题。 ### P2:渐近线判断会误删正常的陡峭连续曲线 当前实现将“相邻采样值分别低于 `ymin` 和高于 `ymax`”直接判断为中间存在渐近线并断开曲线。 但正常的连续函数也可能在两个采样点之间快速穿过可见范围。例如: ```text domain: -1, 1 range: -1, 1 y = 1000*(x-0.0025) ``` 实测该函数最终生成 0 个曲线段,整条本应穿过绘图区的直线完全消失。 建议: - 对疑似不连续的采样区间进行中点求值或自适应细分。 - 如果细分过程中找到位于可见范围内的有限点,则说明曲线连续,应保留并使用细分点绘制。 - 达到细分深度或精度上限后仍无法找到范围内的有限点,再将该区间断开。 - 增加陡峭连续函数的回归测试,确保修复渐近线问题时不会误删正常曲线。 ## 已确认内容 - 上一轮的渐近线伪竖线问题已消除。 - PR 标题和描述已经准确覆盖整个 Export Service。 - 后端完整测试:`720 passed` - `git diff --check`:通过 - 与当前远程 `main`:无合并冲突
Kronecker closed this pull request 2026-09-07 00:25:30 +08:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Kronecker/NotesAgentic#41