Пример #1
0
    def _is_user_input_expected(self, tracker: DialogueStateTracker) -> bool:
        action_requires_input = tracker.latest_action.get(ACTION_NAME) in [
            ACTION_DEFAULT_ASK_AFFIRMATION_NAME,
            ACTION_DEFAULT_ASK_REPHRASE_NAME,
            self.fallback_action_name,
        ]
        try:
            last_utterance_time = tracker.get_last_event_for(
                UserUttered).timestamp
            last_action_time = tracker.get_last_event_for(
                ActionExecuted).timestamp
            input_given = last_action_time < last_utterance_time
        except AttributeError:
            input_given = False

        return action_requires_input and not input_given
Пример #2
0
    def _has_session_expired(self, tracker: DialogueStateTracker) -> bool:
        """Determine whether the latest session in `tracker` has expired.

        Args:
            tracker: Tracker to inspect.

        Returns:
            `True` if the session in `tracker` has expired, `False` otherwise.
        """
        if not self.domain.session_config.are_sessions_enabled():
            # tracker has never expired if sessions are disabled
            return False

        user_uttered_event: Optional[UserUttered] = tracker.get_last_event_for(
            UserUttered)

        if not user_uttered_event:
            # there is no user event so far so the session should not be considered
            # expired
            return False

        time_delta_in_seconds = time.time() - user_uttered_event.timestamp
        has_expired = (time_delta_in_seconds / 60 >
                       self.domain.session_config.session_expiration_time)
        if has_expired:
            logger.debug(
                f"The latest session for conversation ID '{tracker.sender_id}' has "
                f"expired.")

        return has_expired
Пример #3
0
async def _get_e2e_entity_evaluation_result(
    processor: "MessageProcessor",
    tracker: DialogueStateTracker,
    prediction: PolicyPrediction,
) -> Optional[EntityEvaluationResult]:
    previous_event = tracker.events[-1]

    if isinstance(previous_event, SlotSet):
        # UserUttered events with entities can be followed by SlotSet events
        # if slots are defined in the domain
        previous_event = tracker.get_last_event_for(
            (UserUttered, ActionExecuted))

    if isinstance(previous_event, UserUttered):
        entities_predicted_by_policies = [
            entity for prediction_event in prediction.events
            if isinstance(prediction_event, EntitiesAdded)
            for entity in prediction_event.entities
        ]
        entity_targets = previous_event.entities
        if entity_targets or entities_predicted_by_policies:
            text = previous_event.text
            if text:
                parsed_message = await processor.parse_message(
                    UserMessage(text=text))
                if parsed_message:
                    tokens = [
                        Token(text[start:end], start, end)
                        for start, end in parsed_message.get(
                            TOKENS_NAMES[TEXT], [])
                    ]
                    return EntityEvaluationResult(
                        entity_targets, entities_predicted_by_policies, tokens,
                        text)
    return None
Пример #4
0
def _last_n_intent_names(tracker: DialogueStateTracker,
                         number_of_last_intent_names: int) -> List[Text]:
    intent_names = []
    for i in range(number_of_last_intent_names):
        message = tracker.get_last_event_for(
            UserUttered, skip=i, event_verbosity=EventVerbosity.AFTER_RESTART)
        if isinstance(message, UserUttered):
            intent_names.append(message.intent.get("name"))

    return intent_names
Пример #5
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
    ) -> 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
Пример #6
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
        **kwargs: Any,
    ) -> PolicyPrediction:
        """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 self._prediction(result)
Пример #7
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        precomputations: Optional[MessageContainerForCoreFeaturization] = None,
        rule_only_data: Optional[Dict[Text, Any]] = None,
        **kwargs: Any,
    ) -> PolicyPrediction:
        """Predicts the next action the bot should take after seeing the tracker.

        Args:
            tracker: Tracker containing past conversation events.
            domain: Domain of the assistant.
            precomputations: Contains precomputed features and attributes.
            rule_only_data: Slots and loops which are specific to rules and hence
                should be ignored by this policy.

        Returns:
             The policy's prediction (e.g. the probabilities for the actions).
        """
        if self.model is None:
            return self._prediction(self._default_predictions(domain))

        # Prediction through the policy is skipped if:
        # 1. If the tracker does not contain any event of type `UserUttered`
        #    till now or the intent of such event is not in domain.
        # 2. There is at least one event of type `ActionExecuted`
        #    after the last `UserUttered` event.
        if self._should_skip_prediction(tracker, domain):
            logger.debug(
                f"Skipping predictions for {self.__class__.__name__} "
                f"as either there is no event of type `UserUttered`, "
                f"event's intent is new and not in domain or "
                f"there is an event of type `ActionExecuted` after "
                f"the last `UserUttered`."
            )
            return self._prediction(self._default_predictions(domain))

        # create model data from tracker
        tracker_state_features = self._featurize_for_prediction(
            tracker, domain, precomputations, rule_only_data=rule_only_data
        )

        model_data = self._create_model_data(tracker_state_features)
        output = self.model.run_inference(model_data)

        # take the last prediction in the sequence
        all_similarities: np.ndarray = output["similarities"]
        sequence_similarities = all_similarities[:, -1, :]

        # Check for unlikely intent
        query_intent = tracker.get_last_event_for(UserUttered).intent_name
        is_unlikely_intent = self._check_unlikely_intent(
            domain, sequence_similarities, query_intent
        )

        confidences = list(np.zeros(domain.num_actions))

        if is_unlikely_intent:
            confidences[domain.index_for_action(ACTION_UNLIKELY_INTENT_NAME)] = 1.0

        return self._prediction(
            confidences,
            action_metadata=self._collect_action_metadata(
                domain, sequence_similarities, query_intent
            ),
        )
Пример #8
0
    def predict_action_probabilities(
        self,
        tracker: DialogueStateTracker,
        domain: Domain,
        interpreter: NaturalLanguageInterpreter,
        **kwargs: Any,
    ) -> PolicyPrediction:
        """Predicts the next action the bot should take after seeing the tracker.

        Args:
            tracker: Tracker containing past conversation events.
            domain: Domain of the assistant.
            interpreter: Interpreter which may be used by the policies to create
                additional features.

        Returns:
             The policy's prediction (e.g. the probabilities for the actions).
        """
        if self.model is None:
            return self._prediction(self._default_predictions(domain))

        # Prediction through the policy is skipped if:
        # 1. If the tracker does not contain any event of type `UserUttered`
        #    till now.
        # 2. There is at least one event of type `ActionExecuted`
        #    after the last `UserUttered` event.
        if self._should_skip_prediction(tracker):
            logger.debug(
                f"Skipping predictions for {self.__class__.__name__} "
                f"as either there is no event of type `UserUttered` or "
                f"there is an event of type `ActionExecuted` after "
                f"the last `UserUttered`.")
            return self._prediction(self._default_predictions(domain))

        # create model data from tracker
        tracker_state_features = self._featurize_for_prediction(
            tracker, domain, interpreter)

        model_data = self._create_model_data(tracker_state_features)
        output = self.model.run_inference(model_data)

        # take the last prediction in the sequence
        all_similarities: np.ndarray = output["similarities"]
        sequence_similarities = all_similarities[:, -1, :]

        # Check for unlikely intent
        query_intent = tracker.get_last_event_for(UserUttered).intent_name
        is_unlikely_intent = self._check_unlikely_intent(
            domain, sequence_similarities, query_intent)

        confidences = list(np.zeros(domain.num_actions))

        if is_unlikely_intent:
            confidences[domain.index_for_action(
                ACTION_UNLIKELY_INTENT_NAME)] = 1.0

        return self._prediction(
            confidences,
            action_metadata=self._collect_action_metadata(
                domain, sequence_similarities, query_intent),
        )