API de generación de imágenes de Gemini en Python: ejemplo de código

Un recorrido funcional en Python por la API de generación de imágenes de Gemini con el modelo actual gemini-3.1-flash-image y la Interactions API. Genera tu primera imagen, controla la relación de aspecto y la resolución, edita fotos, reintenta las llamadas fallidas y calcula el costo real por imagen.

API de generación de imágenes de Gemini en Python: ejemplo de código
Cristian Da Conceicao
Fundador de Picasso IA

La mayoría de los tutoriales de imágenes de Gemini todavía llaman a gemini-2.5-flash-image, y la página de precios de Google indica que ese modelo está obsoleto, con una fecha de desactivación del 2 de octubre de 2026. Esa fecha ya ha pasado, así que los fragmentos basados en él deben considerarse rotos. Esta página usa el modelo actual, gemini-3.1-flash-image, y la Interactions API que la propia documentación de Google ya presenta en primer lugar.

Pasarás de una carpeta vacía a un script funcional que genera una imagen, controla su tamaño, edita una foto existente, guarda una salida mixta de texto e imagen y sobrevive a los límites de tasa. Cada fragmento es lo bastante corto como para pegarlo en un archivo y ejecutarlo. Una imagen de 1K con el modelo Flash estándar cuesta unos $0.067, así que las pruebas salen baratas.

Qué necesitas antes de programar

Desarrollador escribiendo código en un escritorio de madera con una taza de café con luz de la mañana

Tres cosas te separan de tu primera imagen: una instalación reciente de Python 3, una credencial de Google AI Studio y un proyecto con la facturación activada. La página de precios de Google no muestra ningún nivel gratuito para los modelos de imagen de Gemini, así que un proyecto sin facturación probablemente será rechazado en la primera llamada.

Instala el SDK

Un solo paquete hace todo:

pip install -U google-genai

La Interactions API necesita google-genai 2.3.0 o posterior, por eso importa la marca -U. Ejecuta pip show google-genai si algún fragmento de abajo falla con un error de atributo en client.interactions.

Configura tu credencial

Crea una credencial en Google AI Studio y expórtala como variable de entorno con el nombre exacto que aparece abajo. El SDK lee esa variable por sí solo, así que tu script nunca tiene que contener el secreto.

export GEMINI_API_KEY="paste-your-credential-here"

En Windows PowerShell, la misma línea es $env:GEMINI_API_KEY = "paste-your-credential-here".

💡 Nunca pegues la credencial en un script que vaya a Git. Guárdala en una variable de entorno o en un archivo .env que tu .gitignore ya excluya.

Elige un modelo

Google enumera ahora cuatro modelos de imagen. Tres están vigentes y uno está retirado.

ID del modeloTamañosPrecio por imagenIdeal para
gemini-3.1-flash-lite-imageSolo 1Kunos $0.034Trabajos masivos, miniaturas
gemini-3.1-flash-image0.5K, 1K, 2K, 4K$0.045, $0.067, $0.101, $0.151Opción predeterminada para la mayoría de scripts
gemini-3-pro-image1K, 2K, 4K$0.134 (1K y 2K), $0.24 (4K)Prompts complejos y de varias partes
gemini-2.5-flash-imagen/d$0.039Retirado, no lo uses

Los precios proceden de la página de precios de Google en el momento de escribir esto. Vuelve a comprobarlos antes de una ejecución grande.

¿Cómo eliges? Empieza con gemini-3.1-flash-image. Es el único modelo vigente que ofrece los cuatro tamaños, así que un mismo camino de código sirve para miniaturas y para archivos de impresión. Cambia a Flash Lite cuando generes miles de imágenes pequeñas y cada centavo por imagen cuente. Recurre a Pro cuando un prompt tenga muchas partes, como un cartel con varios elementos etiquetados, y un modelo más barato siga omitiendo detalles. Como los tres modelos vigentes comparten la misma forma de llamada, cambiar de modelo más adelante significa editar una sola cadena.

Genera tu primera imagen

Mujer mirando un monitor que muestra una fotografía nítida de un lago de montaña

Guárdalo como first_image.py:

import base64
from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="A photograph of a bowl of oranges on a linen cloth, soft window light",
)

with open("oranges.png", "wb") as f:
    f.write(base64.b64decode(interaction.output_image.data))

Ejecuta python first_image.py y aparecerá un archivo oranges.png junto al script. Ese es todo el recorrido: prompt de entrada, cadena base64 de salida, bytes en el disco.

Cuando generes más de una imagen, un nombre de archivo fijo sobrescribe el resultado anterior. Construye el nombre a partir de una marca de tiempo, por ejemplo f"image_{int(time.time())}.png", y cada ejecución dejará su propio archivo. Así puedes comparar una docena de variaciones de un mismo prompt, una al lado de otra.

Qué hace cada línea

  • genai.Client() crea un cliente y toma la credencial de la variable de entorno que exportaste antes, así que nada sensible queda en el archivo.
  • client.interactions.create() envía el prompt y devuelve un objeto Interaction que contiene un id, los pasos de salida y accesos directos como output_image.
  • interaction.output_image.data guarda la imagen como una cadena base64. Debes decodificarla antes de escribirla; si no, el archivo será texto y no una imagen.

Escribe prompts que funcionen

El modelo responde mejor a descripciones de escenas que a montones de etiquetas sueltas. Un prompt que se lee como la lista de planos de un fotógrafo te da más control que una lista de adjetivos.

  1. Nombra el sujeto y la acción. "Un panadero espolvoreando harina sobre una hogaza" funciona mejor que "panadería".
  2. Indica la luz. Luz de ventana, cielo nublado, hora dorada o sol de mediodía duro.
  3. Añade objetivo y distancia. "Retrato con 85 mm, profundidad de campo reducida" o "aérea amplia de 24 mm".
  4. Di qué dejar fuera. Una frase corta, como "sin texto en la imagen".

💡 Guarda tus prompts en una lista de Python o en un archivo de texto. Cuando un resultado te sorprenda, puedes cambiar una variable y comparar, lo que gana a reescribir de memoria.

Controla el tamaño y la relación de aspecto

Vista cenital de fotografías impresas en formatos panorámico, alto y cuadrado sobre una mesa de roble

El tamaño y la forma se definen dentro de un diccionario response_format. Esto despista a mucha gente, porque el código antiguo ponía los ajustes de imagen en generation_config.

interaction = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="A wide photograph of a coastal road at dawn, 35mm lens, film grain",
    response_format={
        "type": "image",
        "mime_type": "image/jpeg",
        "aspect_ratio": "16:9",
        "image_size": "2K",
    },
)

with open("coast.jpg", "wb") as f:
    f.write(base64.b64decode(interaction.output_image.data))

Como el mime_type solicitado es JPEG, el archivo recibe la extensión .jpg. Haz que la extensión coincida con el tipo que pides y tu visor de imágenes nunca se quejará.

Relaciones de aspecto que puedes pedir

La documentación de Google enumera diez relaciones: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9 y 21:9.

RelaciónUso típico
1:1Fotos de perfil, miniaturas de producto
4:5Publicaciones en el feed de redes sociales
9:16Historias y miniaturas de video vertical
16:9Cabeceras de blog, miniaturas de video
21:9Banners ultraanchos
3:2Copias fotográficas clásicas

Elige una resolución

El valor de image_size depende del modelo. Flash Lite ofrece solo 1K. Flash ofrece 0.5K, 1K, 2K y 4K. Pro ofrece 1K, 2K y 4K. Usa K en mayúsculas en el valor.

Una regla sencilla mantiene los costos bajo control: 1K para borradores, 2K para páginas web, 4K solo para impresión. Una imagen de 4K en Flash cuesta $0.151 frente a $0.067 en 1K, unas 2.25 veces más, así que la costumbre de "siempre al máximo" se suma rápido.

Edita una foto con prompts de texto

Retocador fotográfico de pie en su escritorio sosteniendo un retrato impreso junto a un monitor calibrado

El mismo endpoint edita imágenes. En lugar de una cadena simple, input se convierte en una lista que mezcla bloques de texto y bloques de imagen. La imagen viaja como cadena base64 con su tipo MIME.

import base64
from google import genai

client = genai.Client()

with open("portrait.png", "rb") as f:
    encoded = base64.b64encode(f.read()).decode("utf-8")

interaction = client.interactions.create(
    model="gemini-3.1-flash-image",
    input=[
        {
            "type": "text",
            "text": "Replace the background with a sunlit brick wall. Keep the person unchanged.",
        },
        {"type": "image", "data": encoded, "mime_type": "image/png"},
    ],
)

with open("portrait_edit.png", "wb") as f:
    f.write(base64.b64decode(interaction.output_image.data))

Fíjate en la redacción del prompt de edición. Dice qué cambia (el fondo) y qué se mantiene (la persona). Sin la segunda mitad, el modelo es libre de reestilizar todo el encuadre.

Encadena ediciones en una conversación

No necesitas reenviar la imagen para cada ajuste. Pasa el id de la interacción anterior y el modelo recuerda la imagen que acaba de crear:

second = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="Make the light warmer, like late afternoon.",
    previous_interaction_id=interaction.id,
    response_format={
        "type": "image",
        "mime_type": "image/jpeg",
        "aspect_ratio": "4:5",
        "image_size": "2K",
    },
)

Mantén la misma relación de aspecto que en la primera imagen; si no, el modelo podría recortar o extender la escena. Guarda cada interaction.id en tu base de datos y podrás volver a cualquier paso anterior de una sesión, algo útil en trabajo con clientes, donde "vuelve a la versión dos" aparece a menudo.

Lee respuestas mixtas y añade búsqueda

Mesa de lectura tranquila en una biblioteca con un equipo portátil abierto, libros y luz de la tarde

A veces el modelo responde con una frase de texto y una imagen. El atajo output_image sirve para scripts sencillos, pero un ayudante que recorre la lista steps gestiona todos los casos:

def save_outputs(interaction, prefix="gemini", ext="png"):
    saved = []
    for step in interaction.steps:
        if step.type != "model_output":
            continue
        for block in step.content:
            if block.type == "text":
                print(block.text)
            elif block.type == "image":
                path = f"{prefix}_{len(saved) + 1}.{ext}"
                with open(path, "wb") as f:
                    f.write(base64.b64decode(block.data))
                saved.append(path)
    return saved

La función devuelve una lista de rutas de archivo. Una lista vacía significa que el modelo envió solo texto, lo cual no es una excepción, así que compruébalo antes de dar por hecho que existe un archivo.

Fundamenta los prompts con búsqueda

Algunas imágenes dependen de datos que cambian a diario: un gráfico del tiempo, un marcador deportivo, un gráfico de precios. Activa Google Search y el modelo puede obtener datos en vivo antes de dibujar:

interaction = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="Create an infographic of this week's weather in Chicago",
    tools=[{"type": "google_search"}],
    generation_config={"thinking_level": "high"},
)

El ajuste thinking_level acepta "minimal" o "high". Usa minimal cuando la velocidad importe y el diseño sea sencillo. Usa high cuando el prompt pida un diseño estructurado con varias partes.

💡 Toda imagen que devuelve la API lleva una marca de agua SynthID, una marca invisible que Google añade para que la imagen pueda identificarse como generada por IA. No necesitas añadir una tú mismo.

Gestiona los errores antes de producción

Mano de ingeniero sosteniendo un marcador amarillo sobre una página impresa con registros de salida

Las llamadas de imagen tardan más que las de texto, y las ráfagas de solicitudes pueden activar límites de tasa. Un pequeño envoltorio de reintentos te evita la mayor parte de los problemas. Reintenta ante HTTP 429, 500 y 503 y espera más tiempo tras cada fallo:

import time

def generate_with_retry(prompt, retries=4, **kwargs):
    for attempt in range(retries):
        try:
            return client.interactions.create(
                model="gemini-3.1-flash-image",
                input=prompt,
                **kwargs,
            )
        except Exception as exc:
            status = getattr(exc, "status_code", None) or getattr(exc, "code", None)
            if status not in (429, 500, 503) or attempt == retries - 1:
                raise
            time.sleep(2 ** attempt)

Según la versión del SDK, el estado HTTP está en status_code o en code, así que el ayudante comprueba ambos. Lo que no admite reintento, como una solicitud incorrecta, se lanza de inmediato para que veas el mensaje real.

Para procesar una lista de prompts, ejecuta unos pocos a la vez:

from multiprocessing.pool import ThreadPool

prompts = ["A bowl of oranges", "A lighthouse at dusk", "A forest road in fog"]

with ThreadPool(4) as pool:
    results = pool.map(generate_with_retry, prompts)

Empieza con cuatro workers. Si el ayudante de reintentos sigue disparándose, baja a dos antes de aumentar tu cuota.

Los prompts rechazados requieren otro hábito. La documentación de Google señala que los ajustes de seguridad personalizados no son compatibles con la Interactions API, así que no puedes relajar los filtros desde el código. Cuando una respuesta llega con texto y sin imagen, registra el prompt y el texto, y luego reescribe el prompt con una descripción más tranquila y concreta. Reintentar el mismo prompt rara vez cambia la respuesta y solo consume tiempo.

3 errores comunes

  1. Llamar a un modelo retirado. Cualquier fragmento con gemini-2.5-flash-image necesita que la cadena del modelo se cambie por una vigente.
  2. Poner aspect_ratio en generation_config. Va en response_format, junto a image_size.
  3. Escribir la cadena base64 directamente en el disco. Ejecuta siempre base64.b64decode() primero, o el archivo no se abrirá.

Si todavía tienes código antiguo que llama a generate_content, Google dice que esa API sigue siendo compatible y ahora aparece como heredada. Para proyectos nuevos, la Interactions API es la que recomienda la documentación de Google.

Vigila los costos

Pequeña empresaria revisando una factura impresa junto a un equipo portátil en un taller de cerámica

Los costos crecen con el volumen, así que haz las cuentas antes de un bucle grande. Quinientas imágenes de 2K en Flash cuestan 500 x $0.101, es decir, $50.50. Google también ofrece precios por lotes, aproximadamente a la mitad de la tarifa estándar, para trabajos que pueden esperar:

ResoluciónEstándarPor lotes
0.5K$0.045$0.022
1K$0.067$0.034
2K$0.101$0.050
4K$0.151$0.076

Las mismas 500 imágenes de 2K por lotes cuestan unos $25. Si nadie espera el resultado, como una actualización nocturna del catálogo, el lote es la vía más barata.

Usa Nano Banana Pro en PicassoIA

Diseñador joven frente a un monitor grande que muestra una cuadrícula de fotografías en un estudio luminoso

No todas las imágenes necesitan un script. Si quieres probar un prompt antes de gastar créditos de API, o pasarle el trabajo a un compañero que no programa en Python, Nano Banana Pro en PicassoIA es una forma sin código de obtener salida de hasta 4K de la misma familia de modelos de Google.

  1. Abre la página del modelo. Ve a la página de Nano Banana Pro.
  2. Escribe tu prompt. Usa el mismo estilo de lista de planos de antes: sujeto, luz, objetivo.
  3. Añade imágenes de referencia (opcional). El campo Image Input acepta hasta 14 imágenes que orientan el estilo, la composición o el sujeto.
  4. Elige una relación de aspecto. Selecciona entre 11 preajustes, incluidos 16:9, 9:16, 4:5, 21:9 y match_input_image.
  5. Elige una resolución. 1K, 2K (la predeterminada) o 4K.
  6. Elige un formato. JPG (el predeterminado) o PNG.
  7. Ajusta el filtro de seguridad. block_only_high es el predeterminado y el más permisivo; block_low_and_above es el más estricto.
  8. Genera y descarga. Vuelve a ejecutar con un prompt ajustado para comparar versiones.

Relaciona los ajustes de la web con la API

Si haces pruebas en la web y luego pasas al código, los ajustes casi coinciden uno a uno:

Campo de PicassoIAEquivalente en la API de Python
Promptinput (bloque de texto)
Image Inputinput (bloques de imagen, base64)
aspect_ratioresponse_format["aspect_ratio"]
resolutionresponse_format["image_size"]
output_formatresponse_format["mime_type"]

La familia de Google en PicassoIA es más amplia que un solo modelo. Nano Banana sirve para ediciones rápidas, Nano Banana 2 Lite prioriza la velocidad, e Imagen 4 e Imagen 4 Ultra se centran en el detalle fotorrealista. Probar el mismo prompt en dos de ellos cuesta un minuto y muestra qué estilo encaja con tu proyecto antes de escribir una sola línea de código de integración.

Crea tus propias imágenes hoy

Dos amigos en una mesa de cafetería mirando una fotografía de paisaje en una tableta

Ya tienes todas las piezas: una instalación funcional, una primera imagen, control de tamaño y relación, ediciones, una forma segura de leer salidas mixtas, un envoltorio de reintentos y una estimación de costos en la que puedes confiar. Elige un trabajo pequeño, como una cabecera de blog o una miniatura de producto, y ejecútalo de principio a fin esta tarde.

Si prefieres ver resultados antes de tocar una terminal, abre Picasso IA, elige un modelo como Nano Banana Pro y escribe el prompt que acabas de redactar para tu script. Prueba tres variaciones, cambia la relación de aspecto y compara. El mejor prompt que encuentres ahí pasa directamente al código de Python de arriba.

Ese ciclo, probar en la web y llevar a código, es la forma más rápida de fijar un estilo sin pagar por cada experimento. Abre Picasso IA, ejecuta tu primer prompt y mira lo que puedes crear antes de que acabe la tarde.

Compartir este artículo

Elige tu idioma