def test_extract_requested_slot_from_entity_with_intent(): """Test extraction of a slot value from entity with the different name and certain intent """ spec = { "name": "default_form", "slots": [{ "name": "some_slot", "filling": [{ "type": "from_entity", "entity": ["some_entity"], "intent": ["some_intent"] }] }] } form, tracker = new_form_and_tracker(spec, "some_slot") tracker.update(UserUttered( intent={"name": "some_intent", "confidence": 1.0}, entities=[{"entity": "some_entity", "value": "some_value"}] )) slot_values = form.extract_requested_slot(OutputChannel(), nlg, tracker, Domain.empty()) assert slot_values == {"some_slot": "some_value"} tracker.update(UserUttered( intent={"name": "some_other_intent", "confidence": 1.0}, entities=[{"entity": "some_entity", "value": "some_value"}] )) slot_values = form.extract_requested_slot(OutputChannel(), nlg, tracker, Domain.empty()) assert slot_values == {}
def test_extract_requested_slot_from_text_with_not_intent(): """Test extraction of a slot value from text with certain intent """ spec = { "name": "default_form", "slots": [ { "name": "some_slot", "filling": [{"type": "from_text", "not_intent": ["some_intent"],}], } ], } form, tracker = new_form_and_tracker(spec, "some_slot") tracker.update( UserUttered(intent={"name": "some_intent", "confidence": 1.0}, text="some_text") ) slot_values = form.extract_requested_slot( OutputChannel(), nlg, tracker, Domain.empty() ) assert slot_values == {} tracker.update( UserUttered( intent={"name": "some_other_intent", "confidence": 1.0}, text="some_text" ) ) slot_values = form.extract_requested_slot( OutputChannel(), nlg, tracker, Domain.empty() ) assert slot_values == {"some_slot": "some_text"}
async def test_rasa_file_importer_with_invalid_domain(tmp_path: Path): config_file = tmp_path / "config.yml" config_file.write_text("") importer = TrainingDataImporter.load_from_dict({}, str(config_file), None, []) actual = await importer.get_domain() assert actual.as_dict() == Domain.empty().as_dict()
async def test_validation(value, operator, comparatum, result, caplog): spec = { "name": "default_form", "slots": [ { "name": "some_slot", "validation": {"operator": operator, "comparatum": comparatum,}, } ], } form, tracker = new_form_and_tracker(spec, "some_slot") tracker.update(UserUttered(entities=[{"entity": "some_slot", "value": value}])) events = await form.validate(OutputChannel(), nlg, tracker, Domain.empty()) if result is True: assert len(events) == 1 assert isinstance(events[0], SlotSet) and events[0].value == value else: assert len(events) == 2 assert isinstance(events[0], SlotSet) and events[0].value == None assert ( isinstance(events[1], BotUttered) and events[1].text == "utter_invalid_some_slot" ) if result is None: assert f"Validation operator '{operator}' requires" in caplog.messages[0]
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()]
async def test_ask_affirm_after_rephrasing(): 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 ActionExecuted(ACTION_TWO_STAGE_FALLBACK_NAME), BotUttered("please rephrase"), # User rephrased with low confidence *_message_requiring_fallback(), ], ) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) assert len(events) == 1 assert isinstance(events[0], BotUttered)
def test_get_next_action_probabilities_passes_interpreter_to_policies( monkeypatch: MonkeyPatch, ): policy = TEDPolicy() test_interpreter = Mock() def predict_action_probabilities( tracker: DialogueStateTracker, domain: Domain, interpreter: NaturalLanguageInterpreter, **kwargs, ) -> List[float]: assert interpreter == test_interpreter return [1, 0] policy.predict_action_probabilities = predict_action_probabilities ensemble = SimplePolicyEnsemble(policies=[policy]) domain = Domain.empty() processor = MessageProcessor( test_interpreter, ensemble, domain, InMemoryTrackerStore(domain), Mock() ) # This should not raise processor._get_next_action_probabilities( DialogueStateTracker.from_events("lala", [ActionExecuted(ACTION_LISTEN_NAME)]) )
async def test_loop_without_activate_and_without_deactivate(): expected_do_events = [ActionExecuted("do")] form_name = "my form" class MyLoop(LoopAction): def name(self) -> Text: return form_name async def activate(self, *args: Any) -> List[Event]: raise ValueError("this shouldn't be called") async def do(self, *args: Any) -> List[Event]: return expected_do_events async def deactivate(self, *args) -> List[Event]: return [SlotSet("deactivated")] async def is_activated(self, *args: Any) -> bool: return True async def is_done(self, *args) -> bool: return False tracker = DialogueStateTracker.from_events("some sender", []) domain = Domain.empty() action = MyLoop() actual = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) assert actual == [*expected_do_events]
async def get_domain(self) -> Domain: domains = [importer.get_domain() for importer in self._importers] domains = await asyncio.gather(*domains) return reduce( lambda merged, other: merged.merge(other), domains, Domain.empty() )
async def test_applied_events_after_action_session_start( default_channel: CollectingOutputChannel, template_nlg: TemplatedNaturalLanguageGenerator, ): slot_set = SlotSet("my_slot", "value") events = [ slot_set, ActionExecuted(ACTION_LISTEN_NAME), # User triggers a restart manually by triggering the intent UserUttered( text=f"/{USER_INTENT_SESSION_START}", intent={"name": USER_INTENT_SESSION_START}, ), ] tracker = DialogueStateTracker.from_events("🕵️♀️", events) # Mapping Policy kicks in and runs the session restart action events = await ActionSessionStart().run(default_channel, template_nlg, tracker, Domain.empty()) for event in events: tracker.update(event) assert tracker.applied_events() == [ slot_set, ActionExecuted(ACTION_LISTEN_NAME) ]
async def test_without_additional_e2e_examples(tmp_path: Path): domain_path = tmp_path / "domain.yml" domain_path.write_text(Domain.empty().as_yaml()) config_path = tmp_path / "config.yml" config_path.touch() existing = TrainingDataImporter.load_from_dict({}, str(config_path), str(domain_path), []) stories = StoryGraph([ StoryStep(events=[ UserUttered("greet_from_stories", {"name": "greet_from_stories"}), ActionExecuted("utter_greet_from_stories"), ]) ]) # Patch to return our test stories existing.get_stories = asyncio.coroutine(lambda *args: stories) importer = E2EImporter(existing) training_data = await importer.get_nlu_data() assert training_data.training_examples assert training_data.is_empty() assert not training_data.without_empty_e2e_examples().training_examples
def _create_from_endpoint_config( endpoint_config: Optional[EndpointConfig] = None, domain: Optional[Domain] = None) -> "NaturalLanguageGenerator": """Given an endpoint configuration, create a proper NLG object.""" domain = domain or Domain.empty() if endpoint_config is None: from rasa.core.nlg import ( # pytype: disable=pyi-error TemplatedNaturalLanguageGenerator, ) # this is the default type if no endpoint config is set nlg = TemplatedNaturalLanguageGenerator(domain.templates) elif endpoint_config.type is None or endpoint_config.type.lower( ) == "callback": from rasa.core.nlg import ( # pytype: disable=pyi-error CallbackNaturalLanguageGenerator, ) # this is the default type if no nlg type is set nlg = CallbackNaturalLanguageGenerator(endpoint_config=endpoint_config) elif endpoint_config.type.lower() == "template": from rasa.core.nlg import ( # pytype: disable=pyi-error TemplatedNaturalLanguageGenerator, ) nlg = TemplatedNaturalLanguageGenerator(domain.templates) else: nlg = _load_from_module_name_in_endpoint_config( endpoint_config, domain) logger.debug(f"Instantiated NLG to '{nlg.__class__.__name__}'.") return nlg
async def test_1st_affirmation_is_successful(): 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 affirms UserUttered("hi", {"name": "greet", "confidence": 1.0}), ], ) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) for events in events: tracker.update(events, domain) applied_events = tracker.applied_events() assert applied_events == [ ActionExecuted(ACTION_LISTEN_NAME), UserUttered("hi", {"name": "greet", "confidence": 1.0}), ]
def test_domain_as_dict_with_session_config(): session_config = SessionConfig(123, False) domain = Domain.empty() domain.session_config = session_config serialized = domain.as_dict() deserialized = Domain.from_dict(serialized) assert deserialized.session_config == session_config
def test_extract_requested_slot_default(): """Test default extraction of a slot value from entity with the same name """ spec = {"name": "default_form"} form, tracker = new_form_and_tracker(spec, "some_slot") tracker.update(UserUttered(entities=[{"entity": "some_slot", "value": "some_value"}])) slot_values = form.extract_requested_slot(OutputChannel(), nlg, tracker, Domain.empty()) assert slot_values == {"some_slot": "some_value"}
async def get_domain(self) -> Domain: domain = Domain.empty() try: domain = Domain.load(self._domain_path) domain.check_missing_templates() except InvalidDomain as e: logger.warning( "Loading domain from '{}' failed. Using empty domain. Error: '{}'" .format(self._domain_path, e.message)) return domain
async def get_domain(self) -> Domain: domain = Domain.empty() try: domain = Domain.load(self._domain_path) domain.check_missing_templates() except InvalidDomain: logger.debug( "Loading domain from '{}' failed. Using empty domain.".format( self._domain_path)) return domain
async def get_domain(self) -> Domain: domain = Domain.empty() try: domain = Domain.load(self._domain_path) domain.check_missing_templates() except InvalidDomain as e: raise_warning( f"Loading domain from '{self._domain_path}' failed. Using " f"empty domain. Error: '{e.message}'") return domain
def test_rule_based_data_warnings_no_rule_policy(): trackers = [DialogueStateTracker("some-id", slots=[], is_rule_tracker=True)] policies = [FallbackPolicy()] ensemble = SimplePolicyEnsemble(policies) with pytest.warns(UserWarning) as record: ensemble.train(trackers, Domain.empty(), RegexInterpreter()) assert ( "Found rule-based training data but no policy supporting rule-based data." ) in record[0].message.args[0]
def test_rule_based_data_warnings_no_rule_trackers(): trackers = [DialogueStateTracker("some-id", slots=[], is_rule_tracker=False)] policies = [RulePolicy()] ensemble = SimplePolicyEnsemble(policies) with pytest.warns(UserWarning) as record: ensemble.train(trackers, Domain.empty(), RegexInterpreter()) assert ( "Found a rule-based policy in your pipeline but no rule-based training data." ) in record[0].message.args[0]
async def test_only_getting_e2e_conversation_tests_if_e2e_enabled( tmpdir_factory: TempdirFactory, ): from rasa.core.interpreter import RegexInterpreter from rasa.core.training.structures import StoryGraph import rasa.core.training.loading as core_loading root = tmpdir_factory.mktemp("Parent Bot") config = {"imports": ["bots/Bot A"]} config_path = str(root / "config.yml") utils.dump_obj_as_yaml_to_file(config_path, config) story_file = root / "bots" / "Bot A" / "data" / "stories.md" story_file.write( """ ## story * greet - utter_greet """, ensure=True, ) e2e_story_test_file = ( root / "bots" / "Bot A" / DEFAULT_E2E_TESTS_PATH / "conversation_tests.md" ) e2e_story_test_file.write( """ ## story test * greet : "hello" - utter_greet """, ensure=True, ) selector = MultiProjectImporter(config_path) story_steps = await core_loading.load_data_from_resource( resource=str(e2e_story_test_file), domain=Domain.empty(), interpreter=RegexInterpreter(), template_variables=None, use_e2e=True, exclusion_percentage=None, ) expected = StoryGraph(story_steps) actual = await selector.get_stories(use_e2e=True) assert expected.as_story_string() == actual.as_story_string()
async def test_create_fingerprint_from_invalid_paths(project, project_files): from rasa.nlu.training_data import TrainingData from rasa.core.training.structures import StoryGraph project_files = _project_files(project, *project_files) expected = _fingerprint( config="", config_nlu="", config_core="", domain=hash(Domain.empty()), nlg=get_dict_hash(Domain.empty().templates), stories=0, nlu={}, # bf rasa_version=rasa.__version__, ) actual = await model_fingerprint(project_files) assert actual[FINGERPRINT_TRAINED_AT_KEY] is not None del actual[FINGERPRINT_TRAINED_AT_KEY] del expected[FINGERPRINT_TRAINED_AT_KEY] assert actual == expected
def _create_domain(domain: Union[Domain, Text, None]) -> Domain: if isinstance(domain, str): domain = Domain.load(domain) domain.check_missing_templates() return domain elif isinstance(domain, Domain): return domain elif domain is None: return Domain.empty() else: raise ValueError( "Invalid param `domain`. Expected a path to a domain " "specification or a domain instance. But got " "type '{}' with value '{}'".format(type(domain), domain))
def test_unfeaturized_slot_in_domain_warnings(): # create empty domain domain = Domain.empty() # add one unfeaturized and one text slot unfeaturized_slot = UnfeaturizedSlot("unfeaturized_slot", "value1") text_slot = TextSlot("text_slot", "value2") domain.slots.extend([unfeaturized_slot, text_slot]) # ensure both are in domain assert all(slot in domain.slots for slot in (unfeaturized_slot, text_slot)) # text slot should appear in domain warnings, unfeaturized slot should not in_domain_slot_warnings = domain.domain_warnings()["slot_warnings"]["in_domain"] assert text_slot.name in in_domain_slot_warnings assert unfeaturized_slot.name not in in_domain_slot_warnings
async def get_domain(self) -> Domain: domain = Domain.empty() try: domain = Domain.load(self._domain_path) domain.check_missing_templates() bf_forms = [] for slot in domain.slots: if slot.name == "bf_forms": bf_forms = slot.initial_value bf_forms = [f.get("name") for f in bf_forms] except InvalidDomain as e: logger.warning( "Loading domain from '{}' failed. Using empty domain. Error: '{}'" .format(self._domain_path, e.message)) return domain
def test_extract_requested_slot_default(): """Test default extraction of a slot value from entity with the same name.""" form = FormAction("some form", None) tracker = DialogueStateTracker.from_events( "default", [ SlotSet(REQUESTED_SLOT, "some_slot"), UserUttered( "bla", entities=[{"entity": "some_slot", "value": "some_value"}] ), ActionExecuted(ACTION_LISTEN_NAME), ], ) slot_values = form.extract_requested_slot(tracker, Domain.empty()) assert slot_values == {"some_slot": "some_value"}
async def test_agent_update_model_none_domain(trained_model: Text): agent = await load_agent(model_path=trained_model) agent.update_model( Domain.empty(), None, agent.fingerprint, agent.interpreter, agent.model_directory, ) sender_id = "test_sender_id" message = UserMessage("hello", sender_id=sender_id) await agent.handle_message(message) tracker = agent.tracker_store.get_or_create_tracker(sender_id) # UserUttered event was added to tracker, with correct intent data assert tracker.events[3].intent["name"] == "greet"
def test_get_next_action_probabilities_pass_policy_predictions_without_interpreter_arg( predict_function: Callable, ): policy = TEDPolicy() policy.predict_action_probabilities = predict_function ensemble = SimplePolicyEnsemble(policies=[policy]) interpreter = Mock() domain = Domain.empty() processor = MessageProcessor(interpreter, ensemble, domain, InMemoryTrackerStore(domain), Mock()) with pytest.warns(DeprecationWarning): processor._get_next_action_probabilities( DialogueStateTracker.from_events( "lala", [ActionExecuted(ACTION_LISTEN_NAME)]))
async def test_update_with_new_domain(trained_rasa_model: Text, tmpdir: Path): _ = model.unpack_model(trained_rasa_model, tmpdir) new_domain = Domain.empty() mocked_importer = Mock() async def get_domain() -> Domain: return new_domain mocked_importer.get_domain = get_domain await model.update_model_with_new_domain(mocked_importer, tmpdir) actual = Domain.load(tmpdir / DEFAULT_CORE_SUBDIRECTORY_NAME / DEFAULT_DOMAIN_PATH) assert actual.is_empty()
async def test_ask_affirmation(): tracker = DialogueStateTracker.from_events( "some-sender", evts=_message_requiring_fallback() ) domain = Domain.empty() action = TwoStageFallbackAction() events = await action.run( CollectingOutputChannel(), TemplatedNaturalLanguageGenerator(domain.templates), tracker, domain, ) assert len(events) == 2 assert events[0] == ActiveLoop(ACTION_TWO_STAGE_FALLBACK_NAME) assert isinstance(events[1], BotUttered)