def _revert_single_affirmation_events() -> List[Event]: return [ UserUtteranceReverted(), # revert affirmation and request # revert original intent (has to be re-added later) UserUtteranceReverted(), # add action listen intent ActionExecuted(action_name=ACTION_LISTEN_NAME), ]
async def test_action_back(default_channel, template_nlg, template_sender_tracker, default_domain): events = await ActionBack().run(default_channel, template_nlg, template_sender_tracker, default_domain) assert events == [ BotUttered("backing up...", metadata={"template_name": "utter_back"}), UserUtteranceReverted(), UserUtteranceReverted(), ]
def _revert_rephrasing_events() -> List[Event]: return [ UserUtteranceReverted(), # remove rephrasing # remove feedback and rephrase request UserUtteranceReverted(), # remove affirmation request and false intent UserUtteranceReverted(), # replace action with action listen ActionExecuted(action_name=ACTION_LISTEN_NAME), ]
async def run( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: # only utter the template if it is available evts = await super().run(output_channel, nlg, tracker, domain) return evts + [UserUtteranceReverted(), UserUtteranceReverted()]
async def run(self, output_channel, nlg, tracker, domain): evts = await super(ActionBotfrontFallback, self).run(output_channel, nlg, tracker, domain) if (len(tracker.events) >= 4 and isinstance(tracker.events[-4], ActionExecuted) and tracker.events[-4].action_name == "action_botfront_disambiguation"): return evts + [UserUtteranceReverted(), UserUtteranceReverted()] else: return evts + [UserUtteranceReverted()]
async def test_2nd_affirmation_failed(intent_which_lets_action_give_up: Text): tracker = DialogueStateTracker.from_events( "some-sender", evts=[ # User sends message with low NLU confidence *_message_requiring_fallback(), ActiveLoop(ACTION_TWO_STAGE_FALLBACK_NAME), # Action asks user to affirm *_two_stage_clarification_request(), ActionExecuted(ACTION_LISTEN_NAME), # User denies suggested intents UserUttered("hi", {"name": USER_INTENT_OUT_OF_SCOPE}), # Action asks user to rephrase *_two_stage_clarification_request(), # User rephrased with low confidence *_message_requiring_fallback(), # Actions asks user to affirm for the last time *_two_stage_clarification_request(), ActionExecuted(ACTION_LISTEN_NAME), # User denies suggested intents for the second time UserUttered("hi", {"name": intent_which_lets_action_give_up}), ], ) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) assert events == [ActiveLoop(None), UserUtteranceReverted()]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: dispatcher.utter_message(text="Hi, I'm nuSDKBot, i can help you to get the information about nuSDK API, please ask me!") return [UserUtteranceReverted()]
async def run(self, output_channel, nlg, tracker, domain): from rasa.core.events import UserUtteranceReverted # only utter the template if it is available evts = await super().run(output_channel, nlg, tracker, domain) return evts + [UserUtteranceReverted()]
def test_json_parse_rewind(): # DOCS MARKER UserUtteranceReverted evt = \ { 'event': 'rewind' } # DOCS END assert Event.from_parameters(evt) == UserUtteranceReverted()
async def run(self, dispatcher, tracker, domain): from rasa.core.events import UserUtteranceReverted await dispatcher.utter_template("utter_default", tracker, silent_fail=True) return [UserUtteranceReverted()]
async def test_action_default_fallback(default_channel, default_nlg, default_tracker, default_domain): events = await ActionDefaultFallback().run(default_channel, default_nlg, default_tracker, default_domain) assert events == [ BotUttered("sorry, I didn't get that, can you rephrase it?"), UserUtteranceReverted(), ]
async def _revert_fallback_events( self, output_channel: OutputChannel, nlg: NaturalLanguageGenerator, tracker: DialogueStateTracker, domain: Domain, events_so_far: List[Event], ) -> List[Event]: revert_events = [UserUtteranceReverted(), UserUtteranceReverted()] temp_tracker = DialogueStateTracker.from_events( tracker.sender_id, tracker.applied_events() + events_so_far + revert_events) while temp_tracker.latest_message and not await self.is_done( output_channel, nlg, temp_tracker, domain, []): temp_tracker.update(revert_events[-1]) revert_events.append(UserUtteranceReverted()) return revert_events
async def test_default_action(default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) fallback_action = action.ActionDefaultFallback() events = await fallback_action.run(default_dispatcher_collecting, tracker, default_domain) channel = default_dispatcher_collecting.output_channel assert channel.messages == [{ u"text": u"sorry, I didn't get that, can you rephrase it?", u"recipient_id": u"my-sender", }] assert events == [UserUtteranceReverted()]
async def run( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: revert_events = [ UserUtteranceReverted(), UserUtteranceReverted(), ActionExecuted(action_name="action_listen"), ] last_user_event = None for event in list(tracker.events)[::-1]: if isinstance(event, UserUttered): last_user_event = copy.deepcopy(event) last_user_event.parse_data["intent"]["confidence"] = 1.0 break if last_user_event: revert_events += [last_user_event] return revert_events
def test_revert_user_utterance_event(default_domain): tracker = DialogueStateTracker("default", default_domain.slots) # the retrieved tracker should be empty assert len(tracker.events) == 0 intent1 = {"name": "greet", "confidence": 1.0} tracker.update(ActionExecuted(ACTION_LISTEN_NAME)) tracker.update(UserUttered("/greet", intent1, [])) tracker.update(ActionExecuted("my_action_1")) tracker.update(ActionExecuted(ACTION_LISTEN_NAME)) intent2 = {"name": "goodbye", "confidence": 1.0} tracker.update(UserUttered("/goodbye", intent2, [])) tracker.update(ActionExecuted("my_action_2")) tracker.update(ActionExecuted(ACTION_LISTEN_NAME)) # Expecting count of 6: # +5 executed actions # +1 final state assert tracker.latest_action_name == ACTION_LISTEN_NAME assert len(list(tracker.generate_all_prior_trackers())) == 6 tracker.update(UserUtteranceReverted()) # Expecting count of 3: # +5 executed actions # +1 final state # -2 rewound actions associated with the /goodbye # -1 rewound action from the listen right before /goodbye assert tracker.latest_action_name == "my_action_1" assert len(list(tracker.generate_all_prior_trackers())) == 3 dialogue = tracker.as_dialogue() recovered = DialogueStateTracker("default", default_domain.slots) recovered.recreate_from_dialogue(dialogue) assert recovered.current_state() == tracker.current_state() assert tracker.latest_action_name == "my_action_1" assert len(list(tracker.generate_all_prior_trackers())) == 3
async def _correct_wrong_nlu( corrected_nlu: Dict[Text, Any], events: List[Dict[Text, Any]], endpoint: EndpointConfig, sender_id: Text, ) -> None: """A wrong NLU prediction got corrected, update core's tracker.""" revert_latest_user_utterance = UserUtteranceReverted().as_dict() # `UserUtteranceReverted` also removes the `ACTION_LISTEN` event before, hence we # have to replay it. listen_for_next_message = ActionExecuted(ACTION_LISTEN_NAME).as_dict() corrected_message = latest_user_message(events) if corrected_message is None: raise Exception("Failed to correct NLU data. User message not found.") corrected_message["parse_data"] = corrected_nlu await send_event( endpoint, sender_id, [revert_latest_user_utterance, listen_for_next_message, corrected_message], )
async def test_give_it_up_after_low_confidence_after_affirm_request(): tracker = DialogueStateTracker.from_events( "some-sender", evts=[ # User sends message with low NLU confidence *_message_requiring_fallback(), ActiveLoop(ACTION_TWO_STAGE_FALLBACK_NAME), # Action asks user to affirm *_two_stage_clarification_request(), # User's affirms with low NLU confidence again *_message_requiring_fallback(), ], ) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) assert events == [ActiveLoop(None), UserUtteranceReverted()]
async def _undo_latest(sender_id: Text, endpoint: EndpointConfig) -> None: """Undo either the latest bot action or user message, whatever is last.""" tracker = await retrieve_tracker(endpoint, sender_id, EventVerbosity.ALL) # Get latest `UserUtterance` or `ActionExecuted` event. last_event_type = None for i, e in enumerate(reversed(tracker.get("events", []))): last_event_type = e.get("event") if last_event_type in {ActionExecuted.type_name, UserUttered.type_name}: break elif last_event_type == Restarted.type_name: break if last_event_type == ActionExecuted.type_name: undo_action = ActionReverted().as_dict() await send_event(endpoint, sender_id, undo_action) elif last_event_type == UserUttered.type_name: undo_user_message = UserUtteranceReverted().as_dict() listen_for_next_message = ActionExecuted(ACTION_LISTEN_NAME).as_dict() await send_event( endpoint, sender_id, [undo_user_message, listen_for_next_message] )
def test_json_parse_rewind(): # DOCS MARKER UserUtteranceReverted evt = {"event": "rewind"} # DOCS END assert Event.from_parameters(evt) == UserUtteranceReverted()
def run(self, dispatcher, tracker, domain): inp = next(tracker.get_latest_entity_values("username"), None) if not inp: dispatcher.utter_message("Please enter your name") return [UserUtteranceReverted()] return [SlotSet('username', inp)]
def run(self, dispatcher, tracker, domain): inp = next(tracker.get_latest_entity_values("phone-number"), None) if not inp: dispatcher.utter_message("Please enter a valid contact") return [UserUtteranceReverted()] return [SlotSet('phone-number', inp)]
def run(self, dispatcher, tracker, domain): dest = next(tracker.get_latest_entity_values("location"), None) if not dest: dispatcher.utter_message("Please enter destination") return [UserUtteranceReverted()] return [SlotSet('destination', dest)]
def run(self, dispatcher, tracker, domain): orig = next(tracker.get_latest_entity_values("location"), None) if not orig: dispatcher.utter_message("Please enter source") return [UserUtteranceReverted()] return [SlotSet('source', orig)]
def run(self, dispatcher, tracker, domain): # only utter the template if it is available dispatcher.utter_template("utter_back", tracker, silent_fail=True) return [UserUtteranceReverted(), UserUtteranceReverted()]
async def run(self, output_channel, nlg, tracker, domain): # only utter the template if it is available events = await super(ActionBack, self).run(output_channel, nlg, tracker, domain) return events + [UserUtteranceReverted(), UserUtteranceReverted()]
"name": "greet", "confidence": 1.0 }, []), UserUttered("/goodbye", { "name": "goodbye", "confidence": 1.0 }, []), ), (SlotSet("my_slot", "value"), SlotSet("my__other_slot", "value")), (Restarted(), None), (AllSlotsReset(), None), (ConversationPaused(), None), (ConversationResumed(), None), (StoryExported(), None), (ActionReverted(), None), (UserUtteranceReverted(), None), (ActionExecuted("my_action"), ActionExecuted("my_other_action")), (FollowupAction("my_action"), FollowupAction("my_other_action")), ( BotUttered("my_text", {"my_data": 1}), BotUttered("my_other_test", {"my_other_data": 1}), ), ( AgentUttered("my_text", "my_data"), AgentUttered("my_other_test", "my_other_data"), ), ( ReminderScheduled("my_action", datetime.now()), ReminderScheduled("my_other_action", datetime.now()), ), ],
def test_json_parse_rewind(): evt = {"event": "rewind"} assert Event.from_parameters(evt) == UserUtteranceReverted()