Hardware components | ||||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
Everytime we have a friends gathering, we play games related to Bollywood movies, singers etc. So I decided to build a similar skill for Amazon echo.
What is this Skill About?This skill is about playing a Bollywood Trivia game. You ask alexa to start the game, and alexa will ask 5 multiple choice questions related to bollywood movies, singers, actors etc. For every correct answer you score 1 point and for every wrong answer you score 0. At the end of 5 questions, alexa will tell you how much you scored.
This skill is been certified and is live for general use by anyone. Search for "Bollywood Trivia Game" in alexa app, under skills. Here is the link to the published skill.
Assuming that you already have a developer account, follow this Get Started link to build this custom skill.
Code a AWS lambda function for the skill
- Select Lambda from Compute service after login to console
- Skip "Select Blueprint"
- In "Configure Function", enter "Name/Description/Runtime"
- Select the ‘Code Entry Type’ as ‘Edit Code inline’ and copy/paste the Lambda function from code section below. Remember to change the App Id.
- Set the handler and role as follows: (a) keep handler as "index.handler" and (b) add a new role for "lambda_basic_execution"
- You will be asked to setup your IAM role if you have not done so.
- Keep the advanced setting as default.
- Select "Next" and review. Then "Create Your Function"
- Next create an Event Source. Select Add event source and Select type as Alexa Skills Set
- Copy the ARN for your lambda function. You will need it for setting up your skill.
Setup up skill in Developer Portal
- Sign into Developer Portal account and navigate to Apps & Services/Alexa/Alexa Skills Kit.
- Select add new skill and add name/innovation name. Select Save and Next.
- Define skill's interaction model. Cut & Paste the Intent Schema from code section below.
- Add Slot Type.
- Add the Utterances.
- Select Save and it should look like screenshot below.
- In the Configuration tab, add ARN endpoint from the Lambda function and select "No" for the account linking. Then select Next.
- Test your skill providing sample utterances. Once your testing is done, submit it for certification by clicking "next" and providing appropriate descriptions and details required.
AWS Lambda function
JavaScript/**
Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at
http://aws.amazon.com/apache2.0/
or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
/**
* This sample shows how to create a simple Trivia skill with a multiple choice format. The skill
* supports 1 player at a time, and does not support games across sessions.
*/
'use strict';
/**
* When editing your questions pay attention to your punctuation. Make sure you use question marks or periods.
* Make sure the first answer is the correct one. Set at least 4 answers, any extras will be shuffled in.
*/
var questions = [
{
"Name the first Indian actress, who won the best actress award in an International film festival?": [
"Suchitra Sen",
"Waheeda Rehmaan",
"Nootan",
"Nargis Dutt"
]
},
{
"Who joined the Cannes Film festival 2013, as Jury member?": [
"Vidya baalan",
"Sonam Kapoor",
"Aishwarya Rai",
"Amitabh Bachchan"
]
},
{
"Who was awarded best actor of the decade for period 1990 to 2000?": [
"Shahrukh Khan",
"Sunny Deol",
"Hritik Roshan",
"Amitabh Bachchan"
]
},
{
"What was Yash Chopra's first film, as a director?": [
"Dhool Ka Phool",
"Deewar",
"Dharma",
"Andaz"
]
},
{
"What is Hrithik Roshan's pet name at home?": [
"Duggu",
"Guddu",
"Pappu",
"Babloo"
]
},
{
"Who plays the lead star in the movie, Page Three?": [
"Konkana Sen",
"Rani Mukherjee",
"Nandita Das",
"Kajol"
]
},
{
"In the bollywood movie Black, Amitabh Bachchan suffers from which disease?": [
"Alzheimer's Disease",
"Blindness",
"Tuberculosis",
"Parkinson's Disease"
]
},
{
"Who produced the film, 'Phir bhi dil hai hindustani'?": [
"Sharukh Khan and Juhi Chawla",
"Jatin Lalit",
"Salman Khan and Juhi Chawla",
"Aziz Mirza"
]
},
{
"Whose first film, as a director of Main Hoon Na?": [
"Farah khan",
"Farhan Akhtar",
"Saroj Khan",
"Gauri Khan"
]
},
{
"Who is the first Indian, to win an Oscar award?": [
"Bhanu Athaiya",
"A.R. Rahman",
"Rasul Pookutty",
"Satyajit Ray"
]
},
{
"From which year, the filmfare awards started?": [
"1954",
"1972",
"1960",
"2000",
"1928"
]
},
{
"Which Shah Rukh Khan film had the tagline ‘Ready Steady Po?": [
"Chennai Express",
"Dil to pagal hai",
"Jab tak hai jaan",
"Khiladi 786",
"Ra One"
]
},
{
"Which Shah Rukh Khan film had the tagline ‘Ready Steady Po?": [
"Chennai Express",
"Dil to pagal hai",
"Jab tak hai jaan",
"Khiladi 786",
"Ra One"
]
},
{
"Who became the first Indian Director to shoot at NASA?": [
"Ashutosh Gawariker",
"A.K. Hangal",
"Kidar Sharma",
"Arjun Sarja"
]
},
{
"Who is popularly known as 'Father of Indian Cinema'?": [
"Dadasaheb Phalke",
"V. Shantaram",
"Ardeshir Irani",
"Kidar Sharma"
]
},
{
"Which book is Bombay Velvet based on?": [
"Mumbai Fables",
"Breathless in Mumbai",
"Zero Point Bombay"
]
},
{
"Who plays the villain in the Shah Rukh Khan-starrer Happy New Year?": [
"Jackie Shroff",
"Boman Irani",
"Anupam Kher",
"Sunil Shetty"
]
},
{
"What language has Saif Ali Khan reportedly learnt for Phantom?": [
"Kurdish",
"Spanish",
"German",
"Chinese"
]
},
{
"Which producer turned director with the Salman Khan-starrer Kick?": [
"Sajid Nadiadwala",
"Malaika Arora Khan",
"Rhea Kapoor"
]
},
{
"Akshay Kumar's Holiday is a remake of which Tamil film?": [
"Thuppakki",
"Dookudu",
"Stalin"
]
},
{
"Which film had Farhan Akhtar and Vidya Balan opposite each other?": [
"Shaadi Ke Side Effects",
"Humshakals",
"Pyar Ke Side Effects"
]
},
{
"Which is the first bollywood movie to have two intervals?": [
"Mera Naam Joker",
"Lagaan",
"Karantee",
"Love Aaj Kal"
]
},
{
"Which movie name has been added to the Oxford English dictionary?": [
"Bollywood",
"Pyaar",
"Diwaana",
"Kabootar"
]
},
{
"Which actor has won the most Filmfare Award for Best Actor?": [
"Dilip Kumar",
"Amitabh Bachchan",
"Shahrukh Khan",
"Aamir Khan"
]
},
{
"Which famous singer has won the most Filmfare Best Male Playback Awards?": [
"Kishore Kumar",
"Mukesh",
"Rafi",
"Sonu Nigam"
]
},
{
"In which film, more than forty-two well-known and famous Bollywood stars appeared?": [
"Om Shanti Om",
"Kranti",
"Singh is King",
"Diwar"
]
},
{
"Who was the youngest actress to win Filmfare Award for Best Actress?": [
"Dimple Kapadia",
"Madhuri Dixit",
"Shabana Azmi",
"Kareena Kapoor"
]
}
];
// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
try {
console.log("event.session.application.applicationId=" + event.session.application.applicationId);
/**
* Uncomment this if statement and populate with your skill's application ID to
* prevent someone else from configuring a skill that sends requests to this function.
*/
// if (event.session.application.applicationId !== "amzn1.echo-sdk-ams.app.05aecccb3-1461-48fb-a008-822ddrt6b516") {
// context.fail("Invalid Application ID");
// }
if (event.session.new) {
onSessionStarted({requestId: event.request.requestId}, event.session);
}
if (event.request.type === "LaunchRequest") {
onLaunch(event.request,
event.session,
function callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === "IntentRequest") {
onIntent(event.request,
event.session,
function callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === "SessionEndedRequest") {
onSessionEnded(event.request, event.session);
context.succeed();
}
} catch (e) {
context.fail("Exception: " + e);
}
};
/**
* Called when the session starts.
*/
function onSessionStarted(sessionStartedRequest, session) {
console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId
+ ", sessionId=" + session.sessionId);
// add any session init logic here
}
/**
* Called when the user invokes the skill without specifying what they want.
*/
function onLaunch(launchRequest, session, callback) {
console.log("onLaunch requestId=" + launchRequest.requestId
+ ", sessionId=" + session.sessionId);
getWelcomeResponse(callback);
}
/**
* Called when the user specifies an intent for this skill.
*/
function onIntent(intentRequest, session, callback) {
console.log("onIntent requestId=" + intentRequest.requestId
+ ", sessionId=" + session.sessionId);
var intent = intentRequest.intent,
intentName = intentRequest.intent.name;
// handle yes/no intent after the user has been prompted
if (session.attributes && session.attributes.userPromptedToContinue) {
delete session.attributes.userPromptedToContinue;
if ("AMAZON.NoIntent" === intentName) {
handleFinishSessionRequest(intent, session, callback);
} else if ("AMAZON.YesIntent" === intentName) {
handleRepeatRequest(intent, session, callback);
}
}
// dispatch custom intents to handlers here
if ("AnswerIntent" === intentName) {
handleAnswerRequest(intent, session, callback);
} else if ("AnswerOnlyIntent" === intentName) {
handleAnswerRequest(intent, session, callback);
} else if ("DontKnowIntent" === intentName) {
handleAnswerRequest(intent, session, callback);
} else if ("AMAZON.YesIntent" === intentName) {
handleAnswerRequest(intent, session, callback);
} else if ("AMAZON.NoIntent" === intentName) {
handleAnswerRequest(intent, session, callback);
} else if ("AMAZON.StartOverIntent" === intentName) {
getWelcomeResponse(callback);
} else if ("AMAZON.RepeatIntent" === intentName) {
handleRepeatRequest(intent, session, callback);
} else if ("AMAZON.HelpIntent" === intentName) {
handleGetHelpRequest(intent, session, callback);
} else if ("AMAZON.StopIntent" === intentName) {
handleFinishSessionRequest(intent, session, callback);
} else if ("AMAZON.CancelIntent" === intentName) {
handleFinishSessionRequest(intent, session, callback);
} else {
throw "Invalid intent";
}
}
/**
* Called when the user ends the session.
* Is not called when the skill returns shouldEndSession=true.
*/
function onSessionEnded(sessionEndedRequest, session) {
console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId
+ ", sessionId=" + session.sessionId);
// Add any cleanup logic here
}
// ------- Skill specific business logic -------
var ANSWER_COUNT = 4;
var GAME_LENGTH = 5;
var CARD_TITLE = "Bollywood Trivia Game"; // Be sure to change this for your skill.
function getWelcomeResponse(callback) {
var sessionAttributes = {},
speechOutput = "Bollywood Trivia Game. I will ask you " + GAME_LENGTH.toString()
+ " questions, try to get as many right as you can. Just say the number of the answer. Let's begin. ",
shouldEndSession = false,
gameQuestions = populateGameQuestions(),
correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT)), // Generate a random index for the correct answer, from 0 to 3
roundAnswers = populateRoundAnswers(gameQuestions, 0, correctAnswerIndex),
currentQuestionIndex = 0,
spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0],
repromptText = "Question 1. " + spokenQuestion + " ",
i, j;
for (i = 0; i < ANSWER_COUNT; i++) {
repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
}
speechOutput += repromptText;
sessionAttributes = {
"speechOutput": repromptText,
"repromptText": repromptText,
"currentQuestionIndex": currentQuestionIndex,
"correctAnswerIndex": correctAnswerIndex + 1,
"questions": gameQuestions,
"score": 0,
"correctAnswerText":
questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
};
callback(sessionAttributes,
buildSpeechletResponse(CARD_TITLE, speechOutput, repromptText, shouldEndSession));
}
function populateGameQuestions() {
var gameQuestions = [];
var indexList = [];
var index = questions.length;
if (GAME_LENGTH > index){
throw "Invalid Game Length.";
}
for (var i = 0; i < questions.length; i++){
indexList.push(i);
}
// Pick GAME_LENGTH random questions from the list to ask the user, make sure there are no repeats.
for (var j = 0; j < GAME_LENGTH; j++){
var rand = Math.floor(Math.random() * index);
index -= 1;
var temp = indexList[index];
indexList[index] = indexList[rand];
indexList[rand] = temp;
gameQuestions.push(indexList[index]);
}
return gameQuestions;
}
function populateRoundAnswers(gameQuestionIndexes, correctAnswerIndex, correctAnswerTargetLocation) {
// Get the answers for a given question, and place the correct answer at the spot marked by the
// correctAnswerTargetLocation variable. Note that you can have as many answers as you want but
// only ANSWER_COUNT will be selected.
var answers = [],
answersCopy = questions[gameQuestionIndexes[correctAnswerIndex]][Object.keys(questions[gameQuestionIndexes[correctAnswerIndex]])[0]],
temp, i;
var index = answersCopy.length;
if (index < ANSWER_COUNT){
throw "Not enough answers for question.";
}
// Shuffle the answers, excluding the first element.
for (var j = 1; j < answersCopy.length; j++){
var rand = Math.floor(Math.random() * (index - 1)) + 1;
index -= 1;
var temp = answersCopy[index];
answersCopy[index] = answersCopy[rand];
answersCopy[rand] = temp;
}
// Swap the correct answer into the target location
for (i = 0; i < ANSWER_COUNT; i++) {
answers[i] = answersCopy[i];
}
temp = answers[0];
answers[0] = answers[correctAnswerTargetLocation];
answers[correctAnswerTargetLocation] = temp;
return answers;
}
function handleAnswerRequest(intent, session, callback) {
var speechOutput = "";
var sessionAttributes = {};
var gameInProgress = session.attributes && session.attributes.questions;
var answerSlotValid = isAnswerSlotValid(intent);
var userGaveUp = intent.name === "DontKnowIntent";
if (!gameInProgress) {
// If the user responded with an answer but there is no game in progress, ask the user
// if they want to start a new game. Set a flag to track that we've prompted the user.
sessionAttributes.userPromptedToContinue = true;
speechOutput = "There is no game in progress. Do you want to start a new game? ";
callback(sessionAttributes,
buildSpeechletResponse(CARD_TITLE, speechOutput, speechOutput, false));
} else if (!answerSlotValid && !userGaveUp) {
// If the user provided answer isn't a number > 0 and < ANSWER_COUNT,
// return an error message to the user. Remember to guide the user into providing correct values.
var reprompt = session.attributes.speechOutput;
var speechOutput = "Your answer must be a number between 1 and " + ANSWER_COUNT + ". " + reprompt;
callback(session.attributes,
buildSpeechletResponse(CARD_TITLE, speechOutput, reprompt, false));
} else {
var gameQuestions = session.attributes.questions,
correctAnswerIndex = parseInt(session.attributes.correctAnswerIndex),
currentScore = parseInt(session.attributes.score),
currentQuestionIndex = parseInt(session.attributes.currentQuestionIndex),
correctAnswerText = session.attributes.correctAnswerText;
var speechOutputAnalysis = "";
if (answerSlotValid && parseInt(intent.slots.Answer.value) == correctAnswerIndex) {
currentScore++;
speechOutputAnalysis = "correct. ";
} else {
if (!userGaveUp) {
speechOutputAnalysis = "wrong. "
}
speechOutputAnalysis += "The correct answer is " + correctAnswerIndex + ": " + correctAnswerText + ". ";
}
// if currentQuestionIndex is 4, we've reached 5 questions (zero-indexed) and can exit the game session
if (currentQuestionIndex == GAME_LENGTH - 1) {
speechOutput = userGaveUp ? "" : "That answer is ";
speechOutput += speechOutputAnalysis + "You got " + currentScore.toString() + " out of "
+ GAME_LENGTH.toString() + " questions correct. Thank you for playing!";
callback(session.attributes,
buildSpeechletResponse(CARD_TITLE, speechOutput, "", true));
} else {
currentQuestionIndex += 1;
var spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0];
// Generate a random index for the correct answer, from 0 to 3
correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT));
var roundAnswers = populateRoundAnswers(gameQuestions, currentQuestionIndex, correctAnswerIndex),
questionIndexForSpeech = currentQuestionIndex + 1,
repromptText = "Question " + questionIndexForSpeech.toString() + ". " + spokenQuestion + " ";
for (var i = 0; i < ANSWER_COUNT; i++) {
repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
}
speechOutput += userGaveUp ? "" : "That answer is ";
speechOutput += speechOutputAnalysis + "Your score is " + currentScore.toString() + ". " + repromptText;
sessionAttributes = {
"speechOutput": repromptText,
"repromptText": repromptText,
"currentQuestionIndex": currentQuestionIndex,
"correctAnswerIndex": correctAnswerIndex + 1,
"questions": gameQuestions,
"score": currentScore,
"correctAnswerText":
questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
};
callback(sessionAttributes,
buildSpeechletResponse(CARD_TITLE, speechOutput, repromptText, false));
}
}
}
function handleRepeatRequest(intent, session, callback) {
// Repeat the previous speechOutput and repromptText from the session attributes if available
// else start a new game session
if (!session.attributes || !session.attributes.speechOutput) {
getWelcomeResponse(callback);
} else {
callback(session.attributes,
buildSpeechletResponseWithoutCard(session.attributes.speechOutput, session.attributes.repromptText, false));
}
}
function handleGetHelpRequest(intent, session, callback) {
// Provide a help prompt for the user, explaining how the game is played. Then, continue the game
// if there is one in progress, or provide the option to start another one.
// Set a flag to track that we're in the Help state.
session.attributes.userPromptedToContinue = true;
// Do not edit the help dialogue. This has been created by the Alexa team to demonstrate best practices.
var speechOutput = "I will ask you " + GAME_LENGTH + " multiple choice questions. Respond with the number of the answer. "
+ "For example, say one, two, three, or four. To start a new game at any time, say, start game. "
+ "To repeat the last question, say, repeat. "
+ "Would you like to keep playing?",
repromptText = "To give an answer to a question, respond with the number of the answer . "
+ "Would you like to keep playing?";
var shouldEndSession = false;
callback(session.attributes,
buildSpeechletResponseWithoutCard(speechOutput, repromptText, shouldEndSession));
}
function handleFinishSessionRequest(intent, session, callback) {
// End the session with a "Good bye!" if the user wants to quit the game
callback(session.attributes,
buildSpeechletResponseWithoutCard("Good bye!", "", true));
}
function isAnswerSlotValid(intent) {
var answerSlotFilled = intent.slots && intent.slots.Answer && intent.slots.Answer.value;
var answerSlotIsInt = answerSlotFilled && !isNaN(parseInt(intent.slots.Answer.value));
return answerSlotIsInt && parseInt(intent.slots.Answer.value) < (ANSWER_COUNT + 1) && parseInt(intent.slots.Answer.value) > 0;
}
// ------- Helper functions to build responses -------
function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: "PlainText",
text: output
},
card: {
type: "Simple",
title: title,
content: output
},
reprompt: {
outputSpeech: {
type: "PlainText",
text: repromptText
}
},
shouldEndSession: shouldEndSession
};
}
function buildSpeechletResponseWithoutCard(output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: "PlainText",
text: output
},
reprompt: {
outputSpeech: {
type: "PlainText",
text: repromptText
}
},
shouldEndSession: shouldEndSession
};
}
function buildResponse(sessionAttributes, speechletResponse) {
return {
version: "1.0",
sessionAttributes: sessionAttributes,
response: speechletResponse
};
}
Comments