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"}
Beispiel #3
0
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]
Beispiel #5
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()]
Beispiel #6
0
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)
Beispiel #7
0
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)])
    )
Beispiel #8
0
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]
Beispiel #9
0
    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()
        )
Beispiel #10
0
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)
    ]
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
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}),
    ]
Beispiel #14
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"}
Beispiel #16
0
    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
Beispiel #17
0
    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
Beispiel #18
0
    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
Beispiel #19
0
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]
Beispiel #20
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]
Beispiel #21
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()
Beispiel #22
0
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
Beispiel #23
0
    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
Beispiel #25
0
    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
Beispiel #26
0
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"}
Beispiel #27
0
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"
Beispiel #28
0
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)]))
Beispiel #29
0
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()
Beispiel #30
0
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)