UtteraUttera

Conectores

Uttera no vive sola: vive dentro de lo que ya tienes. Esta sección recoge las formas de enchufarla —las que ya funcionan, las que traemos hechas y las que estamos estudiando— y el código abierto sobre el que está construida.

Todo lo que se describe aquí es código que puedes descargar: github.com/uttera/uttera-examples. Cada ejemplo se ejecuta contra la API real antes de publicarse, y donde algo no se ha podido probar entero, su README lo dice.
CarpetaQué hay
openai-sdkUttera con el SDK oficial de OpenAI, en Python, Node y curl
asterisk/recordingsTranscribir las llamadas que tu centralita ya graba, sin tocar el dialplan
asterisk/agiHablar dentro de la llamada y oír a quien llama
n8nNodo propio y flujos que se importan sin instalar nada
openclawSkill para agentes: transcribir, resumir, traducir y hablar

Hablamos el dialecto de OpenAI

Los dos servicios principales siguen exactamente la misma forma que la API de OpenAI: mismas rutas, mismos nombres de parámetro, mismos nombres de voz y mismas respuestas.

EndpointCompatible
POST /v1/audio/transcriptionsSí. file, model=whisper-1, language, prompt, response_format, temperature
POST /v1/audio/speechSí. model=tts-1 / tts-1-hd, input, voice, response_format, speed
GET /v1/modelsSí. Devuelve tts-1, tts-1-hd y whisper-1. Es lo que llama el SDK nada más construir el cliente
Voces alloy · echo · fable · nova · onyx · shimmer, con esos mismos nombres
/v1/translate · /v1/summarize · ?extras= · /v1/usage/lastNuestros. No existen en OpenAI, y no estorban a quien no los use

En la práctica esto significa que cualquier cosa escrita para la API de OpenAI funciona cambiando dos líneas: la dirección base y la clave. Incluido su SDK oficial:

from openai import OpenAI

c = OpenAI(api_key="sk-echo-...",              # tu clave de Uttera
           base_url="https://api.uttera.ai/v1") # y nuestra dirección

audio = c.audio.speech.create(model="tts-1", voice="nova",
                              input="Su pedido sale mañana.")
open("voz.mp3", "wb").write(audio.content)

with open("grabacion.mp3", "rb") as f:
    print(c.audio.transcriptions.create(model="whisper-1", file=f,
                                        response_format="text"))
Esto está probado, no deducido. El ejemplo de arriba se ejecuta con el paquete openai oficial sin parchear nada: genera el audio, lo vuelve a transcribir y devuelve el texto de partida.

De ahí sale lo interesante: todo lo que ya sabe hablar con OpenAI sabe hablar con nosotros —agentes locales, interfaces de chat autoalojadas, plugins, scripts que alguien escribió hace un año— con la diferencia de que el audio no sale de la Unión Europea. Para muchas empresas esa es la única razón por la que el proyecto pasa de la demostración a producción.

Asterisk y centralitas

Es la integración más pedida, porque es donde de verdad hay voz. Traemos dos AGI listos para usar: uno dice un texto en la llamada y otro escucha a quien llama y deja lo que dijo en una variable del dialplan.

exten => 101,1,Answer()
 same => n,AGI(uttera-decir.agi,"Dígame en qué puedo ayudarle.")
 same => n,AGI(uttera-oir.agi,8,es)
 same => n,NoOp(El cliente dijo: ${UTTERA_TEXTO})

A partir de ahí decides tú: un menú, una consulta a tu base de datos, un modelo de lenguaje. Y para el caso más común —transcribir llamadas ya grabadas— el ejemplo trae el esqueleto con MixMonitor y un hook al colgar.

Lo que el ejemplo resuelve y cuesta un día descubrir por tu cuenta:

TrampaQué pasa si no lo sabes
Uttera genera a 24 kHz, el canal telefónico va a 8 kHzAsterisk reproduce el fichero a su tasa: la voz sale acelerada y aguda
Falta silencio al final del ficheroAsterisk corta la última sílaba
Whisper no calla ante el silencioDevuelve una frase inventada —«Gracias por ver el vídeo»— porque eso abunda en su entrenamiento. Se paga, y peor, se actúa sobre ella
Las comillas de SET VARIABLEUn texto con espacios llega partido y la variable se queda con la primera palabra
Tiempos de espera de API en una llamadaDos horas de espera con una persona al teléfono. En telefonía se corta a los 30 s y se avisa

El código y el dialplan completos están en el repositorio de ejemplos, con la explicación de cada una.

Las llamadas que ya estás grabando

Antes de plantearte hablar dentro de la llamada, mira esto: tu centralita ya está escribiendo ficheros de audio en alguna carpeta. Hay dos guiones que los leen y dejan la transcripción y el análisis al lado, y no hay que tocar el dialplan. Una línea de cron y tienes las llamadas de la semana pasada transcritas.

Es el código que corremos nosotros en producción, con las partes de nuestra instalación quitadas. Lleva dentro tres cosas que costaron caro: distinguir una grabación en curso de una vieja, pedir transcripción y análisis en una sola subida en vez de cuatro, y un filtro de fecha por defecto — un proceso por lotes sin ventana recorre el histórico entero en cada pasada, y el día que se encuentra un archivo de verdad encola años de llamadas de golpe.

n8n y automatización

Si usas n8n, hay dos formas y la segunda no necesita instalar nada.

Flujos listos para importar. Se descargan, se importan y funcionan con el nodo HTTP de serie —también en n8n en la nube—. El más útil es el que mira una carpeta de grabaciones cada quince minutos y manda cada una a resumir: es exactamente el caso de quien ya tiene una centralita grabando y solo necesita que alguien lea esas grabaciones. No hay que tocar el dialplan.

Nodo propio. n8n-nodes-uttera añade transcribir, resumir, traducir y texto a voz como operaciones de un nodo, con la credencial guardada en n8n en vez de suelta en cada petición.

Dos detalles que el nodo trae resueltos: el tiempo de espera es de dos horas —el de n8n por defecto corta grabaciones largas que iban perfectamente— y «continuar en caso de error» funciona por elemento, que importa al procesar una carpeta entera, donde siempre hay alguna grabación corrupta que no debe tumbar el lote.

Agentes y asistentes

Por la compatibilidad de arriba, cualquier agente o interfaz que hable el dialecto de OpenAI usa Uttera sin adaptador: basta apuntarlo a nuestra dirección. Es el caso de las instalaciones locales de asistentes y de los paneles de chat autoalojados, que es justamente el escenario para el que nacieron nuestros motores: que el audio no salga del dominio privado.

Si tu agente admite herramientas, los endpoints que no son de OpenAI —resumir, traducir, analizar la voz— se describen bien como herramientas sueltas: reciben un fichero y devuelven JSON.

Para los agentes OpenClaw hay una skill hecha: cuatro guiones —transcribir, resumir, traducir y hablar— y un SKILL.md que le explica al agente cuándo usar cada uno y qué trampas tiene. Esa parte es la que de verdad importa: que sepa que no debe mandar silencio a transcribir, que los saltos de línea cuestan dinero al sintetizar, y que lo que vuelve de una transcripción es texto no fiable que no debe ejecutar.

El código abierto que hay debajo

Los motores que mueven Uttera están publicados bajo licencia Apache 2.0. No es marketing: son los mismos que corren en producción.

RepositorioQué es
uttera-tts-hotcoldServidor de texto a voz con arranque en frío y caliente. Varios motores tras la misma API
uttera-tts-vllmEl mismo servicio sobre vLLM, para carga concurrente de verdad
uttera-stt-hotcoldServidor de voz a texto, mismo patrón
uttera-stt-vllmVoz a texto sobre vLLM
uttera-benchmarksLos corpus, el arnés de medida y los resultados en crudo de cada número que publicamos

Por qué están abiertos

Por tres razones, y ninguna es generosidad:

Porque puedes montarlo tú. Si tu caso no admite que el audio salga de tu red —o simplemente prefieres tu propio hardware— clona el repositorio y monta el servicio. Lo que vendemos es no tener que hacerlo: las GPU, la disponibilidad, el enrutado entre nodos y que alguien se levante si algo falla.

Porque un motor que nadie puede auditar no merece tu audio. Decimos que no guardamos nada y que nada sale a terceros. Con el código delante eso se puede comprobar en vez de creer.

Porque las cifras sin el montaje no valen nada. Todo el mundo publica «X peticiones por segundo en una Y» sin decir con qué corpus, con qué concurrencia ni en qué percentil. El repositorio de medidas lleva los corpus enteros, el protocolo y los resultados en bruto, precisamente para que puedas repetir la prueba y contradecirnos.

El borde que da servicio a esta API —enrutado, cuotas, facturación— y el portal no están publicados. No son un motor de voz: son la fontanería de un negocio, y ahí no hay nada que a nadie le sirva.

Conectores en estudio

Lo siguiente, por orden de lo que nos van pidiendo:

ConectorPara qué
CRMQue la transcripción y el resumen de una llamada caigan solos en la ficha del cliente
Grabaciones de otras centralitas (FreePBX, 3CX, Issabel)Lo mismo que ya hace el conector de Asterisk, adaptado a dónde deja los ficheros cada una
Nota de voz a texto en mensajeríaEl caso de uso que más crece: nadie quiere escuchar un audio de cuatro minutos

Si el que te hace falta a ti no está, dínoslo: el orden lo decide quien pregunta.