UtteraUttera

Connecteurs

Uttera ne vit pas seul : il vit à l'intérieur de ce que vous avez déjà. Cette section rassemble les façons de le brancher — celles qui marchent déjà, celles que nous apportons toutes prêtes, et celles que nous étudions — plus le code ouvert sur lequel il est bâti.

Tout ce qui est décrit ici est du code que vous pouvez télécharger : github.com/uttera/uttera-examples. Chaque exemple est exécuté contre l'API en direct avant d'être publié, et là où quelque chose n'a pas pu être testé de bout en bout, son README le dit.
DossierCe qu'il contient
openai-sdkUttera via le SDK officiel d'OpenAI, en Python, Node et curl
asterisk/recordingsTranscrire les appels que votre système téléphonique enregistre déjà, sans toucher au dialplan
asterisk/agiParler à l'intérieur de l'appel et entendre l'appelant
n8nNotre propre node, plus des workflows qui s'importent sans rien installer
openclawUne skill pour agents : transcrire, résumer, traduire et parler

Nous parlons le dialecte d'OpenAI

Les deux services principaux suivent exactement la même forme que l'API d'OpenAI : mêmes routes, mêmes noms de paramètres, mêmes noms de voix et mêmes réponses.

EndpointCompatible
POST /v1/audio/transcriptionsOui. file, model=whisper-1, language, prompt, response_format, temperature
POST /v1/audio/speechOui. model=tts-1 / tts-1-hd, input, voice, response_format, speed
GET /v1/modelsOui. Renvoie tts-1, tts-1-hd et whisper-1. C'est ce que le SDK appelle dès que le client est construit
Voix alloy · echo · fable · nova · onyx · shimmerOui, sous ces mêmes noms
/v1/translate · /v1/summarize · ?extras= · /v1/usage/lastÀ nous. Ils n'existent pas chez OpenAI, et ils ne gênent personne qui ne les utilise pas

En pratique, cela signifie que tout ce qui est écrit pour l'API d'OpenAI marche en changeant deux lignes : l'adresse de base et la clé. Y compris leur SDK officiel :

from openai import OpenAI

c = OpenAI(api_key="sk-echo-...",              # votre clé Uttera
           base_url="https://api.uttera.ai/v1") # et notre adresse

audio = c.audio.speech.create(model="tts-1", voice="nova",
                              input="Your order ships tomorrow.")
open("voice.mp3", "wb").write(audio.content)

with open("recording.mp3", "rb") as f:
    print(c.audio.transcriptions.create(model="whisper-1", file=f,
                                        response_format="text"))
C'est testé, non supposé. L'exemple ci-dessus tourne avec le paquet openai officiel sans rien modifier : il génère l'audio, le retranscrit et renvoie le texte original.

D'où vient la partie intéressante : tout ce qui sait déjà parler à OpenAI sait parler à nous — agents locaux, interfaces de chat auto-hébergées, plugins, scripts que quelqu'un a écrits il y a un an — avec la différence que l'audio ne quitte jamais l'Union européenne. Pour beaucoup d'entreprises, c'est la seule raison qui fait passer le projet de la démo à la production.

Asterisk et systèmes téléphoniques

C'est l'intégration la plus demandée, parce que c'est là que la voix se trouve réellement. Nous apportons deux scripts AGI prêts à l'emploi : l'un dit un texte à l'intérieur de l'appel et l'autre écoute l'appelant et laisse ce qu'il a dit dans une variable du dialplan.

exten => 101,1,Answer()
 same => n,AGI(uttera-decir.agi,"How can I help you?")
 same => n,AGI(uttera-oir.agi,8,en)
 same => n,NoOp(The caller said: ${UTTERA_TEXTO})

À partir de là, c'est à vous : un menu, une recherche en base de données, un modèle de langage. Et pour le cas le plus courant — transcrire les appels déjà enregistrés — l'exemple apporte le squelette avec MixMonitor et un hook de raccrochage.

Ce que l'exemple résout et ce qui coûte une journée à découvrir seul :

PiègeCe qui se passe si vous ne savez pas
Uttera génère à 24 kHz, le canal téléphonique tourne à 8 kHzAsterisk joue le fichier à sa propre fréquence : la voix sort rapide et aiguë
Silence manquant en fin de fichierAsterisk coupe la dernière syllabe
Whisper ne reste pas silencieux sur le silenceIl renvoie une phrase inventée — « Thanks for watching » — parce que cela abonde dans ses données d'entraînement. Vous la payez, et pire, vous agissez dessus
Le quoting dans SET VARIABLEUn texte avec des espaces arrive découpé et la variable ne garde que le premier mot
Délais d'attente de l'API pendant un appelDeux heures d'attente avec une personne au téléphone. En téléphonie, on coupe à 30 s et on dit quelque chose

Le code complet et le dialplan sont dans le dépôt d'exemples, avec une explication de chacun.

Les appels que vous enregistrez déjà

Avant d'envisager de parler à l'intérieur de l'appel, regardez ceci : votre système téléphonique écrit déjà des fichiers audio dans un dossier. Il y a deux scripts qui les lisent et laissent la transcription et l'analyse à côté, et vous n'avez pas à toucher au dialplan. Une ligne de cron et vous avez les appels de la semaine dernière transcrits.

C'est le code que nous faisons tourner en production nous-mêmes, avec les parties propres à notre installation retirées. Il porte trois choses en son sein qui nous ont coûté cher : distinguer un enregistrement en cours d'un ancien, demander transcription et analyse en un seul téléversement au lieu de quatre, et un filtre de date par défaut — un traitement par lots sans fenêtre parcourt tout l'historique à chaque passage, et le jour où il rencontre une vraie archive, il met en file des années d'appels d'un coup.

n8n et automatisation

Si vous utilisez n8n, il y a deux façons et la seconde ne nécessite rien d'installé.

Des workflows prêts à importer. Vous les téléchargez, les importez, et ils marchent avec le node HTTP standard — y compris sur n8n cloud. Le plus utile est celui qui surveille un dossier d'enregistrements toutes les quinze minutes et envoie chacun à résumer : c'est exactement le cas de quelqu'un qui a déjà un système téléphonique qui enregistre et n'a besoin que de quelqu'un pour lire ces enregistrements. Aucun dialplan à toucher.

Notre propre node. n8n-nodes-uttera ajoute transcrire, résumer, traduire et synthèse vocale comme opérations d'un seul node, avec la référence d'identification stockée dans n8n au lieu d'être en clair dans chaque requête.

Deux détails que le node a déjà résolus : le délai d'attente est de deux heures — celui par défaut de n8n coupe les longs enregistrements qui se passaient bien — et « continue on error » fonctionne par item, ce qui compte en traitant un dossier entier, où il y a toujours un enregistrement corrompu qui ne devrait pas faire tomber le lot.

Agents et assistants

Grâce à la compatibilité ci-dessus, tout agent ou interface qui parle le dialecte d'OpenAI utilise Uttera sans adaptateur : pointez-le vers notre adresse. Cela couvre les installations locales d'assistants et les panneaux de chat auto-hébergés, qui sont exactement le scénario pour lequel nos moteurs sont nés : garder l'audio à l'intérieur du domaine privé.

Si votre agent prend en charge les outils, les endpoints qui ne sont pas ceux d'OpenAI — résumer, traduire, analyser la voix — se décrivent bien comme outils autonomes : ils prennent un fichier et renvoient du JSON.

Pour les agents OpenClaw, il y a une skill toute prête : quatre scripts — transcrire, résumer, traduire et parler — et un SKILL.md qui indique à l'agent quand utiliser chacun et quels sont les pièges. C'est cette partie qui compte vraiment : qu'il sache ne pas envoyer du silence à transcrire, que les sauts de ligne coûtent de l'argent en synthétisant, et que ce qui revient d'une transcription est du texte non fiable qu'il ne doit pas exécuter.

Le code ouvert en dessous

Les moteurs qui font tourner Uttera sont publiés sous la licence Apache 2.0. Ce n'est pas du marketing : ce sont les mêmes qui tournent en production.

DépôtCe que c'est
uttera-tts-hotcoldServeur de synthèse vocale avec démarrage à froid et à chaud. Plusieurs moteurs derrière une API
uttera-tts-vllmLe même service sur vLLM, pour une vraie charge concurrente
uttera-stt-hotcoldServeur de reconnaissance vocale, même schéma
uttera-stt-vllmReconnaissance vocale sur vLLM
uttera-benchmarksLes corpus, le harnais de mesure et les résultats bruts derrière chaque chiffre que nous publions

Pourquoi ils sont ouverts

Pour trois raisons, et aucune n'est de la générosité :

Parce que vous pouvez le faire tourner vous-même. Si votre cas ne permet pas que l'audio quitte votre réseau — ou si vous préférez simplement votre propre matériel — clonez le dépôt et montez le service. Ce que nous vendons, c'est de ne pas avoir à le faire : les GPU, la disponibilité, le routage entre nœuds, et quelqu'un qui se lève si quelque chose casse.

Parce qu'un moteur que personne ne peut auditer ne mérite pas votre audio. Nous disons que nous ne gardons rien et que rien ne va à des tiers. Avec le code sous les yeux, cela peut être vérifié au lieu d'être cru.

Parce que des chiffres sans le protocole ne valent rien. Tout le monde publie « X requêtes par seconde sur un Y » sans dire avec quel corpus, à quelle concurrence, ni à quel percentile. Le dépôt de mesures porte les corpus entiers, le protocole et les résultats bruts, précisément pour que vous puissiez répéter le test et nous contredire.

La couche de bord qui sert cette API — routage, quotas, facturation — et le portail ne sont pas publiés. Ce ne sont pas un moteur vocal : c'est la plomberie d'une entreprise, et il n'y a rien là-dedans qui serait utile à qui que ce soit.

Connecteurs en cours

Ce qui suit, dans l'ordre où on nous le demande :

ConnecteurPour quoi
CRMPour que la transcription et le résumé d'un appel atterrissent d'eux-mêmes dans la fiche du client
Enregistrements d'autres systèmes téléphoniques (FreePBX, 3CX, Issabel)La même chose que fait déjà le connecteur Asterisk, adaptée à l'endroit où chacun laisse ses fichiers
Note vocale en texte dans la messagerieLe cas d'usage qui croît le plus vite : personne ne veut écouter une note vocale de quatre minutes

Si celui dont vous avez besoin n'y est pas, dites-le-nous : l'ordre est décidé par ceux qui le demandent.