HiAPI
블로그

튜토리얼

HiAPI API에서 muse-image-1.0/image-to-image를 호출하는 방법: curl, Python 및 실제로 동작하는 요청 예시

Oct 31, 2026
奶油色底上的多层薄纸叠层插画,一块陶红色纸层作点缀,构图克制均衡,为教程文章封面图。

이미지-투-이미지(image-to-image) 요청은 실제로 무엇을 보내는가

첫 줄의 코드를 작성하기 전에 이미지-투-이미지 호출이 무엇을 기대하는지 먼저 파악해 두면 도움이 됩니다. 순수 텍스트-투-이미지 요청에서 프롬프트가 유일한 창의적 입력인 것과 달리, muse-image-1.0/image-to-image는 원본 이미지와 그것을 어떻게 변환할지에 대한 지시가 필요합니다.

최소한 요청 페이로드에는 다음이 포함됩니다:

  • model: 식별자 muse-image-1.0/image-to-image.
  • image: 편집하려는 원본 이미지. 일반적으로 base64 인코딩 문자열 또는 공개적으로 접근 가능한 URL로 전송되며, 엔드포인트가 허용하는 형식에 따라 다릅니다. 모델의 입력 스키마를 확인하여 정확한 필드 이름과 형식을 확인하세요.
  • prompt: 수행하려는 편집에 대한 텍스트 설명. 무엇을 바꿀지, 무엇을 유지할지 구체적으로 명시하세요.
  • strength나 guidance 같은 선택적 매개변수(모델이 노출하는 경우)를 통해 출력이 원본 이미지에서 얼마나 벗어날지 제어할 수 있습니다. 정확한 매개변수 집합은 모델마다 다르므로 추측하지 말고 API 참조에서 확인하세요.

핵심적인 사고 전환은 이렇습니다: 처음부터 생성하는 것이 아니라 시작점과 방향을 제공하는 것입니다. "make it better" 같은 모호한 프롬프트는 모델에 너무 많은 자유를 주기 때문에 예측할 수 없는 결과를 낳습니다. 반면 "replace the sky with a sunset and keep the buildings unchanged" 같은 프롬프트는 모델에 명확한 제약을 줍니다.

또한 이미지 제약 사항을 미리 확인하세요—지원 형식, 최대 크기, 파일 크기 등. 원본 이미지가 12 MB PNG라면 요청이 수락되기 전에 다운샘플링하거나 JPEG로 변환해야 할 수 있습니다. 전송 전에 이미지를 올바르게 처리하면 왕복 한 번과 혼란스러운 오류 메시지를 절약할 수 있습니다.

원본 이미지와 명확한 편집 프롬프트가 준비되면 첫 번째 호출을 할 수 있습니다.

curl로 첫 번째 요청 보내기

통합을 검증하는 가장 빠른 방법은 터미널에서 직접 요청을 보내는 것입니다. 정확한 엔드포인트 경로와 페이로드 스키마는 모델의 API 참조에 정의되어 있으며, 아래 예시는 현재 사양에 맞게 조정할 수 있도록 일반적인 형태를 보여줍니다.

curl -X POST https://api.hiapi.ai/v1/images/edits \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "muse-image-1.0/image-to-image",
    "image": "https://your-bucket.example.com/source.jpg",
    "prompt": "replace the sky with a warm sunset, keep the buildings unchanged",
    "strength": 0.6
  }'

키를 직접 붙여넣지 말고 $HIAPI_API_KEY를 환경 변수로 대체하세요. 도구가 지원한다면 셸 세션에 키를 내보내 명령 기록에 남지 않게 하세요.

반환되는 응답에는 작업 식별자가 포함됩니다. 이미지 편집은 계산 집약적이므로 API는 보통 완성된 이미지를 같은 응답에서 반환하지 않습니다. 대신 작업 ID와 상태를 받게 됩니다. 해당 ID를 저장하세요—다음 단계에서 결과를 폴링하는 데 사용합니다.

호출이 실패하면 오류 응답 본문을 주의 깊게 읽으세요. 400은 일반적으로 페이로드 형식이 잘못되었거나 지원되지 않는 이미지 형식을 의미합니다. 401은 키가 없거나 잘못되었음을 의미합니다. 429는 요청을 너무 빠르게 보냈다는 뜻입니다. 터미널 단계에서 이런 문제를 해결하는 것이 전체 애플리케이션에서 디버깅하는 것보다 훨씬 쉽습니다.

같은 요청을 Python으로 구현하기

curl 호출이 성공하면 이를 작은 Python 함수로 변환하세요. requests를 사용하면 예시의 의존성을 적게 유지하고 이식하기 쉬워집니다.

import os
import requests

HIAPI_API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1/images/edits"

def submit_edit(image_url: str, prompt: str, strength: float = 0.6) -> str:
    payload = {
        "model": "muse-image-1.0/image-to-image",
        "image": image_url,
        "prompt": prompt,
        "strength": strength,
    }
    headers = {
        "Authorization": f"Bearer {HIAPI_API_KEY}",
        "Content-Type": "application/json",
    }
    response = requests.post(BASE_URL, json=payload, headers=headers, timeout=30)
    response.raise_for_status()
    data = response.json()
    return data["id"]

이 함수에 대한 몇 가지 설명:

  • timeout 매개변수는 네트워크가 정체될 때 스크립트가 무한정 멈추는 것을 방지합니다. 제출 호출의 경우 30초면 충분히 넉넉하지만 필요에 따라 조정할 수 있습니다.
  • raise_for_status()는 HTTP 오류를 예외로 변환하여 한 곳에서 잡을 수 있게 합니다.
  • 작업 ID만 반환하면 함수가 집중된 상태를 유지합니다. 폴링 로직은 별도 함수에 두어야 합니다.

원본 이미지를 URL이 아닌 바이트로 전송하려면 파일을 읽고 base64로 인코딩한 뒤 결과를 image 필드에 넣으세요. 전환하기 전에 문서에서 기대하는 형식을 확인하세요. 두 인코딩이 항상 서로 교환 가능한 것은 아닙니다.

이 함수는 의도적으로 최소한으로 유지됩니다. 실제 서비스에서는 로깅, 재시도 처리, 타입 검증을 추가하겠지만 핵심 요청 패턴은 여기서 보는 것과 같습니다.

비동기 작업 처리 및 결과 폴링

이미지 편집에는 시간이 걸립니다—프롬프트와 해상도에 따라 보통 몇 초에서 수십 초까지 걸립니다. API는 요청을 수락하고 작업 ID를 반환한 뒤 백그라운드에서 작업을 처리합니다. 당신의 임무는 상태가 종료 상태에 도달할 때까지 반복적으로 확인하는 것입니다.

폴링은 간단해 보이지만 100밀리초마다 실행되는 순진한 루프는 할당량을 낭비하고 속도 제한을 유발할 수 있습니다. 합리적인 간격과 재시도 상한을 사용하세요:

import time
import requests

def poll_job(job_id: str, interval: float = 2.0, max_attempts: int = 30) -> dict:
    url = f"https://api.hiapi.ai/v1/jobs/{job_id}"
    headers = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
    for attempt in range(max_attempts):
        response = requests.get(url, headers=headers, timeout=15)
        response.raise_for_status()
        data = response.json()
        status = data["status"]
        if status == "succeeded":
            return data
        if status == "failed":
            raise RuntimeError(data.get("error", "job failed"))
        time.sleep(interval)
    raise TimeoutError(f"job {job_id} did not finish after {max_attempts} attempts")

2초 간격은 합리적인 시작점입니다. 작업이 보통 5초 이내에 완료된다면 처음에 더 자주 폴링한 뒤 점차 간격을 늘릴 수 있습니다. 작업이 보통 더 오래 걸린다면 불필요한 호출을 피하기 위해 폴링 빈도를 낮추세요.

재시도 상한은 안전망입니다. 이것이 없으면 멈춘 작업이 무한 루프에 빠질 수 있습니다. 상한에 도달하면 명확한 오류를 발생시켜 호출자가 작업이 타임아웃되었음을 알 수 있게 하고, 조용히 멈추지 않게 하세요.

프로덕션 환경에서는 폴링을 백그라운드 워커나 큐로 옮겨 요청 처리 스레드가 이미지 렌더링이 끝날 때까지 차단되지 않게 하는 것을 고려하세요.

출력 이미지 다운로드 및 저장

작업이 succeeded 상태에 도달하면 응답에는 하나 이상의 출력 이미지가 포함되며, 보통 URL 형태로 제공됩니다. 다음 단계는 이미지를 다운로드하여 영구 저장하는 것입니다.

def download_image(result: dict, dest_path: str) -> None:
    image_url = result["output"][0]["url"]
    response = requests.get(image_url, timeout=30)
    response.raise_for_status()
    with open(dest_path, "wb") as f:
        f.write(response.content)

몇 가지 실용적인 고려 사항:

  • 출력 URL은 일시적일 수 있습니다. 수명이 짧은 리소스로 취급하고 URL을 유일한 참조로 저장하지 말고 제때 다운로드하세요.
  • 파일을 바이너리 모드로 작성하세요. 이미지 응답은 텍스트가 아닙니다. "w"로 열면 데이터가 손상됩니다.
  • 성공을 선언하기 전에 파일이 비어 있지 않은지 확인하세요. 0바이트 다운로드는 보통 URL이 만료되었거나 요청이 차단되었음을 의미합니다.

로컬 스크립트 외의 모든 시나리오에서는 먼저 디스크에 저장하지 말고 다운로드를 스토리지 제공자로 직접 스트리밍하세요. 대부분의 객체 스토리지 SDK는 파일 유사 객체나 바이트 스트림을 허용하므로 response.raw 또는 response.content를 중간 파일 없이 업로드 호출로 파이프할 수 있습니다.

마지막으로 작업 ID를 저장된 객체와 함께 기록하세요. 나중에 출력이 손상되거나 특정 편집을 재현해야 하는 경우 작업 ID와 원본 입력으로 무엇을 보냈는지 추적할 수 있습니다.

흔한 실패 지점과 해결 방법

대부분의 통합 문제는 몇 가지 범주에 속합니다. 각각을 진단하는 방법은 다음과 같습니다.

작업 생성 전에 요청이 거부됨

제출 시 400 오류는 보통 페이로드 오류를 의미합니다. model이 정확히 muse-image-1.0/image-to-image인지, image가 접근 가능하거나 base64로 올바르게 인코딩되었는지, prompt가 비어 있지 않은 문자열인지 확인하세요. 이미지가 URL이라면 공개적으로 접근 가능한지 확인하세요—비공개 버킷이나 만료된 서명 URL은 검증을 통과하지 못합니다.

처리 중 작업이 실패함

폴링이 failed 상태를 반환하면 응답 본문의 오류 메시지를 읽으세요. 일반적인 원인으로는 이미지가 너무 큼, 프롬프트가 콘텐츠 정책을 위반함, 매개변수 값이 허용 범위를 벗어남 등이 있습니다. 이미지 크기를 줄이고 프롬프트를 단순화하여 원인을 분리하세요.

폴링 타임아웃

종료 상태 없이 재시도 상한에 도달하면 작업이 실제로 더 오래 걸릴 수도 있고 멈췄을 수도 있습니다. 먼저 max_attempts를 늘리고 API 참조에서 일반적인 처리 시간을 확인하세요. 작업이 계속 타임아웃되면 원본 이미지가 비정상적으로 큰지 확인하세요. 재시도 상한을 단순히 제거하지 마세요—제한된 재시도는 조용한 무한 루프를 방지합니다.

속도 제한

429 응답은 요청을 너무 빠르게 보냈다는 뜻입니다. 백오프하고 retry-after 헤더를 준수하며 동시 제출을 분산하세요. 이미지 배치를 처리하는 경우 한 번에 모두 보내지 말고 순차적으로 처리하거나 동시성 제한을 더 작게 설정하세요.

출력 누락 또는 잘림

작업이 성공했지만 다운로드한 파일이 비어 있다면 폴링과 다운로드 사이에 출력 URL이 만료되었을 수 있습니다. 성공한 직후 다운로드하세요. 이미지가 손상되었다면 바이너리 모드로 작성했는지, 스트림에 텍스트 인코딩을 적용하지 않았는지 확인하세요.

요청 페이로드, 작업 ID, 상태 전환을 기록하면 디버깅이 더 쉬워집니다. 이 세 가지 정보만 있으면 거의 모든 실패를 원점까지 추적할 수 있습니다.

요청 형태, curl 및 Python 패턴, 폴링 로직, 다운로드 단계를 갖추었으므로 HiAPI API에서 muse-image-1.0/image-to-image를 사용하는 동작하는 파이프라인을 갖게 되었습니다. 터미널 예시에서 시작하여 스크립트로 옮기고, 정상 경로가 안정되면 재시도와 로깅을 추가하세요.

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

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

API 문서 보기