I’m new to chatbots, and have been trying to implement my own, using RASA. So far it has been going smoothly, due to this forum, the docs and youtube’s masterclass. I have, however, walked into a wall trying to get Two Stage Fallback Policy.
I’ve made it work with buttons, as shown in Open source Two Stage Fallback Policy with Rasa NLU and Rasa Core but can’t make it work with text instead. By text I mean waiting for an user input and then deciding if that input is an “affirm” or “deny” intent to set the payload’s next intent, instead of using buttons to the same effect.
Could you please share some of your insight on this?
Thank you in advance for any help provided
Has anyone had a go with this?
I heard it was possible before, as we could define the positive and negative intents to expect in two stage fallback policy, but how about now?
Hey @Nadroihr, could you share what you’ve attempted here so far? It should work both with buttons and with free text, as long as the correct intents are recognised
Hey @akelad, thank you for the reply.
How should I go about associating my ‘affirm’ and ‘deny’ intents to my two-stage fallback policy?
I’m working with Portuguese, and am not sure if that’s a limitation, but probably isn’t.
Right now I have buttons setting the payload to the next intent, whether it be the last intent a user mentioned or the out_of_scope intent. But I can only make this work with buttons
Hi there! Also building a portuguese chatbot in portuguese. I will probably need to do the same, since our main application is on whatsapp (no buttons so far), and from what I’ve seen in the code, we should be able to change the Action code to ask something like f"you meant to say {my_intent}? (yes/no)" and, instead of evaluating payloads that the answer will have, a simple way of doing if checking literally the answer for “yes” or “no” (otherwise you will need to pass it to nlu to get the intent).
Thank you for the help @lgabs
I also think that’s the way to go. I believe it would be something like checking for the literal answer value the user inputs, and then setting the payload with either the last intent or the “out-of-scope” intent.
How would one go about both checking an user input inside of an action, and setting the payload without using buttons?
@akelad
If you could further help us with this question, or pointing us in the right direction, that would be great
@lgabs you are correct in your assumption that you can change the action code to ask questions differently. See e.g. this example
As for the questions around handling free text user input - this should just be handled with NLU, make sure that you have NLU examples for the intents that you use as the payload and this should work just as well. If simple phrases like “yes” or “no” aren’t classified correctly with your model, then it’s a good idea to take a closer look at your training data and add more examples.
Can you please clarify on how to connect the NLU intent recognition to the 2 stage fallback procedure?
For exemple, I have both an affirm and a deny intent, and they are both getting perfectly recognized by RASA. When RASA uses the 2 stage fallback procedure, it triggers either the fallback_nlu_action_name or the fallback_core_action_name, which in my case are the same custom action. How do I make it so that this action knows it should expect a user text input that’s either an affirm or deny, and then set the payload correctly, depending on which of these intentions the user expressed?
I’m sorry if I’m making a mess of something that’s simple, but I really can’t get around this issue.
are you getting an error when the user just says “yes” rather than clicking the button? You don’t need to set any payload, this should work out of the box.
What does your configuration look like for the buttons?
class ActionDefaultAskAffirmation(Action):
"""
This action is the main fallback action. It consults our CSV database for
for an intent's matching response
"""
def name(self) -> Text:
return "action_default_ask_affirmation"
def __init__(self):
self.intent_mappings = {}
# read the mapping from the fallback_responses csv and store it in a dictionary
with open(r'data\fallback_responses.csv', newline='', encoding='utf-8') as file:
csv_reader = csv.reader(file)
for row in csv_reader:
self.intent_mappings[row[0]] = row[1]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]):
# get the most likely intent
last_intent_name = tracker.latest_message['intent']['name']
# get the prompt for the intent
intent_prompt = self.intent_mappings[last_intent_name]
# reply
message_number = random.randint(1, 4)
if message_number == 1:
message = "Peço desculpa, não tenho a certeza se percebi. Quis {}?".format(intent_prompt)
if message_number == 2:
message = "Lamento, não percebi bem. Quis {}?".format(intent_prompt)
if message_number == 3:
message = "Não tenho a certeza se percebi. Quis {}?".format(intent_prompt)
if message_number == 4:
message = "Não sei se percebi. Quis {}?".format(intent_prompt)
buttons = [{'title': 'Sim',
'payload': '/{}'.format(last_intent_name)},
{'title': 'Não',
'payload': '/out_of_scope'}]
dispatcher.utter_message(message, buttons=buttons)
These buttons do not allow for any user input text, but If I don’t have them implemented, and a two-stage fallback is triggered, and the user both affirms or denies, the chatbot will simply not answer, and wait for another input.
The RASA’s masterclass handbook says that:
deny_suggestion_intent_name - The name of the intent used to detect that the user has denied the suggested intents
So I set deny_suggestion_intent_name = deny in the .config file.
I’m also very interested in an answer to your question. I’m trying the same for the following reasons:
Buttons are not appropriate for our voice solution
We want to use a more intuitive description of the intents instead of “/name_of_intent”
The two stage fallback default language (English) replacing by a custom one (in our case German)
The problem I have (or its just a misunderstanding) is that the action_default_ask_affirmation sets an uncertain intent to a certain one in one action. It uses buttons with a payload and everything is done in one action call. But with our approach we have to call the action (to ask the affirmation), run the nlu again (to recognize the affirmation) and then run the action again to decide whether the original intent was correct or go further to the utter_ask_rephrase action.
So either I am misunderstanding this mechanism or the solution would be more complicated (e.g. by using a form_action?)
Thanks for your input on this!
I also think what you said is a possible solution, if a bit complex, as we would need to have several stories to accommodate the different turns in a Two-Stage fallback. I believe these stories would have to start with an action, and we would have to save slots with the user intent name, so we could then re-set them if the user affirms. Please correct me if I’m wrong.
This doesn’t seem to be very simple though, and I’m not sure how feasible it is. Is there really no other way, maybe something that’s already built-in? @akelad
It’s a bit strange we can’t just set a a deny and affirm intents for the policy.
Thank you all for your participation in this discussion!
This is a very late reply (been a little busy). Not sure what you mean with the stories for the different turns of the two-stage fallback policy, there’s no stories required for that.
It’s a bit strange we can’t just set a a deny and affirm intents for the policy. - but you can Policies
I’ve noticed the TwoStageFallbackPolicy has a deny_suggestion_intent_name, but how about the affirm one?
I’ve tried setting deny_suggestion_intent_name: “deny”, so that when my chatbot asks the user if he means x he can deny it and trigger the next stage of the fallback policy. But how do I set an affirm confirmation for it? (I believe that is missing from the documentation, or is not very clear)
The affirm one isn’t customisable on a policy level, but in the ActionDefaultAskAffirmation, defined here. By default it takes the intent from the latest user message, but you can customise that as you want.
The intent ActionDefaultAskAffirmation is defining there, if I’m correct, is the intent the chatbot should ask the user confirmation for.
With the “affirm” intent, I mean the intent the TwoStageFallbackPolicy should be looking for in the reply the user sends.
Example:
User: Hi chatbot
Chatbot: Hello
User: Can I order a pizza please?
Chatbot: I’m sorry I didn’t understand, did you mean to OrderFood? (this is where the intent_to_affirm appears)
User: Yes (this is where the “Affirm” intent I meant should be detected)
Basically, the affirm and deny intents I’m trying to detect, are the user answers, to either affirm or deny the intent the chatbot purposes.
That affirm intent you’re referring to is simply the intent the chatbot will set. That method does not use an intent to detect whether the user wants to affirm or deny the chatbot suggestion, It uses buttons.
My question is how to use text instead of buttons, to detect wether to set that “intent_to_affirm” or the “USER_INTENT_OUT_OF_SCOPE”, using that code as an example.
Also sorry for my late replay but I didn’t solve it either yet. What you said @Nadroihr is correct, we just try to replace the buttons in the fallback with a new series of actions to wit a new action listen and a new action affirm or deny. Now I try to realize this with the list of actions in the tracker but I couldn’t make it yet. Maybe I have to use the stories like you said @Nadroihr.