这次的目标是:根据一张参考图,生成一页可编辑的 PPTX,文字可改、图形可替换,版式尽量贴近原图。
我的思路
不直接让 GPT "画一张图",而是让它走一条更可控的链路:
参考图 → 版式识别 → 字体/图片环境检查 → python-pptx 生成 → 校验 → 输出可编辑 .pptx
这样生成的不是截图,而是真正的 PPTX 文件,打开后可以继续改文字、换配色、调整图形。
关键步骤
1. 先看工作区里有什么文件
bash
pwd && rg --files -g '*.png' -g '*.jpg' -g '*.pptx' -g 'AGENTS.md' .
这一步主要是确认参考图、已有 PPTX、配置文件是否都在工作区里。
2. 查 PPT 生成 API 文档
bash
cat "$CODEX_PRIMARY_RUNTIME_NODE_MODULES/@oai/artifact-tool/docs/presentations/api/API_DOCS.md"
cat "$CODEX_PRIMARY_RUNTIME_NODE_MODULES/@oai/artifact-tool/docs/presentations/api/references/rich-text.spec.md"
这里会看生成 PPT 时支持哪些元素,比如标题、正文、形状、图片、备注等。
3. 检查中文字体
bash
fc-list :lang=zh family | sort -u
中文 PPT 很容易踩字体坑,所以要先确认环境里有没有可用的中文字体。
4. 查找 CJK / 黑体类字体
bash
rg --files "$CODEX_PRIMARY_RUNTIME_ROOT" -g '*.ttf' -g '*.otf' -g '*.ttc' \
| rg 'CJK|[Ss]ans[Ss][Cc]|[Ss]ans[Hh]ans|[Aa]rial|[Mm]icrosoft|[Ww]qy'
如果要用中文排版,优先找 Noto Sans SC、思源黑体、微软雅黑、WenQuanYi 这类字体。
5. 查看运行时字体加载逻辑
bash
ls "$CODEX_PRIMARY_RUNTIME_ROOT/dependencies"
rg --files "$CODEX_PRIMARY_RUNTIME_ROOT" | rg -i 'font|cjk' | tail -35
sed -n '1,160p' /root/.codex/skills/builtins/presentations/container_tools/runtime_helpers.mjs
这一步是为了确认 PPT 生成流程里,字体是怎么注册、怎么加载的。
6. 检查字体相关代码
bash
rg -n 'font|Font' /root/.codex/skills/builtins/presentations/container_tools/artifact_tool_utils.mjs | head -45
ls /usr/share/fonts
rg --files /usr/share/fonts | head -15
rg --files "$CODEX_PRIMARY_RUNTIME_NODE_MODULES" | rg -i 'CJK|NotoSansSC|\.ttc' | head -15
如果环境里没有合适的中文字体,生成的中文可能会显示异常,所以这里要重点确认。
7. 查看构建校验结果
bash
cat build/validation.json
用来确认之前的生成或校验有没有报错。
8. 分析 artifact 工具内部逻辑
python
from pathlib import Path
import os, re
p = Path(os.environ['CODEX_PRIMARY_RUNTIME_NODE_MODULES']) / '@oai/artifact-tool/dist/artifact_tool.mjs'
s = p.read_text()
for term in ['FONT', 'fontPaths', 'loadFonts', 'registerFont', 'fontDirectory', 'FONTCONFIG', 'GlobalFonts']:
matches = list(re.finditer(term, s))
print(term, len(matches))
for m in matches[:3]:
print(s[max(0, m.start() - 130):m.end() + 220])
这段脚本用来快速定位 PPT 生成工具里和字体相关的函数。
9. 查看核心生成函数
python
from pathlib import Path
import os
s = (Path(os.environ['CODEX_PRIMARY_RUNTIME_NODE_MODULES']) / '@oai/artifact-tool/dist/artifact_tool.mjs').read_text()
i = s.find('function hqt()')
print(s[i - 1400:i + 6500])
找到核心函数后,可以判断它是否支持文本框、形状、图片、备注等元素。
10. 执行生成
bash
"$CODEX_PRIMARY_RUNTIME_NODE" build/create.mjs > build/run.log 2>&1
tail -c 1300 build/run.log
这里真正触发 PPTX 生成,并把日志输出到 build/run.log。
11. 校验字体文件
python
from fontTools.ttLib import TTFont
f = TTFont('fonts/DroidSansFallback.ttf')
print(f['OS/2'].__dict__)
print(f['hhea'].__dict__)
如果生成结果里中文显示异常,可以用 fontTools 检查字体是否完整、是否包含中文字形。
12. 查看最终日志
bash
tail -n 3 build/run.log | cut -c 1-200
确认最后几步有没有报错。
13. 应用补丁并输出文件
json
{
"path": "/connector_openai_library/implicit_link::connector_openai_library/create_library_file",
"args": {
"file": "/workspace/scratch/0b5208d9034e/output/入职感悟与成长体会_可编辑.pptx",
"library_artifact_type": "slides"
}
}
这一步把生成的 PPTX 注册为可下载或可引用的产物。
14. 写入扩展属性
bash
python3 /workspace/scratch/0b5208d9034e/build/library_file_transfer.py apply-xattrs \
'/workspace/scratch/0b5208d9034e/output/入职感悟与成长体会_可编辑.pptx' \
'libfile_9d7bf7ba58e48191907930c0f4174794' <<'JSON'
[{"name":"user.library-file-version","value":"0"}]
JSON
给输出文件加上版本标记,方便后续追踪。
最终输出
生成后的文件路径是:
/workspace/scratch/0b5208d9034e/output/入职感悟与成长体会_可编辑.pptx
它是一个真正的 PPTX,不是图片。打开后可以继续编辑文字、调整图形、替换配色。
踩坑提醒
- 中文优先确认字体:没有中文字体时,中文可能变成方框或默认字体。
- 不要只靠截图还原:截图只能参考版式,真正可编辑要靠 PPTX 元素生成。
- 生成后要校验:至少打开确认文字、图片、版式是否正常。
- 复杂版式建议分步:先做标题区,再做内容区,最后加图形和图片。
命令和脚本都按语言加了语法高亮。
1. 查看工作区文件
bash
pwd && rg --files -g '*.png' -g '*.jpg' -g '*.pptx' -g 'AGENTS.md' .
2. 查看 PPT 生成 API 文档
bash
cat "$CODEX_PRIMARY_RUNTIME_NODE_MODULES/@oai/artifact-tool/docs/presentations/api/API_DOCS.md"
cat "$CODEX_PRIMARY_RUNTIME_NODE_MODULES/@oai/artifact-tool/docs/presentations/api/references/rich-text.spec.md"
3. 检查中文字体
bash
fc-list :lang=zh family | sort -u
4. 查找 CJK / 黑体类字体
bash
rg --files "$CODEX_PRIMARY_RUNTIME_ROOT" -g '*.ttf' -g '*.otf' -g '*.ttc' \
| rg 'CJK|[Ss]ans[Ss][Cc]|[Ss]ans[Hh]ans|[Aa]rial|[Mm]icrosoft|[Ww]qy'
5. 查看运行时字体加载逻辑
bash
ls "$CODEX_PRIMARY_RUNTIME_ROOT/dependencies"
rg --files "$CODEX_PRIMARY_RUNTIME_ROOT" | rg -i 'font|cjk' | tail -35
sed -n '1,160p' /root/.codex/skills/builtins/presentations/container_tools/runtime_helpers.mjs
6. 检查字体相关代码
bash
rg -n 'font|Font' /root/.codex/skills/builtins/presentations/container_tools/artifact_tool_utils.mjs | head -45
ls /usr/share/fonts
rg --files /usr/share/fonts | head -15
rg --files "$CODEX_PRIMARY_RUNTIME_NODE_MODULES" | rg -i 'CJK|NotoSansSC|\.ttc' | head -15
7. 查看构建校验结果
bash
cat build/validation.json
8. 分析 artifact 工具内部逻辑
python
from pathlib import Path
import os, re
p = Path(os.environ['CODEX_PRIMARY_RUNTIME_NODE_MODULES']) / '@oai/artifact-tool/dist/artifact_tool.mjs'
s = p.read_text()
for term in ['FONT', 'fontPaths', 'loadFonts', 'registerFont', 'fontDirectory', 'FONTCONFIG', 'GlobalFonts']:
matches = list(re.finditer(term, s))
print(term, len(matches))
for m in matches[:3]:
print(s[max(0, m.start() - 130):m.end() + 220])
9. 查看核心生成函数
python
from pathlib import Path
import os
s = (Path(os.environ['CODEX_PRIMARY_RUNTIME_NODE_MODULES']) / '@oai/artifact-tool/dist/artifact_tool.mjs').read_text()
i = s.find('function hqt()')
print(s[i - 1400:i + 6500])
10. 执行生成
bash
"$CODEX_PRIMARY_RUNTIME_NODE" build/create.mjs > build/run.log 2>&1
tail -c 1300 build/run.log
11. 校验字体文件
python
from fontTools.ttLib import TTFont
f = TTFont('fonts/DroidSansFallback.ttf')
print(f['OS/2'].__dict__)
print(f['hhea'].__dict__)
12. 查看最终日志
bash
tail -n 3 build/run.log | cut -c 1-200
13. 应用补丁并输出文件
json
{
"path": "/connector_openai_library/implicit_link::connector_openai_library/create_library_file",
"args": {
"file": "/workspace/scratch/0b5208d9034e/output/入职感悟与成长体会_可编辑.pptx",
"library_artifact_type": "slides"
}
}
14. 写入扩展属性
bash
python3 /workspace/scratch/0b5208d9034e/build/library_file_transfer.py apply-xattrs \
'/workspace/scratch/0b5208d9034e/output/入职感悟与成长体会_可编辑.pptx' \
'libfile_9d7bf7ba58e48191907930c0f4174794' <<'JSON'
[{"name":"user.library-file-version","value":"0"}]
JSON