MS BotBuilder : How can I set a combination of an intent and an entity to trigger a dialog? - botframework

I'm using the MS BotBuilder to create a bot language understanding bot. I have a dialog readProfile that's triggered on Read intent that is trained on LUIS.
bot.dialog('readProfile', [
function (session, args) {
var entities = args.intent.entities;
console.log("entities : ", entities)
]).triggerAction({
matches: 'Read'
}).cancelAction('cancelReadProfile', "Ok.", {
matches: /^(cancel|nevermind)/i
});
The LUIS model is trained to recognise entities like Profile and others so I do get the entity in console.
However, I wish to trigger the dialog only if the entity recognised is Profile. I can set some logic to work only when the entity in args is Profile but wondering if there's a builtin / more elegant way to do this.
Thanks for your input.

I think using a logic statement in the first step of the readProfile dialog is the best way to do this. If no Profile entity is found, end the dialog with a message like "It looks like you're trying to read a profile, but didn't I couldn't figure out what profile you're trying to read." This has the advantage of giving the user some feedback about their action and helping them figure out what they need to fix.
You could try to train the Luis model to have a strong correlation between having a Profile entity and the Read intent. Enter a few utterances that are really close to the Read intent but don't include a Profile and mark them with the None intent. That doesn't guarantee that it won't ever match a Read intent without a Profile, though, so I'd still recommend the above step.

Related

Clean Architecture: How to reduce complexity when writing application business rules?

Let's assume we have the following "Create User" scenario:
Users can signup to the application using Facebook, Google+ or LinkedIn;
The backend should retrieve some basic profile information in order to register the user(email, firstName and lastName);
Users are registered with a "client Id" (Just adding complexity to the business rule);
When a signup process is done the data should be sent to a notification topic.
I can imagine a create user request with the following structure:
{
"clientId": "someClientId",
"authProvider": "FACEBOOK | GOOGLE | LINKEDIN",
"accessToken": "someAccessToken"
}
So, thinking about the registration/validation flow we would have:
Check if the create user request is valid;
Check if the clientId is valid;
Try to retrieve the profile information from the social network api;
Check if all the required profile information is filled;
Check if the user exists in the database;
Register the user;
Send the data to the notification topic;
Pass the data to the presenter.
Jumping straight to the use case, we would have a constructor like:
CreateUserUseCase(
ApplicationClientGateway applicationClientGateway,
SocialNetworkGateway socialNetworkGateway,
UserGateway userGateway,
NotificationGateway notificationGateway,
Presenter presenter
)
and an execute method:
execute(CreateUserRequest request)
// validates the payload
// something like
if (request == null)
presenter.setError(someError);
// validates the clientId
applicationClientGateway.findById(request.getClientId())
// retrieves the profile information
// how to inject dinamically the implementation for
// Facebook, Google or LinkeIn based on a request parameter?
profile = socialNetworkGateway.findByAccessToken(request.getAccessToken());
// checks if the user exists
userGateway.findByEmailAndAuthProvider(profile.getEmail(), request.getAuthProvider());
//register the user
userGateway.insert(user);
//sends the notification
notificationGateway.send(user);
// sets the result
presenter.setResult(user);
Now, we have a constructor with lots of arguments(code smells?) and at least 5 validation steps in the execute method.
It looks like a violation of the SRP, so, how can we decompose this code in order to reduce complexity in the interactor?
First of all, lets break this in some small steps:
1) Related to the presenter, looks like you are intersted in give the workflow some output, right? Assuming that, maybe it will be better to return what you want from the usecase and handle this one layer above. (-1 parameter at constructor)
2) Like the others answers are saying, looks like your usecase has a LOT of responsabilities right now. I will suggest you to break this in more then one usecase.
Something like:
... Your first gateway (API)
..... ValidateClientId.execute();
..... profile = RetrieveProfile.execute();
..... InsertUser.execute(...)
3.1) Related to inject the correct bean based on the correct social network, you can handle this logic INSIDE the gateway, not before call it. Remembet that one gateway CAN call another gateway (they are at same layer). So, I suggest you to use something like.
At usercase -> socialNetworkGateway.findByAccessToken(...)
Inside the gateway you can do your "switch" and call somthing like the FacebookGateway, GoogleGateway, etc.
SRP does not say that you have to have small methods or only few constructor parameters. SRP says "there should be only a single reason to change the code".
As far as I can see you explicitly implemented the "business logic sequence" required to register a new user. Even though this may require some "external services" and/or repositories there is still only one reason to change the logic of this code: if the logic "how to register a user" changes.
From this perspective you are not violating SRP.
According to Uncle Bobs picture on "control flow" (https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) it is also totally correct to pass the presenter.
If you still feel the need to reduce the dependencies of your use case class I would suggest looking into "unit of work" pattern and check whether it would make sense to combine some of the dependencies.
More details on "What is a use case in Clean Architecture" you can find in my blog series: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases/

Recognize the user input inside the handler function using dialogflow.ai/api.ai and Microsoft Bot Builder

I am building a bot using the given technology stacks:
Microsoft Bot Builder
Node.js
Dialogflow.ai (api.ai)
We used waterfall model to implement a matched intent Dialog, which includes a couple of handler functions and prompts. After following this scenario I need to identify the entities inside an inner handler function, for a user input.
eg:
Bot : Where do you want to fly?
User: Singapore. (For this we added entities like SIN - Singapore,SIN(Synonym), So I need to resolve the value as SIN)
Any help on this scenario is much appreciated.
Here is a post Using api.ai with microsoft bot framework you can refer for your reqirement, and with a sample at https://github.com/GanadiniAkshay/weatherBot/blob/master/api.ai/index.js. The weather api key leveraged in this sample is out of date, but the waterfall and recognizer api key is still working.
Generally speaking:
Use api-ai-recognizer
Instantiate the apiairecognizer and leveraged builder.IntentDialog to include the recognizer:
var recognizer = new apiairecognizer("<api_key>");
var intents = new builder.IntentDialog({
recognizers: [recognizer]
});
In IntentDialogs, use builder.EntityRecognizer.findEntity(args.entities,'<entity>'); to recognize the intent entities.

Unable to understand correct use of None intent in LUIS

I have an app in LUIS with one intent "Help" (appart from None) and when I test it with utterances that my intent does not cover (e.g "Hi man"), LUIS resolves to the "Help" intent... I have no utterances in "None" intent...
What should I do? Should I add all the utterances I don't want to match "Help" intent in "None"?
Should I need to know everything a user can ask to my bot which is not related with "Help"?
For me, that's not make sense at all... and I think that is exactly how LUIS works...
Intent are the action which we define, None is predefined Intent which come along with every LUIS model that you create , coming back to your problem. You have only define one intent i.e "help" so whenever LUIS gets the any query it will show the highest scoring intent i.e. "help". whenever you create an intent make to sure to save at least 5-6 co-related utterance, so that LUIS can generate a pattern out of it 'more you define co-related utterance better accuracy of result you will get'
if you want LUIS to respond on "HI man" create a new intent 'greet' save some utterance let LUIS do the remaining task, lastly about None intent If any user input 'asdsafdasdsfdsf' string like this. Your bot should be able to handle it respond accordingly like 'this asdsafdasdsfdsf is irrelevant to me' in simple term 'any irregular action that user want bot to perform come under none intent' i hope this will help
You can check the score of the Luis intent and then accordingly send the default response from code. For the utterances which are configured will have a greater score. Also, Luis app shud be balanced in terms of utterances configured as there is not a defined way that u can point utterances to None intent. Please check this link for best practices.
https://learn.microsoft.com/en-us/azure/cognitive-services/luis/luis-concept-best-practices. Also to highlight Luis does not work in terms of keyword matching to the utterances which you have configured. It works in terms of data you add in Luis in respective intents.

Correct way to handle entities anytime in middle of conversation

I have started working with the LUIS and bot framework recently, after having some experience also with API AI / Google home development.
In the sample below that, I will use an example (from https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-dialog-waterfall) is exemplified a step by step interaction with a user. First, it asks for a date, then a number, then a name for the reserve, and so on.
var bot = new builder.UniversalBot(connector, [
function (session) {
session.send("Welcome to the dinner reservation.");
builder.Prompts.time(session, "Please provide a reservation date and time (e.g.: June 6th at 5pm)");
},
function (session, results) {
session.dialogData.reservationDate = builder.EntityRecognizer.resolveTime([results.response]);
builder.Prompts.text(session, "How many people are in your party?");
},
function (session, results) {
session.dialogData.partySize = results.response;
builder.Prompts.text(session, "Who's name will this reservation be under?");
},
function (session, results) {
session.dialogData.reservationName = results.response;
// Process request and display reservation details
session.send("Reservation confirmed. Reservation details: <br/>Date/Time: %s <br/>Party size: %s <br/>Reservation name: %s",
session.dialogData.reservationDate, session.dialogData.partySize, session.dialogData.reservationName);
session.endDialog();
}]);
In my code, I have a similar multi-parameter dialog, but I want to allow the user to answer with multiple information at the same time in any of the responses it have. For example, after providing the reservation date the user can say "a reserve for Robert for 10 people", so both numbers of people and reservation name are giving at the same time.
To identify these text entities I suppose I have to call LUIS and get the entities resolved from the session context. I notice that the bot object has a recognized method that I think can work for that.
My question is how do I organize the structure of the code and the LUIS utterances and entities? Right now I have an intent with some entities and several utterances samples, but if I send this 'partial' user sentence I think it will not be mapped to the same intent and may not identify the entities with a small sentence like that.
How should I handle this? Do I need to provide samples for the intent with these partial sentences, that may contain only some of the entities?
Thanks
Yes, you should provide samples for all those utterances that you want to your intent to recognize. Not a million of samples, but just as few to get everything trained.
Then, the other problem that you might want to solve next, is asking for the information for those entities missing in the utterance. You can do that manually or you could go one step further and explore the LUIS Action Binding library.

How to ask open questions in bot framework?

I am building a chat bot using Bot Framework, C# Bot Builder and FormFlow (with FieldRelfector).
At one step I need to ask an open question to the user like "Add any other relevant information", where I just want to collect some text and store it for later usage.
I tried to define the variable as String:
[Prompt("Add any other relevant information")]
public string OpenText;
In the form chain I have:
.Field(new FieldReflector<MyForm>(nameof(OpenText))
.SetType(null)
.SetActive(state => !state.Finished()))
but that doesn't help, whatever I type the bot answers:
"blah blah" is not a open text option.
How to handle this?
Is there any reason you are using a FieldReflector for that property? I would suggest just defining a normal field for that property (you can have a form with fields defined with FieldReflector and fields defined just with Field).
Just use:
.Field(nameof(MyForm.OpenText), state => !state.Finished())
If there is a reason to use FieldReflector, please update the post with the entire form definition.

Resources