示例#1
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter = RegexInterpreter(),
        **kwargs: Any,
    ) -> List[float]:
        """Predicts the corresponding form action if there is an active form"""
        result = self._default_predictions(domain)

        if tracker.active_loop.get("name"):
            logger.debug(
                "There is an active form '{}'".format(tracker.active_loop["name"])
            )
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                # predict form action after user utterance

                if tracker.active_loop.get("rejected"):
                    if self.state_is_unhappy(tracker, domain):
                        tracker.update(FormValidation(False))
                        return result

                idx = domain.index_for_action(tracker.active_loop["name"])
                result[idx] = 1.0

            elif tracker.latest_action_name == tracker.active_loop.get("name"):
                # predict action_listen after form action
                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                result[idx] = 1.0
        else:
            logger.debug("There is no active form")

        return result
示例#2
0
文件: form_policy.py 项目: zzBBc/rasa
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the corresponding form action if there is an active form"""
        result = [0.0] * domain.num_actions

        if tracker.active_form.get("name"):
            logger.debug("There is an active form '{}'".format(
                tracker.active_form["name"]))
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                # predict form action after user utterance

                if tracker.active_form.get("rejected"):
                    if self.state_is_unhappy(tracker, domain):
                        tracker.update(FormValidation(False))
                        return result

                idx = domain.index_for_action(tracker.active_form["name"])
                result[idx] = 1.0

            elif tracker.latest_action_name == tracker.active_form.get("name"):
                # predict action_listen after form action
                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                result[idx] = 1.0
        else:
            logger.debug("There is no active form")

        return result
示例#3
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the assigned action.

        If the current intent is assigned to an action that action will be
        predicted with the highest probability of all policies. If it is not
        the policy will predict zero for every action."""

        prediction = [0.0] * domain.num_actions
        intent = tracker.latest_message.intent.get('name')
        action = domain.intent_properties.get(intent, {}).get('triggers')
        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            if action:
                idx = domain.index_for_action(action)
                if idx is None:
                    logger.warning("MappingPolicy tried to predict unkown "
                                   "action '{}'.".format(action))
                else:
                    prediction[idx] = 1
            elif intent == USER_INTENT_RESTART:
                idx = domain.index_for_action(ACTION_RESTART_NAME)
                prediction[idx] = 1
            elif intent == USER_INTENT_BACK:
                idx = domain.index_for_action(ACTION_BACK_NAME)
                prediction[idx] = 1
        elif tracker.latest_action_name == action and action is not None:
            latest_action = tracker.get_last_event_for(ActionExecuted)
            assert latest_action.action_name == action

            if latest_action.policy == type(self).__name__:
                # this ensures that we only predict listen, if we predicted
                # the mapped action
                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                prediction[idx] = 1
        return prediction
示例#4
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts a fallback action.

        The fallback action is predicted if the NLU confidence is low
        or no other policy has a high-confidence prediction.
        """

        print("in faq policy")
        nlu_data = tracker.latest_message.parse_data
        print("meg need to deal {}".format(nlu_data))
        print("Last tracker state {}".format(tracker.latest_action_name))
        action_name = tracker.latest_message.intent[0].get("name")
        print("Action name is {}".format(action_name))
        idx = domain.index_for_action(
            tracker.latest_message.intent[0].get("name"))
        print("indx is {}".format(idx))
        result = [0.0] * domain.num_actions
        result[idx] = 1.0
        print("Result is {}".format(result))

        if tracker.latest_action_name == action_name:
            # predict action_listen after form action
            idx = domain.index_for_action(ACTION_LISTEN_NAME)
            result[idx] = 1.0

        return result
示例#5
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the assigned action.

        If the current intent is assigned to an action that action will be
        predicted with the highest probability of all policies. If it is not
        the policy will predict zero for every action."""

        prediction = [0.0] * domain.num_actions
        intent = tracker.latest_message.intent.get("name")
        if intent == USER_INTENT_RESTART:
            action = ACTION_RESTART_NAME
        elif intent == USER_INTENT_BACK:
            action = ACTION_BACK_NAME
        else:
            action = domain.intent_properties.get(intent, {}).get("triggers")

        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            if action:
                idx = domain.index_for_action(action)
                if idx is None:
                    warnings.warn(
                        "MappingPolicy tried to predict unknown "
                        f"action '{action}'. Make sure all mapped actions are "
                        "listed in the domain.")
                else:
                    prediction[idx] = 1

            if any(prediction):
                logger.debug("The predicted intent '{}' is mapped to "
                             " action '{}' in the domain."
                             "".format(intent, action))
        elif tracker.latest_action_name == action and action is not None:
            latest_action = tracker.get_last_event_for(ActionExecuted)
            assert latest_action.action_name == action
            if latest_action.policy and latest_action.policy.endswith(
                    type(self).__name__):
                # this ensures that we only predict listen, if we predicted
                # the mapped action
                logger.debug(
                    "The mapped action, '{}', for this intent, '{}', was "
                    "executed last so MappingPolicy is returning to "
                    "action_listen.".format(action, intent))

                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                prediction[idx] = 1
            else:
                logger.debug(
                    "The mapped action, '{}', for this intent, '{}', was "
                    "executed last, but it was predicted by another policy, '{}', so MappingPolicy is not"
                    "predicting any action.".format(action, intent,
                                                    latest_action.policy))
        elif action == ACTION_RESTART_NAME:
            idx = domain.index_for_action(ACTION_RESTART_NAME)
            prediction[idx] = 1
            logger.debug("Restarting the conversation with action_restart.")
        else:
            logger.debug("There is no mapped action for the predicted intent, "
                         "'{}'.".format(intent))
        return prediction
示例#6
0
    def probabilities_using_best_policy(self,
                                        tracker: DialogueStateTracker,
                                        domain: Domain
                                        ) -> Tuple[List[float], Text]:
        result = None
        max_confidence = -1
        best_policy_name = None
        best_policy_priority = -1

        for i, p in enumerate(self.policies):
            probabilities = p.predict_action_probabilities(tracker, domain)

            if isinstance(tracker.events[-1], ActionExecutionRejected):
                probabilities[domain.index_for_action(
                    tracker.events[-1].action_name)] = 0.0
            confidence = np.max(probabilities)

            if (confidence, p.priority) > (max_confidence,
                                           best_policy_priority):
                max_confidence = confidence
                result = probabilities
                best_policy_name = 'policy_{}_{}'.format(i, type(p).__name__)
                best_policy_priority = p.priority

        if (result.index(max_confidence) ==
                domain.index_for_action(ACTION_LISTEN_NAME) and
                tracker.latest_action_name == ACTION_LISTEN_NAME and
                self.is_not_memo_policy(best_policy_name)):
            # Trigger the fallback policy when ActionListen is predicted after
            # a user utterance. This is done on the condition that:
            # - a fallback policy is present,
            # - there was just a user message and the predicted
            #   action is action_listen by a policy
            #   other than the MemoizationPolicy

            fallback_idx_policy = [(i, p) for i, p in enumerate(self.policies)
                                   if isinstance(p, FallbackPolicy)]

            if fallback_idx_policy:
                fallback_idx, fallback_policy = fallback_idx_policy[0]

                logger.debug("Action 'action_listen' was predicted after "
                             "a user message using {}. "
                             "Predicting fallback action: {}"
                             "".format(best_policy_name,
                                       fallback_policy.fallback_action_name))

                result = fallback_policy.fallback_scores(domain)
                best_policy_name = 'policy_{}_{}'.format(
                    fallback_idx,
                    type(fallback_policy).__name__)

        # normalize probabilities
        if np.sum(result) != 0:
            result = result / np.nansum(result)

        logger.debug("Predicted next action using {}"
                     "".format(best_policy_name))
        return result, best_policy_name
示例#7
0
    def predict_action_probabilities(
        self, tracker: DialogueStateTracker, domain: Domain
    ) -> List[float]:
        logger.debug("Triggers: " + ", ".join(self.triggers.keys()))
        """Predicts the assigned action.

        If the current intent is assigned to an action that action will be
        predicted with the highest probability of all policies. If it is not
        the policy will predict zero for every action."""

        prediction = [0.0] * domain.num_actions
        intent = tracker.latest_message.intent.get("name")
        action = None
        if isinstance(intent, str):
            for trigger in self.triggers:
                match = re.search(trigger, intent)
                if match:
                    action = self.triggers[trigger]
        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            if action:
                idx = domain.index_for_action(action)
                if idx is None:
                    logger.warning("{} is not defined.".format(action))
                else:
                    prediction[idx] = 1
            elif intent == USER_INTENT_RESTART:
                idx = domain.index_for_action(ACTION_RESTART_NAME)
                prediction[idx] = 1
            elif intent == USER_INTENT_BACK:
                idx = domain.index_for_action(ACTION_BACK_NAME)
                prediction[idx] = 1

            if any(prediction):
                logger.debug(
                    "The predicted intent '{}' is being "
                    " handled by BotfrontMappingPolicy."
                    "".format(intent)
                )
        elif tracker.latest_action_name == action and action is not None:
            latest_action = tracker.get_last_event_for(ActionExecuted)
            assert latest_action.action_name == action

            if type(self).__name__ in latest_action.policy:
                # this ensures that we only predict listen, if we predicted
                # the mapped action
                logger.debug(
                    "BotfrontMappingPolicy has just been triggered, "
                    "so now returning to action_listen. "
                )

                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                prediction[idx] = 1
        return prediction
示例#8
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the assigned action.

        If the current intent is assigned to an action that action will be
        predicted with the highest probability of all policies. If it is not
        the policy will predict zero for every action."""

        prediction = [0.0] * domain.num_actions
        active_component = tracker.slots.get("active_component").value
        # if active_component:
        #     idx = domain.index_for_action(active_component)
        #     prediction[idx] = 1
        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            if active_component:
                idx = domain.index_for_action(active_component)
                if idx is None:
                    warnings.warn(
                        "MappingPolicy tried to predict unknown "
                        f"action '{active_component}'. Make sure all mapped actions are "
                        "listed in the domain.")
                else:
                    prediction[idx] = 1

            if any(prediction):
                logger.debug("Continue component exec"
                             " '{}' in the domain."
                             "".format(active_component))
        elif tracker.latest_action_name == active_component and active_component is not None:
            latest_action = tracker.get_last_event_for(ActionExecuted)
            assert latest_action.action_name == active_component
            if latest_action.policy and latest_action.policy.endswith(
                    type(self).__name__):
                # this ensures that we only predict listen, if we predicted
                # the mapped action
                logger.debug(
                    "The mapped action, '{}', for this intent, '{}', was "
                    "executed last so MappingPolicy is returning to "
                    "action_listen.".format(active_component, ""))

                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                prediction[idx] = 1
            else:
                logger.debug(
                    "The mapped action, '{}', for this intent, '{}', was "
                    "executed last, but it was predicted by another policy, '{}', so MappingPolicy is not"
                    "predicting any action.".format(active_component, "",
                                                    latest_action.policy))
        else:
            logger.debug("There is no mapped action for the predicted intent, "
                         "'{}'.".format(""))
        return prediction
示例#9
0
    def action_as_one_hot(action: Text, domain: Domain) -> np.ndarray:
        if action is None:
            return np.ones(domain.num_actions, dtype=int) * -1

        y = np.zeros(domain.num_actions, dtype=int)
        y[domain.index_for_action(action)] = 1
        return y
示例#10
0
    def _default_predictions(self, domain: Domain) -> List[float]:
        result = super()._default_predictions(domain)

        if self._enable_fallback_prediction:
            result[domain.index_for_action(
                self._fallback_action_name)] = self._core_fallback_threshold
        return result
示例#11
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts a fallback action.

        The fallback action is predicted if the NLU confidence is low
        or no other policy has a high-confidence prediction.
        """

        nlu_data = tracker.latest_message.parse_data

        if tracker.latest_action_name == self.fallback_action_name:
            result = [0.0] * domain.num_actions
            idx = domain.index_for_action(ACTION_LISTEN_NAME)
            result[idx] = 1.0

        elif self.should_nlu_fallback(nlu_data, tracker.latest_action_name):
            result = self.fallback_scores(domain)

        else:
            # NLU confidence threshold is met, so
            # predict fallback action with confidence `core_threshold`
            # if this is the highest confidence in the ensemble,
            # the fallback action will be executed.
            logger.debug("NLU confidence threshold met, confidence of "
                         "fallback action set to core threshold ({}).".format(
                             self.core_threshold))
            result = self.fallback_scores(domain, self.core_threshold)

        return result
示例#12
0
    def probabilities_using_best_policy(
            self, tracker: DialogueStateTracker,
            domain: Domain) -> Tuple[Optional[List[float]], Optional[Text]]:
        """Predicts the next action the bot should take after seeing the tracker.

        Picks the best policy prediction based on probabilities and policy priority.
        Triggers fallback if `action_listen` is predicted after a user utterance.

        Args:
            tracker: the :class:`rasa.core.trackers.DialogueStateTracker`
            domain: the :class:`rasa.core.domain.Domain`

        Returns:
            best_probabilities: the list of probabilities for the next actions
            best_policy_name: the name of the picked policy
        """

        probabilities, policy_name = self._best_policy_prediction(
            tracker, domain)

        if (tracker.latest_action_name == ACTION_LISTEN_NAME
                and probabilities is not None
                and probabilities.index(max(probabilities))
                == domain.index_for_action(ACTION_LISTEN_NAME)
                and self.is_not_memo_policy(policy_name, max(probabilities))):
            probabilities, policy_name = self._fallback_after_listen(
                domain, probabilities, policy_name)

        logger.debug(f"Predicted next action using {policy_name}")
        return probabilities, policy_name
示例#13
0
    def action_as_one_hot(action: Text, domain: Domain) -> np.ndarray:
        """Encode system action as one-hot vector."""

        if action is None:
            return np.ones(domain.num_actions, dtype=int) * -1

        y = np.zeros(domain.num_actions, dtype=int)
        y[domain.index_for_action(action)] = 1
        return y
示例#14
0
    def fallback_scores(
        self, domain: Domain, fallback_score: float = 1.0
    ) -> List[float]:
        """Prediction scores used if a fallback is necessary."""

        result = self._default_predictions(domain)
        idx = domain.index_for_action(self.fallback_action_name)
        result[idx] = fallback_score
        return result
示例#15
0
 def _convert_labels_to_ids(
     trackers_as_actions: List[List[Text]], domain: Domain
 ) -> np.ndarray:
     # store labels in numpy arrays so that it corresponds to np arrays of input features
     return np.array(
         [
             np.array(
                 [domain.index_for_action(action) for action in tracker_actions]
             )
             for tracker_actions in trackers_as_actions
         ]
     )
    def predict_action_probabilities(
        self, tracker: DialogueStateTracker, domain: Domain
    ) -> List[float]:
        """Predicts a fallback action if an unsupported intent is received.
        """

        if tracker.latest_action_name == self.fallback_action_name:
            logger.debug(
                "Predicted 'action_listen' after fallback action '{}'".format(
                    self.fallback_action_name
                )
            )
            result = self._default_predictions(domain)
            idx = domain.index_for_action(ACTION_LISTEN_NAME)
            result[idx] = 1.0

            return result

        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            action_name = _get_previous_action_name(tracker)

            if action_name is None or not action_name in SUPPORTED_INTENTS_BY_ACTION:
                logger.debug("Skipping unsupported intent check")
                return self._default_predictions(domain)

            supported_intents = SUPPORTED_INTENTS_BY_ACTION[action_name]

            intent = _get_intent(tracker)

            if intent in supported_intents or intent == FALLBACK_INTENT:
                if (
                    tracker.get_slot(SELF_ASSESS_DONE_SLOT) is True
                    and intent == GET_ASSESSMENT_INTENT
                ):
                    logger.debug(
                        "Received {} intent but assessment is already done".format(
                            GET_ASSESSMENT_INTENT
                        )
                    )
                    return self.fallback_scores(domain, 1.0)

                logger.debug(
                    "No unexpected intent after action '{}'".format(action_name)
                )
                return self._default_predictions(domain)

            logger.debug(
                "Unexpected intent '{}' after action '{}'".format(intent, action_name)
            )
            return self.fallback_scores(domain, 1.0)

        logger.debug("Skipping unsupported intent check")
        return self._default_predictions(domain)
示例#17
0
    def train(
        self,
        training_trackers: List[DialogueStateTracker],
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
        **kwargs: Any,
    ) -> None:
        """Trains the policy on given training trackers."""
        self.lookup = {}

        # only use trackers from rule-based training data
        training_trackers = [t for t in training_trackers if t.is_rule_tracker]

        # only consider original trackers (no augmented ones)
        training_trackers = [
            t for t in training_trackers
            if not hasattr(t, "is_augmented") or not t.is_augmented
        ]
        (
            trackers_as_states,
            trackers_as_actions,
        ) = self.featurizer.training_states_and_actions(
            training_trackers, domain)

        self._add_states_to_lookup(trackers_as_states, trackers_as_actions,
                                   domain)

        # remove action_listens that were added after conditions
        updated_lookup = self.lookup.copy()
        for key in self.lookup.keys():
            # Delete rules if there is no prior action or if it would predict
            # the `...` action
            if "prev" not in key or self.lookup[
                    key] == domain.index_for_action(RULE_SNIPPET_ACTION_NAME):
                del updated_lookup[key]
            elif RULE_SNIPPET_ACTION_NAME in key:
                # If the previous action is `...` -> remove any specific state
                # requirements for that state (anything can match this state)
                new_key = re.sub(r".*prev_\.\.\.[^|]*", "", key)

                if new_key:
                    if new_key.startswith("|"):
                        new_key = new_key[1:]
                    if new_key.endswith("|"):
                        new_key = new_key[:-1]
                    updated_lookup[new_key] = self.lookup[key]

                del updated_lookup[key]

        self.lookup = updated_lookup
        logger.debug("Memorized {} unique examples.".format(len(self.lookup)))
示例#18
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the corresponding form action if there is an active form"""
        result = [0.0] * domain.num_actions

        if tracker.active_form.get('name'):
            logger.debug("There is an active form '{}'"
                         "".format(tracker.active_form['name']))
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                # predict form action after user utterance

                if tracker.active_form.get('rejected'):
                    # since it is assumed that training stories contain
                    # only unhappy paths, notify the form that
                    # it should not be validated if predicted by other policy
                    tracker_as_states = self.featurizer.prediction_states(
                        [tracker], domain)
                    states = tracker_as_states[0]
                    memorized_form = self.recall(states, tracker, domain)

                    if memorized_form == tracker.active_form['name']:
                        logger.debug("There is a memorized tracker state {}, "
                                     "added `FormValidation(False)` event"
                                     "".format(self._modified_states(states)))
                        tracker.update(FormValidation(False))
                        return result

                idx = domain.index_for_action(tracker.active_form['name'])
                result[idx] = 1.0

            elif tracker.latest_action_name == tracker.active_form.get('name'):
                # predict action_listen after form action
                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                result[idx] = 1.0
        else:
            logger.debug("There is no active form")

        return result
示例#19
0
    def _prediction_result(self, action_name: Text,
                           tracker: DialogueStateTracker,
                           domain: Domain) -> List[float]:
        result = self._default_predictions(domain)
        if action_name:
            if self.USE_NLU_CONFIDENCE_AS_SCORE:
                # the memoization will use the confidence of NLU on the latest
                # user message to set the confidence of the action
                score = tracker.latest_message.intent.get("confidence", 1.0)
            else:
                score = 1.0

            result[domain.index_for_action(action_name)] = score

        return result
示例#20
0
    def confidence_scores(self, domain: Domain) -> List[float]:
        """Return confidence scores if a single action is predicted.

        Args:
            action_name: the name of the action for which the score should be set
            value: the confidence for `action_name`
            domain: the :class:`rasa.core.domain.Domain`
        Returns:
            the list of the length of the number of actions

        """
        results = [0.0] * domain.num_actions
        idx = domain.index_for_action(self.action_chain.pop(0))
        results[idx] = 1.0
        return results
示例#21
0
    def _best_policy_prediction(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
    ) -> Tuple[Optional[List[float]], Optional[Text]]:
        """Finds the best policy prediction.

        Args:
            tracker: the :class:`rasa.core.trackers.DialogueStateTracker`
            domain: the :class:`rasa.core.domain.Domain`
            interpreter: Interpreter which may be used by the policies to create
                additional features.

        Returns:
            probabilities: the list of probabilities for the next actions
            policy_name: the name of the picked policy
        """

        # find rejected action before running the policies
        # because some of them might add events
        rejected_action_name = None
        if len(tracker.events) > 0 and isinstance(
            tracker.events[-1], ActionExecutionRejected
        ):
            rejected_action_name = tracker.events[-1].action_name

        predictions = {
            f"policy_{i}_{type(p).__name__}": self._get_prediction(
                p, tracker, domain, interpreter
            )
            for i, p in enumerate(self.policies)
        }

        if rejected_action_name:
            logger.debug(
                f"Execution of '{rejected_action_name}' was rejected. "
                f"Setting its confidence to 0.0 in all predictions."
            )
            for prediction in predictions.values():
                prediction.probabilities[
                    domain.index_for_action(rejected_action_name)
                ] = 0.0

        return self._pick_best_policy(predictions)
示例#22
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter = RegexInterpreter(),
        **kwargs: Any,
    ) -> List[float]:
        """Predicts a fallback action.

        The fallback action is predicted if the NLU confidence is low
        or no other policy has a high-confidence prediction.
        """

        nlu_data = tracker.latest_message.parse_data

        if (
            tracker.latest_action_name == self.fallback_action_name
            and tracker.latest_action_name != ACTION_LISTEN_NAME
        ):
            logger.debug(
                "Predicted 'action_listen' after fallback action '{}'".format(
                    self.fallback_action_name
                )
            )
            result = self._default_predictions(domain)
            idx = domain.index_for_action(ACTION_LISTEN_NAME)
            result[idx] = 1.0

        elif self.should_nlu_fallback(nlu_data, tracker.latest_action_name):
            result = self.fallback_scores(domain)

        else:
            # NLU confidence threshold is met, so
            # predict fallback action with confidence `core_threshold`
            # if this is the highest confidence in the ensemble,
            # the fallback action will be executed.
            logger.debug(
                "NLU confidence threshold met, confidence of "
                "fallback action set to core threshold ({}).".format(
                    self.core_threshold
                )
            )
            result = self.fallback_scores(domain, self.core_threshold)

        return result
示例#23
0
    def predict_action_probabilities(
        self, tracker: DialogueStateTracker, domain: Domain
    ) -> List[float]:
        """Predicts a fallback action.

        The fallback action is predicted if the NLU confidence is low
        or no other policy has a high-confidence prediction.
        """

        nlu_data = tracker.latest_message.parse_data

        # if NLU interpreter does not provide confidence score,
        # it is set to 1.0 here in order
        # to not override standard behaviour
        nlu_confidence = nlu_data.get("intent", {}).get("confidence", 1.0)

        if tracker.latest_action_name == self.fallback_action_name:
            result = [0.0] * domain.num_actions
            idx = domain.index_for_action(ACTION_LISTEN_NAME)
            result[idx] = 1.0

        elif self.should_nlu_fallback(nlu_confidence, tracker.latest_action_name):
            logger.debug(
                "NLU confidence {} is lower "
                "than NLU threshold {}. "
                "".format(nlu_confidence, self.nlu_threshold)
            )
            result = self.fallback_scores(domain)

        else:
            # NLU confidence threshold is met, so
            # predict fallback action with confidence `core_threshold`
            # if this is the highest confidence in the ensemble,
            # the fallback action will be executed.
            logger.debug(
                "NLU confidence threshold met, confidence of "
                "fallback action set to core threshold ({}).".format(
                    self.core_threshold
                )
            )
            result = self.fallback_scores(domain, self.core_threshold)

        return result
示例#24
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter = RegexInterpreter(),
        **kwargs: Any,
    ) -> List[float]:
        """Predicts the next action the bot should take after seeing the tracker.

        Returns the list of probabilities for the next actions.
        If memorized action was found returns 1 for its index,
        else returns 0 for all actions.
        """
        result = self._default_predictions(domain)

        if not self.is_enabled:
            return result

        # Rasa Open Source default actions overrule anything. If users want to achieve
        # the same, they need to a rule or make sure that their form rejects
        # accordingly.
        rasa_default_action_name = _should_run_rasa_default_action(tracker)
        if rasa_default_action_name:
            result[domain.index_for_action(rasa_default_action_name)] = 1
            return result

        active_form_name = tracker.active_form_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)

        # A form has priority over any other rule.
        # The rules or any other prediction will be applied only if a form was rejected.
        # If we are in a form, and the form didn't run previously or rejected, we can
        # simply force predict the form.
        if should_predict_form:
            logger.debug(f"Predicted form '{active_form_name}'.")
            result[domain.index_for_action(active_form_name)] = 1
            return result

        # 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}'."
            )
            result[domain.index_for_action(ACTION_LISTEN_NAME)] = 1
            return result

        possible_keys = set(self.lookup.keys())

        tracker_as_states = self.featurizer.prediction_states([tracker],
                                                              domain)
        states = tracker_as_states[0]

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

        for i, state in enumerate(reversed(states)):
            possible_keys = set(
                filter(lambda _key: self._rule_is_good(_key, i, state),
                       possible_keys))

        if possible_keys:
            # TODO rethink that
            key = max(possible_keys, key=len)

            recalled = self.lookup.get(key)

            if active_form_name:
                # 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 = recalled is None or (
                    domain.action_names[recalled] == ACTION_LISTEN_NAME
                    and f"active_form_{active_form_name}" not in key)
                if predicted_listen_from_general_rule:
                    logger.debug(f"Predicted form '{active_form_name}'.")
                    result[domain.index_for_action(active_form_name)] = 1
                    return result

                # Since rule snippets inside the form contain only unhappy paths,
                # notify the form that
                # it was predicted after an answer to a different question and
                # therefore it should not validate user input for requested slot
                predicted_form_from_form_rule = (
                    domain.action_names[recalled] == active_form_name
                    and f"active_form_{active_form_name}" in key)
                if predicted_form_from_form_rule:
                    logger.debug("Added `FormValidation(False)` event.")
                    tracker.update(FormValidation(False))

            if recalled is not None:
                logger.debug(f"There is a rule for next action "
                             f"'{domain.action_names[recalled]}'.")

                result[recalled] = 1
            else:
                logger.debug("There is no applicable rule.")

        return result
示例#25
0
 def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                  domain: Domain) -> List[float]:
     result = [0.0] * domain.num_actions
     idx = domain.index_for_action("action_hello_world")
     result[idx] = 1.0
     return result
示例#26
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
        **kwargs: Any,
    ) -> List[float]:
        """Predicts the assigned action.

        If the current intent is assigned to an action that action will be
        predicted with the highest probability of all policies. If it is not
        the policy will predict zero for every action."""

        result = self._default_predictions(domain)

        intent = tracker.latest_message.intent.get(INTENT_NAME_KEY)
        if intent == USER_INTENT_RESTART:
            action = ACTION_RESTART_NAME
        elif intent == USER_INTENT_BACK:
            action = ACTION_BACK_NAME
        elif intent == USER_INTENT_SESSION_START:
            action = ACTION_SESSION_START_NAME
        else:
            action = domain.intent_properties.get(intent, {}).get("triggers")

        if tracker.latest_action_name == ACTION_LISTEN_NAME:
            # predict mapped action
            if action:
                idx = domain.index_for_action(action)
                if idx is None:
                    rasa.shared.utils.io.raise_warning(
                        f"MappingPolicy tried to predict unknown "
                        f"action '{action}'. Make sure all mapped actions are "
                        f"listed in the domain.",
                        docs=DOCS_URL_POLICIES + "#mapping-policy",
                    )
                else:
                    result[idx] = 1

            if any(result):
                logger.debug("The predicted intent '{}' is mapped to "
                             " action '{}' in the domain."
                             "".format(intent, action))
        elif tracker.latest_action_name == action and action is not None:
            # predict next action_listen after mapped action
            latest_action = tracker.get_last_event_for(ActionExecuted)
            assert latest_action.action_name == action
            if latest_action.policy and latest_action.policy.endswith(
                    type(self).__name__):
                # this ensures that we only predict listen,
                # if we predicted the mapped action
                logger.debug(
                    "The mapped action, '{}', for this intent, '{}', was "
                    "executed last so MappingPolicy is returning to "
                    "action_listen.".format(action, intent))

                idx = domain.index_for_action(ACTION_LISTEN_NAME)
                result[idx] = 1
            else:
                logger.debug(
                    "The mapped action, '{}', for the intent, '{}', was "
                    "executed last, but it was predicted by another policy, '{}', "
                    "so MappingPolicy is not predicting any action.".format(
                        action, intent, latest_action.policy))
        elif action == ACTION_RESTART_NAME:
            logger.debug("Restarting the conversation with action_restart.")
            idx = domain.index_for_action(ACTION_RESTART_NAME)
            result[idx] = 1
        else:
            logger.debug("There is no mapped action for the predicted intent, "
                         "'{}'.".format(intent))
        return result
示例#27
0
    def predict_action_probabilities(self, tracker: DialogueStateTracker,
                                     domain: Domain) -> List[float]:
        """Predicts the assigned action."""

        # 更新对话ID
        if tracker.sender_id != self.dialogue_id:
            self.dialogue_id = tracker.sender_id
            self.latest_agent_ask_utter = 'utter_ask_own_name'
            self.chat_num = 0

        prediction = self._default_predictions(domain)

        action = None
        intent = tracker.latest_message.intent.get('name')
        if intent == 'greet':
            if self.chat_num == 0:
                if tracker.latest_action_name == ACTION_LISTEN_NAME:
                    action = 'utter_greet'
                elif tracker.latest_action_name == 'utter_greet':
                    # 镜像表达问候之后,
                    # 第一次表达greet,追问之前的问题
                    action = self.latest_agent_ask_utter
                else:
                    # 这一轮闲聊结束,进入用户监听模式
                    # 追问之后就应该agent就应该去监听用户的回答
                    action = ACTION_LISTEN_NAME
                    # 更新最新的询问, 其实不需要更新,继续保持原样就好
                    self.latest_agent_ask_utter = self.latest_agent_ask_utter
                    # 闲聊计数,一轮闲聊结束
                    self.chat_num += 1
            else:
                # 不予许闲聊两次,greet也算一种chat
                if tracker.latest_action_name == ACTION_LISTEN_NAME:
                    action = 'utter_bye'
                else:
                    action = ACTION_LISTEN_NAME
        elif intent == 'bye':
            # 遇到intent bye 直接弹出
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                action = 'utter_bye'
            else:
                action = ACTION_LISTEN_NAME
        elif intent == 'thanks':
            # user
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                action = 'utter_welcome'
            elif tracker.latest_action_name == 'utter_welcome':
                action = 'utter_bye'
            else:
                action = ACTION_LISTEN_NAME
                # 更新最新的询问, 其实不需要更新,继续保持原样就好
                self.latest_agent_ask_utter = self.latest_agent_ask_utter
        elif intent == 'chat':
            if self.chat_num == 0:
                if tracker.latest_action_name == ACTION_LISTEN_NAME:
                    action = 'utter_chat'
                elif tracker.latest_action_name == 'utter_chat':
                    # 第一次表达chaet之意,追问前一个agent的提问
                    action = self.latest_agent_ask_utter
                else:
                    # 此轮闲聊结束,进入用户监听状态
                    action = ACTION_LISTEN_NAME
                    self.latest_agent_ask_utter = self.latest_agent_ask_utter
                    # 闲聊计数
                    self.chat_num += 1
            else:
                if tracker.latest_action_name == ACTION_LISTEN_NAME:
                    action = 'utter_chat'
                elif tracker.latest_action_name == 'utter_chat':
                    action = 'utter_bye'
                else:
                    action = ACTION_LISTEN_NAME
        elif intent == 'inform':
            entities = tracker.latest_message.entities
            if entities:
                if not tracker.get_slot('is_valid_password') is None:
                    # 已经经历了密码匹配
                    if tracker.get_slot('is_valid_password'):
                        # 成功
                        if tracker.latest_action_name == 'utter_validation_pass':
                            action = ACTION_LISTEN_NAME
                        else:
                            # 表达进门,后面再说什么也不在做其他回复,一直回复这句话
                            # 都是为了简化逻辑
                            action = 'utter_validation_pass'
                    elif not tracker.get_slot('is_valid_password'):
                        # 失败
                        if tracker.latest_action_name == 'utter_password_error':
                            action = ACTION_LISTEN_NAME
                        else:
                            # 表达请离开,不管后面在回答任何内容
                            action = 'utter_password_error'
                elif tracker.get_slot('is_own'):
                    # 第二步,匹配密码
                    if tracker.get_slot('password'):
                        # 已经收集到密码,匹配密码
                        action = 'action_match_password'
                    elif tracker.latest_action_name == 'utter_ask_setting_password':
                        # 收集密码的第二步,等待用户的回答
                        action = ACTION_LISTEN_NAME
                    else:
                        # 没有收集到password, 收集密码第一步,提问
                        action = 'utter_ask_setting_password'
                        # 更新最新agent的 ask
                        self.latest_agent_ask_utter = action
                elif tracker.get_slot('name'):
                    # 第一步,匹配姓名
                    if tracker.latest_action_name == ACTION_LISTEN_NAME:
                        action = 'action_match_name'
                    elif tracker.latest_action_name == "utter_own_name_error":
                        # 只要有agent的utter,都将进入agent监状态
                        action = ACTION_LISTEN_NAME
                    elif not tracker.get_slot('is_own'):
                        action = 'utter_own_name_error'
            else:
                if tracker.latest_action_name == ACTION_LISTEN_NAME:
                    # 没有收集到任何实体信息,重新追问上一个问题
                    action = self.latest_agent_ask_utter
                else:
                    action = ACTION_LISTEN_NAME
                    # 更新最新的询问, 其实不需要更新,继续保持原样就好
                    self.latest_agent_ask_utter = self.latest_agent_ask_utter
        else:
            # every dialogue start, no collected any intent(or user utter)
            if tracker.latest_action_name == ACTION_LISTEN_NAME:
                action = self.latest_agent_ask_utter
            else:
                action = ACTION_LISTEN_NAME

        # 获取action的index
        idx = domain.index_for_action(action)
        prediction[idx] = 1

        return prediction