全开源是口号,Presenton 把 PPTX 导出核心藏进了下载包

发布于 · 2,883 字 · 约 7 分钟#Github 解读#AI 生图原文链接
全开源是口号,Presenton 把 PPTX 导出核心藏进了下载包 封面图
  • Presenton 是 Apache 2.0 开源的 AI 演示文稿生成器,主打「可编辑 PPTX 导出」差异化,但二进制转 OOXML 的核心导出包 @presenton/export-core 闭源,仅通过 GitHub Releases 分发 tarball
  • Standard 流水线拆为三阶段解耦:提纲生成禁止 LLM 写制作指令、布局选型有明确规则、逐页 JSON 输出受 schema 校验,内容与视觉分离以便定位错误
  • Smart 流水线让 LLM 直接写 1280×720 的 HTML 页面,配三层防线:sanitize 剥离危险标签、289 行几何审计解析 DOM 查违规、8 次重试预算加断点续写机制
  • 免费自托管体验有天花板:免费图像源仅限 Pexels 等库存图,AI 画图和实时搜索都需付费 API key,且 Docker 版存在缺模板、部分编辑动作失效等已知问题
  • 架构模式为「分层生成、分离导出」,各层独立校验与重试,适用于任何 AI 产出复杂格式文档的场景,长期密钥换短命 session 的认证设计也较讲究

同事甩来一份 Gamma 链接,说这个 AI 做的 deck 漂亮得不像话。我点开看了一遍,确实漂亮,然后问他导出成 PPTX 能不能编辑,他说不行,只能导出 PDF。那一刻我突然意识到,市面上叫「AI 文稿工具」的东西,绝大多数只是「AI 截图工具」,生成了网页再截成图,交到你手里的是一张没有灵魂的图片。

所以当我看到 Presenton 这个项目时,第一反应不是它有多少 Star,而是它把「生成可编辑 PPTX」这件事当真了。一万一千多个文件摊开在面前,两条生成流水线,一条闭源导出链路,我今天把它从头到尾拆一遍。

它解决的不是「生成」,是「可编辑」

先给个定位。Presenton 是一个开源 AI 演示文稿生成器和 API,Apache 2.0,2025 年 5 月建仓,到现在 10004 个 Star、1551 个 fork。TypeScript 为主,但真正的后端在 servers/fastapi,一个 Python FastAPI 服务。

它宣称自己是 Gamma、Canva、Beautiful AI 的开源替代。这话一半对一半不对,对的地方在于它的核心能力确实对标,不对的地方在于「开源替代」这个说法低估了它。Gamma 是闭源 SaaS,Presenton 是你可以 docker run 在自己服务器上的完整产品,还带桌面版、API、MCP server。

但我要说,它最大的差异化不在「自己部署」,而在那个「Fully editable PPTX export」。生成一份能编辑的 PPTX,意味着每一页幻灯片的每个文本框、每条曲线、每个图表,都得有真实坐标、真实尺寸、真实字体,而不是一张 PNG。

Standard 流水线,三阶段的解耦

打开 servers/fastapi/utils/llm_calls/ 目录,能看到这条管线的全部零件。它叫 Standard 模式,走三个独立阶段。

第一阶段叫 generate_presentation_outlines.py,让 LLM 产出整份 deck 的提纲。这里有个非常反直觉的设计,prompt 里有一大段「content only」规则,翻译成人话就是,禁止 LLM 在任何页写「这里放一个柱状图」「加一张图」这种制作指令,只能写观众看得见的文字和数字。如果用户要求图表,那就把它转化成一个 Markdown 表格,数据放在表格里,指令一个字都不留。

第二阶段是 generate_presentation_structure.py,模型拿到提纲后,从当前模板的布局库里给每页选一个布局。选型规则写在 prompt 里,比如表格是文字数据就选 table 布局,表格是数字数据就选图表布局,三列数字表格优先选支持两张图表的布局,绝不选 metrics 布局来装数字表格。

第三阶段 generate_slide_content.py,逐页生成结构化 JSON,输出严格受 schema 约束,直接跑 JSONSchema 校验,失败就重试。

为什么作者要费这么大劲把「内容」和「视觉」拆开?我猜他踩过一个经典的坑,让 LLM 一边想文案一边想排版,结果两头都做不好。内容阶段只产数据,视觉阶段只选布局,各干各的,出错了也知道该修哪一段。而且 outline 阶段的 schema 有硬约束,constants/presentation.py 里写着 MAX_NUMBER_OF_SLIDES = 50、单页 outline 最多 100 词,超了直接被 pydantic 的 validator 截断。

虽然 Standard 是默认路径,但我个人更偏爱 Smart 那条流水线,它把「让 AI 做一份能编辑的演示稿」这个目标推进得更远。

Smart 流水线,让 LLM 直接写网页

Standard 的问题在于,模板布局是有限的,12 个布局摆在那儿,再怎么组合也就那些形状。于是 Presenton 给了第二条路,Smart 模式,代码在 generate_smart_presentation.py,936 行,是全项目我觉得最值得读的文件。

思路一句话,让 LLM 直接写 HTML。每页幻灯片就是一个 1280×720 的 <section>,Tailwind 写样式,图表用真实的 Chart.js canvas。不是让 LLM 描述画面然后截图,是让 LLM 当前端工程师,交付一套能直接跑的页面。

这里就引出一个信任问题,LLM 写的 HTML 怎么能当产品代码用?Presenton 的回答是一套硬校验。

第一层在 sanitize。normalize_smart_slide_html 用正则剥掉 html/head/body/style/link/meta/base/iframe 这些标签,去掉所有事件处理器属性,去掉 javascript: URL,同时把 <script> 的 src 摘掉,只允许 Chart.js 初始化用的内联脚本,还得验证这些脚本确实在初始化 canvas 而不是干别的。

第二层是几何审计。servers/fastapi/utils/smart_slide_layout.py 里有 289 行 _LayoutParser,用 Python 自带的 HTMLParser 把 LLM 输出的 DOM 解析成树,然后做确定性检查。负 margin 且内容有意义的元素算违规,overflow-hidden 藏着文本算违规,绝对定位的元素算出边界或兄弟重叠算违规,提示词里明令禁止的 overflow-auto、line-clamp、truncate 出现就报错。

第三层是重试预算。SMART_GENERATION_MAX_ATTEMPTS = 8,一页不合格不会整份推倒重来,而是走 CONTINUATION MODE。已通过的那些页是不可变前缀,prompt 只回传最近 3 页的完整 HTML 当视觉连续性参考,外加每页的类型和标题摘要,让模型从断点接着写。拒绝原因也会带回去,_continuation_prompt 里把 retry_error 截断到 1200 字符塞进下一条消息。字号有硬下限,正文不许低于 14 px,安全区预留 48 到 64 px,视觉页 80 到 130 词,文字页最多 180 词,TOC 页 220 词封顶。

把这三层连起来看,就是一个完整的审稿闭环,出稿、过滤、审计、接收或驳回。

Smart 模式的审稿闭环流程
Smart 模式的审稿闭环流程

翻译成人话,它把 LLM 当成一个会写代码但总会耍点小聪明的实习生,sanitize 拦掉偷带危险标签的行为,几何审计拦掉偷懒藏文本的行为,驳回的信息再喂回去接着写。模型没指望一次写对,工程师设计了验收标准和预算。

说实话这套组合拳打动我的不是某一条规则,而是「把 LLM 当实习生,结果有审查员」的态度。它没指望模型一次写对,而是给了明确的验收标准和预算,写不好就退回重写。

导出,真相藏在开源外壳里

两条流水线产出的东西不一样。Standard 产 JSON,Smart 产 HTML,但它们最后都汇到同一个出口,导出成 PPTX 或 PDF。

导出链路长这样。FastAPI 收到导出请求后,构造一个 /pdf-maker 的 URL,servers/fastapi/utils/export_utils.py 里 _build_presentation_export_url 拼好参数,可能还带上 cookie,然后 ExportTaskService 起一个 Node 子进程,跑 presentation-export/runner.mjs,让 puppeteer 打开 pdf-maker 页面完成渲染。

关键在 runner.mjs 引用的 @presenton/export-core。这个包不在主仓库,主仓库的 scripts/sync-presentation-export.cjs 会从 GitHub Releases 下载编译好的 tarball,装进 presentation-export/node_modules。我顺着去看它的源码仓库,presenton/presenton-export 里只有一个 README,写着「This Contains the Releases of the Presenton Export」,没有源码。

整条链路的开源边界,用一张图就能说清。

Presenton PPTX 导出的开源边界
Presenton PPTX 导出的开源边界

从 FastAPI 到 puppeteer 打开页面,你能看清每一步,唯独页面里的元素坐标怎么变成 slide*.xml,这一步落在虚线框里够不着。

这就是我要说的重点了。README 首页第一行写「Fully open-source (Apache 2.0)」,听起来整条链路都是开源的,但把二进制转成 OOXML 的那一步,那个决定这份 PPTX 到底能编辑成什么样的一步,是闭源的。你能看清 prompt、看清校验规则、看清布局 JSON,唯独看不清元素坐标是怎么映射进 slide*.xml 的。

公平地说,这不算欺骗,Apache 2.0 管的是它分发的那部分代码,而且主仓库的工程做得确实扎实。但它确实给「fully open-source」这个口号打了个折扣。想 Fork 了改导出逻辑的人,会在这个子包面前停下。

还有个佐证。主仓库里唯一碰 PPTX 文件格式的代码是 servers/fastapi/templates/pptx_font_utils.py,它 import 了 pptx 和 fontTools,做的事只有字体子集化,把模板用到的字样嵌进 PPTX,不生成任何幻灯片。幻灯片 XML 的组装,全在闭源的 export-core 里。

给开发者用的接口

说完内部,说外部。Presenton 不只是个网页应用,它把整条流水线暴露成了 API 和 MCP。

POST /api/v1/ppt/presentation/generate 一行 curl 就能生成,请求体里 content 是主题,n_slides 控制页数,template 选模板,export_as 选 pptx 还是 pdf。返回 presentation_id、path、edit_path,拿着 ID 还能继续进编辑器里改。

MCP 走 2025-11-25 Streamable HTTP 协议,挂在 /mcp 端点。认证用的是 sk-presenton- 开头的 API key,管理员建 key 时指定归属用户和 90 天过期时间,key 在进程内换成短命 session,长期 key 从不转发给生成接口。这个设计挺讲究,key 泄露了也就泄露一个会话,炸不了整台机器。

模型侧是彻底的 BYOK。文本 LLM 支持 OpenAI、DeepSeek、Gemini、Vertex、Azure、Bedrock、OpenRouter、Fireworks、Together、Cerebras、Anthropic、LiteLLM、LM Studio、Ollama 还有自定义兼容端点,图像也有 Pexels、Pixabay、Gemini Flash、DALL-E 3、ComfyUI 一长串。utils/get_env.py 是配置中枢,上百个环境变量。Docker 镜像里还默认装了 spaCy 的 en_core_web_sm,让 Mem0 的本地记忆开箱即用,记忆存在本地 Qdrant 加 SQLite,embedding 用 BAAI/bge-small-en-v1.5,384 维。

一些我验证过的不完美

文章写到这里,得泼几盆冷水。

最想提醒的是免费天花板。图像生成那串 provider 里,真正免费的是 Pexels 和 Pixabay 这类库存图网站,但它们只给你现成的照片,命令模型画图得走 DALL-E 或 Gemini,那些要 API key 要花钱。Web 搜索也类似,想给生成接上实时信息,要么用大厂的模型原生搜索,要么自己架 SearXNG,要么买 Tavily 或 Exa 的 key。免费自托管体验的边界,比 README 的 feature 列表要窄一圈。

Docker 版还有个已知坑。issue #881 有人反馈,官方镜像缺内置模板,社区也有人报 #781 自定义模板离线生成不了,因为自定义模板功能要连 presenton.ai 的社区服务。另外 #860 说部分 AI 编辑动作没效果,比如调字号没变大。这些都不致命,但说明它还没到 1.0,现在的版本号停在 v0.9.8-beta。

还有一处架构上的取舍要说明。Electron 桌面版默认关认证、禁 MCP,原因写得很直白,避免认证冲突。所以在桌面版里想走 API 或 MCP,得趁早搭个 Docker 版。

带走一个判断

拆完这一圈,我脑子里留下一个可复用的东西。Presenton 的整个设计可以总结成一个模式,分层生成,分离导出。内容生成、布局决策、最终渲染导出,三层各是各的,prompt 也好、schema 也好、闭源核心也好,都守着自己的边界。

这个模式对任何「AI 产出复杂格式文档」的工程都适用。尤其是当你发现模型一次输出根本做不到位的时候,别急着堆 prompt 把它按在地上摩擦,先把产物拆成几层,让每一层只有一个责任,再给每一层配一个独立的校验和重试预算。生成管线的每一段都会出错,聪明的系统不会把出错概率压到零,它做的是让每段错误都局限在自己那一层。

至于你要不要用它,也一句话说得清。想自己部署一套能用自己模型生成可编辑 PPT 的服务,Presenton 是目前最完整的开源选项,值得一跑。想完全掌控导出细节,甚至改 OOXML 的映射逻辑,那先在 presenton-export 那个只有 README 的仓库前面停一下,想清楚再上车。

评论互动

© 2026 王若风的技术博客 · Powered by Astro