Image Generation

UniLM.jl supports image generation via the OpenAI Images API using models like gpt-image-2.

Basic Usage

result = generate_image(
    "A watercolor painting of a friendly robot reading a Julia programming book",
    size="1024x1024",
    quality="medium"
)
println("Success: ", result isa ImageSuccess)
if result isa ImageSuccess
    imgs = image_data(result)
    println("Images: ", length(imgs))
    println("Base64 length: ", length(imgs[1]))
    save_image(imgs[1], joinpath(@__DIR__, "..", "assets", "generated_robot.png"))
    println("Image saved to assets/generated_robot.png")
else
    println("Images: 0")
    println("Image generation failed — see result for details")
end

Generated image: A watercolor painting of a friendly robot reading a Julia programming book

The ImageGeneration Type

For full control, construct an ImageGeneration object:

ig = ImageGeneration(
    prompt="A minimalist logo for a Julia programming package",
    model="gpt-image-2",
    size="1024x1024",
    quality="high",
    background="transparent",
    output_format="png"
)
println("Model: ", ig.model)
println("Size: ", ig.size)
println("Quality: ", ig.quality)
println("\nRequest JSON:")
println(JSON.json(ig))
Model: gpt-image-2
Size: 1024x1024
Quality: high

Request JSON:
{"background":"transparent","model":"gpt-image-2","output_format":"png","prompt":"A minimalist logo for a Julia programming package","quality":"high","size":"1024x1024"}

Configuration Options

ParameterValuesDefault
model"gpt-image-2""" (see below)
size"1024x1024", "1536x1024", "1024x1536", "auto"API default
quality"low", "medium", "high", "auto"API default
background"transparent", "opaque", "auto"API default
output_format"png", "webp", "jpeg"API default
output_compression0100 (for webp/jpeg)API default
n1101
input_fidelityprovider-definedAPI default
moderationprovider-definedAPI default
`model` is a sentinel, not a resolved default

Unlike Chat, ImageGeneration does not resolve its model at construction. The field holds "" and resolves only when the request is serialized — to "gpt-image-2" for OpenAI — so ImageGeneration(prompt="…").model reads back as the empty string. Pass model= explicitly if you need to read it, or inspect JSON.json(ig) to see what will go on the wire. A service with no default image model throws ArgumentError at serialization.

Multiple Images

Generate multiple images in a single request:

result = generate_image("A cute robot learning to program", n=3, size="1024x1024")

if result isa ImageSuccess
    imgs = image_data(result)
    for (i, img) in enumerate(imgs)
        save_image(img, "robot_$i.png")
    end
end

Transparent Backgrounds

Perfect for logos and icons:

result = generate_image(
    "A simple geometric icon of a butterfly",
    background="transparent",
    output_format="png",
    quality="high"
)

if result isa ImageSuccess
    save_image(image_data(result)[1], "butterfly_icon.png")
    # => PNG with transparent background
end

Result Structure

# Show the type hierarchy for image results
println("ImageSuccess <: ", supertype(ImageSuccess))
println("ImageFailure <: ", supertype(ImageFailure))
println("ImageCallError <: ", supertype(ImageCallError))
ImageSuccess <: LLMRequestResponse
ImageFailure <: LLMRequestResponse
ImageCallError <: LLMRequestResponse
result = generate_image("A sunset over mountains")

if result isa ImageSuccess
    r = result.response

    r.created                 # Unix timestamp
    r.data                    # Vector{ImageObject}
    r.data[1].b64_json        # base64-encoded image data
    r.data[1].revised_prompt  # revised prompt (may be nothing)
    r.usage                   # token usage Dict

    # Convenience accessors
    image_data(result)        # Vector{String} of base64 data
    save_image(image_data(result)[1], "sunset.png")
end

Saving Images

The save_image helper decodes base64 and writes to disk:

# Demonstrate save_image with a tiny test payload
tmpfile = tempname() * ".txt"
UniLM.save_image("aGVsbG8=", tmpfile)  # "hello" in base64
println("File saved to: ", basename(tmpfile))
println("Contents: ", read(tmpfile, String))
rm(tmpfile)
File saved to: jl_Uvwz8PErG9.txt
Contents: hello

Error Handling

result = generate_image("A sunset over mountains")

if result isa ImageSuccess
    save_image(image_data(result)[1], "sunset.png")
elseif result isa ImageFailure
    @warn "HTTP $(result.status): $(result.response)"
elseif result isa ImageCallError
    @error "Call failed: $(result.error)"
end

Editing Images

edit_image edits an existing image from a text prompt, optionally masked to an inpainting region. The convenience form takes the source image (a file path, or a vector of paths) and the prompt; an optional mask path restricts edits to the mask's transparent area:

# Inpaint: change only the masked region, described by the prompt
result = edit_image("room.png", "Add a large window with a sea view"; mask="room_mask.png")

if result isa ImageSuccess
    save_image(image_data(result)[1], "room_edited.png")
else
    println("Edit failed — see result for details")
end

For full control, build an ImageEdit and call edit_image(e). The model defaults to gpt-image-2; image editing needs the :image_edits capability (OpenAI), and other providers reject it at request time.

Retry Behaviour

generate_image retries transient HTTP statuses (408, 429, 500, 502, 503, 504, 529) within the request budget configured by RequestConfig (max_attempts, default 3), with exponential backoff and jitter; on 429 the Retry-After header is respected. Override per call with config=RequestConfig(...).

See Also