Build a Hamilton Song Recommendation SMS Bot with Machine Learning
Tags: twilio, machinelearning, azure, javascript
Published: 2020-06-29 22:27:02

---
title: Build a Hamilton Song Recommendation SMS Bot with Machine Learning
published: true
description: What Hamilton song should you listen to right now? Recommend a song from the hit Broadway show and DisneyPlus movie using Twilio Functions and SMS, Microsoft Azure Cognitive Services, and Naive Bayes.
tags: twilio, machinelearning, azure, javascript
cover_image: https://twilio-cms-prod.s3.amazonaws.com/images/ham.width-1616.png
---
[Hamilton the Musical will start streaming on Disney Plus](https://www.disneyplus.com/movies/hamilton/3uPmBHWlO6HJ) this Friday, so happy Hamilfilm week! To celebrate, learn how to build a SMS chatbot that recommends the Hamilton song most relevant to you right now using [Twilio Programmable SMS](https://www.twilio.com/sms) and [Functions](https://www.twilio.com/console/functions/manage), [Microsoft Azure Cognitive Services](https://azure.microsoft.com/en-us/services/cognitive-services/), and JavaScript.


See it in-action: text how you’re feeling to <strong>+13364295064</strong>. The longer and more descriptive your message is, the more data the app has to analyze what Hamilton song you need now!

![sms image](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-06-29_at_5.35.24_PM.width-1600.png)

## Prerequisites and setting up Azure Cognitive Services
To follow along with this post, you need three things:
- A Twilio account - sign up for a free one here and [receive an extra $10 if you upgrade through this link](http://www.twilio.com/referral/iHsJ5D)
- A Twilio phone number with SMS capabilities - [configure one here](https://www.twilio.com/console/phone-numbers/search)
- Microsoft Azure - [make a free account here if you don't have one already](https://azure.microsoft.com/en-us/free/cognitive-services/)

To use Azure Cognitive Services, you will need an Azure key and endpoint. Follow the [directions here to create a Cognitive Services resource using the Azure services portal](https://docs.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account).
![Azure services create](https://twilio-cms-prod.s3.amazonaws.com/images/KJIpr1OafGljqivhIUAnKpUqfrdVC4IMijXA-_uI5LRDU.width-1600.png)
After filling out the Resource, click <em>Create</em>. Once your Resource deploys, click <em>Go to resource</em>. You should see your endpoint and key in the quickstart pane that opens, or you can also click <em>Keys and Endpoint</em> beneath <em>Resource Management</em> on the left-hand pane.
![keys and endpoint](https://twilio-cms-prod.s3.amazonaws.com/images/d7xMFHKh_WQbCTi5KDorDar6gZ2gVy5D-Rn3ZdiCWSitL.width-1600.png)
If you are shown two keys, you will only need the first one which we will now configure to be the value for an environment variable.

## Configure Twilio Functions with Azure
[Configure your Twilio Functions](https://www.twilio.com/console/functions/configure) with your Azure endpoint and key as environment variables from the last step.
![configure env variables](https://twilio-cms-prod.s3.amazonaws.com/images/Df6TvRipDSRisJTzVgjmrQFWS2S5O6fArm37I9iCGIZZZ.width-1600.png)

Then add the dependencies `@azure/ai-text-analytics 1.0.0` and `whichx *` as shown below. This post also uses `Whichx`, a naive Bayesian classifier that can succinctly and cleanly analyze data. You can [read more on Naive Bayes here](https://www.twilio.com/blog/top-5-ml-algorithms-to-know).
![dependencies configure](https://twilio-cms-prod.s3.amazonaws.com/images/qW7JN6PQh4zGGRVyXIC387m8XeAzPwtNjcxDSInhPc65G.width-1600.png)
Click <em>Save</em> and you can now use Azure AI Text Analytics and reference your Azure endpoint and key in any of your Twilio Functions!

## Make a Twilio Function
On the left-hand panel underneath Functions, click <em>[Manage](https://www.twilio.com/console/functions/manage)</em>. To make a new Function, click the red plus button and then select a <em>Blank</em> template followed by <em>Create</em>.
![blank Function template](https://twilio-cms-prod.s3.amazonaws.com/images/hzpT5u5tjnT4gtOegp0tVBcM0Z33i-Yg1-5AOoDMxdd_V.width-1600.png)
Give your Function a name like "What Ham Song do you need" and a path, like "/hamilfilm".
![Function name and path](https://twilio-cms-prod.s3.amazonaws.com/images/-Tkvle_WTVtVyE2qNydAD1porW43Mnwp6oFS5ykct50o_.width-1600.png)

## Analyze an inbound SMS using Azure Cognitive Services and Naive Bayes with Node.js
Replace the Function code with the following:
```javascript
const { TextAnalyticsClient, AzureKeyCredential } = require("@azure/ai-text-analytics");
const WhichX = require("whichx");
exports.handler = async function(context, event, callback) {
        let twiml = new Twilio.twiml.MessagingResponse();
        const key = context.AZURE_KEY_HAMILFILM;
        const endpoint = context.AZURE_ENDPOINT_HAMILFILM;
        const textAnalyticsClient = new TextAnalyticsClient(endpoint,  new AzureKeyCredential(key));
        const input = [
            event.Body
        ];
        const songs = {
    "non-stop": {
        desc: "You work a lot. You work too hard and do not sleep much, but it is how you get ahead. Keep pushing forward, maybe take some risks.",
        link: "youtube.com/watch?v=_YHVPNOHySk"
    },
    "wait for it": {
        desc: "Lost, doubtful, confused, maybe sad or down, and you do not know what to do? Good things take time. You will get praise, recognition, and validation soon. If you're doubting yourself, just keep going. You are inimitable, an original.",
        link: "youtube.com/watch?v=ulsLI029rH0"
    },
    "schuyler sisters": {
        desc: "Girl power! Queens. Sisters. You are empowered and thus empower others. Keep your siblings and friends close. You may be looking for a significant other, a friend, a peer, or a general mind at work.",
        link: "youtube.com/watch?v=UeqKF_NF1Qs"
    },
    "dear theodosia": {
        desc: "You get teary over your kid or your pet like when your dog is sleeping. They are cute, young, innocent, and have their whole lives ahead of them, which you will make better.",
        link: "youtube.com/watch?v=TKpJjdKcjeo"
    },
    "story of tonight": {
        desc: "You may be emotional over what you, your friends, and your family will do in the future. The night is still young. You can all do so much and change the world!",
        link: "youtube.com/watch?v=3vqwrepaMR0"
    },
    "my shot": {
        desc: "You may be confused or unsure. Life is tough but you are tougher. All you need is one chance, one shot, and you do not know what to do right now. Well here is the inspiration and motivation you need to accomplish anything.",
        link: "youtube.com/watch?v=Ic7NqP_YGlg"
    },
    "alexander hamilton": {
        desc: "You save time by reading summaries. You do not get the hype over Alexander Hamilton or know the story. Hamilton may be new to you. This song will sum it up succinctly for you and you'll learn some history too.",
        link: "youtube.com/watch?v=VhinPd5RRJw"
    }
    };
    
    const sentimentResult = await textAnalyticsClient.analyzeSentiment(input);
    let sentiment, pos, neg, neutral, max;
    
    sentimentResult.forEach(document => {
        console.log(`ID: ${document.id}`);
        console.log(`Document Sentiment: ${document.sentiment}`);
        console.log(`Positive: ${document.confidenceScores.positive.toFixed(2)} Negative: ${document.confidenceScores.negative.toFixed(2)} Neutral: ${document.confidenceScores.neutral.toFixed(2)}`);
        document.sentences.forEach(sentence => {
            sentiment = sentence.sentiment;
            console.log(`Sentence sentiment: ${sentiment}`);
            pos = sentence.confidenceScores.positive.toFixed(2);
            neg = sentence.confidenceScores.negative.toFixed(2);
            neutral = sentence.confidenceScores.neutral.toFixed(2);
            var obj = {"positive": pos, "negative": neg, "neutral": neutral};
            max = Object.keys(obj).reduce((a, b) => obj[a] > obj[b] ? a : b);
        });
    });
   
    //Build our Bayesian model
    var whichfw = new WhichX();
     whichfw.addLabels(["non-stop", "wait for it", "schuyler sisters", "dear theodosia", "story of tonight", "my shot", "alexander hamilton"]);
    Object.keys(songs).forEach((s) => { whichfw.addData(s.toLowerCase(), songs[s].desc) } );
    const song = whichfw.classify(event.Body); 
    const reasonWhySong = songs[song].desc;
    const link = songs[song].link;
    twiml.message(`You seem to be feeling ${max}. ${reasonWhySong} We recommend listening to ${song} right now: ${link}`);
    callback(null, twiml);
};
```
Wow, that's a lot of code. Let's break it down.

We import <em>Azure AI Text Analytics</em> and <em>WhichX</em> at the top with:
```javascript
const { TextAnalyticsClient, AzureKeyCredential } = require("@azure/ai-text-analytics");
const WhichX = require("whichx");
```
Then we make our Function asynchronous to give the Function more time to analyze the inbound SMS input, make a `MessagingResponse` object that we will later return as an outbound SMS, create variables referencing our Azure endpoint and key environment variables, and pass them to `textAnalyticsClient`. Lastly, we pass in the inbound text message body to an array `input`.

```javascript
exports.handler = async function(context, event, callback) {
        let twiml = new Twilio.twiml.MessagingResponse();
        const key = context.AZURE_KEY_HAMILFILM;
        const endpoint = context.AZURE_ENDPOINT_HAMILFILM;
        const textAnalyticsClient = new TextAnalyticsClient(endpoint,  new AzureKeyCredential(key));
        const input = [
            event.Body
        ];
```
Next we make the key-value object holding the collection of Hamilton songs the user can be classified as. Each song has a brief corresponding description the classifier will attempt to match to according to the inbound SMS.
```javascript
const songs = {
    "non-stop": {
        desc: "You work a lot. You work too hard and do not sleep much, but it is how you get ahead. Keep pushing forward, maybe take some risks.",
        link: "youtube.com/watch?v=_YHVPNOHySk"
    },
        //complete songs object code on GitHub: https://github.com/elizabethsiegle/hamilton_song_recommender_azure_cog_services/blob/master/index.js
        ...
};
```
Now we call our client's `analyzeSentiment` method, which returns a `SentimentBatchResult` object, and create some global variables.
```javascript
const sentimentResult = await textAnalyticsClient.analyzeSentiment(input);
let sentiment, pos, neg, neutral, max;
```
Iterate through the list of results, and print each document's ID and document-level sentiment (analyzes the whole text) with confidence scores. For each document, `result` contains sentence-level sentiment (analyzes just a sentence) along with confidence scores (percent confident the model is that the sentiment is positive, negative, or neutral) and more information that we do not need for this post. Lastly, we find the key (positive, negative, or neutral) that has the highest confidence level value.
```javascript
sentimentResult.forEach(document => {
        console.log(`ID: ${document.id}`);
        console.log(`Document Sentiment: ${document.sentiment}`);
        console.log(`Positive: ${document.confidenceScores.positive.toFixed(2)} Negative: ${document.confidenceScores.negative.toFixed(2)} Neutral: ${document.confidenceScores.neutral.toFixed(2)}`);
        document.sentences.forEach(sentence => {
            sentiment = sentence.sentiment;
            console.log(`Sentence sentiment: ${sentiment}`);
            pos = sentence.confidenceScores.positive.toFixed(2);
            neg = sentence.confidenceScores.negative.toFixed(2);
            neutral = sentence.confidenceScores.neutral.toFixed(2);
            var obj = {"positive": pos, "negative": neg, "neutral": neutral};
            max = Object.keys(obj).reduce((a, b) => obj[a] > obj[b] ? a : b);
        });
    });
```
Finally, we build our naive Bayesian classifier, using it to classify the inbound text according to Hamilton songs by adding the labels of the Hamilton songs we want to classify. You could build a classifier in a variety of ways, but this is a succinct way to do so.
```javascript
 //Build our Bayesian model
    var whichfw = new WhichX();
    whichfw.addLabels(["non-stop", "wait for it", "schuyler sisters", "dear theodosia", "story of tonight", "my shot", "alexander hamilton"]);
    Object.keys(songs).forEach((s) => { whichfw.addData(s.toLowerCase(), songs[s].desc) } );
    const song = whichfw.classify(event.Body); 
    const reasonWhySong = songs[song].desc;
    const link = songs[song].link;
    twiml.message(`You seem to be feeling ${max}. ${reasonWhySong} We recommend listening to ${song} right now: ${link}`);
    callback(null, twiml);
};
```
Save your Function. You can [view the complete code on GitHub here](https://github.com/elizabethsiegle/hamilton_song_recommender_azure_cog_services). Let's now configure a Twilio phone number to analyze text messages to it, sending back the recommended Hamilton song.

## Configure your Twilio Phone Number with a Twilio Function
If you don't have a Twilio number yet, go to the [Phone Numbers section of your Twilio Console](https://www.twilio.com/console/phone-numbers) and search for a phone number in your country and region, making sure the SMS checkbox is ticked.
![buy a number in console](https://twilio-cms-prod.s3.amazonaws.com/images/oB2GQaf2Nt8sO54XFMXQ9Hg92bX7d3H182iaPkV8-mtfo.width-1600.png)
In the <em>Messaging</em> section of your purchased number, in the <em>A Message Comes In</em> section, set the dropdown menu to <em>Function</em> instead of <em>Webhook</em> and then on the right select your Function from the larger dropdown menu, as shown below. Hit <em>Save</em>.
![configure Twilio number with Function](https://twilio-cms-prod.s3.amazonaws.com/images/3hgtacv1puyGkCOlGms-9Og17qTkT3JR2ft0TYTJwrHKn.width-1600.png)
Whip out your phone and text your Twilio number how you are feeling to see what Hamilton song you should listen to right now.
![sms example 2](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-06-29_at_5.37.22_PM.width-1600.png)

## What's Next for Recommending Hamilton Songs
![hamilton spin dance gif](https://twilio-cms-prod.s3.amazonaws.com/original_images/vcBxPWJ1smeBeXuRbcxxviAXT358uIxijmJ5jTvEuSCyfciMNCcySXeqIfQf1ytjH1HriX0X_nxKpL)
I will be listening to Hamilton to celebrate Hamilton coming to Disney Plus. In the meantime, you can use different tools to analyze texts like IBM Watson, Google Cloud Natural Language, TensorFlow.js, and more. You could also recommend a Hamilton lyric (must include "You're On Your Own. Awesome. Wow! Do You Have A Clue What Happens Now?".)  

I'll be livestreaming the 1st and Thursday of each month on [Twitch](https://twitch.tv/lizziepikachu), and July 2nd will be a Hamilton quote chatbot with some different libraries, products, and algorithms!

Let me know what you're building and what your favorite Hamilton song is online or in the comments.
- Twitter: [@lizziepika](https://twitter.com/lizziepika)
- GitHub: [elizabethsiegle](https://github.com/elizabethsiegle)
- Email: lsiegle@twilio.com