Beispiel #1
0
async def test_action_utter_retrieved_response(
    default_channel, default_nlg, default_tracker, default_domain
):
    from rasa.core.channels.channel import UserMessage

    action_name = "utter_chitchat"
    default_tracker.latest_message = UserMessage(
        "Who are you?",
        parse_data={
            "response_selector": {
                "chitchat": {
                    "response": {
                        "intent_response_key": "chitchat/ask_name",
                        "response_templates": [{"text": "I am a bot."}],
                        "template_name": "utter_chitchat/ask_name",
                    }
                }
            }
        },
    )

    default_domain.templates.update(
        {"utter_chitchat/ask_name": [{"text": "I am a bot."}]}
    )

    events = await ActionRetrieveResponse(action_name).run(
        default_channel, default_nlg, default_tracker, default_domain
    )

    assert events[0].as_dict().get("text") == BotUttered("I am a bot.").as_dict().get(
        "text"
    )
    assert (
        events[0].as_dict().get("metadata").get("template_name")
        == "utter_chitchat/ask_name"
    )
Beispiel #2
0
async def test_action_default_ask_affirmation_on_empty_conversation(
        default_channel, default_nlg, default_tracker, domain: Domain):
    events = await ActionDefaultAskAffirmation().run(default_channel,
                                                     default_nlg,
                                                     default_tracker, domain)

    assert events == [
        BotUttered(
            "Did you mean 'None'?",
            {
                "buttons": [
                    {
                        "title": "Yes",
                        "payload": "/None"
                    },
                    {
                        "title": "No",
                        "payload": "/out_of_scope"
                    },
                ]
            },
            {"utter_action": "action_default_ask_affirmation"},
        )
    ]
Beispiel #3
0
            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 test_event_has_proper_implementation(one_event, another_event):
    # equals tests
    assert (
Beispiel #4
0
from ruamel.yaml import StringIO

# a couple of event instances that we can use for testing
test_events = [
    Event.from_parameters({
        "event": UserUttered.type_name,
        "text": "/goodbye",
        "parse_data": {
            "intent": {
                "confidence": 1.0,
                INTENT_NAME_KEY: "greet"
            },
            "entities": [],
        },
    }),
    BotUttered("Welcome!", {"test": True}),
    SlotSet("cuisine", 34),
    SlotSet("cuisine", "34"),
    SlotSet("location", None),
    SlotSet("location", [34, "34", None]),
]


@pytest.fixture
def rasa_app_without_api(rasa_server_without_api: Sanic) -> SanicTestClient:
    return get_test_client(rasa_server_without_api)


@pytest.fixture
def rasa_app(rasa_server: Sanic) -> SanicTestClient:
    return get_test_client(rasa_server)
Beispiel #5
0
async def test_handle_message_with_session_start(
    default_channel: CollectingOutputChannel,
    default_processor: MessageProcessor,
    monkeypatch: MonkeyPatch,
):
    sender_id = uuid.uuid4().hex

    entity = "name"
    slot_1 = {entity: "Core"}
    await default_processor.handle_message(
        UserMessage(f"/greet{json.dumps(slot_1)}", default_channel, sender_id))

    assert default_channel.latest_output() == {
        "recipient_id": sender_id,
        "text": "hey there Core!",
    }

    # patch processor so a session start is triggered
    monkeypatch.setattr(default_processor, "_has_session_expired",
                        lambda _: True)

    slot_2 = {entity: "post-session start hello"}
    # handle a new message
    await default_processor.handle_message(
        UserMessage(f"/greet{json.dumps(slot_2)}", default_channel, sender_id))

    tracker = default_processor.tracker_store.get_or_create_tracker(sender_id)

    # make sure the sequence of events is as expected
    expected = [
        ActionExecuted(ACTION_SESSION_START_NAME),
        SessionStarted(),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered(
            f"/greet{json.dumps(slot_1)}",
            {
                INTENT_NAME_KEY: "greet",
                "confidence": 1.0
            },
            [{
                "entity": entity,
                "start": 6,
                "end": 22,
                "value": "Core"
            }],
        ),
        SlotSet(entity, slot_1[entity]),
        ActionExecuted("utter_greet"),
        BotUttered("hey there Core!",
                   metadata={"template_name": "utter_greet"}),
        ActionExecuted(ACTION_LISTEN_NAME),
        ActionExecuted(ACTION_SESSION_START_NAME),
        SessionStarted(),
        # the initial SlotSet is reapplied after the SessionStarted sequence
        SlotSet(entity, slot_1[entity]),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered(
            f"/greet{json.dumps(slot_2)}",
            {
                INTENT_NAME_KEY: "greet",
                "confidence": 1.0
            },
            [{
                "entity": entity,
                "start": 6,
                "end": 42,
                "value": "post-session start hello",
            }],
        ),
        SlotSet(entity, slot_2[entity]),
        ActionExecuted("utter_greet"),
        BotUttered(
            "hey there post-session start hello!",
            metadata={"template_name": "utter_greet"},
        ),
        ActionExecuted(ACTION_LISTEN_NAME),
    ]

    assert list(tracker.events) == expected
Beispiel #6
0
def _two_stage_clarification_request() -> List[Event]:
    return [
        ActionExecuted(ACTION_TWO_STAGE_FALLBACK_NAME),
        BotUttered("please affirm")
    ]
Beispiel #7
0
         user_uttered("greet"),
         ActionExecuted("loop"),
         ActiveLoop("loop"),
         SlotSet(REQUESTED_SLOT, "bla"),
         SlotSet("slot", "value"),
         ActiveLoop(None),
         SlotSet(REQUESTED_SLOT, None),
     ],
 ),
 (
     [
         user_uttered("trigger form"),
         ActionExecuted("form"),
         ActiveLoop("form"),
         SlotSet(REQUESTED_SLOT, "some slot"),
         BotUttered("ask slot"),
         ActionExecuted(ACTION_LISTEN_NAME),
         user_uttered("fill requested slots"),
         SlotSet("some slot", "value"),
         ActionExecuted("form"),
         SlotSet("some slot", "value"),
         SlotSet(REQUESTED_SLOT, None),
         ActiveLoop(None),
     ],
     [
         user_uttered("trigger form"),
         ActionExecuted("form"),
         ActiveLoop("form"),
         SlotSet(REQUESTED_SLOT, "some slot"),
         BotUttered("ask slot"),
         SlotSet("some slot", "value"),
Beispiel #8
0
async def test_switch_forms_with_same_slot(default_agent: Agent):
    """Tests switching of forms, where the first slot is the same in both forms.

    Tests the fix for issue 7710"""

    # Define two forms in the domain, with same first slot
    slot_a = "my_slot_a"

    form_1 = "my_form_1"
    utter_ask_form_1 = f"Please provide the value for {slot_a} of form 1"

    form_2 = "my_form_2"
    utter_ask_form_2 = f"Please provide the value for {slot_a} of form 2"

    domain = f"""
version: "2.0"
nlu:
- intent: order_status
  examples: |
    - check status of my order
    - when are my shoes coming in
- intent: return
  examples: |
    - start a return
    - I don't want my shoes anymore
forms:
  {form_1}:
    {slot_a}:
    - type: from_entity
      entity: number
  {form_2}:
    {slot_a}:
    - type: from_entity
      entity: number
responses:
    utter_ask_{form_1}_{slot_a}:
    - text: {utter_ask_form_1}
    utter_ask_{form_2}_{slot_a}:
    - text: {utter_ask_form_2}
"""

    domain = Domain.from_yaml(domain)

    # Driving it like rasa/core/processor
    processor = MessageProcessor(
        default_agent.interpreter,
        default_agent.policy_ensemble,
        domain,
        InMemoryTrackerStore(domain),
        TemplatedNaturalLanguageGenerator(domain.templates),
    )

    # activate the first form
    tracker = DialogueStateTracker.from_events(
        "some-sender",
        evts=[
            ActionExecuted(ACTION_LISTEN_NAME),
            UserUttered("order status", {
                "name": "form_1",
                "confidence": 1.0
            }),
            DefinePrevUserUtteredFeaturization(False),
        ],
    )
    # rasa/core/processor.predict_next_action
    prediction = PolicyPrediction([], "some_policy")
    action_1 = FormAction(form_1, None)

    await processor._run_action(
        action_1,
        tracker,
        CollectingOutputChannel(),
        TemplatedNaturalLanguageGenerator(domain.templates),
        prediction,
    )

    events_expected = [
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered("order status", {
            "name": "form_1",
            "confidence": 1.0
        }),
        DefinePrevUserUtteredFeaturization(False),
        ActionExecuted(form_1),
        ActiveLoop(form_1),
        SlotSet(REQUESTED_SLOT, slot_a),
        BotUttered(
            text=utter_ask_form_1,
            metadata={"template_name": f"utter_ask_{form_1}_{slot_a}"},
        ),
    ]
    assert tracker.applied_events() == events_expected

    next_events = [
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered("return my shoes", {
            "name": "form_2",
            "confidence": 1.0
        }),
        DefinePrevUserUtteredFeaturization(False),
    ]
    tracker.update_with_events(
        next_events,
        domain,
    )
    events_expected.extend(next_events)

    # form_1 is still active, and bot will first validate if the user utterance
    #  provides valid data for the requested slot, which is rejected
    await processor._run_action(
        action_1,
        tracker,
        CollectingOutputChannel(),
        TemplatedNaturalLanguageGenerator(domain.templates),
        prediction,
    )
    events_expected.extend([ActionExecutionRejected(action_name=form_1)])
    assert tracker.applied_events() == events_expected

    # Next, bot predicts form_2
    action_2 = FormAction(form_2, None)
    await processor._run_action(
        action_2,
        tracker,
        CollectingOutputChannel(),
        TemplatedNaturalLanguageGenerator(domain.templates),
        prediction,
    )
    events_expected.extend([
        ActionExecuted(form_2),
        ActiveLoop(form_2),
        SlotSet(REQUESTED_SLOT, slot_a),
        BotUttered(
            text=utter_ask_form_2,
            metadata={"template_name": f"utter_ask_{form_2}_{slot_a}"},
        ),
    ])
    assert tracker.applied_events() == events_expected
async def test_logging_of_end_to_end_action():
    end_to_end_action = "hi, how are you?"
    domain = Domain(
        intents=["greet"],
        entities=[],
        slots=[],
        templates={},
        action_names=[],
        forms={},
        action_texts=[end_to_end_action],
    )

    conversation_id = "test_logging_of_end_to_end_action"
    user_message = "/greet"

    class ConstantEnsemble(PolicyEnsemble):
        def __init__(self) -> None:
            super().__init__([])
            self.number_of_calls = 0

        def probabilities_using_best_policy(
            self,
            tracker: DialogueStateTracker,
            domain: Domain,
            interpreter: NaturalLanguageInterpreter,
            **kwargs: Any,
        ) -> PolicyPrediction:
            if self.number_of_calls == 0:
                prediction = PolicyPrediction.for_action_name(
                    domain, end_to_end_action, "some policy"
                )
                prediction.is_end_to_end_prediction = True
                self.number_of_calls += 1
                return prediction
            else:
                return PolicyPrediction.for_action_name(domain, ACTION_LISTEN_NAME)

    tracker_store = InMemoryTrackerStore(domain)
    lock_store = InMemoryLockStore()
    processor = MessageProcessor(
        RegexInterpreter(),
        ConstantEnsemble(),
        domain,
        tracker_store,
        lock_store,
        NaturalLanguageGenerator.create(None, domain),
    )

    await processor.handle_message(UserMessage(user_message, sender_id=conversation_id))

    tracker = tracker_store.retrieve(conversation_id)
    expected_events = [
        ActionExecuted(ACTION_SESSION_START_NAME),
        SessionStarted(),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered(user_message, intent={"name": "greet"}),
        ActionExecuted(action_text=end_to_end_action),
        BotUttered("hi, how are you?", {}, {}, 123),
        ActionExecuted(ACTION_LISTEN_NAME),
    ]
    for event, expected in zip(tracker.events, expected_events):
        assert event == expected
Beispiel #10
0
async def test_restart_triggers_session_start(
    default_channel: CollectingOutputChannel,
    default_processor: MessageProcessor,
    monkeypatch: MonkeyPatch,
):
    # The rule policy is trained and used so as to allow the default action
    # ActionRestart to be predicted
    rule_policy = RulePolicy()
    rule_policy.train([], default_processor.domain, RegexInterpreter())
    monkeypatch.setattr(
        default_processor.policy_ensemble,
        "policies",
        [rule_policy, *default_processor.policy_ensemble.policies],
    )

    sender_id = uuid.uuid4().hex

    entity = "name"
    slot_1 = {entity: "name1"}
    await default_processor.handle_message(
        UserMessage(f"/greet{json.dumps(slot_1)}", default_channel, sender_id))

    assert default_channel.latest_output() == {
        "recipient_id": sender_id,
        "text": "hey there name1!",
    }

    # This restarts the chat
    await default_processor.handle_message(
        UserMessage("/restart", default_channel, sender_id))

    tracker = default_processor.tracker_store.get_or_create_tracker(sender_id)

    expected = [
        ActionExecuted(ACTION_SESSION_START_NAME),
        SessionStarted(),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered(
            f"/greet{json.dumps(slot_1)}",
            {
                INTENT_NAME_KEY: "greet",
                "confidence": 1.0
            },
            [{
                "entity": entity,
                "start": 6,
                "end": 23,
                "value": "name1"
            }],
        ),
        SlotSet(entity, slot_1[entity]),
        DefinePrevUserUtteredFeaturization(use_text_for_featurization=False),
        ActionExecuted("utter_greet"),
        BotUttered("hey there name1!",
                   metadata={"utter_action": "utter_greet"}),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered("/restart", {
            INTENT_NAME_KEY: "restart",
            "confidence": 1.0
        }),
        DefinePrevUserUtteredFeaturization(use_text_for_featurization=False),
        ActionExecuted(ACTION_RESTART_NAME),
        Restarted(),
        ActionExecuted(ACTION_SESSION_START_NAME),
        SessionStarted(),
        # No previous slot is set due to restart.
        ActionExecuted(ACTION_LISTEN_NAME),
    ]
    for actual, expected in zip(tracker.events, expected):
        assert actual == expected
Beispiel #11
0
                "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 test_event_has_proper_implementation(one_event, another_event):
    # equals tests
    assert (one_event != another_event
Beispiel #12
0
                "message_id":
                None,
                "metadata": {},
                "text":
                "Hi my name is Peter",
            },
            text="Hi my name is Peter",
            timestamp=1551953035.076376,
        ),
        SlotSet(key="name", timestamp=1551953035.076385, value="Peter"),
        ActionExecuted(action_name="utter_greet", timestamp=1551953040.607782),
        BotUttered(
            data={
                "attachment": None,
                "buttons": None,
                "elements": None
            },
            text="hey there Peter!",
            timestamp=1551953040.60779,
        ),
    ],
)
TEST_FORMBOT_DIALOGUE = Dialogue(
    name="formbot",
    events=[
        ActionExecuted(action_name="action_listen",
                       timestamp=1551884035.892855),
        UserUttered(
            intent={
                "confidence": 0.3748943507671356,
                "name": "greet"
Beispiel #13
0
async def test_remote_action_logs_events(
    default_channel: OutputChannel,
    default_nlg: NaturalLanguageGenerator,
    default_tracker: DialogueStateTracker,
    domain: Domain,
):
    endpoint = EndpointConfig("https://example.com/webhooks/actions")
    remote_action = action.RemoteAction("my_action", endpoint)

    response = {
        "events": [{
            "event": "slot",
            "value": "rasa",
            "name": "name"
        }],
        "responses": [
            {
                "text": "test text",
                "response": None,
                "buttons": [{
                    "title": "cheap",
                    "payload": "cheap"
                }],
            },
            {
                "response": "utter_greet"
            },
        ],
    }

    with aioresponses() as mocked:
        mocked.post("https://example.com/webhooks/actions", payload=response)

        events = await remote_action.run(default_channel, default_nlg,
                                         default_tracker, domain)

        r = latest_request(mocked, "post",
                           "https://example.com/webhooks/actions")
        assert r

        assert json_of_latest_request(r) == {
            "domain": domain.as_dict(),
            "next_action": "my_action",
            "sender_id": "my-sender",
            "version": rasa.__version__,
            "tracker": {
                "latest_message": {
                    "entities": [],
                    "intent": {},
                    "text": None,
                    "message_id": None,
                    "metadata": {},
                },
                ACTIVE_LOOP: {},
                "latest_action": {},
                "latest_action_name": None,
                "sender_id": "my-sender",
                "paused": False,
                FOLLOWUP_ACTION: ACTION_LISTEN_NAME,
                "latest_event_time": None,
                "slots": {
                    "name": None,
                    REQUESTED_SLOT: None,
                    SESSION_START_METADATA_SLOT: None,
                },
                "events": [],
                "latest_input_channel": None,
            },
        }
    assert len(events) == 3  # first two events are bot utterances
    assert events[0] == BotUttered(
        "test text", {"buttons": [{
            "title": "cheap",
            "payload": "cheap"
        }]})
    assert events[1] == BotUttered("hey there None!",
                                   metadata={"utter_action": "utter_greet"})
    assert events[2] == SlotSet("name", "rasa")
Beispiel #14
0
 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={
         "intent": {
Beispiel #15
0
def test_json_parse_bot():
    evt = {"event": "bot", "text": "Hey there!", "data": {}}
    assert Event.from_parameters(evt) == BotUttered("Hey there!", {})
Beispiel #16
0
async def test_remote_action_logs_events(default_channel, default_nlg,
                                         default_tracker, default_domain):
    endpoint = EndpointConfig("https://example.com/webhooks/actions")
    remote_action = action.RemoteAction("my_action", endpoint)

    response = {
        "events": [{
            "event": "slot",
            "value": "rasa",
            "name": "name"
        }],
        "responses": [
            {
                "text": "test text",
                "template": None,
                "buttons": [{
                    "title": "cheap",
                    "payload": "cheap"
                }],
            },
            {
                "template": "utter_greet"
            },
        ],
    }

    with aioresponses() as mocked:
        mocked.post("https://example.com/webhooks/actions", payload=response)

        events = await remote_action.run(default_channel, default_nlg,
                                         default_tracker, default_domain)

        r = latest_request(mocked, "post",
                           "https://example.com/webhooks/actions")
        assert r

        assert json_of_latest_request(r) == {
            "domain": default_domain.as_dict(),
            "next_action": "my_action",
            "sender_id": "my-sender",
            "version": rasa.__version__,
            "tracker": {
                "latest_message": {
                    "entities": [],
                    "intent": {},
                    "text": None,
                    "message_id": None,
                    "metadata": {},
                },
                ACTIVE_LOOP: {},
                "latest_action": {},
                "latest_action_name": None,
                "sender_id": "my-sender",
                "paused": False,
                "followup_action": "action_listen",
                "latest_event_time": None,
                "slots": {
                    "name": None
                },
                "events": [],
                "latest_input_channel": None,
            },
        }

    assert len(events) == 3  # first two events are bot utterances
    assert events[0] == BotUttered(
        "test text", {"buttons": [{
            "title": "cheap",
            "payload": "cheap"
        }]})
    assert events[1] == BotUttered("hey there None!",
                                   metadata={"template_name": "utter_greet"})
    assert events[2] == SlotSet("name", "rasa")
Beispiel #17
0
        events = await action.run(
            CollectingOutputChannel(),
            TemplatedNaturalLanguageGenerator(domain.templates),
            tracker,
            domain,
        )
        assert events == expected_events


@pytest.mark.parametrize(
    "custom_events",
    [
        # Custom action returned no events
        [],
        # Custom action returned events but no `SlotSet` events
        [BotUttered("some text").as_dict()],
        # Custom action returned only `SlotSet` event for `required_slot`
        [SlotSet(REQUESTED_SLOT, "some value").as_dict()],
    ],
)
async def test_no_slots_extracted_with_custom_slot_mappings(
        custom_events: List[Event]):
    form_name = "my form"
    events = [
        ActiveLoop(form_name),
        SlotSet(REQUESTED_SLOT, "num_tables"),
        ActionExecuted(ACTION_LISTEN_NAME),
        UserUttered("off topic"),
    ]
    tracker = DialogueStateTracker.from_events(sender_id="bla", evts=events)