HiAPI
블로그

튜토리얼

API로 이미지 배경 제거하기: 프롬프트 기반 편집

hiapi에서 이미지-투-이미지 모델로 이미지 배경을 교체하거나 제거하는 방법 — 최소한의 코드, 배치 모드, 그리고 제품 사진 구도를 정확하게 유지하는 스키마 세부 사항.

Aug 6, 2026
API로 이미지 배경 제거하기: 프롬프트 기반 편집

기존 배경 제거 도구는 단 하나의 작업만 제공합니다. 피사체를 오려내고 투명 영역(또는 단색 채우기)을 남기는 것입니다. 반면 프롬프트 기반 배경 제거는 이미지-투-이미지 모델을 사용해 한 번의 호출로 누끼 결과와 교체된 배경을 동시에 얻을 수 있습니다 — 매끄러운 흰색 스튜디오 배경, 라이프스타일 장면, 브랜드 단색 — 모델이 단순히 알파 마스크를 계산하는 것이 아니라 보존된 피사체 주변의 배경을 픽셀 단위로 다시 생성하기 때문입니다.

이 가이드는 hiapi에서 이를 정확히 수행하는 방법을 보여줍니다. 어떤 이미지-투-이미지 모델이 배경 제거에 실제로 뛰어난지, 이에 맞춰 코딩해야 하는 요청/응답 구조, 그리고 배치 작업이 제품 카탈로그를 조용히 오염시키지 않도록 하는 프로덕션 패턴(콜백, 재시도, 오류 처리)입니다.

사전 준비:

  • 대시보드에서 hiapi API 키 발급
  • Python 3.9+ 및 requests 설치(pip install requests)
  • 원본 이미지가 공개 URL에 호스팅되어 있어야 합니다 — hiapi의 작업 API는 파일 업로드가 아니라 URL로 이미지를 가져오므로 로컬 파일 경로는 사용할 수 없습니다. 객체 스토리지나 CDN이면 모두 가능합니다.

이미지-투-이미지 작업으로서의 배경 제거 작동 방식

hiapi의 모든 생성(이미지, 비디오, 오디오)은 동일한 비동기 작업 수명 주기를 따릅니다. 작업을 제출하고 taskId를 받은 다음, 결과를 폴링하거나 콜백 URL로 수신합니다. 전체 계약은 비동기 작업 API 레퍼런스를 참고하세요. 배경 제거에서 중요한 부분은 다음과 같습니다:

  1. model + input(프롬프트, 원본 이미지 URL, 출력 형태)을 담은 POST /v1/tasks는 {"code":200,"data":{"taskId":"tk-hiapi-..."}}를 반환합니다. 이 시점에는 아직 status 필드가 없습니다.
  2. GET /v1/tasks/{taskId}는 data.status를 반환하며, 값은 queued, handling, archiving, success, fail 중 하나입니다. success와 fail만 종료 상태입니다.
  3. 상태가 success일 때 data.output은 {"url","type","expireAt"} 배열입니다. url은 서명된 단기 링크입니다(expireAt은 Unix 타임스탬프). 즉시 다운로드하고 이 핫링크를 저장하지 마세요.

모델은 이미지-투-이미지 엔드포인트를 사용하고, 프롬프트는 단순히 "배경 제거"라고 말하지 말고 교체된 배경을 묘사하세요 — 이 모델들은 부정형 지시보다 구체적인 목표에 훨씬 잘 반응합니다:

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.

최소 예제: 이미지 하나 입력, 배경 교체

seedream-5.0-lite/image-to-image는 이 용도에서 가장 저렴하면서 충분한 옵션입니다 — prompt, image_urls, aspect_ratio, resolution(2K 또는 4K만 지원, 이 엔드포인트에는 1K 옵션이 없으며 n이나 seed 같은 알 수 없는 필드는 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)

이것이 전체 루프입니다: 제출, 폴링, 다운로드. 파이프라인에 연결하기 전에 코드 없이 빠르게 검증하려면 AI 제품 사진 랩에서 동일한 유형의 배경 교체를 브라우저에서 실행할 수 있습니다.

제품 카탈로그 배치 처리

실제 제품 카탈로그에는 수십 또는 수백 장의 이미지가 있으며, 작업 API에는 기본 배치 엔드포인트가 없습니다 — 개별 작업 제출을 직접 확장하고 동시에 폴링해야 합니다:

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}")

max_workers는 적절히 유지하세요 — 많은 동시 작업을 너무 자주 폴링하면 요청 할당량만 소모할 뿐 생성 속도는 빨라지지 않습니다. 각 작업의 실제 소요 시간은 폴링 빈도가 아니라 주로 모델 추론에 의해 결정되기 때문입니다.

프로덕션 환경 강화: 정확한 구도, 콜백, 멱등성, 오류

정확한 제품 구도를 유지하세요. 카탈로그 작업에서는 모델이 구도를 바꾸거나 피사체를 약간 잘라내는 것을 용납할 수 없는 경우가 많습니다 — 입력에서 중앙에 위치한 신발은 출력에서도 중앙에 있어야 합니다. seedream-5.0-pro/image-to-image는 라이트 티어가 지원하지 않는 aspect_ratio 값 match_input_image를 지원합니다. 이는 출력 캔버스를 입력 이미지 자체의 크기로 고정하고 고정 비율로 강제하지 않습니다. 또한 호출당 최대 10개의 image_urls를 받고 resolution을 1K/2K로 제한합니다(라이트와 다른 해상도 집합 — seedream 엔드포인트마다 스키마가 일관되다고 가정하지 마세요. 각 엔드포인트에는 고유한 열거형이 있습니다). 구도가 정확히 일치해야 하는 순수 배경 제거 및 교체 작업에는 이 티어를 선택해야 하며, 이미지당 비용이 더 높습니다 — 현재 요율은 가격을 참고하세요.

호출당 한 장의 이미지가 아니라 여러 소스 각도(예: 동일 제품의 정면도와 측면도)를 한 번에 참조해야 한다면 nano-banana-2가 합리적인 대안입니다 — image_urls가 아닌 image_input으로 참조 이미지를 받으며, resolution은 1K/2K/4K를 사용할 수 있습니다.

폴링 대신 콜백을 사용하세요. 실질적인 규모의 배치 작업에는 웹훅이 폴링보다 낫습니다. input과 같은 레벨로 callback 객체를 추가하세요 — 그 안에 중첩하지 마세요. POST /v1/tasks는 그런 구조를 거부합니다:

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)

작업이 종료 상태에 도달하면 hiapi는 콜백 URL로 GET /v1/tasks/{taskId}가 반환할 것과 동일한 data 객체를 POST합니다. 서버 측에서 콜백 진위를 검증하려면 비동기 작업 레퍼런스의 선택적 X-HiAPI-Signature HMAC 헤더를 참고하세요.

멱등성. POST /v1/tasks에는 문서화된 idempotency_key 필드가 없습니다 — 멱등성은 애플리케이션 계층에서 구현하세요. 작은 저장소(데이터베이스 행, Redis 키, 또는 일회성 스크립트의 로컬 파일)를 사용해 (image_url, prompt, model)의 해시를 키로 삼고, 새 작업을 제출하기 전에 해당 키에 저장된 taskId나 출력 URL이 있는지 확인하세요. 배치 작업이 중간에 중단되어 다시 실행되면 이미 처리한 이미지에 대한 중복 과금을 건너뛸 수 있어 비용이 조용히 늘어나는 일을 막습니다.

오류 처리 — 세 가지 서로 다른 형태를 동일하게 다루지 마세요:

  • 요청 유효성 검사(생성 시 잘못된 입력) — HTTP 400, 평면 구조: {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}. 이는 input 딕셔너리가 모델 스키마와 일치하지 않음을 의미합니다 — 필드명 오타나 잘못된 열거형 값을 확인하세요.
  • 인증 실패 — HTTP 401, 중첩 방식이 다름: {"error":{"code":"permission_denied","message":"...","request_id":"...","type":"hiapi_error"}}. API 키 누락/만료이지 요청 오류가 아닙니다 — 재시도하지 말고 키를 수정하세요.
  • 작업 수준 실패(요청은 유효하지만 생성 자체가 실패) — 폴링할 때 나타남: data.status == "fail", data.error가 실패 원인을 설명. 이는 재시도 가능합니다. 일시적인 업스트림 오류는 다시 제출하면 성공할 수 있습니다.
if task["status"] == "fail":
    err = task.get("error") or {}
    # log err["code"] / err["message"], then decide: retry, skip, or alert

세 가지를 모두 하나의 except Exception으로 묶지 마세요 — 루프에서 401을 재시도하면 속도 제한만 소모하고 절대 성공하지 않으며, 작업 수준 fail은 두 번째 시도에서 성공할 수도 있습니다.

다음 단계

자주 묻는 질문

이것은 정말로 배경을 제거하나요, 아니면 덮어쓰기만 하나요? 기능적으로는 둘 다입니다 — 모델이 보존된 피사체 주변의 전체 캔버스를 다시 생성하므로 에지 감지 누끼 도구처럼 잔여 마스크나 거친 가장자리가 남지 않습니다. 대가는 프롬프트에서 "다른 모든 것은 그대로 유지"라고 명확히 지정해야 한다는 점입니다. 그렇지 않으면 모델이 피사체까지 함께 재스타일링하는 것을 즐기기 때문입니다.

단색 배경 대신 투명 PNG를 얻을 수 있나요? 프롬프트에서 직접 요청하세요(예: "배경을 투명으로 교체" 또는 "투명 배경에 피사체 분리"). 그리고 모델이 output_format 필드를 지원하는 곳에서는 PNG 출력을 요청하세요 — 지원 여부는 모델마다 다르므로 사용 가능하다고 가정하기 전에 해당 모델 페이지를 확인하세요.

왜 내 이미지가 원본과 일치하지 않고 재구성되어 돌아오나요? 아마도 aspect_ratio 열거형에 match_input_image가 없는 티어를 사용하고 있을 것입니다 — 라이트/4.5 티어에서는 고정 비율을 선택하게 되며, 소스 이미지에 비해 자르거나 레터박스가 생길 수 있습니다. seedream-5.0-pro/image-to-image로 전환하고 aspect_ratio를 match_input_image로 설정하세요.

이미지당 비용은 얼마인가요? 가격은 모델과 해상도 티어에 따라 다르며 시간이 지나면 변합니다 — 자체 코드나 문서에 숫자를 하드코딩하지 말고 가격을 확인하세요.

내 이미지 URL이 아직 공개되지 않았다면 어떻게 해야 하나요? 작업 API는 서버 측에서 URL로 이미지를 가져오므로 인증 없이 접근 가능해야 합니다. 먼저 공개 버킷이나 CDN 경로에 업로드하세요 — 서명된/비공개 URL이나 localhost 경로는 작업 생성 시 실패하거나 (더 나쁘게) 처리 중에 조용히 실패합니다.

영구 AI 아티팩트로 빌드 시작하기

API 키를 받아 태스크 기반의 하나의 API로 이미지, 비디오, 오디오 모델을 호출하세요.

API 문서 보기