Get previous intent name from Rasa action? - rasa-core

I have an intent called intent_yes which is shared in several different conversational flows. When the user says "Yes" or "Yeah" etc., it will call my webhook / Rasa action. I need to know what they've said yes to. How can we get the previous intent name from a Rasa webhook action?

I think I agree with the OP.
There are times, when an intent is activated for whole different reasons.
For instance, you have words like "Why?" "How?" for some specific intents, and their corresponding actions get triggered without discrimination.
How do you prevent such basic expressions from being triggered in the most unlikely scenarios?
Surely it is not efficient to write stories for each conceivable conversational turns for "Why" & "How".
This is why I wanted a solution that checks the state of the conversation and determine if a particular intent has been triggered before running.
And Tom's solution above makes sense.
I will try that.
UPDATE:
This was my solution:
def get_latest_event(events)
latest_actions = []
for e in events:
if e['event'] == 'action':
latest_actions.append(e)
return latest_actions[-2:][0]['name']
get_latest_event(tracker.events)
I thought it best to wrap it in a function for portability.
I init an empty list.
Go through all the given events.
If the event is an action event, I push it into the empty list above.
I then return with the last two objects, pick the name of the first one.
The assumption is that we are looking for the last action that was triggered.
Again, my use-case is, I want a way to control my response to a generic follow-up question.
For instance, a user asks why?
I want to know the last thing the bot said (action) that triggers that why.
If it is an edge-case that I am interested in, I handle it differently.
If not, I respond generically.
Is this hacky?
Maybe.
But until I can figure out a way to prevent myself from writing stories for all possible ways a user can ask 'why?', this will do.
I am open to better suggestions.

This is probably not good design - you're better off writing individual stories for each flow and then having a corresponding action for each circumstance, however within the custom action's run method you can access the tracker. This object holds all the events of the conversation in a list called tracker.events, which
will look something like this:
[{'event': 'action', 'timestamp': 1558688062.7624729, 'name': 'action_listen', 'policy': None, 'confidence': None},
{'event': 'user', 'timestamp': 1558688062.7628329, 'text': '/joke', 'parse_data': {'text': '/joke', 'intent': {'name': 'joke', 'confidence': 1.0}, 'intent_ranking': [{'name': 'joke', 'confidence': 1.0}], 'entities': []}, 'input_channel': 'rest'}]
To get the user messages just iterate backwards over this list until you find "event":"user" and the intent is given inside "parse_data"["intent"]

Related

How can I use an observable to perform a recursive search without going over duplicates?

I'm going to phrase the question in rxjs, but I suppose it's similar for any Rx or observable library.
Say I have an observable of users, and a function getAssociates(user) that returns another observable of users. I want to use the getAssociates function on every user in the observable and return an observable of those associates. flatMap is enough for this.
But I also want to run getAssociates on each associate that comes back, but without ever running it twice on any given user (since two users might share an associate, and if A has B as an associate, then B also has A as an associate).
Something like the expand operator is what I think I'm looking for:
seedUsers.pipe(
expand(user => getAssociates(user)),
);
but how can I get in the bit about not running twice on any given user? I could maintain a list of seen users, but I'd like to achieve it in a functional style.
Conceptually, you need to :
Keep track of the known users, for example using a Set
Filter the known users before making a request, for example using filter operator
Here is a suggestion :
let knownIds = new Set();
getAllItems(Ids){
return from(Ids).pipe(
filter(id => ! knownIds.has(id)),
concatMap(id => getAllItems(id)),
map( id => knownIds.add(id))
)
}
getAllItems([originalId]).subscribe( allItems=> console.log)
Notes:
I guess you could manage to do it using rxjs, but none of the solutions I can think of is simpler than using a set + filter.
I used concatMap to ensure you don't run the request twice. Using mergeMap (flatMap), you could have a scenario like this :
---------Req(user1)----------------------------resp(user1)-------------------------
---Req(user2)--------resp(user2)--Req(user1)-----------------resp(user1)-
But if you accept having eventually more than 2 requests per user, you can use flatMap to gain speed.

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.

How can the User Interface know which commands is allowed to perform against an Aggregate Root?

The UI is decoupled from the domain, but the UI should try its best to never allow the user to issue commands that are sure to fail.
Consider the following example (pseudo-code):
DiscussionController
#Security(is_logged)
#Method('POST')
#Route('addPost')
addPostToDiscussionAction(request)
discussionService.postToDiscussion(
new PostToDiscussionCommand(request.discussionId, session.myUserId, request.bodyText)
)
#Method('GET')
#Route('showDiscussion/{discussionId}')
showDiscussionAction(request)
discussionWithAllThePosts = discussionFinder.findById(request.discussionId)
canAddPostToThisDiscussion = ???
// render the discussion to the user, and use `canAddPostToThisDiscussion` to show/hide the form
// from which the user can send a request to `addPostToDiscussionAction`.
renderDiscussion(discussionWithAllThePosts, canAddPostToThisDiscussion)
PostToDiscussionCommand
constructor(discussionId, authorId, bodyText)
DiscussionApplicationService
postToDiscussion(command)
discussion = discussionRepository.get(command.discussionId)
author = collaboratorService.authorFrom(discussion.Id, command.authorId)
post = discussion.createPost(postRepository.nextIdentity(), author, command.bodyText)
postRepository.add(post)
DiscussionAggregate
// originalPoster is the Author that started the discussion
constructor(discussionId, originalPoster)
// if the discussion is closed, you can't create a post.
// *unless* if you're the author (OP) that started the discussion
createPost(postId, author, bodyText)
if (this.close && !this.originalPoster.equals(author))
throw "Discussion is closed."
return new Post(this.discussionId, postId, author, bodyText)
close()
if (this.close)
throw "Discussion already closed."
this.close = true
isClosed()
return this.close
The user goes to /showDiscussion/123 and he see the discussion with the <form> from which he can submit a new post, but only if the discussion is not closed or the current user is who started that discussion.
Or, the user goes to /showDiscussion/123 where it's presented as a REST-as-in-HATEOAS API. A hypermedia link to /addPost will be provided, only if the discussion is not closed or the authenticated user is who started that discussion.
How can I provide that knowledge into the UI?
I could code that into the read model,
canAddPostToThisDiscussion = !discussionWithAllThePosts.discussion.isClosed
&& discussionWithAllThePosts.discussion.originalPoster.id == session.currentUserId
but then I need to maintain that logic and keep it in sync with the write model. This is a fairly simple example, but as the states transitions of an aggregate become more complex, it may become really hard to do. I'd like to image my aggregates as state machines, with their workflows (like the RESTBucks example). But I don't like the idea to move that business logic outside my domain model, and put it in a service that both the read side and write side can use.
Maybe this isn't the best example, but as an aggregate root is basically a consistency boundary, we know that we need to prevent invalid state transitions in its life cycle, and in each transitions to a new state some operations may become illegal and vice versa. So, how can the user interface know what is allowed or not? What are my alternative? How should I approach to this problem? Do you have any example to provide?
How can I provide that knowledge into the UI?
The easiest way is probably to share the domain model's understanding of what is possible with the UI. Ta Da.
Here's a way to think about it -- in the abstract, all of the write model logic has a fairly simple looking shape.
{
// Notice that these statements are queries
State currentState = bookOfRecord.getState()
State nextState = model.computeNextState(currentState, command)
// This statement is a command
bookOfRecord.replace(currentState, nextState)
}
Key ideas here: the book of record is the authority of state; everybody else (including the "write model") is working with a stale copy.
What the model represents is a collection of constraints that ensure that the business invariant is satisfied. Over the lifetime of a system, there might be many different sets of constraints, as the understanding of the business changes.
The write model is the authority for which collection of constraints is currently enforced when replacing the state in the book of record. Everybody else is working with a stale copy.
The staleness is something to keep in mind; in a distributed system, any validation you perform is provisional -- unless you have a lock on the state and a lock on the model, either could be changed while your messages are in flight.
This means that your validation is approximate anyway, so you don't need to be too concerned that you have all of the fiddly details right. You assume that your stale copy of the state is approximately right, and your current understanding of the model is approximately right, and if the command is valid given those pre-conditions, then it is checked enough to send.
I don't like the idea to move that business logic outside my domain model, and put it in a service that both the read side and write side can use.
I think the best answer here is "get over it". I get it; because having the business logic inside the aggregate root is what the literature is telling us to do. But if you continue to refactor, identifying common patterns and separating concerns, you'll see that entities are really just plumbing around a reference to state and a functional core.
AggregateRoot {
final Reference<State> bookOfRecord;
final Model<State,Command> theModel;
onCommand(Command command) {
State currentState = bookOfRecord.getState()
State nextState = model.computeNextState(currentState, command)
bookOfRecord.replace(currentState, nextState)
}
}
All we've done here is taken the "construct the next state" logic, which we used to have scattered through out the AggregateRoot, and encapsulated it into a separate responsibility boundary. Here, its specific to the root itself, but an equivalent refactoring it so pass it as an argument.
AggregateRoot {
final Reference<State> bookOfRecord;
onCommand(Model<State,Command> theModel, Command command) {
State currentState = bookOfRecord.getState()
State nextState = model.computeNextState(currentState, command)
bookOfRecord.replace(currentState, nextState)
}
}
In other words, the model, teased out from the plumbing of tracking state, is a domain service. The domain logic within the domain service is just as much a part of the domain model as the domain logic within the aggregate -- the two implementations are dual to one another.
And there's no reason that a read model of your domain shouldn't have access to a domain service.
I don't like the idea of sharing domain knowlegde (code) between the write and the read models as you will have to continously keep them in sync and that'd really a chalenge even if you are the only developer in your company.
But the good knews is that you don't have to duplicate anything. If you designed your Aggregate to be pure, with no side effect as you should do (!), you can simply send it the command but without persisting the changes. If the command throws an exception then the command would not succeed, otherwise the command would succeed. In case of CQRS this is even better as you have a 3rd outcome: idempotent command detection in which case the command succeeds but it has no effect (no events are raised but no exception is thrown either) and the UI might find this interesting.
So, as an example you could have something like this:
DiscussionController
#Security(is_logged)
#Method('POST')
#Route('addPost')
addPostToDiscussionAction(request)
discussionService.postToDiscussion(
new PostToDiscussionCommand(request.discussionId, session.myUserId, request.bodyText)
)
#Method('GET')
#Route('showDiscussion/{discussionId}')
showDiscussionAction(request)
discussionWithAllThePosts = discussionFinder.findById(request.discussionId)
canAddPostToThisDiscussion = discussionService.canPostToDiscussion(request.discussionId, session.myUserId, "some sample body")
// render the discussion to the user, and use `canAddPostToThisDiscussion` to show/hide the form
// from which the user can send a request to `addPostToDiscussionAction`.
renderDiscussion(discussionWithAllThePosts, canAddPostToThisDiscussion)
DiscussionApplicationService
postToDiscussion(command)
discussion = discussionRepository.get(command.discussionId)
author = collaboratorService.authorFrom(discussion.Id, command.authorId)
post = discussion.createPost(postRepository.nextIdentity(), author, command.bodyText)
postRepository.add(post)
canPostToDiscussion(discussionId, authorId, bodyText)
discussion = discussionRepository.get(discussionId)
author = collaboratorService.authorFrom(discussion.Id, authorId)
try
{
post = discussion.createPost(postRepository.nextIdentity(), author, bodyText)
return true
}
catch (exception)
{
return false
}
You could even have a method named whyCantPostToDiscussion that would return the exception or the exception message and display it in the UI.
There is only one issue with the code: the call to postRepository.nextIdentity() because it would increase the next ID every time but you could replace it with something like postRepository.getBiggestIdentity() that should have no side effect.
I find it is rare that authorization is actually part of the domain. If it isn't, it makes sense to move that logic out into its own service which the UI and the domain can make use of.
I like to build up a set of rules using the specification pattern. I find it to be a fairly elegant way to build up the rules.
This also plays very well in a CQRS context as you can run each command through the 'rules engine' before they get issued to your AR's. If you push queries through a message routeing system you can do the same for queries. I've had a lot of success with this approach.
The response you are looking for is HATEOAS, look no further. You must implement your rest api as really restful (level 3) adhering to hypertext to model the state transitions and return links to the clients (being the UI one of those). These links represent the actions the user can execute in its context according to the model state. It´s simple. If you return a link from the server then you bind it to a button in the UI, if you don´t return the link because of business invariants then you do not show the button on the UI. There is a lot more of concepts behind it such as designing a good API supporting a well designed domain model behind but this is the general idea around it and fits exactly what you want.

c# Bot Builder SDK - Approach for Disambiguation

I'm building a LuisDialog and have LUIS integration working well.
In the cases where LUIS doesnt fill in all the gaps I need, what is the best approach for disambiguation?
Right now, I use PromptDialog callbacks - So inside a Dialog method (decorated with the LuisIntent attribute), when I need to get more details/disambiguate i'd have:
PromptDialog.Choice<string>(context, EnsureTimeOfDayChosen, new[] { "Morning (AM)", "Afternoon (PM)", "Any" }, "What time of day would you like us to book the appointment? (AM/PM/Any)", "Please choose AM or PM. Alternatively, if you don't mind which, just say Any.");
And the delegate's body (EnsureTimeOfDayChosen):
string AmPmOrAny = await result;
context.PerUserInConversationData.SetValue<string>("TimeOfDay", AmPmOrAny);
BookAppointment(context);
The problem with this approach is the last line of the delegate - it doesn't feel right. I can't easily call back into the place I was in the initially called, LuisIntent decorated method and resume.
Instead, I have to deal with the LUIS info up front, and call the BookAppointment method after gathering more info, and storing it in PerUserInConversationData.
Am I doing it wrong?
Any help would be greatly appreciated - Kind Regards,
Matt.
Given current implementation of the Dialog model, I cannot think of a better way of implementing your logic. Currently anytime that you are waiting on an async response from the user, your code will be resumed on the callback you provided upon response. You can think of it as Begin/End model for async programing

What is the 'right' data structure to turn app features on/off based on 'type' of account?

My app has 10 features that are enabled/disabled depending upon which of the 3 'types' of account a user has.
Currently, I have 10 methods (one per feature) along the lines of:
def is_FEATURENAME_enabled
case currentuser.accounttype
when "A", "C" # account types allow to see that feature
return true
else
return false
end
end
Then, in each place where I potentially disable a feature, I do
if foo.is_SOMEFEATURE_enable
do stuff to enable that feature
end
It works. It's not that hard to maintain. But there should be a better way. I suspect the right solution is to define some sort of structure (hash? I dunno) in one place that maps enabled features to accounttypes, then have a single method that I call something like:
if foo.is_feature_enabled(:FEATURENAME)
do stuff to enable feature
end
where the method is_feature_enabled looks at currentuser.accountype and checks the mapping structure to see if the identified feature is enabled.
And I suspect the DRY way to define that mapping (given I have WAY more features than account types) is to list all the features ONCE then for each feature list the accounttypes that have access to that feature (not the other way around). That way when I add a new feature I only have to edit ONE line in the mapping. Something like:
FeatureA: usertype1
FeatureB: usertype1, usertype3
FeatureC: usertype2
...
seems more logical and easier to maintain than:
usertype1: FeatureA, FeatureB, FeatureD, FeatureG
usertype2: FeatureC, FeatureD
usertype3: FeatureB, FeatureD, FeatureG, FeatureH
Any suggestions would be appreciated, and instructive for learning The Right Way to do stuff in ruby.
I think you've pretty much discovered the best way to do it on your own-- what you suggest is wise. Just use the feature name as a lookup key for your hash, then take the resulting list and check whether that list contains the account type of the current user.
E.g.,
# For example...
$AllowedUserCastes = {
:CanLogin => ["admin", "paiduser", "crazyuser", "anonymous"],
:CanDrink => ["admin", "21yearolduser", "crazyuser"],
:CanArrest => ["admin", "police"]
}
def featureAllowed?( whichFeature )
$AllowedUserCastes[whichFeature].include? currentUserCaste()
end
It sounds like you're looking for some kind of event dispatcher. I've yet to bump into a very good one in ruby. But I'm sure I've missed a few, so I'll be happy to be stood corrected in the comments.

Resources