def _find_action_from_rules(self, tracker: DialogueStateTracker, domain: Domain) -> Optional[Text]: tracker_as_states = self.featurizer.prediction_states([tracker], domain) states = tracker_as_states[0] logger.debug(f"Current tracker state: {states}") rule_keys = self._get_possible_keys(self.lookup[RULES], states) predicted_action_name = None best_rule_key = "" if rule_keys: # TODO check that max is correct # if there are several rules, # it should mean that some rule is a subset of another rule best_rule_key = max(rule_keys, key=len) predicted_action_name = self.lookup[RULES].get(best_rule_key) active_form_name = tracker.active_loop_name() if active_form_name: # find rules for unhappy path of the form form_unhappy_keys = self._get_possible_keys( self.lookup[RULES_FOR_FORM_UNHAPPY_PATH], states) # there could be several unhappy path conditions unhappy_path_conditions = [ self.lookup[RULES_FOR_FORM_UNHAPPY_PATH].get(key) for key in form_unhappy_keys ] # Check if a rule that predicted action_listen # was applied inside the form. # Rules might not explicitly switch back to the `Form`. # Hence, we have to take care of that. predicted_listen_from_general_rule = ( predicted_action_name == ACTION_LISTEN_NAME and ACTIVE_FORM_PREFIX + active_form_name not in best_rule_key) if predicted_listen_from_general_rule: if DO_NOT_PREDICT_FORM_ACTION not in unhappy_path_conditions: # negative rules don't contain a key that corresponds to # the fact that active_form shouldn't be predicted logger.debug( f"Predicted form '{active_form_name}' by overwriting " f"'{ACTION_LISTEN_NAME}' predicted by general rule.") return active_form_name # do not predict anything predicted_action_name = None if DO_NOT_VALIDATE_FORM in unhappy_path_conditions: logger.debug("Added `FormValidation(False)` event.") tracker.update(FormValidation(False)) if predicted_action_name is not None: logger.debug( f"There is a rule for the next action '{predicted_action_name}'." ) else: logger.debug("There is no applicable rule.") return predicted_action_name
def _find_action_from_form_happy_path( tracker: DialogueStateTracker, ) -> Optional[Text]: active_form_name = tracker.active_loop_name() active_form_rejected = tracker.active_loop.get("rejected") should_predict_form = (active_form_name and not active_form_rejected and tracker.latest_action_name != active_form_name) should_predict_listen = (active_form_name and not active_form_rejected and tracker.latest_action_name == active_form_name) if should_predict_form: logger.debug(f"Predicted form '{active_form_name}'.") return active_form_name # predict `action_listen` if form action was run successfully if should_predict_listen: logger.debug( f"Predicted '{ACTION_LISTEN_NAME}' after form '{active_form_name}'." ) return ACTION_LISTEN_NAME