Seedream 5.0 Pro API: Python으로 이미지 생성하기
model에 Dola-Seedream-5.0-pro를 넣어 POST 한 번이면 이미지 작업이 생성됩니다. 그대로 실행한 요청 코드, 사이즈와 라벨의 실제 동작, 2026년 10월 29일에 만든 이미지 2장을 정리했습니다.
이 페이지 목차
https://api.omniakey.com/v1/media/tasks로 POST를 한 번 보내고 model에 Dola-Seedream-5.0-pro, operation에 generate를 넣으면 이미지 작업이 생성됩니다. 돌아온 작업 id를 status가 succeeded가 될 때까지 폴링한 뒤 assets[0].url을 내려받습니다. 기본값에서는 이미지 모서리에 "AI generated" 라벨이 붙습니다. 2026년 10월 29일 이 요청과 1024x1024 편집을 한 번씩 실행했고, 두 파일 모두 1024×1024 PNG로 돌아왔습니다.
이어서 모델 id와 두 가지 작업, 그대로 실행한 요청 코드, 요청한 사이즈와 각 파일에서 읽은 픽셀 크기를 나란히 놓은 목록, 라벨과 라벨을 끄는 설정(실행하지 않음), create 호출을 막는 두 가지 오류를 다룹니다. 이미지 두 장은 모두 그날 만든 것입니다.
어떤 모델 id와 작업을 쓰나
Dola-Seedream-5.0-pro를 씁니다. Seedream 5.0 Pro 모델 페이지에 있는 id입니다(2026년 10월 29일 확인). 페이지에는 텍스트로 이미지 생성과 이미지 편집, 두 가지 작업이 적혀 있습니다. 생성과 편집은 같은 요금을 쓰고, 고른 사이즈나 첨부한 참조 이미지가 요금에 더해지지 않는다고도 설명합니다. 현재 요금은 요금 페이지에 있습니다.
프롬프트 앞에서 요청의 모양을 정하는 필드는 다음과 같습니다.
model:Dola-Seedream-5.0-prooperation:generate또는editparameters.size:1K,1.5K,2K, 또는 사이에 소문자x를 넣은widthxheightoutput_format:png또는jpeg, 기본값은jpeg
사이즈와 포맷 필드는 parameters 안에 들어갑니다. 출력은 2K에서 멈춥니다. 모델 페이지(2026년 10월 29일 확인)에 4K 사이즈는 없습니다. Seedream은 두 변 사이에 소문자 x를 쓰고 Qwen과 Wan은 별표를 쓰므로, 둘을 함께 호출하는 클라이언트에서는 두 형식을 구분해야 합니다. 실행한 두 번은 모두 widthxheight 형식의 1024x1024와 PNG를 썼고, 1K·1.5K·2K 세 단계는 쓰지 않았습니다.
ByteDance는 같은 모델을 BytePlus ModelArk에서 다른 id dola-seedream-5-0-pro-260628로 팝니다. 그것은 BytePlus 쪽 id이므로 OmniaKey로 보내는 요청에는 위의 id를 써야 합니다.
요청 코드
아래 스크립트는 2026년 10월 29일에 실행한 그대로입니다. 헬퍼 두 개, 생성 호출 한 번, 편집 호출 한 번이고 Python 표준 라이브러리만 씁니다. 키는 OMNIAKEY_API_KEY에서 읽고 PNG는 스크립트를 실행한 폴더에 씁니다. 이미지 API 문서에도 같은 세 단계가 설명되어 있습니다.
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "Dola-Seedream-5.0-pro"
def request(method, url, body=None, extra_headers=None):
headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
data = None
if body is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(body).encode()
headers.update(extra_headers or {})
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def poll(url, attempts=5):
for attempt in range(attempts):
try:
return request("GET", url)
except urllib.error.HTTPError as err:
if err.code < 500 or attempt == attempts - 1:
raise
except urllib.error.URLError:
if attempt == attempts - 1:
raise
time.sleep(5 * (attempt + 1))
def run_task(body, out_path):
task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
print("task", task, flush=True)
for _ in range(150):
time.sleep(4)
state = poll(f"{API}/{task}")
if state["status"] not in ("queued", "processing"):
break
if state["status"] != "succeeded":
raise RuntimeError(state.get("error") or state["status"])
asset_url = state["assets"][0]["url"] # signed link: short-lived, so download now
req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
with urllib.request.urlopen(req, timeout=120) as resp, open(out_path, "wb") as f:
f.write(resp.read())
return task
def generate_image(prompt, out_path, size="1024x1024"):
body = {
"model": MODEL,
"type": "image",
"operation": "generate",
"input": {"prompt": prompt},
"parameters": {"size": size, "output_format": "png"},
}
return run_task(body, out_path)
def edit_image(source_path, prompt, out_path, size="1024x1024"):
with open(source_path, "rb") as f:
image = base64.b64encode(f.read()).decode()
body = {
"model": MODEL,
"type": "image",
"operation": "edit",
"input": {"prompt": prompt, "image": {"data": image, "mime_type": "image/jpeg"}},
"parameters": {"size": size, "output_format": "png"},
}
return run_task(body, out_path)
if __name__ == "__main__":
task = generate_image(
"A glass bottle of cold-pressed orange juice on a pale stone counter, morning light from the left, "
"a single orange slice beside it, shallow depth of field, no text, no logos.",
"juice-bottle.png",
)
print("generate task", task)
task = edit_image(
"cafe-base.jpg",
"Change the red bicycle to matte black. Keep everything else exactly the same: "
"the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos.",
"cafe-edited.png",
)
print("edit task", task)
세 단계는 모두 run_task 안에 있습니다. 새 멱등성 키로 작업을 만들고, status가 queued와 processing을 벗어날 때까지 작업 URL을 폴링한 다음, 첫 번째 asset URL을 내려받습니다. create 호출은 task_로 시작하는 id와 함께 HTTP 202를 돌려주고, status는 queued에서 시작합니다(문서, 2026년 10월 29일 확인). failed가 된 작업은 응답의 오류를 그대로 던지므로 이유가 터미널에 나옵니다.
실행한 사이즈와 포맷, 돌아온 파일
두 번의 실행은 같은 사이즈 문자열과 같은 포맷을 요청했고, 두 파일 모두 1024×1024 PNG로 돌아왔습니다.
- 생성 — 요청한 사이즈:
1024x1024; 파일의 픽셀: 1024×1024; 포맷: PNG; 날짜: 2026-10-29 - 편집 — 요청한 사이즈:
1024x1024; 파일의 픽셀: 1024×1024; 포맷: PNG; 날짜: 2026-10-29
픽셀 크기는 내려받은 파일에서 읽어야 합니다. 사이즈 문자열은 요청한 값이고, 파일이 실제로 받은 결과입니다. PNG마다 파일을 열어 너비와 높이를 재고, 그 이미지를 만든 프롬프트와 함께 살펴봤습니다.
더 흥미로운 쪽은 편집입니다. 카페 창가를 담은 1024×683 JPEG에 지시를 하나 붙여 보냈더니 정사각형 이미지가 돌아왔습니다. 자전거는 어두운 색이 되었고 테이블, 컵, 식물은 화면에 남아 있습니다. 출력이 정사각형이라 창문과 테이블 끝의 구도는 원본과 달라집니다.
Change the red bicycle to matte black. Keep everything else exactly the same: the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos.

라벨, 그리고 끄는 방법
모델 페이지(2026년 10월 29일 확인)에 따르면 parameters에서 watermark를 false로 두지 않는 한 모든 출력의 모서리에 "AI generated" 라벨이 붙습니다. 페이지는 위치를 오른쪽 아래로 적고 있고, 아래 기본 출력에서도 그 자리에 있습니다. 흐리고 작게 보입니다. watermark를 요청에서 빼면 라벨이 붙은 이미지를 받습니다.
A glass bottle of cold-pressed orange juice on a pale stone counter, morning light from the left, a single orange slice beside it, shallow depth of field, no text, no logos.
기본 설정으로 만든 출력입니다.

watermark를 false로 두는 설정은 실행하지 않았습니다. 블로그 도구의 실행당 비용 상한이 요청을 보내기 전에 그 호출을 막았습니다.
오류와 제한
create 호출이 통과하는지는 두 헤더가 정합니다. Bearer 토큰과 Idempotency-Key입니다.
| 보내는 것 | 돌아오는 것 |
|---|---|
| 멱등성 키 없이 create 호출 | 400 missing_idempotency_key |
| 같은 키와 같은 body를 다시 | 200과 기존 작업, 새 과금 없음 |
| 같은 키에 body를 바꿔서 | 409 idempotency_key_reused |
같은 키에 같은 body가 원하는 재시도입니다. 기존 작업이 돌아오고 새로 과금되지 않습니다. 같은 키로 프롬프트나 사이즈를 바꾸면 409가 돌아오므로 새 요청마다 새 키를 만드세요. 키는 최대 255자입니다(문서, 2026년 10월 29일 확인).
요청 body는 Base64 이미지를 포함해 1 MiB 아래로 유지하고, 큰 원본 사진은 보내기 전에 줄이세요. 작업이 성공하면 응답의 다운로드 URL은 약 한 시간 유효한 서명 링크입니다(문서 기준). 파일을 바로 받거나, 작업을 다시 폴링해 새 링크를 받으세요.
2026년 10월 29일에 헤더 하나가 예상 밖이었습니다. Python 기본 urllib User-Agent로 POST를 보내면 Cloudflare에서 HTTP 403과 error code: 1010 본문이 돌아왔습니다. 직접 넣은 User-Agent 헤더는 API에 도달했고 과금도 없었습니다.
User-Agent 헤더를 넣으세요. 예를 들어 omniakey-example/1입니다. 2026년 10월 29일 Python 기본값은 위의 403을 받았습니다.API 작업이라면 Seedream과 GPT Image 2.5 중 무엇인가
하는 일이 정합니다. 이번 편집에서 Seedream 5.0 Pro는 지정한 객체 하나(자전거)를 바꾸고 장면 대부분을 유지했지만 프레임은 달라졌습니다. 제품 사진은 여기서 시험하지 않았습니다. 호출은 operation에 generate나 edit를 넣은 body 하나이고, 원본은 공개 URL이나 인라인 Base64로 줄 수 있습니다(문서, 2026년 10월 29일 확인).
같은 프롬프트의 결과를 GPT Image 2와 나란히 보려면 Seedream 5.0 Pro와 GPT Image 2 비교에 두 출력이 있습니다. 다른 모델에서 같은 생성·편집 형태를 따라가려면 GPT Image 2.5 API 튜토리얼에 요청과 사이즈가 있습니다. 파이프라인을 옮기기 전에 가장 어려운 프롬프트를 후보 모델에서 먼저 돌려 보고, 요금을 확인하세요.
FAQ
API에 어떤 모델 id를 넘기나요?
Dola-Seedream-5.0-pro입니다. 모델 페이지의 샘플 요청에 있는 id입니다(2026년 10월 29일 확인). ByteDance 자체의 dola-seedream-5-0-pro-260628은 BytePlus ModelArk의 것이고, OmniaKey는 위의 id를 받습니다.
이미지에 "AI generated" 라벨이 붙는 이유는 무엇인가요?
모델 페이지(2026년 10월 29일 확인)에 따르면 watermark를 false로 두지 않는 한 모든 Seedream 5.0 Pro 출력의 오른쪽 아래에 라벨이 붙습니다. 10월 29일 기본 설정 실행에서도 붙어 있었습니다.
API가 받는 사이즈는 무엇인가요?
1K, 1.5K, 2K 세 단계, 또는 두 변 사이에 소문자 x를 넣은 widthxheight 형식입니다(모델 페이지, 2026년 10월 29일 확인). 출력은 2K에서 멈추고, 실행한 두 번은 모두 1024x1024를 요청했습니다.
JPEG 대신 PNG로 받을 수 있나요?
네. output_format에는 png나 jpeg를 넣고 기본값은 JPEG입니다(문서, 2026년 10월 29일 확인). 두 번 모두 PNG를 요청해 PNG로 받았습니다.
Seedream으로 기존 이미지를 편집할 수 있나요?
네. operation에 edit를 넣고 프롬프트와 원본 이미지를 보냅니다. 원본은 mime 타입을 붙인 인라인 Base64나 공개 URL이면 됩니다. 위 사이즈 절의 카페 창문 편집이 그 예입니다.
이 글에서 다루는 모델
관련 글
Seedream 5.0 Pro vs GPT Image 2: 동일 프롬프트 테스트와 가격
여섯 가지 작업, 같은 프롬프트, 세 모델. 각 모델이 만든 이미지와 든 비용을 정리했습니다.
GPT Image 2.5 API: Python으로 이미지 생성하고 편집하기
POST 한 번이면 작업이 만들어지고, GET 한 번이면 결과를 읽습니다. 실행한 요청 코드와 2026년 10월 29일에 시험한 크기, 편집 전후 비교를 담았습니다.
Kling 3.0 API: 텍스트 투 비디오 요청 코드와 실측 클립
텍스트 투 비디오 작업은 model에 kling-3.0을 넣는 POST 한 번으로 시작합니다. 요청 코드와 필수 필드, 2026년 10월 29일에 만들어 측정한 5초 클립 2개를 담았습니다.