Alexa knows English pretty well, but what does it take to translate Pig Latin? Say you want to know the weather, but keep it a secret from others in the room. Ask Alexa the weather in Pig Latin!
Hello WorldThis project allows a user to ask Alexa to translate an English phrase into Pig Latin AND ask Alexa the weather in Pig Latin. To do this, we will set up an Alexa Skill and Lambda Function to take a user's phrase and return the appropriate response in Pig Latin.
To translate into Pig Latin, we apply the following basic algorithm, using the phrase "Tell me the story" as an example:
- Split the phrase into words ["Tell", "me", "the", "story"]
- Move everything before the first vowel to the end ["ellt", "em", "eth", "oryst"]
- add "ay" ["elltay", "emay", "ethay", "orystay"]
There's a catch: in Pig Latin, you keep the pronunciation of each letter as it was in the original English word. However, by default, Alexa will attempt to pronounce Pig Latin words using English phonetics. We can fix this by telling Alexa exactly how to pronounce words with Alexa's Speech Synthesis Markup Language (SSML). Using a pronunciation dictionary, we can look up the phoneme string of individual words, and translate these words as phonemes. When we give our response to Alexa, we'll use <phoneme>.
Doing the weather has its own quirks as well: since we're translating a weather forecast, we need to handle abbreviations (SW winds) and numbers (85F needs to read "eighty-five degrees Fahrenheit") to translate properly.
The Alexa SkillThere are three parts to an Alexa Skill: the Sample Utterances, the Intent Schema, and a reference to a Lambda Function (basically a Node.js project).
To begin, from the Skills Kit Dashboard, start a new Alexa Skill. Give it a good name, like "Pig Latin".
Define a few custom slots, for CITY_TYPES, PHRASE_TYPES, and STATE_TYPES. They don't have to be 100%, but the more you add the better Alexa will handle them. In the end, they'll look something like this:
Use the following Intent Schema:
{
"intents": [
{
"intent": "PhraseIntent",
"slots": [
{
"name": "phrase",
"type": "PHRASE_TYPES"
}
]
},
{
"intent": "WeatherIntent",
"slots": [
{
"name": "city",
"type": "CITY_TYPES"
},
{
"name": "state",
"type": "STATE_TYPES"
}
]
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.StopIntent"
}
]
}
For Sample Utterances, try this:
WeatherIntent what's the weather in {city} {state}
WeatherIntent the weather in {city} {state}
PhraseIntent translate {phrase}
PhraseIntent convert {phrase}
PhraseIntent say {phrase} in pig latin
PhraseIntent say {phrase}
PhraseIntent {phrase}
PhraseIntent what is {phrase}
PhraseIntent what is {phrase} in pig latin
The next part is the Configuration, which asks you to connect a Lambda Function.
The Lambda FunctionIn a new tab, go to the Lambda Dashboard and create a new Function.
- Use "alexa-skills-kit-color-expert" as a blueprint and give your function a name like "alexaPigLatin".
- In "Lambda function handler role" dropdown, pick "lambda_basic_execution"
- Click Next and complete creation
- You'll see a line like "arn:aws:lambda:us-east-1:132258566240:function:alexaPigLatin" in the top right. This is your identifier. Copy this identifier and return to your Alexa Skill Configuration page.
- Paste it like so:
Keep the Lambda Function tab open; we'll be uploading our code there in a minute.
Next, we need to build the Lambda Function as a Node.js project, then zip and upload it to the AWS Lambda Dashboard. In a console, type:
mkdir alexa-pig # make the program directory
cd alexa-pig
npm init
touch translator.js
# Next are weather functions
npm install --save node-weatherunderground
npm install --save dotenv
touch .env
This code is going to build from the Alex Hello World sample on GitHub. Clone the repository, and put src/helloWorld/index.js and src/helloWorld/AlexaSkill.js in your fresh Node project
In index.js, add the following variables to the top:
require('dotenv').config();
var Translator = require('./translator');
var translator = new Translator();
var Wunderground = require('node-weatherunderground');
Change the function `HelloWorld.prototype.intentHandlers` to the following:
HelloWorld.prototype.intentHandlers = {
// register custom intent handlers
"AMAZON.HelpIntent": function (intent, session, response) {
response.ask("You can speak a phrase to be translated into Pig Latin, or you can ask the weather in a specific city and state. For example, say 'what is the weather in Seattle Washington'. You can say 'stop' to end. What would you like to translate?", "What would you like to translate?");
},
"AMAZON.StopIntent": function (intent, session, response) {
response.tell("Goodbye.");
},
"PhraseIntent": function (intent, session, response) {
if (!intent.slots.phrase.value) {
response.ask("You can speak a phrase to be translated into Pig Latin, or you can ask the weather in a specific city and state. For example, say 'what is the weather in Seattle Washington'. You can say 'stop' to end. What would you like to translate?", "What would you like to translate?");
} else {
translator.translate(intent.slots.phrase.value, "Here is your phrase in Pig Latin", function(result){
// speechOutput, cardTitle, cardContent
response.tellWithCard(result, "Translate Result", "phrase: " + intent.slots.phrase.value);
});
}
},
"WeatherIntent": function (intent, session, response) {
// Get the
var client = new Wunderground(process.env.API_KEY, intent.slots.city.value, intent.slots.state.value);
client.forecast('', function(err, data){
console.log("result", err, JSON.stringify(data));
// If it worked
var string = "";
if(err || data.txt_forecast === undefined) {
console.log(err);
string = "Could not find " + intent.slots.city.value + ", " + intent.slots.state.value + ". What would you like to translate?";
response.askWithCard(string, "eather-way", "phrase: " + string);
} else {
// for( var i = 0; i < data.txt_forecast.forecastday.length; i++ ) {
for( var i = 0; i < 2; i++ ) {
var day = data.txt_forecast.forecastday[i];
string += day.title + ", " + day.fcttext + "\n";
}
translator.translate(string, "Here is the weather for " + intent.slots.city.value + " " + intent.slots.state.value + " in Pig Latin", function(result){
// speechOutput, cardTitle, cardContent
response.tellWithCard(result, "eather-way", "Here is the weather for " + intent.slots.city.value + " " + intent.slots.state.value + ": " + string);
});
}
});
}
};
Our translate.js file contains the functions that do the translation and pronunciation, which we'll go over in the next section.
Translate to Pig Latintranslator.js looks like this:
'use strict';
var CMUDict = require('./cmudict');
function Translator() {
this._cache = null;
}
Translator.prototype.translate = function(phrase, language, cb){
var result = {
"type":"SSML",
"speech":"<speak>" + translatePigLatin(phrase) + "</speak>"
};
return cb(result);
};
function translatePigLatin(phrase) {
console.log("translating:", phrase);
var result = "";
var phrase_array = phrase.split(" ");
for (var i = 0; i < phrase_array.length; i++) {
var word = phrase_array[i];
var phoneme_str = CMUDict.get(word);
if(phoneme_str === undefined) {
result += " " + word + " ";
} else {
var phoneme_str_pig = phoneme_str.substr(1) + phoneme_str.charAt(0) + "eɪ"; result += "<phoneme alphabet='ipa' ph='" + phoneme_str_pig + "'>" + word + "</phoneme>"
}
}
console.log("result:", result);
return result;
}
module.exports = Translator;
This calls a pronunciation dictionary file I fashioned for this purpose. Add cmudict.js and cmudict.json to your Node.js project. This file does its best to find a pronunciation for the word it receives.
That's it! Zip up the project (all the files in the folder, not the folder itself) and upload it to the Lambda Function you created earlier.
TestingTest it by going back to your Alexa Skill and typing something into the test area. With the app on your device, you can say "Alexa, ask Pig Latin translate blah blah blah". Test a variety of sentences! Try "I am the very model of a modern major general," "Shut up and take my money," and "One does not simply walk into Mordor" as examples.
Get the WeatherNow, to make our translator useful, we'll give it some more pertinent things to say. Our Intent Schema, Sample Utterances, and index.js:HelloWorld.prototype.intentHandlers above have weather functions in them, but we're missing an API Key. Go to Weather Underground and get an API key, then save that key in the .env file:
API_KEY=44e8ab524081ff2c
Our WeatherIntent function will create a Weather Underground API client, get a forecast for the spoken city and state, then translate that to Pig Latin.
Ask "Alexa, ask Pig Latin the weather in Chicago, Illinois".
Possible Features- Using DynamoDB, store a user's most recent city and state, so they can quickly ask "What's the weather?" to get their local forecast.
- Change the translation algorithm to some other English derivative, like Morse Code or Porky Pig speak.
- Play a game: Have Alexa say a phrase in Pig Latin, then ask the user to say it in English.
Comments