ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: pptx
|
||||
description: 从论文、大纲或结构化文本生成 PowerPoint (.pptx) 演示文稿。Use when 用户需要把一篇论文/文章/大纲做成幻灯片、slides、演示文稿、PPT、deck。Don't use when 只需纯文本总结、生成 Word/PDF、或修改已有 pptx 的单个像素级样式。
|
||||
---
|
||||
|
||||
# pptx Skill —— 从论文生成演示文稿
|
||||
|
||||
## 核心流程(第二层)
|
||||
|
||||
把一份来源文本(论文 / 大纲)转成 8-12 页的演示文稿,按以下步骤:
|
||||
|
||||
1. **通读来源**:理解论文的标题、作者、问题背景、方法、关键结果、结论。
|
||||
2. **规划页序**:一份合格的演示文稿总页数应为 8-12 页,至少覆盖——
|
||||
- 标题页(论文标题 + 作者/来源作为副标题)
|
||||
- 目录 / 大纲页
|
||||
- 研究背景 / 问题动机
|
||||
- 方法概述(**必须拆成 2 页**,例如「总体思路」与「关键机制」)
|
||||
- 关键结果 / 实验发现(**必须拆成 2 页**,例如「效率指标」与「效果对比」)
|
||||
- 局限性 / 讨论
|
||||
- 小结 / 结论页(要点式总结全篇)
|
||||
3. **提炼要点**:每页 3-5 条 bullet,每条一句话,避免整段照搬原文。
|
||||
4. **生成文件**:调用本 Skill 捆绑的脚本 `scripts/generate_pptx.py`
|
||||
(通过 `run_skill_script` 工具),传入下面约定的 JSON payload。
|
||||
|
||||
## 捆绑脚本调用约定
|
||||
|
||||
工具:`run_skill_script(name="pptx", script="generate_pptx.py", payload=<JSON字符串>)`
|
||||
|
||||
payload 的 JSON schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "演示文稿主标题(通常等于论文标题)",
|
||||
"subtitle": "副标题,通常是作者或来源,可留空",
|
||||
"slides": [
|
||||
{"title": "页标题", "bullets": ["要点1", "要点2", "要点3"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
- `slides` **至少 8 项**(加上自动生成的标题页,总页数落在 8-12 页区间)。
|
||||
- 第一项通常是「目录 / 大纲」,最后一项应为「小结 / 结论」。
|
||||
- 每页 `bullets` 建议 3-5 条。
|
||||
|
||||
## 更详细的样式与实现细则(第三层)
|
||||
|
||||
如需了解版式、配色、python-pptx 的实现细节,或排查生成问题,
|
||||
再用 `read_skill_file` 读取本 Skill 内的:
|
||||
- `reference.md` —— 版式、配色与 python-pptx 技术细节
|
||||
- `scripts/generate_pptx.py` —— 生成器源码本身
|
||||
@@ -0,0 +1,43 @@
|
||||
# pptx Skill —— 技术细则(第三层 / 渐进式披露最深一层)
|
||||
|
||||
本文件对应本书「渐进式披露」的第三层:只有当 Agent 需要控制版式、配色,
|
||||
或排查生成问题时才会读取,平时不占用上下文。
|
||||
|
||||
## 版式约定
|
||||
|
||||
生成器使用 python-pptx 的空白版式(`slide_layouts[6]`),并手动摆放文本框,
|
||||
从而完全掌控排版,不依赖模板占位符:
|
||||
|
||||
- 画布尺寸:10 x 7.5 英寸(4:3)。
|
||||
- **标题页**:深蓝底(RGB 1F4E79),白色居中大标题(40pt)+ 浅蓝副标题(20pt)。
|
||||
- **内容页**:白底,顶部深蓝色条内放页标题(26pt 白字),下方为要点列表(18pt)。
|
||||
|
||||
## 配色
|
||||
|
||||
| 名称 | RGB | 用途 |
|
||||
|--------|----------|----------------|
|
||||
| ACCENT | #1F4E79 | 标题页底 / 色条 |
|
||||
| DARK | #222222 | 正文文字 |
|
||||
| LIGHT | #F2F5FA | 备用浅背景 |
|
||||
|
||||
## python-pptx 关键点
|
||||
|
||||
- `Presentation()` 新建演示文稿;`prs.slides.add_slide(layout)` 增页。
|
||||
- 文本必须放进 `text_frame`,逐段 `add_paragraph()`、逐段 `add_run()` 设置字体。
|
||||
- 纯色页背景:`slide.background.fill.solid()` 后设 `fore_color.rgb`。
|
||||
- 形状类型 `1` 对应矩形(MSO_SHAPE.RECTANGLE),用于顶部色条。
|
||||
- 保存:`prs.save(path)`,扩展名必须是 `.pptx`。
|
||||
|
||||
## 校验建议
|
||||
|
||||
生成后重新打开文件即可验证有效性:
|
||||
|
||||
```python
|
||||
from pptx import Presentation
|
||||
prs = Presentation("output/deck.pptx")
|
||||
print(len(list(prs.slides))) # 页数
|
||||
for s in prs.slides: # 每页第一个文本
|
||||
for shp in s.shapes:
|
||||
if shp.has_text_frame and shp.text_frame.text.strip():
|
||||
print(shp.text_frame.text.strip().splitlines()[0]); break
|
||||
```
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
pptx Skill 捆绑的可执行脚本:使用 python-pptx 从结构化大纲生成真实的 .pptx 文件。
|
||||
|
||||
这是 Agent Skills「渐进式披露」中第三层(细则 / 捆绑工具)的一部分:
|
||||
Agent 在读取 SKILL.md 后,得知需要通过 run_skill_script 工具调用本脚本,
|
||||
并按约定的 JSON schema 传入幻灯片大纲。本脚本负责把大纲落地为 PowerPoint。
|
||||
|
||||
payload JSON schema(由 SKILL.md 向 Agent 说明):
|
||||
{
|
||||
"title": "演示文稿主标题(字符串)",
|
||||
"subtitle": "副标题,通常是作者/来源(字符串,可选)",
|
||||
"slides": [
|
||||
{"title": "页标题", "bullets": ["要点1", "要点2", ...]},
|
||||
...
|
||||
]
|
||||
}
|
||||
|
||||
既可作为库被 import(build_presentation),也可作为 CLI 直接运行:
|
||||
python generate_pptx.py outline.json output/deck.pptx
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from pptx import Presentation
|
||||
from pptx.util import Pt, Inches
|
||||
from pptx.dml.color import RGBColor
|
||||
from pptx.enum.text import PP_ALIGN
|
||||
|
||||
|
||||
# 一套简单的品牌配色,作为设计起点(对应 SKILL.md 提到的「模板 / 设计起点」)
|
||||
ACCENT = RGBColor(0x1F, 0x4E, 0x79) # 深蓝
|
||||
DARK = RGBColor(0x22, 0x22, 0x22) # 近黑正文
|
||||
LIGHT = RGBColor(0xF2, 0xF5, 0xFA) # 浅色背景条
|
||||
|
||||
|
||||
def _set_slide_bg(slide, rgb):
|
||||
"""给整页填充一个纯色背景。"""
|
||||
fill = slide.background.fill
|
||||
fill.solid()
|
||||
fill.fore_color.rgb = rgb
|
||||
|
||||
|
||||
def _add_title_slide(prs, title, subtitle):
|
||||
slide = prs.slides.add_slide(prs.slide_layouts[6]) # 6 = 纯空白版式
|
||||
_set_slide_bg(slide, ACCENT)
|
||||
|
||||
# 主标题
|
||||
box = slide.shapes.add_textbox(Inches(0.8), Inches(2.2), Inches(8.4), Inches(2.0))
|
||||
tf = box.text_frame
|
||||
tf.word_wrap = True
|
||||
p = tf.paragraphs[0]
|
||||
p.alignment = PP_ALIGN.CENTER
|
||||
run = p.add_run()
|
||||
run.text = title
|
||||
run.font.size = Pt(40)
|
||||
run.font.bold = True
|
||||
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
|
||||
|
||||
# 副标题
|
||||
if subtitle:
|
||||
sbox = slide.shapes.add_textbox(Inches(0.8), Inches(4.3), Inches(8.4), Inches(1.0))
|
||||
stf = sbox.text_frame
|
||||
stf.word_wrap = True
|
||||
sp = stf.paragraphs[0]
|
||||
sp.alignment = PP_ALIGN.CENTER
|
||||
srun = sp.add_run()
|
||||
srun.text = subtitle
|
||||
srun.font.size = Pt(20)
|
||||
srun.font.color.rgb = RGBColor(0xD5, 0xDE, 0xEB)
|
||||
|
||||
|
||||
def _add_content_slide(prs, title, bullets):
|
||||
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
||||
_set_slide_bg(slide, RGBColor(0xFF, 0xFF, 0xFF))
|
||||
|
||||
# 顶部标题色条
|
||||
bar = slide.shapes.add_shape(
|
||||
1, # MSO_SHAPE.RECTANGLE
|
||||
Inches(0), Inches(0), Inches(10), Inches(1.1),
|
||||
)
|
||||
bar.fill.solid()
|
||||
bar.fill.fore_color.rgb = ACCENT
|
||||
bar.line.fill.background()
|
||||
|
||||
tf = bar.text_frame
|
||||
tf.word_wrap = True
|
||||
tf.margin_left = Inches(0.5)
|
||||
p = tf.paragraphs[0]
|
||||
p.alignment = PP_ALIGN.LEFT
|
||||
run = p.add_run()
|
||||
run.text = title
|
||||
run.font.size = Pt(26)
|
||||
run.font.bold = True
|
||||
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
|
||||
|
||||
# 正文要点
|
||||
body = slide.shapes.add_textbox(Inches(0.7), Inches(1.5), Inches(8.6), Inches(5.2))
|
||||
btf = body.text_frame
|
||||
btf.word_wrap = True
|
||||
for i, bullet in enumerate(bullets):
|
||||
para = btf.paragraphs[0] if i == 0 else btf.add_paragraph()
|
||||
para.space_after = Pt(10)
|
||||
r = para.add_run()
|
||||
r.text = "• " + str(bullet)
|
||||
r.font.size = Pt(18)
|
||||
r.font.color.rgb = DARK
|
||||
|
||||
|
||||
def build_presentation(payload: dict, out_path: str) -> dict:
|
||||
"""从大纲 payload 构建 pptx,返回 {path, num_slides, titles} 供校验。"""
|
||||
title = payload.get("title", "Untitled Presentation")
|
||||
subtitle = payload.get("subtitle", "")
|
||||
slides = payload.get("slides", [])
|
||||
if not slides:
|
||||
raise ValueError("payload.slides 为空,至少需要一页内容")
|
||||
|
||||
prs = Presentation()
|
||||
prs.slide_width = Inches(10)
|
||||
prs.slide_height = Inches(7.5)
|
||||
|
||||
titles = []
|
||||
|
||||
# 标题页
|
||||
_add_title_slide(prs, title, subtitle)
|
||||
titles.append(title)
|
||||
|
||||
# 内容页
|
||||
for s in slides:
|
||||
s_title = s.get("title", "")
|
||||
bullets = s.get("bullets")
|
||||
if bullets is None:
|
||||
bullets = []
|
||||
_add_content_slide(prs, s_title, bullets)
|
||||
titles.append(s_title)
|
||||
|
||||
out = Path(out_path)
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
prs.save(str(out))
|
||||
|
||||
return {"path": str(out), "num_slides": len(list(prs.slides)), "titles": titles}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 3:
|
||||
print("用法: python generate_pptx.py <outline.json> <output.pptx>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
payload = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||||
result = build_presentation(payload, sys.argv[2])
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
Reference in New Issue
Block a user