From 2d6d356f6c45c4f3aa20ce1fda72ae2984dbb2bb Mon Sep 17 00:00:00 2001 From: David Arias <35249025+nomadavid9@users.noreply.github.com> Date: Thu, 13 Dec 2018 16:42:00 -0800 Subject: [PATCH 01/57] update connectors.rst Updated connectors file to reflect the correct way to pass in slack channel. "#my_channel" or "@my_app" > "@my_channel" --- docs/connectors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connectors.rst b/docs/connectors.rst index 436288da50c..0c195989f22 100644 --- a/docs/connectors.rst +++ b/docs/connectors.rst @@ -234,7 +234,7 @@ you need to supply a ``credentials.yml`` with the following content: slack: slack_token: "xoxb-286425452756-safjasdf7sl38KLls" - slack_channel: "@my_channel" + slack_channel: "#my_channel" or "@my_app" The endpoint for receiving slack messages is From adf632a289951b17b7461c88acd5d5e540d1c1d5 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Tue, 5 Feb 2019 11:54:38 +0100 Subject: [PATCH 02/57] update copyright to 2019 --- LICENSE.txt | 2 +- README.md | 2 +- docs/conf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 142b2e361e7..4efaf6a7696 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Rasa Technologies GmbH + Copyright 2019 Rasa Technologies GmbH Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3785b907388..5a341f83df3 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ and apply your changes. ## License Licensed under the Apache License, Version 2.0. -Copyright 2018 Rasa Technologies GmbH. [Copy of the license](LICENSE.txt). +Copyright 2019 Rasa Technologies GmbH. [Copy of the license](LICENSE.txt). A list of the Licenses of the dependencies of the project can be found at the bottom of the diff --git a/docs/conf.py b/docs/conf.py index 51acb41da7d..e71e9ac8778 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -76,7 +76,7 @@ # General information about the project. project = u'Rasa Core' -copyright = u'2018, Rasa Technologies GmbH' +copyright = u'2019, Rasa Technologies GmbH' author = u'Rasa Technologies GmbH' # The version info for the project you're documenting, acts as replacement for From d1a5eadca2cbf7b55a7bb24bd16e64fb9bf98288 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Feb 2019 11:54:39 +0100 Subject: [PATCH 03/57] properly encode table before printing it --- rasa_core/training/interactive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index a65092e76d4..db7273ef619 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -448,7 +448,7 @@ def _print_history(sender_id: Text, endpoint: EndpointConfig) -> None: print("------") print("Chat History\n") - print(table) + print(table.encode("utf-8")) if slot_strs: print("\n") From 390f67ca91a8db61ecd030462c1406c439e0d0a2 Mon Sep 17 00:00:00 2001 From: Alexander Raginsky Date: Thu, 7 Feb 2019 23:58:03 +0300 Subject: [PATCH 04/57] Fixing exception when migrating tracker from 0.11 to 0.12/0.13 version --- rasa_core/events/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rasa_core/events/__init__.py b/rasa_core/events/__init__.py index f6976e93cac..f886ac185e4 100644 --- a/rasa_core/events/__init__.py +++ b/rasa_core/events/__init__.py @@ -232,7 +232,7 @@ def as_dict(self): d.update({ "text": self.text, "parse_data": self.parse_data, - "input_channel": self.input_channel + "input_channel": self.input_channel if hasattr(self, "input_channel") else None }) return d @@ -761,8 +761,8 @@ def as_dict(self): d = super(ActionExecuted, self).as_dict() d.update({ "name": self.action_name, - "policy": self.policy, - "confidence": self.confidence + "policy": self.policy if hasattr(self,"policy") else None, + "confidence": self.confidence if hasattr(self,"confidence") else None }) return d From 987e8a838c0dbcd2a1affa57c38345c520eb6a71 Mon Sep 17 00:00:00 2001 From: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> Date: Mon, 11 Feb 2019 11:28:02 +0000 Subject: [PATCH 05/57] slack.py @akelad. I fixed the incorrect object dereference in the slack events. Please consider pulling so @DPMS (https://forum.rasa.com/t/slack-buttons-fail-silently/4318/12) gets to use it in a docker instance. --- rasa_core/channels/slack.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 958b26bdb49..33c6713f980 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -28,6 +28,7 @@ def __init__(self, def send_text_message(self, recipient_id, message): recipient = self.slack_channel or recipient_id + print("slack.py send_text_message ::",message) for message_part in message.split("\n\n"): super(SlackBot, self).api_call("chat.postMessage", channel=recipient, @@ -37,6 +38,7 @@ def send_image_url(self, recipient_id, image_url, message=""): image_attachment = [{"image_url": image_url, "text": message}] recipient = self.slack_channel or recipient_id + print("slack.py send_image_url ::",message) return super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -44,6 +46,7 @@ def send_image_url(self, recipient_id, image_url, message=""): def send_attachment(self, recipient_id, attachment, message=""): recipient = self.slack_channel or recipient_id + print("slack.py send_attachment ::",message) return super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -54,6 +57,7 @@ def send_attachment(self, recipient_id, attachment, message=""): def _convert_to_slack_buttons(buttons): return [{"text": b['title'], "name": b['payload'], + "value": b['payload'], "type": "button"} for b in buttons] def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): @@ -68,7 +72,7 @@ def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): "callback_id": message.replace(' ', '_')[:20], "actions": self._convert_to_slack_buttons( buttons)}] - + print("slack.py send_button ::",button_attachment) super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -129,13 +133,19 @@ def _is_user_message(slack_event): @staticmethod def _is_button_reply(slack_event): - return (slack_event.get('payload') and - slack_event['payload'][0] and - 'name' in slack_event['payload'][0]) + pay = json.loads(slack_event['payload']); + evaluation = (pay['type'] == u"interactive_message") and (pay['actions'][0]['type'] == u"button"); + ## print("Is it a button ? ",evaluation); + return( evaluation ); + ## return (slack_event.get('payload') and + ## slack_event['payload'][0] and + ## 'name' in slack_event['payload'][0]) @staticmethod def _get_button_reply(slack_event): - return json.loads(slack_event['payload'][0])['actions'][0]['name'] + return json.loads(slack_event['payload'])['actions'][0]['name'] + ## return json.loads(slack_event['payload'][0])['actions'][0]['name'] + @staticmethod def _sanitize_user_message(text, uids_to_remove): @@ -172,16 +182,20 @@ def process_message(self, on_new_message, text, sender_id): """ retry_reason = request.headers.environ.get('HTTP_X_SLACK_RETRY_REASON') retry_count = request.headers.environ.get('HTTP_X_SLACK_RETRY_NUM') - if retry_count and retry_reason in self.errors_ignore_retry: + ## if retry_count and retry_reason in self.errors_ignore_retry: + if retry_count: logger.warning("Received retry #{} request from slack" " due to {}".format(retry_count, retry_reason)) return Response(status=201, headers={'X-Slack-No-Retry': 1}) try: + ## print("slack.py here ... L182 ", self.slack_token, " ", self.slack_channel); out_channel = SlackBot(self.slack_token, self.slack_channel) + print("--->> user text ::",retry_count,":: ",text); user_msg = UserMessage(text, out_channel, sender_id, input_channel=self.name()) + on_new_message(user_msg) except Exception as e: logger.error("Exception when trying to handle " @@ -215,7 +229,8 @@ def webhook(): elif request.form: output = dict(request.form) if self._is_button_reply(output): - sender_id = json.loads(output['payload'][0])['user']['id'] + ## sender_id = json.loads(output['payload'][0])['user']['id'] + sender_id = json.loads(output['payload'])['user']['id'] return self.process_message( on_new_message, text=self._get_button_reply(output), From 91b6ca5782f36ef4e48bbd4836a0882a91684f97 Mon Sep 17 00:00:00 2001 From: Alexander Raginsky Date: Wed, 13 Feb 2019 15:05:23 +0300 Subject: [PATCH 06/57] Fixing formatting issues --- rasa_core/events/__init__.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/rasa_core/events/__init__.py b/rasa_core/events/__init__.py index f886ac185e4..8cb3a3f749f 100644 --- a/rasa_core/events/__init__.py +++ b/rasa_core/events/__init__.py @@ -229,10 +229,13 @@ def empty(): def as_dict(self): d = super(UserUttered, self).as_dict() + input_channel = None + if hasattr(self, "input_channel"): + input_channel = self.input_channel d.update({ "text": self.text, "parse_data": self.parse_data, - "input_channel": self.input_channel if hasattr(self, "input_channel") else None + "input_channel": input_channel }) return d @@ -759,10 +762,17 @@ def _from_story_string( def as_dict(self): d = super(ActionExecuted, self).as_dict() + policy = None + if hasattr(self, "policy"): + policy = self.policy + confidence = None + if hasattr(self, "confidence"): + confidence = self.confidence + d.update({ "name": self.action_name, - "policy": self.policy if hasattr(self,"policy") else None, - "confidence": self.confidence if hasattr(self,"confidence") else None + "policy": policy, + "confidence": confidence }) return d From 9c1d72c1f3e5f054f0c08d677986690b2e023351 Mon Sep 17 00:00:00 2001 From: Alexander Raginsky Date: Wed, 13 Feb 2019 17:47:50 +0300 Subject: [PATCH 07/57] Fixing formatting issues --- rasa_core/events/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rasa_core/events/__init__.py b/rasa_core/events/__init__.py index 8cb3a3f749f..c301b10e191 100644 --- a/rasa_core/events/__init__.py +++ b/rasa_core/events/__init__.py @@ -763,15 +763,15 @@ def _from_story_string( def as_dict(self): d = super(ActionExecuted, self).as_dict() policy = None - if hasattr(self, "policy"): + if hasattr(self, "policy"): policy = self.policy confidence = None - if hasattr(self, "confidence"): + if hasattr(self, "confidence"): confidence = self.confidence d.update({ "name": self.action_name, - "policy": policy, + "policy": policy, "confidence": confidence }) return d From d2f2bb6273d518321b33499ccd5616f9a8b769bf Mon Sep 17 00:00:00 2001 From: harmekai Date: Wed, 13 Feb 2019 16:37:54 +0100 Subject: [PATCH 08/57] Add max_event_history in tracker_store --- rasa_core/tracker_store.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rasa_core/tracker_store.py b/rasa_core/tracker_store.py index e926fa3897c..e87219cd0e3 100644 --- a/rasa_core/tracker_store.py +++ b/rasa_core/tracker_store.py @@ -23,6 +23,7 @@ def __init__(self, event_broker: Optional[EventChannel] = None) -> None: self.domain = domain self.event_broker = event_broker + self.max_event_history = None @staticmethod def find_tracker_store(domain, store=None, event_broker=None): @@ -57,16 +58,19 @@ def load_tracker_from_module_string(domain, store): else: return InMemoryTrackerStore(domain) - def get_or_create_tracker(self, sender_id): + def get_or_create_tracker(self, sender_id, max_event_history=None): tracker = self.retrieve(sender_id) + self.max_event_history = max_event_history if tracker is None: tracker = self.create_tracker(sender_id) return tracker def init_tracker(self, sender_id): if self.domain: - return DialogueStateTracker(sender_id, - self.domain.slots) + return DialogueStateTracker( + sender_id, + self.domain.slots, + max_event_history=self.max_event_history) else: return None From ad1acaf0f025141217fc2de575040bfb614d2870 Mon Sep 17 00:00:00 2001 From: harmekai Date: Fri, 15 Feb 2019 14:14:37 +0100 Subject: [PATCH 09/57] Changelog and documentation --- CHANGELOG.rst | 1 + rasa_core/trackers.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b363405b413..06c06dcd3c9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,7 @@ Added (as long as the event itself is enabled in the application hosting the bot) - Added sanitization mechanism for SlackInput that (in its current shape and form) strips bot's self mentions from messages posted using the said @mentions. +- Added max_event_history in tracker_store to set this value in DialogueStateTracker Removed ------- diff --git a/rasa_core/trackers.py b/rasa_core/trackers.py index a564fc69f70..f1c867284a0 100644 --- a/rasa_core/trackers.py +++ b/rasa_core/trackers.py @@ -43,7 +43,10 @@ class EventVerbosity(Enum): class DialogueStateTracker(object): - """Maintains the state of a conversation.""" + """Maintains the state of a conversation. + + The field max_event_history will only give you these last events, + it can be set in the tracker_store""" @classmethod def from_dict(cls, From a332434fe0cb695c92a5688bc9bdac799e2aef1a Mon Sep 17 00:00:00 2001 From: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> Date: Fri, 15 Feb 2019 16:42:55 +0000 Subject: [PATCH 10/57] Changed some handling for functions slight change to button input detection - boolean state detection now split into functions as requested --- rasa_core/channels/slack.py | 48 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 33c6713f980..c09fe09f69d 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -28,7 +28,6 @@ def __init__(self, def send_text_message(self, recipient_id, message): recipient = self.slack_channel or recipient_id - print("slack.py send_text_message ::",message) for message_part in message.split("\n\n"): super(SlackBot, self).api_call("chat.postMessage", channel=recipient, @@ -38,15 +37,13 @@ def send_image_url(self, recipient_id, image_url, message=""): image_attachment = [{"image_url": image_url, "text": message}] recipient = self.slack_channel or recipient_id - print("slack.py send_image_url ::",message) return super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, attachments=image_attachment) def send_attachment(self, recipient_id, attachment, message=""): - recipient = self.slack_channel or recipient_id - print("slack.py send_attachment ::",message) + recipient = self.slack_channel or recipient_id return super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -60,6 +57,14 @@ def _convert_to_slack_buttons(buttons): "value": b['payload'], "type": "button"} for b in buttons] + + @staticmethod + def _get_text_from_slack_buttons(buttons): + val = [ bb['title'] for bb in buttons] + val = "".join(val); + return val; + + def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): recipient = self.slack_channel or recipient_id @@ -68,11 +73,18 @@ def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): "If you add more, all will be ignored.") return self.send_text_message(recipient, message) + if(len(message) > 0): + callback_string = message.replace(' ', '_')[:20]; + else: + callback_string = self._get_text_from_slack_buttons(buttons); + callback_string = callback_string.replace(' ', '_')[:20]; + + button_attachment = [{"fallback": message, - "callback_id": message.replace(' ', '_')[:20], - "actions": self._convert_to_slack_buttons( + "callback_id": callback_string, + "actions": self._convert_to_slack_buttons( buttons)}] - print("slack.py send_button ::",button_attachment) + super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -131,20 +143,23 @@ def _is_user_message(slack_event): slack_event.get('event').get('text') and not slack_event.get('event').get('bot_id')) + @staticmethod + def _is_interactive_message(payload): + return (payload['type'] == u"interactive_message") + + @staticmethod + def _is_button(payload): + return (payload['actions'][0]['type'] == u"button") + @staticmethod def _is_button_reply(slack_event): - pay = json.loads(slack_event['payload']); - evaluation = (pay['type'] == u"interactive_message") and (pay['actions'][0]['type'] == u"button"); - ## print("Is it a button ? ",evaluation); - return( evaluation ); - ## return (slack_event.get('payload') and - ## slack_event['payload'][0] and - ## 'name' in slack_event['payload'][0]) + payload = json.loads(slack_event['payload']); + return (SlackInput._is_interactive_message(payload) and + SlackInput._is_button(payload)) @staticmethod def _get_button_reply(slack_event): return json.loads(slack_event['payload'])['actions'][0]['name'] - ## return json.loads(slack_event['payload'][0])['actions'][0]['name'] @staticmethod @@ -190,9 +205,7 @@ def process_message(self, on_new_message, text, sender_id): return Response(status=201, headers={'X-Slack-No-Retry': 1}) try: - ## print("slack.py here ... L182 ", self.slack_token, " ", self.slack_channel); out_channel = SlackBot(self.slack_token, self.slack_channel) - print("--->> user text ::",retry_count,":: ",text); user_msg = UserMessage(text, out_channel, sender_id, input_channel=self.name()) @@ -229,7 +242,6 @@ def webhook(): elif request.form: output = dict(request.form) if self._is_button_reply(output): - ## sender_id = json.loads(output['payload'][0])['user']['id'] sender_id = json.loads(output['payload'])['user']['id'] return self.process_message( on_new_message, From d3e95b45b3cb853fe410cf3f921e957a5072870a Mon Sep 17 00:00:00 2001 From: paulaWesselmann Date: Mon, 25 Feb 2019 17:57:35 +0100 Subject: [PATCH 11/57] changed to ask for entities as well as intent --- rasa_core/training/interactive.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index 554a4a3ccfd..766ea47cee2 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -1006,6 +1006,7 @@ def _validate_user_text(latest_message: Dict[Text, Any], else: question = questionary.confirm( "Is the NLU classification for '{}' with intent '{}' correct?" + "\n AND are all occurring entities labeled correctly?" "".format(text, intent)) return _ask_or_abort(question, sender_id, endpoint) From 5137c8c639a4a3d87227d289a3789eba883cf9ab Mon Sep 17 00:00:00 2001 From: Jimmy Leblanc Date: Tue, 26 Feb 2019 13:20:21 +0100 Subject: [PATCH 12/57] update interactive.py When trying to detect format of the training data file in the _write_nlu_to_file function, there is a conflict between the opening of the file in writing mode and the call to the "_guess_format" fonction from rasa_nlu/rasa_nlu/training_data/loading.py. Indeed, after the opening, the file is everytime detected as markdown by the "_guess_format" func because the "js = json.loads(content)" loads an empty file resulting in wrong detection (if the file is a json). Quick fix to avoid that. --- rasa_core/training/interactive.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index cd2e04f7bd5..1fa75187734 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -739,14 +739,18 @@ def _write_nlu_to_file( previous_examples = TrainingData() nlu_data = previous_examples.merge(TrainingData(msgs)) - + + if _guess_format(export_nlu_path) in {"md", "unk"}: + fformat = "md" + else: + fformat = "json" + with io.open(export_nlu_path, 'w', encoding="utf-8") as f: - if _guess_format(export_nlu_path) in {"md", "unk"}: + if fformat == "md": f.write(nlu_data.as_markdown()) else: f.write(nlu_data.as_json()) - def _entities_from_messages(messages): """Return all entities that occur in atleast one of the messages.""" return list({e["entity"] From 50ccaf0f3b86c65bfcd857ebf4c64f64b9b7c4a0 Mon Sep 17 00:00:00 2001 From: Naoko Date: Sat, 16 Feb 2019 10:44:54 -0700 Subject: [PATCH 13/57] Resolve #1720 Handles slot name contains character that is invalid as python variable name (e.g. dot) in template --- .gitignore | 3 ++- CHANGELOG.rst | 1 + rasa_core/nlg/template.py | 6 +++++- tests/test_nlg.py | 44 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index dd2c1b470fe..b0af10d5527 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ *pyc *~ .env +venv .cache/ .pytest_cache/ .coverage @@ -55,4 +56,4 @@ examples/restaurantbot/models* docs/key docs/key.pub secrets.tar -failed_stories.md \ No newline at end of file +failed_stories.md diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3544e972b77..c70f001557a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,7 @@ Removed Fixed ----- +- Handles slot name contains characters that are invalid as python variable name (e.g. dot) in a template [0.13.2] - 2019-02-06 ^^^^^^^^^^^^^^^^^^^^^ diff --git a/rasa_core/nlg/template.py b/rasa_core/nlg/template.py index ab36a778015..9a888e17a3d 100644 --- a/rasa_core/nlg/template.py +++ b/rasa_core/nlg/template.py @@ -1,5 +1,6 @@ import copy import logging +import re import numpy as np from rasa_core.trackers import DialogueStateTracker @@ -76,7 +77,10 @@ def _fill_template_text( # Filling the template variables in the template if template_vars: try: - template["text"] = template["text"].format(**template_vars) + # blacklist characters that probably should not be + # part of slot name and replace with old %-formatting + text = re.sub(r'{([^\n,]+?)}', r'{0[\1]}', template["text"]) + template["text"] = text.format(template_vars) except KeyError as e: logger.exception( "Failed to fill utterance template '{}'. " diff --git a/tests/test_nlg.py b/tests/test_nlg.py index ddfe07fbdc6..e4534a837c8 100644 --- a/tests/test_nlg.py +++ b/tests/test_nlg.py @@ -1,4 +1,5 @@ import uuid +from unittest import mock import jsonschema import pytest @@ -9,6 +10,7 @@ from rasa_core.nlg.callback import ( nlg_request_format_spec, CallbackNaturalLanguageGenerator) +from rasa_core.nlg.template import TemplatedNaturalLanguageGenerator from rasa_core.utils import EndpointConfig from rasa_core.agent import Agent from tests.conftest import DEFAULT_ENDPOINTS_FILE @@ -79,3 +81,45 @@ def test_nlg_schema_validation_empty_buttons(): def test_nlg_schema_validation_empty_image(): content = {"text": "Hey there!", "image": None} assert CallbackNaturalLanguageGenerator.validate_response(content) + + +@pytest.mark.parametrize("filled_slots", [ + {"tag_w_underscore": "a"}, + {"tag with space": "bacon", "tag_w_int_val": 123}, + {"tag.with.dot": "chocolate", "tag_2": "b"}, + {"tag-w-dash": "apple pie", "tag.with.float.val": 1.3}, + {"tag-w-$": "banana"}, + {"tag-w-@": "one", "tagCamelCase": "two", "tag-w-*": "three"}, +]) +def test_nlg_fill_template_text(filled_slots): + template_text = ", ".join(["{" + t + "}" for t in filled_slots.keys()]) + resolved_text = ", ".join([str(s) for s in filled_slots.values()]) + + template = {'text': template_text} + t = TemplatedNaturalLanguageGenerator(templates=dict( + bot_message_1=[template] + )) + result = t._fill_template_text( + template=template, + filled_slots=filled_slots + ) + assert result == {'text': resolved_text} + + +@pytest.mark.parametrize("filled_slots", [ + {"tag_w_\n": "a"}, + {"tag,w,": "a"}, +]) +@mock.patch('rasa_core.nlg.template.logger') +def test_nlg_fill_template_text_w_bad_slot_name(mock_logger, filled_slots): + template_text = ", ".join(["{" + t + "}" for t in filled_slots.keys()]) + template = {'text': template_text} + t = TemplatedNaturalLanguageGenerator(templates=dict( + bot_message_1=[template] + )) + result = t._fill_template_text( + template=template, + filled_slots=filled_slots + ) + assert mock_logger.exception.call_count == 1 + assert result['text'] == template_text From f1f669800536e606c9a0977353a18c4f2c222824 Mon Sep 17 00:00:00 2001 From: Naoko Date: Mon, 25 Feb 2019 17:32:25 -0700 Subject: [PATCH 14/57] Updated comment to reflect the real change under _fill_template_text Simplify the tests per CR --- rasa_core/nlg/template.py | 9 ++++++--- tests/test_nlg.py | 39 +++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/rasa_core/nlg/template.py b/rasa_core/nlg/template.py index 9a888e17a3d..9f0272b18ca 100644 --- a/rasa_core/nlg/template.py +++ b/rasa_core/nlg/template.py @@ -77,9 +77,12 @@ def _fill_template_text( # Filling the template variables in the template if template_vars: try: - # blacklist characters that probably should not be - # part of slot name and replace with old %-formatting - text = re.sub(r'{([^\n,]+?)}', r'{0[\1]}', template["text"]) + # transforming template tags from + # "{tag_name}" to "{0[tag_name]}" + # as described here: + # https://stackoverflow.com/questions/7934620/python-dots-in-the-name-of-variable-in-a-format-string#comment9695339_7934969 + # assuming that slot_name do not contain newline character here + text = re.sub(r'{([^\n]+?)}', r'{0[\1]}', template["text"]) template["text"] = text.format(template_vars) except KeyError as e: logger.exception( diff --git a/tests/test_nlg.py b/tests/test_nlg.py index e4534a837c8..3ef93065f7f 100644 --- a/tests/test_nlg.py +++ b/tests/test_nlg.py @@ -1,5 +1,4 @@ import uuid -from unittest import mock import jsonschema import pytest @@ -96,9 +95,7 @@ def test_nlg_fill_template_text(filled_slots): resolved_text = ", ".join([str(s) for s in filled_slots.values()]) template = {'text': template_text} - t = TemplatedNaturalLanguageGenerator(templates=dict( - bot_message_1=[template] - )) + t = TemplatedNaturalLanguageGenerator(templates=dict()) result = t._fill_template_text( template=template, filled_slots=filled_slots @@ -106,20 +103,30 @@ def test_nlg_fill_template_text(filled_slots): assert result == {'text': resolved_text} -@pytest.mark.parametrize("filled_slots", [ - {"tag_w_\n": "a"}, - {"tag,w,": "a"}, +@pytest.mark.parametrize("slot_name, slot_value", [ + ("tag_w_underscore", "a"), + ("tag.with.float.val", 1.3), + ("tag-w-$", "banana"), + ("tagCamelCase", "two"), ]) -@mock.patch('rasa_core.nlg.template.logger') -def test_nlg_fill_template_text_w_bad_slot_name(mock_logger, filled_slots): - template_text = ", ".join(["{" + t + "}" for t in filled_slots.keys()]) - template = {'text': template_text} - t = TemplatedNaturalLanguageGenerator(templates=dict( - bot_message_1=[template] - )) +def test_nlg_fill_template_text2(slot_name, slot_value): + template = {'text': "{" + slot_name + "}"} + t = TemplatedNaturalLanguageGenerator(templates=dict()) result = t._fill_template_text( template=template, - filled_slots=filled_slots + filled_slots={slot_name: slot_value} + ) + assert result == {'text': str(slot_value)} + + +@pytest.mark.parametrize("slot_name, slot_value", [ + ("tag_w_\n", "a"), +]) +def test_nlg_fill_template_text_w_bad_slot_name2(slot_name, slot_value): + template_text = "{" + slot_name + "}" + t = TemplatedNaturalLanguageGenerator(templates=dict()) + result = t._fill_template_text( + template={'text': template_text}, + filled_slots={slot_name: slot_value} ) - assert mock_logger.exception.call_count == 1 assert result['text'] == template_text From 920456306856c4a13f1ce6c1d98d98b677dcd951 Mon Sep 17 00:00:00 2001 From: Naoko Date: Tue, 26 Feb 2019 17:22:41 -0700 Subject: [PATCH 15/57] Updated changelog.rst text per CR --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c70f001557a..ba452dad546 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,7 +30,7 @@ Removed Fixed ----- -- Handles slot name contains characters that are invalid as python variable name (e.g. dot) in a template +- Handles slot names which contain characters that are invalid as python variable name (e.g. dot) in a template [0.13.2] - 2019-02-06 ^^^^^^^^^^^^^^^^^^^^^ From 0c2961c0daa0ef0e667fd8d7e2fc7e2d87b230d5 Mon Sep 17 00:00:00 2001 From: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> Date: Wed, 27 Feb 2019 10:40:29 +0000 Subject: [PATCH 16/57] delinted Delinted for code style --- rasa_core/channels/slack.py | 43 ++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index c09fe09f69d..6dc65cece02 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -43,7 +43,7 @@ def send_image_url(self, recipient_id, image_url, message=""): attachments=image_attachment) def send_attachment(self, recipient_id, attachment, message=""): - recipient = self.slack_channel or recipient_id + recipient = self.slack_channel or recipient_id return super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -57,13 +57,11 @@ def _convert_to_slack_buttons(buttons): "value": b['payload'], "type": "button"} for b in buttons] - @staticmethod def _get_text_from_slack_buttons(buttons): - val = [ bb['title'] for bb in buttons] - val = "".join(val); - return val; - + val = [bb['title'] for bb in buttons] + val = "".join(val) + return val def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): recipient = self.slack_channel or recipient_id @@ -73,18 +71,17 @@ def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): "If you add more, all will be ignored.") return self.send_text_message(recipient, message) - if(len(message) > 0): - callback_string = message.replace(' ', '_')[:20]; - else: - callback_string = self._get_text_from_slack_buttons(buttons); - callback_string = callback_string.replace(' ', '_')[:20]; - - + if(len(message) > 0): + callback_string = message.replace(' ', '_')[:20] + else: + callback_string = self._get_text_from_slack_buttons(buttons) + callback_string = callback_string.replace(' ', '_')[:20] + button_attachment = [{"fallback": message, - "callback_id": callback_string, - "actions": self._convert_to_slack_buttons( - buttons)}] - + "callback_id": callback_string, + "actions": self._convert_to_slack_buttons( + buttons)}] + super(SlackBot, self).api_call("chat.postMessage", channel=recipient, as_user=True, @@ -150,24 +147,23 @@ def _is_interactive_message(payload): @staticmethod def _is_button(payload): return (payload['actions'][0]['type'] == u"button") - + @staticmethod def _is_button_reply(slack_event): - payload = json.loads(slack_event['payload']); + payload = json.loads(slack_event['payload']) return (SlackInput._is_interactive_message(payload) and SlackInput._is_button(payload)) @staticmethod def _get_button_reply(slack_event): return json.loads(slack_event['payload'])['actions'][0]['name'] - @staticmethod def _sanitize_user_message(text, uids_to_remove): """Remove superfluous/wrong/problematic tokens from a message. - Probably a good starting point for pre-formatting of user-provided text, - to make NLU's life easier in case they go funky to the power of extreme. + Probably a good starting point for pre-formatting of user-provided text + to make NLU's life easier in case they go funky to the power of extreme In the current state will just drop self-mentions of bot itself @@ -197,8 +193,7 @@ def process_message(self, on_new_message, text, sender_id): """ retry_reason = request.headers.environ.get('HTTP_X_SLACK_RETRY_REASON') retry_count = request.headers.environ.get('HTTP_X_SLACK_RETRY_NUM') - ## if retry_count and retry_reason in self.errors_ignore_retry: - if retry_count: + if retry_count and retry_reason in self.errors_ignore_retry: logger.warning("Received retry #{} request from slack" " due to {}".format(retry_count, retry_reason)) From 9c7106f0c26672ee7732849c4203c688e6fd4455 Mon Sep 17 00:00:00 2001 From: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> Date: Wed, 27 Feb 2019 16:36:15 +0000 Subject: [PATCH 17/57] Hanging indent delinted again Ok, so hanging indent rules seem to be a bit arbitrary, this passes pylama and pycodestyle but who knows what internal configs you are using. --- rasa_core/channels/slack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 6dc65cece02..4b726458a7d 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -79,8 +79,8 @@ def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): button_attachment = [{"fallback": message, "callback_id": callback_string, - "actions": self._convert_to_slack_buttons( - buttons)}] + "actions": + self._convert_to_slack_buttons(buttons)}] super(SlackBot, self).api_call("chat.postMessage", channel=recipient, From 4d441d1abc69103d8311995c45cbbb5d4c7887ed Mon Sep 17 00:00:00 2001 From: Naoko Date: Thu, 28 Feb 2019 13:45:01 -0700 Subject: [PATCH 18/57] Updated test to test to pass single slot and value per test --- tests/test_nlg.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/test_nlg.py b/tests/test_nlg.py index 3ef93065f7f..36967be2789 100644 --- a/tests/test_nlg.py +++ b/tests/test_nlg.py @@ -82,25 +82,24 @@ def test_nlg_schema_validation_empty_image(): assert CallbackNaturalLanguageGenerator.validate_response(content) -@pytest.mark.parametrize("filled_slots", [ - {"tag_w_underscore": "a"}, - {"tag with space": "bacon", "tag_w_int_val": 123}, - {"tag.with.dot": "chocolate", "tag_2": "b"}, - {"tag-w-dash": "apple pie", "tag.with.float.val": 1.3}, - {"tag-w-$": "banana"}, - {"tag-w-@": "one", "tagCamelCase": "two", "tag-w-*": "three"}, +@pytest.mark.parametrize("slot_name, slot_value", [ + ("tag_w_underscore", "a"), + ("tag with space", "bacon"), + ("tag.with.dot", "chocolate"), + ("tag-w-dash", "apple pie"), + ("tag-w-$", "banana"), + ("tag-w-@", "one"), + ("tagCamelCase", "two"), + ("tag-w-*", "three"), ]) -def test_nlg_fill_template_text(filled_slots): - template_text = ", ".join(["{" + t + "}" for t in filled_slots.keys()]) - resolved_text = ", ".join([str(s) for s in filled_slots.values()]) - - template = {'text': template_text} +def test_nlg_fill_template_text(slot_name, slot_value): + template = {'text': "{" + slot_name + "}"} t = TemplatedNaturalLanguageGenerator(templates=dict()) result = t._fill_template_text( template=template, - filled_slots=filled_slots + filled_slots={slot_name: slot_value} ) - assert result == {'text': resolved_text} + assert result == {'text': str(slot_value)} @pytest.mark.parametrize("slot_name, slot_value", [ From 8e78687c64ad4ee24770cb355624324f16956fce Mon Sep 17 00:00:00 2001 From: paulaWesselmann Date: Mon, 4 Mar 2019 11:55:57 +0100 Subject: [PATCH 19/57] validate both intent and entities --- rasa_core/training/interactive.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index c39e65e347f..aa7fc567d8f 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -397,6 +397,8 @@ def _request_fork_from_user( endpoint) if fork_idx is not None: + # TODO: add saving of tracker up to now in stories here? + return tracker.get("events", [])[:int(fork_idx)] else: return None @@ -595,6 +597,18 @@ def _ask_if_quit(sender_id: Text, endpoint: EndpointConfig) -> bool: elif answer == "undo": raise UndoLastStep() elif answer == "fork": + # first the path taken is saved as when the user quits + story_path, nlu_path, domain_path = _request_export_info() + + tracker = retrieve_tracker(endpoint, sender_id) + evts = tracker.get("events", []) + + _write_stories_to_file(story_path, evts) + _write_nlu_to_file(nlu_path, evts) + _write_domain_to_file(domain_path, evts, endpoint) + + logger.info("Successfully wrote stories and NLU data") + raise ForkTracker() elif answer == "restart": raise RestartConversation() @@ -997,6 +1011,13 @@ def _validate_user_text(latest_message: Dict[Text, Any], parse_data = latest_message.get("parse_data", {}) text = _as_md_message(parse_data) intent = parse_data.get("intent", {}).get("name") + entities = parse_data.get("entities", []) + if entities: + entity = [] + for e in entities: + entity.append('[' + e['value'] + '](' + e['entity'] + ')') + else: + entity = "'None'" if intent is None: print("The NLU classification for '{}' returned '{}'" @@ -1004,9 +1025,9 @@ def _validate_user_text(latest_message: Dict[Text, Any], return False else: question = questionary.confirm( - "Is the NLU classification for '{}' with intent '{}' correct?" - "\n AND are all occurring entities labeled correctly?" - "".format(text, intent)) + "Is the NLU classification for '{}' with intent '{}' " + "and entities: {} correct?" + "".format(text, intent, entity)) return _ask_or_abort(question, sender_id, endpoint) From ca4bd0de1c00456f085609a41646d2b78eb32d5f Mon Sep 17 00:00:00 2001 From: paulaWesselmann Date: Mon, 4 Mar 2019 13:13:42 +0100 Subject: [PATCH 20/57] deleted things that should not have been on this branch --- rasa_core/training/interactive.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index aa7fc567d8f..b285edce854 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -397,7 +397,6 @@ def _request_fork_from_user( endpoint) if fork_idx is not None: - # TODO: add saving of tracker up to now in stories here? return tracker.get("events", [])[:int(fork_idx)] else: @@ -597,18 +596,6 @@ def _ask_if_quit(sender_id: Text, endpoint: EndpointConfig) -> bool: elif answer == "undo": raise UndoLastStep() elif answer == "fork": - # first the path taken is saved as when the user quits - story_path, nlu_path, domain_path = _request_export_info() - - tracker = retrieve_tracker(endpoint, sender_id) - evts = tracker.get("events", []) - - _write_stories_to_file(story_path, evts) - _write_nlu_to_file(nlu_path, evts) - _write_domain_to_file(domain_path, evts, endpoint) - - logger.info("Successfully wrote stories and NLU data") - raise ForkTracker() elif answer == "restart": raise RestartConversation() From 4ea45d1147f8b78864364876b47554fd965df4f1 Mon Sep 17 00:00:00 2001 From: Paula Wesselmann <38981219+paulaWesselmann@users.noreply.github.com> Date: Mon, 4 Mar 2019 13:14:49 +0100 Subject: [PATCH 21/57] Update interactive.py --- rasa_core/training/interactive.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index b285edce854..3820c5d65db 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -397,7 +397,6 @@ def _request_fork_from_user( endpoint) if fork_idx is not None: - return tracker.get("events", [])[:int(fork_idx)] else: return None From 0931c1d6b046b24ad6d2a670dcdd6eeae3411f84 Mon Sep 17 00:00:00 2001 From: Hsiaofei Tsien Date: Tue, 5 Mar 2019 16:45:32 +0800 Subject: [PATCH 22/57] Set default log file encoding to utf-8 Set default log file encoding to utf-8 --- rasa_core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/utils.py b/rasa_core/utils.py index b89ed9713e4..5fbb0def185 100644 --- a/rasa_core/utils.py +++ b/rasa_core/utils.py @@ -28,7 +28,7 @@ def configure_file_logging(loglevel, logfile): if logfile: - fh = logging.FileHandler(logfile) + fh = logging.FileHandler(logfile, encoding='utf-8') fh.setLevel(loglevel) logging.getLogger('').addHandler(fh) logging.captureWarnings(True) From c37e8517d9bc3f52b7028a813a2d90bb189f02e9 Mon Sep 17 00:00:00 2001 From: paulaWesselmann Date: Tue, 5 Mar 2019 17:10:02 +0100 Subject: [PATCH 23/57] better phrasing --- rasa_core/training/interactive.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index 3820c5d65db..aa253b8b3e9 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -999,21 +999,20 @@ def _validate_user_text(latest_message: Dict[Text, Any], intent = parse_data.get("intent", {}).get("name") entities = parse_data.get("entities", []) if entities: - entity = [] - for e in entities: - entity.append('[' + e['value'] + '](' + e['entity'] + ')') + msg = ("Is the intent '{}' correct for '{}' and are " + "all entities labeled correctly?" + .format(text, intent)) else: - entity = "'None'" + msg = ("Your NLU model classified '{}' with " + "intent '{}' and there are no entities, is this correct?" + .format(text, intent)) if intent is None: print("The NLU classification for '{}' returned '{}'" "".format(text, intent)) return False else: - question = questionary.confirm( - "Is the NLU classification for '{}' with intent '{}' " - "and entities: {} correct?" - "".format(text, intent, entity)) + question = questionary.confirm(msg) return _ask_or_abort(question, sender_id, endpoint) From 1fc2bdd5b2f574086a1391b6ba275fbb279810e8 Mon Sep 17 00:00:00 2001 From: Tobias Wochinger Date: Wed, 6 Mar 2019 11:21:28 +0100 Subject: [PATCH 24/57] change test discovery to test_ so that rasa_core.test() is not discovered --- setup.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 4c25db9539f..e3e3566a3f6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,8 @@ -# pytest pycodestyle configuration [tool:pytest] +# Function starting with the following pattern are considered for test cases. +python_functions=test_ + +# pytest pycodestyle configuration codestyle_max_line_length = 80 codestyle_ignore = E251 From c135535c0ca9fc438e8a0accb5f927a0e2c5f5d5 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:05:06 +0000 Subject: [PATCH 25/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 4b726458a7d..895813aedaf 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -71,7 +71,7 @@ def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): "If you add more, all will be ignored.") return self.send_text_message(recipient, message) - if(len(message) > 0): + if message: callback_string = message.replace(' ', '_')[:20] else: callback_string = self._get_text_from_slack_buttons(buttons) From 05ab3798628abddfcd437c23ed77b1add2780ebe Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:05:42 +0000 Subject: [PATCH 26/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 895813aedaf..07cac66e718 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -59,7 +59,7 @@ def _convert_to_slack_buttons(buttons): @staticmethod def _get_text_from_slack_buttons(buttons): - val = [bb['title'] for bb in buttons] + return "".join([b.get("title", "") for b in buttons]) val = "".join(val) return val From c1d9d71b3b843cfef38c6a1cbe8b43a046bcbf5d Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:05:51 +0000 Subject: [PATCH 27/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 07cac66e718..a29f1ffa594 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -60,7 +60,6 @@ def _convert_to_slack_buttons(buttons): @staticmethod def _get_text_from_slack_buttons(buttons): return "".join([b.get("title", "") for b in buttons]) - val = "".join(val) return val def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): From 19a886901daa7ad5a3bcd3665d1908275551e5f7 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:05:59 +0000 Subject: [PATCH 28/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index a29f1ffa594..22a601a2224 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -60,7 +60,6 @@ def _convert_to_slack_buttons(buttons): @staticmethod def _get_text_from_slack_buttons(buttons): return "".join([b.get("title", "") for b in buttons]) - return val def send_text_with_buttons(self, recipient_id, message, buttons, **kwargs): recipient = self.slack_channel or recipient_id From 36444498cc327111dce0d256eec4ee051d7f8480 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:06:12 +0000 Subject: [PATCH 29/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 22a601a2224..0bd0844c9f8 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -140,7 +140,7 @@ def _is_user_message(slack_event): @staticmethod def _is_interactive_message(payload): - return (payload['type'] == u"interactive_message") + return (payload['type'] == "interactive_message") @staticmethod def _is_button(payload): From b1d2bb9d6bbeb30f87579ba306f5574da5dfe831 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 12:06:19 +0000 Subject: [PATCH 30/57] Update rasa_core/channels/slack.py Co-Authored-By: mark-collins-voxsio <47524257+mark-collins-voxsio@users.noreply.github.com> --- rasa_core/channels/slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/channels/slack.py b/rasa_core/channels/slack.py index 0bd0844c9f8..a33e1b8bac3 100644 --- a/rasa_core/channels/slack.py +++ b/rasa_core/channels/slack.py @@ -144,7 +144,7 @@ def _is_interactive_message(payload): @staticmethod def _is_button(payload): - return (payload['actions'][0]['type'] == u"button") + return (payload['actions'][0]['type'] == "button") @staticmethod def _is_button_reply(slack_event): From 70af62e6649a953078ec30571bdf1e247fbc5901 Mon Sep 17 00:00:00 2001 From: paulaWesselmann Date: Wed, 6 Mar 2019 13:07:18 +0100 Subject: [PATCH 31/57] renamed message --- rasa_core/training/interactive.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index aa253b8b3e9..50c77a5f0a6 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -999,20 +999,20 @@ def _validate_user_text(latest_message: Dict[Text, Any], intent = parse_data.get("intent", {}).get("name") entities = parse_data.get("entities", []) if entities: - msg = ("Is the intent '{}' correct for '{}' and are " - "all entities labeled correctly?" - .format(text, intent)) + message = ("Is the intent '{}' correct for '{}' and are " + "all entities labeled correctly?" + .format(text, intent)) else: - msg = ("Your NLU model classified '{}' with " - "intent '{}' and there are no entities, is this correct?" - .format(text, intent)) + message = ("Your NLU model classified '{}' with intent '{}'" + " and there are no entities, is this correct?" + .format(text, intent)) if intent is None: print("The NLU classification for '{}' returned '{}'" "".format(text, intent)) return False else: - question = questionary.confirm(msg) + question = questionary.confirm(message) return _ask_or_abort(question, sender_id, endpoint) From 8ef7aa03cc6f58b5a19a715337ee93fa4753e739 Mon Sep 17 00:00:00 2001 From: ricwo Date: Wed, 6 Mar 2019 13:26:45 +0100 Subject: [PATCH 32/57] update user profile url --- rasa_core/channels/rasa_chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/channels/rasa_chat.py b/rasa_core/channels/rasa_chat.py index 015da014837..0df7e95b3a1 100644 --- a/rasa_core/channels/rasa_chat.py +++ b/rasa_core/channels/rasa_chat.py @@ -27,7 +27,7 @@ def __init__(self, url): self.base_url = url def _check_token(self, token): - url = "{}/users/me".format(self.base_url) + url = "{}/user".format(self.base_url) headers = {"Authorization": token} logger.debug("Requesting user information from auth server {}." "".format(url)) From d9944ce72e07c2139631b696470597549ad43a75 Mon Sep 17 00:00:00 2001 From: ricwo Date: Wed, 6 Mar 2019 13:27:50 +0100 Subject: [PATCH 33/57] increment version --- rasa_core/version.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rasa_core/version.py b/rasa_core/version.py index 0d07139dd67..6d886b9fa79 100644 --- a/rasa_core/version.py +++ b/rasa_core/version.py @@ -1,2 +1 @@ - -__version__ = '0.14.0a1' +__version__ = '0.14.0a2' From a9933dcdea8ecf24358ea70ae0bac6d50107a676 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 14:38:06 +0100 Subject: [PATCH 34/57] adapted to changed model format --- docs/_static/spec/server.yml | 51 ++++++++++++++++++++++++++++++++++++ rasa_core/agent.py | 8 +++--- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/docs/_static/spec/server.yml b/docs/_static/spec/server.yml index cf09e648e4d..1a2e2fbcd91 100644 --- a/docs/_static/spec/server.yml +++ b/docs/_static/spec/server.yml @@ -675,6 +675,57 @@ paths: 500: $ref: '#/components/responses/500Action' + /parse: + post: + security: + - TokenAuth: [] + - JWT: [] + tags: + - Model + summary: Parse a message and run the NLU model + description: >- + Predicts the intent and entities of the message + posted to this endpoint. No messages will be stored + to a conversation and no action will be run. This will + just retrieve the NLU parse results. + operationId: parseNLU + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + q: + type: string + description: Message to ne parsed + example: + q: "Hello, I am Rasa!" + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ParseData' + examples: + text: "Hello, I am Rasa!" + entities: + - start: 12 + end: 16 + entity: name + value: Rasa + intent: + confidence: 0.87 + name: greet + intent_ranking: + - confidence: 0.87 + name: greet + - confidence: 0.13 + name: goodbye + 403: + $ref: '#/components/responses/403Permissions' + /domain: get: security: diff --git a/rasa_core/agent.py b/rasa_core/agent.py index 98862f4e34a..eaf435e721a 100644 --- a/rasa_core/agent.py +++ b/rasa_core/agent.py @@ -86,18 +86,18 @@ def _init_model_from_server(model_server: EndpointConfig def _is_stack_model(model_directory: Text): """Decide whether a persisted model is a stack or a core model.""" - # TODO: find a better way to check this - return os.path.exists(os.path.join(model_directory, "rasa_model")) + return os.path.exists(os.path.join(model_directory, "fingerprint.json")) def _load_and_set_updated_model(agent: 'Agent', model_directory: Text, fingerprint: Text): """Load the persisted model into memory and set the model on the agent.""" + if _is_stack_model(model_directory): from rasa_core.interpreter import RasaNLUInterpreter - nlu_model = os.path.join(model_directory, "rasa_model", "nlu") - core_model = os.path.join(model_directory, "rasa_model", "core") + nlu_model = os.path.join(model_directory, "nlu") + core_model = os.path.join(model_directory, "core") interpreter = RasaNLUInterpreter(model_directory=nlu_model) else: interpreter = agent.interpreter From edfcf5490603bde2f89cacacad6f472ff1fd4bbf Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 15:09:39 +0100 Subject: [PATCH 35/57] added tests --- .../pika_endpoint.yml} | 3 +- rasa_core/broker.py | 3 +- tests/test_broker.py | 84 ++++++++++++++++--- tests/test_server.py | 25 ++++-- 4 files changed, 93 insertions(+), 22 deletions(-) rename data/test_endpoints/{event_broker_endpoint.yml => event_brokers/pika_endpoint.yml} (73%) diff --git a/data/test_endpoints/event_broker_endpoint.yml b/data/test_endpoints/event_brokers/pika_endpoint.yml similarity index 73% rename from data/test_endpoints/event_broker_endpoint.yml rename to data/test_endpoints/event_brokers/pika_endpoint.yml index c1e1704d83e..1b1ae725301 100644 --- a/data/test_endpoints/event_broker_endpoint.yml +++ b/data/test_endpoints/event_brokers/pika_endpoint.yml @@ -2,4 +2,5 @@ event_broker: url: localhost username: username password: password - queue: queue \ No newline at end of file + queue: queue + type: pika \ No newline at end of file diff --git a/rasa_core/broker.py b/rasa_core/broker.py index 6320330a0c1..5e491ee59fb 100644 --- a/rasa_core/broker.py +++ b/rasa_core/broker.py @@ -62,7 +62,7 @@ def __init__(self, host, username, password, self.credentials = pika.PlainCredentials(username, password) @classmethod - def from_endpoint_config(cls, broker_config): + def from_endpoint_config(cls, broker_config) -> Optional['PikaProducer']: if broker_config is None: return None @@ -99,6 +99,7 @@ class FileProducer(EventChannel): DEFAULT_LOG_FILE_NAME = "rasa_event.log" def __init__(self, path=None) -> None: + self.path = path self.event_logger = self._event_logger(path) @classmethod diff --git a/tests/test_broker.py b/tests/test_broker.py index 279987dd80a..24041906525 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -1,25 +1,85 @@ -from rasa_core import utils -from rasa_core.broker import PikaProducer +import json + +from rasa_core import utils, broker +from rasa_core.broker import PikaProducer, EventChannel, FileProducer +from rasa_core.events import UserUttered, SlotSet, Restarted, Event +from rasa_core.utils import EndpointConfig from tests.conftest import DEFAULT_ENDPOINTS_FILE -EVENT_BROKER_ENDPOINT_FILE = 'data/test_endpoints/event_broker_endpoint.yml' +EVENT_BROKER_ENDPOINT_FILE = 'data/test_endpoints/event_brokers/' \ + 'pika_endpoint.yml' + +TEST_EVENTS = [ + UserUttered("/greet", {"name": "greet", "confidence": 1.0}, []), + SlotSet("name", "rasa"), + Restarted()] -def test_broker_from_config(): +def test_pika_broker_from_config(): cfg = utils.read_endpoint_config(EVENT_BROKER_ENDPOINT_FILE, "event_broker") - actual = PikaProducer.from_endpoint_config(cfg) - - expected = PikaProducer("localhost", "username", "password", "queue") + actual = broker.from_endpoint_config(cfg) - assert actual.host == expected.host - assert actual.credentials.username == expected.credentials.username - assert actual.queue == expected.queue + assert isinstance(actual, PikaProducer) + assert actual.host == "localhost" + assert actual.credentials.username == "username" + assert actual.queue == "queue" -def test_broker_not_in_config(): +def test_no_broker_in_config(): cfg = utils.read_endpoint_config(DEFAULT_ENDPOINTS_FILE, "event_broker") - actual = PikaProducer.from_endpoint_config(cfg) + actual = broker.from_endpoint_config(cfg) assert actual is None + + +def test_file_broker_from_config(): + cfg = utils.read_endpoint_config('data/test_endpoints/event_brokers/' + 'file_endpoint.yml', + "event_broker") + actual = broker.from_endpoint_config(cfg) + + assert isinstance(actual, FileProducer) + assert actual.path == "rasa_event.log" + + +def test_file_broker_logs_to_file(tmpdir): + fname = tmpdir.join("events.log").strpath + + actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", + "path": fname})) + + assert isinstance(actual, FileProducer) + + for e in TEST_EVENTS: + actual.publish(e.as_dict()) + + # reading the events from the file one event per line + recovered = [] + with open(fname, "r") as f: + for l in f: + recovered.append(Event.from_parameters(json.loads(l))) + + assert recovered == TEST_EVENTS + + +def test_file_broker_properly_logs_newlines(tmpdir): + fname = tmpdir.join("events.log").strpath + + actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", + "path": fname})) + + assert isinstance(actual, FileProducer) + + 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(fname, "r") as f: + for l in f: + recovered.append(Event.from_parameters(json.loads(l))) + + assert recovered == [event_with_newline] diff --git a/tests/test_server.py b/tests/test_server.py index 736afc728d0..90775782140 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -81,8 +81,6 @@ def test_requesting_non_existent_tracker(app): assert content["slots"] == {"location": None, "cuisine": None} assert content["sender_id"] == "madeupid" assert content["events"] == [{"event": "action", - "policy": None, - "confidence": None, "name": "action_listen", "policy": None, "confidence": None, @@ -101,6 +99,22 @@ def test_respond(app): assert content == [{'text': 'hey there!', 'recipient_id': 'myid'}] +def test_parse(app): + data = json.dumps({"q": """/greet{"name": "Rasa"}"""}) + response = app.post("http://dummy/parse", + data=data, content_type='application/json') + content = response.get_json() + assert response.status_code == 200 + print(content) + assert content == { + 'entities': [ + {'end': 22, 'entity': 'name', 'start': 6, 'value': 'Rasa'}], + 'intent': {'confidence': 1.0, 'name': 'greet'}, + 'intent_ranking': [{'confidence': 1.0, 'name': 'greet'}], + 'text': '/greet{"name": "Rasa"}' + } + + @pytest.mark.parametrize("event", test_events) def test_pushing_event(app, event): cid = str(uuid.uuid1()) @@ -108,13 +122,11 @@ def test_pushing_event(app, event): data = json.dumps({"query": "/greet"}) response = app.post("{}/respond".format(conversation), data=data, content_type='application/json') - content = response.get_json() assert response.status_code == 200 data = json.dumps(event.as_dict()) response = app.post("{}/tracker/events".format(conversation), data=data, content_type='application/json') - content = response.get_json() assert response.status_code == 200 tracker_response = app.get("http://dummy/conversations/{}/tracker" @@ -148,7 +160,6 @@ def test_list_conversations(app): data = json.dumps({"query": "/greet"}) response = app.post("http://dummy/conversations/myid/respond", data=data, content_type='application/json') - content = response.get_json() assert response.status_code == 200 response = app.get("http://dummy/conversations") @@ -215,9 +226,7 @@ def test_sorted_predict(http_app, app): response = app.post("http://dummy/conversations/{}/predict".format(cid)) content = response.get_json() scores = content["scores"] - sorted_scores = sorted(scores, - key = lambda k: (-k['score'], - k['action'])) + sorted_scores = sorted(scores, key=lambda k: (-k['score'], k['action'])) assert scores == sorted_scores From 47712d420ad43ce0027f4872855292a97b32545d Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 15:14:36 +0100 Subject: [PATCH 36/57] added more tests --- tests/test_broker.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_broker.py b/tests/test_broker.py index 24041906525..0314b646353 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -83,3 +83,13 @@ def test_file_broker_properly_logs_newlines(tmpdir): recovered.append(Event.from_parameters(json.loads(l))) assert recovered == [event_with_newline] + + +def test_load_custom_broker_name(): + config = EndpointConfig(**{"type": "rasa_core.broker.FileProducer"}) + assert broker.from_endpoint_config(config) + + +def test_load_non_existent_custom_broker_name(): + config = EndpointConfig(**{"type": "rasa_core.broker.MyProducer"}) + assert broker.from_endpoint_config(config) is None From 7aa264d87e5eb289094252ee643a2752f0f9959b Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 15:15:55 +0100 Subject: [PATCH 37/57] some test cleanups --- tests/test_broker.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_broker.py b/tests/test_broker.py index 0314b646353..47d5785fca1 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -1,22 +1,20 @@ import json -from rasa_core import utils, broker -from rasa_core.broker import PikaProducer, EventChannel, FileProducer -from rasa_core.events import UserUttered, SlotSet, Restarted, Event +from rasa_core import broker, utils +from rasa_core.broker import FileProducer, PikaProducer +from rasa_core.events import Event, Restarted, SlotSet, UserUttered from rasa_core.utils import EndpointConfig from tests.conftest import DEFAULT_ENDPOINTS_FILE -EVENT_BROKER_ENDPOINT_FILE = 'data/test_endpoints/event_brokers/' \ - 'pika_endpoint.yml' - -TEST_EVENTS = [ +TEST_EVENTS = [ UserUttered("/greet", {"name": "greet", "confidence": 1.0}, []), SlotSet("name", "rasa"), Restarted()] def test_pika_broker_from_config(): - cfg = utils.read_endpoint_config(EVENT_BROKER_ENDPOINT_FILE, + cfg = utils.read_endpoint_config('data/test_endpoints/event_brokers/' + 'pika_endpoint.yml', "event_broker") actual = broker.from_endpoint_config(cfg) From 3c5ff9727e16553aca0a4c18a563a4979bcf6a10 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 15:21:40 +0100 Subject: [PATCH 38/57] fixed style --- rasa_core/training/interactive.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index 1fa75187734..04393341505 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -1,6 +1,5 @@ import sys -import io import logging import numpy as np import os @@ -704,7 +703,7 @@ def _write_stories_to_file( sub_conversations = _split_conversation_at_restarts(evts) - with io.open(export_story_path, 'a', encoding="utf-8") as f: + 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) @@ -739,18 +738,21 @@ def _write_nlu_to_file( previous_examples = TrainingData() nlu_data = previous_examples.merge(TrainingData(msgs)) - + + # need to guess the format of the file before opening it to avoid a read + # in a write if _guess_format(export_nlu_path) in {"md", "unk"}: - fformat = "md" - else: - fformat = "json" + fformat = "md" + else: + fformat = "json" - with io.open(export_nlu_path, 'w', encoding="utf-8") as f: + with open(export_nlu_path, 'w', encoding="utf-8") as f: if fformat == "md": f.write(nlu_data.as_markdown()) else: f.write(nlu_data.as_json()) + def _entities_from_messages(messages): """Return all entities that occur in atleast one of the messages.""" return list({e["entity"] From 205da267e220a2cbea83329d7188d1eb66fe1820 Mon Sep 17 00:00:00 2001 From: Ella Rohm-Ensing Date: Wed, 6 Mar 2019 15:56:52 +0100 Subject: [PATCH 39/57] move changes from changelog to CHANGELOG --- CHANGELOG.rst | 2 ++ docs/changelog.rst | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3cd0d57963f..c3e4ab81d55 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,7 @@ Added - utility functions for colored logging - open webbrowser when visualizing stories - added ability to use multiple env vars per line in yaml files +- added ``priority`` property of policies to influence best policy in the case of equal confidence Changed ------- @@ -28,6 +29,7 @@ Changed - renamed ``rasa_core.evaluate`` to ``rasa_core.test`` - ``scores`` array returned by the ``/conversations/{sender_id}/predict`` endpoint is now sorted according to the actions' scores. +- changed payloads from "text" to "message" in files: server.yml, docs/connectors.rst, rasa_core/server.py, rasa_core/training/interactive.py, tests/test_interactive.py Removed ------- diff --git a/docs/changelog.rst b/docs/changelog.rst index 939bfac0e59..1d3cbbe7c9f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,10 +1,3 @@ :desc: Rasa Core Changelog .. include:: ../CHANGELOG.rst -Added -------- -- Added `priority` property of policies to influence best policy in the case of equal confidence - -Changed -------- -- Change payloads from "text" to "message" in files: server.yml, docs/connectors.rst, rasa_core/server.py, rasa_core/training/interactive.py, tests/test_interactive.py From af45414c15ba07ec467701487dd7c2ff155b3845 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 15:58:07 +0100 Subject: [PATCH 40/57] pep 8 fix --- rasa_core/training/interactive.py | 2 +- tests/test_nlg.py | 17 +++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/rasa_core/training/interactive.py b/rasa_core/training/interactive.py index 4743e8af2f6..004e1513948 100644 --- a/rasa_core/training/interactive.py +++ b/rasa_core/training/interactive.py @@ -752,7 +752,7 @@ def _write_nlu_to_file( fformat = "md" else: fformat = "json" - + with open(export_nlu_path, 'w', encoding="utf-8") as f: if fformat == "md": f.write(nlu_data.as_markdown()) diff --git a/tests/test_nlg.py b/tests/test_nlg.py index 36967be2789..aadb329629c 100644 --- a/tests/test_nlg.py +++ b/tests/test_nlg.py @@ -36,6 +36,7 @@ def generate(): return app +# noinspection PyShadowingNames @pytest.fixture(scope="module") def http_nlg(request): http_server = WSGIServer(application=nlg_app()) @@ -54,7 +55,7 @@ def test_nlg(http_nlg, default_agent_path): agent = Agent.load(default_agent_path, None, generator=nlg_endpoint) - response = agent.handle_message("/greet", sender_id=sender) + response = agent.handle_text("/greet", sender_id=sender) assert len(response) == 1 assert response[0] == {"text": "Hey there!", "recipient_id": sender} @@ -91,24 +92,12 @@ def test_nlg_schema_validation_empty_image(): ("tag-w-@", "one"), ("tagCamelCase", "two"), ("tag-w-*", "three"), -]) -def test_nlg_fill_template_text(slot_name, slot_value): - template = {'text': "{" + slot_name + "}"} - t = TemplatedNaturalLanguageGenerator(templates=dict()) - result = t._fill_template_text( - template=template, - filled_slots={slot_name: slot_value} - ) - assert result == {'text': str(slot_value)} - - -@pytest.mark.parametrize("slot_name, slot_value", [ ("tag_w_underscore", "a"), ("tag.with.float.val", 1.3), ("tag-w-$", "banana"), ("tagCamelCase", "two"), ]) -def test_nlg_fill_template_text2(slot_name, slot_value): +def test_nlg_fill_template_text(slot_name, slot_value): template = {'text': "{" + slot_name + "}"} t = TemplatedNaturalLanguageGenerator(templates=dict()) result = t._fill_template_text( From 209086062c32e5aaa5af4a298e6ac08bb091f630 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 16:32:59 +0100 Subject: [PATCH 41/57] proper comment --- docs/connectors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connectors.rst b/docs/connectors.rst index 0c195989f22..bf9dfbd5d49 100644 --- a/docs/connectors.rst +++ b/docs/connectors.rst @@ -234,7 +234,7 @@ you need to supply a ``credentials.yml`` with the following content: slack: slack_token: "xoxb-286425452756-safjasdf7sl38KLls" - slack_channel: "#my_channel" or "@my_app" + slack_channel: "#my_channel" The endpoint for receiving slack messages is From 485dbdb5013d20fd3e9c2a22c21897f9cf047365 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 16:33:42 +0100 Subject: [PATCH 42/57] added missing files --- data/test_endpoints/event_brokers/file_endpoint.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 data/test_endpoints/event_brokers/file_endpoint.yml diff --git a/data/test_endpoints/event_brokers/file_endpoint.yml b/data/test_endpoints/event_brokers/file_endpoint.yml new file mode 100644 index 00000000000..a0beff44783 --- /dev/null +++ b/data/test_endpoints/event_brokers/file_endpoint.yml @@ -0,0 +1,3 @@ +event_broker: + path: "rasa_event.log" + type: file \ No newline at end of file From 3e97315ae71fc931a56160f54a5c263437c38e1b Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 16:46:21 +0100 Subject: [PATCH 43/57] added missing line endings --- data/test_endpoints/event_brokers/file_endpoint.yml | 2 +- data/test_endpoints/event_brokers/pika_endpoint.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/test_endpoints/event_brokers/file_endpoint.yml b/data/test_endpoints/event_brokers/file_endpoint.yml index a0beff44783..13c7002f397 100644 --- a/data/test_endpoints/event_brokers/file_endpoint.yml +++ b/data/test_endpoints/event_brokers/file_endpoint.yml @@ -1,3 +1,3 @@ event_broker: path: "rasa_event.log" - type: file \ No newline at end of file + type: file diff --git a/data/test_endpoints/event_brokers/pika_endpoint.yml b/data/test_endpoints/event_brokers/pika_endpoint.yml index 1b1ae725301..9c23e6c3dff 100644 --- a/data/test_endpoints/event_brokers/pika_endpoint.yml +++ b/data/test_endpoints/event_brokers/pika_endpoint.yml @@ -3,4 +3,4 @@ event_broker: username: username password: password queue: queue - type: pika \ No newline at end of file + type: pika From a4458729f87ce1d6755e6ee2bcc1d03bec468fcd Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 16:53:10 +0100 Subject: [PATCH 44/57] removed outdated changelog entries --- CHANGELOG.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e3af23ef076..83a2678401b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,11 +31,9 @@ Changed and only on master and branches ending in ``.x`` (i.e. new version releases) - renamed ``train_dialogue_model`` to ``train`` - renamed ``rasa_core.evaluate`` to ``rasa_core.test`` -- changed export paths for interactive training to ``data/core/stories.md``, - ``data/nlu/nlu.md`` and ``data/nlu/nlu_interactive.md`` - ``event_broker.publish`` receives the event as a dict instead of text - configuration key ``store_type`` of the tracker store endpoint configuration - has been renamed to ``type`` to allow usage accross endpoints + has been renamed to ``type`` to allow usage across endpoints - renamed ``policy_metadata.json`` to ``metadata.json`` for persisted models - ``scores`` array returned by the ``/conversations/{sender_id}/predict`` endpoint is now sorted according to the actions' scores. From fd77ce8f9005cdb0375b68981fef7532048caf2b Mon Sep 17 00:00:00 2001 From: Tobias Wochinger Date: Wed, 6 Mar 2019 16:53:32 +0100 Subject: [PATCH 45/57] Update docs/_static/spec/server.yml Co-Authored-By: tmbo --- docs/_static/spec/server.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/spec/server.yml b/docs/_static/spec/server.yml index 1a2e2fbcd91..13972c03d0b 100644 --- a/docs/_static/spec/server.yml +++ b/docs/_static/spec/server.yml @@ -698,7 +698,7 @@ paths: properties: q: type: string - description: Message to ne parsed + description: Message to be parsed example: q: "Hello, I am Rasa!" responses: From 329ec665e64f598f20f28612c42e331803a84834 Mon Sep 17 00:00:00 2001 From: Tobias Wochinger Date: Wed, 6 Mar 2019 16:53:55 +0100 Subject: [PATCH 46/57] Update docs/_static/spec/server.yml Co-Authored-By: tmbo --- docs/_static/spec/server.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/spec/server.yml b/docs/_static/spec/server.yml index 13972c03d0b..7597d5bb719 100644 --- a/docs/_static/spec/server.yml +++ b/docs/_static/spec/server.yml @@ -682,7 +682,7 @@ paths: - JWT: [] tags: - Model - summary: Parse a message and run the NLU model + summary: Parse a message using the loaded NLU model description: >- Predicts the intent and entities of the message posted to this endpoint. No messages will be stored From e41b7212c704142c5f89195d42f4235dcb9318ca Mon Sep 17 00:00:00 2001 From: Tobias Wochinger Date: Wed, 6 Mar 2019 17:02:07 +0100 Subject: [PATCH 47/57] Apply suggestions from code review Co-Authored-By: tmbo --- rasa_core/agent.py | 4 ++-- rasa_core/broker.py | 12 ++++++------ rasa_core/tracker_store.py | 2 +- rasa_core/utils.py | 2 +- tests/test_broker.py | 6 ++---- tests/test_server.py | 1 - 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/rasa_core/agent.py b/rasa_core/agent.py index eaf435e721a..219eeed1ecb 100644 --- a/rasa_core/agent.py +++ b/rasa_core/agent.py @@ -83,7 +83,7 @@ def _init_model_from_server(model_server: EndpointConfig return fingerprint, model_directory -def _is_stack_model(model_directory: Text): +def _is_stack_model(model_directory: Text) -> bool: """Decide whether a persisted model is a stack or a core model.""" return os.path.exists(os.path.join(model_directory, "fingerprint.json")) @@ -244,7 +244,7 @@ def update_model(self, self.policy_ensemble = policy_ensemble if interpreter: - self.interpreter = interpreter + self.interpreter = NaturalLanguageInterpreter.create(interpreter) self._set_fingerprint(fingerprint) diff --git a/rasa_core/broker.py b/rasa_core/broker.py index 5e491ee59fb..2239c9070bb 100644 --- a/rasa_core/broker.py +++ b/rasa_core/broker.py @@ -16,7 +16,7 @@ def load_event_channel_from_module_string(broker_config: EndpointConfig event_channel = class_from_module_path(broker_config.type) return event_channel.from_endpoint_config(broker_config) except (AttributeError, ImportError): - logger.warning("EventChannel type {} not found. " + logger.warning("EventChannel type '{}' not found. " "Not using any event channel." .format(broker_config.type)) return None @@ -98,12 +98,12 @@ class FileProducer(EventChannel): DEFAULT_LOG_FILE_NAME = "rasa_event.log" - def __init__(self, path=None) -> None: - self.path = path + def __init__(self, path: Optional[Text] = None) -> None: + self.path = path or self.DEFAULT_LOG_FILE_NAME self.event_logger = self._event_logger(path) @classmethod - def from_endpoint_config(cls, broker_config) -> Optional['FileProducer']: + def from_endpoint_config(cls, broker_config: Optional['EndpointConfig']) -> Optional['FileProducer']: if broker_config is None: return None @@ -111,7 +111,7 @@ def from_endpoint_config(cls, broker_config) -> Optional['FileProducer']: return cls(**broker_config.kwargs) def _event_logger(self, file_name): - """Instantiate the file logger""" + """Instantiate the file logger.""" logger_file = file_name or self.DEFAULT_LOG_FILE_NAME # noinspection PyTypeChecker @@ -126,7 +126,7 @@ def _event_logger(self, file_name): return query_logger - def publish(self, event): + def publish(self, event: Dict) -> None: """Write event to file.""" self.event_logger.info(json.dumps(event)) diff --git a/rasa_core/tracker_store.py b/rasa_core/tracker_store.py index c1f33a2b55a..c3bb2fcbc56 100644 --- a/rasa_core/tracker_store.py +++ b/rasa_core/tracker_store.py @@ -47,7 +47,7 @@ def load_tracker_from_module_string(domain, store): try: custom_tracker = class_from_module_path(store.type) except (AttributeError, ImportError): - logger.warning("Store type {} not found. " + logger.warning("Store type '{}' not found. " "Using InMemoryTrackerStore instead" .format(store.type)) diff --git a/rasa_core/utils.py b/rasa_core/utils.py index b20d025f9f6..7d740e32fd2 100644 --- a/rasa_core/utils.py +++ b/rasa_core/utils.py @@ -399,7 +399,7 @@ def zip_folder(folder): return shutil.make_archive(zipped_path.name, str("zip"), folder) -def unarchive(byte_array: bytes, directory: Text): +def unarchive(byte_array: bytes, directory: Text) -> Text: """Tries to unpack a byte array interpreting it as an archive. Tries to use tar first to unpack, if that fails, zip will be used.""" diff --git a/tests/test_broker.py b/tests/test_broker.py index 47d5785fca1..66cbdd47793 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -33,8 +33,8 @@ def test_no_broker_in_config(): def test_file_broker_from_config(): - cfg = utils.read_endpoint_config('data/test_endpoints/event_brokers/' - 'file_endpoint.yml', + cfg = utils.read_endpoint_config("data/test_endpoints/event_brokers/" + "file_endpoint.yml", "event_broker") actual = broker.from_endpoint_config(cfg) @@ -48,7 +48,6 @@ def test_file_broker_logs_to_file(tmpdir): actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", "path": fname})) - assert isinstance(actual, FileProducer) for e in TEST_EVENTS: actual.publish(e.as_dict()) @@ -68,7 +67,6 @@ def test_file_broker_properly_logs_newlines(tmpdir): actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", "path": fname})) - assert isinstance(actual, FileProducer) event_with_newline = UserUttered("hello \n there") diff --git a/tests/test_server.py b/tests/test_server.py index 90775782140..042c5be0629 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -105,7 +105,6 @@ def test_parse(app): data=data, content_type='application/json') content = response.get_json() assert response.status_code == 200 - print(content) assert content == { 'entities': [ {'end': 22, 'entity': 'name', 'start': 6, 'value': 'Rasa'}], From 7244b1aa9089165072f06e846cb2ffb38d1f8393 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 17:04:12 +0100 Subject: [PATCH 48/57] more improvements --- rasa_core/agent.py | 2 +- rasa_core/broker.py | 43 ++++++++++++++++++++++--------------------- rasa_core/server.py | 5 +++-- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/rasa_core/agent.py b/rasa_core/agent.py index 219eeed1ecb..81dccc143f4 100644 --- a/rasa_core/agent.py +++ b/rasa_core/agent.py @@ -173,7 +173,7 @@ def _pull_model_and_fingerprint(model_server: EndpointConfig, return None utils.unarchive(response.content, model_directory) - logger.debug("Unzipped model to {}" + logger.debug("Unzipped model to '{}'" "".format(os.path.abspath(model_directory))) # get the new fingerprint diff --git a/rasa_core/broker.py b/rasa_core/broker.py index 2239c9070bb..c17b2e08041 100644 --- a/rasa_core/broker.py +++ b/rasa_core/broker.py @@ -8,20 +8,6 @@ logger = logging.getLogger(__name__) -def load_event_channel_from_module_string(broker_config: EndpointConfig - ) -> Optional['EventChannel']: - """Instantiate an event channel based on its class name.""" - - try: - event_channel = class_from_module_path(broker_config.type) - return event_channel.from_endpoint_config(broker_config) - except (AttributeError, ImportError): - logger.warning("EventChannel type '{}' not found. " - "Not using any event channel." - .format(broker_config.type)) - return None - - def from_endpoint_config(broker_config: Optional[EndpointConfig] ) -> Optional['EventChannel']: """Instantiate an event channel based on its configuration.""" @@ -36,6 +22,20 @@ def from_endpoint_config(broker_config: Optional[EndpointConfig] return load_event_channel_from_module_string(broker_config) +def load_event_channel_from_module_string(broker_config: EndpointConfig + ) -> Optional['EventChannel']: + """Instantiate an event channel based on its class name.""" + + try: + event_channel = class_from_module_path(broker_config.type) + return event_channel.from_endpoint_config(broker_config) + except (AttributeError, ImportError) as e: + logger.warning("EventChannel type '{}' not found. " + "Not using any event channel. Error: {}" + .format(broker_config.type, e)) + return None + + class EventChannel(object): @classmethod def from_endpoint_config(cls, broker_config: EndpointConfig @@ -100,27 +100,28 @@ class FileProducer(EventChannel): def __init__(self, path: Optional[Text] = None) -> None: self.path = path or self.DEFAULT_LOG_FILE_NAME - self.event_logger = self._event_logger(path) + self.event_logger = self._event_logger() @classmethod - def from_endpoint_config(cls, broker_config: Optional['EndpointConfig']) -> Optional['FileProducer']: + def from_endpoint_config(cls, broker_config: Optional['EndpointConfig'] + ) -> Optional['FileProducer']: if broker_config is None: return None # noinspection PyArgumentList return cls(**broker_config.kwargs) - def _event_logger(self, file_name): + def _event_logger(self): """Instantiate the file logger.""" - logger_file = file_name or self.DEFAULT_LOG_FILE_NAME + logger_file = self.path # noinspection PyTypeChecker query_logger = logging.getLogger('event-logger') query_logger.setLevel(logging.INFO) - ch = logging.FileHandler(logger_file) - ch.setFormatter(logging.Formatter('%(message)s')) + handler = logging.FileHandler(logger_file) + handler.setFormatter(logging.Formatter('%(message)s')) query_logger.propagate = False - query_logger.addHandler(ch) + query_logger.addHandler(handler) logger.info("Logging events to '{}'.".format(logger_file)) diff --git a/rasa_core/server.py b/rasa_core/server.py index c4a6f598ff3..2528e17e993 100644 --- a/rasa_core/server.py +++ b/rasa_core/server.py @@ -618,8 +618,9 @@ def tracker_predict(): @cross_origin(origins=cors_origins) @ensure_loaded_agent(agent) def parse(): - request_params = request.get_json() - return jsonify(agent.interpreter.parse(request_params.get("q"))) + request_params = request.get_json(force=True) + parse_data = agent.interpreter.parse(request_params.get("q")) + return jsonify(parse_data) return app From 6135b64bcfd6d69307513c0dd9d3dfac923d70b6 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 17:27:42 +0100 Subject: [PATCH 49/57] use proper sdk & nlu versions --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4bb08f80b1b..6c27eed3f8f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ coloredlogs==10.0 flask==1.0.2 flask_cors==3.0.7 scikit-learn==0.20.2 -rasa_nlu~=0.15.0a1 +rasa_nlu~=0.15.0a4 slackclient==1.3.0 python-telegram-bot==11.1.0 twilio==6.23.0 @@ -29,7 +29,7 @@ jsonschema==2.6.0 packaging==18.0 gevent==1.4.0 pytz==2018.9 -rasa_core_sdk~=0.13 +rasa_core_sdk~=0.13.0a1 pymongo==3.7.2 python-dateutil==2.7.5 rocketchat_API==0.6.25 From 1d0cfa673af839d6f60c6190049c7d548a87ce5f Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 17:30:40 +0100 Subject: [PATCH 50/57] removed to many empty lines --- tests/test_broker.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_broker.py b/tests/test_broker.py index 66cbdd47793..69fecd5664b 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -48,7 +48,6 @@ def test_file_broker_logs_to_file(tmpdir): actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", "path": fname})) - for e in TEST_EVENTS: actual.publish(e.as_dict()) @@ -67,7 +66,6 @@ def test_file_broker_properly_logs_newlines(tmpdir): actual = broker.from_endpoint_config(EndpointConfig(**{"type": "file", "path": fname})) - event_with_newline = UserUttered("hello \n there") actual.publish(event_with_newline.as_dict()) From 5f87b6da2b5fd20446fb3ecde8a7ccc77884585f Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 17:33:20 +0100 Subject: [PATCH 51/57] added comments about backwards compatibility --- rasa_core/events/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rasa_core/events/__init__.py b/rasa_core/events/__init__.py index c301b10e191..5eeed59ce85 100644 --- a/rasa_core/events/__init__.py +++ b/rasa_core/events/__init__.py @@ -151,7 +151,7 @@ def _from_parameters(cls, parameters): @staticmethod def resolve_by_type( type_name: Text, - default: Optional[Text] = None + default: Optional[Type['Event']] = None ) -> Optional[Type['Event']]: """Returns a slots class by its type name.""" @@ -229,7 +229,7 @@ def empty(): def as_dict(self): d = super(UserUttered, self).as_dict() - input_channel = None + input_channel = None # for backwards compatibility (persisted evemts) if hasattr(self, "input_channel"): input_channel = self.input_channel d.update({ @@ -762,7 +762,7 @@ def _from_story_string( def as_dict(self): d = super(ActionExecuted, self).as_dict() - policy = None + policy = None # for backwards compatibility (persisted evemts) if hasattr(self, "policy"): policy = self.policy confidence = None From cfb4f197e50ff5ffdc2999b7dbbb45497b7932d6 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 17:54:47 +0100 Subject: [PATCH 52/57] added test to check tracker store properly recovers max history --- tests/test_tracker_stores.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_tracker_stores.py b/tests/test_tracker_stores.py index 16012c7cada..93c470bf2ed 100644 --- a/tests/test_tracker_stores.py +++ b/tests/test_tracker_stores.py @@ -6,6 +6,7 @@ TrackerStore, InMemoryTrackerStore, RedisTrackerStore) +from rasa_core.trackers import DialogueStateTracker from rasa_core.utils import EndpointConfig from tests.conftest import DEFAULT_ENDPOINTS_FILE @@ -45,6 +46,16 @@ def test_restart_after_retrieval_from_tracker_store(default_domain): assert latest_restart == latest_restart_after_loading +def test_tracker_store_remembers_max_history(default_domain): + store = InMemoryTrackerStore(default_domain) + tr = store.get_or_create_tracker("myuser", max_event_history=42) + tr.update(Restarted()) + + store.save(tr) + tr2 = store.retrieve("myuser") + assert tr._max_event_history == tr2._max_event_history == 42 + + def test_tracker_store_endpoint_config_loading(): cfg = utils.read_endpoint_config(DEFAULT_ENDPOINTS_FILE, "tracker_store") From 086af11776567f256143d0574920cd8e1704759e Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 18:00:32 +0100 Subject: [PATCH 53/57] fixed specification --- docs/_static/spec/server.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/docs/_static/spec/server.yml b/docs/_static/spec/server.yml index 7597d5bb719..c7bdca7bccd 100644 --- a/docs/_static/spec/server.yml +++ b/docs/_static/spec/server.yml @@ -708,21 +708,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ParseData' - examples: - text: "Hello, I am Rasa!" - entities: - - start: 12 - end: 16 - entity: name - value: Rasa - intent: - confidence: 0.87 - name: greet - intent_ranking: - - confidence: 0.87 - name: greet - - confidence: 0.13 - name: goodbye 403: $ref: '#/components/responses/403Permissions' From 96d0172dea8bef61f742f65f3961a87332f9dba3 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 18:07:40 +0100 Subject: [PATCH 54/57] fixed pep8 --- tests/test_tracker_stores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tracker_stores.py b/tests/test_tracker_stores.py index 93c470bf2ed..470e3f25cb3 100644 --- a/tests/test_tracker_stores.py +++ b/tests/test_tracker_stores.py @@ -48,7 +48,7 @@ def test_restart_after_retrieval_from_tracker_store(default_domain): def test_tracker_store_remembers_max_history(default_domain): store = InMemoryTrackerStore(default_domain) - tr = store.get_or_create_tracker("myuser", max_event_history=42) + tr = store.get_or_create_tracker("myuser", max_event_history=42) tr.update(Restarted()) store.save(tr) From fd3a7dd06b3ffd9bf3fc80c259b2590fa9a9d07e Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 18:25:58 +0100 Subject: [PATCH 55/57] Update version.py --- rasa_core/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/version.py b/rasa_core/version.py index 6d886b9fa79..c1d5be236f8 100644 --- a/rasa_core/version.py +++ b/rasa_core/version.py @@ -1 +1 @@ -__version__ = '0.14.0a2' +__version__ = '0.14.0a3' From 2872c9a2228eeb6e31ab5a1b4fda3ec911bd9cef Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 18:26:18 +0100 Subject: [PATCH 56/57] Update constants.py --- rasa_core/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rasa_core/constants.py b/rasa_core/constants.py index 396d4766dae..42db4b97cb7 100644 --- a/rasa_core/constants.py +++ b/rasa_core/constants.py @@ -4,7 +4,7 @@ DEFAULT_SERVER_URL = DEFAULT_SERVER_FORMAT.format(DEFAULT_SERVER_PORT) -MINIMUM_COMPATIBLE_VERSION = "0.14.0a1" +MINIMUM_COMPATIBLE_VERSION = "0.14.0a3" DOCS_BASE_URL = "https://rasa.com/docs/core" From 7377440ac3e2669c65b8220dbd7b8c7cce9798b6 Mon Sep 17 00:00:00 2001 From: Tom Bocklisch Date: Wed, 6 Mar 2019 19:09:36 +0100 Subject: [PATCH 57/57] fixed docs --- docs/brokers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/brokers.rst b/docs/brokers.rst index 9fff5248fb5..852ff77d9dd 100644 --- a/docs/brokers.rst +++ b/docs/brokers.rst @@ -21,7 +21,7 @@ You can use an endpoint configuration file to instruct Rasa Core to stream all events to your event broker. To do so, add the following section to your endpoint configuration, e.g. ``endpoints.yml``: -.. literalinclude:: ../data/test_endpoints/event_broker_endpoint.yml +.. literalinclude:: ../data/test_endpoints/event_brokers/pika_endpoint.yml Then instruct Rasa Core to use the endpoint configuration by adding ``--endpoints