Tutorial
Cómo usar el modo imagen a imagen de gpt-image-2 a través de la API de hiapi
Una receta de código lista para ejecutar que te enseña cómo llamar al endpoint de imagen a imagen de gpt-image-2 en hiapi: el sobre de la petición, los parámetros de imagen de referencia y aspect_ratio, la disyuntiva entre sondeo y callback, y ejemplos de curl, Python y Node.js listos para copiar y pegar.
Esta receta te mostrará paso a paso cómo llamar al modo imagen a imagen de gpt-image-2 mediante la API de tareas unificada de hiapi. Obtendrás un ejemplo de curl listo para ejecutar, un script de Python que puedes incrustar directamente en tu backend, una versión de Node.js para escenarios sin servidor, y los parámetros que realmente importan junto con los detalles que suelen causar problemas en producción.
Al terminar de leer este artículo, tendrás un script que recibe una URL de imagen de referencia y un prompt, y devuelve una URL de imagen generada que puedes descargar directamente o pasar a tu capa de almacenamiento.
Preparación
- Una cuenta de hiapi y una clave de API. Puedes obtenerlas en la consola de hiapi.
- Una imagen de referencia alojada en una URL HTTPS pública (o una URL de datos base64 — ambas funcionan).
- Un prompt de texto que describa lo que quieres que el modelo haga con esa imagen de referencia.
Eso es todo. No necesitas instalar ningún SDK — hiapi es HTTP + JSON, así que cualquier lenguaje que pueda enviar una petición POST sirve.
¿Quieres conocer primero la generación de imágenes solo a partir de texto? Consulta Cómo generar imágenes con la API de hiapi. El patrón que sigue es el mismo flujo de tareas asíncrono, solo que con un campo
imageadicional.
Llamada mínima funcional
hiapi expone todos los modelos de imagen a través de la misma interfaz de tareas asíncrona:
POST /v1/tasks— envía la tarea y devuelve untaskId.- O bien sondea
GET /v1/tasks/{taskId}hasta questatus === "success", o bien proporcionacallback.urlpara recibir el resultado final mediante webhook. - Lee la URL de la imagen desde
data.output[0].urly descárgala o guárdala.
curl
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2/image-to-image",
"input": {
"prompt": "transform the subject into a watercolor painting, soft pastel palette",
"image": "https://example.com/reference.jpg",
"aspect_ratio": "1:1",
"resolution": "1K"
}
}'
La respuesta inmediata te da el id de la tarea:
{ "data": { "taskId": "task_01HXXXX..." } }
Luego sondea el resultado:
curl https://api.hiapi.ai/v1/tasks/task_01HXXXX... \
-H "Authorization: Bearer sk-YOUR_KEY"
Cuando la tarea está lista, la respuesta es así:
{
"data": {
"status": "success",
"output": [{ "url": "https://cdn.hiapi.ai/...png", "expireAt": "..." }]
}
}
output[0].url tiene una validez temporal corta (fíjate en expireAt), así que descárgala de inmediato o vuelve a subirla a tu propio almacenamiento — nunca enlaces directamente a ella para tus usuarios finales.
Los parámetros que realmente importan
| Campo | Tipo | Descripción |
|---|---|---|
model |
string | Usa el id sin prefijo gpt-image-2/image-to-image. No añadas el prefijo models/. |
input.prompt |
string | La transformación que deseas aplicar a la imagen de referencia. |
input.image |
string | Una URL HTTPS o una URL data:image/...;base64,.... |
input.aspect_ratio |
string | Uno de estos valores: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 o auto. |
input.resolution |
string | 1K, 2K o 4K. Por defecto 1K. |
Dos comportamientos importantes:
- Algunos modelos de hiapi solo aceptan
aspect_ratio(sinresolution); otros modelos requieren dimensiones en píxeles. gpt-image-2/image-to-image acepta la combinación deaspect_ratio+resolutionmostrada arriba — no pases aquísize: "1024x1024". - El campo
imagees la imagen de referencia. Si pasas una URL de datos base64, asegúrate de que el payload esté por debajo del límite de tamaño del cuerpo de la petición de tu plataforma (unos pocos MB están bien; las imágenes de varios megabytes deberían subirse primero y pasarse como URL).
Script de Python de nivel producción
Esta versión sondea con manejo de fecha límite y sale limpiamente en caso de fallo:
import os
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
def submit(prompt: str, image_url: str, aspect_ratio: str = "1:1") -> str:
payload = {
"model": "gpt-image-2/image-to-image",
"input": {
"prompt": prompt,
"image": image_url,
"aspect_ratio": aspect_ratio,
"resolution": "1K",
},
}
r = requests.post(API, headers=HEADERS, json=payload, timeout=30)
r.raise_for_status()
return r.json()["data"]["taskId"]
def wait(task_id: str, timeout_s: int = 300, interval_s: int = 5) -> str:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=20)
r.raise_for_status()
task = r.json()["data"]
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(interval_s)
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
if __name__ == "__main__":
task_id = submit(
prompt="transform the subject into a watercolor painting, soft pastel palette",
image_url="https://example.com/reference.jpg",
)
print("task:", task_id)
print("url:", wait(task_id))
Ejecútalo con HIAPI_API_KEY=sk-... python recipe.py.
Node.js (fetch, sin dependencias)
const API = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;
const headers = {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
};
async function submit(prompt, imageUrl, aspectRatio = "1:1") {
const r = await fetch(API, {
method: "POST",
headers,
body: JSON.stringify({
model: "gpt-image-2/image-to-image",
input: { prompt, image: imageUrl, aspect_ratio: aspectRatio, resolution: "1K" },
}),
});
const data = await r.json();
if (!r.ok) throw new Error(JSON.stringify(data));
return data.data.taskId;
}
async function wait(taskId, timeoutMs = 300000, intervalMs = 5000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const r = await fetch(`${API}/${taskId}`, { headers });
const task = (await r.json()).data;
if (task.status === "success") return task.output[0].url;
if (task.status === "fail") throw new Error(JSON.stringify(task.error));
await new Promise((res) => setTimeout(res, intervalMs));
}
throw new Error(`task ${taskId} timed out`);
}
(async () => {
const id = await submit(
"transform the subject into a watercolor painting, soft pastel palette",
"https://example.com/reference.jpg",
);
console.log("task:", id, "\nurl:", await wait(id));
})();
Sondeo vs. callback
Sondear cada 5 segundos está bien para un script puntual, pero mantiene ocupado a un worker durante toda la tarea. En un backend real, normalmente querrás un webhook:
{
"model": "gpt-image-2/image-to-image",
"input": { "prompt": "...", "image": "https://example.com/reference.jpg" },
"callback": { "url": "https://your-app.example.com/api/hiapi-callback", "when": "final" }
}
Cuando la tarea se liquida (con éxito o con fallo), hiapi hará POST a esa URL con el mismo payload que obtendrías de GET /v1/tasks/{id}. Trata ese manejador como idempotente — los reintentos son posibles — y verifícalo antes de confiar en la petición (incluye tu propio token de firma en la URL, comprueba la cabecera Authorization, etc.).
Un patrón limpio es: enviar la tarea, persistir el taskId con tu propio job id como clave, devolver 202 Accepted al llamador y dejar que el webhook haga el trabajo de almacenamiento y notificación.
Manejo de errores
En la práctica te encontrarás con tres modos de fallo:
401 permission_deniedcon"This API key cannot use the selected model."— la clave no está autorizada para usargpt-image-2/image-to-image. Compruébalo en la consola de hiapi y confirma en la página de precios que el modelo está incluido en tu plan.400conadditional properties not allowed— enviaste un campo que ese modelo concreto no acepta (por ejemplo,sizeen lugar deaspect_ratio). El mensaje de error indicará el nombre de la clave infractora; elimínala y reinténtalo.status: "fail"durante el sondeo con un objetodata.error— el modelo mismo rechazó la entrada (contenido no seguro, URL de referencia inaccesible, etc.). Registraerror.codeyerror.messageen los logs y no reintentes automáticamente a ciegas.
Establece siempre un tiempo de espera para las llamadas a POST /v1/tasks (30 segundos es suficiente — devuelve el taskId rápidamente) y un tiempo de espera independiente y más largo para el bucle de sondeo o la ruta de recepción del webhook.
Enlaces relacionados
- Página del modelo gpt-image-2 — matriz de capacidades y niveles de precios.
- Todos los modelos de hiapi — el catálogo completo si necesitas otros modelos de imagen o vídeo.
- Documentación de la API — referencia completa de
/v1/tasksy de toda la superficie de la interfaz. - Cómo generar imágenes con la API de hiapi — el artículo hermano de esta receta para texto a imagen.
Preguntas frecuentes
P: ¿gpt-image-2/image-to-image admite varias imágenes de referencia?
R: El contrato mínimo usa un único campo image. Si tu caso de uso requiere varias imágenes de referencia (por ejemplo, una imagen del sujeto + una imagen de estilo), combínalas primero en una sola, o consulta la página del modelo para conocer los campos más recientes admitidos.
P: ¿Puedo pasar un archivo local en lugar de una URL?
R: Sí — codifícalo como una URL data:image/png;base64,... y pásalo como input.image. Para archivos de más de unos 3 MB, súbelo primero a tu propio almacenamiento y pasa una URL pública; así es más rápido y evitas los límites del cuerpo de la petición.
P: ¿Cuánto tarda una tarea?
R: La mayoría de las tareas de imagen a imagen de gpt-image-2 se completan en 10–30 segundos con resolución 1K. Resoluciones más altas y prompts complejos pueden tardar más — para ir sobre seguro, establece el tiempo de espera del sondeo en 5 minutos.
P: ¿Cómo puedo controlar cuánto difiere la salida de la imagen de referencia? R: Exprésalo claramente en el prompt. "Keep the subject's pose and composition, only restyle to watercolor" produce una consistencia más estricta que "make this a watercolor". El modo imagen a imagen de gpt-image-2 está dirigido por el prompt — no hay un control deslizante de "strength" independiente en el sobre de la petición.
P: ¿output[0].url es permanente?
R: No. Lleva una marca de tiempo expireAt (normalmente unas pocas horas). En cuanto la tarea tenga éxito, descarga los bytes lo antes posible y súbelos a tu propio almacenamiento (R2, S3, etc.).
P: ¿Cuánto cuesta cada imagen? R: Depende de tu plan y de la resolución. Consulta el coste actual por llamada en la página de precios.
Artículos relacionados
Ver todos los artículos →-
Tutorial
Cómo llamar a hailuo-2.3-fast/image-to-video a través de la API de HiAPI: práctica con curl y Python
La primera solicitud ejecutable del nivel rápido y de bajo coste de imagen a vídeo: del ID del modelo a la descarga del MP4
-
Tutorial
Cómo llamar a hailuo-2.3/text-to-video mediante la API de HiAPI: curl, Python y ejemplos de solicitud ejecutables
-
Tutorial
Uso de Kandinsky 6.0 Pro texto a video en HiAPI: tutorial con curl y Python
Demostración práctica centrada en la solicitud: construir la llamada de prompt a clip de video, enviar la solicitud, sondear el estado de finalización y descargar el resultado