Programa
Grok Voice Transcribe 2.0 de SpaceXAI es un modelo de voz a texto. En este tutorial de la API Grok Voice Transcribe 2.0, envías grabaciones por REST y audio en directo por WebSocket. La API devuelve texto, marcas temporales por palabra, IDs de hablante opcionales y eventos de fin de turno; no responde al interlocutor.
Una llamada de soporte es más compleja que un narrador limpio. Hay pausas cortas, nombres poco comunes, varias voces y datos de contacto dictados por una línea a 8 kHz. Nuestro proyecto, llamado Qivora Sync, da cohesión al tutorial: un cliente reporta un fallo de sincronización de archivos, el agente recoge los datos de contacto y se une un ingeniero de escalado. El mismo cliente de Python gestiona primero la grabación y después el audio en vivo.
Para voz a voz, donde el modelo responde directamente a la llamada, consulta nuestro tutorial de Grok Voice Think Fast 2.0. El código de este tutorial está en el repositorio de GitHub.
TL;DR
¿Vas con prisa? Esto es lo que mostró la llamada.
-
POST /v1/sttgestiona audio grabado ywss://api.x.ai/v1/sttaudio en directo, con controles comunes para diarización, términos clave, muletillas y manejo de audio. -
Un término clave corrigió el nombre inventado del producto, pero un sesgo de vocabulario fuerte arrastró un eco tenue hacia ese nombre en una comprobación con hablante en vivo.
-
Las etiquetas de hablante se mantuvieron estables en la mezcla limpia pero se volvieron poco fiables a 8 kHz.
-
El cambio al árabe se mantuvo en escritura árabe, y
format=truearregló el número de teléfono, pero solo medio arregló el email. -
En la larga pausa a mitad del número, Smart Turn superó todos los umbrales probados, así que ajustar el umbral por sí solo no fue suficiente.
Ingeniero Asociado de IA para Científicos de Datos
¿Qué es Grok Voice Transcribe 2.0?
Grok Voice Transcribe 2.0 (grok-voice-transcribe-2.0) es el modelo de voz a texto de SpaceXAI. La ruta REST transcribe un archivo finalizado, mientras que la ruta WebSocket gestiona audio en directo.
El anuncio de Grok Voice Transcribe 2.0 de SpaceXAI destaca las llamadas telefónicas, múltiples hablantes, credenciales e idioma múltiple. Para comparativas de benchmarks, consulta nuestro resumen de Grok Voice Transcribe 2.0.
Cómo crear un transcriptor de soporte en tiempo real
El escenario controlado de Qivora Sync permanece fijo mientras cambian el audio y los ajustes de la API. La llamada incluye un nombre de producto inventado, muletillas, un cambio de idioma, datos de contacto dictados, una pausa durante el dictado y un tercer hablante.
Tres voces se convierten en una transcripción en vivo. Imagen del autor.
Creación de la llamada con tres hablantes
El escenario controlado usa tres voces distintas de la API Grok Text to Speech. Cada segmento de idioma se sintetiza por separado y se une con ffmpeg para que los puntos de cambio permanezcan fijos. La API también acepta language=auto; separar las solicitudes es una elección de diseño experimental, no un requisito de la API.
Definir la transcripción esperada
Antes de la primera petición, define el texto esperado, los hablantes, la ortografía del producto, los datos del cliente, las muletillas y las pausas. Así cada configuración tiene el mismo objetivo.
Configuración de Grok Voice Transcribe 2.0 en Python
Instala las dependencias antes de enviar audio.
Requisitos previos
Necesitas Python 3.10 o superior, una clave de API de xAI y ffmpeg para construir el audio. Los clientes de Python usan requests, websockets y python-dotenv.
La documentación de Speech to Text indica que la versión 2.0 es la predeterminada si omites model, y que grok-voice-transcribe-1.0 llegó a su fin de vida el 2 de octubre de 2026. Aun así, yo fijaría el ID de versión.
Instalar dependencias y construir el audio
Clona el repositorio, añade tu clave a .env y construye el audio de ejemplo:
git clone https://github.com/KhalidAbdelaty/grok-voice-transcribe-2.0.git
cd grok-voice-transcribe-2.0
pip install -r requirements.txt
cp .env.example .env # luego pega tu clave en .env
python project/scripts/make_fixtures.py
El comando de configuración crea el diálogo y los archivos de audio que se usarán más tarde. Si tienes tu propia grabación, omite ese comando.
Un .env escrito en Windows puede dejar un \r en la clave, y requests rechaza la cabecera antes de que llegue nada a SpaceXAI. Elimina ese carácter de la clave antes de añadirla a la cabecera de autorización.
Establecer una base de referencia por lotes
La base de referencia es el modelo sin opciones activadas, para poder comparar cada cambio posterior. La primera petición envía el archivo y un modelo fijado:
import os
import requests
from dotenv import load_dotenv
load_dotenv()
api_key = os.environ["XAI_API_KEY"].strip()
with open("support_call.wav", "rb") as audio_file:
response = requests.post(
"https://api.x.ai/v1/stt",
headers={"Authorization": f"Bearer {api_key}"},
data=[("model", "grok-voice-transcribe-2.0")],
files={"file": ("support_call.wav", audio_file, "audio/wav")},
)
response.raise_for_status()
result = response.json()
La respuesta incluye text, language detectado, duration y un array de words con tiempos. La referencia REST muestra confidence por palabra, pero no apareció en las respuestas por lotes de este escenario. Trata ese campo como opcional y comprueba cada respuesta de la API antes de usarlo. Pon los campos opcionales antes de file; los posteriores pueden ignorarse.
La base eliminó muletillas, mantuvo el árabe en escritura árabe y dejó los dígitos hablados separados. De forma consistente, escribió mal el nombre inventado del producto.
Añadir diarización, términos clave y formato de texto
Una transcripción de soporte necesita etiquetas de hablante, la ortografía correcta del producto y datos de cliente utilizables. Cada ajuste es un campo más del formulario:
data = [
("model", "grok-voice-transcribe-2.0"),
("diarize", "true"), # id de hablante en cada palabra
("keyterm", "Qivora Sync"), # repite el campo para más términos
("language", "en"), # requerido por format
("format", "true"), # normalización inversa de texto
("filler_words", "false"), # valor por defecto; true mantiene "uh" y "um"
]
Añade una opción cada vez sobre el mismo audio. Empieza por las etiquetas de hablante.
Agrupar palabras en turnos de hablante
La diarización de hablantes asigna IDs numéricos a las palabras, no nombres. Agrupa palabras consecutivas con el mismo ID para formar turnos:
def group_turns(words):
turns = []
for word in words:
if turns and turns[-1]["speaker"] == word.get("speaker"):
turns[-1]["words"].append(word["text"])
turns[-1]["end"] = word["end"]
else:
turns.append({"speaker": word.get("speaker"), "start": word["start"],
"end": word["end"], "words": [word["text"]]})
for turn in turns:
turn["text"] = " ".join(turn.pop("words"))
return turns
Con audio limpio, cada turno previsto mantuvo un ID de hablante coherente. Mapear nombres según el orden de primera aparición solo funciona cuando ya conoces el orden de la llamada; los sistemas en producción necesitan su propio mapeo de hablantes.

El audio limpio mantiene etiquetas de hablante consistentes. Imagen del autor.
Usar sesgo de término clave para nombres de producto
El sesgo por término clave es una pista por petición, no entrenamiento. Pasa keyterm=Qivora Sync (hasta 100 términos, 50 caracteres cada uno), y el modelo tenderá hacia esa ortografía cuando el audio la respalde.
El término clave corrigió el error del nombre del producto en la base, sin cambiar la transcripción circundante.
En una comprobación aparte con hablante en vivo, un vocabulario muy sesgado arrastró un eco tenue hacia el término clave. Eso no significa que los términos clave inventen texto por sí mismos; significa que el audio ambiguo sigue necesitando una comprobación de eco.
Transcribir cambios de inglés a árabe
Como mostró la base, el árabe de Khalid se mantuvo en escritura árabe. El resultado fue el mismo con detección automática y con language=en, porque language selecciona reglas de formato en lugar de forzar un idioma de salida.
Formatear números de teléfono y emails dictados
La base mantuvo los dígitos hablados por separado. La normalización inversa de texto (ITN) convierte esas formas habladas en escritas. format=true lo activa y requiere language, o la petición falla con un 400.
El número de teléfono pasó a ser una cadena continua de dígitos. El email solo se normalizó parcialmente: la puntuación mejoró, pero el "arroba" hablado y el dominio deletreado aún necesitaban limpieza.
Ese resultado irregular es frustrante. ITN da formato al texto; no valida datos de contacto. Yo validaría ambos campos antes de almacenarlos.
ITN también puede reescribir duraciones comunes como cantidades abreviadas. En la respuesta formateada por lotes de este escenario, solo se normalizó el text de nivel superior; el array words mantuvo la forma hablada.
Conservar o quitar muletillas
Como mostró la base, por defecto se eliminan las muletillas de text y words. filler_words=true trajo de vuelta los "eh" y "um" de Khalid donde correspondía. Déjalas desactivadas para notas de soporte y actívalas para un registro literal de QA.
La salida por lotes cubre hablantes, vocabulario, formato y control de muletillas. A continuación, envía el mismo audio como flujo en vivo.
Transmitir Grok Voice Transcribe 2.0 por WebSocket
La ruta en streaming usa parámetros de consulta en lugar de un mensaje de inicio. Espera transcript.created, envía audio binario en crudo (sin base64) y cierra con {"type": "audio.done"}. Nuestro tutorial de GPT Live Transcribe sigue el mismo patrón con otro modelo.
Empieza por los eventos y luego conecta el cliente.
En lotes se usa el format=true documentado junto con language=en. La documentación de streaming dice que language activa ITN, pero en una prueba en vivo, language=en por sí solo no cambió la transcripción. La lista de consulta del WebSocket no incluye format, así que este tutorial trata la ITN en streaming como un comportamiento a verificar, no en el que depender.
Leer eventos parciales y finales
Cada actualización de transcripción es un evento transcript.partial con dos booleanos. El texto interino aún puede cambiar. Un bloque final (is_final=true) fija unos 3 segundos de texto mientras el turno sigue abierto, y un final de enunciado (speech_final=true) cierra el turno.

Los estados en streaming llevan el texto hacia su finalización. Imagen del autor.
Transmitir audio PCM de 16 kHz en Python
Para transmitir, remuestrea primero la fuente a PCM mono de 16 bits a 16 kHz. El cliente principal envía bloques de 100 milisegundos al ritmo del tiempo real mientras otra tarea recibe eventos de transcripción:
import asyncio, json, os, wave
import websockets
from dotenv import load_dotenv
load_dotenv()
url = ("wss://api.x.ai/v1/stt?model=grok-voice-transcribe-2.0"
"&sample_rate=16000&encoding=pcm&interim_results=true&diarize=true")
headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY'].strip()}"}
async def stream_call(path):
async with websockets.connect(url, additional_headers=headers) as ws:
assert json.loads(await ws.recv())["type"] == "transcript.created"
async def send():
with wave.open(path, "rb") as wf:
assert wf.getframerate() == 16000
assert wf.getnchannels() == 1
assert wf.getsampwidth() == 2
while chunk := wf.readframes(1600):
await ws.send(chunk)
await asyncio.sleep(0.1)
await ws.send(json.dumps({"type": "audio.done"}))
async def receive():
async for raw in ws:
event = json.loads(raw)
if event["type"] == "transcript.partial":
print(event["text"])
elif event["type"] == "transcript.done":
break
await asyncio.gather(send(), receive())
El texto interino crecía aproximadamente cada medio segundo. Es una medición local, no latencia oficial.

Los subtítulos parciales se asientan en la transcripción final. Imagen del autor.
Los "chunk finals" congelan texto sin cerrar el turno. Smart Turn controla cuándo speech_final lo cierra.
Mantener los bloques de transcripción en orden
Si solo muestras el evento activo, las palabras anteriores desaparecen tras el final de cada bloque, porque el siguiente interino empieza de nuevo desde el audio entrante.
Conserva cada bloque fijado, añade el interino actual y deja que el final de enunciado sustituya a ambos.
El texto puede crecer sin perder bloques previos. Resuelto el estado de visualización, los límites de turno son el problema pendiente del streaming.
Usar Smart Turn para detectar fin de turno
Smart Turn evalúa cada silencio y estima si la persona ha terminado. Existe para casos como el número de Khalid: "cero uno cero, cinco cinco cinco, [pausa], uno dos tres cuatro", donde el silencio por sí solo no distingue una pausa de pensamiento del final.
Probar el umbral de Smart Turn
El umbral no es la confianza de transcripción ni el umbral de VAD. Es la probabilidad de fin de turno que debe superar un silencio para que speech_final dispare; por debajo, el turno sigue abierto. Dos parámetros de consulta lo ajustan:
params += [
("smart_turn", "0.7"), # prob. de fin de turno necesaria para cerrar
("smart_turn_timeout", "3000"), # cerrar de todos modos tras 3 s de silencio
]
La documentación llama 0.5 equilibrado, 0.7 conservador para secuencias numéricas y 0.9 muy conservador. En este escenario, las pausas más cortas que la ventana por defecto de endpointing no produjeron una decisión útil de Smart Turn. Es un resultado observado, no una regla de temporización documentada.
En la prueba en streaming, parar los fotogramas de audio no avanzó el temporizador de silencio observado. Seguir enviando silencio digital permitió a Smart Turn cerrar el enunciado.
Alargar la pausa durante el dictado del número hace visible el comportamiento. Las pausas cortas se mantienen en un mismo turno, mientras que una larga lo divide en todos los umbrales cuando la confianza supera los tres ajustes.

Las pausas largas pueden dividir un dictado de números. Imagen del autor.
Las personas son menos predecibles. Una secuencia corta de dígitos puede parecer terminada. Luego, el interlocutor continúa.
Si Smart Turn cierra durante un dictado de números, espera un instante y fusiona la continuación antes de responder.
Configurar un tiempo de espera de Smart Turn
smart_turn_timeout cierra un turno tras un silencio fijo, incluso cuando Smart Turn no está seguro. En el flujo rápido de tres hablantes, Smart Turn agrupó varios turnos previstos antes de que un timeout forzara el cierre.
Si ya sabes dónde acaban los turnos, envía {"type": "finalize"} en cada límite; si no, combina Smart Turn con un tiempo de espera.
Una vez bajo control los límites de turno, la misma llamada tiene que sobrevivir a una línea de 8 kHz.
Transcribir audio telefónico a 8 kHz
Aquí el audio con calidad telefónica es G.711 mu-law a 8 kHz, generado a partir de la misma llamada:
ffmpeg -i support_call.wav -ar 8000 -ac 1 -f mulaw support_call_8k.raw
El audio de telefonía en crudo no tiene contenedor, así que indica audio_format=mulaw y sample_rate=8000 en el formulario por lotes, o encoding=mulaw&sample_rate=8000 en el socket. Revisa texto y etiquetas de hablante por separado.
Comparar audio limpio y telefónico
Las conclusiones anteriores sobre términos clave, formato y cambio de idioma cambiaron poco a 8 kHz.
Las etiquetas de hablante fueron menos fiables. La versión telefónica introdujo un ID de hablante extra y asignó un turno de cierre a la persona equivocada. Contar segmentos por sí solo oculta ambos errores.
La versión degradada limita la banda de la llamada a 300-3400 Hz, la codifica como mu-law de 8 kHz y pierde cada paquete de 20 ms con una probabilidad de 0.03. Una semilla aleatoria fija de 7 mantiene los mismos huecos en cada reproducción.
Esa pérdida de paquetes no cambió mucho la transcripción en inglés en esta muestra, y los datos de contacto dictados se mantuvieron en orden. Este resultado solo aplica a esta muestra.
La simulación telefónica estrecha el audio y pierde paquetes. Imagen del autor.
Ajustar VAD para audio telefónico
La detección de actividad de voz (VAD) decide si el audio es habla. La documentación sugiere bajar el vad_threshold para habla telefónica tenue, con el riesgo de texto espurio por ruido.
Bajar vad_threshold no cambió nada en audio telefónico limpio porque no había habla tenue que recuperar. El resultado nulo apoya una regla: baja el umbral solo cuando desaparece habla telefónica.
Usar transcripción multicanal para separar hablantes
Usa un formulario por lotes nuevo sin diarize:
data = [
("model", "grok-voice-transcribe-2.0"),
("multichannel", "true"),
]
La API detecta el número de canales a partir de un WAV u otro contenedor. Para audio multicanal en crudo, añade ("channels", "3"); la entrada multicanal por WebSocket también requiere un número de canales explícito.
Envía el formulario con el archivo multicanal mediante la petición REST mostrada antes y luego lee result["channels"]. Cada elemento contiene un índice, texto de transcripción y palabras temporizadas. En el escenario controlado de tres canales, cada canal contenía solo su hablante asignado. El streaming usa la misma separación y añade channel_index a sus eventos.
Usaría patas separadas siempre que el sistema telefónico las proporcione. A diferencia de la diarización en el apartado de audio telefónico, una separación conocida no infiere hablantes.
Construir el transcriptor completo de soporte en Python
El cliente completo expone un grupo de ajustes y luego construye por separado el formulario REST o la URL del WebSocket. Los ajustes compartidos cubren diarización, términos clave, muletillas, codificación de audio y manejo de turnos; el formato sigue las reglas específicas del transporte vistas antes.
Aplica los ajustes finales a una grabación con calidad telefónica y comprueba por separado la ortografía del producto, los cambios de idioma, los datos de contacto y las etiquetas de hablante. En el escenario controlado, las comprobaciones de texto pasaron mientras que una etiqueta de hablante aún requería revisión. Guarda los ajustes y el mapeo de hablantes con cada transcripción para que las comparativas posteriores usen la misma configuración.
Explorar la demo completa de agente de voz
El tutorial de transcripción de soporte termina con esa verificación final. El repositorio también contiene una extensión de agente de voz con respuestas generadas, salida hablada, interrupciones y gestión de eco.
Transcribe mantiene el mismo papel en esa demo: produce texto. Un modelo de lenguaje escribe las respuestas y Grok TTS las locuta.
La llamada en vivo cambia de ruta de audio a mitad de conversación. Vídeo del autor.
Limitaciones de Grok Voice Transcribe 2.0
Las transcripciones de soporte pueden contener nombres, teléfonos y correos electrónicos. Las FAQ de seguridad de SpaceXAI indican que almacenan los datos de la API cifrados en reposo durante 30 días para auditoría de abusos. SpaceXAI también afirma que no entrena con los datos sin permiso. Los equipos elegibles pueden activar Zero Data Retention a nivel de equipo.
Mantén la clave de API en tu servidor. La documentación de Speech-to-Text indica que debes pasar el WebSocket por tu backend.
Una llamada controlada no representa todos los acentos, salas o líneas telefónicas. Prueba los ajustes con audio del entorno previsto antes de usarlos en producción.
Errores comunes y resolución de problemas
La mayoría de fallos aquí provienen del formato de audio o la gestión del socket:
-
InvalidHeader ... return character(s) in header valuees el\rde Windows en la clave. -
Un 400 puede significar que falta
fileourl, un formato no compatible, audio en crudo sinsample_rateoformat=truesinlanguage. -
En la prueba en streaming, parar los fotogramas de audio no avanzó el temporizador de silencio observado; seguir enviando silencio digital permitió cerrar el turno.
-
cannot call recv while another coroutine is already running recvsignifica que dos corrutinas leen el mismo socket. Da a cada conexión un único lector. -
En esta configuración de Windows, el procesado de audio en la ruta de entrada recortaba sílabas suaves. Apagarlo o usar captura exclusiva solucionó la entrada.
Si ninguno de esos casos encaja, compara los eventos en crudo con el audio de origen para aislar la causa.
Precios de Grok Voice Transcribe 2.0
La página de precios de SpaceXAI indica la transcripción a $0.10 por hora en REST y $0.20 por hora en streaming. El anuncio dice que la diarización, las marcas temporales y los términos clave están incluidos. Calcula el coste por duración de audio, no por número de peticiones.
Cada flujo abierto factura su propia duración de audio. Un segundo oyente añade coste de streaming y duplica los minutos de STT solo cuando ambos flujos reciben la misma duración completa.
Reflexiones finales
No evaluaría un transcriptor de llamadas solo con audio limpio. La sección de audio telefónico muestra por qué.
La API devuelve datos de transcripción; el cliente sigue siendo responsable del estado de la conversación y la validación. Además, mantén el ID de modelo versionado. Toma el resto de ajustes como punto de partida y pruébalos con el audio objetivo.
Las próximas extensiones son una entrada de teléfono SIP, vocabulario por llamada y una exportación al CRM. Si quieres un agente y no solo un transcriptor, nuestro tutorial de la API Grok Voice Agent cubre ese camino.
FAQs
¿Grok Voice Transcribe 2.0 admite transcripción en tiempo real?
Sí, por WebSocket, y no solo como PCM en crudo. Un cliente con ancho de banda limitado puede transmitir con encoding=opus, alrededor de 4 KB/s frente a 48 KB/s para PCM a 24 kHz, siempre que cada frame lleve un paquete Opus. Opus es solo mono, así que no admite streaming multicanal.
¿Grok Voice Transcribe 2.0 admite diarización de hablantes?
Configura diarize=true en cualquiera de los endpoints. En la respuesta con diarización en streaming de este escenario, las palabras también incluían un campo no documentado speaker_confidence. No basaría lógica de aplicación en él. Trata los IDs de hablante como etiquetas locales de la petición o sesión, no como reconocimiento de identidad persistente.
¿Puede Grok Voice Transcribe 2.0 transcribir varios idiomas en una misma grabación?
La detección automática puede preservar un cambio de idioma a mitad de grabación sin pista previa. El parámetro language controla el formato para 25 idiomas listados, incluido árabe (ar), así que prueba el código relevante con tu propio audio antes de fiarte del formato.
¿Cuál es la diferencia entre Smart Turn y VAD?
VAD pregunta si el audio es habla; Smart Turn pregunta si el habla ha terminado. vad_threshold por defecto es 0.5 en batch y 0.08 en el stream. endpointing por defecto es 400 ms y marca el silencio necesario antes de poder cerrar un enunciado.
¿Puedo transcribir una grabación desde una URL en lugar de subir un archivo?
Usa el campo url del endpoint por lotes en lugar de file. SpaceXAI descarga la grabación en el servidor, y una descarga fallida devuelve un 502.
Soy ingeniero de datos y creador de comunidades. Trabajo con canalizaciones de datos, nube y herramientas de IA, al tiempo que escribo tutoriales prácticos y de gran impacto para DataCamp y programadores emergentes.





