From f5a951f47a5ebec3f7339ab23725fb3000ab9bb8 Mon Sep 17 00:00:00 2001 From: potaser Date: Thu, 15 Oct 2026 19:35:51 +0800 Subject: [PATCH] docs: add P5 PR report --- .../pr-reports/2026-10-14-p5-ppt-assistant.md | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 docs/pr-reports/2026-10-14-p5-ppt-assistant.md diff --git a/docs/pr-reports/2026-10-14-p5-ppt-assistant.md b/docs/pr-reports/2026-10-14-p5-ppt-assistant.md new file mode 100644 index 0000000..6a4d605 --- /dev/null +++ b/docs/pr-reports/2026-10-14-p5-ppt-assistant.md @@ -0,0 +1,131 @@ +# P5 科研汇报助手 — PR 报告(2026-10-14,v4 更新 2026-10-15) + +## 概要 + +新增「科研汇报助手」(P5):论文 PDF/粘贴文本 → vstore 解析 → map-reduce LLM 大纲 +(5 场景 × 4 时长 × **14 版式**,逐条证据可溯)→ 逐页编辑 → python-pptx 本地生成 +16:9 PPTX 初稿(论文真图卡片化嵌入、分隔页主副标题、讲者备注携带证据引用)。 +全程只新增 `review_service/` 内代码 + BFF 既有 `REVIEW_ENABLED` 条件反代, +禁区(RAG 核心、既有服务、前端 router/db)零改动。 + +**v4 迭代(2026-10-15)**:① 副标题风格数改为动态读取 `GET /ppt/styles`(缺数据回落 +「多风格·图文混排」)② 章节分隔页加副标题(prompt 强制 `subtitle`、渲染 40pt 主标题 + +20pt muted 副标题 + 底部 accent 装饰线、编辑器可改)③ 论文白底原图与页面底色融合 +(surface_2 圆角卡片 + 图注 + 宽/高上限 + 单图页居中留白)。 + +## 修改内容 + +### 后端(`review_service/`) + +| 类别 | 文件 | 说明 | +| --- | --- | --- | +| 改 | `app/config.py` | +`ppt_jobs_dir` / `ppt_styles_dir` 及 abs 属性(+14 行) | +| 改 | `app/main.py` | 导入 ppt 路由、lifespan `ppt_ensure_table()`、挂载(+8 行) | +| 改 | `tooling/requirements.lock` | **+3 行**:`pillow==12.3.0` / `python-pptx==1.0.2` / `xlsxwriter==3.2.9`(三者均已实装于统一 venv) | +| 改 | `.gitignore` | +9 行:`ppt_jobs/` 运行数据、`prewarm.log`、`data/compile_jobs/`、`scripts/`、`data/review.db` | +| 新 | `app/routers/ppt.py`(317 行) | **9 端点**:`GET /styles`、`POST /jobs`、`POST /jobs/pdf`、`GET/PATCH /jobs/{id}`、`POST /jobs/{id}/build`、`GET /jobs/{id}/pptx`、`GET /jobs/{id}/preview/{page}`、`DELETE /jobs/{id}` | +| 新 | `app/services/ppt_outline.py`(917 行) | map-reduce 大纲核心(索引/配额/重验/裁剪/膨胀回修/分隔页 subtitle 规则) | +| 新 | `app/services/ppt_build.py`(1176 行) | python-pptx 生成器(14 版式 token、字体栈、真图卡片容器、分隔页主副标题、讲者备注) | +| 新 | `app/services/ppt_figure_index.py`(264 行) | 论文真图索引(para/图号 → 图片落盘与状态) | +| 新 | `app/services/ppt_preview.py`(230 行) | 逐页 PNG 预览(供面板缩略图,失败不阻断) | +| 新 | `app/services/ppt_store.py`(155 行) | `ppt_jobs` SQLite 持久化(约定 DDL 逐字实现) | +| 新 | `data/ppt_styles/*.json`(14 个) | 版式 token 源码资产(随 git 走,`GET /styles` 的唯一数据源) | +| 新 | `tests/test_ppt_*.py`(6 个 / 102 例) | outline / build / figure_index / preview / router / store | + +### 前端(`ui/` + `tests/`) + +| 类别 | 文件 | 说明 | +| --- | --- | --- | +| 改 | `ui/src/api/review.js`(+50 行) | PPT API 段 + `pptStyles()` | +| 改 | `ui/src/stores/edu.js`(+147 行) | `ppt` 状态块 + actions + `pptLoadStyles` + `SECTIONS` 增列 | +| 改 | `ui/src/components/edu/EduSideNav.vue` / `EduWorkspace.vue` | 菜单项 + PptPanel 注册(各 +2 行) | +| 新 | `ui/src/components/edu/panels/PptPanel.vue`(578 行) | 生成表单 + 编辑器(动态风格数、分隔页副标题输入、逐页预览) | +| 新 | `ui/src/components/edu/panels/ppt-styles.css`(40 行) | 面板样式 | +| 新 | `ui/src/assets/ppt-style-cards/*.png`(14 个,约 21KB/个) | 版式卡面截图 | +| 新 | `tests/frontend/unit/edu/ppt.panel.test.js`(12 例)/ `ppt.store.test.js`(7 例) | P5 前端单测 | +| 改 | `tests/frontend/unit/b2/components.test.js`、`b3/benchpanel.test.js`、`bioflow/benchpanel.bioflow.test.js`、`tests/e2e/bench.spec.js` | **预存失败清零**:① tab 文案「提取任务」→「上传文献」(对齐 `51532a3`)② 模式 pill 断言改为「已随 `43a7c6c` 移除」 | + +**依赖偏差声明**:`python-pptx==1.0.2`(PyPI 最高 1.0.2;需求中 1.1.2 实为 +python-docx 版本,系记混,已在实现时更正)。`xlsxwriter==3.2.9` 当前无代码直接引用, +属统一 venv `pip freeze` 的真实记录,一并同步锁文件——**合并前仍需人工确认这 3 行锁变更**。 + +**DDL**(与约定逐字一致): + +```sql +ppt_jobs(id, status /*outline_ready|building|done|error*/, source_kind, filename, + raw_text, scenario, minutes, style_id, pages_json, pptx_path, + warnings_json, created_at, updated_at) +``` + +**API 前缀** `/api/review/ppt`(9 端点;业务错误一律 200 信封 +`{ok:false, error:{code,message,degraded}}`;二进制下载缺失时回同款信封 JSON)。 + +### 关键渲染约定(v4) + +- **分隔页**:`section_bg` 底(缺则 `surface_2`→`cover_bg`→`bg`),40pt 居中粗体主标题 + + 20pt muted 副标题(`bullets[0]` → `subtitle` → 该章第一页 title 三级兜底,浅底自动换深字)+ + 底部 30% 宽 accent 短线。 +- **真图卡片**:`surface_2` 圆角矩形(8px)容器 + 5mm 内边距,图居中、图注 + `Fig N(论文 S?P?)` 10–12pt muted、与图区留 3mm;混排页图区 ≤55% 页宽且 ≤60% 页高, + 单独图页居中、上下留白 ≥5%。 + +## 测试结果(2026-10-15) + +``` +pytest(review_service 全库): 215 passed in 13.7s (P5 新增 102 → 113 + 102) +vitest edu(tests/frontend/unit/edu): 43 passed (P5 新增 19:panel 12 + store 7) +vitest 全量(tests/frontend/unit): 32 files / 421 passed / 0 failed + —— 修掉 b2/b3/bioflow 共 5 个预存失败(文案改名 + 模式按钮移除) +npm run build: ✓ built(chunk > 500kB 警告为预存) +版式目检: 3 风格 × 10 页预览 PNG 渲染核对(分隔页主副标题/对比度回退、 + 混排图卡 ≤55%、单独图页居中留白)均符合预期 +``` + +## 真实 e2e(v1 阶段记录:官方 MDPI 模板实例 PDF,16813 字符,真实 DeepSeek) + +``` +PDF 模式创建: 21.77s → 12 页(目标 [11,14])warnings=0 llm_calls=7 unverified_evidence=0 +PATCH 编辑: 改写要点 + 新增无证据行 → evidence 同长重验、结构清洗 ✓ +build: 0.13s → 12 slides / 64157 B / 16:9(13.33×7.50in)逐页讲者备注 ✓ +python-pptx 回读: 12 页,S3 首条 = 人工改写文本 ✓ +编辑后下载: ok=false NOT_FOUND(盘上旧文件存在但拒发,pptx_path 清空生效)✓ +text 模式: 15.0s → 9 页(目标 [8,10])group_meeting / 10min / botanic-forest ✓ +短文本: 200 信封 VALIDATION「正文过短(<300 字),无法生成汇报大纲」✓ +清理: 双 DELETE → ppt_jobs 0 行、产物目录空 ✓ +``` + +## 部署验证步骤 + +1. 依赖:同步 `tooling/requirements.lock`(+3 行)并安装到统一 venv。 +2. 重启服务:`cd review_service && bash restart.sh`(8100)。 +3. 健康检查:`curl http://127.0.0.1:8100/health` → `status=ok`、`vstore connected=true`。 +4. 路由:`curl .../openapi.json` 确认 9 个 `/api/review/ppt/*` 路径在列(含 `/styles`)。 +5. BFF:`sdk/.env` 确认 `REVIEW_ENABLED=1`,走 8090 反代冒烟 + `POST /api/review/ppt/jobs`(短文本应得 200 VALIDATION 信封,不打 LLM)。 +6. 真实链路:上传一篇论文 PDF → 出大纲 → 编辑分隔页副标题并保存 → build → 下载 PPTX → + 用 python-pptx 核对页数、16:9 尺寸与分隔页副标题文本。 +7. 回归:`cd review_service && /bin/python -m pytest -q`; + `cd ui && npx vitest run` + `npm run build`。 + +## 部署决策 + +**建议:只合并,下次批量部署。** 本次改动对存量服务零影响(纯新增模块 + +开关化反代),无数据迁移、无 schema 破坏性变更;单点重启 8100 即可生效, +不值得为它单独发版,随下一次批量部署一并上即可。 + +## 风险与回滚 + +| 风险 | 影响 | 缓解 / 回滚 | +| --- | --- | --- | +| `python-pptx==1.0.2` 版本与需求(1.1.2)不一致 | 依赖锁未按原文落库 | 已声明偏差,合并前人工确认 3 行锁变更;如需回退直接还原 lock | +| `xlsxwriter==3.2.9` 无代码引用 | 锁文件带入未用依赖 | venv 实况记录,可保留;若要求最小化可单独剔除该行 | +| LLM 大纲偶发超时/无效 JSON | 创建接口报 `LLM_ERROR`/`LLM_INVALID` | 已分片 reduce + 单次膨胀回修 + 警告降级;前端可重试,无脏数据落库 | +| quote 反查失败残留 evidence(2 条) | 个别要点 `unverified` | **Phase 2**:最长公共子串(≥20 字符)匹配补 `para_id`,失败保持 unverified(边际价值低,v4 不做) | +| 编辑后旧 PPTX 残留盘上 | 无(`pptx_path` 清空后拒发,仅占磁盘) | 删除 job 时 `rmtree` 一并清理 | +| 回滚 | — | 反向还原 12 个已跟踪文件改动 + 删除 44 个新增文件(后端 26 + 前端 18)即可;`ppt_jobs` 表与产物目录可留可删,不被其他模块引用 | + +## 与 `feature/p3b-compile-ui#4f9c077` 的关系 + +v1 版报告曾以同一路径提交于该分支(`docs: add P5 PR report`),内容停留在 3 版式 / +7 端点 / 208 pytest 阶段。本文件为 v4 权威版本;若两分支先后合入,同路径会产生一次 +文本冲突,取本文件(v4)内容即可。