HiAPI
Blog

Tutoriel

Supprimer l'arrière-plan d'une image via l'API : édition par prompt

Comment remplacer ou supprimer l'arrière-plan d'une image avec les modèles image-vers-image sur hiapi — un minimum de code, le mode lot, et les détails de schéma qui rendent la composition de vos photos produit parfaitement fidèle.

Aug 6, 2026
Supprimer l'arrière-plan d'une image via l'API : édition par prompt

Les outils classiques de suppression d'arrière-plan n'offrent qu'une seule opération : détourer le sujet et laisser une zone transparente (ou un remplissage uni). Avec la suppression d'arrière-plan par prompt via un modèle image-vers-image, vous obtenez en un seul appel à la fois le détourage et l'arrière-plan de remplacement — fond de studio blanc sans raccord, scène de vie, couleur de marque unie — car le modèle régénère l'arrière-plan pixel par pixel autour du sujet conservé, au lieu de simplement calculer un masque alpha.

Ce guide montre précisément comment y parvenir sur hiapi : quels modèles image-vers-image excellent réellement en suppression d'arrière-plan, la structure requête/réponse sur laquelle coder, et les patrons de production (callbacks, nouvelles tentatives, gestion des erreurs) qui empêchent vos tâches en lot de polluer silencieusement votre catalogue produit.

Prérequis :

  • Obtenir une clé API hiapi depuis votre tableau de bord
  • Python 3.9+ avec requests installé (pip install requests)
  • Vos images sources hébergées sur une URL publique — l'API de tâches hiapi récupère les images par URL, pas par upload de fichier, donc les chemins de fichiers locaux ne fonctionnent pas. N'importe quel stockage objet ou CDN convient.

Fonctionnement de la suppression d'arrière-plan en tant que tâche image-vers-image

Chaque génération sur hiapi — image, vidéo ou audio — suit le même cycle de vie de tâche asynchrone : vous soumettez une tâche, recevez un taskId, puis soit interrogez le résultat, soit le recevez via une URL de callback. Le contrat complet figure dans la référence de l'API de tâches asynchrones ; pour la suppression d'arrière-plan, l'essentiel est le suivant :

  1. Un POST /v1/tasks avec model + input (votre prompt, l'URL de l'image source et la forme de sortie) renvoie {"code":200,"data":{"taskId":"tk-hiapi-..."}}. Il n'y a pas encore de champ status à ce stade.
  2. GET /v1/tasks/{taskId} renvoie data.status, qui vaut queued, handling, archiving, success ou fail. Seuls success et fail sont des états terminaux.
  3. En cas de success, data.output est un tableau de {"url","type","expireAt"}. url est un lien signé à durée courte (expireAt est un horodatage Unix) — téléchargez immédiatement, ne stockez pas ce lien à chaud.

Côté modèle, utilisez le point d'accès image-vers-image et faites décrire par le prompt l'arrière-plan de remplacement, plutôt que de dire isolément « supprimer l'arrière-plan » — ces modèles répondent bien mieux à une cible concrète qu'à une consigne négative :

Remove the background completely and replace it with a seamless, pure white
studio background. Keep the subject's shape, edges, lighting, and colors
exactly unchanged. Do not add shadows, reflections, or any other objects
that were not in the original image.

Exemple minimal : une image en entrée, arrière-plan remplacé

seedream-5.0-lite/image-to-image est l'option la moins chère et suffisante pour cet usage — il accepte prompt, image_urls, aspect_ratio et resolution (uniquement 2K ou 4K ; ce point d'accès n'a pas de palier 1K, et les champs inconnus comme n ou seed sont purement rejetés avec un 400).

import os
import time
import requests

API = "https://api.hiapi.ai/v1"
HEADERS = {
    "Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
    "Content-Type": "application/json",
}

BACKGROUND_PROMPT = (
    "Remove the background completely and replace it with a seamless, pure "
    "white studio background. Keep the subject's shape, edges, lighting, and "
    "colors exactly unchanged. Do not add shadows, reflections, or any other "
    "objects that were not in the original image."
)

def create_task(model: str, task_input: dict) -> str:
    resp = requests.post(f"{API}/tasks", headers=HEADERS,
                          json={"model": model, "input": task_input}, timeout=60)
    resp.raise_for_status()
    return resp.json()["data"]["taskId"]

def wait_task(task_id: str, timeout_s: int = 180, poll_s: int = 3) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        resp = requests.get(f"{API}/tasks/{task_id}", headers=HEADERS, timeout=30)
        resp.raise_for_status()
        task = resp.json()["data"]
        if task["status"] == "success":
            return task
        if task["status"] == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task {task_id} failed: {err.get('code')} {err.get('message')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} still {task['status']} after {timeout_s}s")

task_id = create_task("seedream-5.0-lite/image-to-image", {
    "prompt": BACKGROUND_PROMPT,
    "image_urls": ["https://your-cdn.example.com/product-photo.jpg"],
    "aspect_ratio": "1:1",
    "resolution": "2K",
})
task = wait_task(task_id)
image_bytes = requests.get(task["output"][0]["url"], timeout=60).content

with open("product-no-bg.png", "wb") as f:
    f.write(image_bytes)

C'est tout le cycle : soumettre, interroger, télécharger. Pour une validation rapide sans code avant de l'intégrer à votre pipeline, le laboratoire de photos produit IA exécute le même type de remplacement d'arrière-plan dans le navigateur.

Traitement par lot d'un catalogue produit

Un vrai catalogue produit compte des dizaines ou des centaines d'images, et l'API de tâches n'a pas de point d'accès par lot natif — vous devez vous-même dérouler les soumissions individuelles et les interroger en parallèle :

from concurrent.futures import ThreadPoolExecutor, as_completed

def remove_background(image_url: str, aspect_ratio: str = "1:1") -> str:
    task_id = create_task("seedream-5.0-lite/image-to-image", {
        "prompt": BACKGROUND_PROMPT,
        "image_urls": [image_url],
        "aspect_ratio": aspect_ratio,
        "resolution": "2K",
    })
    task = wait_task(task_id)
    return task["output"][0]["url"]

source_urls = [
    "https://your-cdn.example.com/sku-1001.jpg",
    "https://your-cdn.example.com/sku-1002.jpg",
    # ...
]

results = {}
with ThreadPoolExecutor(max_workers=5) as pool:
    futures = {pool.submit(remove_background, url): url for url in source_urls}
    for future in as_completed(futures):
        url = futures[future]
        try:
            results[url] = future.result()
        except Exception as exc:
            results[url] = None
            print(f"failed: {url}: {exc}")

Gardez max_workers modéré — interroger trop fréquemment un grand nombre de tâches concurrentes ne fait que consommer votre quota de requêtes sans accélérer la génération, car le temps réel de chaque tâche dépend principalement de l'inférence du modèle, pas de votre fréquence d'interrogation.

Durcissement en production : composition précise, callbacks, idempotence, erreurs

Préserver la composition exacte du produit. Pour un travail de catalogue, vous ne pouvez généralement pas tolérer que le modèle recompose ou recadre légèrement le sujet — une chaussure centrée en entrée doit rester centrée en sortie. seedream-5.0-pro/image-to-image prend en charge une valeur d'aspect_ratio que le palier lite ne propose pas : match_input_image, qui verrouille le canevas de sortie sur les dimensions propres de l'image d'entrée au lieu d'imposer un ratio fixe. Il accepte aussi jusqu'à 10 image_urls par appel et limite resolution à 1K/2K (un jeu de résolutions différent du lite — ne présumez pas que les schémas des points d'accès seedream sont identiques, chacun a ses propres énumérations). Pour un travail de pure suppression et remplacement d'arrière-plan où la composition doit correspondre exactement, c'est le palier à choisir, plus coûteux par image — consultez la tarification pour les tarifs actuels.

Si vous devez référencer plusieurs angles sources à la fois (par exemple une vue de face et une vue de côté du même produit), au lieu de traiter une image par appel, nano-banana-2 est une alternative raisonnable — il accepte les images de référence via image_input (et non image_urls), avec en plus resolution pouvant valoir 1K/2K/4K.

Utiliser des callbacks plutôt que l'interrogation. Pour toute tâche en lot à échelle réelle, le webhook est préférable à l'interrogation : ajoutez un objet callback au même niveau que input — pas imbriqué à l'intérieur, POST /v1/tasks rejetterait cette structure :

task_input = {
    "prompt": BACKGROUND_PROMPT,
    "image_urls": [image_url],
    "aspect_ratio": "1:1",
    "resolution": "2K",
}
resp = requests.post(f"{API}/tasks", headers=HEADERS, json={
    "model": "seedream-5.0-lite/image-to-image",
    "input": task_input,
    "callback": {"url": "https://your-service.example.com/hooks/hiapi", "when": "final"},
}, timeout=60)

Une fois la tâche dans un état terminal, hiapi envoie par POST à votre URL de callback le même objet data que celui renvoyé par GET /v1/tasks/{taskId}. Si vous souhaitez vérifier l'authenticité du callback côté serveur, reportez-vous à l'en-tête HMAC optionnel X-HiAPI-Signature décrit dans la référence des tâches asynchrones.

Idempotence. Il n'existe pas de champ idempotency_key documenté sur POST /v1/tasks — construisez l'idempotence au niveau de l'application. Avec un petit stockage (ligne de base de données, clé Redis, ou même fichier local pour un script ponctuel), utilisez comme clé le hachage de (image_url, prompt, model) et, avant de soumettre une nouvelle tâche, vérifiez si cette clé possède déjà un taskId ou une URL de sortie stockés. Si votre traitement par lot plante en cours de route et redémarre, vous éviterez la double facturation des images déjà traitées au lieu d'augmenter silencieusement les coûts.

Gestion des erreurs — trois formes distinctes, à ne pas traiter de la même façon :

  • Validation de la requête (entrée invalide à la création) — HTTP 400, structure plate : {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}. Cela signifie que votre dictionnaire input ne correspond pas au schéma du modèle — vérifiez les noms de champs mal orthographiés ou les valeurs d'énumération erronées.
  • Échec d'authentification — HTTP 401, imbriqué différemment : {"error":{"code":"permission_denied","message":"...","request_id":"...","type":"hiapi_error"}}. Clé API absente/expirée, et non requête erronée — ne réessayez pas, corrigez la clé.
  • Échec au niveau de la tâche (requête valide, mais la génération elle-même échoue) — apparaît lors de votre interrogation : data.status == "fail", data.error décrit la cause. C'est réessayable ; une erreur amont temporaire peut réussir après resoumission.
if task["status"] == "fail":
    err = task.get("error") or {}
    # log err["code"] / err["message"], then decide: retry, skip, or alert

Ne regroupez pas les trois dans un seul except Exception — réessayer un 401 en boucle ne fait que consommer votre limite de débit et ne réussira jamais, alors qu'un fail au niveau de la tâche peut effectivement réussir à la deuxième tentative.

Étapes suivantes

Questions fréquentes

Est-ce que cela supprime vraiment l'arrière-plan, ou ne fait-il que le recouvrir ? Fonctionnellement, les deux — le modèle régénère tout le canevas autour du sujet conservé, donc il ne laisse pas de masque résiduel ni de franges comme un outil de détourage par détection de contours. Le prix à payer est de préciser explicitement dans le prompt « garder tout le reste inchangé », sinon le modèle restylisera volontiers le sujet lui-même.

Puis-je obtenir un PNG transparent plutôt qu'un fond uni ? Demandez-le directement dans le prompt (par exemple « remplacer l'arrière-plan par du transparent » ou « isoler le sujet sur fond transparent »), et demandez une sortie PNG là où le modèle prend en charge le champ output_format — la prise en charge varie selon le modèle, donc vérifiez la page du modèle concerné avant de la présumer disponible.

Pourquoi mon image revient-elle recomposée au lieu de correspondre à l'originale ? Vous utilisez probablement un palier dont l'énumération aspect_ratio n'inclut pas match_input_image — dans les paliers lite/4.5, vous choisissez un ratio fixe qui peut recadrer ou ajouter des bandes noires par rapport à la source. Passez à seedream-5.0-pro/image-to-image et définissez aspect_ratio sur match_input_image.

Combien coûte chaque image ? La tarification varie selon le modèle et le palier de résolution, et évolue dans le temps — consultez la tarification plutôt que de coder en dur des chiffres dans votre propre code ou documentation.

Que faire si mon URL d'image n'est pas encore publique ? L'API de tâches récupère les images par URL côté serveur, elle doit donc être accessible sans authentification. Téléversez d'abord vers un bucket public ou un chemin de CDN quelconque — une URL signée/privée ou un chemin localhost échouera à la création de la tâche, ou (pire) échouera silencieusement pendant le traitement.

Articles similaires

Voir tous les articles →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API