display a herocard using luis action binding - node.js

How to create and display a "HeroCard" within the fulfill() function of LUIS action binding using node.js ? I am following the samples provided by the microsoft(https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/blog-LUISActionBinding)
Here is that how I tried to do this...
fulfill: function (parameters, callback) {
utilities.FilterFunction(parameters.x, parameters.y).then(function (matches){
utilities.CreateCard(session, matches).then(function(cards){
var reply = new builder.Message(session)
.attachmentLayout(builder.AttachmentLayout.carousel)
.attachments(cards);
callback(util.format(reply));
});
});
}
How can I use session value in the fulfill method?...without session "utilities.CreateCard" won't work...

Since session is not available in the action's fulfill method, we can make call to only to the utilities.FilterFunction and return the result via the callback. Now in our main js file, in the fulfillReplyHandler we get the actionModel which contains the result from utilities.FilterFunction.
Now we can create the "HeroCard" using the "session" that is accessible in the fulfillReplyHandler.

Related

custom function to form a url to download a document based on key

i am using integrated document server 4.4.3 ubuntu based, bellow code is customized for my suitability, how can i form a url based on key
asc_docs_api.prototype.asc_customCallback = function(typeFile, bIsDownloadEvent)
{
var actionType = c_oAscAsyncAction.DownloadAs;
var options = {downloadType : DownloadType.Download };
this._downloadAs("save", typeFile, actionType, options, function(incomeObject){
if (null != incomeObject && "save" == incomeObject["type"]) {
//incomeObject["data"] will return key of the document instead of key, i need full url of the document with md5 and expires like below
//ex: http://cache/files/.....
});
};
thank you in advance
You are trying to get the link too early, the file is not yet available, the conversion process might not be completed.
This callback only means that the conversion task is created
But you can try using the function onDownloadAs (created for the integrators who are going to create external button downloadAs)
http://api.onlyoffice.com/editors/config/events#onDownloadAs
A link to the file will be sent to:
asc_docs_api.prototype.processSavedFile = function(url, downloadType)

newbie node.js bot integration with database lookup (looking for best practice)

OK, new to Node.js and botframework. I built first bot using Azure site and downloaded the code. Chose the Luis integrated bot template.
I understand (finally) the event driven model of node.js and the concept of callbacks.
I have the code snippet below. When Luis finds an intent of "Help" it triggers this function. In turn, I have database calls to lookup the entity. Within the database I have an entity, response (if entity is bottle, answer "Recycle").
I have that code working too.
Below the first block is a function handleHelpRequester which is the callback function, I have that working as well. Where I am a little stuck (best practice) is that in this callback function I want to send something to the session object (session.send toward the bottom of the function).
Since I don't create the session object (directly) I'm not sure on the options.
Should I pass the session object to the database function, then pass it back?
Should I create a global variable and set it to the session object (I'm concerned that if multiple people are using this bot then this approach won't work).
I'm open for suggestions.
Thanks
.matches('Help', (session, args) => {
var entities = args.entities;
var itype = builder.EntityRecognizer.findEntity(args.entities, 'ItemTypes');
var respondToUser = '';
var msg = 'Initialized';
// if there is an entity provided, perform a lookup of the entity.
if (itype.entity !== null) {
//Use session.sendTyping so the user thinks something is happening rather than being ignored while we do the lookup in SharePoint.
session.sendTyping();
//perform lookup
respondToUser = sp.lookupEntity(itype.entity, handleHelpRequest);
};
})
function handleHelpRequest(err, respondToUser) {
var msg = 'uninitialized';
if (err = 'success') {
console.log('Respond to user from matches:'.concat(respondToUser));
//return from lookup
if (respondToUser === 'No match found') {
msg = 'I think you are asking for help, but I don\'t understand what you need help with.';
}
else {
msg = 'I can help you with that, \'%s\'.', respondToUser;
}
console.log(msg);
session.send(msg);
//The following two lines are for debugging
session.send('How may I assist you? ' + JSON.stringify(args));
session.send('Value of entity you said: \'%s\'.', itype.entity);
}
else {
console.log('an error occurred');
}
}
If you want to have access to the session object, then pass it as a parameter to your helper function.
Example:
function handleHelpRequest(session, err, respondToUser) {
// do session stuff
}

Unable to pass control to another method within a dialog in botbuilder for Node.js

I'm creating my first bot with Node.js and MS Bot Framework and I'm trying to figure out how to pass control from one method to another within a dialog.
In Bot Framework for C#, it's very easy:
context.Wait(NextMethodName);
where NextMethodName is the name of the method that runs after the bot receives the next user message.
I am trying to do a similar thing in Node.js. I have two functions. The first one prompts the user to enter something or click a button, and the second should process the user's input. I am struggling with passing control to the second function.
bot.dialog('subscribe', [
function (session) {
var card = new builder.HeroCard(session)
.title("Subscribe for reminders?")
.text("It seems you're not enrolled yet. Subscribe for reminders to submit your work hours?")
.buttons([
builder.CardAction.imBack(session, "subscribe", "Subscribe")
]);
var msg = new builder.Message(session).attachments([card]);
session.send(msg);
//next(); //compile error
},
function (session, results) {
if (results.response === 'subscribe') {
session.send('You are now subscribed to reminders through ' + session.message.user.channelId + '.');
}
else {
session.send('You must subscribe to reminders before using this bot.');
}
}
]);
How do I make the second function run after the user clicks the button or answers anything?
In node's botbuilder sdk, you can define waterfall dialogs that contains what are called as 'steps'. Each step leads to another (like a waterfall). According to docs:
'Waterfalls let you collect input from a user using a sequence of steps. A bot is
always in a state of providing a user with information or asking a
question and then waiting for input. In the Node version of Bot
Builder it's waterfalls that drive this back-n-forth flow'.
Some steps can start with a prompt to ask the user for information, and then the following step handles the response by saving it using dialogData. Then you can invoke the next function argument to pass control to the next step. In your case, calling next() gives you an error because that function isn't in scope, you must provide it as a parameter to your step function.
Check this sample here:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/core-MultiDialogs
In your first step code I would do:
function (session,args,next) {
var card = new builder.HeroCard(session)
.title("Subscribe for reminders?")
.text("It seems you're not enrolled yet. Subscribe for reminders to submit your work hours?")
.buttons([
builder.CardAction.imBack(session, "subscribe", "Subscribe")
]);
var msg = new builder.Message(session).attachments([card]);
session.send(msg);
next();
}
But that would just lead you to the next step, so if you want to wait for user input (with text prompt), or for example using HeroCard actions, like you defined in your sample:
Your card triggers an action called "subscribe" with the parameter "Subscribe" via a button. Think of this as a function that is called within your dialog by pressing the button on the card. Now to define that function, we do:
// An action is essentially a card calling a global dialog method
// with respective parameters. This dialog action will route the action
// command to a dialog.
bot.beginDialogAction('subscribe', '/subscribe');
// Create the dialog for the action...
bot.dialog('/subscribe', [
function (session, args) {
//do something!
}
]);

How to add metadata to nodejs grpc call

I'd like to know how to add metadata to a nodejs grpc function call. I can use channel credentials when making the client with
var client = new proto.Document('some.address:8000',
grpc.credentials.createInsecure()
)
Which are send when using client.Send(doc, callback), but the go grpc server looks in the call metadata for identification information which I have to set. I tried using grpc.credentials.combineChannelCredentials with the insecure connection and a grpc.Metadata instance but I can't find the right way to do it.
The error I run into is TypeError: compose's first argument must be a CallCredentials object. I tried to follow it down but it goes into c code which loses me, I can't see what javascript type I have to give to comebineChannelCredentials to achieve what I'm looking for and the docs are a little sparse on how to achieve this.
You can pass metadata directly as an optional argument to a method call. So, for example, you could do this:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);
For sake of completeness I'm going to extend on #murgatroid99 answer.
In order to attach metadata to a message on the client you can use:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);
On the server side int your RPC method being called, when you want to grab your data you can use:
function(call, callback){
var myVals = call.metadata.get("key");
//My vals will be an array, so if you want to grab a single value:
var myVal = myVals[0];
}
I eventually worked it out through introspecting the grpc credentials code and modifying the implementation to expose an inner function. In the grpc module in the node_modules, file grpc/src/node/src/credentials.js add the line
exports.CallCredentials = CallCredentials;
after CallCredentials is imported. Then, in your code, you can write something like
var meta = grpc.Metadata();
meta.add('key', 'value');
var extra_creds = grpc.credentials.CallCredentials.createFromPlugin(
function (url, callback) {
callback(null, meta);
}
)
Then use extra_creds in the client builder
var creds = grpc.credentials.combineChannelCredentials(
grpc.credentials.createSsl(),
extra_creds,
)
Now you can make your client
var client = new proto.Document(
'some.address:8000',
creds,
)

extend the CRUD method in LoopBack

I would like to know how to extend CRUD methods created by LoopBack.
I have a model with an attribute public_key. I would like to build two custom behaviors for the POST api endpoint for this model.
generate a public key and set the value
generate a private key and send it back as a result (using SSL)
How can I extend the default method to implement these behaviors?
I was able to override the default method by creating a javascript file under server/boot.
module.exports = function(app) {
var MyModel = app.models.MyModel;
var create = MyModel.create;
// Overrides POST '/api/MyModel' endpoint
MyModel.create = function(data, done) {
// Do custom things
create.call(MyModel, data, done);
};
};
However I was not able to modify the return value.
You can define custom remote methods that are exposed as REST endpoints

Resources