- name
- total-pipe-deck
- description
- 从论文 PDF 到研究汇报 PPT 的证据—故事—页面流水线(paperworkflow → 高能力 Story subagent → pwf2rpa → research_ppt)。当用户要"把这篇论文做成汇报/组会 PPT""从 PDF 生成 slides""跑通 Total-pipe"时使用。
# Total-pipe:论文 → 研究汇报 PPT
Evidence、Story、Slide Plan、Render 四层流水线。**本文件就是调用契约,不要再去读连接器源码。**
```
paperworkflow Story Planner subagent pwf2rpa research_ppt render(分支) telemetry + QA
PDF → 证据注册表 → 科研叙事重构 → 叙事映射 → 选版面 / 规划 → deck.pptx → OOXML 遥测 + QA
workflow.json story_plan.json rpa_input.json deck_plan.json sidecar / QA 报告
```
渲染只能在 `deck_plan.json` 已完成后选择一个下游分支:
| 分支 | 交付渲染器 | 设计落地与遥测门禁 |
|---|---|---|
| `slidep` | slidep / tencent-pptx | `deckplan2slide.py` 骨架 → S8 设计落地 → `pptx-telemetry` |
| `artifact-tool` | Presentations + `@oai/artifact-tool` | 直接按 `deck_plan` 槽位、treatment 与 decoration 生成 → `artifact-telemetry` → `pptx-telemetry` |
两条分支是**等价的替代路径,不是可任选跳过的步骤**。不得用 artifact-tool 在没有计划约束的情况下自由手写一份 PPT,也不得要求 artifact-tool 再伪造 `.slide` 骨架。
| 段 | 连接器 | 位置 |
|---|---|---|
| 1 | `paperworkflow` | `F:/Workbuddy/Total-pipe/paperworkflow` |
| 1.5 | Story Planner | 用户明确选择的高能力模型 subagent(不是主代理自行总结) |
| 2 | `pwf2rpa` | `F:/Workbuddy/pwf2rpa` |
| 3 | `research_ppt` | `C:/Users/Beibei/plugins/research-ppt-assistant`(symlink,真身 `F:/Project/PPTcreator/...`)|
版本:RPA **0.6.1**,版面库 **2.0.0**(320 版面 / 40 分类),pwf2rpa **1.1.0**。
> RPA 必须用 **Node.js 24**(固定 `D:/Node24/node.exe`,v24.20.0 Krypton LTS)。
> 不要硬编码 WorkBuddy managed node 的 `versions/<ver>/node.exe` 路径——升级会漂移。
> 三个连接器都必须在连接器管理页点过 **Trust** 才有工具可用。如果某个工具
> 不存在,先让用户去 Trust,不要去改代码。
### ⚠ Story Planner 是硬门禁:必须先问用户选模型,再调用 subagent
`paperworkflow` 产出 `workflow.json` 后,**不要直接调用 `pwf2rpa_check/convert`**。
必须依次完成:
1. 从当前运行环境可用模型中筛出高能力候选,向用户明确提问“Story Planner 用哪个模型?”;给 2–3 个候选即可,可以标推荐项,但**不得替用户默认选择**。
2. 用户选择后调用 `pwf2rpa_story_prompt`:
```text
pwf2rpa_story_prompt
workflow_path
model # 用户刚刚明确选择的精确模型名
reasoning_effort # high / xhigh / max / ultra;不得低于 high
selected_by_user=true
```
3. 把工具返回的完整 prompt package 原样交给该模型的 **subagent**。不得由主代理代写,不得用新建普通任务冒充 subagent,也不得静默改用更便宜模型。
4. 保存 subagent 的纯 JSON 输出为 `story_plan.json`。若输出不合规,错误和原始证据应回送同一个 subagent 修订;主代理只负责编排与确定性校验。
5. 若当前环境没有 subagent 能力、用户尚未选模型或所选模型不可用,停在此阶段如实报告。完整 Total-pipe 不得退回 Figure 顺序或确定性 fallback 冒充成功。
`story_plan.json` 的最小契约:
```json
{
"planner": {
"mode": "subagent",
"model": "<用户选择>",
"reasoning_effort": "high",
"selected_by_user": true
},
"core_question": "论文真正要解决的核心问题",
"main_message": "整场汇报希望听众记住的一句话",
"story": [
{
"question": "当前科学问题",
"answer": "Evidence 支撑的回答",
"evidence": ["EV0001", "EV0002"],
"next": "当前证据留下、使下一步实验成为必要的疑问"
}
],
"ending": {"takeaway": "最终结论", "limitation": "边界或未解决问题"}
}
```
必须有 5–8 个节点。节点是科研推理步骤,不是 Figure,也不等同于最终页数;下游保留 `allow_auto_split`。Story 只决定“哪些证据最重要、为什么按这个顺序讲”,不决定布局、配色、裁图、页数或完整实验参数。
硬规则:Evidence id 必须真实存在;不得把共现改成因果;不得提高 may/likely/suggest/possibly 的确定性;`next` 必须是疑问、缺口、待排除解释或待验证机制,不能是“然后 / 此外 / 接下来 Fig.4”。相邻节点应能用“因此 / 但是 / 为了验证 / 为了排除 / 如果该解释成立”连接。
---
## ⚠️ 第一次跑就要走完:不许挑着用命令
历史教训:RPA 有 20 个 CLI 命令 + 20 个 MCP 工具,实测第一次跑只用了 3 个就开工,
`deck_plan.json` 沦为一次性产物。**根因不是 Agent 偷懒,是渲染层不消费 deck_plan
——slidep 吃手写 SlideDSL,Agent 完全可以绕开规划。**
slidep 分支用「骨架生成器」防止绕开规划;artifact-tool 分支用不可省略的 plan-to-layout 映射和 layout/v4 遥测防止同一问题。
### slidep 分支:阶段 3 必须按序跑完(缺一步不许进阶段 4)
**首选方式:一条命令跑完,别手敲:**
```bash
python "C:/Users/Beibei/.workbuddy/skills/total-pipe-deck/scripts/rpa_full_pipeline.py" \
--rpa-input F:/x/rpa_input.json \
--out-dir F:/x \
--project F:/x/deck \
--assets-from-slides # 或 --assets-map 映射.json
```
它按 S0→S8 串行,任一步 FAIL 立即中断(退出码 1),每步产物落在 `<out-dir>/_rpa/`,
并生成 `_pipeline_report.md`。常用开关:
| 参数 | 用途 |
| :-- | :-- |
| `--assets-map m.json` | `{"4":["assets/fig1.png"]}` 显式指定每页用图 |
| `--assets-from-slides` | 从 `<project>/slides/NN.slide` grep 图片引用自动映射 |
| `--skeleton-out slides` | 默认 `slides_skeleton`(**不会覆盖正式页面**);显式改 slides 才覆盖 |
| `--skeleton-force` | 骨架目录已有 .slide 时强制覆盖 |
| `--allow-visual-fail` | S5 几何不兼容仍继续(仅当手写 DSL 不按 RPA 槽位摆位时用) |
| `--no-design` | 跳过 S8(不推荐;跳过就等于回到"空旷"的旧行为) |
| `--min-font 18` | S8 默认字号下限;不能豁免上游或最终投影检查 |
| `--density LO HI` | 可选元素数参考,默认关闭,不应以此填满页面 |
| `--strict` | warning 也当失败 |
| `--allow-legacy-no-story` | 仅兼容旧输入,跳过 Story provenance;完整 Total-pipe 禁用 |
S0–S8 分别是(**以 `rpa_full_pipeline.py` 的实现编号为准**,别按语感排):
| | 步骤 | 说明 |
| :-- | :-- | :-- |
| S0 | Story provenance | 必须证明用户明确选模、由 subagent 执行、reasoning ≥ high;否则阻断 |
| S1 | `normalize-content` | → `content_model.json` |
| S2 | `plan` | → `deck_plan.json`,`pipeline_status` 必须 `plan_complete` |
| S3 | `validate-deck` | 必须 `valid` |
| S4 | `deckplan2slide.py` | 生成 SlideDSL 骨架(**必须先于 S5**,否则 preflight 报 `NO_PAGE_SOURCES`) |
| S5 | `preflight` | `preflight_complete` 且 `status != invalid` |
| S6 | `visual-fit-preflight` | 每张图不得 `fail` |
| S7 | `group-fit-preflight` | 每页 ≥2 图时查分组几何 |
| S8 | `design_land.py` | 出 `design_contract.json` + `_design_brief.md`;准备失败不可放行 |
S5 失败时脚本会直接给替代版面(按图槽几何算 contain 填充率排序),照着把该页
brief 的 `category_hint` 改掉再重跑即可,不用自己翻版面库。
<details><summary>手工分步跑法(脚本出问题时才用)</summary>
```bash
NODE=D:/Node24/node.exe
RPA=C:/Users/Beibei/plugins/research-ppt-assistant
cd $RPA
$NODE server/cli.mjs normalize-content --file <rpa_input.json> --detail-level compact > content_model.json
$NODE server/cli.mjs plan --file <rpa_input.json> --presentation-type group_meeting \
--slide-count N --detail-level compact > deck_plan.json
$NODE server/cli.mjs validate-deck --file <deck_plan 与 content_model 合并后的 json>
$NODE server/cli.mjs preflight --file preflight-input.json
```
`preflight-input.json` 模板(`deck_plan.slides` 必须填完整数组):
```json
{
"renderer_inputs": {
"requested_renderer": "slidep", "renderer_version": "5.4.4", "platform": "win32",
"project_path": "<PPT项目目录绝对路径>", "project_exists": true,
"source_files": ["slides/01.slide"], "live_watch_requested": false
},
"deck_plan": { "theme_id": "paper_blue", "slides": [] }
}
```
`visual-fit-preflight` 最小输入(注意 `visual_container.content_bbox` 若给则必须
**等于** `allocated_visual_bbox`,否则抛 RangeError):
```json
{
"visual_id": "P04:visual",
"source": {"width": 1440, "height": 1253},
"source_region": {"x": 0, "y": 0, "width": 1440, "height": 1253},
"visual_intent": {"visual_type": "dense_plot", "crop_policy": "full_figure",
"fit_policy": "contain", "priority": "primary_visual"},
"visual_container": {"container_id": "visual"},
"allocated_visual_bbox": {"x": 659.1, "y": 388.8, "width": 550.4, "height": 223.2}
}
```
`allocated_visual_bbox` = 版面 `slot_specs[].pptx_in` × 96(英寸→px)。
</details>
过关线:`pipeline_status == preflight_complete` 且 `status != invalid`,无重复 pageId。
页面带科研图必跑 `visual-fit-preflight`;同页多图有语义关系时补 `group-fit-preflight`。
### slidep 分支:阶段 4 只能从骨架开始(硬约束,这是关键机制)
```bash
python "C:/Users/Beibei/.workbuddy/skills/total-pipe-deck/scripts/deckplan2slide.py" \
--plan deck_plan.json --rpa-root $RPA --out slides/ --node $NODE
```
- 没有 `deck_plan.json`,或 `pipeline_status != plan_complete` → **退出码 1,一个页面都不给生成**
- 输出 `slides/NN.slide`:slot 几何取自 `slot_specs[].pptx_in`(×96 转 px),按 `reading_order` 摆好,附 C 区页脚
- 输出 `slides/_slots.md`:每页每 slot 的 `max_chars` / `max_lines` / 字号 hint
- **填内容时严格照 `_slots.md` 的容量写**,超了会被判 `CAPACITY_EXCEEDED`
这套机制把 RPA 从「可跳过」变成「绕不过」:不跑 plan → 没有 layout_id → 没有骨架 → 无法渲染。
实测生成的 13 页骨架 `slidep-validate` 13/13 通过。
改页数时先改 `briefs.json` 的条数再重跑 plan(`--slide-count` 是目标不是填充),
然后删掉旧 slides/ 重新生成骨架。
### S8 设计落地层(骨架 → 渲染之间的必经站)
可在 slide brief 的 `metadata.presentation_intent` 声明页面意图:
```json
{"objective":"定量证据只覆盖指定样品", "emphasis":"low",
"required_on_screen":["2 nm MoS₂"],
"speaker_notes":["补充实验的详细条件"], "appendix":["完整光谱"]}
```
`objective` 是本页要建立的判断,`emphasis` 为 low/medium/high;RPA 将其写入
`design_ir.presentation_intent`,并用于主消息与强调等级。其他字段默认空数组。
两条 telemetry 的 `run_qa.py --plan deck_plan.json` 按页码传入此契约。
`required_on_screen` 检查渲染文本中的字面短语(忽略空白),不是语义等价判断;
栅格图片可能包含未识别文字时标为不可评估,需看渲染图确认。
notes/appendix 字段只是分层计划,不代表已写入 PPT;渲染作者仍须落实。
影响结论范围的必要限定语不能只放讲稿或附录。
QA 的标准字号单位是 pt;artifact-tool CSS px 按 72/96 转换。
Total-pipe 的两条 QA 默认启用投影字号门槛,保留 `--viewing-mode` 的显式选择;
缺失字号数据不可算通过。旧 RPA 调用未启用 `enforce_typography` 时保持原行为。
两条 QA 脚本在硬失败、字号不可评估或必要短语未确认时退出码为 1,
汇总 `release_status=blocked`。普通警告或待人工看图标为 `review_required`,
退出码 0 不等于已完成视觉验收。计划页码与 sidecar 必须匹配,不能默默跳过。
**作用**:在已放行的槽位内部细化视觉组织。少元素和留白不是缺陷;
优先放大关键证据、删除重复强调,不能为了填空缩字或添加无信息装饰。
S8 保留上游可读性约束,最终以实际渲染结果检查为准。
契约关系(别搞反):
| 契约 | 管辖范围 | 字号下限 |
| :-- | :-- | :-- |
| `layouts.json` | 版面选槽(S1–S7) | 18pt(实测 `{20:242, 18:78}`) |
| `design_contract.json` | 槽位内部排版(S8+) | 默认 18pt(显式旧契约仍可加载) |
阶段切换不豁免字号约束。旧契约可加载不等于通过最终投影 QA。
```bash
DL="C:/Users/Beibei/.workbuddy/skills/total-pipe-deck/scripts/design_land.py"
python "$DL" contract --out design_contract.json --min-font 18
python "$DL" brief --skeleton slides/ --slots slides/_slots.md --out slides/_design_brief.md
# —— 这里由 Agent 按任务书自由发挥,改写/扩写 slides/*.slide(构图不受脚本约束)——
python "$DL" check --slides slides/ --contract design_contract.json --out _design_check.md
# 图片资产不在默认位置时用 --assets 指路(可给多个;给「含 assets/ 的目录」或 assets/ 本身都行):
# python "$DL" check --slides deck/slides --assets deck/assets
```
`rpa_full_pipeline.py` 的 S8 已把 contract + brief 一并跑掉,所以一键跑完就有任务书;
**`check` 要等落地页写完再手动跑。**
**关键:脚本不代写设计。** `brief` 只给三类东西——
1. **事实**:每槽 bbox / 容量 / 已用字数 / 未覆盖的空白带 / 本页图片路径
**+ 每张图的原始像素、图片比例、当前图框、建议图框、不改会裁掉多少**
2. **软目标**:字号阶梯;元素数区间仅在显式指定时启用,不是填充任务
3. **语汇货架**:顶栏标签 / 图注 / 脚注引文 / 指标双列 / 序号徽章 / 关键词高亮 /
来源标注 / 对比条 / 流程箭头 / 分隔留白 —— **是"货架"不是"清单",可全不用,可自创**
`check` 只卡**物理不可行**项(画布越界 / 字号低于下限 / 文字溢出 / 页脚与页码 /
**图片图框比例 ≠ 图片比例**),密度与构图只 WARN。`--strict` 才把 WARN 算失败。
#### ⚠ 图片:图框宽高比必须 = 图片文件自身比例(v1.1.0 起进 check)
**这是最容易被忽略、后果最直观的一条。** slidep 的 pptx 写出端对图片
**一律按 cover 裁切到图框比例**:
- `objectFit` 写 prop 也好、写在 `style` 里也好,填 `contain` / `cover` / `fill`
—— 产出**逐字节相同**,属性完全无效(已用 5 变体探针实测)
- 唯一影响裁切量的是**图框自身的宽高比**:`裁切比 = 1 − min(框AR/图AR, 图AR/框AR)`
- 实例:`440×209` 的图(AR 2.11)放进 `1107×318` 的槽(AR 3.48)→ 上下各裁 **19.76%**,
器件截面图的顶部标签与底部衬底**双双被切掉**
所以**「把图铺满槽位框」这个动作本身就是错的**。正确顺序是:
1. 读图片真实像素(`design_land.py` 自带 PNG/JPEG/GIF/BMP/WebP 头解析,纯标准库)
2. 按图片比例算 contain 适配矩形 `fit_rect(iw, ih, box_w, box_h)`
3. **让图框等于这个矩形**(contain 与 cover 在此时重合,歧义消失),在槽位内居中
4. 图卡 = 适配矩形 + padding;**腾出来的空档要用真实内容填**(参数表 / 指标行),
而不是让大卡片空着 —— 否则 `element_area_ratio` 反而掉下来
`brief` 已为每张图算好建议尺寸,直接抄;`check` 对偏差 >2% 的图判
`IMAGE_ASPECT_MISMATCH`(FAIL)并给出应改成的具体尺寸。
`deckplan2slide.py` 的图槽注释里也会打印**槽位框的宽高比**供落地层比对。
> 规划器其实已经声明了 `allowed_transformations.preserve_visual_aspect = true`,
> 只是此前**没有任何一环执行它** —— S8 就是执行者。
**版面库实测天花板**(`research-ppt-assistant/assets/layout-library/layouts.json` v2.0.0):
| 事实 | 值 |
| :-- | :-- |
| 每版面槽位数 | `{4:16, 5:112, 6:114, 7:68, 8:10}` → 单页最多 8 个元素 |
| 1864 个槽的 `font_pt_hint` | 全为 `None`(不规定细粒度字号) |
Voir sur GitHub