Hardware components | ||||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
Movie World is my first Alexa Skill. I have developed this skill to get information about movies world and compete within this contest (hoping for a Dot and a T-short :) ). It's build around TMDb (The Movie DB)'s Public API for getting movie information and other details. The API is free for developers. The application is hosted as Lambda Function in Amazon AWS.
Prerequisites- Basic Knowledge of JavaScript and Node.js
- Amazon AWS Account for deploying Lambda Function
- Amazon Developer Account for publishing the skill
- Echosim.io for Testing
The Movie World (even if initial intended to help users calls their favorite actors :) ) offers, till now, some only some functionalities:
- Tells which are the most popular movies - generally or within a specific genre - and what are their casts.
- Tells if someone is known into the movie world and for which movies.
- Tells if two actors performed together in movies.
- More to come.
The application' intents are:
- AskActorIntent - To search for an actor or movie related person.
- AskMovieIntent - To know which are mos popular movies.
- MatchPersonsIntent - To match movies into which actors performed together.
- PersonMovies Intent - To know about top movies by a actor or director.
The Intent Schema looks like:
{
"intents": [
{
"intent": "HelloMovieWorldIntent"
},
{
"intent": "AskMovieIntent",
"slots":[
{
"name":"NBMOVIES",
"type":"AMAZON.NUMBER"
}
]
},
{
"intent": "AskActorIntent",
"slots":[
{
"name":"ACTORNAME",
"type":"ACTOR_NAME"
}
]
},
{
"intent": "AMAZON.HelpIntent"
}
]
}
These are the custom slots used by Movie World so far:
ACTOR_NAME
Tom Hanks | Angelina Jolie | Brad Pitt | Robert Redford
GoalThe primary goal was for me to accommodate with Alexa the Amazon's voice platform and eventually to win an Amazon Alexa Echo Dot even if I will be happy with an Alexa T-shirt.
Alexa flows diagram: // JavaScript Document
/* eslint-disable func-names */
/* eslint quote-props: ["error", "consistent"]*/
/**
* This sample demonstrates a simple skill built with the Amazon Alexa Skills
* nodejs skill development kit.
* This sample supports en-US lauguage.
* The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
* as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-trivia
**/
'use strict';
const Alexa = require('alexa-sdk');
const https = require('https');
const arrDigits =[
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten"
];
const APP_NAME = 'Movie World';
const APP_ID = 'amzn1.ask.skill.xxx';
const APP_STATES = {
TRIVIA: '_TRIVIAMODE', // Asking trivia questions.
START: '_STARTMODE', // Entry point, start the app.
HELP: '_HELPMODE', // The user is asking for help.
};
const newSessionHandlers = {
/**
* Entry point. Start a new app on new session. Handle any setup logic here.
*/
'NewSession': function () {
this.handler.state = APP_STATES.START;
if (this.event.request.type === 'LaunchRequest') {
this.emitWithState('AppStart', true);
} else if (this.event.request.type === 'IntentRequest') {
//console.log(`current intent: ${this.event.request.intent.name
// }, current state:${this.handler.state}`);
const intent = this.event.request.intent.name;
//console.log(`nume intent: ${intent}`);
this.emitWithState(intent);
}
},
'SessionEndedRequest': function () {
const speechOutput = 'OK, Goodbye!';
this.emit(':tell', speechOutput);
},
};
const createStateHandler = Alexa.CreateStateHandler;
const triviaStateHandlers = createStateHandler(APP_STATES.START, {
'HelloMovieWorldIntent': function() {
const speechOutput = 'Welcome to Movie World! We\'re very happy to hear you. Let\'s start our conversation. Ask me anything you want to know about movie world.';
//console.log(`Din Movie World intent!`);
this.emit(':tell', speechOutput);
},
'AppStart': function() {
const speechOutput = 'Welcome to Movie World! I love you Ecaterina! Now, let\'s start our conversation.';
//console.log(`Din Movie World intent!`);
this.emit(':tell', speechOutput);
},
'AskActorIntent' : function() {
var filme = [];
var strActorName = this.event.request.intent.slots.ACTORNAME.value;
var objP = this;
if ((typeof(strActorName) !== 'undefined')) {
//if (intNbMovies > 10) {
// intNbMovies = 10;
//}
var strActorNameSanit = strActorName.replace(/ /g, "%20");
console.log(`Actorul sanitizat: `+strActorNameSanit)
var options = {
"method": "GET",
"hostname": "api.themoviedb.org",
"port": null,
"path": "/3/search/person?include_adult=true&page=1&query="+strActorNameSanit+"&language=en-US&api_key=ddd",
"headers": {}
};
var req = https.request(options, function (res) {
var chunks = [];
//console.log(`A intrat in responsul lui request...`);
res.on("data", function (chunk) {
chunks.push(chunk);
//console.log(`Scrie data...`);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
//console.log(body.toString());
//console.log(`Am scris data.`);
var objData = JSON.parse(body);
var speechOutput = '';
if (typeof(objData) !== 'undefined'){
if (objData["results"].length < 1) {
speechOutput += 'Sorry, we don\'t know who \"'+ strActorName +'\" is. Please try again with a real comedian !';
//this.emit(':tell', speechOutput);
}else{
speechOutput += 'Yes \"'+ strActorName +'\" is known in the Movie World for the folowing movies:';
for (var i = 0, len = objData["results"][0]["known_for"].length; i < len; i++) {
filme[i] = (typeof(objData["results"][0]["known_for"][i].title) !== 'undefined' ? objData["results"][0]["known_for"][i].title : objData["results"][0]["known_for"][i].name);
}
var intLimit = 10;
if(filme.length < intLimit){
intLimit = filme.length;
}
for (var j = 0, ln = intLimit; j < ln; j++) {
if(j == (ln-1)){
speechOutput += ' and';
}
speechOutput += ' the number ' + arrDigits[(j+1)] + ' is \"' + filme[j].replace(/!'[\W_]+/g," ") +'\"';
if(j < (ln-2) ){
speechOutput += ',';
}
}
}
//'Please look into the Alexa logs.';
//console.log(`Uita-te in loguri ca urmeaza promptul !`);
//console.log(speechOutput);
objP.emit(':tell', speechOutput.toString());
}else{
speechOutput += ' Ups this is a technical issue: unfortunatelly the web service didn\'t answer properly. Please try again! ';
this.emit(':tell', speechOutput);
}
//console.log(JSON.stringify(this, null, 4));
//console.dir(this, { depth: null })
//const speechOutput1 = speechOutput;
//this.emit(':tell', speechOutput);
});
});
//console.log(`Inainte de req.write`);
req.write("{}");
//console.log(`Dupa de req.write`);
req.end();
//console.log(`Dupa de req.end`);
} else{
const speechOutput = 'Sorry, we didn\'t understand who you asked for. Please try again with a real actor!';
this.emit(':tell', speechOutput);
}
},
'AskMovieIntent': function() {
var filme = [];
var intNbMovies = this.event.request.intent.slots.NBMOVIES.value;
var objP = this;
if ((typeof(intNbMovies) !== 'undefined') && (intNbMovies > 0)) {
if (intNbMovies > 10) {
intNbMovies = 10;
}
var options = {
"method": "GET",
"hostname": "api.themoviedb.org",
"port": null,
"path": "/3/discover/movie?page=1&include_video=true&include_adult=false&sort_by=popularity.desc&language=en-US&api_key=ddd",
"headers": {}
};
var req = https.request(options, function (res) {
var chunks = [];
//console.log(`A intrat in responsul lui request...`);
res.on("data", function (chunk) {
chunks.push(chunk);
//console.log(`Scrie data...`);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
//console.log(body.toString());
//console.log(`Am scris data.`);
var objData = JSON.parse(body);
var speechOutput = '';
if (typeof(objData) !== 'undefined'){
if (objData["results"].length < intNbMovies) {
intNbMovies = objData["results"].length;
}
for (var i = 0, len = intNbMovies; i < len; i++) {
filme[i] = objData["results"][i].title;
}
//console.log(filme.toString());
if(intNbMovies == 1){
speechOutput += 'The best movie is \"' + filme[0] +'\"';
}else{
speechOutput += 'The best ' + arrDigits[intNbMovies] + ' movies are: ';
for (var j = 0, ln = filme.length; j < ln; j++) {
if(j == (ln-1)){
speechOutput += ' and';
}
speechOutput += ' the number ' + arrDigits[(j+1)] + ' is \"' + filme[j] +'\"';
if(j < (ln-2) ){
speechOutput += ',';
}
}
}
//'Please look into the Alexa logs.';
//console.log(`Uita-te in loguri ca urmeaza promptul !`);
//console.log(speechOutput);
objP.emit(':tell', speechOutput.toString());
}else{
speechOutput += ' Ups this is a technical issue: unfortunatelly the web service didn\'t answer properly. Please try again! ';
this.emit(':tell', speechOutput);
}
//console.log(JSON.stringify(this, null, 4));
//console.dir(this, { depth: null })
//const speechOutput1 = speechOutput;
//this.emit(':tell', speechOutput);
});
});
//console.log(`Inainte de req.write`);
req.write("{}");
//console.log(`Dupa de req.write`);
req.end();
//console.log(`Dupa de req.end`);
} else{
const speechOutput = 'You should tell me how many movies do you want to have into the response.';
//console.log(`Numar filme nu e specificat !`);
this.emit(':tell', speechOutput);
}
},
'AnswerIntent': function () {
//handleUserGuess.call(this, false);
},
'DontKnowIntent': function () {
//handleUserGuess.call(this, true);
},
'AMAZON.StartOverIntent': function () {
this.handler.state = APP_STATES.START;
this.emitWithState('AppStart', false);
},
'AMAZON.RepeatIntent': function () {
this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptText);
},
'AMAZON.HelpIntent': function () {
this.handler.state = APP_STATES.HELP;
this.emitWithState('helpTheUser', false);
},
'AMAZON.StopIntent': function () {
this.handler.state = APP_STATES.HELP;
const speechOutput = 'Would you like to keep talking?';
this.emit(':ask', speechOutput, speechOutput);
},
'AMAZON.CancelIntent': function () {
this.emit(':tell', 'Ok, let\'s talk again soon.');
},
'Unhandled': function () {
const speechOutput = 'Would you like to keep talking?';
this.emit(':ask', speechOutput, speechOutput);
},
'SessionEndedRequest': function () {
const speechOutput = 'OK, Goodbye!';
this.emit(':tell', speechOutput);
},
});
const helpStateHandlers = createStateHandler(APP_STATES.HELP, {
'helpTheUser': function (newApp) {
const askMessage = newApp ? 'Would you like to start Movie World?' : 'To repeat the last question, say, repeat. Would you like to keep using Movie World?';
const speechOutput = ` Here are a few examples of things you can say:`
+ ` What are the most popular movies `
+ ` What are the best drama\'s . ${askMessage}`;
const repromptText = `To give an answer to a question, respond with the number of the answer . ${askMessage}`;
this.emit(':ask', speechOutput, speechOutput);
},
'StartApp': function () {
this.handler.state = APP_STATES.START;
this.emitWithState('AppStart', false);
},
'AMAZON.RepeatIntent': function () {
this.emitWithState('helpTheUser');
},
'AMAZON.HelpIntent': function () {
this.emitWithState('helpTheUser', false);
},
'AMAZON.YesIntent': function () {
if (this.attributes.speechOutput && this.attributes.repromptText) {
this.handler.state = APP_STATES.TRIVIA;
this.emitWithState('AMAZON.RepeatIntent');
} else {
this.handler.state = APP_STATES.START;
this.emitWithState('StartApp', false);
}
},
'AMAZON.NoIntent': function () {
const speechOutput = 'Ok, we\'ll talk another time. Goodbye!';
this.emit(':tell', speechOutput);
},
'AMAZON.StopIntent': function () {
const speechOutput = 'Would you like to keep talking?';
this.emit(':ask', speechOutput, speechOutput);
},
'AMAZON.CancelIntent': function () {
this.handler.state = APP_STATES.TRIVIA;
this.emitWithState('AMAZON.RepeatIntent');
},
'Unhandled': function () {
const speechOutput = 'Say yes to continue, or no to end the session.';
this.emit(':ask', speechOutput, speechOutput);
},
'SessionEndedRequest': function () {
const speechOutput = 'OK, Goodbye!';
this.emit(':tell', speechOutput);
},
});
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
alexa.registerHandlers(newSessionHandlers, triviaStateHandlers, helpStateHandlers);
alexa.appId = APP_ID;
alexa.execute();
};
{
"intents": [
{
"intent": "HelloMovieWorldIntent"
},
{
"intent": "AskMovieIntent",
"slots":[
{
"name":"NBMOVIES",
"type":"AMAZON.NUMBER"
}
]
},
{
"intent": "AskActorIntent",
"slots":[
{
"name":"ACTORNAME",
"type":"ACTOR_NAME"
}
]
},
{
"intent": "AMAZON.HelpIntent"
}
]
}
HelloMovieWorldIntent say hello
AskMovieIntent which the {NBMOVIES} most popular movies are
AskMovieIntent what are the {NBMOVIES} most popular movies
AskMovieIntent which are the {NBMOVIES} most popular movies
AskActorIntent if {ACTORNAME} is an actor
AskActorIntent who {ACTORNAME} is
AskActorIntent if {ACTORNAME} is an actress
AskActorIntent if {ACTORNAME} is a comedian
AskActorIntent is {ACTORNAME} an actress
AskActorIntent is {ACTORNAME} an actor
AskActorIntent is {ACTORNAME} a comedian
Comments