Example #1
0
async def test_pushing_event(rasa_app: SanicASGITestClient, event: Event):
    sender_id = str(uuid.uuid1())
    conversation = f"/conversations/{sender_id}"

    serialized_event = event.as_dict()
    # Remove timestamp so that a new one is assigned on the server
    serialized_event.pop("timestamp")

    time_before_adding_events = time.time()
    _, response = await rasa_app.post(
        f"{conversation}/tracker/events",
        json=serialized_event,
        headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE},
    )
    assert response.json() is not None
    assert response.status == 200

    _, tracker_response = await rasa_app.get(f"/conversations/{sender_id}/tracker")
    tracker = tracker_response.json()
    assert tracker is not None

    assert len(tracker.get("events")) == 4

    deserialized_events = [Event.from_parameters(event) for event in tracker["events"]]

    # there is an initial session start sequence at the beginning of the tracker
    assert deserialized_events[:3] == session_start_sequence

    assert deserialized_events[3] == event
    assert deserialized_events[3].timestamp > time_before_adding_events
Example #2
0
def test_pushing_event(rasa_app: SanicTestClient, event: Event):
    sender_id = str(uuid.uuid1())
    conversation = f"/conversations/{sender_id}"

    serialized_event = event.as_dict()
    # Remove timestamp so that a new one is assigned on the server
    serialized_event.pop("timestamp")

    time_before_adding_events = time.time()
    _, response = rasa_app.post(
        f"{conversation}/tracker/events",
        json=serialized_event,
        headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE},
    )
    assert response.json is not None
    assert response.status == 200

    _, tracker_response = rasa_app.get(f"/conversations/{sender_id}/tracker")
    tracker = tracker_response.json
    assert tracker is not None

    assert len(tracker.get("events")) == 1

    evt = tracker.get("events")[0]
    deserialised_event = Event.from_parameters(evt)
    assert deserialised_event == event
    assert deserialised_event.timestamp > time_before_adding_events
Example #3
0
    def update(self, event: Event, domain: Optional[Domain] = None) -> None:
        """Modify the state of the tracker according to an ``Event``."""
        if not isinstance(event, Event):  # pragma: no cover
            raise ValueError("event to log must be an instance of a subclass of Event.")

        if self.model_id and METADATA_MODEL_ID not in event.metadata:
            event.metadata = {**event.metadata, METADATA_MODEL_ID: self.model_id}

        self.events.append(event)
        event.apply_to(self)
Example #4
0
    def update(self, event: Event, domain: Optional[Domain] = None) -> None:
        """Modify the state of the tracker according to an ``Event``. """
        if not isinstance(event, Event):  # pragma: no cover
            raise ValueError("event to log must be an instance of a subclass of Event.")

        self.events.append(event)
        event.apply_to(self)

        if domain and isinstance(event, UserUttered):
            # store all entities as slots
            for e in domain.slots_for_entities(event.parse_data["entities"]):
                self.update(e)
Example #5
0
def test_json_parse_user():
    evt = {
        "event": "user",
        "text": "Hey",
        "parse_data": {
            "intent": {
                "name": "greet",
                "confidence": 0.9
            },
            "entities": []
        },
        "metadata": {},
    }
    assert Event.from_parameters(evt) == UserUttered(
        "Hey",
        intent={
            "name": "greet",
            "confidence": 0.9
        },
        entities=[],
        parse_data={
            "intent": {
                "name": "greet",
                "confidence": 0.9
            },
            "entities": []
        },
        metadata={},
    )
Example #6
0
    def _add_event(self, event_name: Text, parameters: Dict[Text, Any]) -> None:
        # add 'name' only if event is not a SlotSet,
        # because there might be a slot with slot_key='name'
        if "name" not in parameters and event_name != SlotSet.type_name:
            parameters["name"] = event_name

        parsed_events = Event.from_story_string(
            event_name, parameters, default=ActionExecuted
        )
        if parsed_events is None:
            raise StoryParseError(
                "Unknown event '{}'. It is Neither an event "
                "nor an action).".format(event_name)
            )
        if self.current_step_builder is None:
            raise StoryParseError(
                "Failed to handle event '{}'. There is no "
                "started story block available. "
                "".format(event_name)
            )

        for p in parsed_events:
            _map_legacy_event_names(p)
            if self._is_parsing_conditions:
                self.current_step_builder.add_event_as_condition(p)
            else:
                self.current_step_builder.add_event(p)
Example #7
0
def test_bot_output_format():
    message = {
        "event": "bot",
        "text": "Hello!",
        "data": {
            "image": "http://example.com/myimage.png",
            "attachment": "My Attachment",
            "buttons": [
                {"title": "yes", "payload": "/yes"},
                {"title": "no", "payload": "/no", "extra": "extra"},
            ],
            "elements": [
                {
                    "title": "element1",
                    "buttons": [{"title": "button1", "payload": "/button1"}],
                },
                {
                    "title": "element2",
                    "buttons": [{"title": "button2", "payload": "/button2"}],
                },
            ],
            "quick_replies": [
                {
                    "title": "quick_reply1",
                    "buttons": [{"title": "button3", "payload": "/button3"}],
                },
                {
                    "title": "quick_reply2",
                    "buttons": [{"title": "button4", "payload": "/button4"}],
                },
            ],
        },
    }
    from rasa.shared.core.events import Event

    bot_event = Event.from_parameters(message)

    assert isinstance(bot_event, BotUttered)

    formatted = interactive.format_bot_output(bot_event)
    assert formatted == (
        "Hello!\n"
        "Image: http://example.com/myimage.png\n"
        "Attachment: My Attachment\n"
        "Buttons:\n"
        "1: yes (/yes)\n"
        '2: no (/no) - {"extra": "extra"}\n'
        "Type out your own message...\n"
        "Elements:\n"
        '1: element1 - {"buttons": '
        '[{"payload": "/button1", "title": "button1"}]'
        '}\n2: element2 - {"buttons": '
        '[{"payload": "/button2", "title": "button2"}]'
        "}\nQuick replies:\n"
        '1: quick_reply1 - {"buttons": '
        '[{"payload": "/button3", "title": "button3"}'
        ']}\n2: quick_reply2 - {"buttons": '
        '[{"payload": "/button4", "title": "button4"}'
        "]}"
    )
Example #8
0
async def test_post_conversation_id_with_slash(rasa_app: SanicASGITestClient):
    conversation_id = str(uuid.uuid1())
    id_len = len(conversation_id) // 2
    conversation_id = conversation_id[:id_len] + "/+-_\\=" + conversation_id[id_len:]
    conversation = f"/conversations/{conversation_id}"

    events = [e.as_dict() for e in test_events]
    _, response = await rasa_app.post(
        f"{conversation}/tracker/events",
        json=events,
        headers={"Content-Type": "application/json"},
    )
    assert response.json() is not None
    assert response.status == 200

    _, tracker_response = await rasa_app.get(
        f"/conversations/{conversation_id}/tracker"
    )
    tracker = tracker_response.json()
    assert tracker is not None

    # there is a session start sequence at the start
    assert [
        Event.from_parameters(event) for event in tracker.get("events")
    ] == session_start_sequence + test_events
Example #9
0
def test_event_fingerprint_consistency(event: Event):
    f1 = event.fingerprint()

    event2 = copy.deepcopy(event)
    f2 = event2.fingerprint()

    assert f1 == f2
Example #10
0
def _map_legacy_event_names(event: Event) -> None:
    if (isinstance(event, ActionExecuted)
            and event.action_name == LEGACY_ACTION_DEACTIVATE_LOOP_NAME):
        rasa.shared.utils.io.raise_deprecation_warning(
            f"Using action '{event.action_name}' is deprecated. Please use "
            f"'{ACTION_DEACTIVATE_LOOP_NAME}' instead. Support for "
            f"'{event.action_name}' will be removed in Rasa Open Source version "
            f"{NEXT_MAJOR_VERSION_FOR_DEPRECATIONS}.")
        event.action_name = ACTION_DEACTIVATE_LOOP_NAME
Example #11
0
    def update(self, event: Event, domain: Optional[Domain] = None) -> None:
        """Modify the state of the tracker according to an ``Event``. """
        if not isinstance(event, Event):  # pragma: no cover
            raise ValueError("event to log must be an instance of a subclass of Event.")

        self.events.append(event)
        event.apply_to(self)

        if domain and isinstance(event, (UserUttered, EntitiesAdded)):
            if isinstance(event, UserUttered):
                # Rather get entities from `parse_data` as
                # `DefinePrevUserUtteredEntities` might have already affected the
                # `UserUttered.entities` attribute (this might e.g. happen when the
                # `InMemoryTrackerStore` is used).
                entities = event.parse_data[ENTITIES]
            else:
                entities = event.entities

            for e in domain.slots_for_entities(entities):
                self.update(e)
Example #12
0
def test_json_parse_action_executed_with_no_hide_rule():
    evt = {
        "event": "action",
        "name": "action_listen",
        "policy": None,
        "confidence": None,
        "timestamp": None,
    }
    deserialised: ActionExecuted = Event.from_parameters(evt)
    expected = ActionExecuted("action_listen", )
    assert deserialised == expected
    assert deserialised.hide_rule_turn == expected.hide_rule_turn
Example #13
0
def test_event_metadata_dict(event_class: Type[Event]):
    metadata = {"foo": "bar", "quux": 42}

    # Create the event from a `dict` that will be accepted by the
    # `_from_parameters` method of any `Event` subclass (the values themselves
    # are not important).
    event = Event.from_parameters({
        "metadata": metadata,
        "event": event_class.type_name,
        "parse_data": {},
        "date_time": "2019-11-20T16:09:16Z",
    })
    assert event.as_dict()["metadata"] == metadata
Example #14
0
def test_event_default_metadata(event_class: Type[Event]):
    # Create an event without metadata. When converting the `Event` to a
    # `dict`, it should not include a `metadata` property - unless it's a
    # `UserUttered` or a `BotUttered` event (or subclasses of them), in which
    # case the metadata should be included with a default value of {}.
    event = Event.from_parameters({
        "event": event_class.type_name,
        "parse_data": {},
        "date_time": "2019-11-20T16:09:16Z",
    })

    if isinstance(event, BotUttered) or isinstance(event, UserUttered):
        assert event.as_dict()["metadata"] == {}
    else:
        assert "metadata" not in event.as_dict()
Example #15
0
    def from_parameters(cls, parameters: Dict[Text, Any]) -> "Dialogue":
        """Create `Dialogue` from parameters.

        Args:
            parameters: Serialised dialogue, should contain keys 'name' and 'events'.

        Returns:
            Deserialised `Dialogue`.

        """

        return cls(
            parameters.get("name"),
            [Event.from_parameters(evt) for evt in parameters.get("events")],
        )
Example #16
0
    def _parse_events(self, event_name: Text,
                      parameters: Dict[Text, Any]) -> Optional[List["Event"]]:
        # add 'name' only if event is not a SlotSet,
        # because there might be a slot with slot_key='name'
        if "name" not in parameters and event_name != SlotSet.type_name:
            parameters["name"] = event_name

        parsed_events = Event.from_story_string(event_name,
                                                parameters,
                                                default=ActionExecuted)
        if parsed_events is None:
            raise StoryParseError("Unknown event '{}'. It is Neither an event "
                                  "nor an action).".format(event_name))

        return parsed_events
Example #17
0
def test_json_parse_reminder():
    evt = {
        "event": "reminder",
        "intent": "my_intent",
        "entities": {"entity1": "value1", "entity2": "value2"},
        "date_time": "2018-09-03T11:41:10.128172",
        "name": "my_reminder",
        "kill_on_user_msg": True,
    }
    assert Event.from_parameters(evt) == ReminderScheduled(
        "my_intent",
        parser.parse("2018-09-03T11:41:10.128172"),
        name="my_reminder",
        kill_on_user_message=True,
    )
Example #18
0
async def test_file_broker_logs_to_file(tmp_path: Path):
    log_file_path = str(tmp_path / "events.log")

    actual = await EventBroker.create(
        EndpointConfig(**{"type": "file", "path": log_file_path})
    )

    for e in TEST_EVENTS:
        actual.publish(e.as_dict())

    # reading the events from the file one event per line
    recovered = []
    with open(log_file_path, "r") as log_file:
        for line in log_file:
            recovered.append(Event.from_parameters(json.loads(line)))

    assert recovered == TEST_EVENTS
Example #19
0
async def test_remote_action_valid_payload_all_events(
    default_channel: OutputChannel,
    default_nlg: NaturalLanguageGenerator,
    default_tracker: DialogueStateTracker,
    domain: Domain,
    event: Event,
):
    endpoint = EndpointConfig("https://example.com/webhooks/actions")
    remote_action = action.RemoteAction("my_action", endpoint)
    events = [event.as_dict()]
    response = {"events": events, "responses": []}
    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)

    assert len(events) == 1
Example #20
0
async def test_file_broker_properly_logs_newlines(tmp_path: Path):
    log_file_path = str(tmp_path / "events.log")

    actual = await EventBroker.create(
        EndpointConfig(**{"type": "file", "path": log_file_path})
    )

    event_with_newline = UserUttered("hello \n there")

    actual.publish(event_with_newline.as_dict())

    # reading the events from the file one event per line
    recovered = []
    with open(log_file_path, "r") as log_file:
        for line in log_file:
            recovered.append(Event.from_parameters(json.loads(line)))

    assert recovered == [event_with_newline]
Example #21
0
def test_event_metadata_dict(event_class: Type[Event]):
    metadata = {"foo": "bar", "quux": 42}
    parameters = {
        "metadata": metadata,
        "event": event_class.type_name,
        "parse_data": {},
        "date_time": "2019-11-20T16:09:16Z",
    }
    # `ActionExecuted` class and its subclasses require either that action_name
    # is not None if it is not an end-to-end predicted action
    if event_class.type_name in ["action", "wrong_action", "warning_predicted"]:
        parameters["name"] = "test"

    # Create the event from a `dict` that will be accepted by the
    # `_from_parameters` method of any `Event` subclass (the values themselves
    # are not important).
    event = Event.from_parameters(parameters)
    assert event.as_dict()["metadata"] == metadata
Example #22
0
def test_json_parse_reminder_cancelled():
    evt = {
        "event": "cancel_reminder",
        "name": "my_reminder",
        "intent": "my_intent",
        "entities": [
            {"entity": "entity1", "value": "value1"},
            {"entity": "entity2", "value": "value2"},
        ],
        "date_time": "2018-09-03T11:41:10.128172",
    }
    assert Event.from_parameters(evt) == ReminderCancelled(
        name="my_reminder",
        intent="my_intent",
        entities=[
            {"entity": "entity1", "value": "value1"},
            {"entity": "entity2", "value": "value2"},
        ],
        timestamp=parser.parse("2018-09-03T11:41:10.128172"),
    )
Example #23
0
def test_event_default_metadata(event_class: Type[Event]):
    parameters = {
        "event": event_class.type_name,
        "parse_data": {},
        "date_time": "2019-11-20T16:09:16Z",
    }
    # `ActionExecuted` class and its subclasses require either that action_name
    # is not None if it is not an end-to-end predicted action
    if event_class.type_name in ["action", "wrong_action", "warning_predicted"]:
        parameters["name"] = "test"

    # Create an event without metadata. When converting the `Event` to a
    # `dict`, it should not include a `metadata` property - unless it's a
    # `UserUttered` or a `BotUttered` event (or subclasses of them), in which
    # case the metadata should be included with a default value of {}.
    event = Event.from_parameters(parameters)

    if isinstance(event, BotUttered) or isinstance(event, UserUttered):
        assert event.as_dict()["metadata"] == {}
    else:
        assert "metadata" not in event.as_dict()
Example #24
0
    def _get_events_from_request_body(request: Request) -> List[Event]:
        events = request.json

        if not isinstance(events, list):
            events = [events]

        events = [Event.from_parameters(event) for event in events]
        events = [event for event in events if event]

        if not events:
            rasa.shared.utils.io.raise_warning(
                f"Append event called, but could not extract a valid event. "
                f"Request JSON: {request.json}"
            )
            raise ErrorResponse(
                400,
                "BadRequest",
                "Couldn't extract a proper event from the request body.",
                {"parameter": "", "in": "body"},
            )

        return events
Example #25
0
async def test_push_multiple_events(rasa_app: SanicASGITestClient):
    conversation_id = str(uuid.uuid1())
    conversation = f"/conversations/{conversation_id}"

    events = [e.as_dict() for e in test_events]
    _, response = await rasa_app.post(
        f"{conversation}/tracker/events",
        json=events,
        headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE},
    )
    assert response.json() is not None
    assert response.status == 200

    _, tracker_response = await rasa_app.get(
        f"/conversations/{conversation_id}/tracker"
    )
    tracker = tracker_response.json()
    assert tracker is not None

    # there is an initial session start sequence at the beginning
    assert [
        Event.from_parameters(event) for event in tracker.get("events")
    ] == session_start_sequence + test_events
Example #26
0
def test_print_end_to_end_events_in_markdown(end_to_end_event: Event):
    with pytest.raises(UnsupportedFeatureException):
        end_to_end_event.as_story_string()
Example #27
0
def test_json_parse_agent():
    evt = {"event": "agent", "text": "Hey, how are you?"}
    assert Event.from_parameters(evt) == AgentUttered("Hey, how are you?")
Example #28
0
def test_json_parse_action():
    evt = {"event": "action", "name": "my_action"}
    assert Event.from_parameters(evt) == ActionExecuted("my_action")
Example #29
0
def test_json_parse_resume():
    evt = {"event": "resume"}
    assert Event.from_parameters(evt) == ConversationResumed()
Example #30
0
def test_json_parse_pause():
    evt = {"event": "pause"}
    assert Event.from_parameters(evt) == ConversationPaused()