def test_resolve_intent_response_key_from_label( predicted_label, train_on_text, resolved_intent_response_key ): # use data that include some responses training_data = rasa.shared.nlu.training_data.loading.load_data( "data/examples/rasa/demo-rasa.yml" ) training_data_responses = rasa.shared.nlu.training_data.loading.load_data( "data/examples/rasa/demo-rasa-responses.yml" ) training_data = training_data.merge(training_data_responses) response_selector = ResponseSelector( component_config={"use_text_as_label": train_on_text} ) response_selector.preprocess_train_data(training_data) label_intent_response_key = response_selector._resolve_intent_response_key( {"id": hash(predicted_label), "name": predicted_label} ) assert resolved_intent_response_key == label_intent_response_key assert ( response_selector.responses[ util.intent_response_key_to_template_key(label_intent_response_key) ] == training_data.responses[ util.intent_response_key_to_template_key(resolved_intent_response_key) ] )
def process(self, message: Message, **kwargs: Any) -> None: """Return the most likely response, the associated intent_response_key and its similarity to the input.""" out = self._predict(message) top_label, label_ranking = self._predict_label(out) # Get the exact intent_response_key and the associated # response templates for the top predicted label label_intent_response_key = ( self._resolve_intent_response_key(top_label) or top_label[INTENT_NAME_KEY]) label_response_templates = self.responses.get( util.intent_response_key_to_template_key( label_intent_response_key)) if label_intent_response_key and not label_response_templates: # response templates seem to be unavailable, # likely an issue with the training data # we'll use a fallback instead rasa.shared.utils.io.raise_warning( f"Unable to fetch response templates for {label_intent_response_key} " f"This means that there is likely an issue with the training data." f"Please make sure you have added response templates for this intent." ) label_response_templates = [{TEXT: label_intent_response_key}] for label in label_ranking: label[INTENT_RESPONSE_KEY] = ( self._resolve_intent_response_key(label) or label[INTENT_NAME_KEY]) # Remove the "name" key since it is either the same as # "intent_response_key" or it is the response text which # is not needed in the ranking. label.pop(INTENT_NAME_KEY) selector_key = (self.retrieval_intent if self.retrieval_intent else RESPONSE_SELECTOR_DEFAULT_INTENT) logger.debug( f"Adding following selector key to message property: {selector_key}" ) prediction_dict = { RESPONSE_SELECTOR_PREDICTION_KEY: { "id": top_label["id"], RESPONSE_SELECTOR_RESPONSES_KEY: label_response_templates, PREDICTED_CONFIDENCE_KEY: top_label[PREDICTED_CONFIDENCE_KEY], INTENT_RESPONSE_KEY: label_intent_response_key, RESPONSE_SELECTOR_TEMPLATE_NAME_KEY: util.intent_response_key_to_template_key( label_intent_response_key), }, RESPONSE_SELECTOR_RANKING_KEY: label_ranking, } self._set_message_property(message, prediction_dict, selector_key)
def test_resolve_intent_response_key_from_label( predicted_label: Text, train_on_text: bool, resolved_intent_response_key: Text, response_selector_training_data: TrainingData, create_response_selector: Callable[ [Dict[Text, Any]], ResponseSelectorGraphComponent ], ): response_selector = create_response_selector({"use_text_as_label": train_on_text},) response_selector.preprocess_train_data(response_selector_training_data) label_intent_response_key = response_selector._resolve_intent_response_key( {"id": hash(predicted_label), "name": predicted_label} ) assert resolved_intent_response_key == label_intent_response_key assert ( response_selector.responses[ util.intent_response_key_to_template_key(label_intent_response_key) ] == response_selector_training_data.responses[ util.intent_response_key_to_template_key(resolved_intent_response_key) ] )
def _needed_responses_for_examples( self, examples: List[Message] ) -> Dict[Text, List[Dict[Text, Any]]]: """Get all responses used in any of the examples. Args: examples: messages to select responses by. Returns: All responses that appear at least once in the list of examples. """ responses = {} for ex in examples: if ex.get(INTENT_RESPONSE_KEY) and ex.get(RESPONSE): key = util.intent_response_key_to_template_key(ex.get_full_intent()) responses[key] = self.responses[key] return responses
def _fill_response_phrases(self) -> None: """Set response phrase for all examples by looking up NLG stories.""" for example in self.training_examples: # if intent_response_key is None, that means the corresponding intent is # not a retrieval intent and hence no response text needs to be fetched. # If intent_response_key is set, fetch the corresponding response text if example.get(INTENT_RESPONSE_KEY) is None: continue # look for corresponding bot utterance story_lookup_key = util.intent_response_key_to_template_key( example.get_full_intent()) assistant_utterances = self.responses.get(story_lookup_key, []) if assistant_utterances: # Use the first response text as training label if needed downstream for assistant_utterance in assistant_utterances: if assistant_utterance.get(TEXT): example.set(RESPONSE, assistant_utterance[TEXT]) # If no text attribute was found use the key for training if not example.get(RESPONSE): example.set(RESPONSE, story_lookup_key)
def process(self, messages: List[Message]) -> List[Message]: """Selects most like response for message. Args: messages: List containing latest user message. Returns: List containing the message augmented with the most likely response, the associated intent_response_key and its similarity to the input. """ for message in messages: out = self._predict(message) top_label, label_ranking = self._predict_label(out) # Get the exact intent_response_key and the associated # responses for the top predicted label label_intent_response_key = ( self._resolve_intent_response_key(top_label) or top_label[INTENT_NAME_KEY]) label_responses = self.responses.get( util.intent_response_key_to_template_key( label_intent_response_key)) if label_intent_response_key and not label_responses: # responses seem to be unavailable, # likely an issue with the training data # we'll use a fallback instead rasa.shared.utils.io.raise_warning( f"Unable to fetch responses for {label_intent_response_key} " f"This means that there is likely an issue with the training data." f"Please make sure you have added responses for this intent." ) label_responses = [{TEXT: label_intent_response_key}] for label in label_ranking: label[INTENT_RESPONSE_KEY] = ( self._resolve_intent_response_key(label) or label[INTENT_NAME_KEY]) # Remove the "name" key since it is either the same as # "intent_response_key" or it is the response text which # is not needed in the ranking. label.pop(INTENT_NAME_KEY) selector_key = (self.retrieval_intent if self.retrieval_intent else RESPONSE_SELECTOR_DEFAULT_INTENT) logger.debug( f"Adding following selector key to message property: {selector_key}" ) utter_action_key = util.intent_response_key_to_template_key( label_intent_response_key) prediction_dict = { RESPONSE_SELECTOR_PREDICTION_KEY: { RESPONSE_SELECTOR_RESPONSES_KEY: label_responses, PREDICTED_CONFIDENCE_KEY: top_label[PREDICTED_CONFIDENCE_KEY], INTENT_RESPONSE_KEY: label_intent_response_key, RESPONSE_SELECTOR_UTTER_ACTION_KEY: utter_action_key, }, RESPONSE_SELECTOR_RANKING_KEY: label_ranking, } self._set_message_property(message, prediction_dict, selector_key) if (self._execution_context.should_add_diagnostic_data and out and DIAGNOSTIC_DATA in out): message.add_diagnostic_data(self._execution_context.node_name, out.get(DIAGNOSTIC_DATA)) return messages
def test_intent_response_key_to_template_key(): intent_response_key = "chitchat/ask_name" template_key = "utter_chitchat/ask_name" assert intent_response_key_to_template_key(intent_response_key) == template_key