ModelFold PPT 1.1
ModelFold 自研模型。发一个主题(可以附上笔记、事实或一篇文章),返回一整套可编辑的演示文稿:
- 先生成大纲,再分批写每一页,整套内容前后连贯;
- 6–50 页,10 种版式:封面、目录、章节页、要点、左右两栏、图文、数据大字、引言、时间线、结束页;
- 6 套主题(
midnight/corporate/paper/forest/sunset/mono),每页统一配色、字体、页码、页脚和 Logo 位; - 可选 AI 配图(只给需要图片的版式生成);
- 输出 PPTX(文字框、形状是 PowerPoint 原生可编辑对象)、PDF、PNG(ZIP)、Studio 文档 JSON;
- 每套都会存进调用者账户的 Studio,返回的
studio_url可直接打开继续编辑。
概览
| 字段 | 值 |
|---|---|
| 模型 ID | modelfold-ppt-1.1 |
| 类型 | 办公 / 演示文稿(document) |
| 调用方式 | 异步任务:POST /api/v1/jobs/createTask + GET /api/v1/jobs/recordInfo |
| 鉴权 | Authorization: Bearer <API Key> |
| 耗时 | 通常 30–90 秒;开启 AI 配图时更久 |
| 文件保留 | 30 天(与其他生成文件相同) |
计费
每套价格 = 基础价 + 每页价格 × 页数 + 每张 AI 配图价格 × 实际生成张数。
| 项目 | 默认价格(积分) |
|---|---|
| 基础价(每套) | 3 |
| 每页 | 0.5 |
| 每张 AI 配图 | 6(= 站内生图模型售价 + 1,随加价倍数变化) |
提交时按最多可能的配图张数(min(12, ceil(页数 × 0.4)))预扣,完成后按实际生成张数结算、多退少补;任务失败全额退款。示例:8 页不配图 7 积分;10 页配 4 张图 32 积分。最新价格以模型页为准。
参数(放在 input 里)
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
prompt | string | 是 | — | 主题或一句话需求,2–1000 字。也可写作 topic。 |
content | string | 否 | — | 资料:笔记、事实或一篇文章,最多 20000 字,PPT 会按它来写。也可写作 notes。 |
slides | integer | 否 | 10 | 页数,6–50。 |
language | string | 否 | en | 文字语言:zh en ja es ko fr de pt。 |
theme | string | 否 | midnight | midnight corporate paper forest sunset mono。 |
template | string | 否 | — | 本人模版 ID 或公开设计 ID,优先于内置主题。 |
ai_images | boolean | 否 | true | 是否生成 AI 配图(按实际生成张数计费)。 |
output_formats | string[] | 否 | ["pptx"] | 可选 pptx、pdf、png(每页一张 PNG 的 ZIP)、json(Studio 文档)。 |
顶层可选 callBackUrl + callbackSecret(任务结束回调),请求头可选 Idempotency-Key(防重复提交),用法与其他异步模型相同,见异步任务接口。
请求示例
curl -X POST https://ai.modelfold.online/api/v1/jobs/createTask \
-H "Authorization: Bearer $MODELFOLD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "modelfold-ppt-1.1",
"input": {
"prompt": "AI 视频产品季度业务汇报",
"content": "Q3 营收增长 38%,付费用户 1.2 万,NPS 64;下季度重点:出海和企业版",
"slides": 10,
"language": "zh",
"theme": "corporate",
"template": "TEMPLATE_ID",
"ai_images": true,
"output_formats": ["pptx", "pdf"]
}
}'
# 返回 {"code":200,"msg":"success","data":{"taskId":"…","state":"queued","credits":27}}
curl "https://ai.modelfold.online/api/v1/jobs/recordInfo?taskId=TASK_ID" \
-H "Authorization: Bearer $MODELFOLD_API_KEY"import os, time, json, requests
API = "https://ai.modelfold.online/api/v1/jobs"
H = {"Authorization": f"Bearer {os.environ['MODELFOLD_API_KEY']}"}
task = requests.post(f"{API}/createTask", headers=H, json={
"model": "modelfold-ppt-1.1",
"input": {"prompt": "新员工销售培训", "slides": 8, "language": "zh", "theme": "paper", "template": "TEMPLATE_ID", "ai_images": False},
}).json()["data"]
while True:
job = requests.get(f"{API}/recordInfo", headers=H, params={"taskId": task["taskId"]}).json()["data"]
if job["state"] in ("success", "fail"):
break
time.sleep(5)
result = json.loads(job["resultJson"])["resultObject"]
open("deck.pptx", "wb").write(requests.get(result["files"]["pptx"]).content)const API = 'https://ai.modelfold.online/api/v1/jobs'
const headers = { Authorization: `Bearer ${process.env.MODELFOLD_API_KEY}`, 'Content-Type': 'application/json' }
const { data: task } = await fetch(`${API}/createTask`, { method: 'POST', headers,
body: JSON.stringify({ model: 'modelfold-ppt-1.1', input: { prompt: '咖啡店开业计划', slides: 8, template: 'TEMPLATE_ID', language: 'zh' } }) }).then((r) => r.json())
let job
do {
await new Promise((r) => setTimeout(r, 5000))
job = (await fetch(`${API}/recordInfo?taskId=${task.taskId}`, { headers }).then((r) => r.json())).data
} while (!['success', 'fail'].includes(job.state))
console.log(JSON.parse(job.resultJson).resultObject.files.pptx)返回结果
state 为 success 时,resultJson 是 JSON 字符串:resultUrls 是所有生成文件的地址,resultObject 是结构化结果:
{
"title": "AI 视频产品季度汇报",
"slides": 10,
"theme": "corporate",
"language": "zh",
"template": "123",
"files": { "pptx": "https://…/modelfold-ppt-….pptx", "pdf": "https://…/modelfold-ppt-….pdf" },
"cover_url": "https://…/modelfold-ppt-…-cover.jpg",
"studio_url": "https://ai.modelfold.online/studio/edit/123",
"design_id": 123,
"ai_images": { "requested": true, "generated": 3 },
"outline": [{ "index": 1, "type": "cover", "title": "…", "points": ["…"] }],
"billing": { "credits": 26, "base": 3, "per_slide": 0.5, "per_image": 6 }
}| 字段 | 说明 |
|---|---|
files.pptx / files.pdf / files.png_zip / files.json | 按 output_formats 生成的文件 |
studio_url | 在 ModelFold Studio 打开继续编辑(仅 API Key 的主人可打开) |
outline | 每页类型、标题和要点 |
ai_images | 请求 / 实际生成的配图张数 |
billing | 最终积分和价格明细(与 usage.credits 一致) |
失败时 state 为 fail,failMsg 说明原因,预扣积分全额退回。
相关
可选上传模版
使用同一 API Key 向 POST /v1/studio/templates/upload 发送 JSON { "name": "brand.pptx", "data": "PPTX文件的BASE64" },文件最大 12 MB,返回 template_id。在 input 中加入 "template": "123",可使用本人上传/保存的 Studio 模版,或公开设计 ID。私有模版校验归属,原始文件不公开提供下载。导入基础主题色、字体、背景、Logo 和文本版式;复杂图表、组合、动画和不支持的媒体简化或略过,缺失字体降级为系统字体,请核对结果。
长篇大纲按最多 10 页分段;正文每批 4 页、最多 3 批并发。50 页生成及导出请预留数分钟。AI 配图最多 12 张,PDF 逐页渲染以控制内存。
模版 ID 与配图风格(Template IDs and image style)
上传不调用模型。上传后用同一 API Key 创建 PPT 任务,input.template 填返回的 template_id(字符串);该参数优先于 theme。私有模版只有本人可用。
- GET /v1/studio/templates:鉴权,列出本人模版。
- GET /v1/studio/templates/public:无需登录,列出真实公开/官方模版 ID。返回 {"ok":true,"templates":[{"id":"123","title":"…","format":"slide","preview_url":null}]};没有已发布模版时列表为空,请查询后选 ID,勿编造官方 ID。
- POST /v1/studio/templates/upload:鉴权,JSON 的 name 为 .pptx 文件名,data 为纯 Base64(不带 data: 前缀),最大 12 MB。返回 {"ok":true,"template_id":"123","warnings":["pptx_simplified","font_fallback"],"design":{…}}。原 PPTX 不提供公开下载。
- 从 OOXML 提取配色、字体、基础文本版式及母版图片;生成内容时在现有计费对话请求中分析最多两张非 Logo 图片,识别摄影/插画/扁平/3D、光感、构图、背景纹理,将风格写进每页 imagePrompt。文字与基础布局套用同一模板转换。
- 生图优先使用支持参考图的同系列模型(Seedream 5 Flash image-to-image 或 Nano Banana 2 Lite),发送最多两张模板图片。图片素材保存在 uploads/studio;原文件保持私有。无图片或模型不支持时使用风格文字提示,不保证像素级复刻。复杂图表/组合/动画及缺失字体仍会简化。
- ai_images=false 不生成图片、不收图片费;图片按实际成功张数计费,最多 min(12, ceil(slides × 0.4)) 张。模板分析并入原有对话计费,不增加独立分析调用。结果的 template 返回所用 ID(未指定则 null)。
# Inspect public IDs, then upload a private template (Python avoids shell Base64 differences).
curl https://ai.modelfold.online/v1/studio/templates/public
python3 -c 'import base64,json; print(json.dumps({"name":"brand.pptx","data":base64.b64encode(open("brand.pptx","rb").read()).decode()}))' > template.json
curl https://ai.modelfold.online/v1/studio/templates/upload \
-H "Authorization: Bearer $MODELFOLD_API_KEY" -H "Content-Type: application/json" --data-binary @template.json
curl https://ai.modelfold.online/v1/studio/templates -H "Authorization: Bearer $MODELFOLD_API_KEY"
# Use returned template_id in input.template in the createTask examples above.import base64, os, requests
base = "https://ai.modelfold.online"
headers = {"Authorization": "Bearer " + os.environ["MODELFOLD_API_KEY"]}
public = requests.get(base + "/v1/studio/templates/public").json()["templates"]
with open("brand.pptx", "rb") as f:
uploaded = requests.post(base + "/v1/studio/templates/upload", headers=headers,
json={"name": "brand.pptx", "data": base64.b64encode(f.read()).decode()})
uploaded.raise_for_status()
template_id = uploaded.json()["template_id"]
response = requests.post(base + "/api/v1/jobs/createTask", headers=headers,
json={"model": "modelfold-ppt-1.1", "input": {"prompt": "Brand launch plan",
"slides": 6, "template": template_id, "ai_images": True, "output_formats": ["pptx", "json"]}})
response.raise_for_status()
print(response.json()) # Poll recordInfo as above; check state=success before reading resultJson.import { readFile } from 'node:fs/promises'
const base = 'https://ai.modelfold.online'
const headers = { Authorization: `Bearer ${process.env.MODELFOLD_API_KEY}`, 'Content-Type': 'application/json' }
const publicTemplates = await fetch(base + '/v1/studio/templates/public').then(r => r.json())
const upload = await fetch(base + '/v1/studio/templates/upload', { method: 'POST', headers,
body: JSON.stringify({ name: 'brand.pptx', data: (await readFile('brand.pptx')).toString('base64') }) })
if (!upload.ok) throw new Error(await upload.text())
const { template_id } = await upload.json()
const task = await fetch(base + '/api/v1/jobs/createTask', { method: 'POST', headers,
body: JSON.stringify({ model: 'modelfold-ppt-1.1', input: { prompt: 'Brand launch plan',
slides: 6, template: template_id, ai_images: true, output_formats: ['pptx', 'json'] } }) }).then(r => r.json())
console.log(task) // Poll recordInfo as above; check state=success before reading resultJson.