Stop slot filling after 3 failed runs

Hi

Introduction:

I have a custom form which collects a few pieces of information from a user: name, birthday,…

Everything the user enters is validated by my class FormValidatorDispatcher. This works great. For example if the user writes 31.13.1999 (which is not a valid birthday!) in the slot, the validation will give an error message and will ask the user to repeat this step.

Goal:

Some user may have troubles to fill out the slots correctly. I want to stop the form after the user failed 3 times for one slot.

My approach:

This is my class which contains all slots that have to be filled by the user (name, name_last and birthday).

class AuthenticateForm(FormAction):

    """Example of a custom form action"""

    def name(self):
        ....
        return "authenticate_form"

    @staticmethod
    def required_slots(tracker):
        ....
        return ["name", "name_last", "birthday" ]

    def submit(self, dispatcher, tracker, domain):
        ....
        return []

    def slot_mappings(self):
        ....

        return {
            "name": [self.from_entity(entity="name", not_intent=["chitchat"])],
            "name_last": [self.from_entity(entity="name_last", not_intent=["chitchat"])],
            "birthday": [self.from_entity(entity="birthday", not_intent=["chitchat"])]
        }

    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():

            if slot == 'birthday':

                validator_birthday = FormValidatorDispatcher()
                if validator_birthday.is_valid_birthday(value, dispatcher, tracker):
                    date = dt.datetime.strptime(value, "%d.%m.%Y")
                    date_string = dt.date.strftime(date, "%d.%m.%Y")
                    slot_values[slot] = date_string
                else:
                    slot_values[slot] = None

          
            if slot == 'name':

                validator_name = FormValidatorDispatcher()
                if validator_name.is_valid_name(value, dispatcher, tracker):
                    slot_values[slot] = value
                else:
                    slot_values[slot] = None

            if slot == 'name_last':
                count = 0
                if count <= 2:
                    validator_name_last = FormValidatorDispatcher()
                    if validator_name_last.is_valid_name_last(value, dispatcher, tracker):
                        slot_values[slot] = value

                    else:
                        slot_values[slot] = None
                        count += 1

                else:
                    return self.deactivate()  # deactivate form

          

        # validation succeed, set the slots values to the extracted values
        return [SlotSet(slot, value) for slot, value in slot_values.items()]

I started with the slot name_last. I used a counter variable that starts with 0 --> counter = 0. Each time the validation of the slot returns False (meaning the slot value is not valid), I incease the counter variable by 1. After 3 fails I want the form to be deactivated.

My problem:

It does not work, because each time the slot_value is set to None my count variable is set to 0 again. I do not know where to place count = 0 to initialize the variable.

How can I count how many times the user failed to enter the correct value?

Hope you can help me!!!

Can you set the count to a slot, then when you deactivate the form, you also reset the count to 0 ?

2 Likes