Example #1
0
    async def run(self, output_channel, nlg, tracker, domain) -> List[Event]:
        json_body = self._action_call_format(tracker, domain)

        if not self.action_endpoint:
            logger.error("The model predicted the custom action '{}', "
                         "but you didn't configure an endpoint to "
                         "run this custom action. Please take a look at "
                         "the docs and set an endpoint configuration via the "
                         "--endpoints flag. "
                         "{}/core/actions"
                         "".format(self.name(), DOCS_BASE_URL))
            raise Exception("Failed to execute custom action.")

        try:
            logger.debug("Calling action endpoint to run action '{}'.".format(
                self.name()))
            response = await self.action_endpoint.request(
                json=json_body, method="post", timeout=DEFAULT_REQUEST_TIMEOUT)

            self._validate_action_result(response)

            events_json = response.get("events", [])
            responses = response.get("responses", [])
            bot_messages = await self._utter_responses(responses,
                                                       output_channel, nlg,
                                                       tracker)

            evts = events.deserialise_events(events_json)
            return bot_messages + evts

        except ClientResponseError as e:
            if e.status == 400:
                response_data = json.loads(e.text)
                exception = ActionExecutionRejection(
                    response_data["action_name"], response_data.get("error"))
                logger.error(exception.message)
                raise exception
            else:
                raise Exception("Failed to execute custom action.") from e

        except aiohttp.ClientConnectionError as e:
            logger.error("Failed to run custom action '{}'. Couldn't connect "
                         "to the server at '{}'. Is the server running? "
                         "Error: {}".format(self.name(),
                                            self.action_endpoint.url, e))
            raise Exception("Failed to execute custom action.")

        except aiohttp.ClientError as e:
            # not all errors have a status attribute, but
            # helpful to log if they got it

            # noinspection PyUnresolvedReferences
            status = getattr(e, "status", None)
            logger.error("Failed to run custom action '{}'. Action server "
                         "responded with a non 200 status code of {}. "
                         "Make sure your action server properly runs actions "
                         "and returns a 200 once the action is executed. "
                         "Error: {}".format(self.name(), status, e))
            raise Exception("Failed to execute custom action.")
    async def get_conversation_tracker_impl(request: Request,
                                            conversation_id: Text,
                                            user: Dict[Text, Any] = None):
        event_service = _event_service(request)

        if not _has_access_to_conversation(event_service, conversation_id,
                                           user):
            return rasa_x_utils.error(HTTPStatus.UNAUTHORIZED, "NoPermission",
                                      "Access denied")

        until_time = rasa_x_utils.float_arg(request, "until", None)
        since_time = rasa_x_utils.float_arg(request, "since", None)
        rasa_environment_query = rasa_x_utils.default_arg(
            request, "rasa_environment", DEFAULT_RASA_ENVIRONMENT)
        event_verbosity = _event_verbosity_from_request(request)
        exclude_leading_action_session_start = rasa_x_utils.bool_arg(
            request, "exclude_leading_action_session_start", False)

        tracker = event_service.get_tracker_with_message_flags(
            conversation_id,
            until_time,
            since_time,
            event_verbosity,
            rasa_environment_query,
            exclude_leading_action_session_start,
        )

        if not tracker:
            return rasa_x_utils.error(
                HTTPStatus.NOT_FOUND,
                "ClientNotFound",
                f"Client for conversation_id '{conversation_id}' could not be found",
            )

        requested_format = request.headers.get("Accept")

        if requested_format == "application/json":
            dispo = f"attachment;filename={conversation_id}-dump.json"
            return response.json(
                tracker,
                content_type="application/json",
                headers={"Content-Disposition": dispo},
            )
        elif requested_format == "text/markdown":
            _events = events.deserialise_events(tracker["events"])
            story = Story.from_events(_events)
            exported = story.as_story_string(flat=True)
            return response.text(
                exported,
                content_type="text/markdown",
                headers={
                    "Content-Disposition":
                    f"attachment;filename={conversation_id}-story.md"
                },
            )
        else:
            return response.json(tracker,
                                 headers={"Content-Disposition": "inline"})
Example #3
0
async def _write_stories_to_file(export_story_path: Text,
                                 evts: List[Dict[Text, Any]]) -> None:
    """Write the conversation of the sender_id to the file paths."""

    sub_conversations = _split_conversation_at_restarts(evts)

    with open(export_story_path, "a", encoding="utf-8") as f:
        for conversation in sub_conversations:
            parsed_events = events.deserialise_events(conversation)
            s = Story.from_events(parsed_events)
            f.write(s.as_story_string(flat=True) + "\n")
Example #4
0
    def from_dict(cls,
                  sender_id: Text,
                  events_as_dict: List[Dict[Text, Any]],
                  slots: List[Slot],
                  max_event_history: Optional[int] = None
                  ) -> 'DialogueStateTracker':
        """Create a tracker from dump.

        The dump should be an array of dumped events. When restoring
        the tracker, these events will be replayed to recreate the state."""

        evts = events.deserialise_events(events_as_dict)
        return cls.from_events(sender_id, evts, slots, max_event_history)
Example #5
0
def test_put_tracker(app):
    data = json.dumps([event.as_dict() for event in test_events])
    _, response = app.put("/conversations/pushtracker/tracker/events",
                          data=data,
                          headers={"Content-Type": "application/json"})
    content = response.json
    assert response.status == 200
    assert len(content["events"]) == len(test_events)
    assert content["sender_id"] == "pushtracker"

    _, tracker_response = app.get("/conversations/pushtracker/tracker")
    tracker = tracker_response.json
    assert tracker is not None
    evts = tracker.get("events")
    assert events.deserialise_events(evts) == test_events
Example #6
0
async def _fetch_events(sender_ids: List[Union[Text, List[Event]]],
                        endpoint: EndpointConfig) -> List[List[Event]]:
    """Retrieve all event trackers from the endpoint for all sender ids."""

    event_sequences = []
    for sender_id in sender_ids:
        if isinstance(sender_id, str):
            tracker = await retrieve_tracker(endpoint, sender_id)
            evts = tracker.get("events", [])

            for conversation in _split_conversation_at_restarts(evts):
                parsed_events = events.deserialise_events(conversation)
                event_sequences.append(parsed_events)
        else:
            event_sequences.append(sender_id)
    return event_sequences
Example #7
0
def test_put_tracker(rasa_app: SanicTestClient):
    data = [event.as_dict() for event in test_events]
    _, response = rasa_app.put(
        "/conversations/pushtracker/tracker/events",
        json=data,
        headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE},
    )
    content = response.json
    assert response.status == 200
    assert len(content["events"]) == len(test_events)
    assert content["sender_id"] == "pushtracker"

    _, tracker_response = rasa_app.get("/conversations/pushtracker/tracker")
    tracker = tracker_response.json
    assert tracker is not None
    evts = tracker.get("events")
    assert events.deserialise_events(evts) == test_events
Example #8
0
async def _write_stories_to_file(
    export_story_path: Text, evts: List[Dict[Text, Any]]
) -> None:
    """Write the conversation of the sender_id to the file paths."""

    sub_conversations = _split_conversation_at_restarts(evts)

    create_path(export_story_path)

    if os.path.exists(export_story_path):
        append_write = "a"  # append if already exists
    else:
        append_write = "w"  # make a new file if not

    with open(export_story_path, append_write, encoding="utf-8") as f:
        for conversation in sub_conversations:
            parsed_events = events.deserialise_events(conversation)
            s = Story.from_events(parsed_events)
            f.write("\n" + s.as_story_string(flat=True))
Example #9
0
    def execute(self, action_name, text, get_tracker=False):
        """
        $ python -m sagas.bots.action_runner execute action_about_date '找音乐会'
        $ python -m sagas.bots.action_runner execute action_about_date '找音乐会' True
        $ python -m sagas.bots.action_runner execute action_joke '找音乐会'
        :param action_name:
        :param text:
        :return:
        """
        # tracker = DialogueStateTracker("default", domain.slots)
        tracker = self.prepare(text)

        dispatcher = CollectingDispatcher()
        action = self.executor.actions.get(action_name)
        events = action(dispatcher, tracker, self.domain)
        resp = self.create_api_response(events, dispatcher.messages)
        if get_tracker:
            evs = deserialise_events(events)
            for ev in evs:
                tracker.update(ev)
            return resp, tracker
        else:
            return resp