How to use actions.intent.DATETIME? - actions-on-google

It is "clearly" defined in the documentation, but I can find no example of how to use actions.intent.DATETIME.
Please provide an example of what is needed in the 'action.json' file, and how my code can get the date and time provided using the assistant SDK helper. I haven't been able to figure out how to use actions.intent.___ at all!
At the simplest level, I want my code to know whether it is morning or evening for the person since I need to give different information in each case. Someone might want to do this to respond "Good morning" or "Good evening".
Also to do with intents, at a more complex level, I also want to know their approximate location (lat/long). I figured that once I know how to work with DATETIME, I'd be able to apply the same code pattern to use getDeviceLocation.
There is some code at https://github.com/actions-on-google/actions-on-google-nodejs that uses the DATETIME intent, but it asks the user for any time. I want to simply know what their current time is.

The DateTime intent can be invoked using the askForDateTime() method from the ActionsSdkApp class in our client library. Simply call the method from an intent, and pass it some queries which clarify the prompting. Then listen for the response using a listener for the actions.intent.DATETIME intent, just as you would listen for the actions.intent.TEXT intent.
In the handler for the actions.intent.DATETIME intent, you can use the getDateTime() method to retrieve the data. Unfortunately this intent only works by asking for an exact date and time from the user, and it is a generic date and time, so there is no guarantee that it is their current datetime unless you structure your prompts in a way to guide the user towards that.
const app = new ActionsSdkApp({ request, response });
function welcomeIntent (app) {
app.askForDateTime('When do you want to come in?',
Which date works best for you?',
'What time of day works best for you?');
}
function datetime (app) {
app.tell({speech: 'Great see you at your appointment!',
displayText: 'Great, we will see you on '
+ app.getDateTime().date.month
+ '/' + app.getDateTime().date.day
+ ' at ' + app.getDateTime().time.hours
+ (app.getDateTime().time.minutes || '')});
}
const actionMap = new Map();
actionMap.set(app.StandardIntents.MAIN, welcomeIntent);
actionMap.set(app.StandardIntents.DATETIME, datetime);
app.handleRequest(actionMap);
As you mentioned you can invoke and handle the actions.intent.PERMISSION intent in a similar way to get a precise longitude and latitude location.
As a side note, if you are using API.AI, you can use their Date and Time system entities to do this, or use the askForDateTime() method in the ApiAiApp class from the client library.

You can em-bed the maps API location/time in your app JSON or, other open source. As far as location it is device and user settings specific so, whether or not you get a JSNODE response from the device/user depends on the user even if they are running the APP and, have different setting preferences.

Related

Microsoft Bot Framework - Multi turn context is lost after the first interaction

I recently moved my code from SDK v3 to v4 and I am trying to take advantage of the multi-turn features.
I have looked over the samples from GitHub. The samples work well for multi-turn but one issue I noticed is that it recognizes the context only if the prompt is clicked immediately after the initial answer (with prompts) is shown.
I would like to be able to identify, at any given time that a prompt is clicked. I am storing all the previous prompts in the state object (dialogInstance.State) already. I have a custom host, which sends the replytoid and using that I can get the appropriate state.
The problem is though, I am not able to get to a point where I can use the dialoginstance.State.
The sample code uses the DialogExtensions class. The "DialogExtensions" class tries to gather the previous context by checking if the result from the ContinueDialogAsync method returns null or not.
DialogExtensions class with multi-turn
When there is no previous context (no previous answer with prompts), then the call to the ContinueDialogAsync returns a result with Empty Status.
I am thinking this where I need to check the dialogstate and if the new message refers to any of the old messages at any given point, it can then start to continue the old conversation.
I am not sure if that is even possible.
Any help/pointers would be appreciated.
thanks,
I eventually ended up implementing something that will work for custom bot host/direct channel bot client.
The whole point is that the call to the qnamaker api should happen with the old context object, whenever an option is chosen, even if it is out-of-context.
First let me explain how it works in the current version of the code.
The way the bot code was trying to solve multi turn dialog, was by storing the current answer if it had prompts/options and returning the conversation state in "waiting" mode. When the next question is received, it would automatically assume that the new question is part of the prompts/options of the old question. It would then pass the oldstate along to the QnAMaker.
What I noticed is that, even if the question in the second turn is not part of the prompts/options (something the user has typed manually and is a completely different question), it would still send the oldstate object to the QnAMaker.
The QnAMaker api call seem to ignore oldstate if the new question is not part of the prompts/options of the oldstate. It will work correctly by fetching the answer for the new question that was typed manually.
This was the key. If we can focus on what gets to the qnamaker then we can solve our original problem.
I realized that having the bot return a waiting state is only a mechanism to create a condition to extract the oldstate in the next turn. However, if I can rebuild the oldstate anytime when there is an option chosen, then the call to the qnamaker would work equally well.
This is what I have done now.
In my custom bot host code (which is a direct line client), I am sending the ReplyToID field populated with the original question whenever a prompt is clicked. Then in the bot code, I have changed it so that if there is a replytoid present, then build a new oldstate object with the data from the reply to id. Below is the QnABotState class that represents the oldstate. its a very simple class containing previous qna question id and the question text.
public int PreviousQnaId { get; set; }
public string PreviousUserQuery { get; set; }
QnABoState class
Now, the problem was the Activity object contains ReplyToId but does not contain ReplyToQuery (or something like that). Activity object is used to send data from bot client to the bot. So, either I would have to use a different field or send the PreviousUserQuery as an empty string. I had a hunch that it would work with just the previousqnaid.
//starting the process to get the old context (create an object that will hold the Process function's current state from the dialog state)
//if there is replyToId field is present, then it is a direct channel request who is replying to an old context
//get the reply to id from summary field
var curReplyToId = "";
curReplyToId = dialogContext.Context.Activity.ReplyToId;
var curReplyToQuery = "";
var oldState = GetPersistedState(dialogContext.ActiveDialog);
//if oldstate is null also check if there is replytoid populated, if it is then it maybe a new conversation but it is actually an "out of turn option" selection.
if (oldState == null)
{
if (!string.IsNullOrEmpty(curReplyToId))
{
//curReplyToId is not empty. this is an option that was selected out-of-context
int prevQnaId = -1;
int.TryParse(curReplyToId, out prevQnaId);
oldState = new QnABotState() { PreviousQnaId = prevQnaId, PreviousUserQuery = curReplyToQuery };
}
}
With that in place, my call to the qnamaker api would receive an oldstate object even if it is called out-of-context.
I tried the code and it worked. Not having the previous qna query did not make a difference. It worked with just the PreviousQnaId field being populated.
However, please note, this will not work for other channels. It would work for channels where you can set the ReplyToId field, such as the Direct Channel Client.
here is the code from my bot host:
// to create a new message
Activity userMessage = new Activity
{
From = new ChannelAccount(User.Identity.Name),
Text = questionToBot,
Type = ActivityTypes.Message,
Value = paramChatCode,// + "|" + "ShahID-" + DateTime.Now.TimeOfDay,
Id = "ShahID-" + DateTime.Now.TimeOfDay,
ChannelData = botHostId//this will be added as the bot host identifier
};
//userMessage.Type = "imBack";
if (paramPreviousChatId > 0)
{
//we have a valid replytoid (as a part of dialog)
userMessage.ReplyToId = paramPreviousChatId.ToString();
}

Cannot pass data across intents in Dialogflow Fulfillment

In Dialogflow Fulfillment I simply want to pass data from the Welcome Intent to the help Intent using conv.user.storage as seen in the code below. I can add it in the welcome intent but when I try to retrieve it in the help intent it is always undefined meaning data is NOT passed to the help intent. I have spent several hours on something I thought was straight forward and played around without any success. I would really appreciate a real world example on how to fix it and understand what I'm doing wrong.
function welcome(agent) {
agent.add(request.body.queryResult.fulfillmentMessages[0].text.text[0]);
var entity = 'media_getreq?message=volume';
getData(entity).then(result => {
let conv = agent.conv();
conv.user.storage["devicedata"] = result;
console.log(conv.user.storage["devicedata"]); //WORKS
});
}
function help(agent) {
agent.add(request.body.queryResult.fulfillmentMessages[0].text.text[0]);
let conv = agent.conv();
console.log(conv.user.storage["devicedata"]); //ALWAYS EMPTY
}
You have missed out Contexts a critical componet required to link intents.
Contexts represent the current state of a user's
request and allow your agent to transport conversation information from one intent to another.
You can use combinations of input and output contexts to control the conversational path the user traverses through your dialog sequence.
In summary, The intent that collects your Welcome input uses an output context to "remember" what you said.
The same context is used as the input context to the next intent, which collects input into the HelpIntent.
You need to update your code accordingly. Please see for details:
https://dialogflow.com/docs/contexts
https://dialogflow.com/docs/contexts/contexts-api

Extbase Hooks - execute code upon record creation

I want to create a standard typo3 extension but when I create a record (or modify it) I want to calculate something (in my case I want to call the Google Map API to get coordinates from a given address).
SO I search for a hook or something. Any idea?
One of my project example, may helps you for hook in backend when record has been changed.
In your extension file ext_localconf.php
// Hook for cancellation
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:femanager/class.tx_femanager_tcemainprocdm.php:tx_femanager_tcemainprocdm';
hook file class.tx_femanager_tcemainprocdm.php where you can execute
your script
class tx_femanager_tcemainprocdm{
function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$reference){
// $status also called action like delete
// $table - table name of excute backend action
// $id - record UID
// $fieldArray - fields of your table
if($table = 'your_extension_table_name'){
// your script
}
}
}
Maybe this answer is useful to you.
Register your class as a data handling hook in your extension. This one "is called AFTER all commands of the commandmap" were executed. Maybe you need to look for a more appropriate one.
Then in your registered Hook i.e. 'typo3conf/ext/your_ext/Classes/Hooks/AfterCreate.php' do your calculation. Hope this sets you on the right track.
In my special case there was no need to calculate the coordinates when the record got saved. So I just used the listAction in the controller, check if coordinates are there and if not call the Google API (and send an email if the Google API does not give a coordinate back).
In another case where the new record comes from a frontend plugin and I had to do something with this data I used the createAction in the Controller. (I am not sure if the createAction is also called when the record is created from the backend.)

Autoscale text input with JEditable.js?

I've been looking for a script that combines the autoGrowInput with the JEditable but found none.
Use https://github.com/MartinF/jQuery.Autosize.Input initialized automatically via jEditable's event data:
jQuery(element).editable(save_fn, {
data: function(value,settings} {
var target = event.target;
window.setTimeout(function(){
jQuery(target).find('input').autosizeInput();
});
return value;
}
});
It's worth noting that this event (data) fires before the input element is actually created, hence the use of the timeout. There doesn't seem to be an event available at the present time for after the input has been created.
Actually I have created a plugin that does exactly that. You can check the demo and the documentation. I tried to make it very intuitive. It has ajax capabilities, using the RESTful philosophy. If you liked the animation effect on the autoGrowInput, it will be really easy to add it to the plugin just by changing the css file, using the transition property.
If I get people to like it, I may be able to improve and add more features to it. Hope it helps.

How to add some extra parameter in the airbrake parameters for JS errors

When we are sending the airbrake error to the airbrake server, by default it includes the controller name and action name.
But the question is that I want to add some extra parameters like username, email of the current user. If anyone has any idea please suggest how to do that?
In my layout application.html:
- if ['development'].include?(Rails.env)
= airbrake_javascript_notifier
= render :partial => 'layouts/airbrake_notifier'
and in the partial I have written:
Airbrake.errorDefaults['name'] = "#{current_user.name}";<br/>
Airbrake.errorDefaults['email'] = "#{current_user.email}";<br/>
Airbrake.errorDefaults['phone'] = "#{current_user.phone}";<br/>
Airbrake.errorDefaults['title'] = "#{current_user.title;<br/>
Not a great solution, but the Airbrake Knowledge Base recommends essentially patching the airbrake gem source of the lib/airbrake/notice.rb file.
def initialize(args)
...
self.parameters = args[:parameters] ||
action_dispatch_params ||
rack_env(:params) ||
{'username' => current_user.name}
It would certainly be better to have this be configurable without patching source.
What I've done instead is simply add a few pieces of data to the session (current_user.name mainly), since session data is sent with the request. I wouldn't do this for more than a few little pieces of data.
We've just added getting current users into the Airbrake Gem.
https://github.com/airbrake/airbrake/wiki/Sending-current-user-information
You'll soon be able to sort by current user in an upcoming redesign of the UI.