Tutorial
Cómo llamar a gpt-image-2/image-to-image en HiAPI: curl, Python y una solicitud que funciona
Práctica de solicitudes de imagen a imagen para desarrolladores: enviar la imagen de referencia, consultar el estado de la tarea y descargar el resultado
Qué espera el endpoint image-to-image
El modelo gpt-image-2/image-to-image en HiAPI es un endpoint de generación de imágenes asíncrono. A diferencia de una llamada síncrona que bloquea la espera hasta recibir la imagen, este endpoint recibe tu solicitud, la pone en cola y devuelve un identificador de tarea. Después debes seguir esa tarea hasta que se complete.
A nivel de solicitud, debes proporcionar tres cosas:
- ID del modelo:
gpt-image-2/image-to-image. - Una imagen de referencia: la imagen de origen a partir de la cual el modelo debe transformar o construir. Esta es la entrada decisiva del modo imagen a imagen; sin ella, estarías haciendo texto a imagen.
- Prompt y opciones: una instrucción de texto que describe la salida deseada, junto con los campos opcionales que figuran en la documentación del modelo (por ejemplo, el tamaño o el formato de salida). Envía únicamente los parámetros que la documentación del modelo enumera.
La respuesta no es la imagen en sí, sino un objeto de tarea que contiene un identificador y un estado. Trata ese estado como la única fuente de verdad: pending o processing significan que debes seguir esperando, succeeded significa que el resultado está listo y failed significa que algo salió mal y debes dejar de consultar.
Diseña tu cliente en torno a este ciclo de vida desde el principio. Todo lo demás en este tutorial —curl, Python, consulta de estado, descarga— se basa en el hecho de que «enviar» y «completar» son dos momentos independientes.
Prepara tu clave de HiAPI y la imagen de referencia
Antes de escribir cualquier código, prepara dos cosas.
Una clave de API. Crea una en la consola de HiAPI y guárdala en una variable de entorno en lugar de pegarla directamente en el script:
export HIAPI_API_KEY="your-key-here"
Trata la clave como un secreto. No la confirmes en el repositorio ni la registres en los logs de solicitudes.
Una imagen de referencia. Elige un archivo de imagen local que quieras transformar. Mantén un tamaño razonable: las imágenes de origen demasiado grandes o de alta resolución son la causa más común de solicitudes lentas o rechazadas. Coloca un PNG o JPEG en el mismo directorio que el script; así la primera ejecución será lo más sencilla posible:
ls -lh ./reference.png
Anota la ruta del archivo; la usarás tanto en el ejemplo de curl como en el de Python. Si piensas llamar al modelo desde un servidor, asegúrate de que el proceso tenga permiso de lectura sobre esa ruta y de que el archivo sea una imagen válida (no un archivo renombrado con una extensión incorrecta).
Con la clave exportada y la imagen en disco, ya tienes todo lo necesario para la primera solicitud.
Una solicitud curl que funciona
La forma más rápida de verificar las credenciales y la estructura del cuerpo de la solicitud es hacer una llamada curl. Envía la tarea e imprime el objeto de tarea:
curl -sS https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2/image-to-image",
"input": {
"image": "https://example.com/reference.png",
"prompt": "Turn this photo into a watercolor illustration"
}
}'
Dos aclaraciones sobre este ejemplo. Primero, la imagen de referencia se pasa como URL mediante el campo input.image; si la documentación del endpoint admite base64 en línea o carga multipart para tu caso, usa esa forma, pero mantén el nombre del campo igual. Segundo, el prompt es donde describes la transformación: sé específico sobre el estilo, la composición y qué elementos deben permanecer sin cambios.
Ejecútalo y lee la respuesta. Un envío correcto devuelve un id de tarea y un estado no terminal. Si obtienes un 401, tu clave falta o es incorrecta. Si obtienes un 422 o un error de validación similar, revisa el cuerpo de la solicitud; normalmente es el id del modelo o el formato del campo image lo que está mal.
Guarda el id de la tarea. Los pasos siguientes dependen de él.
Lo mismo en Python
La versión en Python debe corresponder exactamente a la llamada curl, manteniendo explícitos la autenticación y la construcción del cuerpo de la solicitud para que nada quede oculto tras una capa de abstracción. Usa requests:
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
payload = {
"model": "gpt-image-2/image-to-image",
"input": {
"image": "https://example.com/reference.png",
"prompt": "Turn this photo into a watercolor illustration",
},
}
response = requests.post(f"{BASE_URL}/tasks", json=payload, headers=headers, timeout=30)
response.raise_for_status()
task = response.json()
print(task["id"], task["status"])
Si tu integración envía un archivo local en lugar de una URL, codifica y adjunta la imagen según la documentación del endpoint en vez de inventar campos. La disciplina es la misma que con curl: construye el cuerpo de la solicitud como un diccionario normal, envíalo y comprueba el estado HTTP antes de analizar la respuesta.
Encapsula la lógica de envío en una función que devuelva el id de la tarea. Así el código de consulta de la siguiente sección será independiente de cómo se creó la tarea.
Consultar el estado de la tarea asíncrona hasta que se complete
La llamada de envío regresa cuando la imagen aún se está generando. Para obtener el resultado, consulta el endpoint de estado de la tarea hasta que esta alcance un estado terminal. Un bucle robusto tiene tres características: una pausa entre consultas, un tiempo máximo de espera y un manejo explícito de los estados de fallo.
import time
def wait_for_task(task_id, headers, base_url, timeout=300, interval=3):
deadline = time.time() + timeout
while time.time() < deadline:
r = requests.get(f"{base_url}/tasks/{task_id}", headers=headers, timeout=30)
r.raise_for_status()
task = r.json()
status = task["status"]
if status == "succeeded":
return task
if status == "failed":
raise RuntimeError(f"Task failed: {task}")
time.sleep(interval)
raise TimeoutError(f"Task {task_id} did not finish within {timeout}s")
Algunas mejoras prácticas:
- Retroceso: empieza con un intervalo corto y auméntalo gradualmente, o mantén un intervalo fijo suficientemente amplio para no saturar la API. La generación de imágenes no es instantánea.
- Tiempo de espera: fija siempre un límite al tiempo total de espera. De lo contrario, una tarea atascada dejará tu worker colgado indefinidamente.
- Estados terminales: considera terminales únicamente
succeededyfailed. Cualquier otro estado significa seguir consultando. Si la API añade en el futuro estados intermedios, tu bucle seguirá funcionando correctamente.
Si vas a ejecutar muchas tareas, consulta el estado en un worker en segundo plano o en una cola en lugar de bloquear una solicitud web. El ciclo de vida es el mismo; solo cambia el modelo de concurrencia.
Descargar y verificar el resultado
Cuando la tarea informe de éxito, el objeto de tarea incluirá la ubicación de la imagen generada, normalmente una URL en un campo de salida. Descárgala y guárdala en disco:
task = wait_for_task(task_id, headers, BASE_URL)
image_url = task["output"]["image"]
img = requests.get(image_url, timeout=60)
img.raise_for_status()
with open("result.png", "wb") as f:
f.write(img.content)
Si la URL firmada tiene fecha de caducidad, descárgala inmediatamente después de completarse la tarea, o guarda el archivo directamente en lugar de almacenar la URL para usarla más tarde. Si tu endpoint devuelve base64 en lugar de una URL, decodifícalo antes de escribir el archivo.
Una comprobación rápida de integridad evita fallos posteriores confusos:
from PIL import Image
with Image.open("result.png") as im:
im.verify()
print("valid image, bytes:", os.path.getsize("result.png"))
Si el archivo no es una imagen decodificable, verify() lanzará una excepción, lo que permite detectar descargas truncadas y páginas de error guardadas como si fueran imágenes. Comprobar el tamaño en bytes también te indica si la respuesta es razonable. Con esto se cierra el ciclo: enviar, consultar, descargar y verificar.
Solucionar fallos comunes
La mayoría de las primeras integraciones fallan de unas pocas formas previsibles. Diagnostica en el siguiente orden.
Errores de autenticación (401/403). La clave falta, tiene un formato incorrecto o carece de permisos. Confirma que la variable de entorno está exportada en el shell o proceso que ejecuta la solicitud y que la cabecera Authorization usa exactamente el prefijo que espera la API.
Imagen de referencia inválida o demasiado grande (400/422). Puede que la URL de la imagen no sea accesible desde el lado de la API, que el archivo esté dañado o que el tamaño y el peso del archivo superen los límites. Prueba primero con un PNG pequeño y confirmado como válido. Si envías una URL, asegúrate de que sea de acceso público; si envías datos en línea, confirma que la codificación es correcta.
Tiempo de espera agotado en la consulta. Si la tarea alcanza repetidamente tu límite de espera, aumenta el límite, alarga el intervalo o comprueba si la tarea ya falló y simplemente no estás mostrando el motivo. Registra el último objeto de tarea antes de lanzar la excepción para poder inspeccionar el estado.
Límite de solicitudes (429). Aplica retroceso y reintenta con jitter en lugar de reintentar de inmediato. Si envías muchas solicitudes en paralelo, limita la concurrencia para que un pico de tráfico no active el límite, y haz que los reintentos sean idempotentes registrando el id de la tarea.
Para cualquier categoría de error, registra el estado HTTP, el cuerpo de la respuesta truncado y el id de la tarea; estos tres datos suelen bastar para determinar si el problema está en la autenticación, en el cuerpo de la solicitud o en la temporización. Usa primero el ejemplo de curl para aislar si el problema está en tu código o en la entrada, y luego traslada la corrección a Python.
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