项目文件夹

文件
2026-07-13 21:35:32 +08:00

7.1 KiB

name, description, license
name description license
ppt-editing-skill 使用 XML 安全的工作流程编辑现有的 PowerPoint 文件或模板。适用于基于模板的演示文稿更新:分析布局、将内容映射到幻灯片、安全地复制/重新排序/删除幻灯片、并行编辑幻灯片 XML、清理孤立资源,并重新打包经过验证的 PPTX 输出。 专有许可。完整条款见 LICENSE.txt

编辑演示文稿

基于模板的工作流程

使用现有演示文稿作为模板时:

  1. 复制并分析

    cp /path/to/user-provided.pptx template.pptx
    python -m markitdown template.pptx > template.md
    

    查看 template.md 以了解占位文本和幻灯片结构。

  2. 规划幻灯片映射:为每个内容段落选择合适的模板幻灯片。

    ⚠️ 使用多样化的布局——单调的演示文稿是常见的失败模式。不要默认使用基本的标题加项目符号幻灯片。主动寻找:

    • 多列布局(2 列、3 列)
    • 图片与文字组合
    • 满版图片加文字叠加
    • 引用或标注幻灯片
    • 章节分隔页
    • 统计数据/数字标注
    • 图标网格或图标加文字行

    避免: 每张幻灯片重复使用相同的纯文本密集型布局。

    将内容类型与布局风格相匹配(例如,关键点→项目符号幻灯片,团队信息→多列布局,客户评价→引用幻灯片)。

  3. 解包

  4. 构建演示文稿(亲自完成,不要使用子代理):

    • 删除不需要的幻灯片(从 <p:sldIdLst> 中移除)
    • 复制要重复使用的幻灯片(add_slide.py
    • <p:sldIdLst> 中重新排序幻灯片
    • 在第 5 步之前完成所有结构变更
  5. 编辑内容:更新每个 slide{N}.xml 中的文本。 如果可用,在此处使用子代理——幻灯片是独立的 XML 文件,因此子代理可以并行编辑。

  6. 清理

  7. 打包

输出结构

将用户提供的文件复制到当前工作目录的 template.pptx。这样可以保留原始文件,并为所有下游脚本提供可预测的名称。

cp /path/to/user-provided.pptx template.pptx
./
├── template.pptx               # 用户提供的文件副本(绝不修改)
├── template.md                 # markitdown 提取结果
├── unpacked/                   # 可编辑的 XML 树
└── edited.pptx                 # 最终重新打包的演示文稿

最低预期交付物:edited.pptx


脚本

脚本 用途
unpack.py 提取并美化打印 PPTX
add_slide.py 复制幻灯片或从布局创建
clean.py 移除孤立文件
pack.py 重新打包并验证

移除不在 <p:sldIdLst> 中的幻灯片、未引用的媒体文件以及孤立的关联关系。

始终先写入 /tmp/,然后再复制到最终路径。Python 的 zipfile 模块内部使用 seek,这在某些卷挂载(例如 Docker 绑定挂载)上会失败。先写入本地临时路径可以避免此问题。

验证、修复、压缩 XML,并重新编码智能引号。


幻灯片操作

幻灯片顺序在 ppt/presentation.xml<p:sldIdLst> 中定义。

重新排序:重新排列 <p:sldId> 元素。

删除:移除 <p:sldId>,然后运行 clean.py

添加:使用 add_slide.py。切勿手动复制幻灯片文件——该脚本会处理手动复制时遗漏的备注引用、Content_Types.xml 和关联关系 ID。


编辑内容

子代理: 如果可用,在此处使用它们(在完成第 4 步之后)。每张幻灯片是一个独立的 XML 文件,因此子代理可以并行编辑。在给子代理的提示中,请包含:

  • 要编辑的幻灯片文件路径
  • "对所有更改使用 Edit 工具"
  • 下面的格式化规则和常见陷阱

对于每张幻灯片:

  1. 读取幻灯片的 XML
  2. 识别所有占位内容——文本、图片、图表、图标、说明文字
  3. 将每个占位符替换为最终内容

使用 Edit 工具,而不是 sed 或 Python 脚本。 Edit 工具要求精确指定要替换的内容及其位置,从而提供更高的可靠性。

格式化规则

  • 将所有标题、副标题和内联标签加粗:在 <a:rPr> 上使用 b="1"。这包括:
    • 幻灯片标题
    • 幻灯片内的段落标题
    • 行首的内联标签(例如:"状态:"、"描述:"
  • 绝不使用 Unicode 项目符号(•):使用正确的列表格式化,搭配 <a:buChar><a:buAutoNum>
  • 项目符号一致性:让项目符号继承自布局。仅在需要时指定 <a:buChar><a:buNone>

常见陷阱

模板适配

当源内容比模板项目少时:

  • 完全移除多余元素(图片、形状、文本框),而不仅仅是清空文本
  • 清除文本内容后检查是否有残留的视觉元素
  • 使用 markitdown 进行内容质量检查,以发现数量不匹配的问题

当用不同长度的内容替换文本时:

  • 替换为较短内容:通常安全
  • 替换为较长内容:可能导致溢出或意外的换行
  • 在文本更改后使用 markitdown 进行验证
  • 考虑截断或拆分内容以适应模板的设计限制

模板槽位 ≠ 源项目:如果模板有 4 个团队成员但源只有 3 个用户,请删除第 4 个成员的整个组合(图片加文本框),而不仅仅是清空文本。

多项内容

如果源包含多个项目(编号列表、多个段落),请为每个项目创建独立的 <a:p> 元素——绝不将它们合并为一个字符串

错误做法——所有项目在一个段落中:

<a:p>
  <a:r><a:rPr .../><a:t>步骤 1:做第一件事。步骤 2:做第二件事。</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>步骤 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>做第一件事。</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>步骤 2</a:t></a:r>
</a:p>
<!-- 继续此模式 -->

从原段落复制 <a:pPr> 以保留行间距。在标题上使用 b="1"

智能引号

由 unpack/pack 自动处理。但 Edit 工具会将智能引号转换为 ASCII 码。

添加包含引号的新文本时,请使用 XML 实体:

<a:t>the &#x201C;Agreement&#x201D;</a:t>
字符 名称 Unicode XML 实体
" 左双引号 U+201C &#x201C;
" 右双引号 U+201D &#x201D;
' 左单引号 U+2018 &#x2018;
' 右单引号 U+2019 &#x2019;

其他

  • 空白字符:在包含前导或尾随空格的 <a:t> 上使用 xml:space="preserve"
  • XML 解析:使用 defusedxml.minidom,而非 xml.etree.ElementTree(后者会破坏命名空间)