Eigent PPTX 技能编辑指南:基于 XML 解包工作流精准修改 PowerPoint 模板
【免费下载链接】eigentEigent: The Open Source Cowork Desktop - Local and Free Alternative to Claude Cowork and Codex项目地址: https://gitcode.com/GitHub_Trending/ei/eigent
在 Eigent 桌面应用中,PPTX 技能(Skill)负责处理一切与.pptx文件相关的任务:读取、解析、编辑、套用模板。当 Agent 需要基于一个已有演示文稿生成新文件时,editing.md 定义的"解包—改 XML—清理—打包"工作流就是其核心方法论。本文完整继承该文档的模板化编辑流程、五个配套脚本、幻灯片操作规则、内容编辑格式规范与常见陷阱,并结合resources/example-skills/pptx/scripts/下的真实源码,讲清每一步命令背后实际做了什么,帮助你理解 Agent 是如何在不破坏 OOXML 结构的前提下可靠地修改演示文稿的。
一、工作流总览:为什么走"解包-改 XML-打包"路线
PPTX 文件本质是一个 ZIP 压缩包,内部是遵循 OOXML 标准的一组 XML 文件(幻灯片、母版、布局、主题、媒体、关系文件等)。直接操作二进制 zip 或用黑盒 API 很难精确控制模板布局,而 Eigent 的 PPTX 技能选择了一条透明路线:把 pptx 解压成可读的 XML 目录,用精确编辑工具逐文件修改,再用带校验的打包器重新封装。
SKILL.md 中的快速参考表给出了整个技能的任务路由:
| 任务 | 指南 |
|---|---|
| 读取/分析内容 | python -m markitdown presentation.pptx |
| 编辑或从模板创建 | 阅读 editing.md |
| 从零创建 | 阅读 pptxgenjs.md |
也就是说,editing.md 专门服务于"已有模板,我要基于它改"这一场景,与从零创建的 pptxgenjs 路线互补。
模板化工作流(Template-Based Workflow)
文档给出的七步流程如下,每一步都可直接复制执行:
1. 分析现有幻灯片
python scripts/thumbnail.py template.pptx python -m markitdown template.pptx查看生成的thumbnails.jpg了解各页版式,查看 markitdown 输出了解占位文本。
2. 规划幻灯片映射(Plan slide mapping):为每个内容板块选择一个模板页。
文档特别强调使用多样化版式——单调的演示文稿是常见失败模式,不要默认只用"标题+要点"式版式。应主动寻找:
- 多栏版式(两栏、三栏)
- 图文组合
- 全出血图片 + 文字叠加
- 引言/强调页(Quote / callout)
- 章节分隔页(Section dividers)
- 数据/数字强调页(Stat callouts)
- 图标网格或图标+文字行
避免:每一页都重复同一种文字密集的版式。应让内容类型匹配版式风格(如:要点→bullet 页,团队信息→多栏,用户评价→引言页)。
3. 解包
python scripts/office/unpack.py template.pptx unpacked/4. 构建演示文稿(结构调整):
- 删除不需要的幻灯片(从
<p:sldIdLst>中移除) - 复制要复用的幻灯片(
add_slide.py) - 在
<p:sldIdLst>中重排顺序 - 务必在第 5 步之前完成所有结构性变更
5. 编辑内容:更新每个slide{N}.xml中的文本——每页幻灯片是独立的 XML 文件。
6. 清理
python scripts/clean.py unpacked/7. 打包
python scripts/office/pack.py unpacked/ output.pptx --original template.pptx二、五个配套脚本:文档说明 + 源码印证
文档附带的脚本总表如下:
| 脚本 | 用途 |
|---|---|
unpack.py | 解压并格式化 PPTX |
add_slide.py | 复制幻灯片或从布局新建 |
clean.py | 移除孤立文件 |
pack.py | 带校验的重新打包 |
thumbnail.py | 生成幻灯片视觉缩略图网格 |
下面逐个结合源码深入说明。
unpack.py:解压、美化、转义
python scripts/office/unpack.py input.pptx unpacked/文档说明:解压 PPTX、格式化 XML、转义智能引号。源码 unpack.py 印证了这一点,并补充了几个文档未展开的细节:
- 它同时服务
.docx、.pptx、.xlsx三种后缀(L61); - 对所有
*.xml和*.rels文件调用toprettyxml(缩进两空格)进行美化,解析失败时静默跳过(L96-L102),这解释了为什么解包后 XML 是缩进整齐的; - 智能引号转义由
SMART_QUOTE_REPLACEMENTS表实现:U+201C/201D/2018/2019 四种字符分别替换为“等 XML 实体(L40-L45)。这正是后文"智能引号"陷阱的源头——解包阶段主动把 Unicode 引号变成实体,保证后续文本编辑不引入编码问题; --merge-runs与--simplify-redlines两个开关仅对 DOCX 生效,PPTX 编辑流程不受影响(L76-L83)。
add_slide.py:唯一被允许的"新增幻灯片"方式
python scripts/add_slide.py unpacked/ slide2.xml # 复制幻灯片 python scripts/add_slide.py unpacked/ slideLayout2.xml # 从布局新建两种来源(见 add_slide.py 的模块 docstring):
- 传入
slide{N}.xml:复制该幻灯片,自动生成slide{下一个序号}.xml; - 传入
slideLayout{N}.xml:基于版式创建一个空幻灯片骨架(内置最小<p:sld>模板,L62-L84)。
脚本执行后会打印一段<p:sldId>片段,由你手动插入presentation.xml的<p:sldIdLst>期望位置(L101、L141)。
从源码可以看到,手动复制幻灯片文件会漏掉的三件事,脚本都会自动处理:
- Content_Types 登记:向
[Content_Types].xml追加新幻灯片的 Override 条目(_add_to_content_types); - 关系 ID:在
ppt/_rels/presentation.xml.rels中分配下一个rId并添加 slide 类型的 Relationship(_add_to_presentation_rels); - notes 引用剥离:复制幻灯片时会用正则把源
.rels中的 notesSlide 关系删除,避免两页共享同一份演讲者备注(L126-L132)。
此外,新幻灯片的id取自现有<p:sldId>最大值 +1,无幻灯片时从 256 起(_get_next_slide_id)——这也是文档强调"绝不要手动复制幻灯片文件"的原因:以上任何一步漏掉都会导致 PowerPoint 打开时报损坏。
clean.py:引用图驱动的垃圾回收
python scripts/clean.py unpacked/文档说明:移除不在<p:sldIdLst>中的幻灯片、未被引用的媒体、孤立的 rels。源码 clean.py 的 docstring 给出了完整清理清单,比文档表格更细:
- 不在 sldIdLst 中的孤立幻灯片及其
.rels(remove_orphaned_slides,并同步从presentation.xml.rels移除对应关系); [trash]目录(L105-L117);- charts/diagrams/drawings 下的孤儿
.rels(L142-L164); media、embeddings、charts、diagrams、tags、drawings、ink七个资源目录中未被任何.rels引用的文件,以及未引用的 theme、notesSlide(remove_orphaned_files);- 最后同步删除
[Content_Types].xml中对应 Override(update_content_types)。
值得注意的实现细节:主循环 clean_unused_files 用while True反复执行"删孤儿 rels → 重新扫描引用图 → 删孤儿文件",直到一轮删不动为止——因为删除一个资源后可能连带使其 rels 文件也成为孤儿,需要级联回收。这也意味着文档中"删幻灯片后运行 clean.py"一步,实际是保证包内不残留任何不可达对象的安全网。
pack.py:先自动修复、再校验、后压缩
python scripts/office/pack.py unpacked/ output.pptx --original input.pptx文档说明:校验、修复、压缩 XML、重新编码智能引号。源码 pack.py 的实际流程是:
- 当传入
--original时,先运行校验器。PPTX 走PPTXSchemaValidator,会依次做:XML 良构性、命名空间、ID 唯一性、UUID 形态、文件引用存在性、slideMaster 中sldLayoutId引用合法性、Content-Types 一致性、XSD schema 校验、备注页引用唯一性、slideLayout 引用不重复等十余项检查(validate()); - 校验前先执行
repair()自动修复,并打印Auto-repaired N issue(s)(pack.py#L110-L117); - 复制一份到临时目录,对所有
*.xml/*.rels执行_condense_xml:删除标签间纯空白文本节点和注释,把 unpack 阶段美化产生的缩进"压缩"回紧凑形态——且明确跳过*:t文本元素,保住正文中的空格; - 以
ZIP_DEFLATED压缩打包输出。--validate false可跳过第 1 步(L155-L161)。
从源码结构看,校验失败(Validation failed)会直接中止打包,这使pack.py成为整个工作流的质量闸门:能走通 pack 的目录,大概率能被 PowerPoint 正常打开。
thumbnail.py:只用于模板分析,不用于最终 QA
python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]生成thumbnails.jpg,每格标注对应幻灯片文件名。文档强调它只用于模板分析(选择版式);最终视觉 QA 应走 SKILL.md 中的soffice+pdftoppm高清单页渲染路线。源码 thumbnail.py 给出了文档未展开的默认值与上限:
- 缩略图宽 300px、渲染 DPI 100、JPEG 质量 95(L43-L47);
--cols默认 3,最大 6,超出会降级并告警(L74-L76);- 每张网格最多
cols × (cols+1)页(默认 3 列即每格 12 页,与文档"max 12 per grid"一致,create_grids),超出自动拆分为prefix-1.jpg、prefix-2.jpg; - 隐藏幻灯片(
show="0")不渲染,用斜线占位图并标注(hidden)(create_hidden_placeholder)——在模板分析时这是个实用信号:带斜线的格子不可用作版式来源。
三、幻灯片操作(Slide Operations)
文档的核心断言:幻灯片顺序由ppt/presentation.xml中的<p:sldIdLst>决定。三个操作的具体规则:
- 重排(Reorder):直接调整
<p:sldId>元素顺序即可,无需动任何幻灯片文件; - 删除(Delete):移除
<p:sldId>条目,然后运行clean.py回收幻灯片文件、rels、媒体与 Content-Types 条目(对应 clean.py 的 remove_orphaned_slides); - 新增(Add):必须使用
add_slide.py。绝不要手动复制幻灯片文件——脚本会处理 notes 引用、Content_Types.xml 与关系 ID 这些手动复制必然遗漏的环节(前文 add_slide.py 一节已逐一印证)。
四、编辑内容(Editing Content)
工具选择:用 Edit 工具而非 sed 或 Python
文档明确:编辑 XML 内容应使用精确的 Edit 工具,而不是 sed 或 Python 脚本。理由是 Edit 工具强制你指明"替换什么、在哪里替换",可靠性更高。这一规则对 Agent 执行尤其重要:批量正则替换很容易误伤<a:t>文本中出现的形似标签的内容。
格式规则(Formatting Rules)
- 标题、小标题、行内标签全部加粗:在
<a:rPr>上加b="1"。范围包括:- 幻灯片标题
- 页内章节小标题
- 行首的行内标签(如 "Status:"、"Description:")
- 绝不使用 Unicode 项目符号(•):应使用
<a:buChar>或<a:buAutoNum>实现真正的列表格式。配套的 pptxgenjs.md 中也有同样警告——直接写 "• First item" 会产生双重项目符号; - 项目符号继承优先:让 bullet 从版式(layout)继承。确需显式声明时只允许
<a:buChar>或<a:buNone>,不要自造其他属性。
智能引号(Smart Quotes)
解包/打包阶段自动处理智能引号,但Edit 类工具会把智能引号转换成 ASCII。因此新增带引号的文本时,必须写 XML 实体:
<a:t>the “Agreement”</a:t>| 字符 | 名称 | Unicode | XML 实体 |
|---|---|---|---|
“ | 左双引号 | U+201C | “ |
” | 右双引号 | U+201D | ” |
‘ | 左单引号 | U+2018 | ‘ |
’ | 右单引号 | U+2019 | ’ |
该表与 unpack.py 的 SMART_QUOTE_REPLACEMENTS 一一对应,保证解包侧的实体化与打包侧的反解码闭环。
其他注意点
- 空白:首尾含空格的
<a:t>必须加xml:space="preserve",否则空白会被 XML 解析器吞掉; - XML 解析库:需要程序化处理时用
defusedxml.minidom,不要用xml.etree.ElementTree——后者会破坏命名空间。这一选择在整个脚本库中得到了贯彻:unpack.py、clean.py、thumbnail.py 全部 import 的是defusedxml.minidom。
五、常见陷阱(Common Pitfalls)
5.1 模板适配(Template Adaptation)
源内容条目少于模板时:
- 多余元素要整体删除(图片、形状、文本框),而不是只清空文字;
- 清空文本后检查是否残留孤立视觉元素;
- 运行视觉 QA 核对数量是否匹配。
文档给出一条关键等式:模板槽位 ≠ 源数据条目。例如模板画了 4 位团队成员而源数据只有 3 人,应删除第 4 位成员的整个组合(图片 + 文本框),而不是留一个空框。
替换为不同长度文本时:
- 更短的替换通常安全;
- 更长的替换可能溢出或意外换行;
- 文本改动后必须做视觉 QA;
- 必要时截断或拆分内容以适应模板的设计约束。
5.2 多条目内容:每个条目独立段落
当源内容包含多个条目(编号列表、多个小节)时,每个条目必须创建独立的<a:p>段落,绝不拼成一个字符串。
错误示范——所有条目挤在一个段落里:
<a:p> <a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r> </a:p>正确示范——独立段落 + 加粗小标题:
<a:p> <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr> <a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r> </a:p> <a:p> <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr> <a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r> </a:p> <a:p> <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr> <a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r> </a:p> <!-- continue pattern -->要点:从原段落复制<a:pPr>以保留行距(如上例中3919百分之一的spcPts行距设置),标题行使用b="1"加粗。若把多条目压进一个<a:t>,PowerPoint 会把它渲染成一行连续文字,版式完全失控。
六、端到端执行清单与 QA 衔接
把以上规则串起来,一次完整的模板化编辑按序执行:
# 1. 分析模板 python scripts/thumbnail.py template.pptx # → thumbnails.jpg(选版式) python -m markitdown template.pptx # → 占位文本清单 # 3. 解包 python scripts/office/unpack.py template.pptx unpacked/ # 4. 结构调整(在编辑文本之前完成!) python scripts/add_slide.py unpacked/ slide2.xml # 输出待插入的 <p:sldId> # 编辑 unpacked/ppt/presentation.xml 的 <p:sldIdLst>:增/删/排序 # 5. 编辑内容:精确编辑 unpacked/ppt/slides/slide{N}.xml # - 标题/小标题/行内标签加粗(b="1") # - 多条目用多个 <a:p>,引号用 “ 等实体 # - 模板槽位多于源数据时整组删除 # 6. 清理 python scripts/clean.py unpacked/ # 7. 打包(自动校验 + 修复) python scripts/office/pack.py unpacked/ output.pptx --original template.pptx打包成功后,QA 阶段衔接 SKILL.md 的验证循环:先跑内容 QA(python -m markitdown output.pptx,并用grep -iE "xxxx|lorem|ipsum|this.*(page|slide).*layout"揪出残留占位符),再做视觉 QA(python scripts/office/soffice.py --headless --convert-to pdf output.pptx后pdftoppm -jpeg -r 150逐页检查)。SKILL.md 要求"假设一定有问题",至少完成一轮"修复—复检"循环才可宣告成功——这一点对长文本替换可能溢出的场景尤其重要。
七、依赖与环境前提
执行上述命令需要以下依赖(来自 SKILL.md 的 Dependencies 一节):
pip install "markitdown[pptx]"— 文本抽取;pip install Pillow— 缩略图网格(thumbnail.py 依赖);- LibreOffice(
soffice)— PDF 转换,脚本通过 soffice.py 为沙箱环境自动配置; - Poppler(
pdftoppm)— PDF 转图片。
需要注意的适用前提:thumbnail.py 在scripts/目录下运行from office.soffice import ...(thumbnail.py#L40),意味着命令需要以resources/example-skills/pptx/scripts/为工作目录执行,使office包可导入;pack 的自动修复与校验依赖lxml与 XSD schema(位于 scripts/office/schemas/ISO-IEC29500-4_2016/,含pml.xsd、dml-main.xsd等 PresentationML/DrawingML 模式文件)。
八、小结
editing.md 的价值在于把"改 PPT"这件黑盒操作拆解成一条可审计的流水线:thumbnail 分析 → unpack 解包 → 先结构后内容 → clean 级联回收 → pack 校验打包。源码印证了几个关键设计决策:add_slide.py自动维护 Content_Types、rels 与 slide id 三处登记并剥离共享备注引用;clean.py以引用图做级联垃圾回收;pack.py用 XSD 校验器加自动修复作为最后一道闸门;智能引号在 unpack 阶段实体化、pack 阶段还原,形成闭环。掌握了这套规则,无论是人工操作还是为 Agent 编写提示词,都能在不破坏 OOXML 结构的前提下可靠地基于任意模板产出结构合法、版式多样的演示文稿。
【免费下载链接】eigentEigent: The Open Source Cowork Desktop - Local and Free Alternative to Claude Cowork and Codex项目地址: https://gitcode.com/GitHub_Trending/ei/eigent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考