商品套图

简介

上传同一商品的 1–6 张原图,规划并生成主图、场景图、卖点图、细节图、氛围图与广告图。能力标识为 image.product_kit。平台接口使用 Authorization: Bearer <ANYCAP_API_KEY>,不携带浏览器 Cookie 或 Origin。可直接提供已有有效方案,或先通过下方可选的文本/视觉接口准备方案;成图复用现有图片生成服务。

请求接口

方法路径返回
GET/api/v1/capabilities/image.product_kit有权限的分析/图片模型、精确规格与接口路径
POST/api/v1/capabilities/image.product_kit/analysis-requests免费构造 native_request、execution_path、execution_required=true
POST/v1/chat/completions单独计费的商品分析,JSON 方案位于 choices[0].message.content
POST/api/v1/capabilities/image.product_kit/quotes201 保存的整套报价;相同请求回放返回 200
POST/api/v1/capabilities/image.product_kit/executions202 原套图与逐张任务状态
GET/api/v1/capabilities/image.product_kit/executions/{id}?result=true套图状态与已完成图片临时链接

调用顺序:发现 image_models → 选择 priced_combinations 中的一组规格 → 提供 plan → 报价 → 提交已保存的套图 id → 使用 result=true 查询 → 批量保存成图。已有方案可跳过 analysis-requests 和 chat/completions。/api/v1/product-kit/workflows 使用浏览器会话,不作为 Bearer 接入地址。

可选:准备套图方案

字段类型含义
modelstring
含义从发现结果 analysis_models[].model 选择
image_urlsstring[1–6]
含义不重复的公开 HTTPS 商品原图;不接受认证信息、私网/本机地址、片段或 Data URL
max_tokensinteger
含义1024–16000,默认 8192,同时受模型发现结果上限约束
settings.platform / market / language / stylestring
含义必填:电商平台、市场、图中文字语言与视觉风格
settings.requirementstring
含义可选真实商品信息与补充要求,最多 1600 字符
settings.countsobject
含义hero主图 / scene场景 / selling卖点 / detail细节 / mood氛围 / ad广告;每类0–4,合计1–12。整个对象省略默认各一张;显式对象中省略的类别为0
settings.listingboolean
含义是否生成商品标题与描述,默认false
settings.commercial_style_analysisboolean
含义商业构图建议,默认false,不检索实时爆款

构造请求不会调用模型。将返回的 native_request 原样发往 execution_path,并附稳定的 Idempotency-Key,才会执行单独计费的分析。仅在 choices[0].finish_reason 为 stop,且 content 可解析为 JSON 时使用方案。在付费调用前保存分析操作键;超时不代表未调用,不可据此换键重做,应先核对原文本调用。

套图报价参数

字段类型含义
idempotency_keystring
含义必填、1–255字节的稳定套图操作键,按连接隔离;同键修改内容返回409
model / size / resolution / qualitystring
含义model取image_models[].model,size/resolution/quality从同一条priced_combinations原样复制。比例与清晰度必须为已报价组合;quality可能表示版本。勿写死选项数量或修改大小写。
image_urlsstring[1–6]
含义同一组商品原图,同时受所选模型参考图上限约束
plan.product / summarystring
含义必填商品名(≤300字符)与商品事实/视觉方案(≤2000)
plan.selling_points / title / descriptionarray / string
含义可选真实卖点(≤8条)、上架标题(≤300)与描述(≤3000)
plan.imagesarray[1–12]
含义逐张必填kind、title(≤120)与独立prompt(20–6000字符);每类最多四张

可编辑分析方案,也可直接提供有效方案。每张固定n=1,均携带同一组商品原图。报价返回id、amount_microcredits、expires_at及items;每项包含index、id、kind、title、quote_id、resource_id、native_request、amount_microcredits和expires_at。整套金额为各张独立取整后的合计,分析费用另计。提交前保存完整报价清单;报价本身不预留积分。expires_at为最早一张报价的到期时间。

提交与结果

提交 {"id":"BATCH_UUID","max_microcredits":"已授权图片总预算"}。预算为正int64微积分,限制本套已报价图片总额。服务端先校验全部报价,再原子领取本套提交权,使用已保存的逐张任务ID并发生成。每张独立计费,某张拒绝不会取消其他任务。重复提交返回原套图,不会再次发起整套提交。

套图state含义
quoted尚未开始整套提交
processing仍有图片处理
completed全部完成
partial全部进入终态,部分成功、部分失败
failed全部失败或明确未提交
pending至少一张结果待核对,不自动新建替代套图

返回id、image_count、items、charged_microcredits、reserved_microcredits、manifest_expires_at及未过期的manifest。每项含index、id、state;任务存在时带原ImageJob。charged_microcredits合计已知图片实扣,reserved_microcredits合计已知held/pending预留。submission_unconfirmed表示缺失任务结果尚不确定,不能把已知合计当作最终零费用。result=true读取.items[].job.images临时链接,请及时保存;也可GET /api/v1/image-executions/{id}?result=true读取原单张任务。完整方案清单保留72小时,到期后保留套图身份与原单张账务记录。

完整调用示例

BASH
# Requires bash, curl and jq. Save artifacts privately; the API key stays in the environment.set -euo pipefailumask 077BASE="https://api.anycap.io"KIT="$BASE/api/v1/capabilities/image.product_kit"curl --fail-with-body "$KIT" -H "Authorization: Bearer $ANYCAP_API_KEY" > kit-models.json # Set ORIGINAL_IMAGE_URL to a public HTTPS photo of your own product.# Choose one exact image specification from the returned catalog.# Supply kit-plan.json yourself to skip the optional text/vision call.if [ ! -s kit-plan.json ]; thenANALYSIS_MODEL=$(jq -er '.analysis_models[0].model' kit-models.json)ANALYSIS_TOKENS=$(jq -er '.analysis_models[0].max_output_tokens | if . < 8192 then . else 8192 end' kit-models.json)jq -n --arg model "$ANALYSIS_MODEL" --arg image "$ORIGINAL_IMAGE_URL" --argjson tokens "$ANALYSIS_TOKENS" \  '{model:$model,image_urls:[$image],max_tokens:$tokens,settings:{platform:"Amazon",market:"United States",language:"English",style:"Minimal studio photography",listing:true}}' > analysis-input.jsoncurl --fail-with-body "$KIT/analysis-requests" -H "Authorization: Bearer $ANYCAP_API_KEY" \  -H "Content-Type: application/json" --data-binary @analysis-input.json > analysis-request.jsonjq -e '.native_request' analysis-request.json > analysis-native.json # This next request is a separately billed text/vision call. Run only after authorization.# Set and persist ANALYSIS_OPERATION before calling; never change it to retry an unknown outcome.: "${ANALYSIS_OPERATION:?Set a stable analysis operation key}"curl --fail-with-body "$BASE/v1/chat/completions" -H "Authorization: Bearer $ANYCAP_API_KEY" \  -H "Idempotency-Key: $ANALYSIS_OPERATION" -H "Content-Type: application/json" \  --data-binary @analysis-native.json > analysis-result.jsonjq -e '.choices[0].finish_reason == "stop"' analysis-result.json >/dev/null || exit 1jq -er '.choices[0].message.content' analysis-result.json | jq -e . > kit-plan.jsonfi # Review/edit kit-plan.json. Use a new operation key for each NEW set, never for a lost response.: "${KIT_OPERATION:?Set a stable kit operation key}"jq -n --arg operation "$KIT_OPERATION" --arg image "$ORIGINAL_IMAGE_URL" \  --slurpfile catalog kit-models.json --slurpfile plan kit-plan.json \  '{idempotency_key:$operation,model:$catalog[0].image_models[0].model,image_urls:[$image],plan:$plan[0]} + ($catalog[0].image_models[0].priced_combinations[0] | {size,resolution,quality})' > kit-input.jsoncurl --fail-with-body "$KIT/quotes" -H "Authorization: Bearer $ANYCAP_API_KEY" \  -H "Content-Type: application/json" --data-binary @kit-input.json > kit-quote.json# The complete batch id, child ids and prices are now saved BEFORE the paid POST.jq '{id,amount_microcredits,expires_at,items:[.items[]|{id,kind,amount_microcredits}]}' kit-quote.json # Explicit image budget in integer microcredits; 1 credit = 1000000 microcredits.: "${ANYCAP_MAX_MICROCREDITS:?Set the authorized total image budget}"jq --arg budget "$ANYCAP_MAX_MICROCREDITS" '{id,max_microcredits:$budget}' kit-quote.json > kit-submit.jsoncurl --fail-with-body "$KIT/executions" -H "Authorization: Bearer $ANYCAP_API_KEY" \  -H "Content-Type: application/json" --data-binary @kit-submit.json > kit-execution.json # Also use this GET if the submission response was lost. Poll at 15-second intervals.BATCH_ID=$(jq -er '.id' kit-quote.json)curl --fail-with-body "$KIT/executions/$BATCH_ID?result=true" \  -H "Authorization: Bearer $ANYCAP_API_KEY" > kit-result.jsonjq '.items[]|{id,state,images:(.job.images // []),error_code:(.error_code // .job.error_code)}' kit-result.json

单张重新生成

用户明确要求重做时,新建报价请求:保留原image_urls及model/size/resolution/quality,保留plan.product和plan.summary,将plan.images设为已保存方案中选定的那一项。为这张新图使用新的idempotency_key,再提交、查询返回的新套图id;不必再次调用文本/视觉接口。适用于已完成或已释放的任务,不能用来替代结果未知的pending任务。

整套保存到目录与ZIP

把result=true响应保存为kit-result.json,在同一目录运行以下Python 3示例;可用KIT_OUTPUT_DIR指定保存目录。程序一次保存全部已完成且已结算的原图,按序号写入新文件夹,并在旁边生成ZIP;partial套图仅导出成功图片。链接临时有效,失效时查询原套图获取新链接。选择目录和打包由接入客户端完成,不需要新增生成请求。

PYTHON
# Python 3 standard library. Input: the saved GET .../executions/{id}?result=true response.import json, os, uuid, zipfilefrom pathlib import Pathfrom urllib.parse import urlsplitfrom urllib.request import Request, urlopen result = json.loads(Path("kit-result.json").read_text(encoding="utf-8"))if result.get("state") not in ("completed", "partial"):    raise SystemExit("Query the original batch until completed or partial before saving.")files, total = [], 0extensions = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp", "image/gif": "gif"}for index, item in enumerate(result["items"]):    job = item.get("job", {})    if job.get("state") != "completed" or job.get("billing_status") != "settled":        continue    for image_index, url in enumerate(job.get("images", [])):        parsed = urlsplit(url)        if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password:            raise SystemExit("Invalid image link. Query result=true again.")        # Image downloads do not receive your Anycap key or browser cookies.        with urlopen(Request(url), timeout=60) as response:            if urlsplit(response.geturl()).scheme != "https":                raise SystemExit("Unexpected image redirect.")            extension = extensions.get(response.headers.get("Content-Type", "").split(";")[0])            if not extension:                raise SystemExit("Image unavailable. Query result=true again.")            data = response.read(20 * 1024 * 1024 + 1)        total += len(data)        if not data or len(data) > 20 * 1024 * 1024 or total > 120 * 1024 * 1024:            raise SystemExit("Image set exceeds download limits.")        files.append((f"{item.get('index', index) + 1:02d}_{image_index + 1:02d}.{extension}", data))if not files:    raise SystemExit("No completed images available. Query result=true again.")output = Path(os.environ.get("KIT_OUTPUT_DIR", "."))output.mkdir(parents=True, exist_ok=True)folder = output / ("anycap-product-kit-" + uuid.uuid4().hex[:12])folder.mkdir()  # A new folder prevents overwriting existing images.archive = folder.with_suffix(".zip")with zipfile.ZipFile(archive, "x", compression=zipfile.ZIP_STORED) as bundle:    for name, data in files:        (folder / name).write_bytes(data)        bundle.writestr(folder.name + "/" + name, data)print(f"Saved {len(files)} images: {folder.resolve()}")print(f"ZIP: {archive.resolve()}") 

错误

状态码处理
400修正字段、商品图URL、方案或预算
401 / 403检查密钥、成员与来源权限
402预算低于图片报价总额或余额不足;整套已领取提交权时检查逐张状态
404套图/报价不属于当前连接,或完整清单已过期
409同键修改输入或报价绑定不一致,保留原套图与任务ID
429请求或并发限制,检查已有逐张结果
503模型/来源不可用或服务暂时异常;已提交时查询原套图,不自动重建
上一篇文本生成
下一篇图片生成