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),
    ]
Exemple #2
0
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
Exemple #3
0
    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)]
Exemple #4
0
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
Exemple #5
0
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 == []
Exemple #6
0
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 == []
Exemple #7
0
    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())]
Exemple #8
0
    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())]
Exemple #9
0
    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()]
Exemple #10
0
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 == []
Exemple #11
0
    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
Exemple #12
0
    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
Exemple #13
0
 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)]