构建 · 虚拟 Try-On

为你的应用构建虚拟 try-on 功能

一句话总结

在你的后端接收商品图,将其附带 mannequin ID 通过 POST 提交至 /api/v1/tryon/apparel,在后台 worker 中(绝不要在 HTTP 请求主线程中)轮询返回的 generation ID 直至 status 变为 completed,随后将 output_url 持久化保存至你自己的对象存储,并在 UI 中渲染展示。

  • Credits: 2K 分辨率 5 credits · 4K 分辨率 6 credits
  • 常规耗时: 1.5–4 min
  • 处理方式: 异步,轮询

本页所有数据均来自 Photta API 文档 · 已验证

生产级方案实践:顾客上传商品图,你的后端将 Photta try-on 任务加入队列,后台 worker 持续轮询直到完成,前端展示模特上身效果。无阻塞请求,无 API key 泄露风险,无需依赖伪 SDK。

RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
  -H "Authorization: Bearer $PHOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_type": "top",
  "product_images": [
    "https://cdn.yourstore.com/products/shirt-front.jpg"
  ],
  "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
  "product_category": "t_shirt",
  "mannequin_id": "mnk_f3a9b1",
  "pose_id": "pose_c2d4e5",
  "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
  "lock_background": true,
  "resolution": "2K",
  "aspect_ratio": "3:4",
  "body_size": "M",
  "expression": "neutral",
  "user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')

工作原理

从上传图片到生成模特上身图

6 个具体步骤。首次接入预计需要 10 到 15 分钟的开发时间。

  1. 步骤 1

    梳理数据流

    顾客设备 → 你的后端(上传)→ Photta API(提交)→ Photta API(轮询)→ 你的数据库(状态同步)→ 顾客设备(渲染)。在写第一行代码前先理清该流程——明确你自身后端与 Photta 之间的边界至关重要。

  2. 步骤 2

    生成并存储 API key

    生产环境密钥以 photta_live_ 开头。请将其存入环境变量中。切勿暴露给浏览器。单个密钥通用 Photta 的所有能力,无需为 try-on、珠宝或假人隐形分别申请单独的密钥。

  3. 步骤 3

    配置上传 endpoint

    首先将顾客上传的商品图存入对象存储。向 Photta 提供公开 URL 比传输 base64 更简洁,同时也为每次请求保留了完整的审计追踪记录。

  4. 步骤 4

    从服务端提交任务

    向 POST /api/v1/tryon/apparel 提交商品 URL、mannequin_id、resolution 和 aspect_ratio。接口将返回 202 Accepted 以及 generation ID。请将该 ID 保存至你的数据库中,以便客户端直接轮询你自己的 endpoint,而非 Photta 的接口。

  5. 步骤 5

    通过后台 worker 进行轮询

    切勿在 HTTP 请求内部进行轮询——任务生成需要 1.5 到 4 分钟,这会超出大部分 serverless 环境的超时限制。推荐使用 Trigger.dev、Inngest、BullMQ、Vercel Cron 或你自己的消息队列,每隔 3 秒重新调度一次轮询任务,直至生成完成。

  6. 步骤 6

    渲染最终结果

    当 status 变为 completed 时,将 data.output_url 保存至你的数据库,并向顾客设备推送实时事件(websocket、SSE 或长轮询)。前端 UI 随即将骨架加载屏替换为生成的图像。流程结束。

三段端到端代码示例

上传处理、任务分发、worker 端轮询器——上线该功能所需的全部组件。

// POST /app/try-on → your backend upload handler
import { put } from "@vercel/blob";

export async function uploadProduct(file: File) {
  const { url } = await put(`products/${crypto.randomUUID()}.jpg`, file, {
    access: "public",
  });
  return url;
}
const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_type": "top",
    "product_images": [
      "https://cdn.yourstore.com/products/shirt-front.jpg"
    ],
    "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
    "product_category": "t_shirt",
    "mannequin_id": "mnk_f3a9b1",
    "pose_id": "pose_c2d4e5",
    "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
    "lock_background": true,
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "body_size": "M",
    "expression": "neutral",
    "user_instruction": "Keep the collar pattern crisp and centered."
  }),
});
const { data } = await res.json(); // data.id, data.status
// Trigger.dev / Inngest / BullMQ task
const BASE = "https://api.photta.app/api/v1";

export const pollTryOnTask = task({
  id: "poll-try-on",
  run: async ({ generationId, attempt = 0 }) => {
    const res = await fetch(`${BASE}/tryon/apparel/${generationId}`, {
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` },
    });
    const { data } = await res.json();
    if (data.status === "completed") return data.output_url;
    if (data.status === "failed") throw new Error(data.error_message);
    if (attempt >= 120) throw new Error("try-on timed out");
    // Re-schedule this same task after 3 seconds.
    return ctx.retry.after(3000, { generationId, attempt: attempt + 1 });
  },
});

开发者常见问题

上线前常见问题

没有后端我可以实现这个吗?

不行。你的 Photta API key 必须保留在服务端。就此而言,即便是一个轻量的 Next.js route handler 或 Cloudflare Worker 也算作后端——该 key 只需要存放在 user-agent 无法读取的地方即可。

我该如何避免 HTTP 请求挂起?

切勿在请求处理程序内部进行 polling。同步提交任务,将 generation ID 返回给客户端,然后在后台 worker 中进行 polling。客户端应当 polling 你的 status endpoint,而不是 Photta 的——这样 rate limit 就由你来掌控,而不是转嫁给每个用户。

如果任务在执行中途失败了会怎样?

失败时 Photta 会自动退还 credits,且响应中会包含 data.error_code + data.error_message。向用户展示友好的提示信息,并提供一个能发起新任务的重试按钮。

我可以展示真实的进度吗?

Photta 不会输出中间进度——状态只有 processing、completed 或 failed。行之有效的做法是根据 1.5–4 分钟的时间窗口校准一个定时进度条,或者使用简单的骨架屏加载器。不要伪造百分比。

结果 URL 是永久有效的吗?

CDN URL 是稳定的,但你的产品不应依赖它来进行长期渲染展示。下载一次字节数据并将其存储在自有的 S3/GCS/R2 bucket 中——这样即使 Photta 的 CDN 发生变动,你的 PDP 也能正常运行。

一个下午即可上线虚拟 try-on

本页面的每个代码示例均与 Photta 官方文档一致。获取 API key,咖啡还没煮好你就能跑通一个原型。