curl --request POST \
--url https://api.apimart.ai/v1/images/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Idempotency-Key: 6baf0940-25d6-4ec2-9131-925250840fa7' \
--data '{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"image_urls": ["https://upload.apimart.ai/f/image/..."],
"cache_only": true,
"include_mask_rle": false
}'
const response = await fetch("https://api.apimart.ai/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
Accept: "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
model: "grok-imagine-2.0-ext",
operation: "region_edit",
image_id: "<SOURCE_IMAGE_ID>",
prompt: "把选中的跑车改成亮红色,保持其他画面不变",
selection_regions: [
{
outer: {
points: [0.12, 0.2, 0.48, 0.2, 0.48, 0.61, 0.12, 0.61],
},
},
],
}),
});
console.log(response.status, await response.json());
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_..."
}
]
}
{
"error": {
"message": "Invalid selection regions",
"type": "invalid_selection_regions",
"param": "selection_regions",
"code": "invalid_selection_regions"
}
}
Grok Imagine 2.0 Ext
Grok Imagine 2.0 Ext 图层与选区编辑
使用 segment 获取对象图层和精确遮罩,并通过 region_edit 按多边形、矩形或对象索引编辑指定区域。
POST
/
v1
/
images
/
generations
curl --request POST \
--url https://api.apimart.ai/v1/images/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Idempotency-Key: 6baf0940-25d6-4ec2-9131-925250840fa7' \
--data '{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"image_urls": ["https://upload.apimart.ai/f/image/..."],
"cache_only": true,
"include_mask_rle": false
}'
const response = await fetch("https://api.apimart.ai/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
Accept: "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
model: "grok-imagine-2.0-ext",
operation: "region_edit",
image_id: "<SOURCE_IMAGE_ID>",
prompt: "把选中的跑车改成亮红色,保持其他画面不变",
selection_regions: [
{
outer: {
points: [0.12, 0.2, 0.48, 0.2, 0.48, 0.61, 0.12, 0.61],
},
},
],
}),
});
console.log(response.status, await response.json());
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_..."
}
]
}
{
"error": {
"message": "Invalid selection regions",
"type": "invalid_selection_regions",
"param": "selection_regions",
"code": "invalid_selection_regions"
}
}
segment 和 region_edit 均使用现有异步图片入口。创建任务后保存 task_id,再轮询 获取任务状态;不要等待创建请求直接返回图层或图片。不要把 API Key 写入浏览器包、LocalStorage、URL 或前端日志。浏览器应调用业务 BFF,由服务端持有 Key 并转发请求。
curl --request POST \
--url https://api.apimart.ai/v1/images/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Idempotency-Key: 6baf0940-25d6-4ec2-9131-925250840fa7' \
--data '{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"image_urls": ["https://upload.apimart.ai/f/image/..."],
"cache_only": true,
"include_mask_rle": false
}'
const response = await fetch("https://api.apimart.ai/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
Accept: "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
model: "grok-imagine-2.0-ext",
operation: "region_edit",
image_id: "<SOURCE_IMAGE_ID>",
prompt: "把选中的跑车改成亮红色,保持其他画面不变",
selection_regions: [
{
outer: {
points: [0.12, 0.2, 0.48, 0.2, 0.48, 0.61, 0.12, 0.61],
},
},
],
}),
});
console.log(response.status, await response.json());
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_..."
}
]
}
{
"error": {
"message": "Invalid selection regions",
"type": "invalid_selection_regions",
"param": "selection_regions",
"code": "invalid_selection_regions"
}
}
操作概览
| 操作 | 用途 | 关键输入 | 完成结果 | 计费 |
|---|---|---|---|---|
segment | 识别对象并获取图层、边界框和精确遮罩 | source_task_id,或包含一张已上传图片的 image_urls | image_id、image_url、objects | 免费 |
region_edit | 修改多边形、矩形或对象所在区域 | segment 返回的 image_id、编辑提示词和选区 | 新图片 URL 和新 image_id | 按完成任务结算 |
已完成的 Grok 单图任务 task_id ─┐
├→ segment
上传图片返回的公网图片 URL ──────┘
→ image_id + objects[].mask_rle
→ 前端把 mask 转为 selection_regions
→ region_edit(image_id, prompt, selection_regions)
→ 新图片 URL + 新 image_id
segment 必须且只能选择一种来源:source_task_id 或 image_urls。source_task_id、image_urls 和 image_id 不可互换;region_edit 仍使用 segment 返回的图片资产 ID。编辑后重新获取图层时,将本次 region_edit 的 task_id 作为新的 source_task_id。请求头
string
必填
使用 Bearer Token:
Bearer <APIMART_API_KEY>。string
必填
固定为
application/json。string
可选。付费的
region_edit 强烈建议使用。支持 1–191 个可见 ASCII 字符,推荐 UUID。每次新的逻辑操作使用一个新 Key。网络失败重试同一次请求时,必须复用原 Key 和完全相同的请求体。409 idempotency_in_progress。如果返回 idempotency_result_indeterminate,停止自动重提并保留原 Key;尤其不要为结果不确定的付费 region_edit 生成新 Key。
异步任务流程
创建任务成功返回 HTTP200,任务 ID 位于 data[0].task_id。随后查询:
GET https://api.apimart.ai/v1/tasks/{task_id}?language=zh
Authorization: Bearer <APIMART_API_KEY>
Accept: application/json
pending、processing、completed 或 failed。建议从 2 秒间隔开始轮询,逐步退避到最多 5 秒,并设置 10 分钟总超时。切换源图或离开页面时,使用 AbortController 终止旧轮询。
任务查询即使返回 HTTP
200,data.status 仍可能是 failed。必须根据 data.status 判断任务成败,并展示 data.error。获取图层:segment
请求参数
string
默认值:"grok-imagine-2.0-ext"
必填
固定为
grok-imagine-2.0-ext。string
默认值:"segment"
必填
获取图层时固定为
segment。boolean
默认值:"false"
是否在提交图层解析任务前执行内容审核。
true:使用omni-moderation-latest审核来源图片false或不传:不发起审核请求,不增加审核成本与延迟(默认)
string
当前用户已完成的 Grok 单图任务 ID。来源任务必须成功、属于图片任务,且最终结果仅包含一张图片。与
image_urls 二选一。不要同时发送 image_id 或 image_index;服务端会从来源任务解析对应资产。string[]
上传图片来源。数组中必须且只能包含一个公网可访问的绝对
http:// 或 https:// URL。与 source_task_id 二选一。本地图片请先调用 上传图片,再把返回的 url 放入数组。使用此来源时必须设置 cache_only=true,且不要发送 cached_only 或 refresh。boolean
默认值:"true"
是否返回 COCO compressed RLE。设为
false 时仍会返回 image_id、对象索引和边界框,但不返回 RLE 遮罩;需要精确描边、画笔或多边形编辑时应显式设为 true。boolean
默认值:"false"
仅查询分段缓存,未命中时不回源。使用
image_urls 时固定为 true;使用 source_task_id 时不能与 refresh=true 同时使用。boolean
默认值:"false"
传递给上游的缓存提示,不代表本地一定命中缓存。仅适用于
source_task_id 来源。boolean
默认值:"false"
强制跳过缓存重新获取。仅适用于
source_task_id 来源;不要用于普通编辑器流程,也不能与 cache_only=true 同时使用。segment 不需要 prompt,也不要发送 billing_model_name、n、size 或 response_format。source_task_id 与 image_urls 必须二选一,不能同时发送或同时省略。
请求示例
- 使用任务 ID
- 使用上传图片
- 任务缓存探测
{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
"include_mask_rle": true,
"cached_only": false
}
{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"image_urls": ["https://upload.apimart.ai/f/image/..."],
"cache_only": true,
"include_mask_rle": false
}
{
"model": "grok-imagine-2.0-ext",
"operation": "segment",
"source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
"include_mask_rle": true,
"cache_only": true
}
cache_only=true 时,缓存未命中仍是成功任务。根据 cache_status 判断:hit 可直接显示图层,miss 表示尚无缓存。不要用 cached 字段判断是否命中。
从本地上传图片
先通过上传接口把本地文件换成公网 URL:curl --request POST \
--url https://api.apimart.ai/v1/uploads/images \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/source.png'
url,将其作为唯一的 image_urls 元素提交给 segment。后续异步轮询、完成响应以及 region_edit 的调用方式都与 source_task_id 来源一致:从完成结果中读取 result.image_id 和 objects,再提交选区编辑。上传 URL 为临时地址,默认保留 72 小时。
image_urls 仅接受一张公网可访问的绝对 HTTP(S) URL。图片来源模式只支持 cache_only=true;不要同时发送 source_task_id、cached_only 或 refresh。完成响应
segment 的 data.result 直接是分段结果,不包在 images 中:
{
"code": 200,
"data": {
"id": "task_...",
"status": "completed",
"progress": 100,
"cost": 0,
"credits_cost": 0,
"result": {
"created": 1786784507,
"source_task_id": "task_...",
"image_id": "6b78a7c3-5f9e-4a3d-a928-9e9b42113a3f",
"image_url": "https://.../source.jpg",
"cached": false,
"from_cache": true,
"cache_status": "hit",
"objects": [
{
"index": 0,
"name": "red sports car",
"box_xyxy": [38.1, 689.8, 945.8, 1065.4],
"score": 0.9765625,
"mask_size": [1792, 1008],
"mask_url": "",
"mask_rle": {
"size": [1792, 1008],
"counts": "..."
}
}
]
}
}
}
| 字段 | 说明 |
|---|---|
result.image_id | 来源图片的资产 ID,后续 region_edit 使用此值 |
result.image_url | 与 image_id 对齐的公网 HTTP(S) 图片 URL |
objects[].index | 服务端原始对象索引;使用 object_indices 时必须原样保留 |
objects[].box_xyxy | mask 像素坐标 [x1,y1,x2,y2] |
objects[].score | 识别置信度,可能为 null |
objects[].mask_size | [height,width],不可写死图片尺寸 |
objects[].mask_rle | COCO compressed RLE,精确描边的首选数据 |
objects[].mask_url | 可选的遮罩图片 URL,可能为空 |
mask_rle 或 mask_url 的对象只能用于矩形近似编辑,不能标记为精确图层。
解码 mask_rle
mask_rle.counts 是 COCO 压缩计数字符串,不是 Base64,也不是 zlib。数据按列优先顺序展开;第一个 run 表示背景像素数,此后在背景和前景之间交替。
以下 TypeScript 将结果转换为浏览器常用的行优先二值数组:
export interface CocoRLE {
size: [height: number, width: number];
counts: string;
}
export interface BinaryMask {
width: number;
height: number;
data: Uint8Array; // data[y * width + x]
}
function decodeCompressedCounts(counts: string): number[] {
const runs: number[] = [];
let cursor = 0;
while (cursor < counts.length) {
let value = 0;
let shift = 0;
let more = true;
while (more) {
if (cursor >= counts.length) throw new Error("截断的 COCO RLE counts");
const current = counts.charCodeAt(cursor++) - 48;
value |= (current & 0x1f) << shift;
more = (current & 0x20) !== 0;
shift += 5;
if (!more && (current & 0x10) !== 0) value |= -1 << shift;
}
if (runs.length > 2) value += runs[runs.length - 2] ?? 0;
if (value < 0) throw new Error(`非法 COCO RLE run: ${value}`);
runs.push(value);
}
return runs;
}
export function decodeCocoRLE(rle: CocoRLE): BinaryMask {
const [height, width] = rle.size;
if (!Number.isInteger(height) || !Number.isInteger(width) || height <= 0 || width <= 0) {
throw new Error(`非法 mask size: ${JSON.stringify(rle.size)}`);
}
const pixelCount = width * height;
if (!Number.isSafeInteger(pixelCount) || pixelCount > 32_000_000) {
throw new Error(`mask 像素数超出前端安全上限: ${pixelCount}`);
}
if (typeof rle.counts !== "string" || rle.counts.length === 0) {
throw new Error("缺少 COCO RLE counts");
}
const data = new Uint8Array(pixelCount);
const runs = decodeCompressedCounts(rle.counts);
let position = 0;
let foreground = false;
for (const run of runs) {
if (position + run > data.length) throw new Error("COCO RLE 超出 mask_size");
if (foreground) {
for (let offset = 0; offset < run; offset++) {
const columnMajorIndex = position + offset;
const y = columnMajorIndex % height;
const x = (columnMajorIndex - y) / height;
data[y * width + x] = 1;
}
}
position += run;
foreground = !foreground;
}
if (position !== data.length) {
throw new Error(`COCO RLE 只覆盖 ${position}/${data.length} 个像素`);
}
return { width, height, data };
}
mask_rle.counts 写入日志、埋点、URL 或错误上报。
转换为精确选区
region_edit 使用归一化多边形:
export interface SelectionBoundary {
points: number[]; // [x0,y0,x1,y1,...],坐标范围 0~1
}
export interface SelectionRegion {
outer: SelectionBoundary;
holes?: SelectionBoundary[];
}
mask_size 的顺序是 [height,width],坐标基于原始 mask,不是 CSS 显示尺寸。使用 object-fit: contain 时,需要先扣除留白偏移并按实际绘制区域换算,最后将坐标限制在 0~1。mask_url 的像素,图片服务器必须允许当前站点跨域访问,并且要在设置 src 前指定 image.crossOrigin = "anonymous",或通过 fetch 获取 Blob。否则图片绘制到 Canvas 后会污染画布,无法再读取像素。图层轮廓优先直接解码 mask_rle,不依赖跨域读取源图。
编辑选区:region_edit
请求参数
string
默认值:"grok-imagine-2.0-ext"
必填
固定为
grok-imagine-2.0-ext。string
默认值:"region_edit"
必填
编辑选区时固定为
region_edit。boolean
默认值:"false"
是否在提交选区编辑任务前执行内容审核。
true:使用omni-moderation-latest审核编辑提示词和输入图片false或不传:不发起审核请求,不增加审核成本与延迟(默认)
string
必填
当前源图的资产 ID。首次编辑使用 segment 响应中的
result.image_id;连续编辑使用上次编辑返回的新 image_id。string
必填
描述如何修改选区,去除首尾空格后不能为空。
array
精确多边形选区,推荐用于正式图层和画笔编辑。坐标归一化到
0~1,支持 outer 和可选 holes。number[][]
矩形选区,每项为
[x1,y1,x2,y2]。可使用归一化坐标;使用像素坐标时必须同时传 mask_size。integer[]
segment 返回的原始
objects[].index。上游按对象边界框编辑,因此只适合快速联调或矩形近似模式。integer[]
像素
boxes 使用的 [height,width]。两个值都必须为正整数。selection_regions、boxes、object_indices 至少有一个非空。接口允许组合,但建议一次只使用一种,避免重叠选区和语义不清。
不要发送
billing_model_name、size、aspect_ratio、source_aspect_ratio、source_size 或 image_urls。n 只能省略或设为 1;claim_asset 只能省略或设为 false;response_format 只能省略或设为 url;不支持 Base64 输出和 stream=true。三种选区方式
- 精确多边形(推荐)
- 归一化矩形
- 像素矩形
- 对象索引
{
"model": "grok-imagine-2.0-ext",
"operation": "region_edit",
"image_id": "<SOURCE_IMAGE_ID>",
"prompt": "把选中的跑车改成亮红色,保持其他画面不变",
"selection_regions": [
{
"outer": {
"points": [0.12, 0.20, 0.48, 0.20, 0.48, 0.61, 0.12, 0.61]
},
"holes": [
{
"points": [0.30, 0.35, 0.38, 0.35, 0.38, 0.45, 0.30, 0.45]
}
]
}
]
}
points 可使用扁平数组,也兼容 [[x0,y0],[x1,y1],...]。每项必须是 0~1 的有限数字,每个 ring 至少包含 3 对坐标。{
"model": "grok-imagine-2.0-ext",
"operation": "region_edit",
"image_id": "<SOURCE_IMAGE_ID>",
"prompt": "把框内车辆改成亮红色",
"boxes": [[0.04, 0.385, 0.938, 0.594]]
}
{
"model": "grok-imagine-2.0-ext",
"operation": "region_edit",
"image_id": "<SOURCE_IMAGE_ID>",
"prompt": "把框内车辆改成亮红色",
"boxes": [[40, 689.6, 945.9, 1064.4]],
"mask_size": [1792, 1008]
}
x2>x1、y2>y1。{
"model": "grok-imagine-2.0-ext",
"operation": "region_edit",
"image_id": "<SOURCE_IMAGE_ID>",
"prompt": "把选中的跑车改成亮红色,保持其他画面不变",
"object_indices": [0]
}
image_id 的 segment 响应。不要使用前端过滤、排序或分组后重新生成的数组下标。完成响应
{
"code": 200,
"data": {
"id": "task_...",
"status": "completed",
"progress": 100,
"cost": 0.016,
"credits_cost": 0.16,
"result": {
"images": [
{
"url": ["https://.../result.jpg"],
"image_ids": ["<NEW_IMAGE_ID>"],
"items": [
{
"url": "https://.../result.jpg",
"image_id": "<NEW_IMAGE_ID>",
"source_image_id": "<SOURCE_IMAGE_ID>",
"role": "region_edit",
"prompt": "把选中的跑车改成亮红色,保持其他画面不变"
}
],
"expires_at": 1787040000
}
]
}
}
}
result.images[0].items[0]。兼容旧响应时,可读取同一下标的 url[0] 和 image_ids[0],但必须同时拿到可展示的 HTTP(S) URL 和新的 image_id。
interface RegionEditResult {
images?: Array<{
url?: string[];
image_ids?: string[];
items?: Array<{
url?: string;
image_id?: string;
}>;
}>;
}
function readRegionEditOutput(result: RegionEditResult): {
url: string;
imageId: string;
} {
const group = result.images?.[0];
const item = group?.items?.[0];
if (item?.url && item.image_id && /^https?:\/\//i.test(item.url)) {
return { url: item.url, imageId: item.image_id };
}
if (
group?.url?.length &&
group.image_ids?.length === group.url.length &&
/^https?:\/\//i.test(group.url[0]) &&
group.image_ids[0]
) {
return { url: group.url[0], imageId: group.image_ids[0] };
}
throw new Error("选区编辑完成,但结果缺少对齐的 HTTP(S) URL 或 image_id");
}
expires_at 为准,不要在前端硬编码固定小时数。需要长期展示时应及时下载或转存。
连续编辑
一次编辑完成后,应同时更新三个值并清除旧图层缓存:const output = readRegionEditOutput(task.data.result);
editor.sourceTaskId = task.data.id; // 下一次 segment 使用
editor.sourceImageId = output.imageId; // 下一次 region_edit 使用
editor.sourceUrl = output.url; // 编辑器展示
editor.layers = [];
- 再次获取图层:
source_task_id = 本次 region_edit 的 task_id - 再次编辑:
image_id = 本次 region_edit 返回的新 image_id - 不要把
image_id传给segment,也不要继续使用上一张图片的旧image_id
错误处理
| HTTP / 状态 | 错误码 | 常见原因 | 建议处理 |
|---|---|---|---|
| 400 | invalid_operation | operation 缺失或不受支持 | 只使用 segment 或 region_edit |
| 400 | invalid_source | source_task_id 与 image_urls 同时发送或同时省略 | 两种 segment 来源严格二选一 |
| 400 | invalid_image_urls | URL 不是公网 HTTP(S) 地址,或数组不是恰好一项 | 先上传图片,并只发送返回的一个 url |
| 400 | invalid_source_task | segment 来源任务不可用,或传入 image_id / image_index | 使用当前用户已完成的 Grok 单图任务 ID |
| 400 | invalid_request | 图片来源未设 cache_only=true,或发送了 cached_only / refresh | 图片来源只保留 cache_only=true |
| 400 | conflicting_cache_flags | 同时使用 cache_only 和 refresh | 二选一 |
| 400 | missing_image_id | region edit 缺少资产 ID | 使用 segment 返回的 result.image_id |
| 400 | empty_prompt | 编辑提示词为空 | 阻止提交并提示用户输入修改描述 |
| 400 | invalid_selection_regions | 无选区、坐标、点数或 box 非法 | 在前端校验并标记问题选区 |
| 400 | invalid_object_index | 对象索引非法 | 保留同一图片 segment 返回的原始索引 |
| 400 | invalid_claim_asset | claim_asset=true | 省略或设为 false |
| 400 | invalid_n | n 不是 1 | 省略或设为 1 |
| 400 | invalid_response_format | 请求 Base64 等不支持格式 | 省略或使用 url |
| 400 | invalid_stream | 请求流式响应 | 移除 stream |
| 401 / 403 | 鉴权或权限错误 | Key 无效或模型未开通 | 检查服务端 Key 和账户权限 |
| 402 | 余额不足 | 付费编辑无法创建 | 提示充值后重试 |
| 409 | 幂等冲突 | 同一 Key 正在处理、请求体变化或结果不确定 | 遵循响应码,不要换 Key 自动重提 |
| 429 | 请求过多 | 触发限流 | 按 Retry-After 退避 |
failed | task_failed | 异步任务执行失败 | 停止轮询并展示 data.error.message |
object_indices 可能在创建后异步失败,因此创建请求成功不代表编辑一定成功。
计费说明
segment免费,完成任务的cost和credits_cost均为0,但仍需正常鉴权并满足来源输入条件。region_edit为付费操作。以任务完成响应中的cost和credits_cost为准,不要在前端硬编码价格。- 不要发送内部计费字段
billing_model_name。
前端接入检查
- API Key 只保存在后端或 BFF。
segment仅发送一种来源:已有任务使用source_task_id,上传图片使用只含一个公网 URL 的image_urls;不要发送image_id或image_index。- 使用
image_urls时设置cache_only=true,且不发送cached_only或refresh。 region_edit使用 segment 返回的image_id,并至少提供一种选区。- 正式图层编辑使用
selection_regions;object_indices仅为矩形近似。 mask_size始终按[height,width]解析,并正确处理图片显示区域的缩放和留白。- 同一次网络重试复用原
Idempotency-Key,收费请求结果不确定时不自动换 Key 重提。 - 任务完成后同时校验 URL 和新
image_id,连续编辑时清理旧图层和旧轮询。