def test_validate_prefilled_slots(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] def validate_some_slot(self, value, dispatcher, tracker, domain): if value == "some_value": return {"some_slot": "validated_value"} else: return {"some_slot": None} form = CustomFormAction() tracker = Tracker( "default", {"some_slot": "some_value", "some_other_slot": "some_other_value"}, { "entities": [{"entity": "some_slot", "value": "some_bad_value"}], "text": "some text", }, [], False, None, {}, "action_listen", ) events = form._activate_if_required(dispatcher=None, tracker=tracker, domain=None) # check that the form was activated and prefilled slots were validated assert events == [ Form("some_form"), SlotSet("some_slot", "validated_value"), SlotSet("some_other_slot", "some_other_value"), ] or events == [ # this 'or' is only necessary for python 2.7 and 3.5 Form("some_form"), SlotSet("some_other_slot", "some_other_value"), SlotSet("some_slot", "validated_value"), ] events.extend( form._validate_if_required(dispatcher=None, tracker=tracker, domain=None) ) # check that entities picked up in input overwrite prefilled slots assert events == [ Form("some_form"), SlotSet("some_slot", "validated_value"), SlotSet("some_other_slot", "some_other_value"), SlotSet("some_slot", None), ] or events == [ # this 'or' is only necessary for python 2.7 and 3.5 Form("some_form"), SlotSet("some_other_slot", "some_other_value"), SlotSet("some_slot", "validated_value"), SlotSet("some_slot", None), ]
def test_early_deactivation(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] def validate(self, dispatcher, tracker, domain): return self.deactivate() form = CustomFormAction() tracker = Tracker('default', {'some_slot': 'some_value'}, {'intent': 'greet'}, [], False, None, { 'name': 'some_form', 'validate': True, 'rejected': False }, 'action_listen') events = form.run(dispatcher=None, tracker=tracker, domain=None) # check that form was deactivated before requesting next slot assert events == [Form(None), SlotSet('requested_slot', None)] assert SlotSet('requested_slot', "some_other_slot") not in events
def deactivate(self): # type: () -> List[Dict] """Return `Form` event with `None` as name to deactivate the form and reset the requested slot""" logger.debug("Deactivating the form '{}'".format(self.name())) return [Form(None), SlotSet(REQUESTED_SLOT, None)]
def test_early_deactivation(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] def validate(self, dispatcher, tracker, domain): return self.deactivate() form = CustomFormAction() tracker = Tracker( "default", {"some_slot": "some_value"}, {"intent": "greet"}, [], False, None, { "name": "some_form", "validate": True, "rejected": False }, "action_listen", ) events = form.run(dispatcher=None, tracker=tracker, domain=None) # check that form was deactivated before requesting next slot assert events == [Form(None), SlotSet("requested_slot", None)] assert SlotSet("requested_slot", "some_other_slot") not in events
def test_activate_if_required(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" form = CustomFormAction() tracker = Tracker('default', {}, { "intent": 'some_intent', "entities": [], "text": "some text" }, [], False, None, {}, 'action_listen') events = form._activate_if_required(tracker) # check that the form was activated assert events == [Form('some_form')] tracker = Tracker('default', {}, {}, [], False, None, { 'name': 'some_form', 'validate': True, 'rejected': False }, 'action_listen') events = form._activate_if_required(tracker) # check that the form was not activated again assert events == []
def test_activate_if_required(): # noinspection PyAbstractClass class CustomCustomFormAction(CustomFormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] form = CustomCustomFormAction() tracker = Tracker( "default", {}, { "intent": "some_intent", "entities": [], "text": "some text" }, [], False, None, {}, "action_listen", ) events = form._activate_if_required(dispatcher=None, tracker=tracker, domain=None) # check that the form was activated assert events == [Form("some_form")] tracker = Tracker( "default", {}, {}, [], False, None, { "name": "some_form", "validate": True, "rejected": False }, "action_listen", ) events = form._activate_if_required(dispatcher=None, tracker=tracker, domain=None) # check that the form was not activated again assert events == []
def _activate_if_required(self, tracker): if tracker.active_form.get('name') is not None: logger.debug("The form '{}' is active" "".format(tracker.active_form)) else: logger.debug("There is no active form") if tracker.active_form.get('name') == self.name(): return [] else: self.request_intent = tracker.latest_message.get('intent')['name'] logger.debug("Activated the form '{}'".format(self.name())) return [Form(self.name())]
def _activate_if_required(self, tracker): # type: (Tracker) -> List[Dict] """Return `Form` event with the name of the form if the form was called for the first time""" if tracker.active_form.get("name") is not None: logger.debug("The form '{}' is active".format(tracker.active_form)) else: logger.debug("There is no active form") if tracker.active_form.get("name") == self.name(): return [] else: logger.debug("Activated the form '{}'".format(self.name())) return [Form(self.name())]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List['Event']: # Fallback caused by TwoStageFallbackPolicy if (len(tracker.events) >= 4 and tracker.events[-4].get('name') == 'action_default_ask_affirmation'): return [ SlotSet('feedback_value', 'negative'), Form('feedback_form'), FollowupAction('feedback_form') ] # Fallback caused by Core else: dispatcher.utter_template('utter_default', tracker) return [UserUtteranceReverted()]
def test_activate_if_required(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" form = CustomFormAction() tracker = Tracker( "default", {}, { "intent": "some_intent", "entities": [], "text": "some text" }, [], False, None, {}, "action_listen", ) events = form._activate_if_required(tracker) # check that the form was activated assert events == [Form("some_form")] tracker = Tracker( "default", {}, {}, [], False, None, { "name": "some_form", "validate": True, "rejected": False }, "action_listen", ) events = form._activate_if_required(tracker) # check that the form was not activated again assert events == []
def run(self, dispatcher, tracker, domain): # type: (CollectingDispatcher, Tracker, Dict[Text, Any]) -> List[Dict] """Execute the side effects of this form. Steps: - activate if needed - validate user input if needed - set validated slots - utter_ask_{slot} template with the next required slot - submit the form if all required slots are set - deactivate the form """ # activate the form events = self._activate_if_required(dispatcher, tracker, domain) # validate user input events.extend(self._validate_if_required(dispatcher, tracker, domain)) # check that the form wasn't deactivated in validation if Form(None) not in events: # create temp tracker with populated slots from `validate` method temp_tracker = tracker.copy() for e in events: if e["event"] == "slot": temp_tracker.slots[e["name"]] = e["value"] next_slot_events = self.request_next_slot(dispatcher, temp_tracker, domain) if next_slot_events is not None: # request next slot events.extend(next_slot_events) else: # there is nothing more to request, so we can submit self._log_form_slots(tracker) logger.debug("Submitting the form '{}'".format(self.name())) events.extend(self.submit(dispatcher, temp_tracker, domain)) # deactivate the form after submission events.extend(self.deactivate()) return events
def _activate_if_required(self, dispatcher, tracker, domain): # type: (CollectingDispatcher, Tracker, Dict[Text, Any]) -> List[Dict] """Activate form if the form is called for the first time. If activating, validate any required slots that were filled before form activation and return `Form` event with the name of the form, as well as any `SlotSet` events from validation of pre-filled slots. """ if tracker.active_form.get("name") is not None: logger.debug("The form '{}' is active".format(tracker.active_form)) else: logger.debug("There is no active form") if tracker.active_form.get("name") == self.name(): return [] else: logger.debug("Activated the form '{}'".format(self.name())) events = [Form(self.name())] # collect values of required slots filled before activation prefilled_slots = {} for slot_name in self.required_slots(tracker): if not self._should_request_slot(tracker, slot_name): prefilled_slots[slot_name] = tracker.get_slot(slot_name) if prefilled_slots: logger.debug("Validating pre-filled required slots: {}".format( prefilled_slots)) events.extend( self.validate_slots(prefilled_slots, dispatcher, tracker, domain)) else: logger.debug("No pre-filled required slots to validate.") return events
def _deactivate(self): self.request_intent = '' self.time_type = {} self.slots_filled.clear() logger.debug("Deactivating the form '{}'".format(self.name())) return [Form(None), SlotSet(REQUESTED_SLOT, None)]