Tutorial
Cómo llamar a gemini-3.1-flash-tts en HiAPI: curl, Python y una solicitud funcional
Qué puede hacer gemini-3.1-flash-tts por ti en HiAPI
gemini-3.1-flash-tts es un modelo de texto a voz disponible a través de la API unificada de HiAPI. Envías texto y la configuración de voz, y la plataforma devuelve el audio generado. Como se expone mediante una interfaz única y coherente, no necesitas integrar cada modelo por separado: las mismas cabeceras de autenticación, la misma URL base y el mismo patrón de tareas asíncronas se aplican a todos los modelos TTS de la plataforma.
Puedes elegir este modelo cuando necesites:
- Narración con múltiples hablantes. Guiones, diálogos o contenido estilo pódcast en el que distintos fragmentos deben sonar como voces diferentes.
- Respuesta rápida. La serie
flashestá orientada a la generación de baja latencia, algo especialmente importante para aplicaciones interactivas o tareas por lotes con SLA ajustados. - Una interfaz de integración predecible. Una sola forma de solicitud cubre todos los casos, desde una línea de texto hasta escenarios con múltiples hablantes.
Si tu aplicación ya llama a otros modelos de HiAPI, añadir capacidad de voz solo requiere cambiar el identificador del modelo y ajustar el cuerpo de la solicitud: sin SDK nuevo ni flujo de credenciales nuevo.
Requisitos previos y configuración de autenticación
Antes de tu primera llamada, asegúrate de tener:
- Una cuenta de HiAPI y una clave de API. Genera la clave desde la consola. Trátala como un secreto: no la incluyas en el control de versiones.
- La URL base de HiAPI. Todas las solicitudes van al mismo host; solo cambia la ruta de cada endpoint.
- Una herramienta para realizar solicitudes HTTP.
curlpara pruebas rápidas, y Python 3.9+ con la bibliotecarequestspara scripts.
La autenticación se realiza mediante un token bearer en la cabecera Authorization:
Authorization: Bearer $HIAPI_API_KEY
Guarda la clave en una variable de entorno en lugar de codificarla directamente:
export HIAPI_API_KEY="your_key_here"
Todos los endpoints descritos a continuación (envío de tareas, consulta de estado y obtención de archivos) usan la misma cabecera. Si recibes un 401, significa que la cabecera falta, tiene un formato incorrecto o la clave ha sido revocada. Rota la clave en la consola en lugar de compartir una misma clave entre distintos entornos.
Construir el cuerpo de la solicitud para voz con múltiples hablantes
El cuerpo de la solicitud es JSON. Como mínimo debe incluir el identificador del modelo y el contenido de entrada. Para salidas con múltiples hablantes, debes añadir una configuración de hablantes que asocie hablantes con nombre a voces, y marcar el texto de entrada con etiquetas de hablante.
Un cuerpo de solicitud típico se ve así:
{
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": true,
"speakers": [
{ "name": "Host", "voice": "voice_a" },
{ "name": "Guest", "voice": "voice_b" }
]
}
}
Puntos clave que suelen causar problemas:
- Los nombres de los hablantes deben coincidir exactamente. Los
namedel arrayspeakersdeben coincidir exactamente con las etiquetas usadas en el texto (en este caso, entre corchetes). Una discrepancia en mayúsculas y minúsculas es la causa más frecuente de fallo en la renderización con múltiples hablantes. - Cada etiqueta debe estar declarada. Si el texto referencia
[Narrator]pero no se define un hablante conname: "Narrator", la solicitud será rechazada. - Los identificadores de voz provienen del catálogo de voces de la plataforma. Usa los identificadores que proporciona HiAPI, no los inventes. Para tareas de un solo hablante, omite
multi_speakeryspeakers, y en su lugar establece un único campovoice. - El texto se envía como una única cadena. Los guiones largos no son problema, pero ten en cuenta los límites por solicitud documentados en la plataforma.
Una vez que el cuerpo de la solicitud pasa la validación, la tarea se acepta y se devuelve un identificador de tarea, que usarás para consultar su estado.
Ejecutar con curl
Guarda el cuerpo de la solicitud anterior como payload.json y envíalo:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d @payload.json
La respuesta contiene un objeto de tarea con los campos id y status (normalmente queued o processing):
{ "id": "job_abc123", "status": "queued" }
Para comprobar el progreso, obtén la tarea por su ID:
curl "$HIAPI_BASE_URL/v1/audio/speech/jobs/job_abc123" \
-H "Authorization: Bearer $HIAPI_API_KEY"
Cuando status pase a succeeded, la respuesta incluirá una referencia al archivo de audio (una URL o un ID de archivo) que puedes descargar mediante una solicitud posterior; consulta la sección de sondeo más abajo. Si la tarea falla, status será failed y habrá un campo error que explica el motivo.
Para experimentar rápidamente, puedes omitir el archivo y pasar el JSON directamente:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gemini-3.1-flash-tts","input":{"text":"Hello from HiAPI.","voice":"voice_a"}}'
Ejecutar con Python
La versión en Python usa requests y una pequeña función auxiliar para mantener legible el bucle de sondeo. El cuerpo de la solicitud es idéntico al del ejemplo con curl.
import os
import time
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
payload = {
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": True,
"speakers": [
{"name": "Host", "voice": "voice_a"},
{"name": "Guest", "voice": "voice_b"},
],
},
}
resp = requests.post(
f"{BASE_URL}/v1/audio/speech/jobs",
headers={**HEADERS, "Content-Type": "application/json"},
json=payload,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print("submitted", job_id)
while True:
r = requests.get(f"{BASE_URL}/v1/audio/speech/jobs/{job_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
status = r.json()
if status["status"] in ("succeeded", "failed"):
break
time.sleep(2)
if status["status"] == "failed":
raise RuntimeError(status.get("error"))
print("audio ready:", status["output"])
Consideraciones:
- Los tiempos de espera son importantes. Establece un tiempo de espera explícito en cada solicitud; un bucle de sondeo bloqueado es peor que un bucle que falla.
- No consultes con demasiada frecuencia. Un intervalo de dos segundos es razonable para guiones cortos; para guiones largos conviene aplicar retroceso exponencial.
- Coloca el cuerpo de la solicitud en una función. En código real, parametriza el texto, los hablantes y las voces para poder reutilizar la misma lógica de envío en tareas de un solo hablante.
Sondear tareas asíncronas y descargar el audio
La generación de voz es asíncrona: envías la tarea y luego consultas el estado hasta que la tarea alcanza un estado terminal. Hay dos estados terminales: succeeded y failed. Cualquier otro estado debe tratarse como "seguir esperando".
Un sondeo robusto debería:
- Limitar el tiempo total de espera. Incluso un modelo rápido puede quedar detrás de otro trabajo. Detente tras un límite razonable y expón el ID de la tarea para que quien llama pueda reintentar.
- Retroceso exponencial. Empieza con uno o dos segundos y duplica en cada intento hasta un límite. Así evitas someter la API a una carga excesiva durante tareas largas.
- Gestionar los fallos de forma explícita. Cuando
status == "failed", lee y registra el campoerror; normalmente apunta a un problema en el cuerpo de la solicitud (hablante no declarado, texto vacío, voz no compatible).
Cuando la tarea tiene éxito, la respuesta de estado incluye una referencia de salida. Descárgala con las mismas cabeceras de autenticación:
out = status["output"]
audio = requests.get(out["url"], headers=HEADERS, timeout=60)
audio.raise_for_status()
with open("narration.wav", "wb") as f:
f.write(audio.content)
Si la respuesta devuelve un ID de archivo en lugar de una URL, obtenlo a través del endpoint de archivos correspondiente en HiAPI. Guarda el ID de la tarea original junto con el archivo descargado: es la única forma fiable de rastrear más adelante una renderización deficiente hasta su solicitud.
Entender el cobro por caracteres
gemini-3.1-flash-tts en HiAPI se factura según el número de caracteres del texto de entrada. No hay componentes de facturación por solicitud ni por minuto que modelar: el coste de la tarea escala con la cantidad de texto que envías, lo que hace que el cálculo sea sencillo: el número total de caracteres de todos los guiones multiplicado por la tarifa actual por carácter.
Implicaciones prácticas:
- Calcula el coste antes de lanzar. Suma el volumen de texto mensual previsto y compáralo con la tarifa actual que aparece en el panel de precios. No codifiques la tarifa directamente en el código; léela desde la plataforma al compilar o guárdala en la configuración.
- El contenido largo domina el coste. Diez minutos de narración son principalmente coste de texto. Si vas a generar audiolibros o material de cursos, modela primero el volumen.
- Los reintentos generan costes. Las tareas que fallan después de la generación pueden seguir facturándose, según el modo de fallo. Valida en el cliente antes de enviar: comprueba que cada etiqueta de hablante esté declarada y que el texto no esté vacío.
- Cachea de forma activa. Si un mismo guion se renderiza repetidamente (por ejemplo, en demostraciones o fixtures de prueba), guarda el audio generado y reutilízalo en lugar de facturar varias veces los mismos caracteres.
Para conocer las tarifas actuales y cualquier tramo por volumen, consulta el panel de precios del sitio web: es la única fuente de verdad.
Puntos de fallo habituales y cómo solucionarlos
La mayoría de los problemas de integración encajan en unas pocas categorías. Revísalos en orden.
401 no autorizado
Tu cabecera Authorization falta o tiene un formato incorrecto. Confirma que la clave está definida en el entorno y que el contenido de la cabecera es exactamente Bearer <key>. Si la clave se ha rotado, actualiza tu entorno.
400 solicitud incorrecta: hablante desconocido
El texto contiene una etiqueta [Name] que no está declarada en speakers, o las mayúsculas y minúsculas no coinciden. Haz que la etiqueta y el campo name sean idénticos byte a byte.
400 solicitud incorrecta: entrada vacía o demasiado grande
El texto vacío no pasa la validación de inmediato. Los guiones muy largos pueden superar el límite por solicitud; divídelos en varias tareas en lugar de truncarlos.
400 solicitud incorrecta: identificador de voz no válido
Los nombres de voz deben provenir del catálogo de la plataforma. Copia el identificador exactamente; no inventes nombres descriptivos.
La tarea se queda en estado processing
Normalmente esto es cola de espera, no un bug. Aplica retroceso y un tiempo de espera total. Si persiste mucho más allá de lo normal, registra el ID de la tarea y reintenta una vez con un cuerpo de solicitud más pequeño para determinar si el tamaño es el problema.
La tarea failed con un error de generación
Lee el campo error. Normalmente apunta a un problema de contenido o configuración, no a un fallo transitorio. Corrige el cuerpo de la solicitud, vuelve a enviarla y evita bucles de reintento ciegos: cada intento puede facturar caracteres.
El audio se puede descargar pero no se reproduce
Antes de asumir que el archivo está dañado, comprueba el tipo de contenido del archivo descargado. Guárdalo con la extensión correcta correspondiente al formato devuelto y verifica que la longitud en bytes no sea cero. Un archivo truncado suele significar que la solicitud de descarga se interrumpió: reintenta la descarga en lugar de volver a generar.
Con estas comprobaciones, la mayoría de los problemas de integración del primer día se resuelven en minutos en lugar de horas.
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