此技能创建技能,而非演示文稿。 当用户想要将其
PowerPoint
模板转换为可重用的技能以便日后生成演示文稿时使用此技能。如果用户只是想创建演示文稿,请使用
pptx 技能。
生成的技能包括:
assets/template.pptx - 模板文件SKILL.md - 完整说明(无需引用此元技能)关于通用技能构建最佳实践,请参考
skill-creator 技能。此技能专注于 PPT 特定模式。
skill-creator
技能设置技能结构assets/template.pptxskill-creator 技能打包为
.skill 文件关键:提取精确的占位符位置 - 这决定了内容区域边界。
from pptx import Presentation
prs = Presentation(template_path)
print(f"尺寸:{prs.slide_width/914400:.2f}\" x {prs.slide_height/914400:.2f}\"")
print(f"布局数:{len(prs.slide_layouts)}")
for idx, layout in enumerate(prs.slide_layouts):
print(f"\n[{idx}] {layout.name}:")
for ph in layout.placeholders:
try:
ph_idx = ph.placeholder_format.idx
ph_type = ph.placeholder_format.type
# 重要:提取精确位置(英寸)
left = ph.left / 914400
top = ph.top / 914400
width = ph.width / 914400
height = ph.height / 914400
print(f" idx={ph_idx}, type={ph_type}")
print(f" x={left:.2f}\", y={top:.2f}\", w={width:.2f}\", h={height:.2f}\"")
except:
pass要记录的关键测量值:
关键: 内容区域并不总是在副标题占位符之后立即开始。许多模板在副标题和内容区域之间有视觉边框、线条或保留空间。
最佳方法: 查看布局 2 或类似的"内容"布局,这些布局有
OBJECT 占位符 — 这个占位符的 y
位置指示内容应该实际从哪里开始。
# 找到 OBJECT 占位符以确定真正的内容起始位置
for idx, layout in enumerate(prs.slide_layouts):
for ph in layout.placeholders:
try:
if ph.placeholder_format.type == 7: # OBJECT 类型
top = ph.top / 914400
print(f"布局 [{idx}] {layout.name}:OBJECT 从 y={top:.2f}\" 开始")
# 这个 y 值就是您的内容应该开始的位置!
except:
pass示例: 一个模板可能有:
使用 OBJECT 占位符的 y
位置作为内容起始点,而不是副标题的结束位置。
生成的技能应有此结构:
[公司]-ppt-template/
├── SKILL.md
└── assets/
└── template.pptx
生成的 SKILL.md 必须是自包含的,包含所有嵌入的说明。使用此模板,从您的分析中填写括号内的值:
---
name: [公司]-ppt-template
description: [公司] PowerPoint 模板,用于创建演示文稿。当创建[公司]品牌的融资演示稿、董事会材料或客户演示文稿时使用。
---
# [公司] PPT 模板
模板:`assets/template.pptx`([宽]\" x [高]\",[N] 个布局)
## 创建演示文稿
```python
from pptx import Presentation
prs = Presentation("path/to/skill/assets/template.pptx")
# 先删除所有现有幻灯片
while len(prs.slides) > 0:
rId = prs.slides._sldIdLst[0].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[0]
# 从布局添加幻灯片
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_IDX])
```
## 关键布局
| 索引 | 名称 | 用途 |
|------|------|------|
| [0] | [布局名称] | [封面/标题幻灯片] |
| [N] | [布局名称] | [带要点的内容] |
| [N] | [布局名称] | [双列布局] |
## 占位符映射
**关键:为每个占位符包含精确位置(x、y 坐标)。**
### 布局 [N]:[名称]
| idx | 类型 | 位置 | 用途 |
|-----|------|------|------|
| [idx] | 标题(1)| y=[Y]" | 幻灯片标题 |
| [idx] | 正文(2)| y=[Y]" | 副标题/描述 |
| [idx] | 正文(2)| y=[Y]" | 页脚 |
| [idx] | 正文(2)| y=[Y]" | 来源/注释 |
### 内容区域边界
**记录自定义形状/表格/图表的安全内容区域:**
```
内容区域(布局 [N]):
- 左边距:[X]"(内容从这里开始)
- 顶部:[Y]"(副标题占位符下方)
- 宽度:[W]"
- 高度:[H]"(在页脚之前结束)
对于四象限布局:
- 左列:x=[X]",宽度=[W]"
- 右列:x=[X]",宽度=[W]"
- 顶行:y=[Y]",高度=[H]"
- 底行:y=[Y]",高度=[H]"
```
**为什么这很重要:** 自定义内容(文本框、表格、图表)必须保持在这些边界内,以避免与模板占位符(如标题、页脚和来源行)重叠。
## 填充内容
**不要手动添加项目符号字符** — 幻灯片母版处理格式。
```python
# 填充标题
for shape in slide.shapes:
if hasattr(shape, 'placeholder_format'):
if shape.placeholder_format.type == 1: # 标题
shape.text = "幻灯片标题"
# 带层级填充内容(级别 0 = 标题,级别 1 = 项目符号)
for shape in slide.shapes:
if hasattr(shape, 'placeholder_format'):
idx = shape.placeholder_format.idx
if idx == [CONTENT_IDX]:
tf = shape.text_frame
for para in tf.paragraphs:
para.clear()
content = [
("部分标题", 0),
("第一个项目符号", 1),
("第二个项目符号", 1),
]
tf.paragraphs[0].text = content[0][0]
tf.paragraphs[0].level = content[0][1]
for text, level in content[1:]:
p = tf.add_paragraph()
p.text = text
p.level = level
```
## 示例:封面幻灯片
```python
slide = prs.slides.add_slide(prs.slide_layouts[[COVER_IDX]])
for shape in slide.shapes:
if hasattr(shape, 'placeholder_format'):
idx = shape.placeholder_format.idx
if idx == [TITLE_IDX]:
shape.text = "公司名称"
elif idx == [SUBTITLE_IDX]:
shape.text = "演示文稿标题 | 日期"
```
## 示例:内容幻灯片
```python
slide = prs.slides.add_slide(prs.slide_layouts[[CONTENT_IDX]])
for shape in slide.shapes:
if hasattr(shape, 'placeholder_format'):
ph_type = shape.placeholder_format.type
idx = shape.placeholder_format.idx
if ph_type == 1:
shape.text = "执行摘要"
elif idx == [BODY_IDX]:
tf = shape.text_frame
for para in tf.paragraphs:
para.clear()
content = [
("关键发现", 0),
("收入同比增长 40% 达到 $5000 万", 1),
("扩展到 3 个新市场", 1),
("建议", 0),
("继续推进战略举措", 1),
]
tf.paragraphs[0].text = content[0][0]
tf.paragraphs[0].level = content[0][1]
for text, level in content[1:]:
p = tf.add_paragraph()
p.text = text
p.level = level
```生成示例演示文稿以验证技能有效。将其与技能一起保存以供参考。
paragraph.level
实现层级