this.emit(':ask') not working - alexa-skills-kit

I have created one intent SampleIntent on amazon skill which prompts the user to enter the city name. Once entered, I have to save that city name, and then again it will prompt/ask user "Do you want to continue ?" If the user enters yes, it will again prompt for the city name, and exit if the user enters no.
For this I have created two slots in Sample Intent. My utterance are {slotA} and {slotB}. When I access SampleIntent it prompts for ener City name but on console I am getting undefined. It is also never reaching the prompt for continuing or not.
Below is my sample model:
{
"name": "SampleIntent",
"slots": [
{
"name": "cityName",
"type": "cityName"
},
{
"name": "confirmForMore",
"type": "confirmForMore"
}
],
"samples": [
"{fName} ",
"{confirmForMore}",
"CityName"
]
}
Code in node.js is below
this.emit(':ask', 'Please provide City Name');
cityName = intent.slots.cityName.value;
console.log('cityName :' + cityName );
this.emit(':ask', 'Do u like details for other City?');
confirmForMore = intent.slots.confirmForMore.value;
console.log("confirmForMore : "+confirmForMore);
Line no 4 to 6 never executes and each time asking for city name. If I enter city name I am not able to see cityName in console.
Thanks in advance.

See this is the way how your Alexa and Lambda function works.
First you provide some utterance to your lambda function : "Which CITY do you live in?"
Then Alexa creates a JSON input for your lambda function based on the input you provide in last step and the intent invoked and sends it to lambda function.
Lambda Function returns some JSON output which is suitable for Alexa and contains variables like speechOutput, etc and sends it back to Alexa.
Now Alexa speaks the output returned by the lambda function.
What is happening in your skill is, when you ask for a slot information cityName, it works fine and asks for the slot information and probably gets you the right info too. But now what happens is User provides some utterance like "YES" or "NO" in your case, and your lambda function executes from the top. Which results in execution of this block again.
this.emit(':ask', 'Please provide City Name');
cityName = intent.slots.cityName.value;
console.log('cityName :' + cityName );
To avoid such thing what you can do is something like this :
if (cityName in intent.slots && intent.slots.cityName.value <= 0){
this.emit(':ask', 'Please provide City Name');
cityName = intent.slots.cityName.value;
console.log('cityName :' + cityName );
}
else {
this.emit(':ask', 'Do u like details for other City?');
confirmForMore = intent.slots.confirmForMore.value;
console.log("confirmForMore : "+confirmForMore);
}

Related

Zod validation for phone numbers

I am new to using zod for valiadtion. I have read through the documentation but I can see anything on how to add a validation for a phone number.
I used the email one to make sure a user enters a correct email, but how do I do the same for a phone number.
Currently it looks like this:
contactNumber: z
.string()
.min(10, { message: 'Must be a valid mobile number' })
.max(14, { message: 'Must be a valid mobile number' }),
I am just not sure this is correct. I have made it a string because I want the user to be able to put a + in front of the number if necessary for example: +27823456787. I don't want the user to be able to put any letters in the number example: 072r536e98, If the user puts letters I want an error message to say "Must be a valid number".
Can anyone maybe advise me on the correct why to do the validation?
You could use a zod refinement to chain together a check from a library that is more capable of making that check. As was mentioned in the comments, the rules are complicated, and specific to the region.
There seems to be a validation from validator.js for example that could handle refining the string to a mobile phone number with isMobilePhone but you may want/need to have the user specify the country they are in.
An example of how this would work might be:
import { z } from "zod";
import validator from "validator";
const schema = z.object({
name: z.string(),
phone: z.string().refine(validator.isMobilePhone)
});
console.log(
schema.safeParse({
name: "test",
phone: "+1-212-456-7890"
})
); // Success
console.log(
schema.safeParse({
name: "test",
phone: "2124567890"
})
); // Success
console.log(
schema.safeParse({
name: "test",
phone: "1234"
})
); // Failure

Watson Conversation Dialogue, how to save user input using slot

In my Watson conversation dialogue am trying to read user input using slot,
my requirement is to prompt user for enter an issue description and save it in a variable named issue_description.
but in slot, watson check for intent or entity before saving it into a variable. in my case i have put an intent to check with, but it is not saved into variable after the check, i always get true as issue_description.
how can i save the issue _description into a variable?
what should be the possible intent and entity for this?
If you want to save user input then you can use to save the input in any variable.
"context":{
"issue_description":"<?input.text?>"
}
To capture something like a description in a slot, my recommendation is to
define an entity based on a pattern that describes how the description should be.
in the pattern, you could use quotes as delimiter of the string to capture
in the slot definition Watson has to look for that entity, you provide the name of a context variable the entity value is saved to
access the context variable to process the captured value
There is a sample workspace I wrote that captures an event description using a pattern. In the dialog I cut the quotes off the string and then send it to a function for postprocessing. The eventName is defined as follows, the pattern in patterns is the interesting part:
{
"entity": "eventName",
"values": [
{
"type": "patterns",
"value": "shortname",
"created": "2018-01-31T13:28:56.245Z",
"updated": "2018-02-07T09:08:31.651Z",
"metadata": null,
"patterns": [
"[\"„“][A-Za-z0-9.:| #\\']+[\"”“]"
]
}
],
}
To store the user input as in the context variable issue_description, you can either use an intent if you are not validating the input (description) or you can use an entity with the synonym value based on pattern. By doing this, you can configure the bot to recognize the condition and save the value to the context variable.

Getting a link to a specific Google Analytics view

I have a GA account, with defined properties and views. Now, I gave viewing rights for a few users to a specific view. How can I construct/get programmatically a direct URL that will bring those users right to that view/report?
Thanks a lot!
First lets take a look at an typical report url for a specific view:
https://analytics.google.com/analytics/web/#report/visitors-actives/a40777649w70913173p73156703/
Notice the pattern:
BASE_URL = 'https://analytics.google.com/analytics/web/#report/'
REPORT_TYPE = 'visitors-actives/'
ACOUNT_ID = '40777649'
WEBPROPERTY_ID = '70913173'
PROFILE_ID = '73156703' # Also called the view Id.
You can retrieve this information programmatically by calling the Account Summaries: list API method which returns a list of Account Summaries:
{
"id": string,
"kind": "analytics#accountSummary",
"name": string,
"starred": boolean,
"webProperties": [
{
"kind": "analytics#webPropertySummary",
"id": string,
"name": string,
"internalWebPropertyId": string,
"level": string,
"websiteUrl": string,
"starred": boolean,
"profiles": [
{
"kind": "analytics#profileSummary",
"id": string,
"name": string,
"type": string,
"starred": boolean
}
]
}
]
}
The ACCOUNT_ID is the top level acountSumaries.id.
The WEBPROPERTY_ID is the accountsumaries.webproperties[X].internalWebPropertyId.
The PROFILE_ID is the accountsumaries.webproperties[X].profiles[X].id
Now with this information you can recustruct the URL link to the report of interest for a particular view.
FULL_URL = BASE_URL + REPORT_TYPE + 'a' + ACCOUNT_ID + 'w' + WEBPROPERTY_ID + 'p' + PROFILE_ID + '/'
Further to Matt's brilliant answer, you can use the "Try this API" section in their documentation here to get this information without writing a line of code:
https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/accountSummaries/list
There is also some code snippets to do this programmatically.
Don't forget you will need to be logged in with an account with GA access for this to work.
I have a few points to add to Matt and Adam's answers:
I chose to build a generic URL for the main view instead of a report. That way a user can navigate to a report of their choosing. The URL structure is https://analytics.google.com/analytics/web/#/report-home/a[account id]w[internal web property id]p[view id] Important: a user has to have at least READ_AND_ANALYZE permissions for the web property in order to access its default view.
internalWebPropertyId is a resource in the web properties collection and can be obtained through various GA Management API calls. For example, I extracted this value from the response object after creating a new web property using insert call.

Elm: Iterate list performing multiple HTTP requests

I'm wondering if I can get some help with iterating a list of groups, making a POST request for each group to create a 'room', iterating the users for each group and making a POST request to assign them to this specific room.
I have the following model.
model = {
groups = [
{
title = "Foo"
, users = [
{ name = "Joe" }
, { name = "Mary" }
]
},
{
title = "Bar"
, users = [
{ name = "Jill" }
, { name = "Jack" }
]
}
]
}
The desired result is that the room Foo was created and Joe and Mary were assigned, and Bar was created and Jill and Jack were assigned.
The view, for now, would just be a simple button that triggers an action.
div []
[ button [ onClick InviteUsersToRoom ] [ text "Invite users to room" ] ]
I've created 2 POST requests:
createRoom: take a title, create a room using the title and return the room_id
addUser: take a room_id and a user's name, add the the users to the room and return the status of ok
example:
-- create a room for each group
-- passing in `title` as the room name
-- which will return the room id from `decodeCreateRoomResponse`
createRoom : String -> String -> Cmd Msg
createRoom title =
Task.perform
CreateRoomsFail
CreateRoomsSuccess
(Http.post
decodeCreateRoomResponse
("https://some_api?room=" ++ title)
Http.empty
)
decodeCreateRoomResponse : Json.Decoder String
decodeCreateRoomResponse =
Json.at ["room", "id"] Json.string
-- add a user to a room using a `room_id` and the user's name
-- returns a bool from `decodeAddUserResponse`
addUser : String -> String -> Cmd Msg
addUser room_id user =
Task.perform
AddUserFail
AddUserSuccess
(Http.post
decodeCreateChannelResponse
("https://some_api?room=" ++ room_id ++ "&user=" ++ user)
Http.empty
)
decodeAddUserResponse : Json.Decoder String
decodeAddUserResponse =
Json.at ["ok"] Json.bool
I'm wondering how you'd go about stitching this up altogether, so that onclick :
iterate each group
make the POST to create the Room
take the room_id from the response and iterate the users
POST the room_id and the users name
Any help is appreciated.
You've got a few scattered errors that I won't explicitly point out because the compiler will help you, but you're off to a good start. You already have some Http handling Cmds built up so you just need to wire things up with your update function.
Let's define your Model explicitly (you may already be doing this but it isn't in your example):
type alias User =
{ name : String }
type alias Group =
{ title : String
, users : List User
}
type alias Model =
{ groups : List Group }
Based off your functions, here's how I interpret your Msg type, with one small change which is to add a list of users as a parameter to CreateRoomsSuccess.
type Msg
= InviteUsersToRoom
| CreateRoomsFail Http.Error
| CreateRoomsSuccess (List User) String
| AddUserFail Http.Error
| AddUserSuccess Bool
Now we can tweak createRoom in order to pass along the list of users to create. Note that this isn't creating any users at this time. It is using currying to create a partially-applied function so that when the CreateRoomsSuccess case is handled in the update function, it already has the list of users that need to be created (rather than having to look them up in the model list):
createRoom : Group -> Cmd Msg
createRoom group =
Task.perform
CreateRoomsFail
(CreateRoomsSuccess group.users)
(Http.post
decodeCreateRoomResponse
("https://some_api?room=" ++ group.title)
Http.empty
)
To create the list of rooms, you simply map the list of groups to a list of Cmds that perform the post. This will happen when the button is clicked:
case action of
InviteUsersToRoom ->
model ! List.map createRoom model.groups
...
You'll have to implement the update cases for when errors occur. Next up, we have to handle the CreateRoomsSuccess message. This is where you'll need to look up the list of users for a group. Again, you'll map over the function you already created that handles the Http task:
case action of
...
CreateRoomsSuccess users roomID ->
model ! List.map (addUser roomID << .name) users
...
You'll have to handle the AddUserFail and AddUserSuccess cases, but the above examples should help you understand how to post multiple messages and act accordingly based on the success or failure of each.

Firebase orderByChild query not returning ordered results

I am trying to use the Firebase orderByChild() function per the documentation example but the queries are not coming back filtered or sorted.
Here is the sample data structure:
"notifications": {
"001": {
"member_id": "abc123",
"created_at": 1424357680681,
"new": true,
"first_name": "Jon",
"last_name": "Snow",
"message": "likes your photo"
},
"002": {
"member_id": "abc456",
"created_at": 1424357680681,
"new": true,
"first_name": "Clark",
"last_name": "Kent",
"message": "likes your comment"
}
}
When a user logs in, I want to query the notifications hash for only the notifications with a member_id that matches the current user's id.
I have tried both versions with and without the "child_added".
Option A:
ref.orderByChild("member_id").equalTo(memberId);
Option B:
ref.orderByChild("member_id").equalTo(memberId)
.on("child_added", function(data) {
console.log("new child id = " + data.key());
});
When I query the notifications hash, the query returns an array of all of the notifications. They are neither limited to the member_id of the current user, nor sorted by member_id. (I can delete the member_id key entirely and the notification will still be returned).
I can always filter the returned array by member_id in-app, but I would really like to get the query working per the documentation.
Any help is appreciated!
I found the problem!
I was under the impression that you could add the query modifiers in place.
I was doing:
ref.orderByChild("member_id").equalTo(memberId);
var sync = $firebase(ref);
It should actually be:
var sync = $firebase(ref.orderByChild("member_id").equalTo(memberId));
Most likely your memberId variable is a number, while you're storing the corresponding value as a string.
If you store numbers as a string, this query won't give any results:
ref.orderByChild("member_id").equalTo(456)
But this one will:
ref.orderByChild("member_id").equalTo('456')
The easiest fix in your snippet of code is coercing the memberId to a string like this:
ref.orderByChild("member_id").equalTo(''+memberId)
See this fiddle for a working sample: http://jsfiddle.net/695rf0vy/

Resources