
一张图表截图是手工任务,五百张遗留架构图就是迁移项目。批量转换不能只写一个文件循环,还需要异步任务、持久化任务 ID、受控并发、下载验证,以及防止同一图片被重复计费的记录。
本文以 LayerBack 转换 API为例。它接收 PNG、JPEG、WebP,一次转换生成 VSDX、PPTX、draw.io、SVG、结构化 IR 和预览图。
API 生命周期
流程分三步:
- 把原始图像字节发给
POST /api/v1/convert,取得job_id; - 轮询
GET /api/v1/jobs/{job_id},或者提供完成 Webhook; - 从
/download?format=...下载需要的文件。
任务状态依次为 queued → running → succeeded,失败则进入 failed。转换通常需要 30~60 秒,不适合长时间占用普通同步请求。
在 Settings → API Keys 创建密钥,并存入环境变量:
bash
export LAYERBACK_API_KEY="replace-with-your-key"
不要把密钥提交到 Git、写进前端 JavaScript、留在截图里,或直接硬编码在脚本中。
提交一张图片
bash
curl -X POST https://layerback.com/api/v1/convert \
-H "x-api-key: $LAYERBACK_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @diagram.png
响应中包含 job_id。拿到后立即保存源文件路径、SHA-256、任务 ID 与提交时间。如果提交已经成功,但进程在记录 ID 前崩溃,自动重跑可能导致同一图片再次转换和计费。
查询状态并安全下载
bash
curl https://layerback.com/api/v1/jobs/$JOB_ID \
-H "x-api-key: $LAYERBACK_API_KEY"
成功后,下载时要允许跟随重定向:
bash
curl -L \
"https://layerback.com/api/v1/jobs/$JOB_ID/download?format=vsdx" \
-H "x-api-key: $LAYERBACK_API_KEY" \
-o diagram.vsdx
接口可能跳转到短时有效的对象存储地址,所以 -L 不能省。下载完成后,确认文件非空并能作为 ZIP/OOXML 包打开,再把该行标记为完成。
一个便于恢复的 Python 批处理
下面的模式优先保证可恢复性,而不是追求最大吞吐:顺序提交、写入 JSON Lines 清单、固定间隔轮询并下载 VSDX。
python
import hashlib, json, os, time
from pathlib import Path
import requests
BASE = "https://layerback.com/api/v1"
HEADERS = {"x-api-key": os.environ["LAYERBACK_API_KEY"]}
src_dir, out_dir = Path("legacy-diagrams"), Path("converted-vsdx")
out_dir.mkdir(exist_ok=True)
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def log(event):
with open("conversion-manifest.jsonl", "a", encoding="utf-8") as f:
f.write(json.dumps(event, ensure_ascii=False) + "\n")
for source in sorted(src_dir.iterdir()):
if source.suffix.lower() not in {".png", ".jpg", ".jpeg", ".webp"}:
continue
response = requests.post(
f"{BASE}/convert",
headers={**HEADERS, "Content-Type": "application/octet-stream"},
data=source.read_bytes(), timeout=90)
response.raise_for_status()
job_id = response.json()["job_id"]
log({"source": str(source), "sha256": digest(source),
"job_id": job_id, "state": "submitted"})
while True:
status = requests.get(f"{BASE}/jobs/{job_id}",
headers=HEADERS, timeout=30).json()
if status["status"] in {"succeeded", "failed"}:
break
time.sleep(5)
if status["status"] == "failed":
log({"job_id": job_id, "state": "failed",
"error": status.get("error")})
continue
artifact = requests.get(
f"{BASE}/jobs/{job_id}/download?format=vsdx",
headers=HEADERS, timeout=90, allow_redirects=True)
artifact.raise_for_status()
target = out_dir / f"{source.stem}.vsdx"
target.write_bytes(artifact.content)
log({"job_id": job_id, "state": "downloaded",
"target": str(target), "bytes": target.stat().st_size})
用于生产时,应在启动时读取清单,跳过已经处于 submitted、succeeded 或 downloaded 的哈希。先证明恢复流程可靠,再增加有上限的工作池。
大队列使用 Webhook
bash
curl -X POST \
"https://layerback.com/api/v1/convert?callback_url=https://example.com/hooks/layerback" \
-H "x-api-key: $LAYERBACK_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @diagram.png
回调包含任务 ID、状态、耗时、错误和格式列表。当前 API 文档说明会尝试投递两次。应把 Webhook 当成通知,对于重要结果,再调用任务状态接口确认后下载。
接收端必须以 job_id 为键实现幂等。同一通知重复到达或晚到,都不能触发一次新的转换。
生产检查清单
- 只允许 20 MB 以下的 PNG、JPEG 和 WebP;
- 当前默认上限为每账号每小时 20 次转换;
- 分别处理 402、413、415、429:余额、大小、格式和速率限制;
- 轮询前持久化源文件哈希与任务 ID;
- 限制并发,不要一次启动整个文件库;
- 网络读取可以重试,但结果未知的转换不能盲目重新提交;
- 文件至少保留 72 小时,应尽快下载;
- 删除源图前,验证 VSDX 和 PPTX 包;
- 在迁移清单中记录失败与人工复核备注。
一次转换消耗 10 积分并包含所有格式,因此不要为了不同格式重复提交同一图片。先用 10 张有代表性的图测试并统计清理时间,再沿用同一套清单与验证规则扩大规模。