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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
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)))
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
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
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
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)
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
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
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
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
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
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