Seedance 2.5 is live — 30-second cinematic video with native audio & real-person references
产品摄影 API:单张照片生成商用级产品图
2026/09/03

产品摄影 API:单张照片生成商用级产品图

构建能保留商品一致性的产品摄影 API 工作流:从 1K 分辨率起步、逐张验证生成结果、按每一张合格图核算真实的单图成本。

一张普通的产品照片,如果 API 被要求改变场景而非重新发明产品,就足以生成一组受限的正面或四分之三角度店铺图。实用的工作流很简单:写下不可变的细节,生成一个低成本的 1K 候选图,按固定清单拒绝它,只在遇到明确失败时才提升质量或切换模型。

这最后一点很关键。模型调用可能成功完成,却给你一个不同盖子的瓶子、淡化的标志,或一个让物品悬空的阴影。值得追踪的数字因此不是广告价格,而是单张批准图的成本,包括你拒绝的每一个完成候选。

本指南中的费率核实于 2026 年 9 月 3 日。它们会变化,所以在用它们作为客户报价或硬性预算前,请查阅生产模型页面。

TL;DR

  • 从你拥有的产品照片开始,展示一个完整的物品,角度是你打算出售的那个。
  • 为形状、比例、材料、颜色边界、硬件和现有标签标记写一份身份合约。让场景变化;不要让这些细节变。
  • 这里最低成本的首次通过是 Nano Banana 2 Lite,在 2026 年 9 月 3 日核实时为15 积分、0.015 美元、一张完成的 1K 图[1]
  • 用一个候选图验证提示。在批准产品后再批量下单。
  • 从每个终态任务读取结算过的 usage.credits。将完成尝试的总计费积分除以一个人批准的数量。
  • 让确切的价格、用量、成分、认证标记和法律副本远离生成像素。保留或合成验证过的图稿。

产品照片看起来精致不代表已准备好上店

用户能否上传一张简单的产品照片,并得到形状不变、标签文字不损坏、光线自然且输出一致的干净电商图片?成本很重要,因为每一张被拒绝的结果都可能触发另一次生成。

这是对问题的更好定义,而不是"让这张照片更专业"。店铺级资产必须通过可观察检查:

检查通过条件拒绝当
产品数量恰好一个所求物品出现副本、盖子或松散部件
几何轮廓和比例匹配源盖子、把手、泵、边缘或包装宽度改变
材质表面光泽和纹理保持可识别哑面变光泽、透明变不透明或纹理消失
颜色产品色块保持在同一位置白平衡改变产品而非场景
标签现有标记保持位置且无新宣称出现字词变异、消失或被创造
裁剪整个物品可见且有有用的安全边距底部、盖子、把手或阴影被裁掉
接地接触阴影与表面和光线一致物品悬空或投出不可能的阴影
交付宽高比、像素尺寸和文件格式符合目的地文件需要不安全裁剪或有不可用边缘

一张漂亮的图片可能会在这个表上失败。反过来说,保留每个产品事实的克制白色扫过可能是更有价值的资产。

按需要解决的失败选择模型

没有通用的"最佳产品摄影模型"。从能表达编辑的最低成本路线开始,只有当审查告诉你为什么第一条路线不够时才移动。

阶段模型和请求级生产费率何时使用
布局通过nano-banana-2-lite,1K$0.015 / 15 积分单个源、单个简单背景和照明变化
灵活编辑gpt-image-2,1K$0.030 / 30 积分需要更多宽高比选择或有针对性的编辑工作流
生产静帧doubao-seedream-5-0-pro,基础 1K$0.032 / 32 积分材质、照明、构图或多参考控制是更难的部分
复杂或更大资产gemini-3-pro-image-preview,1K 或 2K$0.030 / 30 积分简报密集、参考众多或稍后 4K 通过合理

这些是当前 reAPI 费率,不是上游商家刊例价。Nano Banana 2 Lite 返回一张 1K 图像,接受最多十个公网图像参考。GPT Image 2 提供 1K、2K 和 4K 级。Seedream 5.0 Pro 提供基础 1K 和高级 2K 输出,最多十个参考。Nano Banana Pro 也能达到 4K;它的结算 4K 价格在同一日期为 $0.033、33 积分。[1][2][3][4]

阶段标签是工作流建议,不是商家排名。ByteDance 定位 Seedream 5.0 Pro 在结构一致性、材质和照明控制、多图像融合和生产导向编辑周围;源照片和你的验收测试仍然决定这些能力是否有帮助这个特定产品。[8]

分辨率不是错误几何的修复工具。如果 1K 草稿改变了盖子,4K 重跑可以给你一个更清晰的错盖子。首先修复身份指令或添加有用参考。只有在构图和产品通过后才增加分辨率。

对于更广泛的能力权衡,使用完整的 GPT Image 2 vs Nano Banana Pro 对比Seedream 5.0 Pro vs GPT Image 2 对比。 本指南其余部分停留在产品摄影工作上。

花费积分前准备源照片

在提交前确认你拥有源或有权转换它。不要假设市场列表、另一个目录或客户上传已清除新商业资产;检查适用许可、条款和客户同意。

源不需要工作室背景。它需要让产品清晰可见:

  • 展示一个完整物品,包括其底部和顶部;
  • 使用与你想要结果相同的宽角;
  • 让手指、胶带、炫光和道具远离重要边缘;
  • 避免隐藏材质的压黑和吹白;
  • 让盖子、把手、泵、紧固件和颜色边界易于检查;
  • 当所求结果暴露第一张照片未展示的一面时提供另一个已拥有的角度。

一张照片不是 3D 模型。它无法证明隐藏后面板上打印了什么或未见机制是如何形状的。当证据缺失时,要么捕捉另一个参考,要么把那个表面挡出视线。

API 接受媒体为公网 HTTP(S) URL。Base64 字符串和 data: URL 被拒绝,所以先上传源到你自己的 R2、S3 或等效对象存储。[1]

写一份产品身份合约

在写视觉提示前,把源变成简短检查记录。这还不是模型的散文;它是提示和审查者都将使用的规范。

{
  "product": "250 ml skincare bottle",
  "must_keep": [
    "exactly one bottle",
    "tall rounded-rectangle silhouette",
    "short matte-white pump",
    "cobalt band at the lower quarter",
    "warm-white body with a satin finish",
    "front label position and all existing marks",
    "height-to-width ratio"
  ],
  "may_change": [
    "background",
    "surface",
    "lighting direction",
    "contact shadow",
    "crop room"
  ],
  "must_not_create": [
    "new words or logos",
    "price or discount badge",
    "ingredients or certification claim",
    "extra bottle, cap, pump, or packaging"
  ]
}

"保持一致"给审查者没什么指向。"钴蓝色带保持在下四分之一"会。

构建第一个产品摄影提示

把不可协商的身份放在首位,然后说什么可能改变,然后描述拍摄。模型倾向于比长摄影形容词列表更好地遵循具体边界。

Use Image 1 as the exact product identity.

Keep exactly one product. Preserve its silhouette, dimensions, pump position,
warm-white satin material, cobalt color boundary, surface texture, and every
existing label mark. Do not redesign, relabel, remove, or add branding.

Change only the setting: place the product centered on a warm-white seamless
studio sweep. Use a large soft key light from the upper left, even front detail,
and a natural contact shadow directly below the bottle. Keep the whole product
visible with at least 10% crop room on every side.

No hands, people, props, boxes, extra products, added text, badges, dramatic
reflections, clipped edges, or floating object.

提示不要求模型改进标签。如果标签排版商业很重要,"改进"是重新绘制的邀请。保留原始模板或在生成后添加验证图稿。

提交你的第一个产品摄影 API 任务

创建媒体 API 密钥,用你的公网源图像替换示例 URL,提交一个 Nano Banana 2 Lite 任务。这是一个付费请求;它刻意只是一个候选而非批次。

curl https://reapi.ai/api/v1/images/generations \
  -H "Authorization: Bearer $REAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-2-lite",
    "prompt": "Use Image 1 as the exact product identity. Keep exactly one product. Preserve its silhouette, dimensions, pump position, material, color boundaries, surface texture, and every existing label mark. Do not redesign, relabel, remove, or add branding. Change only the setting: center it on a warm-white seamless studio sweep with a soft key light from upper left and a natural contact shadow. Keep the whole product visible with at least 10% crop room. No hands, people, props, extra products, added text, badges, clipped edges, or floating object.",
    "image_urls": ["https://assets.example.com/my-product.jpg"],
    "aspect_ratio": "1:1"
  }'

响应包含一个 idstatus: "processing"。保存 ID。然后每两三秒轮询任务端点直到它到达 completedfailed

TASK_ID="task_replace_me"

curl "https://reapi.ai/api/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer $REAPI_API_KEY"

轮询不消耗积分。完成的图像任务返回 output.image_urls 中的文件和 usage.credits 中的结算费用。[5]

当客户端在读响应前失去连接时不要盲目重复 POST。第一个请求可能已经创建了付费任务。日志响应和任务 ID 尽快到达;安全地重试 GET,但在创建另一个生成前做出深思熟虑的决定。

一个完整的 Node.js 运行器,带有有界轮询

以下脚本在 Node.js 20 或更高版本中不需要 SDK 即可工作。它支持本指南中使用的四种 1K 请求形状,仅提交一次,使用五分钟本地轮询截止,打印结算积分,并将成功文件复制到当前目录。

import { writeFile } from 'node:fs/promises';

const apiKey = process.env.REAPI_API_KEY;
const sourceUrl = process.env.SOURCE_IMAGE_URL;
const model = process.env.IMAGE_MODEL || 'nano-banana-2-lite';

if (!apiKey || !sourceUrl) {
  throw new Error('Set REAPI_API_KEY and SOURCE_IMAGE_URL first.');
}

const prompt = `Use Image 1 as the exact product identity.
Keep exactly one product. Preserve its silhouette, proportions, hardware,
material, color boundaries, surface texture, and every existing label mark.
Do not redesign, relabel, remove, or add branding.
Change only the setting: center it on a warm-white seamless studio sweep with
a soft key light from upper left and a natural contact shadow. Keep the whole
product visible with at least 10% crop room. No hands, people, props, added
text, badges, extra products, clipped edges, or floating object.`;

function requestBody(selectedModel) {
  const common = {
    model: selectedModel,
    prompt,
    image_urls: [sourceUrl],
  };

  if (selectedModel === 'nano-banana-2-lite') {
    return { ...common, aspect_ratio: '1:1' };
  }
  if (selectedModel === 'gpt-image-2') {
    return { ...common, size: '1:1', resolution: '1k' };
  }
  if (selectedModel === 'doubao-seedream-5-0-pro') {
    return { ...common, aspect_ratio: '1:1', quality: 'basic' };
  }
  if (selectedModel === 'gemini-3-pro-image-preview') {
    return { ...common, size: '1:1', resolution: '1k' };
  }
  throw new Error(`Unsupported IMAGE_MODEL: ${selectedModel}`);
}

const headers = {
  Authorization: `Bearer ${apiKey}`,
  'Content-Type': 'application/json',
};

async function readJson(response) {
  const body = await response.json();
  if (!response.ok) {
    const message = body.error?.message || JSON.stringify(body);
    throw new Error(`HTTP ${response.status}: ${message}`);
  }
  return body;
}

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function getTask(taskId) {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    let response;
    try {
      response = await fetch(`https://reapi.ai/api/v1/tasks/${taskId}`, {
        headers: { Authorization: `Bearer ${apiKey}` },
        signal: AbortSignal.timeout(15_000),
      });
    } catch (error) {
      if (attempt === 3) throw error;
      await sleep(1000 * 2 ** attempt);
      continue;
    }

    if (response.status === 429) {
      const seconds = Number(response.headers.get('retry-after'));
      await response.body?.cancel();
      await sleep(Number.isFinite(seconds) ? seconds * 1000 : 5000);
      continue;
    }

    if ([502, 503, 504].includes(response.status)) {
      await response.body?.cancel();
      await sleep(1000 * 2 ** attempt);
      continue;
    }

    return readJson(response);
  }

  throw new Error(`Task ${taskId} could not be read after transient errors`);
}

// Submit once. If this connection fails ambiguously, reconcile before
// re-running the script: the server may already have accepted the task.
const submission = await readJson(
  await fetch('https://reapi.ai/api/v1/images/generations', {
    method: 'POST',
    headers,
    body: JSON.stringify(requestBody(model)),
    signal: AbortSignal.timeout(30_000),
  }),
);

console.log(`submitted ${submission.id}`);

const deadline = Date.now() + 5 * 60 * 1000;
let task;

while (Date.now() < deadline) {
  await sleep(3000);
  task = await getTask(submission.id);
  if (task.status === 'completed' || task.status === 'failed') break;
}

if (!task || task.status === 'processing') {
  throw new Error(
    `Local polling deadline reached. Resume GET for ${submission.id}; do not POST again.`,
  );
}

console.log(`status=${task.status} credits=${task.usage.credits}`);

if (task.status === 'failed') {
  const credits = task.usage?.credits ?? 'unknown';
  throw new Error(
    `${task.error?.code || 'task_failed'}: ${task.error?.message || 'unknown error'}; task=${task.id}; settled_credits=${credits}`,
  );
}

const outputUrl = task.output?.image_urls?.[0];
if (!outputUrl) throw new Error('Task completed without an image URL.');

const imageResponse = await fetch(outputUrl, {
  signal: AbortSignal.timeout(30_000),
});
if (!imageResponse.ok) {
  throw new Error(`Image download failed: HTTP ${imageResponse.status}`);
}

const contentType = (imageResponse.headers.get('content-type') || '')
  .split(';')[0]
  .trim()
  .toLowerCase();
const extensionByType = {
  'image/jpeg': 'jpg',
  'image/png': 'png',
  'image/webp': 'webp',
};
const extension = extensionByType[contentType];
if (!extension) throw new Error(`Unexpected output type: ${contentType}`);
const outputPath = `product-candidate.${extension}`;

await writeFile(outputPath, Buffer.from(await imageResponse.arrayBuffer()));
console.log(`saved ${outputPath} from ${outputUrl}`);

这样运行:

export REAPI_API_KEY="rk_live_replace_me"
export SOURCE_IMAGE_URL="https://assets.example.com/my-product.jpg"
export IMAGE_MODEL="nano-banana-2-lite"
node product-photo.mjs

在审查后试 GPT Image 2、Seedream 5.0 Pro 或 Nano Banana Pro,只改变 IMAGE_MODEL。请求构建器为每个模型供应正确的大小字段。

一个 15 积分实时测试返回了什么

源陶瓷杯在样式场景旁边的 1K API 输出在平面温白工作室背景上

在 2026 年 9 月 3 日,我们发送一个 reAPI 托管的 2,048 × 1,152 源 PNG 通过上面准确的 Nano Banana 2 Lite 请求,带方形输出比。任务 task_01a065bb951c735fab44b38c778e069e 完成,返回一张 1,024 × 1,024 JPEG,结算在15 积分($0.015)。图像 URL 在我们检查时可不经认证下载。

结果做了首次通过意图测试的事:它保持一个杯子,展示完整轮廓和把手开口,移除书籍和植物,把产品放在中性扫过。它也改变了小釉面斑点和反射。这使它成为有用布局候选,不是证明独特手工 SKU 保持像素相同。一次运行验证请求形状、输出形状和费用;它不建立延迟、接受率或模型胜者。[1]

以 100% 尺寸审查第一个结果

不要从缩略图决定。并排打开源和候选,缩放到 100%,填充像这样的记录:

{
  "task_id": "task_replace_me",
  "decision": "reject",
  "passed": [
    "one product",
    "complete crop",
    "background",
    "contact shadow"
  ],
  "failed": [
    "pump became taller",
    "lower cobalt band moved upward"
  ],
  "usage_credits": 15,
  "reviewer": "initials",
  "prompt_revision": 1
}

首先检查轮廓。然后比较固定标志:盖子高度、把手开口、角、接缝、按钮数、颜色边界、标签位置和表面光泽。读每个可见词。最后检查裁剪和阴影。

这个顺序是刻意的。有品味的光设置不应说服你批准不同产品。

重试一个失败条件,不要整个简报

"再试一次"教你什么都不是。向前进行通过部分并改变一个与失败联系的指令。

失败更好的下一步
盖子或把手改变命名其位置和比例;如果形状被掩盖添加另一个已拥有视图
产品变太光泽说明观察到的光泽度并移除"豪华光泽"之类词
标签字变异拒绝标签像素;保留或合成验证图稿而不是提示新副本
物品悬空要求直接在其下的接触阴影和底部表面平面
裁剪切割产品要求完整物品加数值安全边距
背景残留物保留使用抠图和确定模板而不是再问生成器
颜色转移描述产品颜色为固定并使所求光中性

给几乎正确的模型一个有针对性的重试。如果相同身份条件再次失败,切换方法:提供更好参考、使用本地化编辑或保留原始产品像素并只重建背景。 背景移除 API 定价指南 展示如何价定那个确定路线。

计算批准图像实际成本

一个积分是 $0.001。有用公式是:

cost per approved image =
  sum of settled credits for completed creative attempts × $0.001
  ----------------------------------------------------------------
                    number of approved images

假设三个 Nano Banana 2 Lite 任务各完成 15 积分。你拒绝两个作为产品漂移且批准一个:

(15 + 15 + 15) × $0.001 / 1 approved image = $0.045

API 单位价是仍然 $0.015。你的接受图像成本是 $0.045。两个数字都是真;它们回答不同问题。

商家失败通常在保留被退款后结算为零积分。你创意拒绝的完成图像保持付费。模型特定的生成后安全检查也可能保留费用即使当它隐藏输出,所以用 statususage.credits 一起而非假设每个失败任务成本为零。[5]

如果你想要小跨模型烟测试,从 Nano Banana 2 Lite、GPT Image 2 和 Seedream 5.0 Pro 各一张 1K 尝试目前预算:

15 + 30 + 32 = 77 credits = $0.077

那是一个非运行规划预算,不是测量基准、接受率或模型排名。每个模型一个输出不会支持这些任何宣称。一个更便宜、更有用的首先移动仍然是单个 15 积分布局候选,其次是失败特定决定。

把工作流放进生产,不失审计跟踪

对每一代,持续化:

  • 源资产的哈希或持久 ID;
  • 准确的模型 ID、输出级、提示和提示修订;
  • 提交时间和返回的任务 ID;
  • 终态 statususage.credits 和任何错误码;
  • 返回的 URL 和你已归档副本的位置;
  • 批准状态、审查者和简短拒绝原因。

保持提交和轮询为单独工作。一个工作者可以提交一次,存储任务 ID,让另一个工作者在重启后恢复 GET 请求。设置本地轮询截止,但不要混淆那个截止与 API 失败:如果你的进程停止等待,稍后恢复相同任务。

将批准文件存档到你控制的存储。任务契约不承诺部署的 CDN 生命周期将匹配目录的生命周期,产品页应不取决于临时生成记录。[5]

对于第一个提示通过后的无代码批处理, n8n 产品广告工作流 显示相同提交和轮询结构。如果你稍后想动作,进行批准静帧和身份合约进入 单产品照片视频工作流

当生成是错误工具时

保留原始产品像素,只在周围画布改变当:

  • 准确标签、序列号或监管标记必须保持可读;
  • 几何必须跨大目录像素相同;
  • 产品是透明、反光或覆盖细重复文本;
  • 目的地使用一个固定白背景模板;
  • 错误颜色或包装细节可能造成重大客户投诉。

在那些案例中,移除背景,清洁掩码,把抠图放在已知表面,用确定设计模板创建阴影。生成 API 仍能生成背景版本,但它不需要重新绘制产品。

FAQ

最便宜的 API 路线首先尝试是什么?

在本指南的路线中,Nano Banana 2 Lite 在 2026 年 9 月 3 日为一张完成 1K 图为 $0.015 或 15 积分。在预算前检查生产模型页因为费率会改变。

一张照片能保留产品后侧和侧吗?

不能。它能指导可见形状、材料和标签放置。它无法可靠地重建源未展示的事实。提供另一个已拥有角度或避免暴露未见表面。

我应该要求模型重写模糊标签吗?

不是为生产真相。使用验证标签图稿或原始产品模板。合理的新成分、用量、认证或保修仍然是假信息。

我应该立即在 2K 或 4K 生成吗?

在 1K 启动以验证身份、构图和裁剪。只有在图像通过那些检查且交付渠道真的需要更多像素后移上。OpenAI 和 Google 都记录他们当前图像模型的多个输出尺寸,虽然模型特定可用性和计费不同。[6][7]

产品列表应该使用什么宽高比?

使用目的地要求的比。对于跨模型试验,1:1 是安全的共享设置。Seedream 5.0 Pro 的当前公网请求接受 1:1、4:3、3:4、16:9、9:16、2:3 和 3:2,但不是 4:5。[3]

API 能返回透明产品图像吗?

取决于模型和请求表面。Seedream 5.0 Pro 暴露透明背景选项只对一个已有 alpha 通道的参考图,且它不能与层分解结合。如果你的起始照片有正常背景,专门移除工作流是更清晰第一步。[3]

失败的任务被计费吗?

商家失败和超时通常被退款,但确定的答案是终态任务的 usage.credits。一些生成后安全决定可以保留模型特定费用即使带 status: "failed"。永远不要单独从状态计算账单。[5]

我能自动化批准吗?

你能自动化机械检查如尺寸、文件解码、alpha 和产品数量。几何、微调标签准确性、颜色和宣称安全仍需人工门除非你有验证的产品特定比较系统。自动化应该路由不确定图到审查,不是安静地发布它们。

从 1K 启动,只对命名失败升级

一个有用的产品摄影 API 工作流是保守的。它从源作证据开始,冻结产品身份,保持 1K 直到产品本身正确。它记录完成拒绝,因为那些是真实成本的一部分。它知道何时抠图加模板比另一次想象生成更安全。

这就是一张普通照片如何变成店铺级图像,而不把好看渲染视为产品幸存的证明。

References

  1. reAPI. Nano Banana 2 Lite API: live pricing, request schema, and task lifecycle. Retrieved September 3, 2026 from the Nano Banana 2 Lite model page.
  2. reAPI. GPT Image 2 API: live pricing and request schema. Retrieved September 3, 2026 from the GPT Image 2 model page.
  3. reAPI. Seedream 5.0 Pro API reference. Retrieved September 3, 2026 from the Seedream 5.0 Pro documentation.
  4. reAPI. Gemini 3 Pro Image Preview API: live pricing and request schema. Retrieved September 3, 2026 from the Nano Banana Pro model page.
  5. reAPI. Tasks API: states, usage, polling, output, and refund semantics. Retrieved September 3, 2026 from the Tasks API reference.
  6. OpenAI. Image generation guide and GPT Image 2 model reference. Retrieved September 3, 2026 from the OpenAI developer documentation.
  7. Google. Gemini API image generation guide. Retrieved September 3, 2026 from the Google AI for Developers documentation.
  8. ByteDance Seed. Beyond Generation, It Understands Design: Introducing Seedream 5.0 Pro. Retrieved September 3, 2026 from the Seed product blog.

Further reading