Image Generation
The Go AI SDK provides the ai.GenerateImage() function to generate images based on a given prompt using an image model.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{APIKey: os.Getenv("OPENAI_API_KEY")})
imageModel, _ := provider.ImageModel("dall-e-3")
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}
// Access image data
fmt.Printf("Image MIME type: %s\n", result.Image.MediaType)
fmt.Printf("Image size: %d bytes\n", len(result.Image.Data))
// Save image to file
err = os.WriteFile("generated.png", result.Image.Data, 0644)
if err != nil {
log.Fatal(err)
}
fmt.Println("Image saved to generated.png")
}
You can access the image data in different formats:
// As bytes
imageBytes := result.Image.Data
// As base64 string
base64String := result.Image.Base64()
// Get image MIME type
mimeType := result.Image.MediaType
Settings
Size and Aspect Ratio
Depending on the model, you can specify either the size or the aspect ratio.
Size
The size is specified as a string in the format {width}x{height}. Models only support specific sizes, and the supported sizes vary by model and provider.
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1024x1024",
})
Aspect Ratio
The aspect ratio is specified as a string in the format {width}:{height}. Models only support specific aspect ratios, which vary by model and provider.
provider := google.New(google.Config{APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY")})
imageModel, _ := provider.ImageModel("imagen-4.0-generate-001")
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1920x1080", // Automatically converts to 16:9 aspect ratio
})
Generating Multiple Images
GenerateImage supports generating multiple images at once:
n := 4 // Number of images to generate
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
N: &n,
})
if err != nil {
log.Fatal(err)
}
// Access all images
for i, image := range result.Images {
filename := fmt.Sprintf("image-%d.png", i+1)
err := os.WriteFile(filename, image.Data, 0644)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Saved %s\n", filename)
}
Note:
GenerateImagewill automatically batch requests as needed to generate the requested number of images.
Each image model has an internal limit on how many images it can generate in a single API call. The SDK manages this automatically by batching requests appropriately. By default, the SDK uses provider-documented limits (e.g., DALL-E 3 can only generate 1 image per call, while DALL-E 2 supports up to 10).
You can override this behavior using MaxImagesPerCall:
n := 10 // Will make 2 calls of 5 images each
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
MaxImagesPerCall: 5, // Override default batch size
N: &n,
})
Providing a Seed
You can provide a seed to control the output of the image generation process. If supported by the model, the same seed will always produce the same image.
seed := 1234567890
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Seed: &seed,
})
Provider-Specific Settings
Image models often have provider- or model-specific settings. You can pass such settings using the ProviderOptions parameter:
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1024x1024",
ProviderOptions: map[string]interface{}{
"openai": map[string]interface{}{
"style": "vivid",
"quality": "hd",
},
},
})
Timeouts with Context
Use Go's context for timeouts and cancellation:
// Timeout after 60 seconds
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("Image generation timed out")
}
log.Fatal(err)
}
Custom Headers
Add custom headers to the image generation request:
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Headers: map[string]string{
"X-Custom-Header": "custom-value",
},
})
Warnings
If the model returns warnings, they will be available in the Warnings field:
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}
for _, warning := range result.Warnings {
fmt.Printf("Warning: %s\n", warning.Message)
}
Additional Provider Metadata
Some providers expose additional metadata for the result:
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}
// Access provider-specific metadata
if metadata, ok := result.ProviderMetadata["openai"].(map[string]interface{}); ok {
if images, ok := metadata["images"].([]interface{}); ok && len(images) > 0 {
if imageMetadata, ok := images[0].(map[string]interface{}); ok {
if revisedPrompt, ok := imageMetadata["revisedPrompt"].(string); ok {
fmt.Printf("Original prompt: %s\n", "Santa Claus driving a Cadillac")
fmt.Printf("Revised prompt: %s\n", revisedPrompt)
}
}
}
}
Error Handling
Handle image generation errors:
import providererrors "github.com/digitallysavvy/go-ai/pkg/provider/errors"
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Generate an image",
})
if err != nil {
// Check for specific error types
var noImageErr *ai.NoImageGeneratedError
var rateLimitErr *providererrors.RateLimitError
if errors.As(err, &noImageErr) {
fmt.Println("No image was generated")
} else if errors.As(err, &rateLimitErr) {
fmt.Println("Rate limit exceeded")
} else {
fmt.Printf("Error: %v\n", err)
}
return
}
Practical Examples
Saving Images in Different Formats
func saveImage(image []byte, mimeType string, filename string) error {
ext := "png"
if mimeType == "image/jpeg" {
ext = "jpg"
}
return os.WriteFile(fmt.Sprintf("%s.%s", filename, ext), image, 0644)
}
result, _ := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Beautiful sunset",
})
saveImage(result.Image.Data, result.Image.MediaType, "sunset")
Generating Image Variations
Generate multiple variations of the same prompt:
func generateVariations(ctx context.Context, model provider.ImageModel, prompt string, count int) ([]types.GeneratedFile, error) {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
N: &count,
})
if err != nil {
return nil, err
}
return result.Images, nil
}
images, _ := generateVariations(ctx, imageModel, "Abstract art with vibrant colors", 4)
for i, img := range images {
os.WriteFile(fmt.Sprintf("variation-%d.png", i+1), img.Data, 0644)
}
Batch Image Generation
Generate multiple different images:
prompts := []string{
"A serene mountain landscape",
"A bustling city street at night",
"An underwater coral reef",
"A cozy coffee shop interior",
}
for i, prompt := range prompts {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: prompt,
})
if err != nil {
log.Printf("Error generating image %d: %v\n", i+1, err)
continue
}
filename := fmt.Sprintf("batch-%d.png", i+1)
os.WriteFile(filename, result.Image.Data, 0644)
fmt.Printf("Generated %s: %s\n", filename, prompt)
}
Image Generation with Retry Logic
func generateImageWithRetry(ctx context.Context, model provider.ImageModel, prompt string, maxRetries int) (*ai.GenerateImageResult, error) {
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
if attempt > 0 {
fmt.Printf("Retry attempt %d/%d\n", attempt, maxRetries)
time.Sleep(time.Duration(attempt) * time.Second)
}
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
})
if err == nil {
return result, nil
}
lastErr = err
// Don't retry on certain errors
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
break
}
}
return nil, fmt.Errorf("failed after %d attempts: %w", maxRetries+1, lastErr)
}
Google Image Generation Examples
Google Generative AI - Imagen 4.0
// High-quality image generation with Imagen 4.0
googleProvider := google.New(google.Config{
APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY"),
})
imagenModel, _ := googleProvider.ImageModel("imagen-4.0-generate-001")
n := 1
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imagenModel,
Prompt: "A serene mountain landscape at sunset with dramatic clouds",
N: &n,
Size: "1024x1024", // Square 1:1 aspect ratio
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("imagen_4_output.png", result.Image.Data, 0644)
fmt.Printf("Generated with Imagen 4.0: %d bytes\n", len(result.Image.Data))
Google Generative AI - Gemini Flash Image
// Fast image generation with Gemini
geminiModel, _ := googleProvider.ImageModel("gemini-2.5-flash-image")
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: geminiModel,
Prompt: "Abstract colorful art with geometric shapes and vibrant patterns",
Size: "1920x1080", // Widescreen 16:9
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("gemini_output.png", result.Image.Data, 0644)
Google Vertex AI - Imagen 3.0
// Enterprise-grade image generation with Vertex AI
vertexProvider, err := googlevertex.New(googlevertex.Config{
Project: os.Getenv("GOOGLE_VERTEX_PROJECT"),
Location: os.Getenv("GOOGLE_VERTEX_LOCATION"),
AccessToken: os.Getenv("GOOGLE_VERTEX_ACCESS_TOKEN"),
})
if err != nil {
log.Fatal(err)
}
vertexModel, _ := vertexProvider.ImageModel("imagen-3.0-generate-001")
n := 1
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: vertexModel,
Prompt: "A futuristic cityscape at night with neon lights",
N: &n,
Size: "1920x1080", // 16:9 aspect ratio
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("vertex_imagen_output.png", result.Image.Data, 0644)
Comparing Google Models
prompts := []string{
"A magical forest with glowing mushrooms",
"Cyberpunk city street at night",
"Mountain landscape with aurora borealis",
}
models := map[string]provider.ImageModel{
"imagen-4.0": imagenModel,
"gemini-flash": geminiModel,
"vertex-imagen": vertexModel,
}
for name, model := range models {
for i, prompt := range prompts {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
Size: "1024x1024",
})
if err != nil {
log.Printf("Error with %s: %v\n", name, err)
continue
}
filename := fmt.Sprintf("%s_%d.png", name, i+1)
os.WriteFile(filename, result.Image.Data, 0644)
fmt.Printf("✓ Generated %s\n", filename)
}
}
Image Models
Several providers offer image generation models:
| Provider | Model | Supported Sizes/Aspect Ratios |
|---|---|---|
| xAI | grok-imagine-image | Flexible aspect ratios (1:1, 16:9, 9:16, 4:3, etc.) |
| OpenAI | gpt-image-1 | 1024x1024, 1536x1024, 1024x1536 |
| OpenAI | dall-e-3 | 1024x1024, 1792x1024, 1024x1792 |
| OpenAI | dall-e-2 | 256x256, 512x512, 1024x1024 |
| Amazon Bedrock | amazon.nova-canvas-v1:0 | 320-4096 (multiples of 16) |
| Fal | fal-ai/flux/dev | 1:1, 3:4, 4:3, 9:16, 16:9, 9:21, 21:9 |
| Fal | fal-ai/flux-pro/v1.1-ultra | 1:1, 3:4, 4:3, 9:16, 16:9, 9:21, 21:9 |
imagen-4.0-generate-001 | 1:1, 3:4, 4:3, 9:16, 16:9 | |
gemini-2.5-flash-image | 1:1, 3:4, 4:3, 9:16, 16:9 | |
| Google Vertex | imagen-3.0-generate-001 | 1:1, 3:4, 4:3, 9:16, 16:9 |
| Black Forest Labs | flux-pro-1.1-ultra | 3:7 to 7:3 aspect ratios |
| Stability AI | Various via providers | Multiple sizes supported |
Example with Different Providers
// XAI (Grok)
xaiProvider := xai.New(xai.Config{APIKey: os.Getenv("XAI_API_KEY")})
grokModel, _ := xaiProvider.ImageModel("grok-imagine-image")
// OpenAI
openaiProvider := openai.New(openai.Config{APIKey: os.Getenv("OPENAI_API_KEY")})
dalleModel, _ := openaiProvider.ImageModel("dall-e-3")
// Google Generative AI - Imagen 4.0
googleProvider := google.New(google.Config{APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY")})
imagenModel, _ := googleProvider.ImageModel("imagen-4.0-generate-001")
// Google Generative AI - Gemini Image
geminiImageModel, _ := googleProvider.ImageModel("gemini-2.5-flash-image")
// Google Vertex AI - Imagen 3.0
vertexProvider, _ := googlevertex.New(googlevertex.Config{
Project: os.Getenv("GOOGLE_VERTEX_PROJECT"),
Location: os.Getenv("GOOGLE_VERTEX_LOCATION"),
AccessToken: os.Getenv("GOOGLE_VERTEX_ACCESS_TOKEN"),
})
vertexImagenModel, _ := vertexProvider.ImageModel("imagen-3.0-generate-001")
// Fal
falProvider := fal.New(fal.Config{APIKey: os.Getenv("FAL_API_KEY")})
fluxModel, _ := falProvider.ImageModel("fal-ai/flux/dev")
// Use any model with the same API
result, _ := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imagenModel, // or grokModel, dalleModel, geminiImageModel, vertexImagenModel, or fluxModel
Prompt: "A beautiful landscape",
})
Advanced Features
Image Editing
Some providers support editing existing images with natural language instructions:
// XAI image editing
imageData, _ := os.ReadFile("source.jpg")
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Change the sky to vibrant sunset colors",
Files: []provider.ImageFile{
{
Type: "file",
Data: imageData,
MediaType: "image/jpeg",
},
},
})
Checking File and Mask Support
Not every model that accepts Files / Mask actually consumes them for editing; some silently ignore them and return an unrelated fresh generation. A model can optionally advertise support through SupportsFileInputs() *bool / SupportsMaskInputs() *bool, read via provider.ImageModelSupportsFileInputs / provider.ImageModelSupportsMaskInputs. nil means unknown — only route an editing request to a model when the result is a non-nil true:
if supported := provider.ImageModelSupportsFileInputs(model); supported != nil && *supported {
// safe to pass Files for image editing
}
Image Inpainting
Fill specific areas of an image with new content using masks:
sourceImage, _ := os.ReadFile("source.jpg")
maskImage, _ := os.ReadFile("mask.png")
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Add a rainbow in the masked area",
Files: []provider.ImageFile{
{Type: "file", Data: sourceImage, MediaType: "image/jpeg"},
},
Mask: &provider.ImageFile{
Type: "file",
Data: maskImage,
MediaType: "image/png",
},
})
Mask Requirements:
- White pixels (255,255,255) indicate areas to modify
- Black pixels (0,0,0) indicate areas to preserve
- Mask should match source image dimensions
Image Variations
Generate multiple variations of a source image:
sourceImage, _ := os.ReadFile("source.jpg")
n := 4
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Generate creative variations with different styles",
N: &n,
Files: []provider.ImageFile{
{Type: "file", Data: sourceImage, MediaType: "image/jpeg"},
},
})
Providers that can return multiple images expose every image through result.Images. Low-level provider results also preserve provider-returned base64 strings in result.Base64Images; the high-level ai.GenerateImage helper decodes those strings into GeneratedFile.Data so JSON output contains the expected base64 image data.
Best Practices
- Set Timeouts: Image generation can be slow; always use context with timeout
- Handle Errors: Implement proper error handling and retry logic
- Validate Prompts: Ensure prompts are appropriate and within provider guidelines
- Choose Right Model: Different models excel at different styles and use cases
- Use Appropriate Sizes: Request sizes supported by the model
- Save Efficiently: Use appropriate image formats and compression
- Monitor Costs: Track image generation usage and costs
- Respect Rate Limits: Implement rate limiting for bulk generation
- Cache Results: Cache generated images when appropriate
- Test Prompts: Iterate on prompts to get desired results
Next Steps
- Learn about Speech Generation
- Explore Provider Documentation
- See Examples