Transcribe Your Amazon Connect Recordings

This guide walks through the process of setting up a transcription pipeline for Amazon Connect recordings using AssemblyAI.

Get Started

Before we begin, make sure you have:

  • An AssemblyAI account and an API key. You can sign up for a free account and get your API key from your dashboard.
  • An AWS account.
  • An Amazon Connect instance.

Step-by-Step Instructions

1

In the AWS console, navigate to the Amazon Connect services page. Select your instance and then click into the Data Storage section. On this page, find the subsection named Call Recordings and note the S3 bucket path where your call recordings are stored, you’ll need this for later.

2

Navigate to the Lambda services page, and create a new function. Set the runtime to Python 3.13. In the Change default execution role section, choose the option to create a new role with basic Lambda permissions. Assign a function name and then click Create function.

3

In this new function, scroll down to the Code Source section and paste the following code into lambda_function.py.

1import json
2import os
3import boto3
4import http.client
5import time
6from urllib.parse import unquote_plus
7import logging
8
9# Configure logging
10
11logger = logging.getLogger()
12logger.setLevel(logging.INFO)
13
14# Configuration settings
15
16# See config parameters here: https://www.assemblyai.com/docs/api-reference/transcripts/submit
17
18ASSEMBLYAI_CONFIG = {
19# 'language_code': 'en_us',
20# 'multichannel': True,
21# 'redact_pii': True,
22}
23
24# Initialize AWS services
25
26s3_client = boto3.client('s3')
27
28def get_presigned_url(bucket, key, expiration=3600):
29 """Generate a presigned URL for the S3 object"""
30
31 logger.info({
32 "message": "Generating presigned URL",
33 "bucket": bucket,
34 "key": key,
35 "expiration": expiration
36 })
37
38 s3_client_with_config = boto3.client(
39 's3',
40 config=boto3.session.Config(signature_version='s3v4')
41 )
42
43 return s3_client_with_config.generate_presigned_url(
44 'get_object',
45 Params={'Bucket': bucket, 'Key': key},
46 ExpiresIn=expiration
47 )
48
49def delete_transcript_from_assemblyai(transcript_id, api_key):
50 """
51 Delete transcript data from AssemblyAI's database using their DELETE endpoint.
52
53 Args:
54 transcript_id (str): The AssemblyAI transcript ID to delete
55 api_key (str): The AssemblyAI API key
56
57 Returns:
58 bool: True if deletion was successful, False otherwise
59 """
60
61 headers = {
62 "authorization": api_key,
63 "content-type": "application/json"
64 }
65
66 conn = http.client.HTTPSConnection("api.assemblyai.com")
67
68 try: # Send DELETE request to AssemblyAI API
69 conn.request("DELETE", f"/v2/transcript/{transcript_id}", headers=headers)
70 response = conn.getresponse()
71
72 # Check if deletion was successful (HTTP 200)
73 if response.status == 200:
74 response_data = json.loads(response.read().decode())
75 logger.info(f"Successfully deleted transcript {transcript_id} from AssemblyAI")
76 return True
77 else:
78 error_message = response.read().decode()
79 logger.error(f"Failed to delete transcript {transcript_id}: HTTP {response.status} - {error_message}")
80 return False
81
82 except Exception as e:
83 logger.info(f"Error deleting transcript {transcript_id}: {str(e)}")
84 return False
85 finally:
86 conn.close()
87
88def transcribe_audio(audio_url, api_key):
89 """Transcribe audio using AssemblyAI API with http.client"""
90 logger.info({"message": "Starting audio transcription"})
91
92 headers = {
93 "authorization": api_key,
94 "content-type": "application/json"
95 }
96
97 conn = http.client.HTTPSConnection("api.assemblyai.com")
98
99 # Submit the audio file for transcription with config parameters
100
101 request_data = {"audio_url": audio_url}
102
103 # Add all configuration settings
104
105 request_data.update(ASSEMBLYAI_CONFIG)
106
107 json_data = json.dumps(request_data)
108 conn.request("POST", "/v2/transcript", json_data, headers)
109 response = conn.getresponse()
110
111 if response.status != 200:
112 raise Exception(f"Failed to submit audio for transcription: {response.read().decode()}")
113
114 response_data = json.loads(response.read().decode())
115 transcript_id = response_data['id']
116 logger.info({"message": "Audio submitted for transcription", "transcript_id": transcript_id})
117
118 # Poll for transcription completion
119
120 while True:
121 conn = http.client.HTTPSConnection("api.assemblyai.com")
122 conn.request("GET", f"/v2/transcript/{transcript_id}", headers=headers)
123 polling_response = conn.getresponse()
124 polling_data = json.loads(polling_response.read().decode())
125
126 if polling_data['status'] == 'completed':
127 conn.close()
128 logger.info({"message": "Transcription completed successfully"})
129 return polling_data # Return full JSON response instead of just text
130 elif polling_data['status'] == 'error':
131 conn.close()
132 raise Exception(f"Transcription failed: {polling_data['error']}")
133
134 conn.close()
135 time.sleep(3)
136
137def lambda_handler(event, context):
138 """Lambda function to handle S3 events and process audio files"""
139 try: # Get the AssemblyAI API key from environment variables
140 api_key = os.environ.get('ASSEMBLYAI_API_KEY')
141 if not api_key:
142 raise ValueError("ASSEMBLYAI_API_KEY environment variable is not set")
143
144 # Process each record in the S3 event
145 for record in event.get('Records', []):
146 # Get the S3 bucket and key
147 bucket = record['s3']['bucket']['name']
148 key = unquote_plus(record['s3']['object']['key'])
149
150 # Generate a presigned URL for the audio file
151 audio_url = get_presigned_url(bucket, key)
152
153 # Get the full transcript JSON from AssemblyAI
154 transcript_data = transcribe_audio(audio_url, api_key)
155
156 # Prepare the transcript key - maintaining path structure but changing directory and extension
157 transcript_key = key.replace('/CallRecordings/', '/AssemblyAITranscripts/', 1).replace('.wav', '.json')
158
159 # Convert the JSON data to a string
160 transcript_json_str = json.dumps(transcript_data, indent=2)
161
162 # Upload the transcript JSON to the same bucket but in transcripts directory
163 s3_client.put_object(
164 Bucket=bucket, # Use the same bucket
165 Key=transcript_key,
166 Body=transcript_json_str,
167 ContentType='application/json'
168 )
169 logger.info({"message": "Transcript uploaded to transcript bucket successfully.", "key": transcript_key})
170
171 # Uncomment the following line to delete transcript data from AssemblyAI after saving to S3
172 # https://www.assemblyai.com/docs/api-reference/transcripts/delete
173 # delete_transcript_from_assemblyai(transcript_data['id'], api_key)
174
175 return {
176 "statusCode": 200,
177 "body": json.dumps({
178 "message": "Audio file(s) processed successfully",
179 "detail": "Transcripts have been stored in the AssemblyAITranscripts directory"
180 })
181 }
182
183 except Exception as e:
184 print(f"Error: {str(e)}")
185
186 return {
187 "statusCode": 500,
188 "body": json.dumps({
189 "message": "Error processing audio file(s)",
190 "error": str(e)
191 })
192 }
4

At the top of the lambda function, you can edit the config to enable features for your transcripts. To see all available parameters, check out our API reference.

1ASSEMBLYAI_CONFIG = {
2 # 'language_code': 'en_us',
3 # 'multichannel': True,
4 # 'redact_pii': True,
5}

If you would like to delete transcripts from AssemblyAI after completion, you can uncomment line 166 to enable the delete_transcript_from_assemblyai function. This ensures the transcript data is only saved on your S3 database and not stored on AssemblyAI’s database.

Once you have finished editing the lambda function, click Deploy to save your changes.

5

On the same page, navigate to the Configuration section, under General configuration adjust the timeout to 15min 0sec and click Save. The processing times for transcription will be a lot shorter, but this ensures plenty of time for the function to complete.

6

Now from this page, on the left side panel click Environment variables. Click edit and then add an environment variable, ASSEMBLYAI_API_KEY, and set the value to your AssemblyAI API key. Then click Save.

7

Now, navigate to the IAM services page. On the left side panel under Access Management click Roles and search for your Lambda function role (it’s structure should look like function_name-role-id). Click into the role and then in the Permissions policies section click the dropdown for Add permissions and then select Attach policies.

From this page, find the policy named AmazonS3FullAccess and click Add permissions.

8

Now, navigate to the S3 services page and click into the general purpose bucket where your Amazon Connect recordings are stored. Browse to the Properties tab and then scroll down to Event notifications. Click Create event notification. Give the event a name and then in the prefix section, insert the folder path we noted from Step 1 to ensure the event is triggered for the correct folder.

Then in the Event types section, select All object create events.

Then scroll down to the Destination section, set the destination as Lambda function and then select the Lambda function we created in Step 2. Then click Save changes.

9

To finalise the integration, we’ll need to set the recording behaviour from within your AWS Contact Flows. Navigate to your Amazon Connect instance access URL and sign in to your Admin account. In the left side panel, navigate to the Routing section and then select Flows.

Choose a flow to test with, in this case we’ll utilize the Sample inbound flow (first contact experience). You should see the Block Library on the left hand side of the page. In this section, search for Set recording and analytics behaviour and then drag the block into your flow diagram and connect the arrows.

You can see in our example, we place the block right at the entry of the call flow:

After connecting this block, click the 3 vertical dots in the top right of the block and select Edit settings. Scroll down to the Enable recording and analytics subsection and expand the Voice section. Then select On and select Agent and customer (or whoever you’d like to record). Then click Save, click Save again in the top right and then click Publish to publish the flow.

With this new flow published, you should now receive recordings for your Amazon Connect calls that utilize that flow, and you should now receive AssemblyAI transcripts for those recordings!

The Amazon Connect Call Recordings are saved in the S3 bucket with this naming convention: /connect/{instance-name}/CallRecordings/{YYYY}/{MM}/{DD}/{contact-id}_{YYYYMMDDThh:mm}_UTC.wav

The AssemblyAI Transcripts will be saved in the S3 bucket with this naming convention: /connect/{instance-name}/AssemblyAITranscripts/{YYYY}/{MM}/{DD}/{contact-id}_{YYYYMMDDThh:mm}_UTC.json

10

To view the logs for this integration, navigate to the CloudWatch services page and under the Logs section, select Log groups. Select the log group that matches your Lambda to view the most recent log stream.