이미지 생성
이미지 생성 (Image generation)
이제 그림을 그려 달라고 하면 모델이 실제로 그림을 그려주는 시대예요. OpenAI API로 텍스트 프롬프트에서 이미지를 생성하거나 편집할 수 있어요. 사용하는 모델은 gpt-image-2.5-sunburst와 gpt-image-2.5-flare 두 가지예요. 편집 정밀도가 중요한 워크플로라면 Sunburst를, 빠르고 고품질의 일상적인 이미지 생성이라면 Flare를 선택하세요. 이 기능에 접근하는 방법은 두 가지 API가 있어요.
출처: 공식문서
개요 (Overview)
Image API
Image API는 각각 다른 능력을 가진 두 엔드포인트를 제공해요.
Responses API
Responses API는 대화나 다단계 흐름의 일부로 이미지를 생성할 수 있게 해줘요. 이미지 생성을 내장 도구로 지원하고, 컨텍스트 안에서 이미지 입력과 출력을 받아요.
Image API에 비해 추가로 제공하는 것은:
- 다중 턴 편집: 프롬프팅으로 이미지를 반복적으로 고충실도 편집
- 유연한 입력: 입력 이미지로 바이트뿐 아니라 이미지 File ID도 받아들임
이미지 생성 도구를 호출할 수 있는 메인라인 모델은 지원 모델을 참고하세요.
올바른 API 선택하기
- 한 프롬프트에서 단일 이미지를 생성하거나 편집하는 것만 필요하다면 Image API가 최선의 선택이에요.
- GPT Image로 대화형이고 편집 가능한 이미지 경험을 만들고 싶다면 Responses API를 쓰세요.
Image API에서는 model을 gpt-image-2.5-sunburst 또는 gpt-image-2.5-flare로 직접 설정해요. Responses API에서는 최상위에서 지원되는 메인라인 모델을 선택하고, 이미지 생성 도구의 model 필드에 gpt-image-2.5-sunburst 또는 gpt-image-2.5-flare를 지정해요.
두 API 모두 품질, 크기, 형식, 압축을 조정해 출력을 커스터마이즈할 수 있어요.
이 모델들을 책임감 있게 사용하기 위해, GPT Image 모델을 쓰기 전에 개발자 콘솔에서 API 조직 인증을 완료해야 할 수도 있어요.
이미지 생성 (Generate Images)
이미지 생성 엔드포인트로 텍스트 프롬프트 기반 이미지를 만들거나, Responses API의 이미지 생성 도구로 대화의 일부로 이미지를 생성할 수 있어요.
출력 커스터마이즈(크기, 품질, 형식, 압축)에 대해서는 아래 이미지 출력 커스터마이즈 섹션을 참고하세요.
n 파라미터를 설정하면 한 요청에서 여러 이미지를 한 번에 생성할 수 있어요. (기본적으로 API는 단일 이미지를 반환해요.)
Image API — 이미지 생성하기
import OpenAI from "openai";
import fs from "fs";
const openai = new OpenAI();
const prompt = `
A children's book drawing of a veterinarian using a stethoscope to
listen to the heartbeat of a baby otter.
`;
const result = await openai.images.generate({
model: "gpt-image-2.5-sunburst",
prompt,
});
// Save the image to a file
const image_base64 = result.data[0].b64_json;
const image_bytes = Buffer.from(image_base64, "base64");
fs.writeFileSync("otter.png", image_bytes);
from openai import OpenAI
import base64
client = OpenAI()
prompt = """
A children's book drawing of a veterinarian using a stethoscope to
listen to the heartbeat of a baby otter.
"""
result = client.images.generate(model="gpt-image-2.5-sunburst", prompt=prompt)
image_base64 = result.data[0].b64_json
image_bytes = base64.b64decode(image_base64)
# Save the image to a file
with open("otter.png", "wb") as f:
f.write(image_bytes)
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
result, err := client.Images.Generate(context.Background(), openai.ImageGenerateParams{
Model: openai.ImageModel("gpt-image-2.5-sunburst"),
Prompt: "A children's book drawing of a veterinarian using a stethoscope to " +
"listen to the heartbeat of a baby otter.",
})
if err != nil {
panic(err)
}
image, err := base64.StdEncoding.DecodeString(result.Data[0].B64JSON)
if err != nil {
panic(err)
}
if err := os.WriteFile("otter.png", image, 0o600); err != nil {
panic(err)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.images.ImageGenerateParams;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
var images =
client
.images()
.generate(
ImageGenerateParams.builder()
.model("gpt-image-2.5-sunburst")
.prompt("A watercolor robot reading in a library")
.build());
Files.write(
Path.of("generated-image.png"),
Base64.getDecoder().decode(images.data().orElseThrow().get(0).b64Json().orElseThrow()));
using OpenAI.Images;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-image-2.5-sunburst";
ImageClient client = new(model, key);
GeneratedImage image = await client.GenerateImageAsync(
"A children's book drawing of a veterinarian using a stethoscope to "
+ "listen to the heartbeat of a baby otter."
);
await File.WriteAllBytesAsync("otter.png", image.ImageBytes.ToArray());
require "base64"
require "openai"
client = OpenAI::Client.new
result = client.images.generate(
model: "gpt-image-2.5-sunburst",
prompt: "A watercolor robot reading in a library"
)
generated_image = result.data&.first or raise "No image returned"
File.binwrite(
"generated-image.png",
Base64.strict_decode64(generated_image.b64_json)
)
curl -X POST "https://api.openai.com/v1/images/generations" \
-H "Authorization: Bearer ***" \
-H "Content-type: application/json" \
-d '{
"model": "gpt-image-2.5-sunburst",
"prompt": "A children'\\''s book drawing of a veterinarian using a stethoscope to listen to the heartbeat of a baby otter."
}' | jq -r '.data[0].b64_json' | base64 --decode > otter.png
openai images generate \
--model gpt-image-2.5-sunburst \
--prompt "A children's book drawing of a veterinarian using a stethoscope to listen to the heartbeat of a baby otter." \
--raw-output \
--transform 'data.0.b64_json' | base64 --decode > otter.png
Responses API — 이미지 생성하기
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
input:
"Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
// Save the image to a file
const imageData = response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
const fs = await import("fs");
fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));
}
from openai import OpenAI
import base64
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input="Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
# Save the image to a file
image_data = [
output.result
for output in response.output
if output.type == "image_generation_call"
]
if image_data:
image_base64 = image_data[0]
with open("otter.png", "wb") as f:
f.write(base64.b64decode(image_base64))
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Generate an image of gray tabby cat hugging an otter with an orange scarf"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
saveFirstGeneratedImage(response, "otter.png")
}
func saveFirstGeneratedImage(response *responses.Response, filename string) {
for _, output := range response.Output {
if output.Type != "image_generation_call" {
continue
}
image, err := base64.StdEncoding.DecodeString(output.AsImageGenerationCall().Result)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
return
}
panic("response did not include an image generation call")
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.Tool;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Generate an image of a gray tabby cat hugging an otter with an orange scarf.")
.addTool(Tool.ImageGeneration.builder().build())
.build();
var image =
client.responses().create(params).output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No image generation call returned"));
String encoded =
image.result().orElseThrow(() -> new IllegalStateException("No image returned"));
Files.write(Path.of("otter.png"), Base64.getDecoder().decode(encoded));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf."
)
);
options.Tools.Add(ResponseTool.CreateImageGenerationTool(model: "gpt-image-2.5-sunburst"));
ResponseResult response = await client.CreateResponseAsync(options);
ImageGenerationCallResponseItem image = response
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.FirstOrDefault()
?? throw new InvalidOperationException("No generated image was returned.");
await File.WriteAllBytesAsync("otter.png", image.ImageResultBytes.ToArray());
require "base64"
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
image_call = response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
encoded_image = image_call.result or raise "No image returned"
File.binwrite("otter.png", Base64.strict_decode64(encoded_image))
다중 턴 이미지 생성
Responses API에서는 컨텍스트 안에 이미지 생성 호출 출력을 제공하거나(그냥 이미지 ID를 써도 돼요), previous_response_id 파라미터를 사용해 이미지 생성이 포함된 다중 턴 대화를 만들 수 있어요.
이렇게 하면 여러 턴에 걸쳐 이미지를 반복하며 — 프롬프트를 다듬고, 새 지시를 적용하고, 대화가 진행됨에 따라 시각적 출력을 진화시킬 수 있어요.
Responses API 이미지 생성 도구에서, 지원되는 도구 모델은 새 이미지를 생성할지 대화에 이미 있는 이미지를 편집할지 선택할 수 있어요. 선택적 action 파라미터가 이 동작을 제어해요: action: "auto"로 두면 모델이 알아서 결정하고, action: "generate"로 설정하면 항상 새 이미지를 만들며, action: "edit"로 설정하면 이미지가 컨텍스트에 있을 때 편집을 강제해요.
action으로 이미지 생성을 강제하기
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
input:
"Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools: [
{ type: "image_generation", model: "gpt-image-2.5-sunburst", action: "generate" },
],
});
// Save the image to a file
const imageData = response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
const fs = await import("fs");
fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));
}
from openai import OpenAI
import base64
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input="Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools=[
{"type": "image_generation", "model": "gpt-image-2.5-sunburst", "action": "generate"}
],
)
# Save the image to a file
image_data = [
output.result
for output in response.output
if output.type == "image_generation_call"
]
if image_data:
image_base64 = image_data[0]
with open("otter.png", "wb") as f:
f.write(base64.b64decode(image_base64))
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Generate an image of gray tabby cat hugging an otter with an orange scarf"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst", Action: "generate"}}},
})
if err != nil {
panic(err)
}
for _, output := range response.Output {
if output.Type != "image_generation_call" {
continue
}
image, err := base64.StdEncoding.DecodeString(output.AsImageGenerationCall().Result)
if err != nil {
panic(err)
}
if err := os.WriteFile("otter.png", image, 0o600); err != nil {
panic(err)
}
return
}
panic("response did not include an image generation call")
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.Tool;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Generate an image of a gray tabby cat hugging an otter with an orange scarf.")
.addTool(
Tool.ImageGeneration.builder().action(Tool.ImageGeneration.Action.GENERATE).build())
.build();
String imageResult =
client.responses().create(params).output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.flatMap(call -> call.result().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No generated image returned"));
Path output = Path.of(System.getenv().getOrDefault("OPENAI_EXAMPLE_OUTPUT_PATH", "otter.png"));
Files.write(output, Base64.getDecoder().decode(imageResult));
System.out.println(output);
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf."
)
);
options.Tools.Add(
ResponseTool.CreateImageGenerationTool(
model: "gpt-image-2.5-sunburst",
action: ImageGenerationToolAction.Generate
)
);
ResponseResult response = await client.CreateResponseAsync(options);
ImageGenerationCallResponseItem image = response
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.FirstOrDefault()
?? throw new InvalidOperationException("No generated image was returned.");
await File.WriteAllBytesAsync("otter.png", image.ImageResultBytes.ToArray());
require "base64"
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst",
action: :generate
}
]
)
image_call = response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
encoded_image = image_call.result or raise "No image returned"
output_path = ENV.fetch("OPENAI_EXAMPLE_OUTPUT_PATH", "otter.png")
File.binwrite(output_path, Base64.decode64(encoded_image))
puts(output_path)
컨텍스트에 이미지를 제공하지 않고 edit을 강제하면 호출이 오류를 반환해요. action을 auto에 두면 모델이 언제 생성하거나 편집할지를 스스로 결정해요.
이전 응답 ID 사용하기 — 다중 턴 이미지 생성
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
input:
"Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
const imageData = response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
const fs = await import("fs");
fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));
}
// Follow up
const response_fwup = await openai.responses.create({
model: "gpt-6-astra",
previous_response_id: response.id,
input: "Now make it look realistic",
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
const imageData_fwup = response_fwup.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData_fwup.length > 0) {
const imageBase64 = imageData_fwup[0];
const fs = await import("fs");
fs.writeFileSync(
"cat_and_otter_realistic.png",
Buffer.from(imageBase64, "base64")
);
}
from openai import OpenAI
import base64
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input="Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
image_data = [
output.result
for output in response.output
if output.type == "image_generation_call"
]
if image_data:
image_base64 = image_data[0]
with open("cat_and_otter.png", "wb") as f:
f.write(base64.b64decode(image_base64))
# Follow up
response_fwup = client.responses.create(
model="gpt-6-astra",
previous_response_id=response.id,
input="Now make it look realistic",
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
image_data_fwup = [
output.result
for output in response_fwup.output
if output.type == "image_generation_call"
]
if image_data_fwup:
image_base64 = image_data_fwup[0]
with open("cat_and_otter_realistic.png", "wb") as f:
f.write(base64.b64decode(image_base64))
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Generate an image of gray tabby cat hugging an otter with an orange scarf"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
saveFirstGeneratedImage(first, "cat_and_otter.png")
followUp, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PreviousResponseID: openai.String(first.ID),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Now make it look realistic"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
saveFirstGeneratedImage(followUp, "cat_and_otter_realistic.png")
}
func saveFirstGeneratedImage(response *responses.Response, filename string) {
for _, output := range response.Output {
if output.Type != "image_generation_call" {
continue
}
image, err := base64.StdEncoding.DecodeString(output.AsImageGenerationCall().Result)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
return
}
panic("response did not include an image generation call")
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.Tool;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf.")
.addTool(Tool.ImageGeneration.builder().build())
.build());
var firstImage =
first.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No image generation call returned"));
Files.write(
Path.of("cat_and_otter.png"),
Base64.getDecoder()
.decode(
firstImage
.result()
.orElseThrow(() -> new IllegalStateException("No image returned"))));
var second =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Now make it look realistic.")
.previousResponseId(first.id())
.addTool(Tool.ImageGeneration.builder().build())
.build());
var secondImage =
second.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(
() -> new IllegalStateException("No follow-up image generation call returned"));
Files.write(
Path.of("cat_and_otter_realistic.png"),
Base64.getDecoder()
.decode(
secondImage
.result()
.orElseThrow(() -> new IllegalStateException("No follow-up image returned"))));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.Tools.Add(ResponseTool.CreateImageGenerationTool(model: "gpt-image-2.5-sunburst"));
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf."
)
);
ResponseResult first = await client.CreateResponseAsync(options);
ImageGenerationCallResponseItem initialImage = first
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.First();
await File.WriteAllBytesAsync("cat_and_otter.png", initialImage.ImageResultBytes.ToArray());
CreateResponseOptions followUp = new()
{
Model = "gpt-6-astra",
PreviousResponseId = first.Id,
};
followUp.Tools.Add(ResponseTool.CreateImageGenerationTool(model: "gpt-image-2.5-sunburst"));
followUp.InputItems.Add(ResponseItem.CreateUserMessageItem("Now make it look realistic."));
ResponseResult second = await client.CreateResponseAsync(followUp);
ImageGenerationCallResponseItem updatedImage = second
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.First();
await File.WriteAllBytesAsync(
"cat_and_otter_realistic.png",
updatedImage.ImageResultBytes.ToArray()
);
require "base64"
require "openai"
client = OpenAI::Client.new
first = client.responses.create(
model: "gpt-6-astra",
input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
first_image = first.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
encoded_image = first_image.result or raise "No image returned"
File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))
follow_up = client.responses.create(
model: "gpt-6-astra",
input: "Now make it look realistic.",
previous_response_id: first.id,
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
follow_up_image = follow_up.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No follow-up image generation call returned"
end
encoded_image = follow_up_image.result or raise "No follow-up image returned"
File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))
이미지 ID 사용하기 — 다중 턴 이미지 생성
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
input:
"Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
const imageGenerationCalls = response.output.filter(
(output) => output.type === "image_generation_call"
);
const imageData = imageGenerationCalls.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
const fs = await import("fs");
fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));
}
// Follow up
const response_fwup = await openai.responses.create({
model: "gpt-6-astra",
input: [
{
role: "user",
content: [{ type: "input_text", text: "Now make it look realistic" }],
},
{
type: "image_generation_call",
id: imageGenerationCalls[0].id,
},
],
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
const imageData_fwup = response_fwup.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData_fwup.length > 0) {
const imageBase64 = imageData_fwup[0];
const fs = await import("fs");
fs.writeFileSync(
"cat_and_otter_realistic.png",
Buffer.from(imageBase64, "base64")
);
}
import openai
import base64
response = openai.responses.create(
model="gpt-6-astra",
input="Generate an image of gray tabby cat hugging an otter with an orange scarf",
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
image_generation_calls = [
output for output in response.output if output.type == "image_generation_call"
]
image_data = [output.result for output in image_generation_calls]
if image_data:
image_base64 = image_data[0]
with open("cat_and_otter.png", "wb") as f:
f.write(base64.b64decode(image_base64))
# Follow up
response_fwup = openai.responses.create(
model="gpt-6-astra",
input=[
{
"role": "user",
"content": [{"type": "input_text", "text": "Now make it look realistic"}],
},
{
"type": "image_generation_call",
"id": image_generation_calls[0].id,
},
],
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
image_data_fwup = [
output.result
for output in response_fwup.output
if output.type == "image_generation_call"
]
if image_data_fwup:
image_base64 = image_data_fwup[0]
with open("cat_and_otter_realistic.png", "wb") as f:
f.write(base64.b64decode(image_base64))
package main
import (
"context"
"encoding/base64"
"encoding/json"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Generate an image of gray tabby cat hugging an otter with an orange scarf"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
call := firstImageGenerationCall(first)
saveImage("cat_and_otter.png", call.Result)
input := outputAsInput(first.Output)
input = append(input, responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Now make it look realistic")},
responses.EasyInputMessageRoleUser,
))
followUp, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: input},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
saveImage("cat_and_otter_realistic.png", firstImageGenerationCall(followUp).Result)
}
func firstImageGenerationCall(response *responses.Response) responses.ResponseOutputItemImageGenerationCall {
for _, output := range response.Output {
if output.Type == "image_generation_call" {
return output.AsImageGenerationCall()
}
}
panic("response did not include an image generation call")
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return input
}
func saveImage(filename, encoded string) {
image, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.Tool;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
import java.util.Map;
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf.")
.addTool(Tool.ImageGeneration.builder().build())
.build());
var firstImage =
first.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No image generation call returned"));
Files.write(
Path.of("cat_and_otter.png"),
Base64.getDecoder()
.decode(
firstImage
.result()
.orElseThrow(() -> new IllegalStateException("No image returned"))));
var second =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofMessage(
ResponseInputItem.Message.builder()
.role(ResponseInputItem.Message.Role.USER)
.addInputTextContent("Now make it look realistic.")
.build()),
JsonValue.from(
Map.of("type", "image_generation_call", "id", firstImage.id()))
.convert(ResponseInputItem.class)))
.addTool(Tool.ImageGeneration.builder().build())
.build());
var secondImage =
second.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(
() -> new IllegalStateException("No follow-up image generation call returned"));
Files.write(
Path.of("cat_and_otter_realistic.png"),
Base64.getDecoder()
.decode(
secondImage
.result()
.orElseThrow(() -> new IllegalStateException("No follow-up image returned"))));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.Tools.Add(ResponseTool.CreateImageGenerationTool(model: "gpt-image-2.5-sunburst"));
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"Generate an image of a gray tabby cat hugging an otter with an orange scarf."
)
);
ResponseResult first = await client.CreateResponseAsync(options);
ImageGenerationCallResponseItem initialImage = first
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.First();
await File.WriteAllBytesAsync("cat_and_otter.png", initialImage.ImageResultBytes.ToArray());
CreateResponseOptions followUp = new() { Model = "gpt-6-astra" };
followUp.Tools.Add(ResponseTool.CreateImageGenerationTool(model: "gpt-image-2.5-sunburst"));
followUp.InputItems.Add(ResponseItem.CreateUserMessageItem("Now make it look realistic."));
followUp.InputItems.Add(ResponseItem.CreateReferenceItem(initialImage.Id));
ResponseResult second = await client.CreateResponseAsync(followUp);
ImageGenerationCallResponseItem updatedImage = second
.OutputItems.OfType<ImageGenerationCallResponseItem>()
.First();
await File.WriteAllBytesAsync(
"cat_and_otter_realistic.png",
updatedImage.ImageResultBytes.ToArray()
);
require "base64"
require "openai"
client = OpenAI::Client.new
first = client.responses.create(
model: "gpt-6-astra",
input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
first_image = first.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
encoded_image = first_image.result or raise "No image returned"
File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))
follow_up = client.responses.create(
model: "gpt-6-astra",
input: [
{
role: :user,
content: [
{
type: :input_text,
text: "Now make it look realistic."
}
]
},
{
type: :image_generation_call,
id: first_image.id
}
],
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
follow_up_image = follow_up.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No follow-up image generation call returned"
end
encoded_image = follow_up_image.result or raise "No follow-up image returned"
File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))
첫 프롬프트 "회색 얼룩이 고양이가 주황색 스카프를 두른 수달을 안고 있는 이미지를 생성해"의 결과와, "이제 실제처럼 보이게 해"라는 후속 프롬프트의 결과를 비교해 보면, 같은 이미지를 두고 반복 편집하는 흐름이 잘 드러나요.
스트리밍 (Streaming)
Responses API와 Image API는 이미지 생성 스트리밍을 지원해요. API가 이미지를 생성하는 동안 부분 이미지를 스트리밍받아 더 인터랙티브한 경험을 제공할 수 있어요.
partial_images 파라미터를 조정해 0~3개의 부분 이미지를 받을 수 있어요.
partial_images를 0으로 설정하면 최종 이미지만 받아요.- 0보다 큰 값이면, 전체 이미지가 더 빨리 생성되면 요청한 만큼의 부분 이미지를 다 못 받을 수도 있어요.
Responses API — 이미지 스트리밍
import OpenAI from "openai";
import fs from "fs";
const openai = new OpenAI();
function saveBase64Image(filename, imageBase64) {
const imageBuffer = Buffer.from(imageBase64, "base64");
fs.writeFileSync(filename, imageBuffer);
}
const stream = await openai.responses.create({
model: "gpt-6-astra",
input:
"Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape",
stream: true,
tools: [
{ type: "image_generation", model: "gpt-image-2.5-sunburst", partial_images: 2 },
],
});
for await (const event of stream) {
if (event.type === "response.image_generation_call.partial_image") {
const idx = event.partial_image_index;
saveBase64Image(`river-partial-${idx}.png`, event.partial_image_b64);
} else if (event.type === "response.completed") {
const imageData = event.response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
saveBase64Image("river-final.png", imageData[0]);
}
}
}
from openai import OpenAI
import base64
client = OpenAI()
def save_base64_image(filename, image_base64):
image_bytes = base64.b64decode(image_base64)
with open(filename, "wb") as f:
f.write(image_bytes)
stream = client.responses.create(
model="gpt-6-astra",
input="Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape",
stream=True,
tools=[
{"type": "image_generation", "model": "gpt-image-2.5-sunburst", "partial_images": 2}
],
)
for event in stream:
if event.type == "response.image_generation_call.partial_image":
idx = event.partial_image_index
save_base64_image(f"river-partial-{idx}.png", event.partial_image_b64)
elif event.type == "response.completed":
image_data = [
output.result
for output in event.response.output
if output.type == "image_generation_call"
]
if image_data:
save_base64_image("river-final.png", image_data[0])
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
stream := client.Responses.NewStreaming(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape"),
},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst", PartialImages: openai.Int(2)}}},
})
for stream.Next() {
event := stream.Current()
if event.Type == "response.image_generation_call.partial_image" {
partial := event.AsResponseImageGenerationCallPartialImage()
saveImage(fmt.Sprintf("river-partial-%d.png", partial.PartialImageIndex), partial.PartialImageB64)
}
if event.Type == "response.completed" {
for _, output := range event.AsResponseCompleted().Response.Output {
if output.Type == "image_generation_call" {
saveImage("river-final.png", output.AsImageGenerationCall().Result)
}
}
}
}
if err := stream.Err(); err != nil {
panic(err)
}
}
func saveImage(filename, encoded string) {
image, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStreamEvent;
import com.openai.models.responses.Tool;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Generate an image of a river made of white owl feathers.")
.addTool(Tool.ImageGeneration.builder().partialImages(2).build())
.build();
try (StreamResponse<ResponseStreamEvent> stream = client.responses().createStreaming(params)) {
var events = stream.stream().iterator();
while (events.hasNext()) {
ResponseStreamEvent event = events.next();
if (event.imageGenerationCallPartialImage().isPresent()) {
var partial = event.imageGenerationCallPartialImage().orElseThrow();
Files.write(
Path.of("river-partial-" + partial.partialImageIndex() + ".png"),
Base64.getDecoder().decode(partial.partialImageB64()));
}
if (event.completed().isPresent()) {
var image =
event.completed().orElseThrow().response().output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No generated image returned"));
Files.write(
Path.of("river-final.png"),
Base64.getDecoder()
.decode(
image
.result()
.orElseThrow(
() -> new IllegalStateException("No final image returned"))));
}
}
}
require "base64"
require "openai"
client = OpenAI::Client.new
stream = client.responses.stream(
model: "gpt-6-astra",
input: "Generate an image of a river made of white owl feathers.",
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst",
partial_images: 2
}
]
)
stream.each do |event|
case event
when OpenAI::Models::Responses::ResponseImageGenCallPartialImageEvent
image = Base64.strict_decode64(event.partial_image_b64)
File.binwrite("river-partial-#{event.partial_image_index}.png", image)
when OpenAI::Models::Responses::ResponseCompletedEvent
image_call = event.response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
next unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
File.binwrite(
"river-final.png",
Base64.strict_decode64(image_call.result)
)
end
end
Image API — 이미지 스트리밍
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
const prompt =
"Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape";
const stream = await openai.images.generate({
prompt: prompt,
model: "gpt-image-2.5-sunburst",
stream: true,
partial_images: 2,
});
for await (const event of stream) {
if (event.type === "image_generation.partial_image") {
const idx = event.partial_image_index;
const imageBase64 = event.b64_json;
const imageBuffer = Buffer.from(imageBase64, "base64");
fs.writeFileSync(`river${idx}.png`, imageBuffer);
}
}
from openai import OpenAI
import base64
client = OpenAI()
stream = client.images.generate(
prompt="Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape",
model="gpt-image-2.5-sunburst",
stream=True,
partial_images=2,
)
for event in stream:
if event.type == "image_generation.partial_image":
idx = event.partial_image_index
image_base64 = event.b64_json
image_bytes = base64.b64decode(image_base64)
with open(f"river{idx}.png", "wb") as f:
f.write(image_bytes)
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
stream := client.Images.GenerateStreaming(context.Background(), openai.ImageGenerateParams{
Model: openai.ImageModel("gpt-image-2.5-sunburst"),
Prompt: "Draw a gorgeous image of a river made of white owl feathers, snaking its way through a serene winter landscape",
PartialImages: openai.Int(2),
})
for stream.Next() {
event := stream.Current()
if event.Type != "image_generation.partial_image" {
continue
}
partial := event.AsImageGenerationPartialImage()
saveImage(fmt.Sprintf("river%d.png", partial.PartialImageIndex), partial.B64JSON)
}
if err := stream.Err(); err != nil {
panic(err)
}
}
func saveImage(filename, encoded string) {
image, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
}
require "base64"
require "openai"
client = OpenAI::Client.new
stream = client.images.generate_stream_raw(
model: "gpt-image-2.5-sunburst",
prompt: "A river made of white owl feathers in a winter landscape",
partial_images: 2
)
stream.each do |event|
next unless event.is_a?(OpenAI::Models::ImageGenPartialImageEvent)
image = Base64.strict_decode64(event.b64_json)
File.binwrite("river#{event.partial_image_index}.png", image)
end
프롬프트 "흰 올빼미 깃털로 만들어진 강이 고요한 겨울 풍경을 가로지르는 멋진 이미지를 그려"를 생성하면, 부분 1, 부분 2, 그리고 최종 이미지가 스트리밍돼요. 이렇게 하면 생성이 완료되기 전에도 이미지가 만들어지고 있는 모습을 볼 수 있어요.
수정된 프롬프트 (Revised prompt)
Responses API의 이미지 생성 도구를 사용하면 메인라인 모델(예: gpt-5.5)이 성능 향상을 위해 자동으로 프롬프트를 수정해요.
수정된 프롬프트는 이미지 생성 호출의 revised_prompt 필드에서 확인할 수 있어요.
수정된 프롬프트 응답
{
"id": "ig_123",
"type": "image_generation_call",
"status": "completed",
"revised_prompt": "A gray tabby cat hugging an otter. The otter is wearing an orange scarf. Both animals are cute and friendly, depicted in a warm, heartwarming style.",
"result": "..."
}
이미지 편집 (Edit Images)
이미지 편집 엔드포인트로 다음을 할 수 있어요.
- 기존 이미지 편집
- 다른 이미지를 참조로 사용해 새 이미지 생성
- 교체할 영역을 식별하는 이미지와 마스크를 업로드해 이미지의 일부 편집
이미지 참조로 새 이미지 만들기
하나 이상의 이미지를 참조로 사용해 새 이미지를 생성할 수 있어요.
이 예시에서는 참조 이미지에 있는 항목들이 담긴 선물 바구니의 새 이미지를 만들기 위해 입력 이미지 4개를 사용할 거예요.
Responses API
Responses API에서는 입력 이미지를 3가지 방법으로 제공할 수 있어요.
- 완전한 URL 제공
- Base64 인코딩 데이터 URL로 이미지 제공
- Files API로 만든 파일 ID 제공
파일 만들기
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
async function createFile(filePath) {
const fileContent = fs.createReadStream(filePath);
const result = await openai.files.create({
file: fileContent,
purpose: "vision",
});
return result.id;
}
from openai import OpenAI
client = OpenAI()
def create_file(file_path):
with open(file_path, "rb") as file_content:
result = client.files.create(
file=file_content,
purpose="vision",
)
return result.id
package main
import (
"context"
"fmt"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
file, err := os.Open("image.png")
if err != nil {
panic(err)
}
defer file.Close()
uploaded, err := client.Files.New(context.Background(), openai.FileNewParams{
File: file,
Purpose: openai.FilePurposeVision,
})
if err != nil {
panic(err)
}
fmt.Println(uploaded.ID)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.files.FileCreateParams;
import com.openai.models.files.FilePurpose;
import java.nio.file.Path;
var file =
client
.files()
.create(
FileCreateParams.builder()
.file(Path.of(System.getenv("OPENAI_EXAMPLE_FILE_PATH")))
.purpose(FilePurpose.VISION)
.build());
System.out.println(file.id());
require "openai"
require "pathname"
client = OpenAI::Client.new
file = client.files.create(
file: Pathname("image.png"),
purpose: OpenAI::Models::FilePurpose::VISION
)
puts(file.id)
base64 인코딩 이미지 만들기
import fs from "fs";
function encodeImage(filePath) {
const base64Image = fs.readFileSync(filePath, "base64");
return base64Image;
}
import base64
def encode_image(file_path):
with open(file_path, "rb") as f:
base64_image = base64.b64encode(f.read()).decode("utf-8")
return base64_image
package main
import (
"encoding/base64"
"fmt"
"os"
)
func main() {
image, err := os.ReadFile("image.png")
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(image))
}
require "base64"
image = File.binread("image.png")
puts(Base64.strict_encode64(image))
이미지 편집하기
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
function encodeImage(filePath) {
return fs.readFileSync(filePath, "base64");
}
async function createFile(filePath) {
const result = await openai.files.create({
file: fs.createReadStream(filePath),
purpose: "vision",
});
return result.id;
}
const prompt = `Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.`;
const base64Image1 = encodeImage("fixtures/body-lotion.png");
const base64Image2 = encodeImage("fixtures/soap.png");
const fileId1 = await createFile("fixtures/bath-bomb.png");
const fileId2 = await createFile("fixtures/incense-kit.png");
const response = await openai.responses.create({
model: "gpt-6-astra",
input: [
{
role: "user",
content: [
{ type: "input_text", text: prompt },
{
type: "input_image",
image_url: `data:image/png;base64,${base64Image1}`,
detail: "auto",
},
{
type: "input_image",
image_url: `data:image/png;base64,${base64Image2}`,
detail: "auto",
},
{
type: "input_image",
file_id: fileId1,
detail: "auto",
},
{
type: "input_image",
file_id: fileId2,
detail: "auto",
},
],
},
],
tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst" }],
});
const imageData = response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
fs.writeFileSync("gift-basket.png", Buffer.from(imageBase64, "base64"));
} else {
console.log(response.output_text);
}
from openai import OpenAI
import base64
client = OpenAI()
def encode_image(file_path):
with open(file_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
def create_file(file_path):
with open(file_path, "rb") as file_content:
result = client.files.create(file=file_content, purpose="vision")
return result.id
prompt = """Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures."""
base64_image1 = encode_image("body-lotion.png")
base64_image2 = encode_image("soap.png")
file_id1 = create_file("bath-bomb.png")
file_id2 = create_file("incense-kit.png")
response = client.responses.create(
model="gpt-6-astra",
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": prompt},
{
"type": "input_image",
"image_url": f"data:image/png;base64,{base64_image1}",
},
{
"type": "input_image",
"image_url": f"data:image/png;base64,{base64_image2}",
},
{
"type": "input_image",
"file_id": file_id1,
},
{
"type": "input_image",
"file_id": file_id2,
},
],
}
],
tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
image_generation_calls = [
output for output in response.output if output.type == "image_generation_call"
]
image_data = [output.result for output in image_generation_calls]
if image_data:
image_base64 = image_data[0]
with open("gift-basket.png", "wb") as f:
f.write(base64.b64decode(image_base64))
else:
print(response.output_text)
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
bathBombID := uploadImage(client, "bath-bomb.png")
incenseKitID := uploadImage(client, "incense-kit.png")
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{
responses.ResponseInputContentParamOfInputText("Generate a photorealistic image of a gift basket on a white background labeled 'Relax & Unwind' with a ribbon and handwriting-like font, containing all the items in the reference pictures."),
{OfInputImage: &responses.ResponseInputImageParam{ImageURL: openai.String(dataURL("body-lotion.png")), Detail: responses.ResponseInputImageDetailAuto}},
{OfInputImage: &responses.ResponseInputImageParam{ImageURL: openai.String(dataURL("soap.png")), Detail: responses.ResponseInputImageDetailAuto}},
{OfInputImage: &responses.ResponseInputImageParam{FileID: openai.String(bathBombID), Detail: responses.ResponseInputImageDetailAuto}},
{OfInputImage: &responses.ResponseInputImageParam{FileID: openai.String(incenseKitID), Detail: responses.ResponseInputImageDetailAuto}},
},
responses.EasyInputMessageRoleUser,
),
}},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{Model: "gpt-image-2.5-sunburst"}}},
})
if err != nil {
panic(err)
}
saveFirstGeneratedImage(response, "gift-basket.png")
}
func uploadImage(client openai.Client, filename string) string {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
uploaded, err := client.Files.New(context.Background(), openai.FileNewParams{File: file, Purpose: openai.FilePurposeVision})
if err != nil {
panic(err)
}
return uploaded.ID
}
func dataURL(filename string) string {
image, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
return "data:image/png;base64," + base64.StdEncoding.EncodeToString(image)
}
func saveFirstGeneratedImage(response *responses.Response, filename string) {
for _, output := range response.Output {
if output.Type != "image_generation_call" {
continue
}
image, err := base64.StdEncoding.DecodeString(output.AsImageGenerationCall().Result)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
return
}
panic("response did not include an image generation call")
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.files.FileCreateParams;
import com.openai.models.files.FilePurpose;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputImage;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.Tool;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
Path lotionImage = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH"));
Path soapImage = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_2"));
Path bathBombImage = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_3"));
Path incenseImage = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_4"));
String lotionBase64 = Base64.getEncoder().encodeToString(Files.readAllBytes(lotionImage));
String soapBase64 = Base64.getEncoder().encodeToString(Files.readAllBytes(soapImage));
var firstFile =
client
.files()
.create(
FileCreateParams.builder().file(bathBombImage).purpose(FilePurpose.VISION).build());
var secondFile =
client
.files()
.create(
FileCreateParams.builder().file(incenseImage).purpose(FilePurpose.VISION).build());
String prompt =
"""
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
""";
var input =
ResponseInputItem.ofMessage(
ResponseInputItem.Message.builder()
.role(ResponseInputItem.Message.Role.USER)
.addInputTextContent(prompt)
.addContent(
ResponseInputImage.builder()
.detail(ResponseInputImage.Detail.AUTO)
.imageUrl("data:image/png;base64," + lotionBase64)
.build())
.addContent(
ResponseInputImage.builder()
.detail(ResponseInputImage.Detail.AUTO)
.imageUrl("data:image/png;base64," + soapBase64)
.build())
.addContent(
ResponseInputImage.builder()
.detail(ResponseInputImage.Detail.AUTO)
.fileId(firstFile.id())
.build())
.addContent(
ResponseInputImage.builder()
.detail(ResponseInputImage.Detail.AUTO)
.fileId(secondFile.id())
.build())
.build());
var response =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(List.of(input))
.addTool(Tool.ImageGeneration.builder().build())
.build());
var image =
response.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No image generation call returned"));
Files.write(
Path.of("gift-basket.png"),
Base64.getDecoder()
.decode(
image.result().orElseThrow(() -> new IllegalStateException("No image returned"))));
require "base64"
require "openai"
require "pathname"
client = OpenAI::Client.new
base64_images = ["body-lotion.png", "soap.png"].map do |path|
Base64.strict_encode64(File.binread(path))
end
file_ids = [
client.files.create(file: Pathname("bath-bomb.png"), purpose: :vision).id,
client.files.create(file: Pathname("incense-kit.png"), purpose: :vision).id
]
prompt = <<~PROMPT
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
PROMPT
response = client.responses.create(
model: "gpt-6-astra",
input: [
{
role: :user,
content: [
{
type: :input_text,
text: prompt
},
*base64_images.map do |image|
{
type: :input_image,
image_url: "data:image/png;base64,#{image}"
}
end,
*file_ids.map do |file_id|
{
type: :input_image,
file_id: file_id
}
end
]
}
],
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst"
}
]
)
image_call = response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
File.binwrite("gift-basket.png", Base64.strict_decode64(image_call.result))
Image API — 이미지 편집하기
import fs from "fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI();
const prompt = `
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
`;
const imageFiles = [
"fixtures/bath-bomb.png",
"fixtures/body-lotion.png",
"fixtures/incense-kit.png",
"fixtures/soap.png",
];
const images = await Promise.all(
imageFiles.map(
async (file) =>
await toFile(fs.createReadStream(file), null, {
type: "image/png",
})
)
);
const response = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: images,
prompt,
});
// Save the image to a file
const image_base64 = response.data[0].b64_json;
const image_bytes = Buffer.from(image_base64, "base64");
fs.writeFileSync("basket.png", image_bytes);
import base64
from openai import OpenAI
client = OpenAI()
prompt = """
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
"""
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=[
open("body-lotion.png", "rb"),
open("bath-bomb.png", "rb"),
open("incense-kit.png", "rb"),
open("soap.png", "rb"),
],
prompt=prompt,
)
image_base64 = result.data[0].b64_json
image_bytes = base64.b64decode(image_base64)
# Save the image to a file
with open("gift-basket.png", "wb") as f:
f.write(image_bytes)
package main
import (
"context"
"encoding/base64"
"io"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
files, closeFiles := openImages(
"bath-bomb.png",
"body-lotion.png",
"incense-kit.png",
"soap.png",
)
defer closeFiles()
response, err := client.Images.Edit(context.Background(), openai.ImageEditParams{
Model: openai.ImageModel("gpt-image-2.5-sunburst"),
Image: openai.ImageEditParamsImageUnion{OfFileArray: files},
Prompt: "Generate a photorealistic image of a gift basket on a white background " +
"labeled 'Relax & Unwind' with a ribbon and handwriting-like font, containing all the items in the reference pictures.",
})
if err != nil {
panic(err)
}
saveImage("basket.png", response.Data[0].B64JSON)
}
func openImages(names ...string) ([]io.Reader, func()) {
images := make([]io.Reader, 0, len(names))
files := make([]*os.File, 0, len(names))
for _, name := range names {
file, err := os.Open(name)
if err != nil {
closeFiles(files)
panic(err)
}
images = append(images, openai.File(file, name, "image/png"))
files = append(files, file)
}
return images, func() { closeFiles(files) }
}
func closeFiles(files []*os.File) {
for _, file := range files {
if err := file.Close(); err != nil {
panic(err)
}
}
}
func saveImage(filename, encoded string) {
image, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.MultipartField;
import com.openai.models.images.ImageEditParams;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
Path lotion = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH"));
Path soap = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_2"));
Path bathBomb = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_3"));
Path incense = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_PATH_4"));
try (InputStream lotionImage = Files.newInputStream(lotion);
InputStream bathBombImage = Files.newInputStream(bathBomb);
InputStream incenseImage = Files.newInputStream(incense);
InputStream soapImage = Files.newInputStream(soap)) {
var images =
client
.images()
.edit(
ImageEditParams.builder()
.model("gpt-image-2.5-sunburst")
.image(
MultipartField.<ImageEditParams.Image>builder()
.value(
ImageEditParams.Image.ofInputStreams(
List.of(lotionImage, bathBombImage, incenseImage, soapImage)))
.contentType("image/png")
.filename("gift-basket-reference.png")
.build())
.prompt(
"""
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
""")
.build());
Files.write(
Path.of("gift-basket.png"),
Base64.getDecoder().decode(images.data().orElseThrow().get(0).b64Json().orElseThrow()));
}
require "base64"
require "openai"
require "pathname"
client = OpenAI::Client.new
images = %w[body-lotion.png bath-bomb.png incense-kit.png soap.png].map do |path|
Pathname(path)
end
result = client.images.edit(
image: images,
model: "gpt-image-2.5-sunburst",
prompt: <<~PROMPT
Generate a photorealistic image of a gift basket on a white background
labeled 'Relax & Unwind' with a ribbon and handwriting-like font,
containing all the items in the reference pictures.
PROMPT
)
generated_image = result.data&.first or raise "No image returned"
File.binwrite("gift-basket.png", Base64.strict_decode64(generated_image.b64_json))
curl -s -D >(grep -i x-request-id >&2) \
-o >(jq -r '.data[0].b64_json' | base64 --decode > gift-basket.png) \
-X POST "https://api.openai.com/v1/images/edits" \
-H "Authorization: Bearer ***" \
-F "model=gpt-image-2.5-sunburst" \
-F "image[][email protected]" \
-F "image[][email protected]" \
-F "image[][email protected]" \
-F "image[][email protected]" \
-F 'prompt=Generate a photorealistic image of a gift basket on a white background labeled "Relax & Unwind" with a ribbon and handwriting-like font, containing all the items in the reference pictures'
openai images edit \
--model gpt-image-2.5-sunburst \
--image body-lotion.png \
--image bath-bomb.png \
--image incense-kit.png \
--image soap.png \
--prompt 'Generate a photorealistic image of a gift basket on a white background labeled "Relax & Unwind" with a ribbon and handwriting-like font, containing all the items in the reference pictures' \
--raw-output \
--transform 'data.0.b64_json' | base64 --decode > gift-basket.png
마스크로 이미지 편집하기
이미지의 어느 부분을 편집할지 표시하는 마스크를 제공할 수 있어요.
GPT Image와 함께 마스크를 사용하면 편집 과정을 안내하는 추가 지시가 모델로 전송돼요.
GPT Image의 마스킹은 전적으로 프롬프트 기반이에요. 모델은 마스크를 지침으로 사용하지만, 그 정확한 모양을 완벽하게 따르지는 않을 수 있어요.
입력 이미지를 여러 개 제공하면 마스크는 첫 번째 이미지에 적용돼요.
Responses API — 마스크로 이미지 편집하기
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
async function createFile(filePath) {
const result = await openai.files.create({
file: fs.createReadStream(filePath),
purpose: "vision",
});
return result.id;
}
const fileId = await createFile("fixtures/sunlit_lounge.png");
const maskId = await createFile("fixtures/mask.png");
const response = await openai.responses.create({
model: "gpt-6-astra",
input: [
{
role: "user",
content: [
{
type: "input_text",
text: "generate an image of the same sunlit indoor lounge area with a pool but the pool should contain a flamingo",
},
{
type: "input_image",
file_id: fileId,
detail: "auto",
},
],
},
],
tools: [
{
type: "image_generation",
model: "gpt-image-2.5-sunburst",
quality: "high",
input_image_mask: {
file_id: maskId,
},
},
],
});
const imageData = response.output
.filter((output) => output.type === "image_generation_call")
.map((output) => output.result);
if (imageData.length > 0) {
const imageBase64 = imageData[0];
fs.writeFileSync("lounge.png", Buffer.from(imageBase64, "base64"));
}
from openai import OpenAI
import base64
client = OpenAI()
def create_file(file_path):
with open(file_path, "rb") as file_content:
result = client.files.create(file=file_content, purpose="vision")
return result.id
fileId = create_file("sunlit_lounge.png")
maskId = create_file("mask.png")
response = client.responses.create(
model="gpt-6-astra",
input=[
{
"role": "user",
"content": [
{
"type": "input_text",
"text": "generate an image of the same sunlit indoor lounge area with a pool but the pool should contain a flamingo",
},
{
"type": "input_image",
"file_id": fileId,
},
],
}
],
tools=[
{
"type": "image_generation",
"model": "gpt-image-2.5-sunburst",
"quality": "high",
"input_image_mask": {
"file_id": maskId,
},
}
],
)
image_data = [
output.result
for output in response.output
if output.type == "image_generation_call"
]
if image_data:
image_base64 = image_data[0]
with open("lounge.png", "wb") as f:
f.write(base64.b64decode(image_base64))
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
imageID := uploadImage(client, "sunlit_lounge.png")
maskID := uploadImage(client, "mask.png")
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{
responses.ResponseInputContentParamOfInputText("Generate an image of the same sunlit indoor lounge area with a pool, but the pool should contain a flamingo."),
{OfInputImage: &responses.ResponseInputImageParam{FileID: openai.String(imageID), Detail: responses.ResponseInputImageDetailAuto}},
},
responses.EasyInputMessageRoleUser,
),
}},
Tools: []responses.ToolUnionParam{{OfImageGeneration: &responses.ToolImageGenerationParam{
Model: "gpt-image-2.5-sunburst",
Quality: "high",
InputImageMask: responses.ToolImageGenerationInputImageMaskParam{FileID: openai.String(maskID)},
}}},
})
if err != nil {
panic(err)
}
saveFirstGeneratedImage(response, "lounge.png")
}
func uploadImage(client openai.Client, filename string) string {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
uploaded, err := client.Files.New(context.Background(), openai.FileNewParams{File: file, Purpose: openai.FilePurposeVision})
if err != nil {
panic(err)
}
return uploaded.ID
}
func saveFirstGeneratedImage(response *responses.Response, filename string) {
for _, output := range response.Output {
if output.Type != "image_generation_call" {
continue
}
image, err := base64.StdEncoding.DecodeString(output.AsImageGenerationCall().Result)
if err != nil {
panic(err)
}
if err := os.WriteFile(filename, image, 0o600); err != nil {
panic(err)
}
return
}
panic("response did not include an image generation call")
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.files.FileCreateParams;
import com.openai.models.files.FilePurpose;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputImage;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.Tool;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
var image =
client
.files()
.create(
FileCreateParams.builder()
.file(Path.of(System.getenv("OPENAI_EXAMPLE_FILE_PATH")))
.purpose(FilePurpose.VISION)
.build());
var mask =
client
.files()
.create(
FileCreateParams.builder()
.file(Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_MASK_PATH")))
.purpose(FilePurpose.VISION)
.build());
var response =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofMessage(
ResponseInputItem.Message.builder()
.role(ResponseInputItem.Message.Role.USER)
.addInputTextContent("Add a flamingo to the pool.")
.addContent(
ResponseInputImage.builder()
.detail(ResponseInputImage.Detail.AUTO)
.fileId(image.id())
.build())
.build())))
.addTool(
Tool.ImageGeneration.builder()
.inputImageMask(
Tool.ImageGeneration.InputImageMask.builder()
.fileId(mask.id())
.build())
.build())
.build());
String imageResult =
response.output().stream()
.flatMap(item -> item.imageGenerationCall().stream())
.flatMap(call -> call.result().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No generated image returned"));
Files.write(Path.of("lounge.png"), Base64.getDecoder().decode(imageResult));
require "base64"
require "openai"
require "pathname"
client = OpenAI::Client.new
image = client.files.create(file: Pathname("sunlit_lounge.png"), purpose: :vision)
mask = client.files.create(file: Pathname("mask.png"), purpose: :vision)
response = client.responses.create(
model: "gpt-6-astra",
input: [
{
role: :user,
content: [
{
type: :input_text,
text: "Add a flamingo to the pool."
},
{
type: :input_image,
file_id: image.id
}
]
}
],
tools: [
{
type: :image_generation,
model: "gpt-image-2.5-sunburst",
input_image_mask: { file_id: mask.id }
}
]
)
image_call = response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
end
unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)
raise "No image generation call returned"
end
File.binwrite("lounge.png", Base64.strict_decode64(image_call.result))
Image API — 마스크로 이미지 편집하기
import fs from "fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI();
const rsp = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: await toFile(fs.createReadStream("fixtures/sunlit_lounge.png"), null, {
type: "image/png",
}),
mask: await toFile(fs.createReadStream("fixtures/mask.png"), null, {
type: "image/png",
}),
prompt: "A sunlit indoor lounge area with a pool containing a flamingo",
});
// Save the image to a file
const image_base64 = rsp.data[0].b64_json;
const image_bytes = Buffer.from(image_base64, "base64");
fs.writeFileSync("lounge.png", image_bytes);
from openai import OpenAI
import base64
client = OpenAI()
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=open("sunlit_lounge.png", "rb"),
mask=open("mask.png", "rb"),
prompt="A sunlit indoor lounge area with a pool containing a flamingo",
)
image_base64 = result.data[0].b64_json
image_bytes = base64.b64decode(image_base64)
# Save the image to a file
with open("composition.png", "wb") as f:
f.write(image_bytes)
package main
import (
"context"
"encoding/base64"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
image, err := os.Open("sunlit_lounge.png")
if err != nil {
panic(err)
}
defer image.Close()
mask, err := os.Open("mask.png")
if err != nil {
panic(err)
}
defer mask.Close()
response, err := client.Images.Edit(context.Background(), openai.ImageEditParams{
Model: openai.ImageModel("gpt-image-2.5-sunburst"),
Image: openai.ImageEditParamsImageUnion{OfFile: openai.File(image, "sunlit_lounge.png", "image/png")},
Mask: openai.File(mask, "mask.png", "image/png"),
Prompt: "A sunlit indoor lounge area with a pool containing a flamingo",
})
if err != nil {
panic(err)
}
result, err := base64.StdEncoding.DecodeString(response.Data[0].B64JSON)
if err != nil {
panic(err)
}
if err := os.WriteFile("lounge.png", result, 0o600); err != nil {
panic(err)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.MultipartField;
import com.openai.models.images.ImageEditParams;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
Path imagePath = Path.of(System.getenv("OPENAI_EXAMPLE_FILE_PATH"));
Path maskPath = Path.of(System.getenv("OPENAI_EXAMPLE_IMAGE_MASK_PATH"));
try (InputStream image = Files.newInputStream(imagePath);
InputStream mask = Files.newInputStream(maskPath)) {
var images =
client
.images()
.edit(
ImageEditParams.builder()
.model("gpt-image-2.5-sunburst")
.image(
MultipartField.<ImageEditParams.Image>builder()
.value(ImageEditParams.Image.ofInputStream(image))
.contentType("image/png")
.filename(imagePath.getFileName().toString())
.build())
.prompt("A sunlit indoor lounge area with a pool containing a flamingo")
.mask(
MultipartField.<InputStream>builder()
.value(mask)
.contentType("image/png")
.filename(maskPath.getFileName().toString())
.build())
.build());
Files.write(
Path.of("lounge.png"),
Base64.getDecoder().decode(images.data().orElseThrow().get(0).b64Json().orElseThrow()));
}
require "openai"
require "pathname"
require "base64"
client = OpenAI::Client.new
image = Pathname("sunlit_lounge.png")
mask = Pathname("mask.png")
result = client.images.edit(
image: image,
mask: mask,
model: "gpt-image-2.5-sunburst",
prompt: "A sunlit indoor lounge area with a pool containing a flamingo"
)
generated_image = result.data&.first or raise "No image returned"
File.binwrite("lounge.png", Base64.strict_decode64(generated_image.b64_json))
curl -s -D >(grep -i x-request-id >&2) \
-o >(jq -r '.data[0].b64_json' | base64 --decode > lounge.png) \
-X POST "https://api.openai.com/v1/images/edits" \
-H "Authorization: Bearer ***" \
-F "model=gpt-image-2.5-sunburst" \
-F "[email protected]" \
-F "image[]=@sunlit_lounge.png" \
-F 'prompt=A sunlit indoor lounge area with a pool containing a flamingo'
openai images edit \
--model gpt-image-2.5-sunburst \
--image sunlit_lounge.png \
--mask mask.png \
--prompt "A sunlit indoor lounge area with a pool containing a flamingo" \
--raw-output \
--transform 'data.0.b64_json' | base64 --decode > out.png
프롬프트 "플라밍고가 있는 수영장이 있는 햇살 가득한 실내 라운지"로, 이미지와 마스크를 주면 마스크 영역에 플라밍고가 들어간 결과를 얻을 수 있어요.
마스크 요구사항
편집할 이미지와 마스크는 같은 형식·크기여야 해요. (크기는 50MB 미만)
마스크 이미지에는 알파 채널이 있어야 해요. 이미지 편집 도구로 마스크를 만든다면 알파 채널과 함께 저장했는지 확인하세요.
흑백 이미지를 프로그래밍 방식으로 수정해 알파 채널을 추가할 수도 있어요.
흑백 마스크에 알파 채널 추가하기
from PIL import Image
from io import BytesIO
# 1. Load your black & white mask as a grayscale image
mask = Image.open("mask.png").convert("L")
# 2. Convert it to RGBA so it has space for an alpha channel
mask_rgba = mask.convert("RGBA")
# 3. Then use the mask itself to fill that alpha channel
mask_rgba.putalpha(mask)
# 4. Convert the mask into bytes
buf = BytesIO()
mask_rgba.save(buf, format="PNG")
mask_bytes = buf.getvalue()
# 5. Save the resulting file
img_path_mask_alpha = "mask_alpha.png"
with open(img_path_mask_alpha, "wb") as f:
f.write(mask_bytes)
package main
import (
"image"
"image/color"
"image/png"
"os"
)
func main() {
file, err := os.Open("mask.png")
if err != nil {
panic(err)
}
defer file.Close()
mask, _, err := image.Decode(file)
if err != nil {
panic(err)
}
bounds := mask.Bounds()
withAlpha := image.NewNRGBA(bounds)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
gray := color.GrayModel.Convert(mask.At(x, y)).(color.Gray)
withAlpha.SetNRGBA(x, y, color.NRGBA{R: gray.Y, G: gray.Y, B: gray.Y, A: gray.Y})
}
}
output, err := os.Create("mask_alpha.png")
if err != nil {
panic(err)
}
if err := png.Encode(output, withAlpha); err != nil {
panic(err)
}
if err := output.Close(); err != nil {
panic(err)
}
}
이미지 출력 커스터마이즈 (Customize Image Output)
다음 출력 옵션을 구성할 수 있어요.
- 크기(Size): 이미지 치수 (예:
1024x1024,1024x1536) - 품질(Quality): 렌더링 품질 (예:
low,medium,high) - 형식(Format): 파일 출력 형식
- 압축(Compression): JPEG 및 WebP 형식의 압축 수준 (0-100%)
- 배경(Background): 투명, 불투명, 또는 자동
size, quality, background는 auto 옵션을 지원하고, 이 경우 모델이 프롬프트에 기반해 최상의 옵션을 자동으로 선택해요.
크기와 품질 옵션
gpt-image-2.5-sunburst와 gpt-image-2.5-flare는 xhigh와 max 품질 설정을 추가했어요. 둘 다 기본값은 auto예요. 이전 GPT Image 모델은 high까지의 품질 설정을 지원해요.
| 설정 | 옵션 |
|---|---|
| 권장 크기 | 1024x1024 (정사각형), 1536x1024 (가로), 1024x1536 (세로) |
| 품질 | low, medium, high, xhigh, max, auto |
두 모델 모두 1536x864처럼 WIDTHxHEIGHT 문자열로 커스텀 치수도 지원해요. 너비와 높이는 16의 배수여야 하고, 종횡비는 1:3과 3:1 사이여야 하며, 어느 변도 3840 픽셀을 초과하면 안 돼요. 총 픽셀 수는 655,360과 8,294,400(4K) 사이여야 해요. 2560x1440 이상의 해상도는 실험적이에요.
두 모델 모두 투명 배경을 원한다면 background: "transparent"를 설정하고 output_format: "png" 또는 "webp"를 사용하세요.
빠른 초안이 필요하면 quality: "low"를 쓰세요. 최종 자산에서는 더 높은 품질 설정을 비교해 디테일, 지연 시간, 비용의 균형을 찾는 것이 좋아요.
출력 형식
Image API는 base64 인코딩된 이미지 데이터를 반환해요.
기본 형식은 png이고, jpeg 또는 webp를 요청할 수도 있어요.
jpeg나 webp를 쓰면 output_compression 파라미터로 압축 수준(0-100%)을 지정할 수 있어요. 예를 들어 output_compression=50은 이미지를 50% 압축해요.
jpeg는 png보다 빠르므로, 지연 시간이 걱정된다면 이 형식을 우선시하는 게 좋아요.
한계 (Limitations)
GPT Image 모델은 강력하고 다재다능한 이미지 생성 모델이지만 알아둬야 할 몇 가지 한계가 있어요.
- 지연 시간: 복잡한 프롬프트는 최대 2분까지 처리될 수 있어요.
- 텍스트 렌더링: 크게 개선됐지만 정밀한 텍스트 배치와 선명도에는 여전히 어려움을 겪을 수 있어요.
- 일관성: 일관된 이미지를 만들 수 있지만, 여러 세대에 걸쳐 반복 등장하는 캐릭터나 브랜드 요소의 시각적 일관성을 유지하는 데 어려움을 겪을 때가 있어요.
- 구성 제어: 지시 따르기가 개선됐지만 구조화되거나 레이아웃에 민감한 구성에서 요소를 정밀하게 배치하는 데 어려움을 겪을 수 있어요.
콘텐츠 중재 (Content Moderation)
모든 프롬프트와 생성된 이미지는 콘텐츠 정책에 따라 필터링돼요.
GPT Image 모델을 사용한 이미지 생성에서는 moderation 파라미터로 중재 엄격도를 제어할 수 있어요. 이 파라미터는 두 값을 지원해요.
auto(기본값): 연령에 부적절할 수 있는 특정 범주의 콘텐츠 생성을 제한하는 표준 필터링.low: 덜 제한적인 필터링.
차단된 요청 및 기타 오류 처리
이미지 생성 실패는 다른 API 오류와 같은 방식으로 처리해요: HTTP 상태나 SDK 예외 유형을 확인하고, 요청 ID를 기록하며, 인증·쿼터·속도 제한·서버 실패에 대한 오류 코드 가이드를 참고하세요. 일시적인 속도 제한과 서버 실패는 백오프하여 재시도해요. 쿼터 오류나 요청 변경이 필요한 이미지 생성 사용자 오류는 자동으로 재시도하지 마세요.
일부 이미지 생성 실패는 사용자가 고칠 수 있고 error.type = "image_generation_user_error"를 반환할 수 있어요. 프롬프트나 입력 이미지를 수정하지 않고 이런 오류를 자동 재시도하지 마세요. 프로그래밍 방식 처리는 error.code를 안정적인 구분자로 사용하세요.
error.code = "moderation_blocked"일 때 오류는 선택적으로 error.moderation_details 객체를 포함할 수 있어요.
{
"error": {
"type": "image_generation_user_error",
"code": "moderation_blocked",
"moderation_details": {
"moderation_stage": "input",
"categories": ["harassment"]
}
}
}
moderation_details 객체는 내부 분류기 라벨이나 점수를 노출하지 않으면서 거친 디버깅 컨텍스트를 제공해요.
moderation_stage는 다음과 같을 수 있어요.
input: 프롬프트 또는 요청 입력에서 차단이 발생했어요.output: 생성된 이미지 또는 다운스트림 출력 중재 단계에서 차단이 발생했어요.unknown: 기원을 파악하기 어려운 드문 폴백이에요.
categories는 거친 공개 라벨을 포함해요. 예를 들어 harassment, self-harm, sexual, violence 같은 값이 보일 수 있어요.
대부분의 앱에서는 최종 사용자 메시지를 일반적인 수준으로 유지하세요. moderation_details는 개발자 로그, 지원 워크플로, 분석, 가벼운 시정 힌트에 사용해요.
중재로 차단된 이미지 생성 오류 처리하기
import OpenAI from "openai";
const openai = new OpenAI();
try {
// The same error handling pattern applies to image generation requests,
// image edits, and Responses API tool calls that generate images.
await openai.images.generate({
model: "gpt-image-2.5-sunburst",
prompt: "Create a poster humiliating my coworker with insulting captions",
});
} catch (error) {
if (error?.code !== "moderation_blocked") {
throw error;
}
const moderationDetails = error.error?.moderation_details;
const categories = moderationDetails?.categories ?? [];
const stage = moderationDetails?.moderation_stage;
let hint =
"This request could not be completed because it did not meet safety requirements.";
if (categories.includes("harassment")) {
hint =
"Try removing abusive or targeting language and focus on neutral visual details instead.";
} else if (stage === "input") {
hint =
"Try revising the prompt or input images and submit the request again.";
} else if (stage === "output") {
hint =
"The generated result was blocked by a safety check. Try changing the prompt and generating again.";
}
console.error("Image generation blocked", {
request_id: error?.requestID,
code: error?.code,
moderation_details: moderationDetails,
});
console.log(hint);
}
import openai
from openai import OpenAI
client = OpenAI()
try:
# The same error handling pattern applies to image generation requests,
# image edits, and Responses API tool calls that generate images.
client.images.generate(
model="gpt-image-2.5-sunburst",
prompt="Create a poster humiliating my coworker with insulting captions",
)
except openai.BadRequestError as error:
if error.code != "moderation_blocked":
raise
error_body = error.body if isinstance(error.body, dict) else {}
moderation_details = error_body.get("moderation_details") or {}
categories = moderation_details.get("categories") or []
stage = moderation_details.get("moderation_stage")
hint = "This request could not be completed because it did not meet safety requirements."
if "harassment" in categories:
hint = "Try removing abusive or targeting language and focus on neutral visual details instead."
elif stage == "input":
hint = "Try revising the prompt or input images and submit the request again."
elif stage == "output":
hint = "The generated result was blocked by a safety check. Try changing the prompt and generating again."
print(
"Image generation blocked",
{
"request_id": error.request_id,
"code": error.code,
"moderation_details": moderation_details,
},
)
print(hint)
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"slices"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
_, err := client.Images.Generate(context.Background(), openai.ImageGenerateParams{
Model: openai.ImageModel("gpt-image-2.5-sunburst"),
Prompt: "Create a poster humiliating my coworker with insulting captions",
})
if err == nil {
return
}
var apiError *openai.Error
if !errors.As(err, &apiError) || apiError.Code != "moderation_blocked" {
panic(err)
}
var body struct {
ModerationDetails struct {
Categories []string `json:"categories"`
ModerationStage string `json:"moderation_stage"`
} `json:"moderation_details"`
}
if err := json.Unmarshal([]byte(apiError.RawJSON()), &body); err != nil {
panic(err)
}
hint := "This request could not be completed because it did not meet safety requirements."
if slices.Contains(body.ModerationDetails.Categories, "harassment") {
hint = "Try removing abusive or targeting language and focus on neutral visual details instead."
} else if body.ModerationDetails.ModerationStage == "input" {
hint = "Try revising the prompt or input images and submit the request again."
} else if body.ModerationDetails.ModerationStage == "output" {
hint = "The generated result was blocked by a safety check. Try changing the prompt and generating again."
}
fmt.Printf("Image generation blocked (%s): %s\n", apiError.Code, hint)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.errors.BadRequestException;
import com.openai.models.images.ImageGenerateParams;
import java.util.List;
import java.util.Map;
try {
var images =
client
.images()
.generate(
ImageGenerateParams.builder()
.model("gpt-image-2.5-sunburst")
.prompt("Create a poster humiliating my coworker with insulting captions")
.build());
System.out.println(images.data().orElseThrow().get(0).b64Json().orElseThrow());
} catch (BadRequestException error) {
if (!error.code().orElse("").equals("moderation_blocked")) {
throw error;
}
Map<?, ?> body = error.body().convert(Map.class);
Object detailsValue = body.get("moderation_details");
Map<?, ?> details = detailsValue instanceof Map<?, ?> values ? values : Map.of();
Object categories = details.get("categories");
Object stage = details.get("moderation_stage");
String hint = "This request did not meet safety requirements.";
if (categories instanceof List<?> values && values.contains("harassment")) {
hint = "Remove abusive or targeting language and focus on neutral visual details.";
} else if ("input".equals(stage)) {
hint = "Revise the prompt or input images, then submit the request again.";
} else if ("output".equals(stage)) {
hint = "Change the prompt and generate again; the generated result was blocked.";
}
System.err.println("Image generation blocked (" + error.code().orElseThrow() + "): " + hint);
}
require "openai"
client = OpenAI::Client.new
begin
client.images.generate(
model: "gpt-image-2.5-sunburst",
prompt: "Create a poster humiliating my coworker with insulting captions"
)
rescue OpenAI::Errors::BadRequestError => error
raise unless error.code == "moderation_blocked"
body = Hash.try_convert(error.body) || {}
moderation_details = body[:moderation_details] || body["moderation_details"] || {}
categories = moderation_details[:categories] || moderation_details["categories"] || []
stage = moderation_details[:moderation_stage] || moderation_details["moderation_stage"]
hint = "This request did not meet safety requirements."
if categories.include?("harassment")
hint = "Remove abusive or targeting language and focus on neutral visual details."
elsif stage == "input"
hint = "Revise the prompt or input images, then submit the request again."
elsif stage == "output"
hint = "Change the prompt and generate again; the generated result was blocked."
end
warn("Image generation blocked (#{error.code}): #{hint}")
end
지원 모델 (Supported models)
Responses API에서 이미지 생성을 사용할 때, gpt-5 및 최신 모델이 이미지 생성 도구를 지원해야 해요. 원하는 모델이 이미지 생성 도구를 쓸 수 있는지 모델 상세 페이지에서 확인하세요.
비용과 지연 시간
GPT Image 2.5 비용
Responses API 요청에는 이미지 생성 비용 외에도 메인라인 모델의 토큰 사용이 포함돼요.
두 GPT Image 2.5 모델은 같은 토큰 요금을 사용해요: 이미지 입력 토큰 백만 개당 $8, 캐시된 이미지 입력 토큰 백만 개당 $2, 이미지 출력 토큰 백만 개당 $30, 텍스트 입력 토큰 백만 개당 $5, 캐시된 텍스트 입력 토큰 백만 개당 $1.25예요. pricing을 참고하세요.
프롬프트, 크기, 품질 설정의 토큰 소비를 측정하려면 응답의 usage를 사용하세요. 같은 토큰 요금이 이미지당 같은 비용을 의미하지는 않아요: 토큰 소비는 모델과 품질 설정에 따라 달라질 수 있기 때문이에요. 이전 모델의 가격 예시는 이전 GPT Image 모델을 참고하세요.
GPT Image 2.5 및 GPT Image 2 출력 토큰
모델, 품질, 크기를 선택해 출력 토큰과 이미지 출력 비용을 추정해 보세요.
gpt-image-2.5-sunburst와 gpt-image-2.5-flare의 품질 옵션은 low, medium, high, xhigh, max예요.
gpt-image-2의 옵션은 low, medium, high예요.
모델들은 같은 품질 설정에서 다른 토큰 수를 쓸 수 있고, 이미지 출력 토큰당 같은 가격을 공유해요.
이 추정에는 명시적인 품질과 크기 값을 사용하세요. auto는 생성된 이미지에 의존해요.
부분 이미지 비용
partial_images 파라미터로 이미지 생성 스트리밍을 하고 싶다면, 각 부분 이미지마다 추가로 100개의 이미지 출력 토큰이 발생해요.
이전 GPT Image 모델 (Earlier GPT Image models)
아래 세부사항은 Sunburst나 Flare가 아닌 이전 모델에 적용돼요. 새 통합에는 위에서 설명한 GPT Image 2.5 모델 중 하나를 사용하세요.
GPT Image 2 설정과 입력 충실도
gpt-image-2는 아래 제약을 충족할 때 size 파라미터의 어떤 해상도라도 받아요. 정사각형 이미지가 보통 생성이 가장 빨라요.
| 항목 | 내용 |
|---|---|
| 인기 크기 | 1024x1024 (정사각형), 1536x1024 (가로), 1024x1536 (세로), 2048x2048 (2K 정사각형), 2048x1152 (2K 가로), 3840x2160 (4K 가로), 2160x3840 (4K 세로), auto (기본값) |
| 크기 제약 | 최대 변 길이 ≤ 3840px, 두 변 모두 16px의 배수, 긴 변:짧은 변 비율 ≤ 3:1, 총 픽셀 ≥ 655,360 및 ≤ 8,294,400 |
| 품질 옵션 | low, medium, high, auto (기본값) |
이미지 입력 충실도
input_fidelity 파라미터는 편집 및 참조 이미지 워크플로 중 모델이 입력 이미지의 디테일을 얼마나 강하게 보존하는지 제어해요. gpt-image-2에서는 이 파라미터를 생략하세요. API가 모든 이미지 입력을 자동으로 높은 충실도로 처리하기 때문에 이 값을 변경할 수 없어요.
gpt-image-2는 항상 이미지 입력을 고충실도로 처리하므로, 참조 이미지를 포함한 편집 요청에서 이미지 입력 토큰이 더 높을 수 있어요. 비용 영향을 이해하려면 비전 비용 섹션을 참고하세요.
이전 모델 가격 예시
gpt-image-2 이전 모델
gpt-image-2 이전의 GPT Image 모델은 먼저 특수한 이미지 토큰을 생성해 이미지를 만들어요. 지연 시간과 최종 비용 모두 이미지 렌더링에 필요한 토큰 수에 비례해요. 이미지 크기가 크고 품질 설정이 높을수록 토큰이 더 많아 지죠.
생성되는 토큰 수는 이미지 크기와 품질에 따라 달라져요.
| 품질 | 정사각형 (1024×1024) | 세로 (1024×1536) | 가로 (1536×1024) |
|---|---|---|---|
| Low | 272 토큰 | 408 토큰 | 400 토큰 |
| Medium | 1056 토큰 | 1584 토큰 | 1568 토큰 |
| High | 4160 토큰 | 6240 토큰 | 6208 토큰 |
입력 토큰도 함께 고려해야 해요: 프롬프트의 텍스트 토큰과, 이미지를 편집할 때 입력 이미지의 이미지 토큰이에요.
gpt-image-2는 항상 이미지 입력을 고충실도로 처리하므로 참조 이미지를 포함한 편집 요청은 더 많은 입력 토큰을 사용할 수 있어요.
현재 텍스트·이미지 토큰 가격은 가격 페이지를 참고하고, 아래 비용 계산 섹션으로 요청 비용을 추정하세요.
최종 비용은 다음의 합이에요.
- 입력 텍스트 토큰
- edits 엔드포인트를 쓴다면 입력 이미지 토큰
- 이미지 출력 토큰
비용 계산
아래 가격 계산기로 GPT Image 모델의 요청 비용을 추정해 보세요.
gpt-image-2는 수천 가지의 유효 해상도를 지원하는데, 아래 표는 비교를 위해 이전 GPT Image 모델에서 쓰던 것과 같은 크기들을 나열해요. GPT Image 1.5, GPT Image 1, GPT Image 1 Mini의 경우 레거시 이미지당 출력 가격 표도 아래에 함께 나열돼요. 전체 요청 비용을 추정할 때는 텍스트와 이미지 입력 토큰도 여전히 고려해야 해요.
같은 품질 설정에서 더 큰 비정사각형 해상도가 더 작거나 정사각형 해상도보다 출력 토큰을 적게 만들 수 있어요.
| 모델 | 품질 | 1024 x 1024 | 1024 x 1536 | 1536 x 1024 |
|---|---|---|---|---|
| GPT Image 2 (추가 크기 사용 가능) | Low | $0.006 | $0.005 | $0.005 |
| Medium | $0.053 | $0.041 | $0.041 | |
| High | $0.211 | $0.165 | $0.165 | |
| GPT Image 1.5 | Low | $0.009 | $0.013 | $0.013 |
| Medium | $0.034 | $0.05 | $0.05 | |
| High | $0.133 | $0.2 | $0.2 | |
| GPT Image 1 | Low | $0.011 | $0.016 | $0.016 |
| Medium | $0.042 | $0.063 | $0.063 | |
| High | $0.167 | $0.25 | $0.25 | |
| GPT Image 1 Mini | Low | $0.005 | $0.006 | $0.006 |
| Medium | $0.011 | $0.015 | $0.015 | |
| High | $0.036 | $0.052 | $0.052 |
더 알아보기 (Learn more)
- 이미지와 비전 (Images and vision) — 모델의 비전 능력으로 이미지를 분석하고 이미지 생성 도구를 함께 다루세요.
- 가격 페이지 — 이미지 생성의 현재 요금을 확인하세요.