ppt-template-fit — PPT 报告模板适配与排版质检
解决报告 PPT 制作中最常见的一类问题:内容比例和模板对不上。报告页面按 16:9 设计,公司模板却是 4:3;直接塞进去就右侧溢出、文字跨行窜行、数字被折行拆断("9.10h"变成"9.1/0h")。本技能提供从比例适配、模板清理、写入、锁处理到成品质检的完整流程。
适用场景
- 场景 A|按模板出报告:报告内容已备好(数据、图表、明细表),需要放进公司/个人固定模板(任意比例),要求不跨行、不窜行、不溢出
- 场景 B|换比例重排:16:9 的旧报告要改放进 4:3 模板(或反向)
- 场景 C|成品质检:报告做完后逐页验证有无文字拆行、表格窜行、元素出界
- 场景 D|slidep 报错排查:写入报 pageType notes / page not found / 实例残留,或写入后文件被锁
本技能的操作脚本对任意 .pptx 通用;涉及 slidep DSL 的部分(比例适配的代码写法)会明确标注。
核心规则
比例适配(仅 slidep DSL 页面适用)
- 画布映射:slidep 转换器固定按
1280×720px → 12192000×6858000 EMU(13.33×7.5in)映射,96px/in、px→pt=0.75。Slide 根节点的width属性会被忽略——写width:960没用。但非根 Box 的显式 width 会被精确尊重(66px 色条实测像素级准确)。 - 任意版心解法:Slide 定死
width:1280, height:720, padding:0,内容包进一层显式容器的 Box——目标版心宽度(in)×96 就是容器 px 宽(4:3 版心 10in →width:960)。容器内左右分栏用显式 px 宽度,不依赖根宽度的 flex:1。 - 换行只能
<br />:DSL 文本换行必须用<br />,\n无效。窄栏里的数字会被自动折行拆开("9.10h"→"9.1/0h"),必须用<br />在数字前后受控换行。 - 表格防窜行:明细表用固定行高 + 固定列宽的手工行(每格文字按字宽核算),列窄时缩字号(11-12px),禁止依赖自适应宽度。
文件锁(红线,任何场景适用)
绝不对用户正在打开/预览的文件强制关闭——曾因此丢失用户写到一半的未保存数据。写入前先查编辑器池(edsdk get_pool_status):is_dirty=true 或用户正在用的实例一律不 close,改在副本上操作或提示用户自行关闭。只有 AI 自己产生的残留实例才可 close_file force=true。
模板清理
模板里的空白页(无 <p:sp>)和 notesSlide(备注页)残留会让 slidep 报 page is not found: pageType notes、占用 page-index 导致写错页,写入前必清(scripts/clean_template.py)。
视觉验证(必做,XML 检查不能替代)
slidep 的 screenshot 子命令有内部 bug(模块路径指向 file:///workspace/...),不要重试,直接用 scripts/export_preview.py(PowerPoint COM)导 PNG 逐页目检:数字拆行、表格窜行、底部截断、配色一致性。XML 边界正确 ≠ 视觉正确。
标准工作流
模板备份 → 清理模板(scripts/clean_template.py)→ 删旧页(scripts/delete_slides.py)
→ 逐页写入(slidep upsert-dsl,带重试循环)→ 释放 AI 侧文件锁
→ 边界校验(scripts/check_bounds.py)→ 视觉验证(scripts/export_preview.py 导 PNG 逐页目检)
脚本用法(对任意 .pptx 通用)
# 1. 清理模板:删空白页 + 全部 notesSlide + 对应 rels/ContentTypes 条目
python scripts/clean_template.py <原模板.pptx> <清理后.pptx>
# 2. 删除指定页(0 基索引,逗号分隔)
python scripts/delete_slides.py <in.pptx> <out.pptx> 3,4,5
# 3. 边界校验:逐页报告内容形状右/底边界(英寸),溢出版心即 FAIL;全页背景框自动排除
python scripts/check_bounds.py <成品.pptx> # 全部页
python scripts/check_bounds.py <成品.pptx> 4 10 # 第4~10页(1基)
# 4. 视觉验证:PowerPoint COM 导 PNG(需本机装有 PowerPoint;4:3 建议 1280×960)
python scripts/export_preview.py <成品.pptx> <输出目录> [--pages 4-10] [--width 1280] [--height 960]
slidep 写入要点
<pptx>是位置参数;替换已有页用--page-index(0 基),追加则用当前页数作索引- 首次调用可能因会话未就绪失败,带 3-5 次重试(间隔 1.5s),成功判据:输出含
{开头 JSON 行且"ok":true - 写入后文件被编辑器实例锁定;再次用 python 改 zip 前先释放AI 自己的实例(见文件锁红线)
- 渲染/截图目录用纯 ASCII 路径(如
D:/render_tmp/),中文路径曾导致渲染超时
常见问题速查
| 现象 | 根因 | 处理 |
|---|---|---|
| 内容右侧溢出(右边界 13.33in) | 忘记包版心容器 | 核心规则第 2 条 |
| 文字跨行/窜行 | 比例不匹配 + 自适应宽度 | 版心容器 + 固定行高表格 |
| 数字被拆开("9.1/0h") | 窄栏自动折行 | <br /> 受控换行 |
page is not found: pageType notes |
模板残留备注页 | clean_template.py |
| upsert 首次失败 | 会话未就绪 | 重试循环;仍失败则 close AI 残留实例 |
| WinError 32 文件被占用 | 编辑器实例持锁 | close AI 实例;用户打开中的文件禁止 force |
| 中文路径渲染失败 | 渲染器对中文路径敏感 | 复制到纯 ASCII 路径 |
上架注意
SkillHub 上传白名单不含 .slide 后缀。打包 slidep DSL 模板时一律命名 NN.slide.md——slidep 的 validate / upsert-dsl --dsl-file 不校验扩展名,.md/.txt 均可正常读写。
单位换算表、4:3 完整代码模式、实战避坑详录见 references/pitfalls.md。