Codia
返回文章列表

用 Codia Open API 把 NotebookLM-style PDF 转成可编辑 PPTX

Engineering2026-05-29

NotebookLM-style 幻灯导出的价值在于:每一页已经是一张完整的视觉幻灯片。问题也在这里:PDF 页面通常是扁平页面,不是 PowerPoint 的对象模型。Codia Open API 的 pdf_to_ppt task 面向的正是这个场景:输入是 NotebookLM-style PDF,也就是每页都是整页图片、扫描幻灯或截图型页面;输出是一份可编辑的 .pptx

这篇文章会从外部开发者角度,走完整个生产级接入流程:

  1. /v1/open/uploads 上传本地或私有 NotebookLM-style PDF。
  2. 创建任务前先预估 credits。
  3. 通过统一 Task API 创建 pdf_to_ppt 任务。
  4. 用 webhook 接收最终结果,而不是在浏览器里高频轮询。
  5. 查询历史任务、取消任务,并下载生成的 PPTX。

示例使用 Node.js,因为大多数 Web 应用都会通过服务端路由处理文件上传。同样的 HTTP API 也适用于 Go、Python、Ruby、Java 或任何能发送 multipart 和 JSON 请求的后端。

查看完整 endpoint schema、请求/响应字段和实时 OpenAPI 规范时,可以配合打开 Codia API Reference

什么是 NotebookLM-style PDF

当前 PDF to PPT 流水线最适合 image-only PDF:每个 PDF 页面都应该是一张整页图片。这包括 NotebookLM-style 导出的资料页、截图型幻灯片、扫描报告,以及其他静态演示视觉。

它不适合复杂文本流 PDF,也不适合需要把段落、矢量图、表格和内嵌对象当作文档版式来解析的文件。如果你的源文件是普通文本 PDF,建议先把每页渲染成高分辨率 PNG 或 JPEG,再把这些图片重新打包成 image-only PDF。这样转换器拿到的就是干净的一页一张幻灯输入。

适合的输入:

  • NotebookLM-style PDF 导出
  • 扫描或截图型幻灯片
  • 一页 PDF 对应一张幻灯的 image-only PDF
  • 需要变成可编辑 PPTX 的静态演示页面

风险较高的输入:

  • 带连续段落的长文档 PDF
  • 矢量对象很多、层级复杂的报告
  • 有些页是文档、有些页是幻灯的混合 PDF
  • 小字不可读的低分辨率扫描件

架构

Codia API key 应该只放在服务端。浏览器把 PDF 上传到你的后端,你的后端再把 PDF 上传一次到 Codia,后续所有调用都使用返回的不透明 upload_id

text
Browser -> your server: multipart PDF upload -> Codia /v1/open/uploads: multipart PDF upload <- upload_id -> Codia /v1/open/estimate: JSON with upload_id -> Codia /v1/open/tasks: JSON with upload_id and callback_url <- task_id Codia -> your webhook: terminal task event Browser -> your server: read task/result -> download ppt_url when succeeded

/v1/open/uploads 不返回公网文件 URL,只返回和同一 user、同一 API key 绑定的 upload_id,并带短期有效期。这样不会把上传接口变成免费的公网文件托管。

第 1 步:上传 PDF,拿到 upload_id

本地或私有 PDF 先用 multipart/form-data 发到 /v1/open/uploads

bash
curl 'https://api.codia.ai/v1/open/uploads' \ -H 'Authorization: Bearer {codia_api_key}' \ -F 'file=@./notebooklm-briefing.pdf'

响应示例:

json
{ "code": 0, "message": "ok", "data": { "upload_id": "upl_550e8400-e29b-41d4-a716-446655440000", "filename": "notebooklm-briefing.pdf", "size": 1234567, "content_type": "application/pdf", "expires_at": 1764086400 } }

如果文件由 Codia 上传管理,任务里传 upload_id。只有当 PDF 托管在你自己的存储里,并且 Codia 可以访问时,才传 pdf_url

第 2 步:创建任务前预估 credits

pdf_to_ppt 按页计费,每转换一页 13 credits。如果你传了 page_no,预估值就是所选页数。如果不传 page_no,服务会根据 PDF 解析页数。

bash
curl 'https://api.codia.ai/v1/open/estimate' \ -H 'Authorization: Bearer {codia_api_key}' \ -H 'Content-Type: application/json' \ --data '{ "operation": "pdf_to_ppt", "input": { "upload_id": "upl_550e8400-e29b-41d4-a716-446655440000", "page_no": [0, 1, 2] } }'

响应示例:

json
{ "code": 0, "message": "ok", "data": { "operation": "pdf_to_ppt", "page_count": 3, "unit": "13 credits per page", "credits": 39, "available_credits": 120 } }

页码是 0-based。0 表示 PDF 第一页。

第 3 步:创建 pdf_to_ppt 任务

使用统一 Task API 创建任务。如果你的服务端可能因为超时重试,请带上 Idempotency-Key

bash
curl 'https://api.codia.ai/v1/open/tasks' \ -H 'Authorization: Bearer {codia_api_key}' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: notebooklm-briefing-2026-05-29' \ --data '{ "operation": "pdf_to_ppt", "input": { "upload_id": "upl_550e8400-e29b-41d4-a716-446655440000", "page_no": [0, 1, 2], "title": "NotebookLM source briefing" }, "callback_url": "https://your-app.example.com/webhooks/codia-task" }'

响应示例:

json
{ "code": 0, "message": "ok", "data": { "task_id": "550e8400-e29b-41d4-a716-446655440000", "operation": "pdf_to_ppt", "status": "pending", "created_at": 1780028799 } }

pending 表示任务已入队,processing 表示 worker 已经开始处理。终态是 succeededfailedcanceled

第 4 步:接收 webhook

生产环境建议用 webhook,而不是让浏览器高频轮询。任务进入终态后,Codia 会 POST 到 callback_url

ts
import crypto from 'node:crypto'; import express from 'express'; const app = express(); app.post( '/webhooks/codia-task', express.raw({ type: 'application/json' }), (req, res) => { const signature = String(req.header('X-Codia-Signature') || ''); const expected = 'sha256=' + crypto .createHmac('sha256', process.env.CODIA_WEBHOOK_SECRET!) .update(req.body) .digest('hex'); const ok = signature.length === expected.length && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); if (!ok) { res.sendStatus(401); return; } const event = JSON.parse(req.body.toString('utf8')); if (event.operation === 'pdf_to_ppt' && event.status === 'succeeded') { console.log('PPTX ready:', event.result?.ppt_url || event.ppt_url); } if (event.status === 'failed') { console.error('Conversion failed:', event.error_code, event.error); } res.sendStatus(200); }, );

建议把 webhook event 按 task_id 写入你自己的数据库。前端只读你的业务 API,不需要接触 Codia API key。

第 5 步:查询状态或历史任务

主流程由 webhook 推动,但状态接口仍然适合后台管理、异常恢复和历史列表。

bash
curl 'https://api.codia.ai/v1/open/tasks/550e8400-e29b-41d4-a716-446655440000' \ -H 'Authorization: Bearer {codia_api_key}'

查询正在运行的 PDF to PPT 任务:

bash
curl 'https://api.codia.ai/v1/open/tasks?operation=pdf_to_ppt&status=pending,processing&limit=20' \ -H 'Authorization: Bearer {codia_api_key}'

用 cursor 分页查询历史任务:

bash
curl 'https://api.codia.ai/v1/open/tasks?operation=pdf_to_ppt&limit=20&after=1780028799' \ -H 'Authorization: Bearer {codia_api_key}'

任务归属按创建它的 API key 隔离。查询、列表、取消和 webhook 对账都应该使用同一把 key。

第 6 步:取消任务和部分退款

仍处于 pendingprocessing 的任务可以取消:

bash
curl -X POST 'https://api.codia.ai/v1/open/tasks/550e8400-e29b-41d4-a716-446655440000/cancel' \ -H 'Authorization: Bearer {codia_api_key}'

pdf_to_ppt 来说,取消只退还尚未完成转换的页。如果一个 15 页 NotebookLM-style PDF 任务已经完成 10 页转换,取消后退 65 credits,已完成的 10 页按 130 credits 计费。

json
{ "code": 0, "message": "ok", "data": { "task_id": "550e8400-e29b-41d4-a716-446655440000", "operation": "pdf_to_ppt", "status": "canceled", "credits_reserved": 195, "credits_charged": 130, "credits_refunded": 65 } }

如果任务还在 pending,则全额退还。已经 succeeded 的任务不能取消。

第 7 步:下载可编辑 PPTX

任务成功后读取 result.ppt_url,及时下载文件。

json
{ "code": 0, "message": "ok", "data": { "task_id": "550e8400-e29b-41d4-a716-446655440000", "operation": "pdf_to_ppt", "status": "succeeded", "progress": 100, "result": { "ppt_url": "https://static.codia.ai/pptx/notebooklm-source-briefing.pptx", "page_count": 3, "pages": [ { "index": 0, "source_page": 0, "editable": true, "status": "editable", "preview_url": "https://static.codia.ai/previews/page-0.png" } ] } } }

PPTX 是最终交付物。你可以把它保存到自己的系统、挂到用户项目里,或交给 PowerPoint、Keynote、Google Slides 工作流继续处理。

完整 Node.js 路由

下面这个最小 Express 路由接收浏览器上传,并创建 Codia 任务。Codia API key 保持在服务端,不会发送到浏览器。

ts
import express from 'express'; import multer from 'multer'; import FormData from 'form-data'; import crypto from 'node:crypto'; const app = express(); const upload = multer({ storage: multer.memoryStorage() }); const CODIA_API_BASE = 'https://api.codia.ai'; app.post('/api/notebooklm-pdf-to-pptx', upload.single('file'), async (req, res) => { if (!req.file) { res.status(400).json({ error: 'file is required' }); return; } const form = new FormData(); form.append('file', req.file.buffer, { filename: req.file.originalname || 'notebooklm.pdf', contentType: req.file.mimetype || 'application/pdf', }); const uploadRsp = await fetch(`${CODIA_API_BASE}/v1/open/uploads`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.CODIA_API_KEY}`, ...form.getHeaders(), }, body: form as any, }).then((r) => r.json()); if (uploadRsp.code !== 0) { res.status(502).json(uploadRsp); return; } const uploadId = uploadRsp.data.upload_id; const idempotencyKey = crypto.randomUUID(); const taskRsp = await fetch(`${CODIA_API_BASE}/v1/open/tasks`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.CODIA_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey, }, body: JSON.stringify({ operation: 'pdf_to_ppt', input: { upload_id: uploadId, title: req.body.title || req.file.originalname?.replace(/\.pdf$/i, ''), }, callback_url: `${process.env.PUBLIC_APP_URL}/webhooks/codia-task`, }), }).then((r) => r.json()); if (taskRsp.code !== 0) { res.status(502).json(taskRsp); return; } res.status(202).json({ task_id: taskRsp.data.task_id, status: taskRsp.data.status, upload_id: uploadId, }); });

真实生产代码还需要增加请求大小限制、MIME 校验、用户归属校验、数据库持久化和结构化重试。

上线检查清单

  • 转发前先校验上传文件是 PDF。
  • CODIA_API_KEY 和 webhook secret 只放服务端。
  • UI 需要价格预览时,先调用 /v1/open/estimate
  • 任务创建发生重试时使用 Idempotency-Key
  • 主流程用 callback_url 接收终态更新。
  • 在自己的数据库里保存 task_id、状态、ppt_url 和计费字段。
  • 历史任务页使用 GET /v1/open/tasks 的 cursor pagination。
  • 在产品文案里明确说明:NotebookLM-style image-only PDF 效果最好。

常见问题

可以传 URL,不上传文件吗?

可以。如果 PDF 托管在你自己的存储里,创建任务时传 input.pdf_url。本地或私有 PDF 通过 Codia 上传时,传 input.upload_id

/v1/open/uploads 会返回公网文件 URL 吗?

不会。它返回不透明 upload_id,不是公网文件 URL。任务服务会在服务端解析 upload,并按 user 和 API key 校验归属。

输出真的可编辑吗?

目标是输出带重建文本、版式和视觉元素的可编辑 PPTX。部分密集或低质量页面可能是 image-only 或部分可编辑。任务结果会返回 per-page status,方便你的 UI 展示哪些页可编辑。

credits 怎么计费?

pdf_to_ppt 每转换一页消耗 13 credits。失败任务退还 reserved credits。取消中的 PDF to PPT 任务只退还还没有转换完成的页。

还需要轮询吗?

生产主流程建议用 webhook。GET /v1/open/tasks/{task_id} 更适合异常恢复、后台管理和手动刷新。

#notebooklm#notebooklm-style-pdf#pdf-to-ppt#可编辑pptx#codia-open-api#webhook