AWS Text-To-Speech Serverless Application
Tags: aws, terraform, tutorial, javascript
Published: 2022-12-01 16:00:43

In this article we will go through deploying a Text-To-Speech Serverless Application that contains two main flows presented in the following section.

## Architecture
### New Post

![New Post](https://raw.githubusercontent.com/eelayoubi/aws-serverless-text-to-speech/main/assets/new-post.jpeg)

1. The user calls the API Gateway Restful endpoint that invokes the NewPost lambda function.
2. The NewPost Lambda function inserts information about the post into an Amazon DynamoDB table, where information about all posts is stored.
3. Then, the NewPost Lambda function publishes the post to the SNS topic we create, so it can be converted asynchronously.
4. Convert to Audio Lambda function, is subscribed to the SNS topic and is triggered whenever a new message appears (which means that a new post should be converted into an audio file).
5. The Convert to Audio Lambda function uses Amazon Polly to convert the text into an audio file in the specified language (the same as the language of the text).
6. The new MP3 file is saved in a dedicated S3 bucket.
7. Information about the post is updated in the DynamoDB table (the URL to the audio file stored in the S3 bucket is saved with the previously stored data.)

### Get Post

![Get Post](https://raw.githubusercontent.com/eelayoubi/aws-serverless-text-to-speech/main/assets/get-post.jpeg)

1. The user calls the API Gateway Restful endpoint that invokes the GetPost lambda function which contains the logic for retrieving the post data.
2. The GetPost Lambda function retrieves information about the post (including the reference to Amazon S3) from the DynamoDB table and returns the information.

## Deploying The Resources
You will find the code repository [here](https://github.com/eelayoubi/aws-serverless-text-to-speech).

[To deploy](https://github.com/eelayoubi/aws-serverless-text-to-speech#deploying-the-application) the application, simply run:
```
terraform apply -auto-approve
```

## Breaking it down
We are using [Terraform](www.terraform.io/) to deploy the application.

As you saw in the architecture section. We have two flows, the first one, is when a user submit a post through the API Gateway. And the second flow, in which the user can request one post or all posts.

In the [main.tf](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/main.tf), we are using the [terraform modules](https://github.com/eelayoubi/aws-serverless-text-to-speech/tree/main/modules) that we create, to provision the following:
- DynamoDB Table for storing the posts metadata
- NewPost Lambda function
- GetPost Lambda function
- ConvertToAudio Lambda Function
- The API Gateway



The [iam.tf](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/functions/GetPost/index.js) is where we define the **least-privilege permissions** for the various lambda functions we have.

The **public** S3 bucket that is used to store all the audio posts, is declared in the [s3.tf](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/s3.tf).

The SNS topic used to decouple the application into an asynchronous flow is defined in the [sns.tf](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/sns.tf)

We are creating a topic called **new_posts**, with a lambda as a [subscription](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/sns.tf#L5). So every time this topic receives a message, it will invoke the **ConvertToAudio** lambda function with that message as an event.

To allow SNS to invoke the **ConvertToAudio** lambda function, we create as well a lambda permission [resource](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/sns.tf#L11).

### NewPost Lambda Function
The [NewPost](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/functions/NewPost/index.js) lambda function does two things:
1- Creates an item in the posts table with the following schema:
```
id: recordId,
text: string,
voice: string,
status: 'PROCESSING'
```
The status as you can see is **PROCESSING**, since it still needs to be converted to an audio.

2- Publishes the item id to the SNS topic (so it can be process by ConvertToAudio)

### ConvertToAudio Lambda Function
The [ConvertToAudio](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/functions/ConvertToAudio/index.js) lambda function does the following:

1. Fetches the post metadata from the posts table
2. Splits the text into chunks (if text is larger than 2600 characters)
3. Invokes [Polly synthesizeSpeech](https://docs.aws.amazon.com/polly/latest/dg/API_SynthesizeSpeech.html) with the text and saves them to a local file
4. Uploads the audio file to the S3 bucket
5. Updates the post metadata in the posts table with the S3 audio url and sets the status to **UPDATED**

### GetPost Lambda Function
The [GetPost](https://github.com/eelayoubi/aws-serverless-text-to-speech/blob/main/functions/ConvertToAudio/index.js) lambda function retrieves the post(s):
- If postId (querystring) is "*", the function will return all posts in the posts table
- If postId is a post Id, the function will return that specific post (if it exists) or an empty array.

## Clean-up
Don't forget to clean everything up by running:

```
terraform destroy -auto-approve
```

## Wrap-up
In this article I presented the Text-To-Speech serverless application. In the next article, I will go through how we can handle errors that our lambda could encounter, and how to process them in the API gateway. 

Until then, thank you for reading this article. I hope you found it useful 👋🏻.