Skip to main content

Introducción

La transcripción de voz en tiempo real establece una conexión persistente mediante WebSocket (un protocolo que mantiene una conexión de larga duración entre el cliente y el servidor y permite enviar datos de forma bidireccional). Recibe, transcribe y devuelve el flujo de audio de entrada de forma continua, lo que resulta adecuado para escenarios de voz sensibles a la latencia. Su diferencia con la transcripción de archivos STT: Modelos disponibles:
  • gpt-live-transcribe: modelo de transcripción por streaming, admite varios idiomas y produce el texto transcrito en tiempo real a medida que entra el audio.
Esta API está pensada para integración del lado del servidor; el navegador no puede conectarse directamente. Por motivos de seguridad, el gateway valida y rechaza las conexiones que incluyen la cabecera Origin, rechaza el subprotocolo openai-insecure-api-key y solo acepta la clave mediante la cabecera estándar Authorization. Los WebSocket iniciados por el navegador añaden automáticamente la cabecera Origin, por lo que se rechazan. Si necesitas hacer transcripción en tiempo real en el frontend, establece la conexión al gateway desde tu propio servidor y reenvía después los resultados al frontend.

Inicio rápido

Endpoint de conexión

  • intent=transcription: obligatorio, declara que se trata de una sesión de transcripción.
  • model=gpt-live-transcribe: obligatorio, el modelo queda fijado por el parámetro de la URL en el momento de la conexión y no se puede cambiar durante la sesión (ver las restricciones más abajo).

Autenticación

Durante el handshake, la clave se pasa mediante la cabecera HTTP estándar:

Requisitos del formato de audio

Actualmente solo se admite un formato de entrada. Antes de enviar, convierte el audio a:
  • Codificación: PCM16 (entero con signo de 16 bits, little-endian)
  • Frecuencia de muestreo: 24000 Hz
  • Canales: mono (mono)
Es decir, audio/pcm@24000. Enviar un formato distinto (como G.711/µ-law) provoca el rechazo y el cierre de la sesión.
Las sesiones de transcripción no admiten la detección de actividad de voz (turn_detection / VAD), por lo que debe establecerse explícitamente en null. Si se omite o se pasa un valor distinto de null, el proveedor de modelos lo rechaza con invalid_value. El gateway fuerza a null el campo turn_detection en la configuración que reenvía, pero se recomienda que lo establezcas en null de forma activa en el cliente para mantener un comportamiento claro.

Configuración de la sesión (session.update)

Una vez establecida la conexión, el cliente envía primero un frame session.update para configurar los parámetros de transcripción. Si no lo envías, el gateway inyecta una configuración por defecto de respaldo con el modelo autorizado, pero se recomienda configurarla explícitamente.

Parámetros de configuración

string
requerido
Tipo de sesión; en el escenario de transcripción es fijo transcription.
object
requerido
Formato del audio de entrada, fijo en { "type": "audio/pcm", "rate": 24000 }.
string
requerido
Modelo de transcripción. Debe coincidir con el parámetro model de la URL de conexión (gpt-live-transcribe). Pasar otro modelo se considera un uso no autorizado y la sesión se cierra con 1008.
string[]
Lista de idiomas esperados, en forma de array (por ejemplo, ["en", "zh"]). gpt-live-transcribe usa la forma plural languages, que permite declarar varios idiomas de una vez; especificar el idioma mejora la precisión y reduce la latencia. El diccionario de valores admitidos está más abajo en Códigos de idioma.
string
Forma singular, un único código ISO-639-1 (por ejemplo, "en"). Es una u otra con languages, no las pases a la vez (pasar ambas se rechaza con invalid_value). Para gpt-live-transcribe se recomienda oficialmente usar la forma plural languages; el gateway también acepta la forma singular language para facilitar la migración desde código antiguo.
string
Prompt de texto libre que describe el escenario de la grabación (por ejemplo, «llamada de atención al cliente» o «consulta médica con terminología médica»), para ayudar al modelo a ajustarse al registro. En las pruebas, el servidor lo devuelve tal cual en session.updated, ya está en efecto.
string[]
Array de palabras clave literales, para nombres de producto, siglas, nombres propios y otras palabras propensas a error (por ejemplo, ["AiHubMix", "gpt-live-transcribe"]). Es una sugerencia, no una salida forzada; cada palabra debe ir como un elemento independiente y conviene evitar que incluya <, > o saltos de línea. En las pruebas se devuelve y está en efecto.
string
Nivel de latencia / precisión; valores posibles: minimal, low, medium, high, xhigh. Cuanto más alto el nivel, mayor precisión pero también mayor latencia. Nota: el gateway acepta este campo (no da error), pero en las pruebas no se devuelve en session.updated; su efectividad se rige por la documentación oficial y de momento no está confirmada por el eco de respuesta.
null
requerido
Detección de actividad de voz. En las sesiones de transcripción debe ser null.
object
Configuración opcional de reducción de ruido, como { "type": "near_field" } (campo cercano, adecuado cuando el micrófono está cerca de quien habla) o { "type": "far_field" } (campo lejano).

Códigos de idioma (language codes)

Los valores de languages / language siguen los formatos siguientes, distinguen mayúsculas y minúsculas y deben tener una de las formas admitidas más abajo; pasar un código no admitido o con formato erróneo lo rechaza la API de realtime:
Al usar la forma plural languages, coloca primero los idiomas con mayor probabilidad de aparecer. En escenarios con mezcla de idiomas (como chino e inglés mezclados) puedes escribir ["zh", "en"]; para un solo idioma basta con escribir ["en"], que es más preciso y más rápido que no especificarlo.

Envío de audio

Divide el audio PCM16 en fragmentos pequeños (por ejemplo, uno cada 100ms), codifícalos en base64 y envíalos de forma continua mediante el evento input_audio_buffer.append:
Dado que las sesiones de transcripción no habilitan VAD (detección de actividad de voz), el servidor no determina automáticamente cuándo termina un segmento. Tras enviar un segmento de audio, debes enviar manualmente un frame input_audio_buffer.commit para marcar el fin de ese segmento, lo que desencadena el cierre de la transcripción y devuelve el resultado completed:

Recepción de los resultados de transcripción

El servidor envía eventos de forma continua. Tipos de evento clave:
event
Confirmación de la creación de la sesión y de la actualización de la configuración.
event
Resultado incremental de la transcripción; el campo delta es el fragmento de texto añadido en esta ocasión. Se devuelve mientras se habla, adecuado para mostrarlo en pantalla en tiempo real.
event
Transcripción de un segmento de voz completada; el campo transcript es el texto completo de ese segmento.
event
Evento de error, incluye el código de error y su descripción.

Ejemplo completo

A continuación se presentan dos enfoques; elige el que prefieras:
  • SDK oficial de OpenAI (recomendado): no requiere escribir el WebSocket a mano; basta con apuntar websocket_base_url (el parámetro de la URL base del WebSocket del SDK) al gateway para reutilizar la biblioteca oficial.
  • websockets nativos: sin instalar el SDK, envía y recibe frames directamente según el protocolo, con dependencias mínimas y fácil de depurar.
¿Por qué la demo oficial no pasa el nombre del modelo y nosotros sí? El intent de transcripción de OpenAI coloca el modelo en transcription.model dentro de session.update, y la URL de conexión solo lleva ?intent=transcription. El gateway de AiHubMix es distinto: el nombre del modelo debe aparecer en la URL del handshake (?model=gpt-live-transcribe), porque el gateway lo necesita en el instante mismo del handshake del WebSocket para elegir el proveedor de modelos, autenticar y reservar cuota, mientras que session.update llega después de completado el handshake, demasiado tarde. Por eso, al usar el SDK debes pasar model explícitamente a connect() (el SDK lo incorpora al query de la URL); si falta, el gateway responde 400 missing_model_parameter durante el handshake: connect() lanza una excepción directamente, la conexión no llega a establecerse y nunca se alcanza el paso de session.update. Dentro de la sesión, transcription.model debe seguir coincidiendo con la URL.
Para convertir cualquier audio al formato PCM en crudo que requiere esta API, puedes usar ffmpeg:

Resultado de ejecución (prueba real en producción)

A continuación se muestra el resultado real de ejecutar el ejemplo anterior en el entorno de producción de aihubmix.com (modelo gpt-live-transcribe). Se configuró languages: ["en", "zh"] + prompt + keywords + delay: "low" + noise_reduction: { "type": "near_field" }:
En las pruebas, el servidor devuelve tal cual languages, prompt, keywords y noise_reduction en session.updated, lo que indica que la configuración está realmente en efecto (no que simplemente se acepte sin procesar). El campo delay lo acepta el gateway pero no se devuelve; su efectividad se rige por la documentación oficial. De language (singular) y languages (plural) solo se puede pasar una de las dos.

Notas de facturación

  • Precio unitario: gpt-live-transcribe se factura a $0.017 / minuto (rige el precio de lista en tiempo real de la página de detalle del modelo).
  • Se factura por la duración del audio transcrito: rige el número de segundos de audio realmente reenviados al modelo de transcripción, redondeado hacia arriba al segundo entero. Por ejemplo, transcribir 90 segundos de audio se factura como 90 ÷ 60 × $0.017 = $0.0255.
  • La facturación no se ve afectada por el ida y vuelta de red ni por la espera en inactividad; solo se cronometra el audio que realmente entra en la transcripción.
  • Liquidación sobre la marcha: es una conexión de larga duración, por lo que el coste no se liquida de una sola vez al terminar la sesión, sino que se descuenta en tiempo real por segmentos durante la sesión. Al establecer la sesión se hace primero una reserva de cuota por un consumo de aproximadamente 1 minuto (solo como validación de acceso, no es un cargo real); durante la sesión, la reserva se renueva de forma continua cada 20 segundos, y el coste real se descuenta por segmentos según los segundos realmente reenviados; al terminar la sesión se libera la reserva restante. Por lo tanto, el saldo disponible de la cuenta debe cubrir al menos un consumo de aproximadamente 1 minuto para que la sesión pueda establecerse.
  • En el detalle de consumo de Uso y facturación, la nota de cada registro de transcripción en tiempo real indica el «precio por minuto» y los «segundos realmente cobrados en esta ocasión», para facilitar la conciliación registro a registro.
Registro de facturación de una transcripción en tiempo real de gpt-live-transcribe en la vista Activity de Uso y facturación, con una nota que muestra 7 s de audio cobrados a $0.017 por minuto

Un registro de facturación de transcripción en tiempo real de gpt-live-transcribe en la vista Activity de Uso y facturación; la nota indica 7 s de audio cobrados a $0.017 / min = $0.001982, conforme al formato descrito arriba.

Límites y restricciones

  1. Duración de una sesión: una conexión WebSocket dura como máximo 62 minutos; al cumplirse, el servidor la cierra de forma activa; si necesitas más tiempo, reconéctate por segmentos.
  2. Saldo insuficiente: hay dos casos. Al establecer la sesión, si el saldo disponible no cubre la reserva de cuota de aproximadamente 1 minuto, el handshake se rechaza directamente (HTTP 403) y la sesión no se establece; durante la sesión, si se agota el saldo (detectado en la validación de renovación cada 20 segundos o en la revisión tras un descuento por segmento), la conexión ya establecida se cierra de inmediato.
  3. Solo del lado del servidor: no se admite la conexión directa desde el navegador (se valida la cabecera Origin); realiza la integración en el servidor.
  4. Bloqueo del modelo: el modelo queda fijado en la URL de conexión; cambiar el modelo durante la sesión mediante session.update se rechaza y se cierra la sesión.
  5. Bloqueo del formato: solo se admite audio/pcm@24000 en mono; cualquier otro formato se rechaza.

Errores frecuentes


Última actualización: 2026-09-16