Example #1
0
    def _find_action_from_rules(self, tracker: DialogueStateTracker,
                                domain: Domain) -> Optional[Text]:
        tracker_as_states = self.featurizer.prediction_states([tracker],
                                                              domain)
        states = tracker_as_states[0]

        logger.debug(f"Current tracker state: {states}")

        rule_keys = self._get_possible_keys(self.lookup[RULES], states)
        predicted_action_name = None
        best_rule_key = ""
        if rule_keys:
            # TODO check that max is correct
            # if there are several rules,
            # it should mean that some rule is a subset of another rule
            best_rule_key = max(rule_keys, key=len)
            predicted_action_name = self.lookup[RULES].get(best_rule_key)

        active_form_name = tracker.active_loop_name()
        if active_form_name:
            # find rules for unhappy path of the form
            form_unhappy_keys = self._get_possible_keys(
                self.lookup[RULES_FOR_FORM_UNHAPPY_PATH], states)
            # there could be several unhappy path conditions
            unhappy_path_conditions = [
                self.lookup[RULES_FOR_FORM_UNHAPPY_PATH].get(key)
                for key in form_unhappy_keys
            ]

            # Check if a rule that predicted action_listen
            # was applied inside the form.
            # Rules might not explicitly switch back to the `Form`.
            # Hence, we have to take care of that.
            predicted_listen_from_general_rule = (
                predicted_action_name == ACTION_LISTEN_NAME
                and ACTIVE_FORM_PREFIX + active_form_name not in best_rule_key)
            if predicted_listen_from_general_rule:
                if DO_NOT_PREDICT_FORM_ACTION not in unhappy_path_conditions:
                    # negative rules don't contain a key that corresponds to
                    # the fact that active_form shouldn't be predicted
                    logger.debug(
                        f"Predicted form '{active_form_name}' by overwriting "
                        f"'{ACTION_LISTEN_NAME}' predicted by general rule.")
                    return active_form_name

                # do not predict anything
                predicted_action_name = None

            if DO_NOT_VALIDATE_FORM in unhappy_path_conditions:
                logger.debug("Added `FormValidation(False)` event.")
                tracker.update(FormValidation(False))

        if predicted_action_name is not None:
            logger.debug(
                f"There is a rule for the next action '{predicted_action_name}'."
            )
        else:
            logger.debug("There is no applicable rule.")

        return predicted_action_name
Example #2
0
    def _find_action_from_form_happy_path(
        tracker: DialogueStateTracker, ) -> Optional[Text]:

        active_form_name = tracker.active_loop_name()
        active_form_rejected = tracker.active_loop.get("rejected")
        should_predict_form = (active_form_name and not active_form_rejected
                               and
                               tracker.latest_action_name != active_form_name)
        should_predict_listen = (active_form_name and not active_form_rejected
                                 and tracker.latest_action_name
                                 == active_form_name)

        if should_predict_form:
            logger.debug(f"Predicted form '{active_form_name}'.")
            return active_form_name

        # predict `action_listen` if form action was run successfully
        if should_predict_listen:
            logger.debug(
                f"Predicted '{ACTION_LISTEN_NAME}' after form '{active_form_name}'."
            )
            return ACTION_LISTEN_NAME