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!!!