Alexa custom slot that takes any word or phrase - alexa

What samples can one add to a custom slot to make it accept any word or phrase?

Update
This solution has been outdated with the introduction of phrase slots eg. AMAZON.SearchQuery.
From the Announcements
Phrase slots are designed to improve speech recognition accuracy for
skills where you cannot include a majority of possible values in the
slot while creating the interaction model. The first slot available in
this category is AMAZON.SearchQuery is designed to provide improved
ability for you to collect generic speech from users.
The Problem
Having worked on developing an urban dictionary skill over the weekend to polish up on my Alexa skills I ran into a problem which I think a lot of skill developers might encounter.
TL;DR
Namely, how do you train Alexa on a custom slot to be able to take any value you give it?
First Attempts
At first I added about 5 words to the custom slot samples like bae, boo, ship it. But I quickly found that the skill would only work with those 5 words and I'd get no calls to my lambda function for words outside that list.
I then used
from nltk.corpus import words
import json, random
words_list = random.shuffle(words.words()[:1000])
words_list = [word.lower() for word in words_list]
words_list = list(set(words_list))
values = []
for word in words_list:
value = {}
value['id'] = None
value['name'] = {}
value['name']['value'] = word
value['name']['synonyms'] = []
values.append(value)
print(json.dumps(values))
The above code uses nltk, which you can install with pip install nltk, to generate a 1000 words according to the schema you can find under code editor, it produce a thousand of these;
{
"id": null,
"name": {
"value": "amblygeusia",
"synonyms": []
}
}
I copied and pasted these under values, you can find the whole file under Code Editor on the Skills Builder page.
"languageModel": {
"types": [
{
"name": "phrase", //my custom slot's name
"values": [...] //pasted the thousand words generated here
...
After saving and building in the Skills Builder UI. This only allowed my skill to capture single word slot values. I tried generating 10 000 words in the same way and adding them as samples for the custom slot but two word and three words phrases weren't recognised and the skill failed to get the definition of phrases like;
ship it
The Solution;
What worked for me and worked really well was to generate two word samples. Despite all the examples being two worded, the skill was then able to recognise single word values and even three word values.
Here's the code to do that using nltk;
from nltk.corpus import words
import json, random
words_list = random.shuffle(words.words()[:1000])
words_list = [word.lower() for word in words_list]
words_list = list(set(words_list))
word_pairs = []
for word in words_list:
pair = ' '.join(random.sample(words_list, 2))
word_pairs.append(pair)
word_pairs = list(set(word_pairs))
for pair in word_pairs:
value = {}
value['id'] = None
value['name'] = {}
value['name']['value'] = pair
value['name']['synonyms'] = []
values.append(value)
print(json.dumps(values))
I put that in a file called custom_slot_value_geneator.py and ran it with;
python3 custom_slot_value_geneator.py | xclip -selection c
This generates the values and copies them to the clipboard.
I then copied them into the Code Editor under values, replacing the old values
"languageModel": {
"types": [
{
"name": "phrase", //my custom slot's name
"values": [...] //pasted the thousand two word pairss generated here
...
Save & Build.
That's it! Your skill would then be able to recognize any word or phrase for your custom slot, whether or not it's in the sample you generated!

Related

Generating a reverse-engineerable code to save game, python 3

So I'm making a little text based game in Python and I decided for a save system I wanted to use the old "insert code" trick. The code needs to keep track of the players inventory (as well as other things, but the inventory is what I'm having trouble with).
So my thought process on this would be to tie each item and event in the game to a code. For example, the sword in your inventory would be stored as "123" or something unique like that.
So, for the code that would generate to save the game, imagine you have a sword and a shield in your inventory, and you were in the armory.
location(armory) = abc
sword = 123
shield = 456
When the player inputs the command to generate the code, I would expect an output something like:
abc.123.456
I think putting periods between items in the code would make it easier to distinguish one item from another when it comes to decoding the code.
Then, when the player starts the game back up and they input their code, I want that abc.123.456 to be translated back into your location being the armory and having a sword and shield in your inventory.
So there are a couple questions here:
How do I associate each inventory item with its respective code?
How do I generate the full code?
How do I decode it when the player loads back in?
I'm pretty damn new to Python and I'm really not sure how to even start going about this... Any help would be greatly appreciated, thanks!
So, if I get you correctly, you want to serialize info into a string which can't be "saved" but could be input in your program;
Using dots is not necessary, you can program your app to read your code without them.. this will save you a few caracters in lenght.
The more information your game needs to "save", the longer your code will be; I would suggest to use as short as possible strings.
Depending on the amount of locations, items, etc. you want to store in your save code: you may prefer longer or shorter options:
digits (0-9): will allow you to keep 10 names stored in 1 character each.
hexadecimal (0-9 + a-f, or 0-9 + a-F): will allow you to keep from 16 to 22 names (22 if you make your code case sensitive)
alphanum (0-9 + a-z, or 0-9 + a-Z): will allow you to keep from 36 to 62 names (62 if case sensitive)
more options are possible if you decide to use punctuation and punctuated characters, this example will not go there, you will need to cover that part yourself if you need.
For this example I'm gonna stick with digits as I'm not listing more than 10 items or locations.
You define each inventory item and each place as dictionaries, in your source code:
You can a use single line like I have done for places
places = {'armory':'0', 'home':'1', 'dungeon':'2'}
# below is the same dictionary but sorted by values for reversing.
rev_places = dict(map(reversed, places.items()))
Or for improved readability; use multiple lines:
items = {
'dagger':'0',
'sword':'1',
'shield':'2',
'helmet':'3',
'magic wand':'4'
}
#Below is the same but sorted by value for reversing.
rev_items = dict(map(reversed, items.items()))
Store numbers as strings, for easier understanding, also if you use hex or alphanum options it will be required.
Then also use dictionaries to manage in game information, below is just a sample of how you should represent your game infos that the code will produce or parse, this portion should not be in your source code, I have intentionally messed items order to test it.;
game_infos = {
'location':'armory',
'items':{
'slot1':'sword',
'slot2':'shield',
'slot3':'dagger',
'slot4':'helmet'
}
}
Then you could generate your save code with following function that reads your inventory and whereabouts like so:
def generate_code(game_infos):
''' This serializes the game information dictionary into a save
code. '''
location = places[game_infos['location']]
inventory = ''
#for every item in the inventory, add a new character to your save code.
for item in game_infos['items']:
inventory += items[game_infos['items'][item]]
return location + inventory # The string!
And the reading function, which uses the reverse dictionaries to decipher your save code.
def read_code(user_input):
''' This takes the user input and transforms it back to game data. '''
result = dict() # Let's start with an empty dictionary
# now let's make the user input more friendly to our eyes:
location = user_input[0]
items = user_input[1:]
result['location'] = rev_places[location] # just reading out from the table created earlier, we assign a new value to the dictionary location key.
result['items'] = dict() # now make another empty dictionary for the inventory.
# for each letter in the string of items, decode and assign to an inventory slot.
for pos in range(len(items)):
slot = 'slot' + str(pos)
item = rev_items[items[pos]]
result['items'][slot] = item
return result # Returns the decoded string as a new game infos file :-)
I recommend you play around with this working sample program, create a game_infos dictionary of your own with more items in inventory, add some places, etc.
You could even add some more lines/loops to your functions to manage hp or other fields your game will require.
Hope this helps and that you had not given up on this project!

creating an array that does specific outputs according to Choices

I have songs which are french and Chinese with different difficulty levels such as easy medium and advanced.
I was trying to create an array. I first made a prototype to test it:
var array = [[["a","b","c"],["d","e","f"],["g","h","i"]],[["j","k","l"],["m","n","o"], ["p","q","r"]]]
print(array[1][0])
/*prints j, k, l
index[0] is Chinese songs
index[1] is french songs
index[0][1]= Chinese songs with medium level
index[1][2]= French songs with Hard level
index[0][0]= Chinese songs with beginner level*/
I tried to use the same principle in my current program but I failed. I think I will manage it If I can successfully implement it into an array.I also tried dictionaries but I couldn't manage to do it.Since I have objects such as name, lyrics, mp3type etc within the array that made it diffucult.
My code works perfectly when you want to put all the songs and append it but I want to customise the song choice to the user's choices.So when they click Chinese beginner level only Chinese and beginner level array should pass on to the music player.
arrSong.append(SongModel(name: "Cold Water", lyrics: "Everybody.."
path: Bundle.main.path(forResource: "ColdWater", ofType: "m4a")!))
This is just a prototype song list. I am just trying to figure how to do solve this problem.i also referenced some code related to my project so Maybe it can make more sense.
func setUI(){
lbl_song_name.text = arrSong[currIndex].name
lbl_lyrics.numberOfLines = 0
lbl_lyrics.text = arrSong[currIndex].lyrics
{
func SongPlay(){
self.audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath:
arrSong[currIndex].path))
let asset = AVURLAsset(url: URL(fileURLWithPath:
arrSong[currIndex].path)).duration
}
I think that the best way forward would be to not have some complicated multi-dimensional array to search in but instead to have a struct or class with language (chinese/french) and difficulty as property and then use the built in filter functionality to find all songs that matches the user selection.
Example (simplified)
struct Song {
var name: String
var difficulty: Int //Enum is better here
vae language: String
}
//Simple array with all songs
let allSongs: [Song]
//Filtering user selection
let userSelectedLevel = ... // from UI
let userSelectedLanguage = ...// from UI
let userSelection = allSongs.filter({$0.difficulty == userSelectedLevel && $0.language == userSelectedLAnguage})
The array userSelection will now contain the songs that matches the users choose and can now be used for further processing in the code.

Tone analyser only returns analysis for 1 sentence

When using tone analyser, I am only able to retrieve 1 result. For example, if I use the following input text.
string m_StringToAnalyse = "The World Rocks ! I Love Everything !! Bananas are awesome! Old King Cole was a merry old soul!";
The results only return the analysis for document level and sentence_id = 0, ie. "The World Rocks !". The analysis for the next 3 sentences are not returned.
Any idea what I am doing wrong or am I missing out anything? This is the case when running the provided sample code as well.
string m_StringToAnalyse = "This service enables people to discover and understand, and revise the impact of tone in their content. It uses linguistic analysis to detect and interpret emotional, social, and language cues found in text.";
Running Tone analysis using the sample code on the sample sentence provided above also return results for the document and the first sentence only.
I have tried with versions "2016-02-19" as well as "2017-03-15" with same results.
I believe that if you want sentence by sentence analysis you need to send every separate sentence as a JSON object. It will then return analysis in an array where id=SENTENCE_NUM.
Here is an example of one I did using multiple YouTube comments (using Python):
def get_comments(video):
#Get the comments from the Youtube API using requests
url = 'https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&maxResults=100&videoId='+ video +'&key=' + youtube_credentials['api_key']
r = requests.get(url)
comment_dict = list()
# for item in comments, add an object to the list with the text of the comment
for item in r.json()['items']:
the_comment = {"text": item['snippet']['topLevelComment']['snippet']['textOriginal']}
comment_dict.append(the_comment)
# return the list as JSON to the sentiment_analysis function
return json.dumps(comment_dict)
def sentiment_analysis(words):
# Load Watson Credentials using Python SDK
tone_analyzer = ToneAnalyzerV3(
username=watson_credentials['username'], password=watson_credentials['password'], version='2016-02-11')
# Get the tone, based on the JSON object that is passed to sentiment_analysis
return_sentiment = json.dumps(tone_analyzer.tone(text=words), indent=2)
return_sentiment = json.loads(return_sentiment)
Afterwards you can do whatever you want with the JSON object. I would also like to note for anyone else looking at this if you want to do an analysis of many objects, you can add sentences=False in the tone_analyzer.tone function.

How to highlight all matched word in single snippet in solr

All:
Right now, I am using SOLR highlight feature, but one thing I want to ask is:
Suppose I want to search keyword fund and value:
fund AND value
And the return highlight part is like:
"highlighting": {
"blk_0019": {
"content": [
"philosophy of the <em>fund</em> – <em>value</em> and turning point. \n \n MUSA was an orphaned"
]
},
"blk_0006": {
"content": [
"Global Equities <em>Fund</em> Ltd. \n \n CONFIDENTIAL enclosed"
]
}
}
The problem is I am sure blk_0019 and blk_0006 have both fund and value(obviously I use fund AND report), because the I set hl.fragsize=100, if the fund and value located not close enough in one document, they can not be shown both in same snippet. In blk_0019, solr highlights both fund and value, but in blk_0006, only fund shown.
How can I show both matched in single snippet and just ignore text between them as ..... like in Google
Also some small questions are:
[1] How to specify to search capitalized only word like Hello HELLO
in Solr?
[2] How to search All-capital AND(All-capital "AND" will be consider as logical operator)
Thanks
It depends on the highlighter you are using. For the Standard Highlighter you can set hl.snippets=5 for instance (default is 1). Then you'll get 5 snippets/fragments (at most), each with a maximum length of hl.fragsize.
They're returned as multiple values, so you'll need to join them yourself (using "..." for instance).

JMeter: How to count JSON objects in an Array using jsonpath

In JMeter I want to check the number of objects in a JSON array, which I receive from the server.
For example, on a certain request I expect an array with 5 objects.
[{...},{...},{...},{...},{...}]
After reading this: count members with jsonpath?, I tried using the following JSON Path Assertion:
JSON Path: $
Expected value: hasSize(5)
Validate against expected value = checked
However, this doesn't seem to work properly. When I actually do receive 5 objects in the array, the response assertion says it doesn't match.
What am I doing wrong?
Or how else can I do this?
Although JSONPath Extractor doesn't provide hasSize function it still can be done.
Given the example JSON from the answer by PMD UBIK-INGENIERIE, you can get matches number on book array in at least 2 ways:
1. Easiest (but fragile) way - using Regular Expression Extractor.
As you can see, there are 4 entries for category like:
{ "category": "reference",
{ \"category\": \"fiction\"
...
If you add a Regular Expression Extractor configured as follows:
It'll capture all the category entries and return matches number as below:
So you will be able to use this ${matches_matchNr} variable wherever required.
This approach is straightforward and easy to implement but it's very vulnerable to any changes in the response format. If you expect that JSON data may change in the foreseeable future continue with the next option.
2. Harder (but more stable) way - calling JsonPath methods from Beanshell PostProcessor
JMeter has a Beanshell scripting extension mechanism which has access to all variables/properties in scope as well as to the underlying JMeter and 3rd-party dependencies APIs. In this case you can call JsonPath library (which is under the hood of JsonPath Extractor) directly from Beanshell PostProcessor.
import com.jayway.jsonpath.Criteria;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.JsonPath;
Object json = new String(data);
List categories = new ArrayList();
categories.add("fiction");
categories.add("reference");
Filter filter = Filter.filter(Criteria.where("category").in(categories));
List books = JsonPath.read(json, "$.store.book[?]", new Filter[] {filter});
vars.put("JSON_ARRAY_SIZE", String.valueOf(books.size()));
The code above evaluates JSONPath expression of $.store.book[?] against parent sampler response, counts matches number and stores it into ${JSON_ARRAY_SIZE} JMeter Variable
which can later be reused in an if clause or an assertion.
References:
JMeter – Working with JSON – Extract JSON response
JMeter's User Manual Regular Expressions entry
JSON Path Documentation and Examples
How to use BeanShell: JMeter's favorite built-in component
This is not possible with the plugin you are using (JMeter-plugins).
But it can be done with JSON Extractor since JMeter 3.0, this plugin has been donated by UbikLoadPack (http://jmeter.apache.org/changes_history.html)
Example:
Say you have this JSON that contains an array of books:
{ "store": {"book": [
{ "category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95},
{ "category": "fiction","author": "Evelyn Waugh","title": "Sword of Honour","price": 12.99},
{ "category": "fiction","author": "Herman Melville","title": "Moby Dick","isbn": "0-553-21311-3","price": 8.99},
{ "category": "fiction","author": "J. R. R. Tolkien","title": "The Lord of the Rings","isbn": "0-395-19395-8","price": 22.99}
],
"bicycle": {"color": "red","price": 19.95}} }
To have this count:
1/ Add JSON Extractor:
The count will be then available bookTitle_matchNr which you can access through:
${bookTitle_matchNr}
Running this Test Plan would display this:
As you can see, Debug Sampler-${bookTitle_matchNr} shows Debug Sampler-4

Resources