Graph कॉलिंग बॉट
Graph कॉलिंग बॉट
Microsoft Teams में अपने ElevenLabs एजेंट को किसी सहकर्मी की तरह नाम से कॉल करें या चैट करें।
ओवरव्यू
यह तरीका एजेंट को कॉल किए जा सकने वाले Teams आइडेंटिटी में बदल देता है। यूज़र इसे नाम से खोजकर 1:1 कॉल करता है और एजेंट रियल टाइम में जवाब देता है — इसके लिए फोन नंबर, PSTN या Communications Credits की ज़रूरत नहीं होती। नाम से कॉल किए जा सकने वाला यह एकमात्र तरीका है और इसे चलाने में सबसे ज़्यादा सेटअप लगता है।
इसमें Microsoft Graph रियल-टाइम मीडिया बॉट (Cloud Communications calling platform) का इस्तेमाल होता है। मीडिया SDK (Microsoft.Skype.Bots.Media) केवल Windows Server पर .NET के लिए है — Teams कॉल में raw audio के लिए Linux या non-.NET का कोई विकल्प नहीं है।
Teams में नाम से कॉल करने का यह एकमात्र तरीका है। आसान सेटअप के लिए widget tab चुनें, या जब आपको खास तौर पर फोन नंबर चाहिए, तो ACS चुनें।
यह कैसे काम करता है
बॉट application-hosted media के साथ जवाब देता है, हर सेकंड 50 ऑडियो फ़्रेम (20 ms PCM 16 kHz) लेता है, उन्हें WebSocket के ज़रिए ElevenLabs एजेंट तक पहुँचाता है और एजेंट का ऑडियो वापस कॉल में स्ट्रीम करता है।
ज़रूरी चीज़ें
- एक Azure Bot रजिस्ट्रेशन + ऐप (Entra ऐप रजिस्ट्रेशन)।
- एडमिन सहमति के साथ Graph application permissions:
Calls.AccessMedia.All(raw media) औरCalls.Initiate.All। - पब्लिक IP और खुले मीडिया पोर्ट वाला एक Windows Server VM (≥ 2 physical cores — जैसे
Standard_D4s_v3)। - मीडिया/signaling endpoint के लिए सार्वजनिक FQDN पर CA-signed TLS certificate (मीडिया प्लेटफ़ॉर्म self-signed certs को अस्वीकार करता है)।
- दोनों दिशाओं में PCM 16000 Hz पर सेट एक ElevenLabs एजेंट: Voice टैब में TTS output format और Advanced टैब में user input audio format।
D2s_v3 (2 vCPU = 1 physical core) पर MediaPlatform needs a system with at least 2 cores त्रुटि आती है। ≥ 2 physical cores वाला साइज़ इस्तेमाल करें (जैसे D4s_v3)।
अनुमतियां और रोल
चरण 1 — बॉट + Graph permissions रजिस्टर करें
एक ऐप रजिस्ट्रेशन और उससे जुड़ा Azure Bot बनाएं, फिर calling permissions को grant + consent दें (consent के लिए आपको Global Admin / Privileged Role Admin चाहिए):
दो Graph application roles को grant करें और admin consent दें (Global Admin / Privileged Role Admin चाहिए), फिर पुष्टि करें कि assignments लागू हो गए हैं:
अगर admin-consent से Consent validation failed मिलता है, तो इसके बजाय app roles को सीधे service principal पर grant करें:
पोर्टल में Entra admin center पर App registrations → आपका ऐप → API permissions के तहत जांचें: दोनों permissions के साथ हरे check और Granted दिखना चाहिए।

चरण 2 — Windows VM, cert और ports तैयार करें
VM पर (मीडिया प्लेटफ़ॉर्म के native code को इनकी ज़रूरत होती है — Windows Server में ये डिफ़ॉल्ट रूप से नहीं होते):
वही ports Windows firewall में खोलें और cert का thumbprint नोट करें — बॉट Kestrel (443 + notifications port) और मीडिया प्लेटफ़ॉर्म (8445) को इससे bind करता है।
VM का अपना *.cloudapp.azure.com FQDN Let’s Encrypt cert के लिए काम करता है — अलग डोमेन की
ज़रूरत नहीं है।
चरण 3 — बॉट बनाएं और चलाएं
Microsoft के microsoft-graph-comms-samples PublicSamples/EchoBot से शुरू करें — यह net6.0 को target करता है और .NET SDK के साथ बनता है (Visual Studio Build Tools की ज़रूरत नहीं):
appsettings.json के AppSettings सेक्शन में अपना AadAppId, AadAppSecret, ServiceDnsName/MediaDnsName (VM FQDN), CertificateThumbprint और ports (calling 443, notifications 9441, media 8445) कॉन्फ़िगर करें। नीचे दिए ElevenLabs bridge के लिए दो सेटिंग जोड़ें: ElevenLabsAgentId और ElevenLabsOrigin (wss://api.elevenlabs.io या आपका residency host)। इसे Windows scheduled task / service के रूप में चलाएं, ताकि रीबूट के बाद भी यह चलता रहे।
Task Scheduler की डिफ़ॉल्ट execution time limit (72 hours) लंबे समय तक चलने वाले tasks को बिना बताए बंद कर देती है — boot पर शुरू हुआ बॉट तीन दिन बाद बंद हो जाता है और कॉल में “we couldn’t connect you” त्रुटि आती है। limit बंद करें और restart-on-failure जोड़ें:
standard port 443 पर की गई कॉल में stock EchoBot क्रैश हो जाता है: HttpHelpers.SetAbsoluteUri
req.Host.Port.Value कॉल करता है, जो Host header में स्पष्ट port न होने पर null होता है। इसे
req.Host.Port ?? (req.IsHttps ? 443 : 80) से patch करें।
echo को ElevenLabs से बदलें
EchoBot का audio seam साफ़ है: SpeechService.AppendAudioBuffer(in) और OnSendMediaBufferEventArgs(out) event। इसके Azure-Speech body को ElevenLabs agent WebSocket bridge से बदलें, जो वही surface रखता है:
दोनों तरफ PCM 16 kHz mono है, इसलिए यह base64 passthrough है — एजेंट को pcm_16000 पर सेट करें। ElevenLabs interruption (barge-in) पर bridge FlushMedia raise करता है; इसे अपने media stream से जोड़ें ताकि queued AudioMediaBuffers हट जाएं, नहीं तो एजेंट कॉलर के ऊपर बोलता रहेगा। पूरा message reference WebSocket docs में है। कॉल के अंत में hangup और warm transfer की जानकारी नीचे के सेक्शन में दी गई है।
Connect() में URL public एजेंट तक पहुंचता है। private एजेंट के लिए server-side एक short-lived
signed URL मांगें — अपनी API key के साथ GET /v1/convai/conversation/get-signed-url?agent_id=...
— और इसके बजाय लौटे URL से connect करें। data
residency में ElevenLabsOrigin को अपने residency
host (wss://api.eu.residency.elevenlabs.io, .in., या .sg.) पर सेट करें — signed-URL requests के लिए
उससे मिलता हुआ https:// host इस्तेमाल होता है।
चरण 4 — इसे Teams में कॉल करने योग्य बनाएं
-
Azure Bot के Teams channel पर Calling चालू करें और calling webhook को
https://YOUR_FQDN/api/callingपर सेट करें:पोर्टल में यह आपके Azure Bot resource → Channels → Microsoft Teams → Calling टैब में है:

Azure Bot → Channels — कनेक्टेड Microsoft Teams चैनल 
Microsoft Teams चैनल → Calling — बॉट के webhook के साथ calling चालू -
bots[0].supportsCalling: trueऔर बॉट के app ID के साथ एक Teams app manifest बनाएं, फिर इसे sideload करें (Apps → Manage your apps → Upload a custom app), या UI के बिना इसे पूरी organization में प्रकाशित करें:New-TeamsApp -DistributionMethod organization -Path ./bot-app.zip(MicrosoftTeams PowerShell module)।
Teams में ऐप को नाम से खोजें और कॉल करें — बॉट जवाब देगा और ElevenLabs एजेंट बोलेगा।

1:1 call-by-name के लिए फोन नंबर या resource account की ज़रूरत नहीं है — ये केवल PSTN
dial-in के लिए होते हैं। Calls.AccessMedia.All ही raw-audio bridge को सक्षम करता है।
टेक्स्ट चैट (वही बॉट)
वही Azure Bot Teams में टेक्स्ट का जवाब भी दे सकता है — इसलिए यूज़र एजेंट को कॉल कर सकते हैं या उससे चैट कर सकते हैं। कॉलिंग और मैसेजिंग बॉट पर अलग-अलग चैनल हैं: कॉलिंग webhook वॉइस संभालता है और Bot Framework मैसेजिंग एंडपॉइंट (/api/messages) चैट संभालता है।

बॉट के मैसेजिंग एंडपॉइंट को उस होस्ट पर पॉइंट करें जो इसे सर्व करता है (मीडिया बॉट या कोई अन्य सेवा — ज़रूरी नहीं कि वह Windows VM ही हो):
Bot Framework SDK के साथ एंडपॉइंट लागू करें और हर मैसेज को वॉइस के लिए इस्तेमाल होने वाले उसी conversation WebSocket पर टेक्स्ट मोड में एजेंट तक भेजें — user_message इवेंट भेजें और agent_response इवेंट पढ़ें। पहले एजेंट की overrides सेटिंग्स में पहला मैसेज फ़ील्ड सक्षम करें — नीचे दिया गया कोड इसे खाली से ओवरराइड करता है, ताकि जवाब एजेंट के अभिवादन के बजाय यूज़र के मैसेज का उत्तर हो:
इसे सामान्य तरीके से रजिस्टर करें (एक CloudAdapter, AddTransient<IBot, ChatBot>() के ज़रिए बॉट और एक /api/messages controller), और manifest की bot एंट्री में चैट स्कोप जोड़ें:
यह स्निपेट हर मैसेज के लिए नया conversation खोलता है, इसलिए हर टर्न स्वतंत्र होता है। चैट
मेमोरी के लिए, हर Teams conversation.id के लिए एक WebSocket खुला रखें (टर्न्स के बीच उसका दोबारा इस्तेमाल करें) और निष्क्रिय सेशन बंद करें — तब एजेंट उस चैट के पहले के मैसेज याद रखता है। first_message
ओवरराइड एजेंट की
overrides सेटिंग्स में सक्षम होना चाहिए — अगर अस्वीकृत ओवरराइड भेजा जाता है, तो सर्वर
conversation बंद कर देता है। अगर आप इसे सक्षम नहीं कर सकते, तो ओवरराइड हटाएं और हर सेशन का पहला agent_response (अभिवादन) छोड़ दें और
अगला वाला वापस करें।
अगर चैट के जवाब कभी नहीं आते, तो एजेंट की Advanced
सेटिंग्स में agent_response client
event सक्षम करें — टेक्स्ट जवाब इसी इवेंट के ज़रिए भेजे जाते हैं।
कॉल समाप्ति
जब ElevenLabs बातचीत समाप्त करता है (इसका End Call टूल WebSocket बंद करता है), तो Teams वाला कनेक्शन काट दें:
किसी व्यक्ति को वॉर्म ट्रांसफर
एजेंट एक कस्टम transfer_to_human client tool ट्रिगर करता है; बॉट लाइव कॉल में एक Teams यूज़र को आमंत्रित करता है (consultative add), फिर पीछे हट जाता है:
Consultative transfer (replacesCallId) के लिए दोनों पक्षों का एक ही tenant में Teams यूज़र होना ज़रूरी है; PSTN ट्रांसफर टारगेट के लिए application instance चाहिए। पहले व्यक्ति को जानकारी देने के लिए, एजेंट से reason पैरामीटर पास करें और ब्रिज करने से पहले उसे व्यक्ति को चलाकर सुनाएं।
समस्या निवारण
MediaPlatform needs a system with at least 2 cores
MediaPlatform needs a system with at least 2 cores
VM में सिर्फ़ एक physical core है। कम से कम 2 physical cores (जैसे D4s_v3) में resize करें और रीस्टार्ट करें।
Unable to load DLL 'NativeMedia'
Unable to load DLL 'NativeMedia'
VC++ Redistributable (vcredist140) और Server-Media-Foundation Windows
फीचर इंस्टॉल करें, फिर बॉट रीस्टार्ट करें।
इनकमिंग कॉल 500 लौटाती है / कॉल कनेक्ट नहीं होती
443 पर EchoBot port-null bug — HttpHelpers.SetAbsoluteUri को पैच करें (Step 3 देखें)। यह भी पुष्टि करें
कि cert CA-signed है और 443 पर पहुंच योग्य है।
बॉट को कॉल करने पर 'we couldn't connect you' सुनाई देता है
पुष्टि करें कि Teams चैनल पर सही /api/calling webhook के साथ Calling सक्षम है,
Graph Calls.AccessMedia.All अनुमति के लिए consent दिया गया है, और NSG व Windows firewall दोनों पर ports 443/8445/9441 खुले हैं। अगर कॉलिंग पहले काम करती थी और बंद हो गई, तो जांचें कि बॉट प्रक्रिया
अभी भी VM पर चल रही है — Task Scheduler की डिफ़ॉल्ट 72-hour execution limit, बूट के कुछ
दिनों बाद इसे बंद कर देती है (Step 3 में चेतावनी देखें)।