Tutorial
Cómo usar imagen4-ultra a través de la API de HiAPI: ejemplos con curl y Python
Ejercicio práctico completo de solicitud para generación de imágenes de alta calidad a partir de texto en HiAPI
Qué te ofrece imagen4-ultra en HiAPI
imagen4-ultra es el modelo de generación de imágenes de alta calidad a partir de texto de HiAPI: envías un prompt y recibes una imagen generada. Lo realmente útil para los desarrolladores es que, al igual que todos los demás modelos de la plataforma, se ejecuta detrás de la interfaz unificada de HiAPI, por lo que el método de autenticación, la estructura de las solicitudes y el patrón de manejo de tareas que aprendas aquí podrás reutilizarlos directamente en otros endpoints.
Este tutorial es un ejercicio práctico ejecutable, no una mera lista de parámetros. Al terminar tendrás:
- una solicitud
curllista para copiar y pegar que envía una tarea de generación de imágenes a partir de texto, - un pequeño cliente en Python reescrito a partir de la misma solicitud,
- una idea clara de cómo la relación de aspecto y otras opciones afectan la salida,
- y un bucle de sondeo para esperar a que la tarea finalice y guardar la imagen en disco.
Una aclaración previa: la generación de imágenes no es instantánea. imagen4-ultra funciona de forma asíncrona: envías la tarea, obtienes un identificador de tarea y luego sondeas hasta que el renderizado termine. Si has usado otros endpoints asíncronos de HiAPI, este flujo te resultará familiar; si no, el capítulo de sondeo cubre el ciclo de vida completo.
Nos mantendremos siempre dentro del ámbito de la propia API de HiAPI: sin SDK específicos de proveedores ni consolas de terceros. Una URL base, una clave y un formato de solicitud.
Antes de enviar la primera solicitud
Antes de que la primera llamada tenga éxito, necesitas tres cosas.
1. Una clave de API
Genera la clave desde la consola de tu cuenta de HiAPI. Trátala como una contraseña: guárdala en una variable de entorno en lugar de pegarla directamente en el archivo fuente.
export HIAPI_API_KEY="your-key-here"
2. La URL base
Todas las solicitudes de HiAPI se envían al mismo host de API documentado en la documentación de la plataforma. Centralízalo en un solo lugar en tu código para no tenerlo codificado en varios sitios:
export HIAPI_BASE_URL="https://api.hiapi.ai"
Si tu cuenta o región usa otro host, utiliza el valor que muestra la consola; la ruta de solicitud que aparece a continuación no cambia.
3. Cómo se transmite la autenticación
HiAPI usa un token bearer en la cabecera Authorization. Cada solicitud, ya sea de envío o de sondeo, lleva las mismas dos cabeceras:
Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json
Eso es todo en cuanto a autenticación. No hay pasos de firma de solicitud ni intercambio de tokens por llamada. Con solo poder configurar cabeceras, ya puedes llamar a esta API.
Antes de continuar, haz una comprobación básica: confirma que tu clave está exportada en la misma sesión de shell en la que vas a ejecutar curl. Una gran parte de los informes de "401 Unauthorized" acaba reduciéndose a una clave exportada en una pestaña del terminal pero usada en otra.
En adelante asumiremos siempre que el identificador del modelo es imagen4-ultra. Si quieres confirmar la cadena exacta que expone tu cuenta, consulta la lista de modelos en la documentación.
La solicitud curl ejecutable
A continuación tienes una solicitud de envío completa. Envía el prompt, establece la relación de aspecto de salida y pide una sola imagen.
curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "imagen4-ultra",
"prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
"aspect_ratio": "16:9",
"n": 1
}'
Explicación campo por campo del cuerpo de la solicitud:
model: el identificador del modelo que estás invocando. Determina el enrutamiento de la solicitud; sin él, la API no puede saber qué modelo ejecutar.prompt: la descripción en lenguaje natural de la imagen. Es la palanca principal que afecta a la calidad de la salida. Sé específico con el sujeto, la iluminación, el estilo y la composición; los prompts vagos solo producen imágenes vagas.aspect_ratio: la forma del lienzo de salida, expresada como anchura:altura. Se detalla más adelante.n: cuántas imágenes generar en este envío. Mantenlo en1durante las pruebas para que el coste de cada ejecución sea fácil de calcular.
Según la configuración del endpoint, la respuesta contendrá la imagen ya completada o, lo que es más habitual en este tipo de modelos, un objeto de tarea con un identificador y un campo de estado. Guarda ese identificador; el capítulo de sondeo depende de él.
# 提交响应的典型结构
{
"id": "job_abc123",
"status": "queued"
}
Pasa la respuesta por una herramienta de formateo JSON (si la tienes, | jq .) para poder leer los nombres de los campos según la respuesta de tu cuenta, en lugar de entrecerrar los ojos ante una sola línea.
Escribir la misma solicitud en Python
La versión en Python es una traducción línea por línea: la misma URL, las mismas cabeceras, el mismo cuerpo de solicitud. Usar requests hace que la correspondencia sea evidente:
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ.get("HIAPI_BASE_URL", "https://api.hiapi.ai")
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
payload = {
"model": "imagen4-ultra",
"prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
"aspect_ratio": "16:9",
"n": 1,
}
response = requests.post(
f"{BASE_URL}/v1/images/generations",
headers=headers,
json=payload,
timeout=30,
)
response.raise_for_status()
job = response.json()
print(job["id"], job["status"])
Al llevar este código a un servicio real, hay varios puntos que conviene mantener:
- Lee la clave desde una variable de entorno, nunca desde un literal en el archivo. La forma
os.environ[...]falla de manera explícita cuando la variable no existe, que es justo lo que quieres. - Establece un timeout explícito para la llamada de envío. La tarea en sí se ejecuta de forma asíncrona, así que la solicitud HTTP debería devolver rápido; un límite de 30 segundos detecta problemas de red en lugar de dejar el programa colgado.
- Llama a
raise_for_status()antes de tocar el JSON. El cuerpo de una respuesta 4xx no tiene la estructura que esperas; fallar antes da una traza más clara que unKeyErrortres líneas más abajo. - Reutiliza
requests.Sessionsi vas a enviar muchas tareas; el pooling de conexiones importa más de lo que parece.
Si prefieres httpx o aiohttp, la conversión es mecánica: el mismo diccionario de headers, el mismo cuerpo JSON, la misma ruta. La solicitud en sí es independiente de la librería HTTP.
Relación de aspecto y opciones de la solicitud
La relación de aspecto es la opción que más ajustarás, porque cambia tanto la composición como las dimensiones de salida disponibles para el diseño posterior.
La relación de aspecto se pasa en el cuerpo de la solicitud como una cadena "width:height": "1:1", "16:9", "9:16", "4:3", "3:2", etc. Elige la proporción que coincida con el uso final de la imagen:
1:1: avatares, fichas de producto, publicaciones sociales que se recortan a cuadrado.16:9/9:16: banners principales, miniaturas de vídeo, ubicaciones en formato de historia vertical.4:3/3:2: composición fotográfica clásica, diseños de galería.
Establece la proporción de forma consciente en lugar de generar un cuadrado y recortarlo después. El recorte descarta píxeles que ya has pagado por generar y puede dejar el sujeto fuera del encuadre. Si conoces la ubicación final, codifícala en la solicitud.
Además de la relación de aspecto, las opciones que importan en el uso diario son:
prompt: sigue siendo la entrada con mayor influencia. Itera aquí antes de hacerlo en cualquier otro sitio.n: el número de imágenes generadas por envío. Útil cuando quieres varias variantes entre las que elegir; mantén un valor bajo durante la fase de exploración de prompts.model: el identificador exacto de la variante del modelo. Si tu cuenta expone varios modelos de imagen, este es el conmutador entre ellos.
Cíñete a los parámetros documentados para ese endpoint y no adivines nombres. Los campos desconocidos son una causa habitual de respuestas 400, y una opción mal escrita pasa fácilmente desapercibida en un cuerpo de solicitud grande. En caso de duda, envía primero un cuerpo mínimo (model, prompt, aspect_ratio), confirma que funciona y luego añade una opción cada vez.
Sondear la tarea asíncrona y descargar el resultado
La generación de imágenes lleva tiempo, así que la llamada de envío devuelve una tarea, no una imagen. El ciclo de vida es: enviar → sondear el estado → descargar la salida.
Paso 1: enviar y capturar el ID de la tarea
Reutiliza la solicitud anterior y extrae el id de la respuesta:
job = response.json()
job_id = job["id"]
Paso 2: sondear hasta que la tarea llegue a un estado terminal
Sondea el endpoint de estado con las mismas cabeceras de autenticación, durmiendo entre intentos. Aplica retroceso gradual para no presionar demasiado la API:
import time
def wait_for_job(job_id, headers, base_url, timeout=300):
deadline = time.time() + timeout
delay = 2
while time.time() < deadline:
r = requests.get(
f"{base_url}/v1/images/generations/{job_id}",
headers=headers,
timeout=30,
)
r.raise_for_status()
data = r.json()
status = data["status"]
if status == "succeeded":
return data
if status == "failed":
raise RuntimeError(f"job failed: {data}")
time.sleep(delay)
delay = min(delay * 2, 15)
raise TimeoutError(f"job {job_id} not finished within {timeout}s")
Detalles clave: un plazo límite estricto, un tope para el intervalo de retroceso y una rama explícita para el estado de fallo, de modo que una tarea problemática se manifieste como una excepción en lugar de quedarse colgada indefinidamente.
Paso 3: descargar la imagen
La respuesta de una tarea completada contiene la ubicación de la salida: una URL o una referencia de artefacto equivalente. Obténla y escribe los bytes en disco:
result = wait_for_job(job_id, headers, BASE_URL)
image_url = result["output"][0]["url"]
img = requests.get(image_url, timeout=60)
img.raise_for_status()
with open("lighthouse.png", "wb") as f:
f.write(img.content)
Dos hábitos que evitan la mayoría de los imprevistos en producción: escribe siempre en modo binario ("wb"), nunca en modo texto; y trata la URL de descarga como temporal: guarda el archivo inmediatamente en tu propio almacenamiento en lugar de confiar en que el enlace siga siendo válido indefinidamente.
Errores comunes y cómo solucionarlos
La mayoría de los fallos se agrupan en unas pocas categorías. A continuación se indica cómo se manifiesta cada una y cómo resolverla.
401 Unauthorized
La clave falta, tiene un formato incorrecto o no es visible para el proceso que realiza la solicitud.
- Comprueba que la cabecera sea exactamente
Authorization: Bearer <key>: la palabraBearer, un espacio y luego la clave. - Confirma que la variable de entorno está establecida en el mismo shell o proceso. En contenedores y CI, las variables exportadas en tu shell local no viajan con el código.
- Si has rotado la clave recientemente, asegúrate de que la clave anterior no siga almacenada en caché en algún sitio.
400 Bad Request
Normalmente es un problema del cuerpo de la solicitud.
- Nombres de campo desconocidos o mal escritos: cíñete a los parámetros documentados.
- Valores de
aspect_ratioque el endpoint no acepta: usa la formawidth:heightde la documentación. nfuera del rango permitido.- JSON mal formado, por ejemplo una coma sobrante o comillas sin escapar dentro de la cadena del prompt. Si sospechas de esto, imprime el cuerpo de la solicitud formateado antes de enviarlo.
404 en el paso de consulta de estado o de descarga
El ID de la tarea es incorrecto, o la ruta que estás sondeando no coincide con el endpoint que usaste al enviar. En la primera integración, registra completa la respuesta de envío y compara el ID carácter por carácter.
Timeout de sondeo
Si wait_for_job alcanza el plazo límite:
- Confirma que estás comprobando el valor de estado correcto; un estado terminal que no reconoces parece un cuelgue.
- Para renderizados grandes y complejos, aumenta el timeout global en lugar de acortar el intervalo de sondeo.
- Registra cada respuesta de estado durante la integración para ver cuánto tarda realmente la tarea con tu combinación de prompts.
El estado de la tarea devuelve failed
Lee el cuerpo de error que devuelve la API: está ahí por algo. Las tareas fallidas suelen deberse al prompt o a los parámetros; la corrección está en la solicitud, no en el código de sondeo.
Cuando algo no esté claro, la documentación de HiAPI de ese modelo es la fuente autoritativa de nombres de campo y valores aceptables. Valida un solo cambio cada vez y guarda una solicitud que sepas que funciona como referencia para la próxima integración.
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