从模板生成 PPT
通过从参考模板提取样式,然后使用 PptxGenJS 构建全新幻灯片来生成演示文稿。
核心原则: 绝不修改现有 PPT XML。查看样式,然后从零开始绘制。
模板管理
模板目录
默认模板目录:{workspaceDir}/template/
每次调用时:
- 扫描
{workspaceDir}/template/中的*.pptx文件。 - 如果找到 一个 模板 → 自动使用它。
- 如果找到 多个 模板 → 列出它们并让用户选择。
- 如果 未找到 任何模板 → 告诉用户上传
.pptx文件或提供路径。
用户上传
接受用户上传的 .pptx 文件。处理前:
- 大小检查:拒绝大于 50 MB 的文件,并提示:“模板文件超过 50MB 限制,请压缩后重试”
- 保存到
{workspaceDir}/template/以便复用。
工作流
阶段 1:提取样式
# If .pptx, convert to PDF for visual analysis:
python3 {baseDir}/scripts/pptx_to_pdf.py template.pptx /tmp/ppt_style/template.pdf
# Extract page images:
bash {baseDir}/scripts/extract_pages.sh /tmp/ppt_style/template.pdf /tmp/ppt_style/ 150
# Precision extraction from PPTX XML:
python3 {baseDir}/scripts/extract_style.py template.pptx -o /tmp/ppt_style/style_raw.yaml
读取 style_raw.yaml 获取精确数据(十六进制颜色、字体名称、以 pt 为单位的字号、以英寸为单位的位置、填充类型、线条样式)。然后读取 3-5 张页面图片进行语义理解(元素角色、布局分类)。
提取两个层级:
| 层级 | 来源 | 需要捕获的内容 | |-------|--------|----------------| | 全局 | style_raw.yaml | 颜色(十六进制)、排版(字体/字号/字重)、装饰 | | 每布局 | style_raw.yaml + images | 元素清单:类型、角色、x/y/w/h、样式属性 |
元素类型:text、image、video、shape、line、numbered_list、step_list、tag_group、chart、table。
对于图片/视频:设置 placeholder: true,并提供 description 供用户替换。
将结果写入 style.yaml。Schema:[references/style-schema.md](references/style-schema.md)。
阶段 2:生成 PPT
使用 pptx 技能(PptxGenJS)创建幻灯片:
- 读取
style.yaml获取视觉参数。 - 结合用户内容(主题、页数、大纲)。
- 生成应用已提取样式的 PptxGenJS JavaScript。
- 运行 JS 以生成
.pptx。 - QA:转换为图片,验证样式还原度。
大型演示文稿策略(>15 页)
PptxGenJS 生成速度很快(秒级),但为许多幻灯片 编写 JS 代码 可能会触及上下文/时间限制。缓解措施:
| 页数 | 策略 | |-------|----------| | ≤15 | 单次生成流程 | | 16-30 | 拆分为 2 个 JS 文件:第 1-15 页、第 16-30 页。依次生成,通过 pptx-merge 合并,或在两个代码块中使用一个 pres 对象生成 | | 31-100+ | 为每种布局类型生成一个 幻灯片工厂函数,然后遍历内容数组。一个 JS 文件,数据驱动 |
大型演示文稿的 幻灯片工厂模式:
// Define layout factories from style.yaml
function makeCover(pres, content) { /* ... */ }
function makeContent(pres, content) { /* ... */ }
function makeSection(pres, content) { /* ... */ }
// Content array — easy to extend
const slides = [
{ layout: "cover", title: "...", subtitle: "..." },
{ layout: "content", title: "...", items: [...] },
// ... 50+ entries
];
slides.forEach(s => layoutFactories[s.layout](pres, s));
这使代码规模保持为 O(layouts),而不是 O(pages)。
输出大小控制
目标输出 < 20 MB。PptxGenJS 输出通常很小(纯文本演示文稿为 100-500 KB)。大文件来自嵌入图片。如果输出接近 20 MB:
- 在 PptxGenJS 选项中降低图片分辨率/质量。
- 使用占位符代替嵌入图片。
- 如果不可避免,拆分为多个文件。
- 警告用户:“PPT 接近 20MB 限制,已使用图片占位符,请手动替换”
占位符约定
- 图片:深色矩形 + 虚线灰色边框 + 🖼️ + 标签 + 建议
- 视频:深色矩形 + 虚线红色边框 + ▶️ + 标签 + 建议
关键规则
- 绝不修改现有 PPT XML——始终从零开始生成。
style.yaml可复用——一旦提取,即可在同一风格下生成无限数量的 PPT。- 在 PptxGenJS 中使用
shrinkText: true以自动适配长文本。 - 精确匹配来自
style_raw.yaml的幻灯片尺寸(不要硬编码 16:9)。
文件约定
{workspaceDir}/
├── template/ ← .pptx templates (auto-discovered)
│ └── *.pptx ← max 50 MB each
├── output/ ← generated PPTs
│ └── *.pptx ← max 20 MB each
/tmp/ppt_style/ ← working directory (ephemeral)
├── template.pdf
├── page-*.jpg
├── style_raw.yaml ← from extract_style.py
└── style.yaml ← merged (exact + semantic)
故障排查
| 问题 | 解决方案 | |---------|----------| | 模板 > 50 MB | 让用户压缩或移除嵌入媒体 | | 输出 > 20 MB | 使用占位符,减少图片数量/分辨率 | | >30 页超时 | 使用幻灯片工厂模式、数据驱动生成 | | 未找到模板 | 提示用户上传 .pptx 或指定路径 | | 多个模板 | 列出选项,让用户选择 | | 字体不可用 | 回退到 Arial/sans-serif;在输出中注明 | | 复杂渐变 | 在 style.yaml 中描述;使用背景图片 |