",
21 | },
22 | "replyTo": [{ "address": replyto_address }]
23 | }
24 |
25 | try:
26 | client = EmailClient.from_connection_string(connection_string)
27 |
28 | poller = client.begin_send(message);
29 |
30 | time_elapsed = 0
31 | while not poller.done():
32 | print("Email send poller status: " + poller.status())
33 |
34 | poller.wait(POLLER_WAIT_TIME)
35 | time_elapsed += POLLER_WAIT_TIME
36 |
37 | if time_elapsed > 18 * POLLER_WAIT_TIME:
38 | raise RuntimeError("Polling timed out.")
39 |
40 | if poller.result()["status"] == "Succeeded":
41 | print(f"Successfully sent the email (operation id: {poller.result()['id']})")
42 | else:
43 | raise RuntimeError(str(poller.result()["error"]))
44 |
45 | except Exception as ex:
46 | print(ex)
47 |
--------------------------------------------------------------------------------
/phone-numbers-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Manage Phone Numbers
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Manage Phone Numbers](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/get-phone-number?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - A deployed Communication Services resource and connection string. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
20 |
21 | ## Code Structure
22 |
23 | - **./phone-numbers-quickstart/phone_numbers_sample.py:** contains code for managing phone numbers.
24 |
25 | ## Install the packages
26 |
27 | pip install azure-communication-phonenumbers
28 |
29 | pip install azure-identity
30 |
31 | ## Before running sample code
32 |
33 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
34 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
35 | 3. With the Communication Services procured in pre-requisites, add connection string in the code.
36 |
37 | ## Run Locally
38 |
39 | From a console prompt, navigate to the directory containing the phone_numbers_sample.py file, then execute the following command to run the app.
40 |
41 | python ./phone_numbers_sample.py
42 |
43 |
--------------------------------------------------------------------------------
/chat-insights-openai/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Generate chat insights using Azure OpenAI
12 |
13 | ## Prerequisites
14 |
15 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
16 | - An active Communication Services resource. You will need its connection string and endpoint. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
17 | - Create an Azure OpenAI resource. See [instructions](https://aka.ms/acs-sms-open-ai-create-open).
18 | - Deploy an Azure OpenAI model (Can use GPT-3, ChatGPT or GPT-4 models). See [instructions](https://aka.ms/acs-sms-open-ai-deploy-model).
19 | - [Python](https://www.python.org/downloads/) 3.11.2 or above.
20 |
21 | ## Install the packages
22 |
23 | ```bash
24 |
25 | pip install openai azure.communication.chat azure.communication.identity
26 |
27 | ```
28 |
29 | ## Before running sample code
30 |
31 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
32 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
33 | 3. With the Communication Services procured in pre-requisites, add connection string, endpoint, Azure OpenAI key and Azure OpenAI endpoint to **chatInsights.py** file.
34 |
35 | ## Run Locally
36 |
37 | From a console prompt, navigate to the directory containing the chatInsights.py file, then execute the following command to run the app.
38 |
39 | ```bash
40 |
41 | python ./chatInsights.py
42 |
43 | ```
--------------------------------------------------------------------------------
/direct-routing-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Direct Routing Configuration
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Direct Routing](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/voice-routing-sdk-config?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - A deployed Communication Services resource and connection string. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
20 |
21 | ## Code Structure
22 |
23 | - *./direct-routing-quickstart/direct_routing_sample.py* contains code for Direct Routing configuration.
24 |
25 | ## Install the packages
26 |
27 | pip install azure-communication-phonenumbers==1.1.0b3
28 |
29 | pip install azure-identity
30 |
31 | ## Before running sample code
32 |
33 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
34 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
35 | 3. With the Communication Services procured in pre-requisites, add connection string in the code.
36 |
37 | ## Run Locally
38 |
39 | From a console prompt, navigate to the directory containing the *direct_routing_sample.py* file, then execute the following command to run the app.
40 |
41 | ```console
42 | python ./direct_routing_sample.py
43 | ```
44 |
--------------------------------------------------------------------------------
/use-managed-Identity/managed-identity.py:
--------------------------------------------------------------------------------
1 | from azure.identity import DefaultAzureCredential
2 | from azure.communication.identity import CommunicationIdentityClient
3 | from azure.communication.sms import SmsClient
4 |
5 | credential = DefaultAzureCredential()
6 | # You can find your endpoint and access key from your resource in the Azure portal
7 | # e.g. "https://.communication.azure.com";
8 | def create_identity_and_get_token(resource_endpoint):
9 | client = CommunicationIdentityClient(resource_endpoint, credential)
10 |
11 | user = client.create_user()
12 | token_response = client.get_token(user, scopes=["voip"])
13 |
14 | return token_response
15 |
16 | def send_sms(resource_endpoint, from_phone_number, to_phone_number, message_content):
17 | sms_client = SmsClient(resource_endpoint, credential)
18 |
19 | response = sms_client.send(
20 | from_=from_phone_number,
21 | to=[to_phone_number],
22 | message=message_content,
23 | enable_delivery_report=True # optional property
24 | )
25 | return response
26 |
27 | # You can find your endpoint and access key from your resource in the Azure portal
28 | # e.g. "https://.communication.azure.com";
29 | endpoint = "https://.communication.azure.com/"
30 | print("Retrieving new Access Token, using Managed Identities")
31 | result = create_identity_and_get_token(endpoint)
32 | print(f'Retrieved Access Token: {result.token}')
33 |
34 | print("Sending SMS using Managed Identities")
35 | # You will need a phone number from your resource to send an SMS.
36 | sms_result = send_sms(endpoint, "", "", "Hello from Managed Identities")
37 | print(f'SMS ID: {sms_result[0].message_id}')
38 | print(f'Send Result Successful: {sms_result[0].successful}')
--------------------------------------------------------------------------------
/callautomation-live-transcription/transcriptionDataHandler.py:
--------------------------------------------------------------------------------
1 | import json
2 | from azure.communication.callautomation._shared.models import identifier_from_raw_id
3 |
4 | async def process_websocket_message_async(message):
5 | print("Client connected")
6 | json_object = json.loads(message)
7 | kind = json_object['kind']
8 | print(kind)
9 | if kind == 'TranscriptionMetadata':
10 | print("Transcription metadata")
11 | print("-------------------------")
12 | print("Subscription ID:", json_object['transcriptionMetadata']['subscriptionId'])
13 | print("Locale:", json_object['transcriptionMetadata']['locale'])
14 | print("Call Connection ID:", json_object['transcriptionMetadata']['callConnectionId'])
15 | print("Correlation ID:", json_object['transcriptionMetadata']['correlationId'])
16 | if kind == 'TranscriptionData':
17 | participant = identifier_from_raw_id(json_object['transcriptionData']['participantRawID'])
18 | word_data_list = json_object['transcriptionData']['words']
19 | print("Transcription data")
20 | print("-------------------------")
21 | print("Text:", json_object['transcriptionData']['text'])
22 | print("Format:", json_object['transcriptionData']['format'])
23 | print("Confidence:", json_object['transcriptionData']['confidence'])
24 | print("Offset:", json_object['transcriptionData']['offset'])
25 | print("Duration:", json_object['transcriptionData']['duration'])
26 | print("Participant:", participant.raw_id)
27 | print("Result Status:", json_object['transcriptionData']['resultStatus'])
28 | for word in word_data_list:
29 | print("Word:", word['text'])
30 | print("Offset:", word['offset'])
31 | print("Duration:", word['duration'])
32 |
--------------------------------------------------------------------------------
/manage-teams-identity-mobile-and-desktop/exchange-communication-access-tokens.py:
--------------------------------------------------------------------------------
1 | import os
2 | from azure.communication.identity import CommunicationIdentityClient, CommunicationUserIdentifier
3 | from msal.application import PublicClientApplication
4 |
5 | try:
6 | print("Azure Communication Services - Access Tokens Quickstart")
7 | # Quickstart code goes here
8 |
9 | # This code demonstrates how to fetch your Azure AD client ID and tenant ID
10 | # from an environment variable.
11 | client_id = os.environ["AAD_CLIENT_ID"]
12 | tenant_id = os.environ["AAD_TENANT_ID"]
13 | authority = "https://login.microsoftonline.com/%s" % tenant_id
14 |
15 | # Create an instance of PublicClientApplication
16 | app = PublicClientApplication(client_id, authority=authority)
17 |
18 | scopes = [
19 | "https://auth.msft.communication.azure.com/Teams.ManageCalls",
20 | "https://auth.msft.communication.azure.com/Teams.ManageChats"
21 | ]
22 |
23 | # Retrieve the AAD token and object ID of a Teams user
24 | result = app.acquire_token_interactive(scopes)
25 | aad_token = result["access_token"]
26 | user_object_id = result["id_token_claims"]["oid"]
27 | print(f"Teams token:{aad_token}")
28 |
29 | # This code demonstrates how to fetch your connection string
30 | # from an environment variable.
31 | connection_string = os.environ["COMMUNICATION_SERVICES_CONNECTION_STRING"]
32 |
33 | # Instantiate the identity client
34 | client = CommunicationIdentityClient.from_connection_string(connection_string)
35 |
36 | # Exchange the Azure AD access token of the Teams User for a Communication Identity access token
37 | token_result = client.get_token_for_teams_user(aad_token, client_id, user_object_id)
38 | print("Token: " + token_result.token)
39 |
40 | except Exception as ex:
41 | print(f"Exception: {ex}")
--------------------------------------------------------------------------------
/send-email-advanced/send-email-continuation-token/send-email-continuation-token.py:
--------------------------------------------------------------------------------
1 | from azure.communication.email import EmailClient
2 |
3 | connection_string = ""
4 | sender_address = ""
5 | recipient_address = ""
6 |
7 | POLLER_WAIT_TIME = 10
8 | MAX_POLLS = 18
9 |
10 | message = {
11 | "senderAddress": sender_address,
12 | "recipients": {
13 | "to": [{"address": recipient_address}],
14 | },
15 | "content": {
16 | "subject": "Test email from Python Sample",
17 | "plainText": "This is plaintext body of test email.",
18 | "html": "
This is the html body of test email.
",
19 | }
20 | }
21 |
22 | try:
23 | client = EmailClient.from_connection_string(connection_string)
24 | poller = client.begin_send(message);
25 |
26 | # Pauses operation and saves state that can be used later to resume operation
27 | token = poller.continuation_token()
28 |
29 | # Additional processing can be done here between pausing and resuming the operation
30 |
31 | new_client = EmailClient.from_connection_string(connection_string);
32 | new_poller = new_client.begin_send(message, continuation_token=token);
33 |
34 | time_elapsed = 0
35 | while not new_poller.done():
36 | print("Email send poller status: " + new_poller.status())
37 |
38 | new_poller.wait(POLLER_WAIT_TIME)
39 | time_elapsed += POLLER_WAIT_TIME
40 |
41 | if time_elapsed > MAX_POLLS * POLLER_WAIT_TIME:
42 | raise RuntimeError("Polling timed out.")
43 |
44 | if new_poller.result()["status"] == "Succeeded":
45 | print(f"Successfully sent the email (operation id: {new_poller.result()['id']})")
46 | else:
47 | raise RuntimeError(str(new_poller.result()["error"]))
48 |
49 | except Exception as ex:
50 | print(ex)
51 |
--------------------------------------------------------------------------------
/access-tokens-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Create and manage access tokens
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Create and manage access tokens](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - [Python](https://www.python.org/downloads/) 3.7, or above.
19 | - An active Communication Services resource and connection string.. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
20 |
21 | ## Code Structure
22 |
23 | - **./access-tokens-quickstart/issue-access-tokens.py:** contains code for creating and managing access tokens.
24 |
25 | ## Install the package
26 | pip install azure-communication-identity
27 |
28 | ## Before running sample code
29 |
30 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
31 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
32 | 3. With the Communication Services procured in pre-requisites, add connection string to environment variable using below command
33 |
34 | setx COMMUNICATION_SERVICES_CONNECTION_STRING
35 |
36 | 4. Add pip installation to PATH variables.
37 |
38 | ## Run Locally
39 |
40 | From a console prompt, navigate to the directory containing the issue-access-tokens.py file, then execute the following python command to run the app.
41 |
42 | python ./issue-access-tokens.py
43 |
--------------------------------------------------------------------------------
/messages-quickstart/get_templates_list.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: get_templates_list.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates fetching WhatsApp templates created in your WhatsApp Business account. The NotificationMessageClient is
14 | authenticated using a connection string.
15 | USAGE:
16 | python get_templates_list.py
17 |
18 | Set the environment variable with your own value before running the sample:
19 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
20 | 2) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
21 | """
22 |
23 | import os
24 | import sys
25 |
26 | sys.path.append("..")
27 |
28 | class GetTemplatesSample(object):
29 |
30 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
31 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
32 |
33 | def get_templates_list(self):
34 |
35 | from azure.communication.messages import MessageTemplateClient
36 | from azure.communication.messages.models import ( TextNotificationContent )
37 |
38 | message_template_client = MessageTemplateClient.from_connection_string(self.connection_string)
39 |
40 | # calling send() with whatsapp message details
41 | template_list = message_template_client.list_templates(self.channel_id)
42 |
43 | count_templates = len(list(template_list))
44 | print("Successfully retrieved {} templates from channel_id {}."
45 | .format(count_templates, self.channel_id))
46 |
47 | if __name__ == '__main__':
48 | sample = GetTemplatesSample()
49 | sample.get_templates_list()
50 |
--------------------------------------------------------------------------------
/jobrouter-quickstart/readme.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 |
6 | Products:
7 | - azure
8 | - azure-communication-jobrouter
9 | ---
10 |
11 | # Job Router quick start
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Submit a job for queuing and routing](https://learn.microsoft.com/azure/communication-services/quickstarts/router/get-started-router?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - Install [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - Create an Azure Communication Services resource. For details, see [Quickstart: Create and manage Communication Services resources](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource endpoint for this quickstart.
20 |
21 | ## Code Structure
22 |
23 | - **./jobrouter-quickstart/router-quickstart.py:** contains sample code.
24 |
25 | ## Install the packages
26 |
27 | From a console prompt, navigate to the directory containing the router-quickstart.py file, then execute the following command:
28 |
29 | - pip install azure-communication-jobrouter
30 |
31 | ## Before running sample code
32 |
33 | 1. Open an instance of PowerShell/Windows Terminal/Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
34 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
35 | 3. `cd communication-services-python-quickstarts/jobrouter-quickstart`
36 | 4. With the Communication Services procured in pre-requisites, add connection string in **router-quickstart.py** file ```connection_string = ''```.
37 |
38 | ## Run Locally
39 |
40 | From a console prompt, navigate to the directory containing the router-quickstart.py file, then execute the following command to run the app.
41 |
42 | python ./router-quickstart.py
43 |
--------------------------------------------------------------------------------
/send-email-advanced/send-email-attachments/send-email-attachments.py:
--------------------------------------------------------------------------------
1 | import base64
2 | from azure.communication.email import EmailClient
3 |
4 | with open("./attachment.pdf", "rb") as file:
5 | pdf_b64encoded = base64.b64encode(file.read())
6 |
7 | with open("./attachment.txt", "rb") as file:
8 | txt_b64encoded = base64.b64encode(file.read())
9 |
10 | connection_string = ""
11 | sender_address = ""
12 | recipient_address = ""
13 |
14 | POLLER_WAIT_TIME = 10
15 |
16 | message = {
17 | "senderAddress": sender_address,
18 | "recipients": {
19 | "to": [{ "address": recipient_address }]
20 | },
21 | "content": {
22 | "subject": "Test email from Python Sample",
23 | "plainText": "This is plaintext body of test email.",
24 | "html": "
This is the html body of test email.
"
25 | },
26 | "attachments": [
27 | {
28 | "name": "attachment.pdf",
29 | "contentType": "application/pdf",
30 | "contentInBase64": pdf_b64encoded.decode()
31 | },
32 | {
33 | "name": "attachment.txt",
34 | "contentType": "text/plain",
35 | "contentInBase64": txt_b64encoded.decode()
36 | }
37 | ]
38 | }
39 |
40 | try:
41 | client = EmailClient.from_connection_string(connection_string)
42 |
43 | poller = client.begin_send(message);
44 |
45 | time_elapsed = 0
46 | while not poller.done():
47 | print("Email send poller status: " + poller.status())
48 |
49 | poller.wait(POLLER_WAIT_TIME)
50 | time_elapsed += POLLER_WAIT_TIME
51 |
52 | if time_elapsed > 18 * POLLER_WAIT_TIME:
53 | raise RuntimeError("Polling timed out.")
54 |
55 | if poller.result()["status"] == "Succeeded":
56 | print(f"Successfully sent the email (operation id: {poller.result()['id']})")
57 | else:
58 | raise RuntimeError(str(poller.result()["error"]))
59 |
60 | except Exception as ex:
61 | print(ex)
62 |
--------------------------------------------------------------------------------
/rooms-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 |
6 | Products:
7 | - azure
8 | - azure-communication-rooms
9 | ---
10 |
11 |
12 | # Manage Rooms
13 |
14 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Create a room]
15 |
16 | ## Prerequisites
17 |
18 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
19 | - Install [Python](https://www.python.org/downloads/) 3.7 or above.
20 | - Create an Azure Communication Services resource. For details, see [Quickstart: Create and manage Communication Services resources](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource endpoint for this quickstart.
21 | - Create a [user access token](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python). Be sure to set the scope to **voip**, and note the **token** string as well as the **userId** string.
22 |
23 | ## Code Structure
24 |
25 | - **./rooms-python-quickstart/rooms.py:** contains code for managing rooms.
26 |
27 | ## Install the packages
28 |
29 | From a console prompt, navigate to the directory containing the rooms.py file, then execute the following command:
30 |
31 | - pip install azure-communication-rooms==1.1.0
32 | - pip install azure-communication-identity
33 |
34 | ## Before running sample code
35 |
36 | 1. Open an instance of PowerShell/Windows Terminal/Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
37 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
38 | 3. With the Communication Services procured in pre-requisites, add connection string in **rooms.py** file at line 14 ```connection_string = ''```.
39 |
40 | ## Run Locally
41 |
42 | From a console prompt, navigate to the directory containing the rooms.py file, then execute the following command to run the app.
43 |
44 | python ./rooms.py
45 |
--------------------------------------------------------------------------------
/send-sms-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Manage Phone Numbers
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Send an SMS message](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/send?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - An active Communication Services resource and connection string. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
20 | - An SMS enabled telephone number. [Get a phone number](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/get-phone-number?pivots=programming-language-python).
21 |
22 | ## Code Structure
23 |
24 | - **./send-sms-quickstart/send-sms.py:** contains code for sending message.
25 |
26 | ## Install the packages
27 |
28 | - pip install azure-communication-sms
29 |
30 | ## Before running sample code
31 |
32 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
33 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
34 | 3. With the Communication Services procured in pre-requisites, add connection string to **send-sms.py** file at line no:8 ```sms_client = SmsClient.from_connection_string("")```.
35 | 4. With the SMS enabled telephone number procured in pre-requisites, add it to the **send-sms.py** file. Assign your ACS telephone number and sender numbers at line no 22 & 23.
36 |
37 |
38 | ## Run Locally
39 |
40 | From a console prompt, navigate to the directory containing the send-sms.py file, then execute the following command to run the app.
41 |
42 | python ./send-sms.py
43 |
44 |
--------------------------------------------------------------------------------
/lookup-phone-numbers-quickstart/number-lookup-sample.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | from azure.communication.phonenumbers import PhoneNumbersClient
4 |
5 | try:
6 | print('Azure Communication Services - Number Lookup Quickstart')
7 |
8 | if len(sys.argv) < 2:
9 | sys.exit("Missing a phone number parameter")
10 | phoneNumber = sys.argv[1]
11 |
12 | # This code retrieves your connection string from an environment variable
13 | connection_string = os.getenv('COMMUNICATION_SERVICES_CONNECTION_STRING')
14 | try:
15 | phone_numbers_client = PhoneNumbersClient.from_connection_string(connection_string)
16 | except Exception as ex:
17 | print('Exception:')
18 | print(ex)
19 |
20 | # Use the free number lookup functionality to get number formatting information
21 | formatting_results = phone_numbers_client.search_operator_information(phoneNumber)
22 | formatting_info = formatting_results.values[0]
23 | print(str.format("{0} is formatted {1} internationally, and {2} nationally", formatting_info.phone_number, formatting_info.international_format, formatting_info.national_format))
24 |
25 | # Use the paid number lookup functionality to get operator specific details
26 | # IMPORTANT NOTE: Invoking the method below will incur a charge to your account
27 | options = { "include_additional_operator_details": True }
28 | operator_results = phone_numbers_client.search_operator_information([ phoneNumber ], options=options)
29 | operator_information = operator_results.values[0]
30 |
31 | number_type = operator_information.number_type if operator_information.number_type else "unknown"
32 | if operator_information.operator_details is None or operator_information.operator_details.name is None:
33 | operator_name = "an unknown operator"
34 | else:
35 | operator_name = operator_information.operator_details.name
36 |
37 | print(str.format("{0} is a {1} number, operated in {2} by {3}", operator_information.phone_number, number_type, operator_information.iso_country_code, operator_name))
38 | except Exception as ex:
39 | print('Exception:')
40 | print(ex)
41 |
--------------------------------------------------------------------------------
/messages-quickstart/get_templates_list_async.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: get_templates_list_async.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates fetching WhatsApp templates created in your WhatsApp Business account. The NotificationMessageClient is
14 | authenticated using a connection string.
15 | USAGE:
16 | python get_templates_list_async.py
17 |
18 | Set the environment variable with your own value before running the sample:
19 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
20 | 2) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
21 | """
22 |
23 | import asyncio
24 | import os
25 | import sys
26 |
27 | sys.path.append("..")
28 |
29 | class GetTemplatesSampleAsync(object):
30 |
31 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
32 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
33 |
34 | async def get_templates_list_async(self):
35 |
36 | from azure.communication.messages.aio import MessageTemplateClient
37 |
38 | message_template_client = MessageTemplateClient.from_connection_string(self.connection_string)
39 |
40 | # calling send() with whatsapp message details
41 | async with message_template_client:
42 | template_list = message_template_client.list_templates(self.channel_id)
43 | async_list_data = [x async for x in template_list]
44 | count_templates = len(list(async_list_data))
45 | print("Successfully retrieved {} templates from channel_id {}."
46 | .format(count_templates, self.channel_id))
47 |
48 | async def main():
49 | sample = GetTemplatesSampleAsync()
50 | await sample.get_templates_list_async()
51 |
52 | if __name__ == '__main__':
53 | asyncio.run(main())
54 |
--------------------------------------------------------------------------------
/lookup-phone-numbers-quickstart/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 |
11 | # Manage Phone Numbers
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Look Up Phone Numbers](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/number-lookup?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - A deployed Communication Services resource and connection string. [Create a Communication Services resource](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/create-communication-resource).
20 |
21 | ## Code Structure
22 |
23 | - **./lookup-phone-numbers-quickstart/number-lookup-sample.py:** contains code for looking up phone numbers.
24 |
25 | ## Install the packages
26 |
27 | pip install azure-communication-phonenumbers==1.2.0
28 |
29 | pip install azure-identity
30 |
31 | ## Before running sample code
32 |
33 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
34 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
35 | 3. With the Communication Services procured in pre-requisites, add connection string as an environment variable named `COMMUNICATION_SERVICES_CONNECTION_STRING`
36 | 4. Decide which lookup you would like to perform, and keep in mind that looking up all the operator details incurs a cost, while looking up only number formatting is free.
37 |
38 | > [!WARNING]
39 | > If you want to avoid incurring a charge, comment out lines 27-37
40 | >
41 | ## Run Locally
42 |
43 | From a console prompt, navigate to the directory containing the number-lookup-sample.py file, then execute the following command to run the app, replacing `
46 |
47 |
--------------------------------------------------------------------------------
/send-email-advanced/send-email-inline-attachments/send-email-inline-attachments.py:
--------------------------------------------------------------------------------
1 | import base64
2 | from azure.communication.email import EmailClient
3 |
4 | with open("./inline-attachment.jpg", "rb") as file:
5 | jpg_b64encoded = base64.b64encode(file.read())
6 |
7 | with open("./inline-attachment.png", "rb") as file:
8 | png_b64encoded = base64.b64encode(file.read())
9 |
10 | connection_string = ""
11 | sender_address = ""
12 | recipient_address = ""
13 |
14 | POLLER_WAIT_TIME = 10
15 |
16 | message = {
17 | "senderAddress": sender_address,
18 | "recipients": {
19 | "to": [{ "address": recipient_address }]
20 | },
21 | "content": {
22 | "subject": "Test email from Python Sample",
23 | "plainText": "This is plaintext body of test email.",
24 | "html": "
HTML body inline images:
"
25 | },
26 | "attachments": [
27 | {
28 | "name": "inline-attachments.jpg",
29 | "contentId": "kittens-1",
30 | "contentType": "image/jpeg",
31 | "contentInBase64": jpg_b64encoded.decode()
32 | },
33 | {
34 | "name": "inline-attachments.png",
35 | "contentId": "kittens-2",
36 | "contentType": "image/png",
37 | "contentInBase64": png_b64encoded.decode()
38 | }
39 | ]
40 | }
41 |
42 | try:
43 | client = EmailClient.from_connection_string(connection_string)
44 |
45 | poller = client.begin_send(message);
46 |
47 | time_elapsed = 0
48 | while not poller.done():
49 | print("Email send poller status: " + poller.status())
50 |
51 | poller.wait(POLLER_WAIT_TIME)
52 | time_elapsed += POLLER_WAIT_TIME
53 |
54 | if time_elapsed > 18 * POLLER_WAIT_TIME:
55 | raise RuntimeError("Polling timed out.")
56 |
57 | if poller.result()["status"] == "Succeeded":
58 | print(f"Successfully sent the email (operation id: {poller.result()['id']})")
59 | else:
60 | raise RuntimeError(str(poller.result()["error"]))
61 |
62 | except Exception as ex:
63 | print(ex)
64 |
--------------------------------------------------------------------------------
/messages-quickstart/send_text_notification_messages.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_text_notification_messages.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp message from business phone number to a single user. The NotificationMessageClient is
14 | authenticated using a connection string.
15 | USAGE:
16 | python send_text_notification_messages.py
17 |
18 | Set the environment variable with your own value before running the sample:
19 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
20 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities. Use list for recipient phone number.
21 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
22 | """
23 |
24 | import os
25 | import sys
26 |
27 | sys.path.append("..")
28 |
29 | class SendWhatsAppMessageSample(object):
30 |
31 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
32 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
33 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
34 |
35 | def send_text_send_message(self):
36 |
37 | from azure.communication.messages import NotificationMessagesClient
38 | from azure.communication.messages.models import TextNotificationContent
39 |
40 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
41 |
42 | text_options = TextNotificationContent(
43 | channel_registration_id=self.channel_id,
44 | to=[self.phone_number],
45 | content="Hello World via Notification Messaging SDK.",
46 | )
47 |
48 | # calling send() with whatsapp message details
49 | message_responses = messaging_client.send(text_options)
50 | response = message_responses.receipts[0]
51 | print("Message with message id {} was successful sent to {}"
52 | .format(response.message_id, response.to))
53 |
54 | if __name__ == '__main__':
55 | sample = SendWhatsAppMessageSample()
56 | sample.send_text_send_message()
57 |
--------------------------------------------------------------------------------
/messages-quickstart/send_image_notification_messages.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_image_notification_messages.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp message with image from business phone number to a single user. The NotificationMessageClient is
14 | authenticated using a connection string.
15 | USAGE:
16 | python send_image_notification_messages.py
17 |
18 | Set the environment variable with your own value before running the sample:
19 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
20 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities. Use list for recipient phone number.
21 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
22 | """
23 |
24 | import os
25 | import sys
26 |
27 | sys.path.append("..")
28 |
29 | class SendWhatsAppMessageSample(object):
30 |
31 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
32 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
33 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
34 |
35 | def send_image_send_message(self):
36 |
37 | from azure.communication.messages import NotificationMessagesClient
38 | from azure.communication.messages.models import ImageNotificationContent
39 |
40 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
41 |
42 | image_options = ImageNotificationContent(
43 | channel_registration_id=self.channel_id,
44 | to=[self.phone_number],
45 | content="Hello World via Notification Messaging SDK.",
46 | media_uri="https://aka.ms/acsicon1"
47 | )
48 |
49 | # calling send() with whatsapp message details
50 | message_responses = messaging_client.send(image_options)
51 | response = message_responses.receipts[0]
52 | print("Message with message id {} was successful sent to {}"
53 | .format(response.message_id, response.to))
54 |
55 | if __name__ == '__main__':
56 | sample = SendWhatsAppMessageSample()
57 | sample.send_image_send_message()
58 |
--------------------------------------------------------------------------------
/access-tokens-quickstart/issue-access-tokens.py:
--------------------------------------------------------------------------------
1 | import os
2 | from datetime import timedelta
3 | from azure.communication.identity import CommunicationIdentityClient, CommunicationUserIdentifier
4 |
5 | try:
6 | print("Azure Communication Services - Access Tokens Quickstart")
7 |
8 | # This code demonstrates how to fetch your connection string from an environment variable.
9 | connection_string = os.environ["COMMUNICATION_SERVICES_CONNECTION_STRING"]
10 |
11 | # Instantiate the identity client
12 | client = CommunicationIdentityClient.from_connection_string(connection_string)
13 |
14 | # Create an identity
15 | identity = client.create_user()
16 | print("\nCreated an identity with ID: " + identity.properties['id'])
17 |
18 | #Store the identity to issue access tokens later
19 | existingIdentity = identity
20 |
21 | # Issue an access token with a validity of 24 hours and the "voip" scope for an identity
22 | token_result = client.get_token(identity, ["voip"])
23 | print("\nIssued an access token with 'voip' scope that expires at " + token_result.expires_on + ":")
24 | print(token_result.token)
25 |
26 | # Issue an access token with a validity of an hour and the "voip" scope for an identity
27 | token_expires_in = timedelta(hours=1)
28 | token_result = client.get_token(identity, ["voip"], token_expires_in=token_expires_in)
29 |
30 | # Create an identity and issue an access token with a validity of 24 hours within the same request
31 | identity_token_result = client.create_user_and_token(["voip"])
32 | # Get the token details from the response
33 | identity = identity_token_result[0]
34 | token = identity_token_result[1].token
35 | expires_on = identity_token_result[1].expires_on
36 | print("\nCreated an identity with ID: " + identity.properties['id'])
37 | print("\nIssued an access token with 'voip' scope that expires at " + expires_on + ":")
38 | print(token)
39 |
40 | # Refresh access tokens - existingIdentity represents identity of Azure Communication Services stored during identity creation
41 | identity = CommunicationUserIdentifier(existingIdentity.properties['id'])
42 | token_result = client.get_token( identity, ["voip"])
43 |
44 | # Revoke access tokens
45 | client.revoke_tokens(identity)
46 | print("\nSuccessfully revoked all access tokens for identity with ID: " + identity.properties['id'])
47 |
48 | # Delete an identity
49 | client.delete_user(identity)
50 | print("\nDeleted the identity with ID: " + identity.properties['id'])
51 |
52 | except Exception as ex:
53 | print("Exception:")
54 | print(ex)
--------------------------------------------------------------------------------
/use-managed-Identity/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | - azure-communication-sms
9 | ---
10 |
11 |
12 | # Use managed identities
13 |
14 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Use managed identities](https://docs.microsoft.com/azure/communication-services/quickstarts/managed-identity?pivots=programming-language-python)
15 |
16 | ## Prerequisites
17 |
18 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
19 | - [Python](https://www.python.org/downloads/) 3.7 or above.
20 | - A deployed Communication Services resource and connection string. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
21 | - To send an SMS you will need a [Phone Number](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/get-phone-number?pivots=programming-language-python).
22 | - A setup managed identity for a development environment, see [Authorize access with managed identity](https://docs.microsoft.com/azure/communication-services/quickstarts/managed-identity-from-cli).
23 | ## Code Structure
24 |
25 | - **./use-managed-Identity/managed-identity.py:** contains code to use managed identities.
26 |
27 | ## Install the packages
28 |
29 | - pip install azure-identity
30 | - pip install azure-communication-identity
31 | - pip install azure-communication-sms
32 |
33 | ## Before running sample code
34 |
35 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
36 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
37 | 3. With the Communication Services procured in pre-requisites, add endpoint to the **managed-identity.py** file at line no 29: ```endpoint = "https://.communication.azure.com/"```.
38 | 4. With the SMS enabled telephone number procured in pre-requisites, add it to the **managed-identity.py** file. Assign your ACS telephone number and sender number at line 36: ```sms_result = send_sms(endpoint, "", "", "Hello from Managed Identities");```
39 |
40 | ## Run Locally
41 |
42 | From a console prompt, navigate to the directory containing the managed-identity.py file, then execute the following command to run the app.
43 |
44 | python ./managed-identity.py
45 |
46 |
--------------------------------------------------------------------------------
/add-chat/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-chat
8 | - azure-communication-identity
9 | ---
10 |
11 |
12 | # Add Chat to your App
13 |
14 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Add Chat to your App](https://docs.microsoft.com/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-python)
15 |
16 | ## Prerequisites
17 |
18 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
19 | - Install [Python](https://www.python.org/downloads/) 3.7 or above.
20 | - Create an Azure Communication Services resource. For details, see [Quickstart: Create and manage Communication Services resources](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource endpoint for this quickstart.
21 | - A [user access token](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python). Be sure to set the scope to **chat**, and note the **token** string as well as the **userId** string.
22 |
23 | ## Code Structure
24 |
25 | - **./add-chat/start-chat.py:** contains code for chat.
26 |
27 | ## Install the packages
28 |
29 | pip install azure-communication-chat
30 |
31 | pip install azure-communication-identity
32 |
33 | ## Before running sample code
34 |
35 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
36 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
37 | 3. With the Communication Services procured in pre-requisites, add endpoint to **start-chat.py** file at line no:11 ```endpoint = "https://.communication.azure.com"```.
38 | 4. With the access token procured in pre-requisites, add it to the **start-chat.py** file. Assign token at line no:12 ```chat_client = ChatClient(endpoint, CommunicationTokenCredential(""))```.
39 | 5. With the Communication Services procured in pre-requisites, add connection string to **start-chat.py** file at line no:58 ```identity_client = CommunicationIdentityClient.from_connection_string('')```.
40 |
41 |
42 | ## Run Locally
43 |
44 | From a console prompt, navigate to the directory containing the start-chat.py file, then execute the following command to run the app.
45 |
46 | python ./start-chat.py
47 |
48 |
--------------------------------------------------------------------------------
/messages-quickstart/readme.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 |
6 | Products:
7 | - azure
8 | - azure-communication-messages
9 | ---
10 |
11 | # Advanced Messages quick start
12 |
13 | For full instructions on how to build this code sample from scratch, look at [Quickstart: Send WhatsApp Messages](https://learn.microsoft.com/azure/communication-services/quickstarts/advanced-messaging/whatsapp/get-started?pivots=programming-language-python)
14 |
15 | ## Prerequisites
16 |
17 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
18 | - Install [Python](https://www.python.org/downloads/) 3.7 or above.
19 | - Create an Azure Communication Services resource. For details, see [Quickstart: Create and manage Communication Services resources](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource endpoint for this quickstart.
20 | - Active WhatsApp phone number to receive messages.
21 | - [WhatsApp Business Account registered with your Azure Communication Services resource](/azure/communication-services/quickstarts/advanced-messaging/whatsapp/connect-whatsapp-business-account)
22 |
23 | ## Code Structure
24 | To run any sample, please select the respective python script.
25 | - **./messages-quickstart/send_text_notification_messages.py:** contains sample code for sending whatsapp messages.
26 |
27 | ## Install the packages
28 |
29 | From a console prompt, navigate to the directory containing the messages-quickstart.py file, then execute the following command:
30 |
31 | ```console
32 | pip install azure-communication-messages
33 | ```
34 |
35 | ## Before running sample code
36 |
37 | 1. Open an instance of PowerShell/Windows Terminal/Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
38 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
39 | 3. `cd communication-services-python-quickstarts/messages-quickstart`
40 | 4. With the Communication Services procured in pre-requisites, set environment variables as needed in Sample file and update the same in **send_text_notification_messages.py** file.
41 |
42 | ## Run Locally
43 |
44 | From a console prompt, navigate to the directory containing the send_text_notification_messages.py file, then execute the following command to run the app.
45 |
46 | ```python
47 | python ./send_text_notification_messages.py
48 | ```
49 |
50 | Note: Please follow the same approach for running any Sample.
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Azure Communication Services Python SDK
2 |
3 | Azure Communication Services enable developers to add communication capabilities to their applications.
4 |
5 | ## Prerequisites
6 |
7 | - Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
8 | - Install [Python](https://www.python.org/downloads/) 3.7 or above.
9 | - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&pivots=platform-azp).
10 |
11 | ## Quickstarts
12 |
13 | 1. [Send SMS](https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/telephony-sms/send?pivots=programming-language-python)
14 |
15 | 2. [Add Chat to your app](https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-python)
16 |
17 | 3. [Create and manage access tokens](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python)
18 |
19 | 4. [Set up and manage access tokens for Teams users](https://docs.microsoft.com/azure/communication-services/quickstarts/manage-teams-identity?pivots=programming-language-python)
20 |
21 | 5. [Manage Phone Numbers](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/get-phone-number?pivots=programming-language-python)
22 |
23 | 6. [Use managed identities](https://docs.microsoft.com/azure/communication-services/quickstarts/managed-identity?pivots=programming-language-python)
24 |
25 | 7. [Get started with Rooms](https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/rooms/get-started-rooms?pivots=programming-language-python)
26 |
27 | ## Data CollectionAdd commentMore actions
28 |
29 | The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. Some Quickstart samples collect information about users and their use of the software that cannot be opted out of. Do not use Quickstart samples that collect information if you wish to avoid telemetry. You can learn more about data collection and use in the help documentation and Microsoft’s [privacy statement](https://go.microsoft.com/fwlink/?LinkID=824704). For more information on the data collected by the Azure SDK, please visit the [Telemetry Policy](https://learn.microsoft.com/azure/communication-services/concepts/privacy) page.
30 |
--------------------------------------------------------------------------------
/messages-quickstart/send_text_notification_messages_async.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_text_notification_messages_async.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp message from business phone number to a single user. The NotificationMessageClient is
14 | authenticated using a connection string.
15 |
16 | USAGE:
17 | python send_text_notification_messages_async.py
18 |
19 | Set the environment variable with your own value before running the sample:
20 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
21 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities
22 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
23 | """
24 |
25 | import asyncio
26 | import os
27 | import sys
28 |
29 | sys.path.append("..")
30 |
31 | class SendWhatsAppMessageSampleAsync(object):
32 |
33 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
34 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
35 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
36 |
37 | async def send_text_send_message_async(self):
38 | from azure.communication.messages.aio import NotificationMessagesClient
39 | from azure.communication.messages.models import TextNotificationContent
40 |
41 | # client creation
42 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
43 |
44 | text_options = TextNotificationContent(
45 | channel_registration_id=self.channel_id,
46 | to=[self.phone_number],
47 | content="Hello World via Notification Messaging SDK.",
48 | )
49 |
50 | # calling send() with whatsapp message details
51 | async with messaging_client:
52 | message_responses = await messaging_client.send(text_options)
53 | response = message_responses.receipts[0]
54 | print("Message with message id {} was successful sent to {}"
55 | .format(response.message_id, response.to))
56 |
57 |
58 | async def main():
59 | sample = SendWhatsAppMessageSampleAsync()
60 | await sample.send_text_send_message_async()
61 |
62 |
63 | if __name__ == '__main__':
64 | asyncio.run(main())
65 |
--------------------------------------------------------------------------------
/messages-quickstart/send_image_notification_messages_async.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_image_notification_messages_async.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp message with image from business phone number to a single user. The NotificationMessageClient is
14 | authenticated using a connection string.
15 |
16 | USAGE:
17 | python send_image_notification_messages_async.py
18 |
19 | Set the environment variable with your own value before running the sample:
20 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
21 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities
22 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
23 | """
24 |
25 | import asyncio
26 | import os
27 | import sys
28 |
29 | sys.path.append("..")
30 |
31 | class SendWhatsAppMessageSampleAsync(object):
32 |
33 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
34 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
35 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
36 |
37 | async def send_image_send_message_async(self):
38 | from azure.communication.messages.aio import NotificationMessagesClient
39 | from azure.communication.messages.models import ImageNotificationContent
40 |
41 | # client creation
42 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
43 |
44 | image_options = ImageNotificationContent(
45 | channel_registration_id=self.channel_id,
46 | to= [self.phone_number],
47 | content="Hello World via Notification Messaging SDK.",
48 | media_uri="https://aka.ms/acsicon1"
49 | )
50 |
51 | # calling send() with whatsapp message details
52 | async with messaging_client:
53 | message_responses = await messaging_client.send(image_options)
54 | response = message_responses.receipts[0]
55 | print("Message with message id {} was successful sent to {}"
56 | .format(response.message_id, response.to))
57 |
58 | async def main():
59 | sample = SendWhatsAppMessageSampleAsync()
60 | await sample.send_image_send_message_async()
61 |
62 |
63 | if __name__ == '__main__':
64 | asyncio.run(main())
65 |
--------------------------------------------------------------------------------
/phone-numbers-quickstart/phone_numbers_sample.py:
--------------------------------------------------------------------------------
1 | import os
2 | from azure.communication.phonenumbers import PhoneNumbersClient,PhoneNumberCapabilityType, PhoneNumberAssignmentType, PhoneNumberType, PhoneNumberCapabilities
3 |
4 | connection_string = 'https://.communication.azure.com/;accesskey='
5 | try:
6 | print('Azure Communication Services - Phone Numbers Quickstart')
7 |
8 | #Initializing phone number client
9 | phone_numbers_client = PhoneNumbersClient.from_connection_string(connection_string)
10 |
11 | capabilities = PhoneNumberCapabilities(
12 | calling = PhoneNumberCapabilityType.INBOUND,
13 | sms = PhoneNumberCapabilityType.INBOUND_OUTBOUND
14 | )
15 |
16 | #Search available phone numbers
17 | search_poller = phone_numbers_client.begin_search_available_phone_numbers(
18 | "US",
19 | PhoneNumberType.TOLL_FREE,
20 | PhoneNumberAssignmentType.APPLICATION,
21 | capabilities,
22 | polling = True
23 | )
24 | search_result = search_poller.result()
25 | print ('Search id: ' + search_result.search_id)
26 |
27 | phone_number_list = search_result.phone_numbers
28 | phone_number = phone_number_list[0:1]
29 |
30 | print('Reserved phone numbers:')
31 | for phone_number in phone_number_list:
32 | print(phone_number)
33 |
34 | #Purchase available phone number
35 | purchase_poller = phone_numbers_client.begin_purchase_phone_numbers(search_result.search_id, polling = True)
36 | purchase_poller.result()
37 | print("The status of the purchase operation was: " + purchase_poller.status())
38 |
39 | #Get purchased phone number
40 | purchased_phone_number_information = phone_numbers_client.get_purchased_phone_number(phone_number)
41 | print('Phone number: ' + purchased_phone_number_information.phone_number)
42 | print('Country code: ' + purchased_phone_number_information.country_code)
43 |
44 | #Get all purchased phone numbers
45 | purchased_phone_numbers = phone_numbers_client.list_purchased_phone_numbers()
46 | print('Purchased phone numbers:')
47 | for purchased_phone_number in purchased_phone_numbers:
48 | print(purchased_phone_number.phone_number)
49 |
50 | #Update the capabilities of the purchased phone number
51 | update_poller = phone_numbers_client.begin_update_phone_number_capabilities(
52 | phone_number,
53 | PhoneNumberCapabilityType.OUTBOUND,
54 | PhoneNumberCapabilityType.OUTBOUND,
55 | polling = True
56 | )
57 | update_poller.result()
58 | print('Status of the operation: ' + update_poller.status())
59 |
60 | #Release the purchased phone number
61 | release_poller = phone_numbers_client.begin_release_phone_number(phone_number)
62 | release_poller.result()
63 | print('Status of the operation: ' + release_poller.status())
64 |
65 |
66 | except Exception as ex:
67 | print('Exception:')
68 | print(ex)
--------------------------------------------------------------------------------
/messages-quickstart/send_template_notification_messages.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_template_notification_messages.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp template message from business phone number to a single user.
14 | Template to be used in the sample needs to be created in WhatsApp Business account first.
15 | Follow the instructions in the Meta Business Help Center at https://www.facebook.com/business/help/2055875911147364?id=2129163877102343.
16 | The NotificationMessageClient is authenticated using a connection string.
17 | USAGE:
18 | python send_template_notification_messages.py
19 |
20 | Set the environment variable with your own value before running the sample:
21 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
22 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities. Use list for recipient phone number.
23 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
24 | """
25 |
26 | import os
27 | import sys
28 |
29 | sys.path.append("..")
30 |
31 | class SendWhatsAppTemplateMessageSample(object):
32 |
33 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
34 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
35 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
36 |
37 | def send_template_send_message(self):
38 |
39 | from azure.communication.messages import NotificationMessagesClient
40 | from azure.communication.messages.models import TemplateNotificationContent, MessageTemplate
41 |
42 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
43 |
44 | # Setting template options
45 | input_template: MessageTemplate = MessageTemplate(
46 | name="gathering_invitation", # Name of the WhatsApp Template
47 | language="ca") # Language of the WhatsApp Template
48 | template_options = TemplateNotificationContent(
49 | channel_registration_id= self.channel_id,
50 | to=[self.phone_number],
51 | template=input_template)
52 |
53 | # calling send() with whatsapp message details
54 | message_responses = messaging_client.send(template_options)
55 | response = message_responses.receipts[0]
56 | print("Message with message id {} was successful sent to {}"
57 | .format(response.message_id, response.to))
58 |
59 | if __name__ == '__main__':
60 | sample = SendWhatsAppTemplateMessageSample()
61 | sample.send_template_send_message()
62 |
--------------------------------------------------------------------------------
/jobrouter-quickstart/router-quickstart.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from azure.communication.jobrouter import (
4 | JobRouterClient,
5 | JobRouterAdministrationClient
6 | )
7 |
8 | from azure.communication.jobrouter.models import (
9 | LongestIdleMode,
10 | RouterWorkerSelector,
11 | LabelOperator,
12 | RouterChannel,
13 | CloseJobOptions
14 | )
15 |
16 | class RouterQuickstart(object):
17 | print("Azure Communication Services - Job Router Quickstart")
18 |
19 | # Get a connection string to our Azure Communication Services resource.
20 | connection_string = "conn_str"
21 | router_admin_client = JobRouterAdministrationClient.from_connection_string(conn_str = connection_string)
22 | router_client = JobRouterClient.from_connection_string(conn_str = connection_string)
23 |
24 | distribution_policy = router_admin_client.upsert_distribution_policy(
25 | distribution_policy_id ="distribution-policy-1",
26 | offer_expires_after_seconds = 60,
27 | mode = LongestIdleMode(),
28 | name = "My distribution policy")
29 |
30 | queue = router_admin_client.upsert_queue(
31 | queue_id = "queue-1",
32 | name = "My Queue",
33 | distribution_policy_id = distribution_policy.id)
34 |
35 | job = router_client.upsert_job(
36 | job_id = "job-1",
37 | channel_id = "voice",
38 | queue_id = queue.id,
39 | priority = 1,
40 | requested_worker_selectors = [
41 | RouterWorkerSelector(
42 | key = "Some-Skill",
43 | label_operator = LabelOperator.GREATER_THAN,
44 | value = 10
45 | )
46 | ])
47 |
48 | worker = router_client.upsert_worker(
49 | worker_id = "worker-1",
50 | capacity = 1,
51 | queues = ["queue-1"],
52 | labels = { "Some-Skill": 11 },
53 | channels = [RouterChannel(channel_id = "voice", capacity_cost_per_job = 1)],
54 | available_for_offers = True)
55 |
56 | time.sleep(10)
57 | worker = router_client.get_worker(worker_id = worker.id)
58 | for offer in worker.offers:
59 | print(f"Worker {worker.id} has an active offer for job {offer.job_id}")
60 |
61 | accept = router_client.accept_job_offer(worker_id = worker.id, offer_id = worker.offers[0].offer_id)
62 | print(f"Worker {worker.id} is assigned job {accept.job_id}")
63 |
64 | router_client.complete_job(job_id = job.id, assignment_id = accept.assignment_id)
65 | print(f"Worker {worker.id} has completed job {accept.job_id}")
66 |
67 | router_client.close_job(job_id = job.id, assignment_id = accept.assignment_id, options = CloseJobOptions(disposition_code = "Resolved"))
68 | print(f"Worker {worker.id} has closed job {accept.job_id}")
69 |
70 | router_client.delete_job(accept.job_id)
71 | print(f"Deleting {accept.job_id}")
72 |
73 |
74 | if __name__ == '__main__':
75 | router = RouterQuickstart()
--------------------------------------------------------------------------------
/messages-quickstart/send_template_notification_messages_async.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_template_notification_messages_async.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp template message from business phone number to a single user.
14 | Template to be used in the sample needs to be created in WhatsApp Business account first.
15 | Follow the instructions in the Meta Business Help Center at https://www.facebook.com/business/help/2055875911147364?id=2129163877102343.
16 | The NotificationMessageClient is authenticated using a connection string.
17 | USAGE:
18 | python send_template_notification_messages_async.py
19 |
20 | Set the environment variable with your own value before running the sample:
21 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
22 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities. Use list for recipient phone number.
23 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
24 | """
25 |
26 | import asyncio
27 | import os
28 | import sys
29 |
30 | sys.path.append("..")
31 |
32 | class SendWhatsAppTemplateMessageSampleAsync(object):
33 |
34 | connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
35 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
36 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
37 |
38 | async def send_template_send_message_async(self):
39 | from azure.communication.messages.aio import NotificationMessagesClient
40 | from azure.communication.messages.models import TemplateNotificationContent, MessageTemplate
41 |
42 | messaging_client = NotificationMessagesClient.from_connection_string(self.connection_string)
43 |
44 | # Setting template options
45 | input_template: MessageTemplate = MessageTemplate(
46 | name="gathering_invitation", # Name of the WhatsApp Template
47 | language="ca") # Language of the WhatsApp Template
48 | template_options = TemplateNotificationContent(
49 | channel_registration_id= self.channel_id,
50 | to=[self.phone_number],
51 | template=input_template)
52 |
53 | # calling send() with whatsapp message details
54 | async with messaging_client:
55 | message_responses =await messaging_client.send(template_options)
56 | response = message_responses.receipts[0]
57 | print("Message with message id {} was successful sent to {}"
58 | .format(response.message_id, response.to))
59 |
60 |
61 | async def main():
62 | sample = SendWhatsAppTemplateMessageSampleAsync()
63 | await sample.send_template_send_message_async()
64 |
65 | if __name__ == '__main__':
66 | asyncio.run(main())
67 |
--------------------------------------------------------------------------------
/messages-quickstart/send_text_notification_messages_with_token_credentials.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | # -------------------------------------------------------------------------
4 | # Copyright (c) Microsoft Corporation. All rights reserved.
5 | # Licensed under the MIT License. See License.txt in the project root for
6 | # license information.
7 | # --------------------------------------------------------------------------
8 |
9 | """
10 | FILE: send_text_notification_messages_with_token_credentials.py
11 |
12 | DESCRIPTION:
13 | This sample demonstrates sending an Whatsapp message from business phone number to a single user. The NotificationMessageClient is
14 | authenticated using Bearer TokenCredentials with azureidentity.
15 | More information here: https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python
16 | USAGE:
17 | python send_text_notification_messages_with_token_credentials.py
18 |
19 | Set the environment variable with your own value before running the sample:
20 | 1) COMMUNICATION_SAMPLES_CONNECTION_STRING - the connection string in your ACS resource
21 | 2) RECIPIENT_PHONE_NUMBER - a phone number with Whatsapp capabilities. Use list for recipient phone number.
22 | 3) WHATSAPP_CHANNEL_ID - Channel created in Azure portal for Advanced Messaging.
23 | 4) Follow defining environment variables for DefaultAzureCredentials as give here:
24 | https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python#environment-variables
25 | https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal
26 | Variable name Value
27 | AZURE_CLIENT_ID ID of a Microsoft Entra application
28 | AZURE_TENANT_ID ID of the application's Microsoft Entra tenant
29 | AZURE_CLIENT_SECRET one of the application's client secrets
30 | """
31 |
32 | import os
33 | import sys
34 |
35 | sys.path.append("..")
36 |
37 | class SendWhatsAppMessageSample(object):
38 |
39 | endpoint_string = os.getenv("COMMUNICATION_SAMPLES_ENDPOINT_STRING")
40 | phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
41 | channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
42 |
43 | def send_text_send_message(self):
44 |
45 | from azure.communication.messages import NotificationMessagesClient
46 | from azure.communication.messages.models import TextNotificationContent
47 | from azure.identity import DefaultAzureCredential
48 |
49 | messaging_client = NotificationMessagesClient(endpoint=self.endpoint_string,
50 | credential=DefaultAzureCredential())
51 |
52 | text_options = TextNotificationContent(
53 | channel_registration_id=self.channel_id,
54 | to=[self.phone_number],
55 | content="Hello World via Notification Messaging SDK using Token credentials.",
56 | )
57 |
58 | # calling send() with whatsapp message details
59 | message_responses = messaging_client.send(text_options)
60 | response = message_responses.receipts[0]
61 | print("Message with message id {} was successful sent to {}"
62 | .format(response.message_id, response.to))
63 |
64 | if __name__ == '__main__':
65 | sample = SendWhatsAppMessageSample()
66 | sample.send_text_send_message()
67 |
--------------------------------------------------------------------------------
/manage-teams-identity-mobile-and-desktop/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - python
5 | products:
6 | - azure
7 | - azure-communication-services
8 | ---
9 |
10 | # Create and manage Communication access tokens for Teams users in mobile and desktop applications
11 |
12 | This code sample walks you through the process of acquiring a Communication Token Credential by exchanging an Azure AD token of a user with a Teams license for a valid Communication access token.
13 |
14 | This sample application utilizes the [MSAL Python](https://github.com/AzureAD/microsoft-authentication-library-for-python) library for authentication against the Azure AD and acquisition of a token with delegated permissions. The token exchange itself is facilitated by the `azure-communication-identity` package.
15 |
16 | To be able to use the token for Calling, use it to initialize the `CommunicationTokenCredential` from the `azure-communication-chat` library.
17 |
18 | ## Prerequisites
19 |
20 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
21 | - Python 3.7 or later version.
22 | - An active Communication Services resource and connection string. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource/).
23 | - Azure Active Directory tenant with users that have a Teams license.
24 |
25 | ## Before running sample code
26 |
27 | 1. Complete the [Administrator actions](https://docs.microsoft.com/azure/communication-services/quickstarts/manage-teams-identity?pivots=programming-language-javascript#administrator-actions) from the [Manage access tokens for Teams users quickstart](https://docs.microsoft.com/azure/communication-services/quickstarts/manage-teams-identity).
28 | - Take a note of Fabrikam's Azure AD Tenant ID and Contoso's Azure AD App Client ID. You'll need the values in the following steps.
29 | 1. On the Authentication pane of your Azure AD App, add a new platform of the mobile and desktop application type with the Redirect URI of `http://localhost`.
30 | 1. Open an instance of Windows Terminal, PowerShell, or an equivalent command line and navigate to the directory that you'd like to clone the sample to.
31 | 1. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
32 | 1. Navigate to the `manage-teams-identity-mobile-and-desktop` directory.
33 | 1. With the Communication Services procured in pre-requisites, add connection string, an Azure AD client ID and tenant ID to environment variable using below commands:
34 |
35 | ```console
36 | setx COMMUNICATION_SERVICES_CONNECTION_STRING
37 | setx AAD_CLIENT_ID
38 | setx AAD_TENANT_ID
39 | ```
40 |
41 | ## Run the code
42 |
43 | From a console prompt, navigate to the directory containing the `exchange-communication-access-tokens.py` file, then execute the following node commands to run the app.
44 |
45 | 1. `pip install azure-communication-identity` and `pip install msal` to install the dependencies
46 | 2. `python exchange-communication-access-tokens.py`
47 |
48 | You should be presented with a browser window and navigated to the Azure AD login form. If the authentication is successful, the application receives an Azure AD access token and exchanges it for a Communication access token.
49 |
--------------------------------------------------------------------------------
/send-email/README .md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-email
8 | ---
9 |
10 | # Email Sample
11 |
12 | ## Overview
13 |
14 | This is a sample email application to show how we can use the `azure-communication-email` package to build an email experience.
15 | This sample sends an email to the selected recipients of any domain using an [Email Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/email/create-email-communication-resource).
16 | This is a console application built using python 3.10.6.
17 |
18 | Additional documentation for this sample can be found on [Microsoft Docs](https://pypi.org/project/azure-communication-email).
19 |
20 | ## Prerequisites
21 |
22 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
23 | - [Python](https://www.python.org/downloads/) 3.7+.
24 | - An Azure Email Communication Services resource created and ready with a provisioned domain. [Get started with creating an Email Communication Resource](../create-email-communication-resource.md).
25 | - An active Azure Communication Services resource connected to an Email Domain and its connection string. [Get started by connecting an Email Communication Resource with a Azure Communication Resource](../connect-email-communication-resource.md).
26 |
27 | > Note: We can also send an email from our own verified domain [Add custom verified domains to Email Communication Service](https://docs.microsoft.com/azure/communication-services/quickstarts/email/add-custom-verified-domains).
28 |
29 | ### Prerequisite check
30 |
31 | - In a terminal or command window, run the `python --version` command to check that Python is installed.
32 | - To view the domains verified with your Email Communication Services resource, sign in to the [Azure portal](https://portal.azure.com/). Locate your Email Communication Services resource and open the **Provision domains** tab from the left navigation pane.
33 |
34 | ## Code Structure
35 |
36 | - **./send-email/send-email.py:** contains code for sending emails.
37 |
38 | ## Before running the sample for the first time
39 |
40 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent program and navigate to the directory that you'd like to clone the sample to.
41 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
42 |
43 | ## Create virtual environment
44 |
45 | Navigate to the `send-email` directory in the console. Create a virtual environment and activate it using the following commands.
46 |
47 | ```cmd
48 | python -m venv venv
49 | .\venv\Scripts\activate
50 | ```
51 |
52 | ## Install the packages
53 |
54 | Execute the following command to install the SDK.
55 |
56 | ```cmd
57 | pip install azure-communication-email
58 | ```
59 |
60 | ### Locally configuring the application
61 |
62 | Open the `send-email.py` file and configure the following settings:
63 |
64 | - `connection_string`: Replace `` with the connection string found within the 'Keys' blade of the Azure Communication Service resource.
65 | - `sender_address`: Replace `` with the sender email address obtained from the linked domain resource.
66 | - `recipient_address`: Replace `` with the recipient email address.
67 |
68 | ## Run Locally
69 |
70 | Execute the following command to run the app.
71 |
72 | ```cmd
73 | python ./send-email.py
74 | ```
75 |
76 | ## ❤️ Feedback
77 |
78 | We appreciate your feedback and energy in helping us improve our services. [Please let us know if you are satisfied with ACS through this survey](https://microsoft.qualtrics.com/jfe/form/SV_5dtYL81xwHnUVue).
79 |
--------------------------------------------------------------------------------
/callautomation-azure-openai-voice/readme.md:
--------------------------------------------------------------------------------
1 | |page_type| languages |products
2 | |---|-----------------------------------------|---|
3 | |sample|
Python
|
azure
azure-communication-services
|
4 |
5 | # Call Automation - Quick Start Sample
6 |
7 | This is a sample application demonstrated during Microsoft Ignite 2024. It highlights an integration of Azure Communication Services with Azure OpenAI Service to enable intelligent conversational agents.
8 |
9 | ## Prerequisites
10 |
11 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
12 | - A deployed Communication Services resource. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
13 | - A [phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number) in your Azure Communication Services resource that can get inbound calls. NB: phone numbers are not available in free subscriptions.
14 | - [Python](https://www.python.org/downloads/) 3.7 or above.
15 | - An Azure OpenAI Resource and Deployed Model. See [instructions](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource?pivots=web-portal).
16 |
17 | ## Before running the sample for the first time
18 |
19 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
20 | 2. git clone `https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
21 | 3. Navigate to `callautomation-azure-openai-voice` folder and open `main.py` file.
22 |
23 | ### Setup the Python environment
24 |
25 | Create and activate python virtual environment and install required packages using following command
26 | ```
27 | pip install -r requirements.txt
28 | ```
29 |
30 | ### Setup and host your Azure DevTunnel
31 |
32 | [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service.
33 |
34 | ```bash
35 | devtunnel create --allow-anonymous
36 | devtunnel port create -p 8000
37 | devtunnel host
38 | ```
39 |
40 | ### Configuring application
41 |
42 | Open `main.py` file to configure the following settings
43 |
44 | 1. `ACS_CONNECTION_STRING`: Azure Communication Service resource's connection string.
45 | 2. `CALLBACK_URI_HOST`: Base url of the app. (For local development use dev tunnel url)
46 |
47 | Open `azureOpenAIService.py` file to configure the following settings
48 |
49 | 1. `AZURE_OPENAI_SERVICE_ENDPOINT`: Azure Open AI service endpoint
50 | 2. `AZURE_OPENAI_SERVICE_KEY`: Azure Open AI service key
51 | 3. `AZURE_OPENAI_DEPLOYMENT_MODEL_NAME`: Azure Open AI deployment name
52 |
53 | ## Run app locally
54 |
55 | 1. Navigate to `callautomation-azure-openai-voice` folder and run `main.py` in debug mode or use command `python ./main.py` to run it from PowerShell, Command Prompt or Unix Terminal
56 | 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8000/`or your dev tunnel url.
57 | 3. Register an EventGrid Webhook for the IncomingCall(`https:///api/incomingCall`) event that points to your devtunnel URI. Instructions [here](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/incoming-call-notification).
58 |
59 | Once that's completed you should have a running application. The best way to test this is to place a call to your ACS phone number and talk to your intelligent agent.
60 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to [project-title]
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
6 |
7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | - [Code of Conduct](#coc)
16 | - [Issues and Bugs](#issue)
17 | - [Feature Requests](#feature)
18 | - [Submission Guidelines](#submit)
19 |
20 | ## Code of Conduct
21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
22 |
23 | ## Found an Issue?
24 | If you find a bug in the source code or a mistake in the documentation, you can help us by
25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
26 | [submit a Pull Request](#submit-pr) with a fix.
27 |
28 | ## Want a Feature?
29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
30 | Repository. If you would like to *implement* a new feature, please submit an issue with
31 | a proposal for your work first, to be sure that we can use it.
32 |
33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
34 |
35 | ## Submission Guidelines
36 |
37 | ### Submitting an Issue
38 | Before you submit an issue, search the archive, maybe your question was already answered.
39 |
40 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
41 | Help us to maximize the effort we can spend fixing issues and adding new
42 | features, by not reporting duplicate issues. Providing the following information will increase the
43 | chances of your issue being dealt with quickly:
44 |
45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
46 | * **Version** - what version is affected (e.g. 0.1.2)
47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
48 | * **Browsers and Operating System** - is this a problem with all browsers?
49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
50 | * **Related Issues** - has a similar issue been reported before?
51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
52 | causing the problem (line of code or commit)
53 |
54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new].
55 |
56 | ### Submitting a Pull Request (PR)
57 | Before you submit your Pull Request (PR) consider the following guidelines:
58 |
59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR
60 | that relates to your submission. You don't want to duplicate effort.
61 |
62 | * Make your changes in a new git fork:
63 |
64 | * Commit your changes using a descriptive commit message
65 | * Push your fork to GitHub:
66 | * In GitHub, create a pull request
67 | * If we suggest changes then:
68 | * Make the required updates.
69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
70 |
71 | ```shell
72 | git rebase master -i
73 | git push -f
74 | ```
75 |
76 | That's it! Thank you for your contribution!
77 |
--------------------------------------------------------------------------------
/send-email-advanced/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - Python
5 | products:
6 | - azure
7 | - azure-communication-email
8 | ---
9 |
10 | # Email Sample
11 |
12 | ## Overview
13 |
14 | This is a sample email application to show how we can use the `azure-communication-email` package to build an email experience.
15 | This sample sends an email to the selected recipients of any domain using an [Email Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/email/create-email-communication-resource).
16 | This is a console application built using python 3.10.6.
17 |
18 | Additional documentation for this sample can be found on [Microsoft Docs](https://docs.microsoft.com/azure/communication-services/concepts/email/email-overview).
19 |
20 | ## Prerequisites
21 |
22 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
23 | - [Python](https://www.python.org/downloads/) 3.7+.
24 | - An Azure Email Communication Services resource created and ready with a provisioned domain. [Get started with creating an Email Communication Resource](../create-email-communication-resource.md).
25 | - An active Azure Communication Services resource connected to an Email Domain and its connection string. [Get started by connecting an Email Communication Resource with a Azure Communication Resource](../connect-email-communication-resource.md).
26 |
27 | > Note: We can also send an email from our own verified domain [Add custom verified domains to Email Communication Service](https://docs.microsoft.com/azure/communication-services/quickstarts/email/add-custom-verified-domains).
28 |
29 | ### Prerequisite check
30 |
31 | - In a terminal or command window, run the `python --version` command to check that Python is installed.
32 | - To view the domains verified with your Email Communication Services resource, sign in to the [Azure portal](https://portal.azure.com/). Locate your Email Communication Services resource and open the **Provision domains** tab from the left navigation pane.
33 |
34 | ## Code structure
35 |
36 | The advanced version of send-email includes the following sub samples.
37 |
38 | ### Send email with attachments
39 |
40 | - ./send-email-advanced/send-email-attachments/send-email-attachments.py
41 |
42 | ### Send email with inline attachments
43 |
44 | - ./send-email-advanced/send-email-inline-attachments/send-email-inline.attachments.py
45 |
46 | ### Send email to multiple recipients
47 |
48 | - ./send-email-advanced/send-email-multiple-recipients/send-email-multiple-recipients.py
49 |
50 | ### Resume send email with continuation token
51 |
52 | - ./send-email-advanced/send-email-continuation-token/send-email-continuation-token.py
53 |
54 | ## Before running the sample for the first time
55 |
56 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent program and navigate to the directory that you'd like to clone the sample to.
57 | 2. `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
58 |
59 | ## Create virtual environment
60 |
61 | Navigate to the `send-email` directory in the console. Create a virtual environment and activate it using the following commands.
62 |
63 | ```cmd
64 | python -m venv venv
65 | .\venv\Scripts\activate
66 | ```
67 |
68 | ## Install the packages
69 |
70 | Execute the following command to install the SDK.
71 |
72 | ```cmd
73 | pip install azure-communication-email
74 | ```
75 |
76 | ### Locally configuring the application
77 |
78 | Open the corresponding py file of the sample to configure the following settings:
79 |
80 | - `connection_string`: Replace `` with the connection string found within the 'Keys' blade of the Azure Communication Service resource.
81 | - `sender_address`: Replace `` with the sender email address obtained from the linked domain resource.
82 | - `recipient_address`: Replace `` with the recipient email address.
83 |
84 | ## Run Locally
85 |
86 | Execute the following command to run the app.
87 |
88 | ```cmd
89 | python ./.py
90 | ```
91 |
92 | ## ❤️ Feedback
93 |
94 | We appreciate your feedback and energy in helping us improve our services. [Please let us know if you are satisfied with ACS through this survey](https://microsoft.qualtrics.com/jfe/form/SV_5dtYL81xwHnUVue).
95 |
--------------------------------------------------------------------------------
/add-chat/start-chat.py:
--------------------------------------------------------------------------------
1 | import os
2 | from azure.communication.chat import ChatClient, CommunicationTokenCredential
3 | from datetime import datetime, timedelta
4 | from azure.communication.chat import ChatMessageType
5 | from azure.communication.identity import CommunicationIdentityClient
6 | from azure.communication.chat import ChatParticipant
7 |
8 | try:
9 | print('Azure Communication Services - Chat Quickstart')
10 | # Create a chat client
11 | endpoint = "https://.communication.azure.com"
12 | chat_client = ChatClient(endpoint, CommunicationTokenCredential(""))
13 |
14 | # Start a chat thread
15 | topic="test topic"
16 |
17 | create_chat_thread_result = chat_client.create_chat_thread(topic)
18 | chat_thread_client = chat_client.get_chat_thread_client(create_chat_thread_result.chat_thread.id)
19 |
20 | # Get a chat thread client
21 | thread_id = create_chat_thread_result.chat_thread.id
22 | chat_thread_client = chat_client.get_chat_thread_client(thread_id)
23 |
24 | # List all chat threads
25 | start_time = datetime.utcnow() - timedelta(days=2)
26 |
27 | chat_threads = chat_client.list_chat_threads(results_per_page=5, start_time=start_time)
28 | for chat_thread_item_page in chat_threads.by_page():
29 | for chat_thread_item in chat_thread_item_page:
30 | print(chat_thread_item)
31 | print('Chat Thread Id: ', chat_thread_item.id)
32 |
33 |
34 | # Send a message to a chat thread
35 | content='hello world'
36 | sender_display_name='sender name'
37 |
38 | # specify chat message type with pre-built enumerations
39 | send_message_result_w_enum = chat_thread_client.send_message(content=content, sender_display_name=sender_display_name, chat_message_type=ChatMessageType.TEXT)
40 | print("Message sent: id: ", send_message_result_w_enum.id)
41 |
42 | # Receive chat messages from a chat thread
43 | start_time_receive = datetime.utcnow() - timedelta(days=1)
44 |
45 | chat_messages = chat_thread_client.list_messages(results_per_page=1, start_time=start_time_receive)
46 | for chat_message_page in chat_messages.by_page():
47 | for chat_message in chat_message_page:
48 | print("ChatMessage: Id=", chat_message.id, "; Content=", chat_message.content.message)
49 |
50 | # Send read receipt
51 | content='read receipt'
52 |
53 | send_message_result = chat_thread_client.send_message(content)
54 | chat_thread_client.send_read_receipt(message_id=send_message_result.id)
55 |
56 | # Add a user as a participant to the chat thread
57 | # create 2 users
58 | identity_client = CommunicationIdentityClient.from_connection_string('')
59 | new_users = [identity_client.create_user() for i in range(2)]
60 |
61 |
62 | # # conversely, you can also add an existing user to a chat thread; provided the user_id is known
63 | # from azure.communication.identity import CommunicationUserIdentifier
64 | #
65 | # user_id = 'some user id'
66 | # user_display_name = "Wilma Flinstone"
67 | # new_user = CommunicationUserIdentifier(user_id)
68 | # participant = ChatParticipant(
69 | # user=new_user,
70 | # display_name=user_display_name,
71 | # share_history_time=datetime.utcnow())
72 |
73 |
74 | participants = []
75 | for _user in new_users:
76 | chat_thread_participant = ChatParticipant(
77 | identifier=_user,
78 | display_name='Fred Flinstone',
79 | share_history_time=datetime.utcnow()
80 | )
81 | participants.append(chat_thread_participant)
82 |
83 | response = chat_thread_client.add_participants(participants)
84 |
85 | def decide_to_retry(error, **kwargs):
86 | """
87 | Insert some custom logic to decide if retry is applicable based on error
88 | """
89 | return True
90 |
91 | # verify if all users has been successfully added or not
92 | # in case of partial failures, you can retry to add all the failed participants
93 | retry = [p for p, e in response if decide_to_retry(e)]
94 | if retry:
95 | chat_thread_client.add_participants(retry)
96 |
97 | chat_thread_participants = chat_thread_client.list_participants()
98 | for chat_thread_participant_page in chat_thread_participants.by_page():
99 | for chat_thread_participant in chat_thread_participant_page:
100 | print("ChatParticipant: ", chat_thread_participant)
101 |
102 | except Exception as ex:
103 | print('Exception:')
104 | print(ex)
--------------------------------------------------------------------------------
/callautomation-openai-sample/readme.md:
--------------------------------------------------------------------------------
1 | |page_type| languages |products
2 | |---|-----------------------------------------|---|
3 | |sample|
Python
|
azure
azure-communication-services
|
4 |
5 | # Call Automation - Quick Start Sample
6 |
7 | This is a sample application demonstrated during Microsoft Build 2023. It highlights an integration of Azure Communication Services with Azure OpenAI Service to enable intelligent conversational agents.
8 |
9 | ## Prerequisites
10 |
11 | - Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
12 | - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource **connection string** for this sample.
13 | - An Calling-enabled telephone number. [Get a phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=platform-azp).
14 | - Azure Dev Tunnels CLI. For details, see [Enable dev tunnel](https://docs.tunnels.api.visualstudio.com/cli)
15 | - Create an Azure Cognitive Services resource. For details, see [Create an Azure Cognitive Services Resource](https://learn.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account)
16 | - An Azure OpenAI Resource and Deployed Model. See [instructions](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal).
17 | - Create and host a Azure Dev Tunnel. Instructions [here](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started)
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 |
20 | ## Before running the sample for the first time
21 |
22 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
23 | 2. git clone `https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
24 | 3. Navigate to `callautomation-openai-sample` folder and open `main.py` file.
25 |
26 | ### Setup the Python environment
27 |
28 | Create and activate python virtual environment and install required packages using following command
29 | ```
30 | pip install -r requirements.txt
31 | ```
32 |
33 | ### Setup and host your Azure DevTunnel
34 |
35 | [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service.
36 |
37 | ```bash
38 | devtunnel create --allow-anonymous
39 | devtunnel port create -p 8080
40 | devtunnel host
41 | ```
42 |
43 | ### Configuring application
44 |
45 | Open `main.py` file to configure the following settings
46 |
47 | 1. - `CALLBACK_URI_HOST`: your dev tunnel endpoint
48 | 2. - `COGNITIVE_SERVICE_ENDPOINT`: The Cognitive Services endpoint
49 | 3. - `ACS_CONNECTION_STRING`: Azure Communication Service resource's connection string.
50 | 4. - `AZURE_OPENAI_SERVICE_KEY`: Open AI's Service Key
51 | 5. - `AZURE_OPENAI_SERVICE_ENDPOINT`: Open AI's Service Endpoint
52 | 6. - `AZURE_OPENAI_DEPLOYMENT_MODEL_NAME`: Open AI's Model name
53 | 6. - `AGENT_PHONE_NUMBER`: Agent Phone Number to transfer call
54 |
55 | ## Run app locally
56 |
57 | 1. Navigate to `callautomation-openai-sample` folder and run `main.py` in debug mode or use command `python ./main.py` to run it from PowerShell, Command Prompt or Unix Terminal
58 | 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` or your dev tunnel url.
59 | 3. Register an EventGrid Webhook for the IncomingCall Event that points to your DevTunnel URI. Instructions [here](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/incoming-call-notification).
60 |
61 | Once that's completed you should have a running application. The best way to test this is to place a call to your ACS phone number and talk to your intelligent agent.
62 |
--------------------------------------------------------------------------------
/callautomation-live-transcription/readme.md:
--------------------------------------------------------------------------------
1 | |page_type| languages |products
2 | |---|-----------------------------------------|---|
3 | |sample|
Python
|
azure
azure-communication-services
|
4 |
5 | # Call Automation - Quick Start Sample
6 |
7 | This sample application shows how the Azure Communication Services - Call Automation SDK can be used generate the live transcription between PSTN calls.
8 | It accepts an incoming call from a phone number, performs DTMF recognition, and transfer the call to agent. You can see the live transcription in websocket during the conversation between agent and user
9 | This sample application is also capable of making multiple concurrent inbound calls. The application is a web-based application built on Python.
10 |
11 | ## Prerequisites
12 |
13 | - Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
14 | - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource **connection string** for this sample.
15 | - An Calling-enabled telephone number. [Get a phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=platform-azp).
16 | - Create Azure AI Multi Service resource. For details, see [Create an Azure AI Multi service](https://learn.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account).
17 | - An Azure OpenAI Resource and Deployed Model. See [instructions](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal).
18 | - [Python](https://www.python.org/downloads/) 3.7 or above.
19 |
20 | ## Before running the sample for the first time
21 |
22 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
23 | 2. git clone `https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
24 | 3. Navigate to `callautomation-openai-sample` folder and open `main.py` file.
25 |
26 | ### Setup the Python environment
27 |
28 | [Optional] Create and activate python virtual environment and install required packages using following command
29 | ```
30 | python -m venv venv
31 | venv\Scripts\activate
32 | ```
33 | Install the required packages using the following command
34 | ```
35 | pip install -r requirements.txt
36 | ```
37 |
38 | ### Setup and host your Azure DevTunnel
39 |
40 | [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service.
41 |
42 | ```bash
43 | devtunnel create --allow-anonymous
44 | devtunnel port create -p 8080
45 | devtunnel host
46 | ```
47 |
48 | ### Configuring application
49 |
50 | Open `main.py` file to configure the following settings
51 |
52 | 1. - `CALLBACK_URI_HOST`: Ngrok url for the server port (in this example port 8080)
53 | 2. - `COGNITIVE_SERVICE_ENDPOINT`: The Cognitive Services endpoint
54 | 3. - `ACS_CONNECTION_STRING`: Azure Communication Service resource's connection string.
55 | 4. - `ACS_PHONE_NUMBER`: Acs Phone Number
56 | 5. - `LOCALE`: Transcription locale
57 | 6. - `AGENT_PHONE_NUMBER`: Agent Phone Number to add into the call
58 |
59 | ## Run app locally
60 |
61 | 1. Navigate to `callautomation-live-transcription` folder and run `main.py` in debug mode or use command `python ./main.py` to run it from PowerShell, Command Prompt or Unix Terminal
62 | 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` or your ngrok url which points to 8080 port.
63 | 4. Register an EventGrid Webhook for the IncomingCall(`https:///api/incomingCall`) and for Recording File Status(`https:///api/recordingFileStatus`) Event that points to your devtunnel URI. Instructions [here](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/incoming-call-notification).
64 |
65 | Once that's completed you should have a running application. The best way to test this is to place a call to your ACS phone number and talk to your intelligent agent.
66 |
--------------------------------------------------------------------------------
/callautomation-connect-room/readme.md:
--------------------------------------------------------------------------------
1 | |page_type| languages |products
2 | |---|-----------------------------------------|---|
3 | |sample|
Python
|
azure
azure-communication-services
|
4 |
5 | # Connect to a room call using Call Automation SDK
6 |
7 | In this quickstart sample, we cover how you can use Call Automation SDK to connect to an active Azure Communication Services (ACS) Rooms call with a connect endpoint.
8 | This involves creating a room call with room id and users and enabling PSTN dial out to add PSTN participant(s).
9 |
10 | ## Prerequisites
11 |
12 | - Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
13 | - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource **connection string** for this sample.
14 | - An Calling-enabled telephone number. [Get a phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=platform-azp).
15 | - Create Azure AI Multi Service resource. For details, see [Create an Azure AI Multi service](https://learn.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account).
16 | - [Python](https://www.python.org/downloads/) 3.7 or above.
17 |
18 | ## Before running the sample for the first time
19 |
20 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
21 | 2. git clone `https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
22 | 3. Navigate to `callautomation-connect-room` folder and open `main.py` file.
23 |
24 | ## Before running calling rooms quickstart
25 | 1. To initiate rooms call with room id https://github.com/Azure-Samples/communication-services-javascript-quickstarts/tree/main/calling-rooms-quickstart
26 | 2. cd into the `calling-rooms-quickstart` folder.
27 | 3. From the root of the above folder, and with node installed, run `npm install`
28 | 4. to run sample `npx webpack serve --config webpack.config.js`
29 |
30 | ### Setup the Python environment
31 |
32 | [Optional] Create and activate python virtual environment and install required packages using following command
33 | ```
34 | python -m venv venv
35 | venv\Scripts\activate
36 | ```
37 | Install the required packages using the following command
38 | ```
39 | pip install -r requirements.txt
40 | ```
41 |
42 | ### Setup and host your Azure DevTunnel
43 |
44 | [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service.
45 |
46 | ```bash
47 | devtunnel create --allow-anonymous
48 | devtunnel port create -p 8080
49 | devtunnel host
50 | ```
51 |
52 | ### Configuring application
53 |
54 | Open `config.py` file to configure the following settings
55 |
56 | 1. - `CALLBACK_URI`: Ngrok url for the server port (in this example port 8080)
57 | 2. - `CONNECTION_STRING`: Azure Communication Service resource's connection string.
58 | 3. - `ACS_RESOURCE_PHONE_NUMBER`: Acs Phone Number
59 | 4. - `TARGET_PHONE_NUMBER`: Agent Phone Number to add into the call
60 | 5. - `COGNITIVE_SERVICES_ENDPOINT`: Cognitive service endpoint.
61 |
62 | ## Run app locally
63 |
64 | 1. Navigate to `callautomation-connect-room` folder and run `main.py` in debug mode or use command `python ./main.py` to run it from PowerShell, Command Prompt or Unix Terminal
65 | 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` or your ngrok url which points to 8080 port.
66 | 3. To connect rooms call, click on the `Connect a call!` button or make a Http get request to https:///connectCall
67 |
68 | ### Creating and connecting to room call.
69 |
70 | 1. Navigate to `http://localhost:8080/` or devtunnel url to create users and room id 
71 | 2. Open two tabs for Presenter and attendee 
72 | 3. Copy tokens for presenter and attendee from 
73 | 4. Initialize call agent with tokens for both presenter and attendee.
74 | 5. Take room id  and initiate rooms call for both users. 
75 | 6. Connect room call with callautomation connect call endpoint. 
76 |
77 |
--------------------------------------------------------------------------------
/chat-insights-openai/chatInsights.py:
--------------------------------------------------------------------------------
1 | from azure.communication.chat import ChatClient, CommunicationTokenCredential, ChatMessageType,ChatParticipant
2 | from azure.communication.identity import CommunicationIdentityClient, CommunicationUserIdentifier
3 | from datetime import datetime
4 |
5 | connection_string = "INSERT AZURE COMMUNICATION SERVICES CONNECTION STRING"
6 | endpoint = "INSERT AZURE COMMUNICATION SERVICES ENDPOINT"
7 | client = CommunicationIdentityClient.from_connection_string(connection_string)
8 | identity1 = client.create_user()
9 | token_result1 = client.get_token(identity1, ["chat"])
10 | identity2 = client.create_user()
11 | token_result2 = client.get_token(identity2, ["chat"])
12 |
13 | Agent = ChatParticipant(identifier=identity1, display_name="Agent", share_history_time=datetime.utcnow())
14 | Customer = ChatParticipant(identifier=identity2, display_name="Customer", share_history_time=datetime.utcnow())
15 | participants = [Agent, Customer ]
16 |
17 | chat_client1 = ChatClient(endpoint, CommunicationTokenCredential(token_result1.token))
18 | chat_client2 = ChatClient(endpoint, CommunicationTokenCredential(token_result2.token))
19 | topic="Support conversation"
20 | create_chat_thread_result = chat_client1.create_chat_thread(topic, thread_participants=participants)
21 | chat_thread_client1 = chat_client1.get_chat_thread_client(create_chat_thread_result.chat_thread.id)
22 | chat_thread_client2 = chat_client2.get_chat_thread_client(create_chat_thread_result.chat_thread.id)
23 |
24 | agentText = [
25 | "Thank you for calling our customer service hotline. How may I assist you today?",
26 | "I'm sorry to hear that. Can you provide me with your name and account number, so I can look up your account and assist you better?",
27 | "Thank you. Can you please tell me a little more about the problem you're having with your dishwasher?",
28 | "I see. That can be frustrating. Can you please check if the dishwasher is getting enough water supply? Also, please check if the spray arms inside the dishwasher are properly attached and not clogged.",
29 | "Alright. Please check the spray arms and see if they're clogged or damaged in any way. Also, make sure they're attached properly.",
30 | "That could be the reason why the dishes aren't getting cleaned properly. Can you please try to reattach the spray arm and run the dishwasher again?",
31 | "Great to hear that! Is there anything else I can help you with?",
32 | "You're welcome. Don't hesitate to call us back if you have any more issues. Have a nice day!"
33 | ]
34 |
35 | customerText = [
36 | "Hi, I'm having trouble with my dishwasher. It doesn't seem to be cleaning the dishes properly.",
37 | "Yes, my name is Lisa and my account number is 12345.",
38 | "Well, it seems like the dishwasher isn't spraying enough water to clean the dishes properly. Some of the dishes are coming out dirty even after I run the dishwasher.",
39 | "I've checked the water supply and it seems to be okay. But I haven't checked the spray arms yet.",
40 | "Okay, let me check. Yes, it seems like one of the spray arms is loose and not attached properly.",
41 | "Sure, let me try that. Okay, I reattached the spray arm and ran the dishwasher again. It seems to be working fine now. The dishes are coming out clean.",
42 | "No, that's all. Thank you for your help.",
43 | "Bye."
44 | ]
45 |
46 | for x in range(len(agentText)):
47 | chat_thread_client1.send_message(content= agentText[x], sender_display_name="Agent", chat_message_type=ChatMessageType.TEXT)
48 | chat_thread_client2.send_message(content= customerText[x], sender_display_name="Customer", chat_message_type=ChatMessageType.TEXT)
49 |
50 | from datetime import datetime, timedelta
51 |
52 | start_time = datetime.utcnow() - timedelta(days=1)
53 | messages = []
54 |
55 | chat_messages = chat_thread_client1.list_messages(results_per_page=1, start_time=start_time)
56 | for chat_message_page in chat_messages.by_page():
57 | for chat_message in chat_message_page:
58 | if(chat_message.type == ChatMessageType.TEXT):
59 | messages.append(chat_message)
60 |
61 | # didn't know I had to filter out other messages
62 |
63 | prompt = ""
64 | for m in range(len(messages)-1, -1, -1):
65 | prompt = prompt + messages[m].sender_display_name + ": " + messages[m].content.message + "\n"
66 | print(prompt)
67 |
68 | import os
69 | import requests
70 | import json
71 | import openai
72 |
73 | openai.api_key = "INSERT YOUR AZURE OPENAI API KEY"
74 | openai.api_base = "INSERT YOUR AZURE OPENAI ENDPOINT" # your endpoint should look like the following https://YOUR_RESOURCE_NAME.openai.azure.com/
75 | openai.api_type = 'azure'
76 | openai.api_version = '2022-12-01' # this may change in the future
77 | deployment_name='INSERT YOUR DEPLOyMENT NAME' #This will correspond to the custom name you chose for your deployment when you deployed a model.
78 |
79 | # Send a completion call to generate an answer
80 | start_phrase = 'For the following conversation, extract a topic, summary, highlights (1-3 bullet points of key information) and the sentiment of both of the users.\n\n' + prompt
81 | response = openai.Completion.create(engine=deployment_name, prompt=start_phrase, max_tokens=500)
82 | text = response['choices'][0]['text'].replace('\n', '').replace(' .', '.').strip()
83 | print(start_phrase + '\n' + text)
84 |
85 |
--------------------------------------------------------------------------------
/callautomation-outboundcalling/readme.md:
--------------------------------------------------------------------------------
1 | |page_type| languages |products
2 | |---|-----------------------------------------|---|
3 | |sample|
Python
|
azure
azure-communication-services
|
4 |
5 | # Call Automation - Quick Start Sample
6 |
7 | In this quickstart, we cover how you can use Call Automation SDK to make an outbound call to a phone number and use the newly announced integration with Azure AI services to play dynamic prompts to participants using Text-to-Speech and recognize user voice input through Speech-to-Text to drive business logic in your application.
8 |
9 | # Design
10 |
11 | 
12 |
13 | ## Prerequisites
14 |
15 | - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
16 | - A deployed Communication Services resource. [Create a Communication Services resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource).
17 | - A [phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number) in your Azure Communication Services resource that can make outbound calls. NB: phone numbers are not available in free subscriptions.
18 | - Create Azure AI Multi Service resource. For details, see [Create an Azure AI Multi service](https://learn.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account).
19 | - Create and host a Azure Dev Tunnel. Instructions [here](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started)
20 | - [Python](https://www.python.org/downloads/) 3.7 or above.
21 | - (Optional) A Microsoft Teams user with a phone license that is `voice` enabled. Teams phone license is required to add Teams users to the call. Learn more about Teams licenses [here](https://www.microsoft.com/microsoft-teams/compare-microsoft-teams-bundle-options). Learn about enabling phone system with `voice` [here](https://learn.microsoft.com/microsoftteams/setting-up-your-phone-system). You also need to complete the prerequisite step [Authorization for your Azure Communication Services Resource](https://learn.microsoft.com/azure/communication-services/how-tos/call-automation/teams-interop-call-automation?pivots=programming-language-javascript#step-1-authorization-for-your-azure-communication-services-resource-to-enable-calling-to-microsoft-teams-users) to enable calling to Microsoft Teams users.
22 |
23 | ## Before running the sample for the first time
24 |
25 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
26 | 2. git clone `https://github.com/Azure-Samples/communication-services-python-quickstarts.git`.
27 | 3. Navigate to `callautomation-outboundcalling` folder and open `main.py` file.
28 |
29 | ### Setup the Python environment
30 |
31 | Create and activate python virtual environment and install required packages using following command
32 | ```
33 | pip install -r requirements.txt
34 | ```
35 |
36 | ### Setup and host your Azure DevTunnel
37 |
38 | [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service.
39 |
40 | ```bash
41 | devtunnel create --allow-anonymous
42 | devtunnel port create -p 8080
43 | devtunnel host
44 | ```
45 |
46 | ### Configuring application
47 |
48 | Open `main.py` file to configure the following settings
49 |
50 | 1. `ACS_CONNECTION_STRING`: Azure Communication Service resource's connection string.
51 | 2. `ACS_PHONE_NUMBER`: Phone number associated with the Azure Communication Service resource. For e.g. "+1425XXXAAAA"
52 | 3. `TARGET_PHONE_NUMBER`: Target phone number to add in the call. For e.g. "+1425XXXAAAA"
53 | 4. `CALLBACK_URI_HOST`: Base url of the app. (For local development use dev tunnel url)
54 | 5. `COGNITIVE_SERVICES_ENDPOINT`: Cognitive Service Endpoint
55 | 6. `TARGET_TEAMS_USER_ID`: (Optional) update field with the Microsoft Teams user Id you would like to add to the call. See [Use Graph API to get Teams user Id](https://learn.microsoft.com/azure/communication-services/how-tos/call-automation/teams-interop-call-automation?pivots=programming-language-python#step-2-use-the-graph-api-to-get-microsoft-entra-object-id-for-teams-users-and-optionally-check-their-presence). Uncomment the below snippet in main.py to enable Teams Interop scenario.
56 |
57 | ```python
58 | call_connection_client.add_participant(target_participant = CallInvite(
59 | target = MicrosoftTeamsUserIdentifier(user_id=TARGET_TEAMS_USER_ID),
60 | source_display_name = "Jack (Contoso Tech Support)"))
61 | ```
62 |
63 | ## Run app locally
64 |
65 | 1. Navigate to `callautomation-outboundcalling` folder and run `main.py` in debug mode or use command `python ./main.py` to run it from PowerShell, Command Prompt or Unix Terminal
66 | 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` or your dev tunnel url.
67 | 3. To initiate the call, click on the `Place a call!` button or make a Http get request to `https:///outboundCall`
68 |
--------------------------------------------------------------------------------
/rooms-quickstart/rooms.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, timezone, timedelta
2 | from azure.core.exceptions import HttpResponseError
3 | from azure.communication.rooms import (
4 | RoomsClient,
5 | RoomParticipant,
6 | ParticipantRole
7 | )
8 | from azure.communication.identity import (
9 | CommunicationIdentityClient,
10 | CommunicationUserIdentifier
11 | )
12 | class RoomsQuickstart(object):
13 | roomsCollection = []
14 | connection_string = ''
15 | identity_client = CommunicationIdentityClient.from_connection_string(connection_string)
16 | user1 = identity_client.create_user()
17 | user2 = identity_client.create_user()
18 | user3 = identity_client.create_user()
19 | user4 = identity_client.create_user()
20 | user5 = identity_client.create_user()
21 |
22 | def setup(self):
23 | self.rooms_client = RoomsClient.from_connection_string(self.connection_string)
24 |
25 | def teardown(self):
26 | self.delete_all_rooms()
27 |
28 | def create_room(self):
29 | try:
30 | valid_from = datetime.now(timezone.utc)
31 | valid_until = valid_from + timedelta(weeks=7)
32 | participants = []
33 | participant_1 = RoomParticipant(communication_identifier=self.user1, role=ParticipantRole.PRESENTER)
34 | participant_2 = RoomParticipant(communication_identifier=self.user2, role=ParticipantRole.CONSUMER)
35 | participant_3 = RoomParticipant(communication_identifier=self.user3, role=ParticipantRole.ATTENDEE)
36 | participants = [participant_1, participant_2, participant_3]
37 | pstn_dial_out_enabled=False
38 | created_room = self.rooms_client.create_room(
39 | valid_from=valid_from,
40 | valid_until=valid_until,
41 | participants=participants,
42 | pstn_dial_out_enabled=pstn_dial_out_enabled
43 | )
44 | print('\nRoom created.')
45 | self.print_room(created_room)
46 | self.roomsCollection.append(created_room.id)
47 | except Exception as ex:
48 | print('Room creation failed.', ex)
49 |
50 | def update_room(self, room_id:str):
51 | valid_from = datetime.now(timezone.utc)
52 | valid_until = valid_from + timedelta(weeks=1)
53 | pstn_dial_out_enabled = True
54 | try:
55 | updated_room = self.rooms_client.update_room(room_id=room_id, valid_from=valid_from, valid_until=valid_until,pstn_dial_out_enabled=pstn_dial_out_enabled)
56 | print('\nRoom updated with new valid_from and valid_until time.')
57 | self.print_room(updated_room)
58 | except HttpResponseError as ex:
59 | print(ex)
60 |
61 | def get_room(self, room_id:str):
62 | try:
63 | get_room = self.rooms_client.get_room(room_id=room_id)
64 | self.print_room(get_room)
65 | except HttpResponseError as ex:
66 | print(ex)
67 |
68 | def add_or_update_participants(self, room_id:str, participants_list:list):
69 | try:
70 | participants = []
71 | for p in participants_list:
72 | participants.append(RoomParticipant(communication_identifier=CommunicationUserIdentifier(p), role=ParticipantRole.ATTENDEE))
73 | self.rooms_client.add_or_update_participants(room_id=room_id, participants=participants)
74 | print('\nRoom participants added or updated.')
75 | except HttpResponseError as ex:
76 | print(ex)
77 |
78 | def list_all_rooms(self):
79 | rooms = self.rooms_client.list_rooms()
80 | print('\nList all active rooms')
81 | print('\nPrinting the first two rooms in list')
82 | count = 0
83 | for room in rooms:
84 | if count == 2:
85 | break
86 | print(
87 | "\nRoom Id: " + room.id +
88 | "\nCreated date time: " + str(room.created_at) +
89 | "\nValid From: " + str(room.valid_from) + "\nValid Until: " + str(room.valid_until)+
90 | "\nPstn dial out enabled: " + str(room.pstn_dial_out_enabled ))
91 | count += 1
92 |
93 | def delete_all_rooms(self):
94 | for room_id in self.roomsCollection:
95 | print("\nDeleting room : ", room_id)
96 | self.rooms_client.delete_room(room_id)
97 |
98 | def print_room(self, room):
99 | print("\nRoom Id: " + room.id +
100 | "\nCreated date time: " + str(room.created_at) +
101 | "\nValid From: " + str(room.valid_from) + "\nValid Until: " + str(room.valid_until) + "\nPstn dial out enabled: " + str(room.pstn_dial_out_enabled ))
102 |
103 | def get_participants_in_room(self, room_id:str):
104 | participants = self.rooms_client.list_participants(room_id)
105 | print('\nParticipants in Room Id :', room_id)
106 | for p in participants:
107 | print(p.communication_identifier.properties['id'], p.role)
108 |
109 | def remove_participants_from_room(self, room_id:str, participants_list:list):
110 | try:
111 | participants = []
112 | for p in participants_list:
113 | participants.append(CommunicationUserIdentifier(p))
114 | self.rooms_client.remove_participants(room_id=room_id, participants=participants)
115 | print('\n(' + str(len(participants)) + ') participants removed from the room : ' + str(room_id))
116 | except Exception as ex:
117 | print(ex)
118 |
119 | if __name__ == '__main__':
120 | print('==== Started : Rooms API Operations - Python Quickstart Sample ====')
121 | rooms = RoomsQuickstart()
122 | rooms.setup()
123 | rooms.create_room()
124 | rooms.update_room(room_id=rooms.roomsCollection[0])
125 | rooms.get_room(room_id=rooms.roomsCollection[0])
126 | rooms.add_or_update_participants(room_id=rooms.roomsCollection[0], participants_list=[rooms.user4.raw_id, rooms.user5.raw_id])
127 | rooms.list_all_rooms()
128 | rooms.get_participants_in_room(room_id=rooms.roomsCollection[0])
129 | rooms.remove_participants_from_room(room_id=rooms.roomsCollection[0], participants_list=[rooms.user4.raw_id, rooms.user5.raw_id])
130 | rooms.get_participants_in_room(room_id=rooms.roomsCollection[0])
131 | rooms.teardown()
132 |
133 | print('==== Completed : Rooms API Operations - Python Quickstart Sample ====')
--------------------------------------------------------------------------------
/call-recording/Readme.mD:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - python
5 | products:
6 | - azure
7 | - azure-communication-callautomation
8 | ---
9 |
10 | # Call Recording APIs Sample
11 | This is a sample application to showcase how the Call Automation SDK can be used to add recording features to any application.
12 | The application is a console based application build using Python 3.9 and above.
13 | It harnesses the power of Azure Communication Services to establish connections and enable communication features within the application. A separate branch with end to end implementation is [available](https://github.com/Azure-Samples/communication-services-web-calling-hero/tree/public-preview). It's a public preview branch and uses beta SDKs that are not meant for production use. Please use the main branch sample for any production scenarios.
14 |
15 | ## Getting started
16 |
17 | ### Prerequisites
18 |
19 | - Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
20 | - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource **connection string** for this sample.
21 | - Get a phone number for your new Azure Communication Services resource. For details, see [Get a phone number](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/get-phone-number?pivots=platform-azp)
22 | - Download and install [VS Code](https://code.visualstudio.com/download) or [Visual Studio (2022 v17.4.0 and above)](https://visualstudio.microsoft.com/vs/)
23 | -[Python311](https://www.python.org/downloads/) (Make sure to install version that corresponds with your visual studio instance, 32 vs 64 bit)
24 | - Download and install [Ngrok](https://www.ngrok.com/download). As the sample is run locally, Ngrok will enable the receiving of all the events.
25 | - Generate Ngrok Url by using below steps.
26 | - Open command prompt or powershell window.
27 | - Navigate to the directory, where Ngrok.exe file is located. Then, run:
28 | - ngrok http {portNumber}(For e.g. ngrok http 58963)
29 | - Get Ngrok Url generated. Ngrok Url will be in the form of e.g. "https://95b6-43-230-212-228.ngrok-free.app"
30 | - Create a webhook and subscribe to the recording events. For details, see [Create webhook](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/download-recording-file-sample)
31 | - **Note:** Phone number is required to successfully run this sample.
32 |
33 | ## Clone the code local and update configuration
34 |
35 | 1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you'd like to clone the sample to.
36 | 2. Run `git clone https://github.com/Azure-Samples/communication-services-python-quickstarts.git`
37 | 3. Once you get the code on local machine, navigate to **call-recording/config.ini** file found under the call-recording folder.
38 | 4. Update the values for below.
39 |
40 | | Key | Value | Description |
41 | | -------- | -------- | -------- |
42 | | `ACSResourceConnectionString` | \ | Input your ACS connection string in the variable |
43 | | `ACSAcquiredPhoneNumber` | \ | Phone number associated with the Azure Communication Service resource |
44 | | `CallbackUri` | \ | Base url of the app, don't add `/` at end. generate ngrok url as mentioned above. |
45 |
46 |
47 | ## Code structure
48 |
49 | - *./call-recording/Controller/RecordingsController.py* : Server app core logic for calling the recording APIs using Azure Communication Services callautomation SDK
50 | - *./call-recording/App.py* : Entry point for the server app program logic
51 | - *./call-recording/requirements.txt* : Contains dependencies for running and deploying the application
52 |
53 | ### Setup the Python environment
54 |
55 | Create and activate python virtual environment and install required packages using following command in `call-recording` folder.
56 | ```
57 | pip install -r requirements.txt
58 | ```
59 |
60 | ## Run app locally
61 |
62 | 1. Navigate to `call-recording` folder and run `App.py` in debug mode or use command `python ./App.py` to run it from PowerShell, Command Prompt or Unix Terminal
63 | 2. Import `call-recording\data\Recordings API.postman_collection.json` file into postman, you get `Recordings API` collection. For details, see [Importing and exporting data](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/)
64 | 3. Select `Recordings API`, under Variables, update `HOST_URL` and `TARGET_PHONE_NUMBER` before making calls.
65 |
66 | # Step by step guid for testing recording APIs via postman.
67 |
68 | Once App is running locally,
69 | 1. Create webhook (Follow "Create Webhook for Microsoft.Communication.RecordingFileStatus event" section below )
70 | 2. Start a call by invoking Qutbound Call request.
71 | - Accept the call on Target PSTN Phone number, Keep call running.
72 | 5. Send Request to StartRecording.
73 | - Recording would be started.
74 | 6. (Optional) PauseRecording, ResumeRecording and GetRecordingState.
75 | 7. Send Request for StopRecording.
76 | 8. Send Request for DownloadRecording from server, only last recorded file will be downloaded.
77 | 9. Send Request for DeleteRecording at server.
78 |
79 | ## Create Webhook for Microsoft.Communication.RecordingFileStatus event
80 | Call Recording enables you to record multiple calling scenarios available in Azure Communication Services by providing you with a set of APIs to start, stop, pause and resume recording. To learn more about it, see [this guide](https://learn.microsoft.com/en-us/azure/communication-services/concepts/voice-video-calling/call-recording).
81 | 1. Navigate to your Communication Service resource on Azure portal and select `Events` from the left side blade.
82 | 2. Click `+ Event Subscription` to create a new subscription, provide `Name` field value.
83 | 3. Under Topic details, choose a System Topic or create new, no changes required if its already have topic name.
84 | 4. Under `Event Types` Filter for `Recording File Status Updated(Preview)` event.
85 | 5. Choose `Endpoint Type` as `Web Hook` and provide the public url generated by Ngrok. It would look like `https://2c0a-49-207-209-111.ngrok-free.app/recordingFileStatus`.
86 | 6. Click `Create` to complete the event grid subscription. The subscription is ready when the provisioning status is marked as succeeded.
87 | **Note:** Application should be running to able to create the `Web Hook` successfully.
88 |
--------------------------------------------------------------------------------
/callautomation-azure-openai-voice/main.py:
--------------------------------------------------------------------------------
1 | from quart import Quart, Response, request, json, websocket
2 | from azure.eventgrid import EventGridEvent, SystemEventNames
3 | from urllib.parse import urlencode, urlparse, urlunparse
4 | from logging import INFO
5 | from azure.communication.callautomation import (
6 | MediaStreamingOptions,
7 | AudioFormat,
8 | MediaStreamingContentType,
9 | MediaStreamingAudioChannelType,
10 | StreamingTransportType
11 | )
12 | from azure.communication.callautomation.aio import (
13 | CallAutomationClient
14 | )
15 | import uuid
16 |
17 | from azureOpenAIService import OpenAIRTHandler
18 |
19 | # Your ACS resource connection string
20 | ACS_CONNECTION_STRING = "ACS_CONNECTION_STRING"
21 |
22 | # Callback events URI to handle callback events.
23 | CALLBACK_URI_HOST = "CALLBACK_URI_HOST"
24 | CALLBACK_EVENTS_URI = CALLBACK_URI_HOST + "/api/callbacks"
25 |
26 | acs_client = CallAutomationClient.from_connection_string(ACS_CONNECTION_STRING)
27 | app = Quart(__name__)
28 |
29 | @app.route("/api/incomingCall", methods=['POST'])
30 | async def incoming_call_handler():
31 | app.logger.info("incoming event data")
32 | for event_dict in await request.json:
33 | event = EventGridEvent.from_dict(event_dict)
34 | app.logger.info("incoming event data --> %s", event.data)
35 | if event.event_type == SystemEventNames.EventGridSubscriptionValidationEventName:
36 | app.logger.info("Validating subscription")
37 | validation_code = event.data['validationCode']
38 | validation_response = {'validationResponse': validation_code}
39 | return Response(response=json.dumps(validation_response), status=200)
40 | elif event.event_type =="Microsoft.Communication.IncomingCall":
41 | app.logger.info("Incoming call received: data=%s",
42 | event.data)
43 | if event.data['from']['kind'] =="phoneNumber":
44 | caller_id = event.data['from']["phoneNumber"]["value"]
45 | else :
46 | caller_id = event.data['from']['rawId']
47 | app.logger.info("incoming call handler caller id: %s",
48 | caller_id)
49 | incoming_call_context=event.data['incomingCallContext']
50 | guid =uuid.uuid4()
51 | query_parameters = urlencode({"callerId": caller_id})
52 | callback_uri = f"{CALLBACK_EVENTS_URI}/{guid}?{query_parameters}"
53 |
54 | parsed_url = urlparse(CALLBACK_EVENTS_URI)
55 | websocket_url = urlunparse(('wss',parsed_url.netloc,'/ws','', '', ''))
56 |
57 | app.logger.info("callback url: %s", callback_uri)
58 | app.logger.info("websocket url: %s", websocket_url)
59 |
60 | media_streaming_options = MediaStreamingOptions(
61 | transport_url=websocket_url,
62 | transport_type=StreamingTransportType.WEBSOCKET,
63 | content_type=MediaStreamingContentType.AUDIO,
64 | audio_channel_type=MediaStreamingAudioChannelType.MIXED,
65 | start_media_streaming=True,
66 | enable_bidirectional=True,
67 | audio_format=AudioFormat.PCM24_K_MONO)
68 |
69 | answer_call_result = await acs_client.answer_call(incoming_call_context=incoming_call_context,
70 | operation_context="incomingCall",
71 | callback_url=callback_uri,
72 | media_streaming=media_streaming_options)
73 | app.logger.info("Answered call for connection id: %s",
74 | answer_call_result.call_connection_id)
75 | return Response(status=200)
76 |
77 | @app.route('/api/callbacks/', methods=['POST'])
78 | async def callbacks(contextId):
79 | for event in await request.json:
80 | # Parsing callback events
81 | global call_connection_id
82 | event_data = event['data']
83 | call_connection_id = event_data["callConnectionId"]
84 | app.logger.info(f"Received Event:-> {event['type']}, Correlation Id:-> {event_data['correlationId']}, CallConnectionId:-> {call_connection_id}")
85 | if event['type'] == "Microsoft.Communication.CallConnected":
86 | call_connection_properties = await acs_client.get_call_connection(call_connection_id).get_call_properties()
87 | media_streaming_subscription = call_connection_properties.media_streaming_subscription
88 | app.logger.info(f"MediaStreamingSubscription:--> {media_streaming_subscription}")
89 | app.logger.info(f"Received CallConnected event for connection id: {call_connection_id}")
90 | app.logger.info("CORRELATION ID:--> %s", event_data["correlationId"])
91 | app.logger.info("CALL CONNECTION ID:--> %s", event_data["callConnectionId"])
92 | elif event['type'] == "Microsoft.Communication.MediaStreamingStarted":
93 | app.logger.info(f"Media streaming content type:--> {event_data['mediaStreamingUpdate']['contentType']}")
94 | app.logger.info(f"Media streaming status:--> {event_data['mediaStreamingUpdate']['mediaStreamingStatus']}")
95 | app.logger.info(f"Media streaming status details:--> {event_data['mediaStreamingUpdate']['mediaStreamingStatusDetails']}")
96 | elif event['type'] == "Microsoft.Communication.MediaStreamingStopped":
97 | app.logger.info(f"Media streaming content type:--> {event_data['mediaStreamingUpdate']['contentType']}")
98 | app.logger.info(f"Media streaming status:--> {event_data['mediaStreamingUpdate']['mediaStreamingStatus']}")
99 | app.logger.info(f"Media streaming status details:--> {event_data['mediaStreamingUpdate']['mediaStreamingStatusDetails']}")
100 | elif event['type'] == "Microsoft.Communication.MediaStreamingFailed":
101 | app.logger.info(f"Code:->{event_data['resultInformation']['code']}, Subcode:-> {event_data['resultInformation']['subCode']}")
102 | app.logger.info(f"Message:->{event_data['resultInformation']['message']}")
103 | elif event['type'] == "Microsoft.Communication.CallDisconnected":
104 | pass
105 | return Response(status=200)
106 |
107 | # WebSocket.
108 | @app.websocket('/ws')
109 | async def ws():
110 | handler = OpenAIRTHandler()
111 | print("Client connected to WebSocket")
112 | await handler.init_incoming_websocket(websocket)
113 | await handler.start_client()
114 | while websocket:
115 | try:
116 | # Receive data from the client
117 | data = await websocket.receive()
118 | await handler.acs_to_oai(data)
119 | await handler.send_welcome()
120 | except Exception as e:
121 | print(f"WebSocket connection closed: {e}")
122 | break
123 |
124 | @app.route('/')
125 | def home():
126 | return 'Hello ACS CallAutomation!'
127 |
128 | if __name__ == '__main__':
129 | app.logger.setLevel(INFO)
130 | app.run(port=8000)
131 |
--------------------------------------------------------------------------------
/call-recording/data/Recordings API.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "be622dd7-585a-4b41-b10e-750a9d1ad2f8",
4 | "name": "Recordings API",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
6 | "_exporter_id": "1437196"
7 | },
8 | "item": [
9 | {
10 | "name": "Outbound Call",
11 | "protocolProfileBehavior": {
12 | "disableBodyPruning": true,
13 | "disabledSystemHeaders": {}
14 | },
15 | "request": {
16 | "method": "GET",
17 | "header": [],
18 | "body": {
19 | "mode": "raw",
20 | "raw": "",
21 | "options": {
22 | "raw": {
23 | "language": "json"
24 | }
25 | }
26 | },
27 | "url": {
28 | "raw": "{{HOST_URL}}/outboundCall?targetPhoneNumber={{TARGET_PHONE_NUMBER}}",
29 | "host": [
30 | "{{HOST_URL}}"
31 | ],
32 | "path": [
33 | "outboundCall"
34 | ],
35 | "query": [
36 | {
37 | "key": "targetPhoneNumber",
38 | "value": "{{TARGET_PHONE_NUMBER}}"
39 | }
40 | ]
41 | }
42 | },
43 | "response": []
44 | },
45 | {
46 | "name": "Start recording",
47 | "protocolProfileBehavior": {
48 | "disableBodyPruning": true,
49 | "disabledSystemHeaders": {}
50 | },
51 | "request": {
52 | "method": "GET",
53 | "header": [],
54 | "body": {
55 | "mode": "raw",
56 | "raw": "",
57 | "options": {
58 | "raw": {
59 | "language": "json"
60 | }
61 | }
62 | },
63 | "url": {
64 | "raw": "{{HOST_URL}}/startRecording?serverCallId=",
65 | "host": [
66 | "{{HOST_URL}}"
67 | ],
68 | "path": [
69 | "startRecording"
70 | ],
71 | "query": [
72 | {
73 | "key": "serverCallId",
74 | "value": "",
75 | "description": "Optional, if not passed, it will use last OutboundCall serverCallId"
76 | }
77 | ]
78 | }
79 | },
80 | "response": []
81 | },
82 | {
83 | "name": "Pause recording",
84 | "protocolProfileBehavior": {
85 | "disableBodyPruning": true,
86 | "disabledSystemHeaders": {}
87 | },
88 | "request": {
89 | "method": "GET",
90 | "header": [],
91 | "body": {
92 | "mode": "raw",
93 | "raw": "",
94 | "options": {
95 | "raw": {
96 | "language": "json"
97 | }
98 | }
99 | },
100 | "url": {
101 | "raw": "{{HOST_URL}}/pauseRecording?recordingId=",
102 | "host": [
103 | "{{HOST_URL}}"
104 | ],
105 | "path": [
106 | "pauseRecording"
107 | ],
108 | "query": [
109 | {
110 | "key": "recordingId",
111 | "value": "",
112 | "description": "Optional, if not passed, it will use current active recording Id"
113 | }
114 | ]
115 | }
116 | },
117 | "response": []
118 | },
119 | {
120 | "name": "Get recording state",
121 | "protocolProfileBehavior": {
122 | "disableBodyPruning": true,
123 | "disabledSystemHeaders": {}
124 | },
125 | "request": {
126 | "method": "GET",
127 | "header": [],
128 | "body": {
129 | "mode": "raw",
130 | "raw": "",
131 | "options": {
132 | "raw": {
133 | "language": "json"
134 | }
135 | }
136 | },
137 | "url": {
138 | "raw": "{{HOST_URL}}/getRecordingState?recordingId=",
139 | "host": [
140 | "{{HOST_URL}}"
141 | ],
142 | "path": [
143 | "getRecordingState"
144 | ],
145 | "query": [
146 | {
147 | "key": "recordingId",
148 | "value": "",
149 | "description": "Optional, if not passed, it will use current active recording Id"
150 | }
151 | ]
152 | }
153 | },
154 | "response": []
155 | },
156 | {
157 | "name": "Resume recording",
158 | "protocolProfileBehavior": {
159 | "disableBodyPruning": true,
160 | "disabledSystemHeaders": {}
161 | },
162 | "request": {
163 | "method": "GET",
164 | "header": [],
165 | "body": {
166 | "mode": "raw",
167 | "raw": "",
168 | "options": {
169 | "raw": {
170 | "language": "json"
171 | }
172 | }
173 | },
174 | "url": {
175 | "raw": "{{HOST_URL}}/resumeRecording?recordingId=",
176 | "host": [
177 | "{{HOST_URL}}"
178 | ],
179 | "path": [
180 | "resumeRecording"
181 | ],
182 | "query": [
183 | {
184 | "key": "recordingId",
185 | "value": "",
186 | "description": "Optional, if not passed, it will use current active recording Id"
187 | }
188 | ]
189 | }
190 | },
191 | "response": []
192 | },
193 | {
194 | "name": "Stop recording",
195 | "protocolProfileBehavior": {
196 | "disabledSystemHeaders": {}
197 | },
198 | "request": {
199 | "method": "DELETE",
200 | "header": [],
201 | "body": {
202 | "mode": "raw",
203 | "raw": "",
204 | "options": {
205 | "raw": {
206 | "language": "json"
207 | }
208 | }
209 | },
210 | "url": {
211 | "raw": "{{HOST_URL}}/stopRecording?recordingId=",
212 | "host": [
213 | "{{HOST_URL}}"
214 | ],
215 | "path": [
216 | "stopRecording"
217 | ],
218 | "query": [
219 | {
220 | "key": "recordingId",
221 | "value": "",
222 | "description": "Optional, if not passed, it will use current active recording Id"
223 | }
224 | ]
225 | }
226 | },
227 | "response": []
228 | },
229 | {
230 | "name": "Download recording",
231 | "protocolProfileBehavior": {
232 | "disableBodyPruning": true,
233 | "disabledSystemHeaders": {}
234 | },
235 | "request": {
236 | "method": "GET",
237 | "header": [],
238 | "body": {
239 | "mode": "raw",
240 | "raw": "",
241 | "options": {
242 | "raw": {
243 | "language": "json"
244 | }
245 | }
246 | },
247 | "url": {
248 | "raw": "{{HOST_URL}}/downloadRecording",
249 | "host": [
250 | "{{HOST_URL}}"
251 | ],
252 | "path": [
253 | "downloadRecording"
254 | ]
255 | }
256 | },
257 | "response": []
258 | },
259 | {
260 | "name": "Delete recording",
261 | "protocolProfileBehavior": {
262 | "disabledSystemHeaders": {}
263 | },
264 | "request": {
265 | "method": "DELETE",
266 | "header": [],
267 | "body": {
268 | "mode": "raw",
269 | "raw": "",
270 | "options": {
271 | "raw": {
272 | "language": "json"
273 | }
274 | }
275 | },
276 | "url": {
277 | "raw": "{{HOST_URL}}/deleteRecording",
278 | "host": [
279 | "{{HOST_URL}}"
280 | ],
281 | "path": [
282 | "deleteRecording"
283 | ]
284 | }
285 | },
286 | "response": []
287 | }
288 | ],
289 | "event": [
290 | {
291 | "listen": "prerequest",
292 | "script": {
293 | "type": "text/javascript",
294 | "exec": [
295 | ""
296 | ]
297 | }
298 | },
299 | {
300 | "listen": "test",
301 | "script": {
302 | "type": "text/javascript",
303 | "exec": [
304 | ""
305 | ]
306 | }
307 | }
308 | ],
309 | "variable": [
310 | {
311 | "key": "HOST_URL",
312 | "value": "",
313 | "type": "string"
314 | },
315 | {
316 | "key": "TARGET_PHONE_NUMBER",
317 | "value": "",
318 | "type": "string"
319 | }
320 | ]
321 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # Python virtual environment
7 | */venv/
8 |
9 | # User-specific files
10 | *.rsuser
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Mono auto generated files
20 | mono_crash.*
21 |
22 | # Build results
23 | [Dd]ebug/
24 | [Dd]ebugPublic/
25 | [Rr]elease/
26 | [Rr]eleases/
27 | x64/
28 | x86/
29 | [Aa][Rr][Mm]/
30 | [Aa][Rr][Mm]64/
31 | bld/
32 | [Bb]in/
33 | [Oo]bj/
34 | [Ll]og/
35 | [Ll]ogs/
36 |
37 | # Visual Studio 2015/2017 cache/options directory
38 | .vs/
39 | # Uncomment if you have tasks that create the project's static files in wwwroot
40 | #wwwroot/
41 |
42 | # Visual Studio 2017 auto generated files
43 | Generated\ Files/
44 |
45 | # MSTest test Results
46 | [Tt]est[Rr]esult*/
47 | [Bb]uild[Ll]og.*
48 |
49 | # NUnit
50 | *.VisualState.xml
51 | TestResult.xml
52 | nunit-*.xml
53 |
54 | # Build Results of an ATL Project
55 | [Dd]ebugPS/
56 | [Rr]eleasePS/
57 | dlldata.c
58 |
59 | # Benchmark Results
60 | BenchmarkDotNet.Artifacts/
61 |
62 | # .NET Core
63 | project.lock.json
64 | project.fragment.lock.json
65 | artifacts/
66 |
67 | # StyleCop
68 | StyleCopReport.xml
69 |
70 | # Files built by Visual Studio
71 | *_i.c
72 | *_p.c
73 | *_h.h
74 | *.ilk
75 | *.meta
76 | *.obj
77 | *.iobj
78 | *.pch
79 | *.pdb
80 | *.ipdb
81 | *.pgc
82 | *.pgd
83 | *.rsp
84 | *.sbr
85 | *.tlb
86 | *.tli
87 | *.tlh
88 | *.tmp
89 | *.tmp_proj
90 | *_wpftmp.csproj
91 | *.log
92 | *.vspscc
93 | *.vssscc
94 | .builds
95 | *.pidb
96 | *.svclog
97 | *.scc
98 |
99 | # Chutzpah Test files
100 | _Chutzpah*
101 |
102 | # Visual C++ cache files
103 | ipch/
104 | *.aps
105 | *.ncb
106 | *.opendb
107 | *.opensdf
108 | *.sdf
109 | *.cachefile
110 | *.VC.db
111 | *.VC.VC.opendb
112 |
113 | # Visual Studio profiler
114 | *.psess
115 | *.vsp
116 | *.vspx
117 | *.sap
118 |
119 | # Visual Studio Trace Files
120 | *.e2e
121 |
122 | # TFS 2012 Local Workspace
123 | $tf/
124 |
125 | # Guidance Automation Toolkit
126 | *.gpState
127 |
128 | # ReSharper is a .NET coding add-in
129 | _ReSharper*/
130 | *.[Rr]e[Ss]harper
131 | *.DotSettings.user
132 |
133 | # TeamCity is a build add-in
134 | _TeamCity*
135 |
136 | # DotCover is a Code Coverage Tool
137 | *.dotCover
138 |
139 | # AxoCover is a Code Coverage Tool
140 | .axoCover/*
141 | !.axoCover/settings.json
142 |
143 | # Visual Studio code coverage results
144 | *.coverage
145 | *.coveragexml
146 |
147 | # NCrunch
148 | _NCrunch_*
149 | .*crunch*.local.xml
150 | nCrunchTemp_*
151 |
152 | # MightyMoose
153 | *.mm.*
154 | AutoTest.Net/
155 |
156 | # Web workbench (sass)
157 | .sass-cache/
158 |
159 | # Installshield output folder
160 | [Ee]xpress/
161 |
162 | # DocProject is a documentation generator add-in
163 | DocProject/buildhelp/
164 | DocProject/Help/*.HxT
165 | DocProject/Help/*.HxC
166 | DocProject/Help/*.hhc
167 | DocProject/Help/*.hhk
168 | DocProject/Help/*.hhp
169 | DocProject/Help/Html2
170 | DocProject/Help/html
171 |
172 | # Click-Once directory
173 | publish/
174 |
175 | # Publish Web Output
176 | *.[Pp]ublish.xml
177 | *.azurePubxml
178 | # Note: Comment the next line if you want to checkin your web deploy settings,
179 | # but database connection strings (with potential passwords) will be unencrypted
180 | *.pubxml
181 | *.publishproj
182 |
183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
184 | # checkin your Azure Web App publish settings, but sensitive information contained
185 | # in these scripts will be unencrypted
186 | PublishScripts/
187 |
188 | # NuGet Packages
189 | *.nupkg
190 | # NuGet Symbol Packages
191 | *.snupkg
192 | # The packages folder can be ignored because of Package Restore
193 | **/[Pp]ackages/*
194 | # except build/, which is used as an MSBuild target.
195 | !**/[Pp]ackages/build/
196 | # Uncomment if necessary however generally it will be regenerated when needed
197 | #!**/[Pp]ackages/repositories.config
198 | # NuGet v3's project.json files produces more ignorable files
199 | *.nuget.props
200 | *.nuget.targets
201 |
202 | # Microsoft Azure Build Output
203 | csx/
204 | *.build.csdef
205 |
206 | # Microsoft Azure Emulator
207 | ecf/
208 | rcf/
209 |
210 | # Windows Store app package directories and files
211 | AppPackages/
212 | BundleArtifacts/
213 | Package.StoreAssociation.xml
214 | _pkginfo.txt
215 | *.appx
216 | *.appxbundle
217 | *.appxupload
218 |
219 | # Visual Studio cache files
220 | # files ending in .cache can be ignored
221 | *.[Cc]ache
222 | # but keep track of directories ending in .cache
223 | !?*.[Cc]ache/
224 |
225 | # Others
226 | ClientBin/
227 | ~$*
228 | *~
229 | *.dbmdl
230 | *.dbproj.schemaview
231 | *.jfm
232 | *.pfx
233 | *.publishsettings
234 | orleans.codegen.cs
235 |
236 | # Including strong name files can present a security risk
237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
238 | #*.snk
239 |
240 | # Since there are multiple workflows, uncomment next line to ignore bower_components
241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
242 | #bower_components/
243 |
244 | # RIA/Silverlight projects
245 | Generated_Code/
246 |
247 | # Backup & report files from converting an old project file
248 | # to a newer Visual Studio version. Backup files are not needed,
249 | # because we have git ;-)
250 | _UpgradeReport_Files/
251 | Backup*/
252 | UpgradeLog*.XML
253 | UpgradeLog*.htm
254 | ServiceFabricBackup/
255 | *.rptproj.bak
256 |
257 | # SQL Server files
258 | *.mdf
259 | *.ldf
260 | *.ndf
261 |
262 | # Business Intelligence projects
263 | *.rdl.data
264 | *.bim.layout
265 | *.bim_*.settings
266 | *.rptproj.rsuser
267 | *- [Bb]ackup.rdl
268 | *- [Bb]ackup ([0-9]).rdl
269 | *- [Bb]ackup ([0-9][0-9]).rdl
270 |
271 | # Microsoft Fakes
272 | FakesAssemblies/
273 |
274 | # GhostDoc plugin setting file
275 | *.GhostDoc.xml
276 |
277 | # Node.js Tools for Visual Studio
278 | .ntvs_analysis.dat
279 | node_modules/
280 |
281 | # Visual Studio 6 build log
282 | *.plg
283 |
284 | # Visual Studio 6 workspace options file
285 | *.opt
286 |
287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
288 | *.vbw
289 |
290 | # Visual Studio LightSwitch build output
291 | **/*.HTMLClient/GeneratedArtifacts
292 | **/*.DesktopClient/GeneratedArtifacts
293 | **/*.DesktopClient/ModelManifest.xml
294 | **/*.Server/GeneratedArtifacts
295 | **/*.Server/ModelManifest.xml
296 | _Pvt_Extensions
297 |
298 | # Paket dependency manager
299 | .paket/paket.exe
300 | paket-files/
301 |
302 | # FAKE - F# Make
303 | .fake/
304 |
305 | # CodeRush personal settings
306 | .cr/personal
307 |
308 | # Python Tools for Visual Studio (PTVS)
309 | __pycache__/
310 | *.pyc
311 |
312 | # Cake - Uncomment if you are using it
313 | # tools/**
314 | # !tools/packages.config
315 |
316 | # Tabs Studio
317 | *.tss
318 |
319 | # Telerik's JustMock configuration file
320 | *.jmconfig
321 |
322 | # BizTalk build output
323 | *.btp.cs
324 | *.btm.cs
325 | *.odx.cs
326 | *.xsd.cs
327 |
328 | # OpenCover UI analysis results
329 | OpenCover/
330 |
331 | # Azure Stream Analytics local run output
332 | ASALocalRun/
333 |
334 | # MSBuild Binary and Structured Log
335 | *.binlog
336 |
337 | # NVidia Nsight GPU debugger configuration file
338 | *.nvuser
339 |
340 | # MFractors (Xamarin productivity tool) working folder
341 | .mfractor/
342 |
343 | # Local History for Visual Studio
344 | .localhistory/
345 |
346 | # BeatPulse healthcheck temp database
347 | healthchecksdb
348 |
349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
350 | MigrationBackup/
351 |
352 | # Ionide (cross platform F# VS Code tools) working folder
353 | .ionide/
354 |
--------------------------------------------------------------------------------
/callautomation-azure-openai-voice/azureOpenAIService.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from openai import AsyncAzureOpenAI
4 |
5 | import asyncio
6 | import json
7 | import random
8 |
9 | AZURE_OPENAI_API_ENDPOINT = ''
10 | AZURE_OPENAI_API_VERSION = "2024-10-01-preview"
11 | AZURE_OPENAI_API_KEY = ''
12 | AZURE_OPENAI_DEPLOYMENT_NAME = ''
13 | SAMPLE_RATE = 24000
14 |
15 | def session_config():
16 | """Returns a random value from the predefined list."""
17 | values = ['alloy', 'ash', 'ballad', 'coral', 'echo', 'sage', 'shimmer', 'verse']
18 | ### for details on available param: https://platform.openai.com/docs/api-reference/realtime-sessions/create
19 | SESSION_CONFIG={
20 | "input_audio_transcription": {
21 | "model": "whisper-1",
22 | },
23 | "turn_detection": {
24 | "threshold": 0.4,
25 | "silence_duration_ms": 600,
26 | "type": "server_vad"
27 | },
28 | "instructions": "Your name is Sam, you work for Contoso Services. You're a helpful, calm and cheerful agent who responds with a clam British accent, but also can speak in any language or accent. Always start the conversation with a cheery hello, stating your name and who do you work for!",
29 | "voice": random.choice(values),
30 | "modalities": ["text", "audio"] ## required to solicit the initial welcome message
31 | }
32 | return SESSION_CONFIG
33 |
34 | class OpenAIRTHandler():
35 | incoming_websocket = None
36 | client = None
37 | connection = None
38 | connection_manager = None
39 | welcomed = False
40 |
41 | def __init__(self) -> None:
42 | print("Hello World")
43 | self.client = AsyncAzureOpenAI(
44 | azure_endpoint=AZURE_OPENAI_API_ENDPOINT,
45 | azure_deployment=AZURE_OPENAI_DEPLOYMENT_NAME,
46 | api_key=AZURE_OPENAI_API_KEY,
47 | api_version=AZURE_OPENAI_API_VERSION,
48 | )
49 | self.connection_manager = self.client.beta.realtime.connect(
50 | model="gpt-4o-realtime-preview" # Replace with your deployed realtime model id on Azure OpenAI.
51 | )
52 |
53 | def __exit__(self, exc_type, exc_value, traceback):
54 | self.connection.close()
55 | self.incoming_websocket.close()
56 |
57 | #start_conversation > start_client
58 | async def start_client(self):
59 | self.connection = await self.connection_manager.enter()
60 | await self.connection.session.update(session=session_config())
61 | await self.connection.response.create()
62 | ### running an async task to listen and recieve oai messages
63 | asyncio.create_task(self.receive_oai_messages())
64 |
65 | #send_audio_to_external_ai > audio_to_oai
66 | async def audio_to_oai(self, audioData: str):
67 | await self.connection.input_audio_buffer.append(audio=audioData)
68 |
69 | #receive_messages > receive_oai_messages
70 | async def receive_oai_messages(self):
71 | #while not self.connection._connection.close_code:
72 | async for event in self.connection:
73 | #print(event)
74 | if event is None:
75 | continue
76 | match event.type:
77 | case "session.created":
78 | print("Session Created Message")
79 | print(f" Session Id: {event.session.id}")
80 | pass
81 | case "error":
82 | print(f" Error: {event.error}")
83 | pass
84 | case "input_audio_buffer.cleared":
85 | print("Input Audio Buffer Cleared Message")
86 | pass
87 | case "input_audio_buffer.speech_started":
88 | print(f"Voice activity detection started at {event.audio_start_ms} [ms]")
89 | await self.stop_audio()
90 | pass
91 | case "input_audio_buffer.speech_stopped":
92 | pass
93 | case "conversation.item.input_audio_transcription.completed":
94 | print(f" User:-- {event.transcript}")
95 | case "conversation.item.input_audio_transcription.failed":
96 | print(f" Error: {event.error}")
97 | case "response.done":
98 | print("Response Done Message")
99 | print(f" Response Id: {event.response.id}")
100 | if event.response.status_details:
101 | print(f" Status Details: {event.response.status_details.model_dump_json()}")
102 | case "response.audio_transcript.done":
103 | print(f" AI:-- {event.transcript}")
104 | case "response.audio.delta":
105 | await self.oai_to_acs(event.delta)
106 | pass
107 | case _:
108 | pass
109 |
110 | #init_websocket -> init_incoming_websocket (incoming)
111 | async def init_incoming_websocket(self, socket):
112 | # print("--inbound socket set")
113 | self.incoming_websocket = socket
114 |
115 | #receive_audio_for_outbound > oai_to_acs
116 | async def oai_to_acs(self, data):
117 | try:
118 | data = {
119 | "Kind": "AudioData",
120 | "AudioData": {
121 | "Data": data
122 | },
123 | "StopAudio": None
124 | }
125 |
126 | # Serialize the server streaming data
127 | serialized_data = json.dumps(data)
128 | await self.send_message(serialized_data)
129 |
130 | except Exception as e:
131 | print(e)
132 |
133 | # stop oai talking when detecting the user talking
134 | async def stop_audio(self):
135 | stop_audio_data = {
136 | "Kind": "StopAudio",
137 | "AudioData": None,
138 | "StopAudio": {}
139 | }
140 |
141 | json_data = json.dumps(stop_audio_data)
142 | await self.send_message(json_data)
143 |
144 | # send_message > send_message
145 | async def send_message(self, message: str):
146 | try:
147 | await self.incoming_websocket.send(message)
148 | except Exception as e:
149 | print(f"Failed to send message: {e}")
150 |
151 | async def send_welcome(self):
152 | if not self.welcomed:
153 | await self.connection.conversation.item.create(
154 | item={
155 | "type": "message",
156 | "role": "user",
157 | "content": [{"type": "input_text", "text": "Hi! What's your name and who do you work for?"}],
158 | }
159 | )
160 | await self.connection.response.create()
161 | self.welcomed = True
162 |
163 | #mediaStreamingHandler.process_websocket_message_async -> acs_to_oai
164 | async def acs_to_oai(self, stream_data):
165 | try:
166 | data = json.loads(stream_data)
167 | kind = data['kind']
168 | if kind == "AudioData":
169 | audio_data_section = data.get("audioData", {})
170 | if not audio_data_section.get("silent", True):
171 | audio_data = audio_data_section.get("data")
172 | await self.audio_to_oai(audio_data)
173 | except Exception as e:
174 | print(f'Error processing WebSocket message: {e}')
175 |
--------------------------------------------------------------------------------
/callautomation-outboundcalling/main.py:
--------------------------------------------------------------------------------
1 | from azure.eventgrid import EventGridEvent, SystemEventNames
2 | from flask import Flask, Response, request, json, send_file, render_template, redirect
3 | from logging import INFO
4 | from azure.communication.callautomation import (
5 | CallAutomationClient,
6 | CallConnectionClient,
7 | PhoneNumberIdentifier,
8 | RecognizeInputType,
9 | MicrosoftTeamsUserIdentifier,
10 | CallInvite,
11 | RecognitionChoice,
12 | DtmfTone,
13 | TextSource)
14 | from azure.core.messaging import CloudEvent
15 |
16 | # Your ACS resource connection string
17 | ACS_CONNECTION_STRING = ""
18 |
19 | # Your ACS resource phone number will act as source number to start outbound call
20 | ACS_PHONE_NUMBER = ""
21 |
22 | # Target phone number you want to receive the call.
23 | TARGET_PHONE_NUMBER = ""
24 |
25 | # Callback events URI to handle callback events.
26 | CALLBACK_URI_HOST = ""
27 | CALLBACK_EVENTS_URI = CALLBACK_URI_HOST + "/api/callbacks"
28 | COGNITIVE_SERVICES_ENDPOINT = ""
29 |
30 | #(OPTIONAL) Your target Microsoft Teams user Id ex. "ab01bc12-d457-4995-a27b-c405ecfe4870"
31 | TARGET_TEAMS_USER_ID = ""
32 |
33 | TEMPLATE_FILES_PATH = "template"
34 |
35 | # Prompts for text to speech
36 | SPEECH_TO_TEXT_VOICE = "en-US-NancyNeural"
37 | MAIN_MENU = "Hello this is Contoso Bank, we’re calling in regard to your appointment tomorrow at 9am to open a new account. Please say confirm if this time is still suitable for you or say cancel if you would like to cancel this appointment."
38 | CONFIRMED_TEXT = "Thank you for confirming your appointment tomorrow at 9am, we look forward to meeting with you."
39 | CANCEL_TEXT = "Your appointment tomorrow at 9am has been cancelled. Please call the bank directly if you would like to rebook for another date and time."
40 | CUSTOMER_QUERY_TIMEOUT = "I’m sorry I didn’t receive a response, please try again."
41 | NO_RESPONSE = "I didn't receive an input, we will go ahead and confirm your appointment. Goodbye"
42 | INVALID_AUDIO = "I’m sorry, I didn’t understand your response, please try again."
43 | CONFIRM_CHOICE_LABEL = "Confirm"
44 | CANCEL_CHOICE_LABEL = "Cancel"
45 | RETRY_CONTEXT = "retry"
46 |
47 | call_automation_client = CallAutomationClient.from_connection_string(ACS_CONNECTION_STRING)
48 |
49 | app = Flask(__name__,
50 | template_folder=TEMPLATE_FILES_PATH)
51 |
52 | def get_choices():
53 | choices = [
54 | RecognitionChoice(label = CONFIRM_CHOICE_LABEL, phrases= ["Confirm", "First", "One"], tone = DtmfTone.ONE),
55 | RecognitionChoice(label = CANCEL_CHOICE_LABEL, phrases= ["Cancel", "Second", "Two"], tone = DtmfTone.TWO)
56 | ]
57 | return choices
58 |
59 | def get_media_recognize_choice_options(call_connection_client: CallConnectionClient, text_to_play: str, target_participant:str, choices: any, context: str):
60 | play_source = TextSource (text= text_to_play, voice_name= SPEECH_TO_TEXT_VOICE)
61 | call_connection_client.start_recognizing_media(
62 | input_type=RecognizeInputType.CHOICES,
63 | target_participant=target_participant,
64 | choices=choices,
65 | play_prompt=play_source,
66 | interrupt_prompt=False,
67 | initial_silence_timeout=10,
68 | operation_context=context
69 | )
70 |
71 | def handle_play(call_connection_client: CallConnectionClient, text_to_play: str):
72 | play_source = TextSource(text=text_to_play, voice_name=SPEECH_TO_TEXT_VOICE)
73 | call_connection_client.play_media_to_all(play_source)
74 |
75 | # GET endpoint to place phone call
76 | @app.route('/outboundCall')
77 | def outbound_call_handler():
78 | target_participant = PhoneNumberIdentifier(TARGET_PHONE_NUMBER)
79 | source_caller = PhoneNumberIdentifier(ACS_PHONE_NUMBER)
80 | call_connection_properties = call_automation_client.create_call(target_participant,
81 | CALLBACK_EVENTS_URI,
82 | cognitive_services_endpoint=COGNITIVE_SERVICES_ENDPOINT,
83 | source_caller_id_number=source_caller)
84 | app.logger.info("Created call with connection id: %s", call_connection_properties.call_connection_id)
85 | return redirect("/")
86 |
87 |
88 | # POST endpoint to handle callback events
89 | @app.route('/api/callbacks', methods=['POST'])
90 | def callback_events_handler():
91 | for event_dict in request.json:
92 | # Parsing callback events
93 | event = CloudEvent.from_dict(event_dict)
94 | call_connection_id = event.data['callConnectionId']
95 | app.logger.info("%s event received for call connection id: %s", event.type, call_connection_id)
96 | call_connection_client = call_automation_client.get_call_connection(call_connection_id)
97 | target_participant = PhoneNumberIdentifier(TARGET_PHONE_NUMBER)
98 | if event.type == "Microsoft.Communication.CallConnected":
99 | # (Optional) Add a Microsoft Teams user to the call. Uncomment the below snippet to enable Teams Interop scenario.
100 | # call_connection_client.add_participant(target_participant = CallInvite(
101 | # target = MicrosoftTeamsUserIdentifier(user_id=TARGET_TEAMS_USER_ID),
102 | # source_display_name = "Jack (Contoso Tech Support)"))
103 |
104 | app.logger.info("Starting recognize")
105 | get_media_recognize_choice_options(
106 | call_connection_client=call_connection_client,
107 | text_to_play=MAIN_MENU,
108 | target_participant=target_participant,
109 | choices=get_choices(),context="")
110 |
111 | # Perform different actions based on DTMF tone received from RecognizeCompleted event
112 | elif event.type == "Microsoft.Communication.RecognizeCompleted":
113 | app.logger.info("Recognize completed: data=%s", event.data)
114 | if event.data['recognitionType'] == "choices":
115 | label_detected = event.data['choiceResult']['label'];
116 | phraseDetected = event.data['choiceResult']['recognizedPhrase'];
117 | app.logger.info("Recognition completed, labelDetected=%s, phraseDetected=%s, context=%s", label_detected, phraseDetected, event.data.get('operationContext'))
118 | if label_detected == CONFIRM_CHOICE_LABEL:
119 | text_to_play = CONFIRMED_TEXT
120 | else:
121 | text_to_play = CANCEL_TEXT
122 | handle_play(call_connection_client=call_connection_client, text_to_play=text_to_play)
123 |
124 | elif event.type == "Microsoft.Communication.RecognizeFailed":
125 | failedContext = event.data['operationContext']
126 | if(failedContext and failedContext == RETRY_CONTEXT):
127 | handle_play(call_connection_client=call_connection_client, text_to_play=NO_RESPONSE)
128 | else:
129 | resultInformation = event.data['resultInformation']
130 | app.logger.info("Encountered error during recognize, message=%s, code=%s, subCode=%s",
131 | resultInformation['message'],
132 | resultInformation['code'],
133 | resultInformation['subCode'])
134 | if(resultInformation['subCode'] in[8510, 8510]):
135 | textToPlay =CUSTOMER_QUERY_TIMEOUT
136 | else :
137 | textToPlay =INVALID_AUDIO
138 |
139 | get_media_recognize_choice_options(
140 | call_connection_client=call_connection_client,
141 | text_to_play=textToPlay,
142 | target_participant=target_participant,
143 | choices=get_choices(),context=RETRY_CONTEXT)
144 |
145 | elif event.type in ["Microsoft.Communication.PlayCompleted", "Microsoft.Communication.PlayFailed"]:
146 | app.logger.info("Terminating call")
147 | call_connection_client.hang_up(is_for_everyone=True)
148 |
149 | return Response(status=200)
150 |
151 | # GET endpoint to render the menus
152 | @app.route('/')
153 | def index_handler():
154 | return render_template("index.html")
155 |
156 |
157 | if __name__ == '__main__':
158 | app.logger.setLevel(INFO)
159 | app.run(port=8080)
160 |
--------------------------------------------------------------------------------
/callautomation-connect-room/main.py:
--------------------------------------------------------------------------------
1 | import time
2 | from quart import Quart, render_template, jsonify, request, redirect
3 | from azure.core.exceptions import HttpResponseError
4 | from datetime import datetime, timezone, timedelta
5 | from azure.communication.callautomation import (
6 | PhoneNumberIdentifier,
7 | TextSource
8 | )
9 | from azure.communication.identity import (
10 | CommunicationUserIdentifier,
11 | CommunicationIdentityClient
12 | )
13 | from azure.communication.callautomation.aio import (
14 | CallAutomationClient
15 | )
16 | from azure.communication.rooms import (
17 | RoomsClient,
18 | RoomParticipant,
19 | ParticipantRole
20 | )
21 |
22 | from logging import INFO
23 | import asyncio
24 | from config import Config
25 |
26 | # Initialize Quart app
27 | app = Quart(__name__)
28 |
29 | # Use config values from config.py
30 | PORT = Config.PORT
31 | CONNECTION_STRING = Config.CONNECTION_STRING
32 | ACS_RESOURCE_PHONE_NUMBER = Config.ACS_RESOURCE_PHONE_NUMBER
33 | TARGET_PHONE_NUMBER = Config.TARGET_PHONE_NUMBER
34 | CALLBACK_URI = Config.CALLBACK_URI
35 | COGNITIVE_SERVICES_ENDPOINT = Config.COGNITIVE_SERVICES_ENDPOINT
36 |
37 | # Initialize variables
38 | acs_client = None
39 | call_connection = None
40 | call_connection_id = None
41 | server_call_id = None
42 | room_id = None
43 |
44 | # Global variables to store room and user details
45 | room_details = None
46 |
47 | # Initialize ACS Client
48 | async def create_acs_client():
49 | global acs_client
50 | acs_client = CallAutomationClient.from_connection_string(CONNECTION_STRING)
51 | print("Initialized ACS Client.")
52 |
53 | # Create Room
54 | async def create_room():
55 | identity_client = CommunicationIdentityClient.from_connection_string(CONNECTION_STRING)
56 | app.logger.info("Test")
57 | # Correct unpacking of the returned tuple
58 | user1, token1 = identity_client.create_user_and_token(["voip"])
59 | user2, token2 = identity_client.create_user_and_token(["voip"])
60 |
61 | communication_user_id1 = user1.properties['id']
62 | communication_user_id2 = user2.properties['id']
63 | # Now you can access the 'user' and 'token' separately
64 | print(f"Presenter: {communication_user_id1}, Token: {token1.token}")
65 | print(f"Attendee: {communication_user_id2}, Token: {token2.token}")
66 |
67 | rooms_client = RoomsClient.from_connection_string(CONNECTION_STRING)
68 |
69 | valid_from = datetime.now(timezone.utc)
70 | valid_until = valid_from + timedelta(weeks=7)
71 | # Create participants
72 | participants = [
73 | RoomParticipant(
74 | communication_identifier=CommunicationUserIdentifier(communication_user_id1),
75 | role=ParticipantRole.PRESENTER # Presenter role
76 | ),
77 | RoomParticipant(
78 | communication_identifier=CommunicationUserIdentifier(communication_user_id2),
79 | role=ParticipantRole.CONSUMER # Attendee role
80 | )
81 | ]
82 |
83 | try:
84 | create_room_response = rooms_client.create_room(
85 | valid_from=valid_from,
86 | valid_until=valid_until,
87 | participants=participants,
88 | pstn_dial_out_enabled=True
89 | )
90 | except HttpResponseError as ex:
91 | print(ex)
92 |
93 | global room_id
94 | room_id = create_room_response.id
95 | print(f"Room created with ID: {room_id}")
96 |
97 | room_details = {
98 | "room_id": create_room_response.id,
99 | "presenter_id": communication_user_id1,
100 | "presenter_token": token1.token,
101 | "attendee_id": communication_user_id2,
102 | "attendee_token": token2.token
103 | }
104 | return room_details
105 | # Connect call to the room
106 | async def connect_call():
107 | global call_connection_id
108 | if room_id:
109 | # Use CALLBACK_URI from the config
110 | callback_uri = CALLBACK_URI + "/api/callbacks"
111 | app.logger.info(f"Callback URL: {callback_uri}")
112 | app.logger.info(f"Room ID: {room_id}")
113 |
114 | response = await acs_client.connect_call(
115 | room_id=room_id,
116 | callback_url=callback_uri,
117 | cognitive_services_endpoint=COGNITIVE_SERVICES_ENDPOINT,
118 | operation_context="connectCallContext")
119 | print("Call connection initiated.")
120 | app.logger.info(f"Connect request correlation id: {response.correlation_id}")
121 | else:
122 | print("Room ID is empty or room not available.")
123 |
124 | # Add PSTN participant to the call
125 | async def add_pstn_participant():
126 | if call_connection_id:
127 | target = PhoneNumberIdentifier(TARGET_PHONE_NUMBER)
128 | source_caller_id_number = PhoneNumberIdentifier(ACS_RESOURCE_PHONE_NUMBER)
129 | app.logger.info("source_caller_id_number: %s", source_caller_id_number)
130 |
131 | add_participant_result= await call_connection.add_participant(target_participant=target,
132 | source_caller_id_number=source_caller_id_number,
133 | operation_context=None,
134 | invitation_timeout=15)
135 | app.logger.info("Add Translator to the call: %s", add_participant_result.invitation_id)
136 |
137 | print(f"Adding PSTN participant with invitation ID: {add_participant_result.invitation_id}")
138 | else:
139 | print("Call connection ID is empty or call not active.")
140 |
141 | # Hangup the call
142 | async def hang_up_call():
143 | if call_connection:
144 | await call_connection.hang_up(True)
145 | print("Call hung up.")
146 |
147 | async def handle_play():
148 | play_source = TextSource(text="Hello, welcome to connect room contoso app.", voice_name="en-US-NancyNeural")
149 | if call_connection:
150 | await call_connection.play_media_to_all(play_source)
151 |
152 | # Routes
153 | @app.route('/')
154 | async def home():
155 | global room_details
156 | # Check if room details already exist
157 | if not room_details:
158 | # Create the ACS client and room only if room is not created yet
159 | await create_acs_client()
160 | room_details = await create_room()
161 |
162 | # Render the page with the room details
163 | return await render_template('index.html', details=room_details)
164 |
165 | @app.route('/connectCall', methods=['GET'])
166 | async def connect_call_route():
167 | await connect_call()
168 | return redirect('/')
169 |
170 | @app.route('/addParticipant', methods=['GET'])
171 | async def add_participant_route():
172 | await add_pstn_participant()
173 | return redirect('/')
174 |
175 | @app.route('/hangup', methods=['GET'])
176 | async def hangup_route():
177 | await hang_up_call()
178 | return redirect('/')
179 |
180 | @app.route('/playMedia', methods=['GET'])
181 | async def play_media_route():
182 | await handle_play()
183 | return redirect('/')
184 |
185 | @app.route('/api/callbacks', methods=['POST'])
186 | async def handle_callbacks():
187 | try:
188 | global call_connection_id, server_call_id, call_connection
189 |
190 | # Extract the first event from the request body
191 | events = await request.json
192 | event = events[0] # Assumes at least one event is present
193 | event_data = event['data']
194 | # Handle specific event types
195 | if event['type'] == "Microsoft.Communication.CallConnected":
196 | app.logger.info("Received CallConnected event")
197 | app.logger.info(f"Correlation ID: {event_data['correlationId']}")
198 | # Extract necessary details
199 | call_connection_id = event_data['callConnectionId']
200 | server_call_id = event_data['serverCallId']
201 | call_connection = acs_client.get_call_connection(call_connection_id)
202 |
203 | elif event['type'] == "Microsoft.Communication.AddParticipantSucceeded":
204 | app.logger.info("Received AddParticipantSucceeded event")
205 |
206 | elif event['type'] == "Microsoft.Communication.AddParticipantFailed":
207 | result_info = event_data['resultInformation']
208 | app.logger.info("Received AddParticipantFailed event")
209 | app.logger.info(f"Code: {result_info['code']}, Subcode: {result_info['subCode']}")
210 | app.logger.info(f"Message: {result_info['message']}")
211 | elif event['type'] == "Microsoft.Communication.PlayCompleted":
212 | app.logger.info("Received PlayCompleted event")
213 | elif event['type'] == "Microsoft.Communication.PlayFailed":
214 | result_info = event_data['resultInformation']
215 | app.logger.info("Received PlayFailed event")
216 | app.logger.info(f"Code: {result_info['code']}, Subcode: {result_info['subCode']}")
217 | app.logger.info(f"Message: {result_info['message']}")
218 | elif event['type'] == "Microsoft.Communication.CallDisconnected":
219 | app.logger.info("Received CallDisconnected event")
220 | app.logger.info(f"Correlation ID: {event_data['correlationId']}")
221 |
222 | # Respond with a success status
223 | return jsonify({"status": "OK"}), 200
224 |
225 | except Exception as e:
226 | app.logger.error(f"Error processing callback: {e}")
227 | return jsonify({"error": "Internal server error"}), 500
228 |
229 | if __name__ == '__main__':
230 | app.logger.setLevel(INFO)
231 | app.run(port=PORT)
232 |
233 |
--------------------------------------------------------------------------------
/call-recording/Controller/RecordingsController.py:
--------------------------------------------------------------------------------
1 | from azure.eventgrid import EventGridEvent
2 | from ConfigurationManager import ConfigurationManager
3 | from Logger import Logger
4 | import json
5 | import ast
6 | from aiohttp import web
7 | from azure.core.messaging import CloudEvent
8 | from azure.communication.callautomation import (
9 | CallAutomationClient,
10 | CallInvite,
11 | PhoneNumberIdentifier,
12 | ServerCallLocator)
13 |
14 | configuration_manager = ConfigurationManager.get_instance()
15 | connection_string = configuration_manager.get_app_settings("ACSResourceConnectionString")
16 | _client = CallAutomationClient.from_connection_string(connection_string)
17 | _call_connection_id = None
18 | _server_call_id = None
19 | _recording_id = None
20 | _content_location = None
21 | _delete_location = None
22 |
23 | class RecordingsController():
24 |
25 | def __init__(self):
26 | app = web.Application()
27 | app.add_routes([web.get('/startRecording', RecordingsController.start_recording)])
28 | app.add_routes([web.get('/pauseRecording', RecordingsController.pause_recording)])
29 | app.add_routes([web.get('/resumeRecording', RecordingsController.resume_recording)])
30 | app.add_routes([web.delete('/stopRecording', RecordingsController.stop_recording)])
31 | app.add_routes([web.get('/getRecordingState', RecordingsController.get_recording_state)])
32 | app.add_routes([web.get('/downloadRecording', RecordingsController.download_recording)])
33 | app.add_routes([web.delete('/deleteRecording', RecordingsController.delete_recording)])
34 | app.add_routes([web.get('/outboundCall', RecordingsController.outbound_call)])
35 | app.add_routes([web.post('/api/callbacks', RecordingsController.start_callback)])
36 | app.add_routes([web.post('/recordingFileStatus', RecordingsController.recording_file_status)])
37 | web.run_app(app, port=58963)
38 |
39 | ## region outbound call - an active call required for recording to start.
40 | async def outbound_call(request):
41 | callback_url = configuration_manager.get_app_settings('CallbackUri') + "/api/callbacks"
42 | targetPhoneNumber = (str)(request.rel_url.query['targetPhoneNumber']).replace(" ", "+")
43 | target = PhoneNumberIdentifier(targetPhoneNumber)
44 | caller_id = PhoneNumberIdentifier(configuration_manager.get_app_settings('ACSAcquiredPhoneNumber'))
45 | call_invite = CallInvite(target=target, source_caller_id_number=caller_id)
46 | response = _client.create_call(target_participant=call_invite, callback_url=callback_url)
47 | global _call_connection_id
48 | _call_connection_id = response.call_connection_id
49 | return web.Response(text=response.call_connection_id)
50 |
51 | async def start_recording(request):
52 | try:
53 | server_call_id = request.rel_url.query['serverCallId']
54 | if not server_call_id:
55 | server_call_id = _server_call_id
56 |
57 | response = _client.start_recording(call_locator=ServerCallLocator(server_call_id))
58 | global _recording_id
59 | _recording_id = response.recording_id
60 | return web.Response(text=response.recording_id)
61 | except Exception as ex:
62 | Logger.log_message( Logger.ERROR, "Failed to start server recording --> " + str(ex))
63 | return web.Response(text=str(ex), status=400)
64 |
65 | async def pause_recording(request):
66 | try:
67 | recording_id = request.rel_url.query['recordingId']
68 | if not recording_id:
69 | recording_id = _recording_id
70 |
71 | res = _client.pause_recording(recording_id=recording_id)
72 | Logger.log_message(Logger.INFORMATION, "PauseRecording response --> " + str(res))
73 | return web.Response(text="OK")
74 | except Exception as ex:
75 | Logger.log_message(Logger.ERROR, "Failed to pause server recording --> " + str(ex))
76 | return web.Response(text=str(ex), status=500)
77 |
78 | async def resume_recording(request):
79 | try:
80 | recording_id = request.rel_url.query['recordingId']
81 | if not recording_id:
82 | recording_id = _recording_id
83 |
84 | res = _client.resume_recording(recording_id=recording_id)
85 | Logger.log_message(Logger.INFORMATION, "ResumeRecording response --> " + str(res))
86 | return web.Response(text="Ok")
87 | except Exception as ex:
88 | Logger.log_message(Logger.ERROR, "Failed to resume server recording --> " + str(ex))
89 | return web.Response(text=str(ex), status=500)
90 |
91 | async def stop_recording(request):
92 | try:
93 | recording_id = request.rel_url.query['recordingId']
94 | if not recording_id:
95 | recording_id = _recording_id
96 |
97 | res = _client.stop_recording(recording_id=recording_id)
98 | Logger.log_message(Logger.INFORMATION,"StopRecording response --> " + str(res))
99 | return web.Response(text="Ok")
100 | except Exception as ex:
101 | Logger.log_message(Logger.ERROR, "Failed to stop server recording --> " + str(ex))
102 | return web.Response(text=str(ex), status=500)
103 |
104 | async def get_recording_state(request):
105 | try:
106 | recording_id = request.rel_url.query['recordingId']
107 | if not recording_id:
108 | recording_id = _recording_id
109 |
110 | res = _client.get_recording_properties(recording_id=recording_id)
111 | Logger.log_message(Logger.INFORMATION, "GetRecordingState response --> " + str(res))
112 | return web.Response(text=res.recording_state, status=200)
113 | except Exception as ex:
114 | Logger.log_message(Logger.ERROR, "Failed to get recording status --> " + str(ex))
115 | return web.Response(text=str(ex), status=500)
116 |
117 | async def download_recording(request):
118 | try:
119 | recording_data = _client.download_recording(_content_location)
120 | with open("Recording_File.wav", "wb") as binary_file:
121 | binary_file.write(recording_data.read())
122 | return web.Response(text="Ok")
123 | except Exception as ex:
124 | Logger.log_message(Logger.ERROR, "Failed to download recording --> " + str(ex))
125 | return web.Response(text=str(ex), status=500)
126 |
127 | async def delete_recording(request):
128 | try:
129 | _client.delete_recording(_delete_location)
130 | return web.Response(text="Ok")
131 | except Exception as ex:
132 | Logger.log_message(Logger.ERROR, "Failed to delete server recording --> " + str(ex))
133 | return web.Response(text=str(ex), status=500)
134 |
135 |
136 | ## region call backs apis
137 | async def start_callback(request):
138 | try:
139 | content = await request.content.read()
140 | post_data = str(content.decode('UTF-8'))
141 | if post_data:
142 | json_data = ast.literal_eval(json.dumps(post_data))
143 | event = CloudEvent.from_dict(ast.literal_eval(json_data)[0])
144 | if event.type == "Microsoft.Communication.CallConnected":
145 | global _server_call_id
146 | _server_call_id = event.data['serverCallId']
147 | Logger.log_message(Logger.INFORMATION, "ServerCallId => "+event.data['serverCallId'])
148 |
149 | except Exception as ex:
150 | Logger.log_message(Logger.ERROR, 'Failed to parse callback --> ' + str(ex))
151 |
152 |
153 | # Web hook to receive the recording file update status event, [Do not call directly from Swagger]
154 | async def recording_file_status(request):
155 | try:
156 | content = await request.content.read()
157 | post_data = str(content.decode('UTF-8'))
158 | if post_data:
159 | json_data = ast.literal_eval(json.dumps(post_data))
160 | event = EventGridEvent.from_dict(ast.literal_eval(json_data)[0])
161 | Logger.log_message(Logger.INFORMATION,"Event type is --> " + str(event.event_type))
162 | Logger.log_message(Logger.INFORMATION,"Request data --> " + str(event.data))
163 |
164 | event_data = event.data
165 | if event.event_type == 'Microsoft.EventGrid.SubscriptionValidationEvent':
166 | subscription_validation_event = event_data
167 | code = subscription_validation_event['validationCode']
168 | if code:
169 | data = {"validationResponse": code}
170 | Logger.log_message(Logger.INFORMATION,"Successfully Subscribed EventGrid.ValidationEvent --> " + str(data))
171 | return web.Response(body=str(data), status=200)
172 |
173 | if event.event_type == 'Microsoft.Communication.RecordingFileStatusUpdated':
174 | acs_recording_file_status_updated_event_data = event_data
175 | acs_recording_chunk_info_properties = acs_recording_file_status_updated_event_data['recordingStorageInfo']['recordingChunks'][0]
176 |
177 | Logger.log_message(Logger.INFORMATION, "acsRecordingChunkInfoProperties response data --> " + str(acs_recording_chunk_info_properties))
178 |
179 | global _content_location
180 | global _delete_location
181 | _content_location = acs_recording_chunk_info_properties['contentLocation']
182 | _delete_location = acs_recording_chunk_info_properties['deleteLocation']
183 |
184 | except Exception as ex:
185 | Logger.log_message(Logger.INFORMATION, "Failed to get recording file")
186 | return web.Response(text='Failed to get recording file', status=400)
--------------------------------------------------------------------------------