AIFreeAPI Logo

Editar imágenes con GPT Image 2: variations y errores de dall-e-2

A
9 min readDesarrollo de IA

GPT Image 2 permite crear alternativas a partir de una referencia mediante edits y un prompt. Aprende a migrar desde variations, investigar el rechazo de dall-e-2 y guardar una versión que puedas seguir editando.

Ilustración de una edición de un salón mediante la API junto a un aviso de error de modelo

gpt-image-2 admite edición mediante client.images.edit() y /v1/images/edits. Recibir Value must be 'dall-e-2' no significa que tengas que cambiar a ese modelo: DALL·E 2 se ha retirado de la API. La documentación actual de GPT Image 2 y el aviso de retirada de DALL·E 2 son las referencias para esta decisión, revisadas el 8 de septiembre de 2026.

Si tu aplicación aún llama a /v1/images/variations, también debes cambiar la operación: GPT Image 2 no admite ese endpoint. Obtener una alternativa de una imagen sigue siendo posible mediante edición y una instrucción explícita.

Cuando ya utilizas edits, el mensaje sí merece investigar la validación de la petición. Puede aparecer en contextos distintos y, por sí solo, no identifica si el rechazo procede del servicio final, de una integración o de parámetros heredados. Empieza con una edición sencilla, sin máscara, sin response_format y sin input_fidelity; comprueba que puedes guardar los bytes de la respuesta. Después añade los controles que necesite tu aplicación.

De variations a edits: cambia la operación y define la alternativa

La palabra «variación» puede describir otra fotografía del mismo producto o una escena con distinta iluminación. El endpoint variations, en cambio, es una operación antigua: la referencia de create_variation la limita a DALL·E 2. Que el tipo compartido ImageModel incluya GPT Image 2 no elimina esa restricción específica.

Comprueba tanto el método del SDK como la ruta HTTP efectiva:

Si tu código utiliza…Sustitúyelo por…
client.images.create_variation() en Pythonclient.images.edit()
client.images.createVariation() en Node.jsclient.images.edit()
POST /v1/images/variationsPOST /v1/images/edits
Solo una imagen, sin instruccionesLa imagen y un prompt significativo y no vacío

Actualizar el paquete o cambiar únicamente model no resuelve una llamada que sigue llegando a variations. La edición requiere describir el resultado: «Crea otra versión» deja demasiadas decisiones abiertas. Para el salón de esta guía podrías pedir: «Mantén los muebles y el encuadre; propón otra iluminación de tarde cálida, sin añadir objetos». Has definido qué puede cambiar y qué debe conservarse, en lugar de esperar el comportamiento del antiguo modo sin prompt.

El parámetro n indica cuántas imágenes solicitas; no determina cuánto cambia la referencia ni activa variations. Para comparar propuestas con una intención distinta, modifica la instrucción y guarda cada alternativa por separado. Si solicitas varias imágenes en una petición, procesa todos los elementos de data; los ejemplos siguientes guardan solo el primero.

Una edición completa: subir la imagen y guardar el resultado

Para una operación independiente basta con Images API. Envía la imagen original, describe cómo debe quedar la escena y elige el formato del resultado. Los ejemplos siguientes ilustran el uso documentado; no son una prueba de acceso de tu cuenta ni una llamada ejecutada para este artículo.

En Python, instala el SDK con python -m pip install --upgrade openai, define OPENAI_API_KEY en tu entorno y coloca salon.png junto al programa:

python
import base64 from pathlib import Path from openai import OpenAI client = OpenAI() with open("salon.png", "rb") as original: result = client.images.edit( model="gpt-image-2", image=original, prompt=( "Fotografía de este mismo salón. Sustituye el póster de la pared " "por una lámina botánica enmarcada. Conserva los muebles, la " "distribución, la iluminación y el encuadre de la imagen original." ), output_format="png", ) if not result.data or not result.data[0].b64_json: raise RuntimeError("La respuesta no contiene una imagen en b64_json") image_bytes = base64.b64decode(result.data[0].b64_json, validate=True) Path("salon-editado.png").write_bytes(image_bytes)

El equivalente en Node.js utiliza un flujo de archivo. Instala openai con npm install openai y guarda este ejemplo como editar.mjs para poder utilizar import y await en el nivel superior. Ejecútalo con node editar.mjs en un entorno que tenga definida la clave:

javascript
import fs from "node:fs"; import OpenAI from "openai"; const client = new OpenAI(); const result = await client.images.edit({ model: "gpt-image-2", image: fs.createReadStream("salon.png"), prompt: "Fotografía de este mismo salón. Sustituye el póster de la pared " + "por una lámina botánica enmarcada. Conserva los muebles, la " + "distribución, la iluminación y el encuadre de la imagen original.", output_format: "png", }); const encoded = result.data?.[0]?.b64_json; if (!encoded) { throw new Error("La respuesta no contiene una imagen en b64_json"); } fs.writeFileSync("salon-editado.png", Buffer.from(encoded, "base64"));

Hay dos diferencias relevantes frente a muchos ejemplos antiguos. response_format se omite: GPT Image devuelve la imagen en b64_json; escribir response_format="b64_json" no es necesario. input_fidelity también se omite con GPT Image 2: el procesamiento de alta fidelidad es automático y no se puede ajustar con ese parámetro. output_format sí decide si los bytes corresponden a PNG, JPEG o WebP; utiliza una extensión coherente al guardarlos. Estas distinciones se recogen en la guía de generación y edición de imágenes.

Guardar el texto base64 en un archivo .png no crea una imagen PNG. Debes decodificarlo, como hacen los ejemplos. Y una respuesta HTTP satisfactoria tampoco basta para tu aplicación: comprueba que contiene la imagen y que el archivo guardado puede abrirse antes de dar la tarea por terminada.

Qué se sabe del error Value must be 'dall-e-2'

El issue #1844 de openai-node documentó el 27 de abril de 2026 ese rechazo al enviar gpt-image-2. Incluía una reproducción con cURL, sin response_format, además del uso del SDK. En agosto, una respuesta indicó que la validación de edición se había corregido en el servicio y el issue se cerró como resuelto.

Ese historial explica por qué cambiar el modelo o culpar automáticamente al SDK puede llevarte por el camino equivocado. Tampoco demuestra que cualquier intermediario haya aplicado la misma corrección o que una petición actual con el mismo texto tenga idéntica causa. No hay aquí una versión mínima del SDK que pueda garantizarse como arreglo universal.

Otro hilo de marzo sobre el endpoint de edición contiene dos experiencias diferentes con modelos GPT Image anteriores: un participante resolvió su caso al quitar response_format; el autor original atribuyó el suyo a un archivo en memoria sin nombre y lo resolvió asignándolo. Son pistas para comparar peticiones, no una regla según la cual todos los errores se arreglan con el mismo cambio.

Aísla el rechazo sin cambiar varias cosas a la vez

Esquema de las etapas de diagnóstico: petición, archivos, respuesta y resultado visual
Esquema de las etapas de diagnóstico: petición, archivos, respuesta y resultado visual

Antes de retocar el prompt, identifica qué falló. Este orden evita confundir un archivo rechazado con una mala edición:

Lo que observasQué comprobar primeroQué todavía no demuestra
Error sobre model o dall-e-2Modelo explícito, campos enviados, URL real y validación de la integraciónQue GPT Image 2 no admita edición
Error sobre image o maskNombre, tipo MIME, bytes, tamaño y requisitos de la máscaraQue el modelo esté retirado o no disponible
Respuesta sin imagen utilizableEstado, objeto de error y contenido de b64_jsonQue se haya generado y guardado una imagen
Archivo válido que cambia demasiado la escenaInstrucciones, referencias, máscara y comparación con el originalQue la subida o la validación hayan fallado

Para comparar el SDK con una subida directa, esta petición mínima utiliza multipart para enviar un archivo local. cURL construye el cuerpo y su delimitador; no añadas manualmente un encabezado Content-Type: application/json a este ejemplo:

bash
curl --fail-with-body --silent --show-error \ https://api.openai.com/v1/images/edits \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -F 'model=gpt-image-2' \ -F 'image=@salon.png;type=image/png' \ -F 'prompt=Sustituye el póster por una lámina botánica. Conserva el resto del salón.' \ -F 'output_format=png' \ -o respuesta.json

Aquí respuesta.json contiene la respuesta de la API, no la imagen final. Si cURL termina con un error, lee primero el objeto de error; si devuelve una imagen, decodifica data[0].b64_json. La referencia actual de edición también define un cuerpo JSON con un array images: cada referencia puede utilizar image_url —una URL completa o una URL de datos base64— o file_id de un archivo ya subido. Una ruta local escrita como "salon.png" dentro del JSON no envía sus bytes ni la convierte en una URL accesible. Elige multipart para subir el archivo o una de esas referencias para JSON, y comprueba que tu versión del SDK admite la forma elegida antes de cambiar los argumentos del método.

Haz la comparación contra el mismo proveedor previsto. El ejemplo apunta a OpenAI y requiere una clave de OpenAI. Si tu aplicación utiliza otro destino, prepara ambas peticiones para ese destino con sus propias credenciales; no reutilices una clave en un servicio diferente. Comprueba la URL efectiva, incluida cualquier configuración de base_url o baseURL que herede tu cliente.

A continuación, cambia una sola variable:

  1. Reduce la petición a modelo, imagen, prompt y formato de salida; retira campos copiados de DALL·E y los que tu integración añada automáticamente.
  2. Usa el mismo archivo y el mismo destino en cURL y en el SDK. Si solo falla la integración, compara el cuerpo que construye y su validación local.
  3. Si el archivo procede de memoria, repite con nombre y MIME explícitos. Si utilizas un flujo que ya has leído, vuelve a abrirlo o restablece su posición antes de enviarlo.
  4. Si ambas formas devuelven el mismo rechazo, conserva los datos para que el proveedor investigue; el texto del error no basta para atribuirlo al SDK.

Registra la hora con zona horaria, endpoint, modelo, versión del SDK, estado HTTP, campos type, code, param y message del error cuando existan, identificador de petición si se devuelve y metadatos del archivo. Retira claves, cabeceras de autorización y el contenido privado de las imágenes antes de compartir ese registro.

Los archivos en memoria no están prohibidos

El SDK oficial de Python acepta bytes, objetos PathLike y tuplas con nombre, contenido y tipo MIME. Para comprobar si el nombre o el tipo de una subida influyen en tu caso, puedes sustituir el argumento image del ejemplo por:

python
image=("salon.png", image_bytes, "image/png")

En este fragmento, image_bytes debe contener los bytes PNG originales, no una cadena base64. En Node.js, el SDK oficial admite flujos y ofrece toFile para preparar datos en memoria:

javascript
import { toFile } from "openai"; const upload = await toFile(imageBytes, "salon.png", { type: "image/png", }); // Usa image: upload en client.images.edit(...).

Un nombre explícito es una comparación útil cuando investigas la subida. No convierte en cierta la afirmación de que los bytes sin archivo en disco siempre fallan.

Añadir una máscara y conservar el resto de la escena

Salón original, selección del cuadro con una máscara y ejemplo ilustrativo del cambio
Salón original, selección del cuadro con una máscara y ejemplo ilustrativo del cambio

Una vez que la edición básica funciona, una máscara permite señalar la zona que quieres modificar. Prepara salon.png y mascara.png con las mismas dimensiones. La máscara debe ser PNG, tener canal alfa y dejar transparente —alfa cero— la región editable. Para este ejemplo, mantén la máscara por debajo de 4 MB.

La referencia del endpoint de edición especifica ese límite de máscara, aunque la guía general emplea una formulación más amplia de 50 MB. Utilizar ambos archivos en PNG, del mismo tamaño en píxeles y con máscara inferior a 4 MB evita depender de esa discrepancia. Para las imágenes de entrada de GPT Image, la referencia admite PNG, WebP o JPG, menos de 50 MB por imagen y hasta 16 imágenes; el límite de la máscara se comprueba por separado.

En el ejemplo Python, sustituye el bloque que abre el original y llama a la API por este:

python
with open("salon.png", "rb") as original, open("mascara.png", "rb") as mask: result = client.images.edit( model="gpt-image-2", image=original, mask=mask, prompt=( "Fotografía del salón original con una lámina botánica " "enmarcada en la zona transparente de la máscara. Conserva " "la posición y el aspecto del sofá, la mesa y las ventanas, " "así como la luz y el encuadre originales." ), output_format="png", )

El código de comprobación y guardado sigue siendo el mismo. Si envías varias referencias, la máscara se aplica a la primera imagen; deja claro en el prompt qué contiene cada referencia y qué debes extraer de ella. Por ejemplo: «Usa la primera imagen como escena base y coloca la lámina de la segunda dentro del marco de la pared».

Para combinar referencias sin máscara, puedes abrir salon.png y lamina.png en modo binario y pasar ambos archivos en image=[original, lamina] al mismo método. No es necesario darles el mismo peso creativo: una aporta la escena y la otra el diseño. Explica que deben mantenerse el marco, los muebles y la perspectiva, y que solo se incorpora la lámina. Conserva los archivos originales y su orden de envío para poder repetir o revisar la composición.

Que se acepte la máscara no garantiza que todos los píxeles de fuera queden idénticos. La guía de máscaras explica que orientan la generación y pueden no respetar su forma con precisión absoluta. Describe la imagen final completa y las partes que deben mantenerse. Después compara el resultado con el original, sobre todo en rostros, logotipos y geometría del producto.

Si tu aplicación exige conservar exactamente el exterior de una selección, tendrás que controlar también la composición del resultado con el original y verificar esa condición. Es una exigencia de tu producto que no queda resuelta simplemente añadiendo mask.

Continuar desde una versión aceptada o usar Responses

Con Images API, una segunda edición necesita una nueva entrada: el endpoint no recuerda automáticamente la llamada anterior. Guarda el original y cada resultado aceptado con nombres distintos. Para afinar la lámina, vuelve a enviar salon-editado.png y pide, por ejemplo: «Conserva esta versión y reduce ligeramente el reflejo del cristal del cuadro».

Elige como punto de partida la última revisión que hayas aceptado, no cualquier resultado recién generado. Si una modificación cambia demasiado el sofá o la geometría de la habitación, vuelve al original o a una revisión anterior. Así puedes conservar una mejora válida sin acumular correcciones sobre una imagen que ya no sirve.

Mantén images.edit() si la aplicación recibe una imagen, realiza un cambio y devuelve un archivo. Responses resulta útil cuando la edición forma parte de una conversación: el usuario pide un cambio, revisa el resultado y continúa con instrucciones que dependen de lo anterior, o el asistente combina imágenes con otras herramientas.

En Responses se utiliza un modelo principal compatible con la herramienta image_generation. No pongas gpt-image-2 como modelo de nivel superior de Responses. La guía documenta también entradas mediante identificadores de archivo y la continuidad conversacional con previous_response_id; consulta el apartado de generación de imágenes para escoger la forma de entrada adecuada.

Cambiar de API solo para esquivar un mensaje histórico complica el diagnóstico. Primero averigua si la edición directa funciona con la petición reducida. Si funciona y tu necesidad siguiente es mantener una conversación de edición, entonces el paso a Responses tiene una razón concreta.

Para ampliar la implementación más allá de la edición —incluidos los usos del modelo y la forma de integrar la API— continúa con la guía de GPT Image 2 en español.