HiAPI
Blog

Tutorial

Cómo llamar a gemini-3.1-flash-tts en HiAPI: curl, Python y una solicitud funcional

Oct 31, 2026
深靛蓝色背景上多层嵌套的宽箭头依次向右上方推进,箭头前缘为杏橙色,构成规整的信号流示意图形,这是文章的封面图。

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 flash está 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:

  1. 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.
  2. La URL base de HiAPI. Todas las solicitudes van al mismo host; solo cambia la ruta de cada endpoint.
  3. Una herramienta para realizar solicitudes HTTP. curl para pruebas rápidas, y Python 3.9+ con la biblioteca requests para 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 name del array speakers deben 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 con name: "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_speaker y speakers, y en su lugar establece un único campo voice.
  • 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:

  1. 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.
  2. 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.
  3. Gestionar los fallos de forma explícita. Cuando status == "failed", lee y registra el campo error; 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 →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API