feat/export-service
main
导出服务(Markdown → HTML)与函数图像静态渲染,含两轮审阅修复。本 PR 是 #20 审阅结论(1 P1 + 2 P2)修复后的复审提交。
#20
backend/app/export/
backend/app/plot/
ast
<script>
function-plot
054f704
contracts.py
main.py
README.md
backend 全量 pytest:616 passed(含新增 test_plot.py 与审阅回归用例)。
backend
pytest
test_plot.py
backend/
实现 Export Service 完整生命周期:mistune AST → Document AST → HtmlExporter 渲染完整 HTML5,异步任务注册表 + 取消 + 24h 产物过期。新增 5 个 /api/exports 端点与 15 项测试;pdf/docx 与函数图像静态渲染留待后续 PR。
- P1 链接/图片 URL 协议白名单校验,危险协议降级为纯文本 + warning - P2 图片 AST 字段映射(src=attrs.url,alt 取 children 文本) - P2 原始 HTML 块转义保留,正文不丢失 + warning - P2 过期/淘汰/重启清理导出产物文件 - P2 解析与渲染移入 asyncio.to_thread,运行中取消生效 - P2 function-plot 围栏别名补全 - 回归测试覆盖全部修复 Co-Authored-By: Claude Code <noreply@anthropic.com>
- 新增 app/plot 包:白名单表达式解析(ast 无 eval)+ FunctionPlot 模型 + 静态 SVG 渲染 - HtmlExporter 的 function_plot 节点解析并内嵌 SVG,解析失败回退占位并转诊断 - 新增 test_plot.py(13 个测试)覆盖表达式安全、指令解析、SVG 输出与导出链路集成 Co-Authored-By: Claude Code <noreply@anthropic.com>
- P1 浮点刻度死循环:_ticks 改为有上限的整数索引推进并校验步长推进 - P2 求值异常:白名单函数校验参数数量;负数底非整数指数按断点处理;采样容错复数 - P2 无效纵轴范围:退化/非有限 range 丢弃并自动采样重算;渲染异常回退占位不阻断导出 - 补 6 个回归测试 Co-Authored-By: Claude Code <noreply@anthropic.com>
同步 main(054f704),解决 contracts.py / main.py / README.md / 技术栈说明 的合并冲突。 - contracts.py:保留 pydantic 多行导入并新增 RequestOverride - main.py:合并 lifespan(导出孤儿清理 + 转写/本地模型生命周期) - README.md / 技术栈说明:文档取 main 最新版本 Co-Authored-By: Claude Code <noreply@anthropic.com>
审阅提交:50d7fb4
50d7fb4
上一轮提出的 1 个 P1、2 个 P2 已完成修复,对应回归测试也已补充。本轮复审另发现 2 个 P2、1 个 P3。
位置:backend/app/export/exporters/html.py:205–213
backend/app/export/exporters/html.py:205–213
parse_source(node.text) 位于 try 块之外。由约 1000 个连续加法组成的合法表达式会在 AST 递归检查过程中触发 RecursionError,异常直接离开 HtmlExporter,最终导致整篇笔记的导出任务变为 EXPORT_RENDER_FAILED。
parse_source(node.text)
try
RecursionError
HtmlExporter
EXPORT_RENDER_FAILED
建议:
nan
位置:backend/app/plot/render.py:188–218
backend/app/plot/render.py:188–218
当前只检查坐标端点是否有限,没有检查端点相减后的跨度是否仍为有限数值。例如:
domain: -1e308, 1e308 range: -1, 1 y=0
或者:
domain: -1, 1 range: -1e308, 1e308 y=x
端点均能通过现有校验,但跨度计算会溢出为 inf,后续坐标换算生成包含 nan 的 SVG。导出任务仍报告成功,且不会产生 warning。
inf
xmax - xmin
ymax - ymin
位置:docs/contracts/第二阶段接口契约-开发版.md:1083
docs/contracts/第二阶段接口契约-开发版.md:1083
本 PR 已经实现 function-plot 到静态 SVG 的导出,但文档仍称函数图像将保留为占位代码块、静态渲染等待后续 PR,与实际实现和 PR 描述不一致。
请将状态更新为:
git diff --check
请修复以上问题并补充边界测试后再提交复审。
No dependencies set.
The note is not visible to the blocked user.
概述
导出服务(Markdown → HTML)与函数图像静态渲染,含两轮审阅修复。本 PR 是
#20审阅结论(1 P1 + 2 P2)修复后的复审提交。主要内容
导出服务(Markdown → HTML)
backend/app/export/:异步导出任务(内存注册表 + 取消)、mistune AST 渲染、HTML 导出器。函数图像静态渲染(Function Plot)
backend/app/plot/:白名单表达式解析(ast白名单,不 eval/exec)、结构化模型、纯几何 SVG 静态渲染(无<script>)。function-plotfenced block → 内嵌 SVG;非法表达式回退占位 + 可定位诊断。审阅修复(本轮,对应
#20结论)合并 main
main(054f704),解决contracts.py/main.py/README.md/ 技术栈说明 合并冲突。测试
backend全量pytest:616 passed(含新增test_plot.py与审阅回归用例)。说明
backend/代码(合并 main 带来的 frontend 变更除外)。审阅结论:请求修改,暂不建议合并
审阅提交:
50d7fb4上一轮提出的 1 个 P1、2 个 P2 已完成修复,对应回归测试也已补充。本轮复审另发现 2 个 P2、1 个 P3。
[P2] 复杂表达式会绕过函数图像的异常回退
位置:
backend/app/export/exporters/html.py:205–213parse_source(node.text)位于try块之外。由约 1000 个连续加法组成的合法表达式会在 AST 递归检查过程中触发RecursionError,异常直接离开HtmlExporter,最终导致整篇笔记的导出任务变为EXPORT_RENDER_FAILED。建议:
[P2] 极端但有限的坐标范围会生成包含
nan的 SVG位置:
backend/app/plot/render.py:188–218当前只检查坐标端点是否有限,没有检查端点相减后的跨度是否仍为有限数值。例如:
或者:
端点均能通过现有校验,但跨度计算会溢出为
inf,后续坐标换算生成包含nan的 SVG。导出任务仍报告成功,且不会产生 warning。建议:
xmax - xmin、ymax - ymin必须有限且大于零;[P3] 接口文档仍描述函数图像静态渲染尚未实现
位置:
docs/contracts/第二阶段接口契约-开发版.md:1083本 PR 已经实现
function-plot到静态 SVG 的导出,但文档仍称函数图像将保留为占位代码块、静态渲染等待后续 PR,与实际实现和 PR 描述不一致。请将状态更新为:
function-plot已支持静态 SVG;验证结果
git diff --check:通过main:无合并冲突请修复以上问题并补充边界测试后再提交复审。
Pull request closed