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), ]
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 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(), ]
async def run( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: # only utter the response 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 run( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: """Runs action. Please see parent class for the full docstring.""" # only utter the response if it is available evts = await super().run(output_channel, nlg, tracker, domain) return evts + [UserUtteranceReverted(), 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.responses), tracker, domain, ) assert events == [ActiveLoop(None), 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_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?", metadata={"template_name": "utter_default"}, ), UserUtteranceReverted(), ]
async def deactivate( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", events_so_far: List[Event], ) -> List[Event]: if _two_fallbacks_in_a_row(tracker) or _second_affirmation_failed(tracker): return await self._give_up(output_channel, nlg, tracker, domain) # revert fallback events return [UserUtteranceReverted()] + _message_clarification(tracker)
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: 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.get(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.get(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.get(ACTION_NAME) == "my_action_1" assert len(list(tracker.generate_all_prior_trackers())) == 3
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.responses), tracker, domain, ) assert events == [ActiveLoop(None), UserUtteranceReverted()]
LegacyFormValidation(validate=True, timestamp=None), LoopInterrupted(timestamp=None, is_interrupted=False), ActiveLoop(name="loop"), LegacyForm(name="my_form"), AllSlotsReset(), SlotSet(key="my_slot", value={}), SlotSet(key="my slot", value=[]), SlotSet(key="test", value=1), SlotSet(key="test", value="text"), ConversationResumed(), ConversationPaused(), FollowupAction(name="test"), StoryExported(), Restarted(), ActionReverted(), UserUtteranceReverted(), BotUttered(text="Test bot utterance"), UserUttered( parse_data={ "entities": [], "response_selector": { "all_retrieval_intents": [], "chitchat/ask_weather": { "response": {}, "ranking": [] }, }, }), UserUttered( text="hello", parse_data={
def test_json_parse_rewind(): evt = {"event": "rewind"} assert Event.from_parameters(evt) == UserUtteranceReverted()
@pytest.mark.parametrize( "one_event,another_event", [ ( UserUttered("/greet", {"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), (SessionStarted(), 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_intent", datetime.now()), ReminderScheduled("my_other_intent", datetime.now()), ),
), ] def _two_stage_clarification_request() -> List[Event]: return [ ActionExecuted(ACTION_TWO_STAGE_FALLBACK_NAME), BotUttered("please affirm") ] @pytest.mark.parametrize( "events", [ _message_requiring_fallback(), _message_requiring_fallback() + [UserUtteranceReverted()] + _message_requiring_fallback(), ], ) async def test_ask_affirmation(events: List[Event]): tracker = DialogueStateTracker.from_events("some-sender", evts=events) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.responses), tracker, domain, )