> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apimart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Calques et édition de zones Grok Imagine 2.0 Ext

> Utilisez segment pour récupérer les calques d'objets et les masques précis, puis modifiez des polygones, cadres ou objets détectés avec region_edit.

<Info>
  `segment` et `region_edit` utilisent le point d'entrée d'images asynchrone existant. Enregistrez le `task_id`, puis interrogez [Obtenir le statut de la tâche](/fr/api-reference/tasks/status) ; la requête de création ne renvoie pas directement les calques ou images finaux.
</Info>

<Warning>
  N'exposez jamais une clé API dans le bundle du navigateur, LocalStorage, une URL ou les journaux frontend. Appelez APIMart via votre backend ou BFF.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  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",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cached_only": false
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "code": 200,
    "data": [{ "status": "submitted", "task_id": "task_..." }]
  }
  ```
</ResponseExample>

## Vue d'ensemble des opérations

| Objectif                                                                      | Entrée principale               | Résultat final                     | Facturation                |
| ----------------------------------------------------------------------------- | ------------------------------- | ---------------------------------- | -------------------------- |
| `segment`: Détecter les objets et récupérer calques, cadres et masques précis | `source_task_id`                | `image_id`, `image_url`, `objects` | Gratuit                    |
| `region_edit`: Modifier un polygone, rectangle ou objet détecté               | `image_id`, `prompt`, sélection | Nouvelle URL et `image_id`         | Facturé par tâche terminée |

```text theme={null}
task_id → segment(source_task_id) → image_id + mask_rle
        → selection_regions → region_edit → new task_id + image_id
```

<Note>
  `source_task_id` et `image_id` ne sont pas interchangeables. `segment` reçoit l'ID de tâche source, `region_edit` l'ID de l'asset image. Pour segmenter une image modifiée, utilisez l'ID de la tâche `region_edit` terminée comme nouveau `source_task_id`.
</Note>

## En-têtes de requête

Utilisez `Authorization: Bearer <APIMART_API_KEY>`, `Content-Type: application/json` et `Accept: application/json`.

`Idempotency-Key` est facultatif et fortement recommandé pour les requêtes `region_edit` payantes. Il accepte 1 à 191 caractères ASCII visibles ; un UUID est recommandé. Utilisez une nouvelle clé par opération logique. Une nouvelle tentative réseau de la même requête doit réutiliser la clé et le corps d'origine. Si le résultat est indéterminé, ne relancez pas automatiquement avec une nouvelle clé.

## Flux de tâche asynchrone

Une création réussie renvoie HTTP `200` et `data[0].task_id`. Interrogez `GET /v1/tasks/{task_id}?language=fr` toutes les 2 secondes, puis jusqu'à 5 secondes maximum, avec une limite globale de 10 minutes. Arrêtez l'ancien polling lorsque l'image source change.

<Warning>
  Une consultation peut renvoyer HTTP `200` alors que `data.status` vaut `failed`. Déterminez toujours le résultat via `data.status` et affichez `data.error` s'il existe.
</Warning>

## `segment`

### Paramètres de requête

| Champ              | Type    | Obligatoire | Défaut  | Description                                                                       |
| ------------------ | ------- | :---------: | ------- | --------------------------------------------------------------------------------- |
| `model`            | string  |      ✅      | —       | Fixé à `grok-imagine-2.0-ext`                                                     |
| `operation`        | string  |      ✅      | —       | Fixé à `segment`                                                                  |
| `source_task_id`   | string  |      ✅      | —       | Tâche Grok terminée, à image unique, appartenant à l'utilisateur actuel           |
| `include_mask_rle` | boolean |      —      | `true`  | Renvoyer le COCO compressed RLE ; conserver `true` pour l'édition précise         |
| `cache_only`       | boolean |      —      | `false` | Vérifier uniquement le cache de segmentation ; aucun appel amont en cas d'absence |
| `cached_only`      | boolean |      —      | `false` | Indication de cache amont, sans garantie locale                                   |
| `refresh`          | boolean |      —      | `false` | Ignorer le cache ; ne pas utiliser dans le flux normal                            |

`segment` ne nécessite pas de `prompt`. N'envoyez pas `image_id`, `image_index`, `billing_model_name`, `n`, `size` ou `response_format`. `cache_only=true` et `refresh=true` sont incompatibles.

### Exemples de requête

<Tabs>
  <Tab title="Récupérer les calques">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "segment",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cached_only": false
    }
    ```
  </Tab>

  <Tab title="Tester le cache">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "segment",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cache_only": true
    }
    ```
  </Tab>
</Tabs>

Une absence du cache reste une tâche réussie. Utilisez `cache_status` (`hit` ou `miss`) ou `from_cache` ; ne déduisez pas un hit de `cached`.

### Réponse terminée

Pour `segment`, `data.result` contient directement le résultat de segmentation ; il n'est pas enveloppé dans `images`.

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_...",
    "status": "completed",
    "progress": 100,
    "cost": 0,
    "credits_cost": 0,
    "result": {
      "source_task_id": "task_...",
      "image_id": "6b78a7c3-5f9e-4a3d-a928-9e9b42113a3f",
      "image_url": "https://.../source.jpg",
      "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": "..." }
      }]
    }
  }
}
```

| Champ                 | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `result.image_id`     | ID d'asset utilisé par `region_edit`                         |
| `result.image_url`    | URL HTTP(S) alignée avec `image_id`                          |
| `objects[].index`     | Indice serveur d'origine ; à conserver pour `object_indices` |
| `objects[].box_xyxy`  | Cadre de masque en pixels `[x1,y1,x2,y2]`                    |
| `objects[].score`     | Confiance de détection ; peut être `null`                    |
| `objects[].mask_size` | Toujours `[height,width]` ; ne jamais figer les dimensions   |
| `objects[].mask_rle`  | COCO compressed RLE pour les contours précis                 |
| `objects[].mask_url`  | URL d'image de masque facultative ; peut être vide           |

Sans `mask_rle` ou `mask_url` valide, un objet ne peut être modifié que par approximation rectangulaire.

## Décoder `mask_rle`

`mask_rle.counts` est une chaîne de comptages compressés COCO, ni Base64 ni zlib. Elle se déploie par colonnes ; le premier run est l'arrière-plan, puis avant-plan et arrière-plan alternent.

Le TypeScript suivant la convertit en masque binaire par lignes adapté au navigateur :

```ts theme={null}
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("Truncated 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(\`Invalid 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(\`Invalid mask size: \${JSON.stringify(rle.size)}\`);
  }
  const pixelCount = width * height;
  if (!Number.isSafeInteger(pixelCount) || pixelCount > 32_000_000) {
    throw new Error(\`Mask exceeds the frontend safety limit: \${pixelCount}\`);
  }
  if (!rle.counts) throw new Error("Missing 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 exceeds mask_size");
    if (foreground) {
      for (let offset = 0; offset < run; offset++) {
        const index = position + offset;
        const y = index % height;
        const x = (index - y) / height;
        data[y * width + x] = 1;
      }
    }
    position += run;
    foreground = !foreground;
  }
  if (position !== data.length) throw new Error("COCO RLE does not cover the mask");
  return { width, height, data };
}
```

Décodez les grands masques dans un Web Worker. N'envoyez jamais les valeurs complètes de `mask_rle.counts` dans les logs, analyses, URL ou rapports d'erreur.

### Convertir les masques en sélections précises

```ts theme={null}
interface SelectionBoundary { points: number[] }
interface SelectionRegion { outer: SelectionBoundary; holes?: SelectionBoundary[] }
```

Tracez les composants connexes et les trous, simplifiez les contours et normalisez chaque point sur `0–1`. Chaque anneau doit avoir au moins 3 points distincts, une aire non nulle et aucune auto-intersection. Conservez au plus les 16 plus grandes régions par calque et 400 points par anneau.

<Warning>
  `mask_size` est `[height,width]` et utilise les coordonnées du masque source, pas les dimensions CSS. Avec `object-fit: contain`, retirez les marges, mettez à l'échelle selon la zone réellement dessinée et limitez le résultat à `0–1`.
</Warning>

La lecture des pixels de l'image source ou de `mask_url` exige CORS. Définissez `crossOrigin = "anonymous"` avant `src` ou récupérez un Blob. Le décodage direct de `mask_rle` évite cette dépendance.

## Modifier une zone : `region_edit`

### Paramètres de requête

| Champ               | Type         | Obligatoire | Description                                                                                            |
| ------------------- | ------------ | :---------: | ------------------------------------------------------------------------------------------------------ |
| `model`             | string       |      ✅      | Fixé à `grok-imagine-2.0-ext`                                                                          |
| `operation`         | string       |      ✅      | `region_edit`                                                                                          |
| `image_id`          | string       |      ✅      | ID de l'asset source ; utilisez d'abord le `image_id` de `segment`, puis le dernier résultat d'édition |
| `prompt`            | string       |      ✅      | Instruction non vide décrivant la modification                                                         |
| `selection_regions` | array        |      \*     | Polygones normalisés sur `0–1` avec `outer` et `holes` facultatifs ; recommandé                        |
| `boxes`             | number\[]\[] |      \*     | Rectangles `[x1,y1,x2,y2]` ; les cadres en pixels exigent `mask_size`                                  |
| `object_indices`    | integer\[]   |      \*     | Valeurs `objects[].index` d'origine ; approximation rectangulaire uniquement                           |
| `mask_size`         | integer\[]   |      \*     | Obligatoire pour les cadres en pixels ; `[height,width]` avec entiers positifs                         |

Au moins l'un de `selection_regions`, `boxes` ou `object_indices` doit être non vide. L'API accepte les combinaisons, mais le frontend devrait utiliser une seule méthode par requête.

<Warning>
  N'envoyez pas `billing_model_name`, `size`, `aspect_ratio`, `source_aspect_ratio`, `source_size` ou `image_urls`. Omettez `n` ou utilisez `1`, omettez `claim_asset` ou utilisez `false`, omettez `response_format` ou utilisez `url`. Base64 et `stream=true` ne sont pas pris en charge.
</Warning>

### Méthodes de sélection

| Méthode             | Source de sélection       | Précision                   | Usage recommandé                            |
| ------------------- | ------------------------- | --------------------------- | ------------------------------------------- |
| `selection_regions` | Polygones du frontend     | Précise, trous compris      | Édition de calques ou pinceau en production |
| `boxes`             | Rectangles du frontend    | Approximation rectangulaire | Outil cadre ou MVP                          |
| `object_indices`    | Indices segment d'origine | Approximation rectangulaire | Test d'intégration rapide                   |

<Tabs>
  <Tab title="Polygone précis">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the selected car to bright red and preserve the rest",
      "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` peut être une liste plate ou des paires imbriquées. Chaque valeur doit être finie et dans `0–1` ; chaque anneau exige au moins 3 paires.
  </Tab>

  <Tab title="Cadre normalisé">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the car inside the box to bright red",
      "boxes": [[0.04, 0.385, 0.938, 0.594]]
    }
    ```
  </Tab>

  <Tab title="Cadre en pixels">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the car inside the box to bright red",
      "boxes": [[40, 689.6, 945.9, 1064.4]],
      "mask_size": [1792, 1008]
    }
    ```
  </Tab>

  <Tab title="Indice d'objet">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the selected car to bright red",
      "object_indices": [0]
    }
    ```

    Les indices doivent provenir de la réponse segment du même `image_id`. Ne les remplacez pas par ceux d'une liste frontend filtrée, triée ou groupée.
  </Tab>
</Tabs>

### Réponse terminée

```json theme={null}
{
  "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"
        }],
        "expires_at": 1787040000
      }]
    }
  }
}
```

Préférez `result.images[0].items[0]`. Pour une ancienne réponse, n'associez `url[0]` et `image_ids[0]` que si les tableaux ont la même longueur. Continuez uniquement après obtention d'une URL HTTP(S) et d'un nouveau `image_id`.

Utilisez `expires_at` comme référence d'expiration ; ne figez pas un nombre d'heures. Téléchargez ou conservez les assets nécessaires à long terme.

## Édition continue

À la fin d'une édition, mettez à jour ensemble l'URL affichée, l'ID d'asset actuel et l'ID de tâche source, puis effacez les anciens calques et états de polling.

* Segmenter à nouveau : utiliser l'ID de cette tâche `region_edit` comme `source_task_id`
* Modifier à nouveau : utiliser le nouveau `image_id` renvoyé
* Ne transmettez jamais `image_id` à `segment` et ne continuez jamais avec l'ancien ID d'image.

## Gestion des erreurs

| HTTP / statut                    | Cause fréquente                                                                          | Traitement                                                                                |
| -------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| 400 source ou opération invalide | Mauvaise opération, tâche source inutilisable ou `image_id/image_index` envoyé à segment | Valider l'opération et utiliser une tâche à image unique terminée de l'utilisateur actuel |
| 400 sélection invalide           | Prompt vide, sélection absente, polygone, cadre ou indice invalide                       | Valider le prompt et la sélection avant l'envoi                                           |
| 400 option non prise en charge   | `claim_asset`, `n`, format, taille ou streaming invalide                                 | Supprimer les champs non pris en charge et utiliser une sortie URL                        |
| 401 / 403                        | Clé invalide ou autorisation du modèle absente                                           | Vérifier la clé serveur et l'accès du compte                                              |
| 402                              | Solde insuffisant                                                                        | Demander un rechargement avant de réessayer                                               |
| 409                              | Requête idempotente en cours, modifiée ou indéterminée                                   | Suivre la réponse ; ne pas changer automatiquement de clé                                 |
| 429 / 5xx                        | Limitation ou panne temporaire                                                           | Respecter `Retry-After` et appliquer un backoff limité                                    |
| failed / task\_failed            | Échec de l'exécution asynchrone                                                          | Arrêter le polling et afficher `data.error.message`                                       |

## Facturation

* `segment` est gratuit et se termine avec `cost=0` et `credits_cost=0`, mais exige une authentification et une tâche source valide.
* `region_edit` est payant. Utilisez `cost` et `credits_cost` de la tâche terminée ; ne figez pas les prix dans le frontend.
* N'envoyez jamais le champ interne `billing_model_name`.

## Liste de contrôle frontend

* Conserver la clé API uniquement dans le backend ou BFF.
* Envoyer uniquement `source_task_id` à `segment`, jamais `image_id` ou `image_index`.
* Utiliser le `image_id` de segment pour `region_edit` avec au moins une méthode de sélection.
* Utiliser `selection_regions` pour l'édition précise ; `object_indices` n'est qu'une approximation rectangulaire.
* Toujours lire `mask_size` comme `[height,width]` et gérer mise à l'échelle et marges.
* Réutiliser la clé idempotente d'origine pour le même retry et valider l'URL ainsi que le nouveau `image_id`.
