Bot d’appel Graph
Bot d’appel Graph
Appelez ou échangez par chat avec votre agent ElevenLabs par son nom dans Microsoft Teams, comme avec un collègue.
Vue d’ensemble
Cette approche fait de l’agent une identité Teams appelable. Un utilisateur le recherche par son nom et l’appelle en tête-à-tête, l’agent répond en temps réel, sans numéro de téléphone, RTPC ni crédits de communication. C’est la seule approche appelable par son nom et la plus complexe à mettre en œuvre.
Elle utilise un bot de médias en temps réel Microsoft Graph (la plateforme d’appel Cloud Communications). Le SDK média (Microsoft.Skype.Bots.Media) fonctionne uniquement avec .NET sur Windows Server, il n’existe aucune option Linux ou autre que .NET pour l’audio brut lors des appels Teams.
C’est la seule approche appelable par son nom dans Teams. Préférez l’onglet widget pour une configuration plus légère, ou ACS si vous souhaitez spécifiquement un numéro de téléphone.
Fonctionnement
Le bot répond avec des médias hébergés par l’application, reçoit 50 trames audio par seconde (PCM 16 kHz de 20 ms), les transmet à l’agent ElevenLabs via un WebSocket et diffuse l’audio de l’agent dans l’appel.
Prérequis
- Un enregistrement Azure Bot et une application (enregistrement d’application Entra).
- Des autorisations d’application Graph avec consentement administrateur :
Calls.AccessMedia.All(médias bruts) etCalls.Initiate.All. - Une VM Windows Server (≥ 2 cœurs physiques, par exemple
Standard_D4s_v3) avec une IP publique et des ports média ouverts. - Un certificat TLS signé par une AC sur un FQDN public pour le point de terminaison média/signalisation (la plateforme média refuse les certificats autosignés).
- Un agent ElevenLabs configuré sur PCM 16000 Hz dans les deux sens : le format de sortie TTS dans l’onglet Voice, le format audio d’entrée utilisateur dans l’onglet Advanced.
Une D2s_v3 (2 vCPU = 1 cœur physique) échoue avec MediaPlatform needs a system with at least 2 cores. Utilisez une taille avec ≥ 2 cœurs physiques (par exemple, D4s_v3).
Autorisations et rôles
Étape 1 : enregistrer le bot et les autorisations Graph
Créez un enregistrement d’application et un Azure Bot qui y est associé, puis accordez et approuvez les autorisations d’appel (vous devez être administrateur général ou administrateur de rôle privilégié pour donner votre consentement) :
Accordez les deux rôles d’application Graph et le consentement administrateur (nécessite le rôle d’administrateur général ou d’administrateur de rôle privilégié), puis confirmez que les attributions ont bien été effectuées :
Si admin-consent renvoie Consent validation failed, accordez plutôt directement les rôles d’application sur le principal de service :
Dans le portail, vérifiez dans le centre d’administration Entra, sous App registrations → your app → API permissions : les deux autorisations doivent afficher Granted avec des coches vertes.

Étape 2 : provisionner la VM Windows, le certificat et les ports
Sur la VM (le code natif de la plateforme média les nécessite, Windows Server ne les inclut pas par défaut) :
Ouvrez les mêmes ports dans le pare-feu Windows et notez l’empreinte du certificat, le bot y associe Kestrel (443 et un port de notifications) ainsi que la plateforme média (8445).
Le FQDN *.cloudapp.azure.com de la VM fonctionne avec un certificat Let’s Encrypt, aucun domaine distinct
n’est nécessaire.
Étape 3 : créer et exécuter le bot
Partez de l’PublicSamples/EchoBot de microsoft-graph-comms-samples, il cible net6.0 et se compile avec le SDK .NET (aucun outil de génération Visual Studio requis) :
Configurez la section AppSettings de appsettings.json avec vos valeurs AadAppId, AadAppSecret, ServiceDnsName/MediaDnsName (le FQDN de la VM), CertificateThumbprint et les ports (443 pour les appels, 9441 pour les notifications, 8445 pour les médias). Ajoutez deux paramètres pour le pont ElevenLabs ci-dessous : ElevenLabsAgentId et ElevenLabsOrigin (wss://api.elevenlabs.io, ou votre hôte de résidence des données). Exécutez-le en tant que tâche planifiée ou service Windows afin qu’il continue de fonctionner après les redémarrages.
La limite de durée d’exécution par défaut (72 heures) du Planificateur de tâches arrête silencieusement les tâches de longue durée, un bot lancé au démarrage s’arrête trois jours plus tard et les appels échouent avec « we couldn’t connect you ». Désactivez la limite et ajoutez un redémarrage en cas d’échec :
L’EchoBot fourni s’arrête lorsqu’un appel est passé au port standard 443 : HttpHelpers.SetAbsoluteUri
appelle req.Host.Port.Value, qui est nul lorsque l’en-tête Host n’a pas de port explicite. Corrigez-le avec
req.Host.Port ?? (req.IsHttps ? 443 : 80).
Remplacer l’écho par ElevenLabs
L’interface audio d’EchoBot est claire : SpeechService.AppendAudioBuffer(in) et un événement OnSendMediaBufferEventArgs(out). Remplacez son corps Azure Speech par un pont WebSocket d’agent ElevenLabs qui conserve la même interface :
Les deux côtés utilisent du PCM mono 16 kHz, il s’agit donc d’un relais base64. Configurez l’agent sur pcm_16000. Lors d’une interruption ElevenLabs (interruption de parole), le pont déclenche FlushMedia. Reliez-le à votre flux média pour supprimer tous les AudioMediaBuffer en file d’attente, sans quoi l’agent continue à parler par-dessus l’appelant. La référence complète des messages se trouve dans la documentation WebSocket. La fin d’appel et le transfert assisté sont abordés dans les sections ci-dessous.
L’URL dans Connect() atteint un agent public. Pour un agent privé, demandez côté serveur une URL signée
de courte durée, GET /v1/convai/conversation/get-signed-url?agent_id=... avec votre clé API, puis connectez-vous à l’URL renvoyée. Pour la résidence des
données, définissez ElevenLabsOrigin sur votre hôte de résidence des données
(wss://api.eu.residency.elevenlabs.io, .in. ou .sg.), les requêtes d’URL signée utilisent l’hôte
https:// correspondant.
Étape 4 : le rendre appelable dans Teams
-
Activez Calling sur le canal Teams de l’Azure Bot et définissez le webhook d’appel sur
https://YOUR_FQDN/api/calling:Dans le portail, vous le trouverez dans votre ressource Azure Bot → Channels → Microsoft Teams → onglet Calling :

Azure Bot → Channels, le canal Microsoft Teams connecté 
Canal Microsoft Teams → Calling, appels activés avec le webhook du bot -
Créez un manifeste d’application Teams avec
bots[0].supportsCalling: trueet l’ID d’application du bot, puis chargez-le de façon indépendante (Apps → Manage your apps → Upload a custom app) ou publiez-le dans toute l’organisation sans l’interface :New-TeamsApp -DistributionMethod organization -Path ./bot-app.zip(module PowerShell MicrosoftTeams).
Recherchez l’application par son nom dans Teams et appelez-la, le bot répond et l’agent ElevenLabs parle.

Aucun numéro de téléphone ni compte de ressource n’est nécessaire pour les appels en tête-à-tête par nom, ils sont uniquement requis pour les
appels entrants RTPC. Calls.AccessMedia.All permet le pont audio brut.
Chat textuel (même bot)
Le même Azure Bot peut également répondre aux messages textuels dans Teams, les utilisateurs peuvent donc appeler l’agent ou échanger avec lui par chat. Les appels et la messagerie sont des canaux indépendants sur le bot : le webhook d’appel gère la voix et un point de terminaison de messagerie Bot Framework (/api/messages) gère le chat.

Dirigez le point de terminaison de messagerie du bot vers l’hôte qui le sert (le bot média ou tout autre service, il ne doit pas nécessairement s’agir de la VM Windows) :
Implémentez le point de terminaison avec le SDK Bot Framework et transmettez chaque message à l’agent en mode texte via le même WebSocket de conversation utilisé pour la voix, envoyez un événement user_message, puis lisez l’événement agent_response. Activez d’abord le champ first message dans les paramètres d’overrides de l’agent, le code ci-dessous le remplace par une valeur vide afin que la réponse traite le message de l’utilisateur plutôt que le message d’accueil de l’agent :
Enregistrez-le de la manière habituelle (un CloudAdapter, le bot via AddTransient<IBot, ChatBot>() et un contrôleur /api/messages), puis ajoutez des étendues de chat à l’entrée du bot dans le manifeste :
L’extrait ouvre une nouvelle conversation par message, chaque tour est donc indépendant. Pour conserver la
mémoire du chat, maintenez un WebSocket ouvert par conversation.id Teams (réutilisez-le entre les tours) et fermez les
sessions inactives, l’agent se souviendra alors des messages précédents de cette conversation. Le remplacement first_message
doit être activé dans les paramètres d’overrides
de l’agent, le serveur ferme la conversation si un remplacement non autorisé est envoyé. Si vous ne pouvez pas l’activer, omettez le
remplacement et ignorez plutôt le premier agent_response de chaque session (le message d’accueil), puis renvoyez
le suivant.
Si les réponses du chat n’arrivent jamais, activez l’événement client agent_response client
event dans les paramètres Advanced
de l’agent, les réponses textuelles sont transmises par cet événement.
Fin d’appel
Quand ElevenLabs termine la conversation (son outil End Call ferme le WebSocket), raccrochez la partie Teams :
Transfert assisté vers un humain
L’agent déclenche un outil client personnalisé transfer_to_human. Le bot invite un utilisateur Teams dans l’appel en cours (ajout consultatif), puis se retire :
Le transfert consultatif (replacesCallId) exige que les deux parties soient des utilisateurs Teams du **même
tenant **. Les cibles de transfert RTPC nécessitent une instance d’application. Pour informer d’abord l’humain, transmettez un paramètre
reason depuis l’agent et diffusez-le à l’humain avant la mise en relation.
Dépannage
MediaPlatform needs a system with at least 2 cores
MediaPlatform needs a system with at least 2 cores
La VM ne possède qu’un seul cœur physique. Redimensionnez-la avec ≥ 2 cœurs physiques (par exemple, D4s_v3) et redémarrez-la.
Unable to load DLL 'NativeMedia'
Unable to load DLL 'NativeMedia'
Installez le VC++ Redistributable (vcredist140) et la fonctionnalité Windows
Server-Media-Foundation, puis redémarrez le bot.
L’appel entrant renvoie 500 / l’appel ne se connecte pas
Il s’agit du bug de port nul d’EchoBot sur 443, corrigez HttpHelpers.SetAbsoluteUri (voir l’étape 3). Vérifiez également
que le certificat est signé par une AC et accessible sur le port 443.
L’appel au bot indique « we couldn't connect you »
Vérifiez que Calling est activé sur le canal Teams avec le webhook /api/calling correct, que l’autorisation
Graph Calls.AccessMedia.All a reçu le consentement et que les ports 443/8445/9441 sont ouverts à la fois dans le
NSG et le pare-feu Windows. Si les appels fonctionnaient auparavant puis se sont arrêtés, vérifiez que le processus du bot
fonctionne toujours sur la VM, la limite d’exécution par défaut de 72 heures du Planificateur de tâches l’arrête quelques
jours après le démarrage (voir l’avertissement de l’étape 3).