Skip to content
Blog

Image Generation APIs and Structured Prompts

Turn image generation from a coin flip into a repeatable pipeline. Structure your prompt, set aspect ratio and size, ground with search, and wire it into code with Gemini image models.

Published on August 8, 2026

AI Assistant

Drawing a picture is output that looks right but is secretly easy to get wrong: wrong aspect ratio, garbled text, and compositions that miss the prompt entirely. The fix is treating the image prompt like a structured pipeline input — not a vibe sentence. In 2026, Gemini’s image models (gemini-3-pro-image, gemini-3.1-flash-image) finally make that structure explicit with parameters, search grounding, and even interleaved text+image output.

The models

ModelStrengthOutput
gemini-3-pro-image (“Nano Banana Pro”)Complex compositions, brand consistency, precision editingImage + interleaved text
gemini-3.1-flash-image (“Nano Banana 2”)High-ish volume, fast, grounded image searchImage (1–4K)

Both support structured output schemes (JSON) and images; the pro model also interleaves text and image in one response (gemini-3-pro-image) for infographics, tutorials, and multi-step visual guides.

Structured prompts: treat the prompt as data

The reliability killer in image generation is free text. Define a prompt object in code, validate it, and merge it into a template:

from dataclasses import dataclass

@dataclass
class ImageSpec:
    subject: str      # "a coral reef"
    style: str        # "photorealistic macro, warm light"
    composition: str  # "medium shot, rule of thirds, subject right"
    palette: str      # "teal and amber"
    mood: str         # "calm, exploratory"
    background: str   # "clean gradient, blurred"

def build_prompt(s: ImageSpec, extra: str = "") -> str:
    base = (
        f"{s.subject}. Style: {s.style}. "
        f"Composition: {s.composition}. Palette: {s.palette}. "
        f"Mood: {s.mood}. Background: {s.background}."
    )
    return f"{base}\n{extra}".strip()

Then generate with explicit response config:

from google import genai
from google.genai import types

client = genai.Client()
spec = ImageSpec(subject="a robotic hummingbird sipping from a circuit board flower",
                 style="photorealistic macro",
                 composition="close-up, rule of thirds",
                 palette="copper, emerald, ivory",
                 mood="wonder and stillness",
                 background="dark studio backdrop")

response = client.models.generate_content(
    model="gemini-3-pro-image",
    contents=build_prompt(spec),
    config=types.GenerateContentConfig(
        response_format={"image": {"aspect_ratio": "16:9", "image_size": "4K"}}
    ),
)
for part in response.candidates[0].content.parts:
    if part.inline_data:
        with open("hummingbird.png", "wb") as f:
            f.write(part.inline_data.data)

Constants worth encoding (aspect_ratio, image_size: "1K"|"2K"|"4K") go in the spec, not in the prose prompt.

Grounded generation: let the model verify first

Gemini 3 image models can think, then search the web before drawing — so an “infographic of current weather” is grounded:

response = client.models.generate_content(
    model="gemini-3-pro-image",
    contents="Generate an infographic of the current weather in Tokyo.",
    config=types.GenerateContentConfig(
        tools=[{"google_search": {}}],
        response_format={"image": {"aspect_ratio": "16:9", "image_size": "4K"}},
    ),
)

Same shape as the previous call — you just added search. That’s the structural upgrade: grounding, aspect ratio, and size are parameters, so your prompt stays clean and your pipeline stays data-driven.

Multi-turn editing with image signatures

Conversational editing (e.g., “make the background a sunset”) works because the model carries a thoughtSignature between turns. Keep your image-editing loop storing the last response and passing it back with the new instruction — treat the signature like a session token, required for any follow-up edit.

Putting It All Together

  • Define an ImageSpec (or Pydantic model) and validate it before sending.
  • Set response_format.image.aspect_ratio + .image_size explicitly — never rely on the default square.
  • Check the response part-by-part; for gemini-3-pro-image, iterate all parts to capture interleaved text+image, not just output_image.
  • Add grounding via tools=[{"google_search": {}}] for anything with facts (charts, weather, product snapshots).

Conclusion & Next Steps

Structuring controls the reliability we previously lacked in image gen: prompt as data, response config as constants, grounding for facts, and signatures for edits. Next: move your spec into a JSON Schema fitted to your product, add a render queue that retries on blocked responses, run an eval that scores aspect-ratio match and text fidelity, and connect the pipeline to your CMS so every marketing banner keeps the brand palette tokenized.

References / Sources