Back to the question before if the user were wrong

Hi everyone,

I’m wondering if we can rollback to the question before in my bot using a button “Rollback” as example if the user were wrong ?

Thank you in advance.

Hi @Ahmed, you might be interested in using action_back. You can invoke it by having a custom action return ActionBack(). This action should not be written into stories, there should be no stories in which the user is wrong and it rolls back.

Thank you @erohmensing, i’m not able to import MappingPolicy in my actions.py .

@Ahmed you don’t have to, just add it to you policies in your config.yml and retrain :slight_smile:

Thank you @erohmensing, i posted a topic in how i can add a calendar to my webchat or having the type date in a field, i tested the example on rasa doc (Domains) talking about custom output payload but it’s not working. Do you have any idea about that ? Thank you

@Ahmed the datepicker mentioned here is specifically formatted for Slack, it won’t work in other channels. You can use custom output payloads to send any message to your output channel, but the different types of things you can send depend on what that channel (your webchat) supports. If you want to support the user free-typing the date, I suggest you add Duckling to your pipeline.

@erohmensing thank you !

@erohmensing we checked your solution, i forgot to mention that i want in a rollback in a formAction. There are many requested slots and i would like for the user to go back to the former slot if he makes an error. Thank you

Hi @Ahmed

sounds to me like a case for a validation method - since this is what validators are up for. If your case can’t be handled by a validation method, you should provide a sample.

Another possible solution could be:

UserUtteranceReverted() combined with SlotSet()

@erohmensing Wouldn’t that have the desired effect - besides what I previously mentioned?

Regards

Yes, I think @JulianGerhard is right. In forms, you can add a helper validation method, which will check the user’s answer. If it’s a wrong (not acceptable) answer, the form will not accept it, won’t populate the slot, and will ask again. More info found here.

I believe the tracker would actually undo the slots if action_back is used. However within a form it gets complicated and that might not be the case. Where are you writing this code for correcting the mistakes if its happening in a form?

I tried to use UserUtteranceReverted() in my action_back, but the bot is asking the actual slot question, and not rolling back to the question before.

I want to go back to the question : Quel est le nom de la personne que vous voulez ajouter ?

@erohmensing @JulianGerhard

@Ahmed action_back is actually already an action, you don’t have to write a new one. it will return two UserUtteranceReverted()s, so I think it will do what you want it to do. How are you currently triggering that action? would suggest you make an intent for something like go_back, and then make it so that

go_back:
    triggers: action_back

I hope this will achieve what you want it to (but it will also depend on how you have your slot mappings defined).

@JulianGerhard @erohmensing i’m trying to launch the action back using UserUttered but it’s not working. Any ideas ?

Can you post your whole code for that action, as well as a full description of what you’re trying to achieve with the form and the going back? I feel like theres probably a better way than the way you’re handling it. Have you tried with the intent and the mapping? You want to be able to handle more ways of saying go back than just the word “retour”.

@erohmensing @Ahmed

Based on that, how about the following suggestion, besides what @erohmensing mentioned previously (an which is quite useful!):

Let’s assume the user is in the process of a FormAction - some of the slots are filled, some not. “Making an error” is quite ambiguous in the context of conversational AI, but let’s further assume that you mean: If the user fills a slot, the bot utters the question for the next slot and then the user states that he has filled the last slot with the wrong value - accidently. Now you are imho asking for a method of correcting this slot.

I think going backward is not the best way to achieve this functionality. My suggestion - and @erohmensing correct me if this is a bad approach:

  1. Add an intent “correct_slot_value” with enough samples

  2. Write a class method for the FormAction (or a CustomAction that is triggered with this intent):

    def run(self, dispatcher, tracker, domain):
    return[SlotSet(“name_of_the_last_slot”, None)]

  3. You now might not want to add this to your story, instead I’d suggest to overwrite the validate-function in your FormAction by basically leaving it as it is besides adding the following call to it:

    if tracker.latest_message[‘intent’].get(‘name’) == ‘correct_slot_value’:
    <METHOD_CALL>

I’d suggest to put it that way because if you put it in the validation_ methods, it might not get excuted if the user utters something out of that no entity is extracted hence no slot is filled.

This would cause the bot to reask for the slot because it isn’t filled yet and you didn’t break the proceeding of the story.

Might this work?

@erohmensing Hi,

Here is an example of my code. In a FormAction, I would like for the user to be able to correct his answer and go back to the former question. For example, the bot will ask for the name (“nom”) and the user will write it. The bot will then ask for the surname. At that moment, if the user write “retour”, the bot should ask again for the name (and put the right value in the slot).

action.py

Class CreateForm(FormAction): “”“Example of a custom form action”""

def name(self):
    # type: () -> Text
    """Unique identifier of the form"""

    return "formulaire"

@staticmethod
def required_slots(tracker: Tracker) -> List[Text]:
    """A list of required slots that the form has to fill"""

    return ["nom","surname","rest", "date"]

def slot_mappings(self):
    # type: () -> Dict[Text: Union[Dict, List[Dict]]]
    """A dictionary to map required slots to
        - an extracted entity
        - intent: value pairs
        - a whole message
        or a list of them, where a first match will be picked"""

    return {"nom": self.from_text(), "surname": self.from_text(), 
            "rest": self.from_text(), "date": self.from_text()}

def validate(self,
             dispatcher: CollectingDispatcher,
             tracker: Tracker,
             domain: Dict[Text, Any]) -> List[Dict]:
    """Validate extracted requested slot
        else reject the execution of the form action
    """
    # extract other slots that were not requested
    # but set by corresponding entity
    slot_values = self.extract_other_slots(dispatcher, tracker, domain)

    # extract requested slot
    slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
    if slot_to_fill:
        slot_values.update(self.extract_requested_slot(dispatcher,
                                                       tracker, domain))
        if not slot_values:
            # reject form action execution
            # if some slot was requested but nothing was extracted
            # it will allow other policies to predict another action
            raise ActionExecutionRejection(self.name(),
                                           "Failed to validate slot {0} "
                                           "with action {1}"
                                           "".format(slot_to_fill,
                                                     self.name()))

    # we'll check when validation failed in order
    # to add appropriate utterances
    for slot, value in slot_values.items():
       
            
        msg = tracker.latest_message.get('text')   
        if msg=="retour":
            return [FollowupAction("action_back")]
        
    # validation succeed, set the slots values to the extracted values
    return [SlotSet(slot, value) for slot, value in slot_values.items()]

def submit(self,
           dispatcher: CollectingDispatcher,
           tracker: Tracker,
           domain: Dict[Text, Any]) -> List[Dict]:
    """Define what the form has to do
        after all required slots are filled"""
    return []

actions.yml

  • utter_ask_nom
  • utter_ask_surname
  • utter_ask_rest
  • utter_ask_date
  • action_booking
  • utter_booking

forms.yml

  • formulaire

intents.yml

  • booking

entities.yml

  • nom
  • surname
  • rest
  • date

slots.yml

nom: type: text surname: type: text rest: type: text date: type: text


utter_ask_nom:

  • text: “What is your name?”

utter_ask_surname:

  • text: “What is your surname?”

utter_ask_rest:

  • text: “Which restaurant?”

utter_ask_date:

  • text: “Which date?”

utter_booking:

  • text: “The restaurant is booked.”

stories.md

story 1

  • booking
  • formulaire
  • form{“name”:“formulaire”}
  • slot{“nom”:“None”, “surname”:“None”, “rest”:“None”, “date”: “None”}
  • form{“name”:null}
  • utter_booking
  • action_restart

@JulianGerhard thank you i’ll check your solution.

//digression maybe? @erohmensing @JulianGerhard Does UserUtteranceReverted actually delete events from tracker since the last user utterance? If not how does the Policy knows how to featurize that for predicting next action? Thanks

did you find the solution?
any solution @erohmensing @Ahmed