Last active
March 13, 2017 02:44
-
-
Save c0achmcguirk/ec748f13dac70c86a52c32061b07dc6a to your computer and use it in GitHub Desktop.
Alexa developer portal settings for talk 2017-04-28
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using Alexa.NET.Request; | |
using Alexa.NET.Request.Type; | |
using Alexa.NET.Response; | |
using Amazon.Lambda.Core; | |
using Newtonsoft.Json; | |
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. | |
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] | |
namespace AlexaCountryInfo | |
{ | |
public class Function | |
{ | |
private static HttpClient _httpClient; | |
public const string INVOCATION_NAME = "Country Info"; | |
public Function() | |
{ | |
_httpClient = new HttpClient(); | |
} | |
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context) | |
{ | |
var requestType = input.GetRequestType(); | |
if (requestType == typeof(IntentRequest)) | |
{ | |
return await HandleIntentRequest(input, context); | |
} | |
else if (requestType == typeof(LaunchRequest)) | |
{ | |
return HandleLaunchRequest(input, context); | |
} | |
else if (requestType == typeof(SessionEndedRequest)) | |
{ | |
return MakeSkillResponse($"Thanks for using {INVOCATION_NAME}. Goodbye.", true); | |
} | |
else | |
{ | |
return MakeSkillResponse($"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Canada.", true); | |
} | |
} | |
/// <summary> | |
/// this request comes in when someone asks "Alexa, Open Country Info" or "Alexa, Start Country Info" | |
/// </summary> | |
/// <param name="input"></param> | |
/// <param name="context"></param> | |
/// <returns></returns> | |
private SkillResponse HandleLaunchRequest(SkillRequest input, ILambdaContext context) | |
{ | |
var launchRequest = input.Request as IntentRequest; | |
context.Logger.LogLine($"Launch request:\n{JsonConvert.SerializeObject(input)}"); | |
var outputSpeech = $"Welcome to {INVOCATION_NAME}. To ask information about a country, say, tell me about Canada. To exit, say, exit."; | |
return MakeSkillResponse(outputSpeech, false); | |
} | |
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession, string repromptText = "Just say, tell me about Canada to learn more. To exit, say, exit.") | |
{ | |
var response = new ResponseBody | |
{ | |
ShouldEndSession = shouldEndSession, | |
OutputSpeech = new PlainTextOutputSpeech {Text = outputSpeech} | |
}; | |
if (repromptText != null) | |
{ | |
response.Reprompt = new Reprompt() {OutputSpeech = new PlainTextOutputSpeech() {Text = repromptText}}; | |
} | |
var skillResponse = new SkillResponse | |
{ | |
Response = response, | |
Version = "1.0" | |
}; | |
return skillResponse; | |
} | |
private async Task<SkillResponse> HandleIntentRequest(SkillRequest input, ILambdaContext context) | |
{ | |
var intentRequest = input.Request as IntentRequest; | |
context.Logger.LogLine($"Intent request:\n{JsonConvert.SerializeObject(input)}"); | |
if (intentRequest.Intent.Name == "CountryInfoIntent") | |
{ | |
context.Logger.LogLine($"Determining country with :\n{JsonConvert.SerializeObject(intentRequest?.Intent?.Slots)}"); | |
var country = intentRequest?.Intent?.Slots["Country"].Value; | |
if (country == null) | |
{ | |
context.Logger.LogLine($"The country was not understood."); | |
return MakeSkillResponse("I'm sorry, but I didn't understand the country you were asking for. Please ask again.", false); | |
} | |
context.Logger.LogLine($"Guessed that country is:\n{country}"); | |
var countryInfo = await GetCountryInfo(country, context); | |
context.Logger.LogLine($"Done awaiting, got this back from method: {JsonConvert.SerializeObject(countryInfo)}"); | |
var outputSpeech = "I couldn't find any information for that country. Please try another."; | |
if (countryInfo != null) | |
{ | |
outputSpeech = $"About {countryInfo.name}. The capitol is {countryInfo.capital} " + | |
$"and the population is {countryInfo.population}."; | |
} | |
return MakeSkillResponse(outputSpeech, false); | |
} | |
else if (intentRequest.Intent.Name == "AMAZON.StopIntent") | |
{ | |
var outputSpeech = "Goodbye"; | |
return MakeSkillResponse(outputSpeech, true); | |
} | |
else | |
{ | |
var outputSpeech = "Just say, tell me about Canada or what's the capital of Mexico. To exit, say, exit."; | |
return MakeSkillResponse(outputSpeech, false); | |
} | |
} | |
private async Task<Country> GetCountryInfo(string countryName, ILambdaContext context) | |
{ | |
countryName = countryName.ToLowerInvariant(); | |
var countries = new List<Country>(); | |
// search by "North Korea" or "Vatican City" gives us poor results | |
// instead search by both "North" and "Korea" to get better results | |
var countryPartNames = countryName.Split(' '); | |
if (countryPartNames.Length > 1) | |
{ | |
foreach (var searchPart in countryPartNames) | |
{ | |
// The United States of America results in too many search requests. | |
if (searchPart != "the" || searchPart != "of") | |
{ | |
countries.AddRange(await GetResultsForCountrySearch(searchPart, context)); | |
} | |
} | |
} | |
else | |
{ | |
countries.AddRange(await GetResultsForCountrySearch(countryName, context)); | |
} | |
// try to find a match on the name "korea" could return both north korea and south korea | |
var bestMatch = (from c in countries | |
where c.name.ToLowerInvariant() == countryName || | |
c.demonym.ToLowerInvariant() == $"{countryName}n" // north korea hack (name is not North Korea, by demonym is North Korean) | |
orderby c.population descending | |
select c).FirstOrDefault(); | |
var match = bestMatch ?? (from c in countries | |
where c.name.ToLowerInvariant().IndexOf(countryName) > 0 | |
|| c.demonym.ToLowerInvariant().IndexOf(countryName) > 0 | |
orderby c.population descending | |
select c).FirstOrDefault(); | |
if (match == null && countries.Count > 0) | |
{ | |
match = countries.FirstOrDefault(); | |
} | |
return match; | |
} | |
private async Task<List<Country>> GetResultsForCountrySearch(string countryName, ILambdaContext context) | |
{ | |
List<Country> countries = new List<Country>(); | |
var uri = new Uri($"https://restcountries.eu/rest/v2/name/{countryName}"); | |
context.Logger.LogLine($"Attempting to fetch data from {uri.AbsoluteUri}"); | |
try | |
{ | |
var response = await _httpClient.GetStringAsync(uri); | |
context.Logger.LogLine($"Response from URL:\n{response}"); | |
// TODO: (PMO) Handle bad requests | |
countries = JsonConvert.DeserializeObject<List<Country>>(response); | |
} | |
catch (Exception ex) | |
{ | |
context.Logger.LogLine($"\nException: {ex.Message}"); | |
context.Logger.LogLine($"\nStack Trace: {ex.StackTrace}"); | |
} | |
return countries; | |
} | |
} | |
public class Country | |
{ | |
public string name { get; set; } | |
public string[] topLevelDomain { get; set; } | |
public string alpha2Code { get; set; } | |
public string alpha3Code { get; set; } | |
public string[] callingCodes { get; set; } | |
public string capital { get; set; } | |
public string[] altSpellings { get; set; } | |
public string region { get; set; } | |
public int population { get; set; } | |
public float[] latlng { get; set; } | |
public string demonym { get; set; } | |
public float area { get; set; } | |
public float? gini { get; set; } | |
public string[] timezones { get; set; } | |
public string[] borders { get; set; } | |
public string nativeName { get; set; } | |
public string numericCode { get; set; } | |
public Currency[] currencies { get; set; } | |
public Language[] languages { get; set; } | |
public Translations translations { get; set; } | |
} | |
public class Translations | |
{ | |
public string de { get; set; } | |
public string es { get; set; } | |
public string fr { get; set; } | |
public string ja { get; set; } | |
public string it { get; set; } | |
public string br { get; set; } | |
public string pt { get; set; } | |
} | |
public class Currency | |
{ | |
public string code { get; set; } | |
public string name { get; set; } | |
public string symbol { get; set; } | |
} | |
public class Language | |
{ | |
public string iso639_1 { get; set; } | |
public string iso639_2 { get; set; } | |
public string name { get; set; } | |
public string nativeName { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"intents": [ | |
{ | |
"intent": "CountryInfoIntent", | |
"slots": [ | |
{ | |
"name": "Country", | |
"type": "AMAZON.Country" | |
} | |
] | |
}, | |
{ | |
"intent": "AMAZON.HelpIntent" | |
}, | |
{ | |
"intent": "AMAZON.StopIntent" | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "1.0.0-*", | |
"buildOptions": { | |
}, | |
"dependencies": { | |
"Microsoft.NETCore.App": { "version": "1.1.1", "type": "platform" }, | |
"Amazon.Lambda.Core": "1.0.0*", | |
"Amazon.Lambda.Serialization.Json": "1.0.1", | |
"Amazon.Lambda.Tools": { | |
"type": "build", | |
"version": "1.3.0-preview1" | |
}, | |
"Alexa.NET": "1.0.0-beta-3"}, | |
"tools": { | |
"Amazon.Lambda.Tools" : "1.3.0-preview1" | |
}, | |
"frameworks": { | |
"netcoreapp1.0": { | |
"imports": "dnxcore50" | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CountryInfoIntent the capitol of {Country} | |
CountryInfoIntent get the capitol of {Country} | |
CountryInfoIntent country info for {Country} | |
CountryInfoIntent what is the capitol of {Country} | |
CountryInfoIntent about {Country} | |
CountryInfoIntent {Country} | |
CountryInfoIntent tell me the capitol of {Country} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment