From 55c33734ea900e4ace5c9f8229ba0df00e35da85 Mon Sep 17 00:00:00 2001 From: melindaloubser1 Date: Wed, 16 Sep 2020 17:14:14 +0200 Subject: [PATCH] reminder updates --- .typo-ci.yml | 3 + docs/docs/reaching-out-to-user.mdx | 263 +++++++++++------------- examples/reminderbot/actions/actions.py | 2 +- examples/reminderbot/domain.yml | 3 + 4 files changed, 129 insertions(+), 142 deletions(-) diff --git a/.typo-ci.yml b/.typo-ci.yml index fe64b206776b..d8bda1eb8a4f 100644 --- a/.typo-ci.yml +++ b/.typo-ci.yml @@ -186,5 +186,8 @@ excluded_words: - memoizationpolicy - NLG - nlg + - Juste + - Tanja + - Vova spellcheck_filenames: false diff --git a/docs/docs/reaching-out-to-user.mdx b/docs/docs/reaching-out-to-user.mdx index 3057423fc012..b33faef274d6 100644 --- a/docs/docs/reaching-out-to-user.mdx +++ b/docs/docs/reaching-out-to-user.mdx @@ -55,7 +55,7 @@ responses: - text: Hi there! What can I help you with today? ``` -## External Events +## A Step-by-Step guide to External Events Sometimes you want an external device to change the course of an ongoing conversation. For example, if you have a moisture-sensor attached to a Raspberry Pi, you could use it to notify @@ -63,9 +63,8 @@ you when a plant needs watering via your assistant. The examples below are from the [reminderbot example bot](https://github.com/RasaHQ/rasa/blob/master/examples/reminderbot), which includes both reminders and external events. -You can clone it and follow the instructions in README.md to try out the full version. -### Using the `trigger_intent` Endpoint +### 1. Using the `trigger_intent` Endpoint To have an event from an external device change the course of an ongoing conversation, you can have the device post to the @@ -86,43 +85,11 @@ curl -H "Content-Type: application/json" -X POST \ #### Getting the Conversation ID -To have an external device post to the `trigger_intent` endpoint, you need the conversation ID of the ongoing conversation. -To try it out locally, you can define a custom action `action_tell_id` to tell you -the conversation ID, and then use it in the POST request to the `trigger_intent` endpoint: - -```python -class ActionTellID(Action): - """Informs the user about the conversation ID.""" - - def name(self) -> Text: - return "action_tell_id" - - async def run( - self, dispatcher, tracker: Tracker, domain: Dict[Text, Any] - ) -> List[Dict[Text, Any]]: - - conversation_id = tracker.sender_id - - dispatcher.utter_message( - f"The ID of this conversation is: " f"{conversation_id}." - ) - - dispatcher.utter_message( - f"Trigger an intent with " - f'curl -H "Content-Type: application/json" ' - f'-X POST -d \'{{"name": "EXTERNAL_dry_plant", ' - f'"entities": {{"plant": "Orchid"}}}}\' ' - f"http://localhost:5005/conversations/{conversation_id}/" - f"trigger_intent" - ) - - return [] -``` - -In a real-life scenario, your external device would get hold of the conversation ID some other way. +In a real-life scenario, your external device would get the conversation ID from an API or a database. In the dry plant example, you might have a database of plants, the users that water them, and the users' conversation IDs. Your Raspberry Pi would get the conversation ID directly from the database. - +To try out the reminderbot example locally, you'll need to get the conversation ID manually. See +the reminderbot [README](https://github.com/RasaHQ/rasa/blob/master/examples/reminderbot for more information. ### Defining the Training Data @@ -130,27 +97,15 @@ conversation IDs. Your Raspberry Pi would get the conversation ID directly from In the dry plant example, your Raspberry Pi needs to send a message with the intent `EXTERNAL_dry_plant` to the `trigger_intent` endpoint. This intent will be reserved for use by the Raspberry Pi, so -there won't be any NLU training examples for it. You'll also need to define an intent to get the conversation ID -for the POST request. You can add NLU training examples for this intent if you want, or you can just add the intent -and trigger it by entering `/ask_id`: +there won't be any NLU training examples for it. ```rasa-yaml intents: - EXTERNAL_dry_plant - - ask_id - -nlu: - - intent: ask_id - examples: | - - what's the conversation id? - - id - - What is the ID of this conversation? - - How do I send a POST request to this conversation? ``` :::note -It is recommended -to name intents that come from other devices with the `EXTERNAL_` prefix because it makes it +You should name intents that come from other devices with the `EXTERNAL_` prefix because it makes it easier to see which intents are expected to come from external devices when working with your training data. ::: @@ -168,14 +123,9 @@ slots: #### Rules and Actions -You'll need two rules for the dry plant example: one to get the conversation ID back, and one -that tells your assistant how to respond when it receives a message from the Raspberry Pi. +You'll need a rule that tells your assistant how to respond when it receives a message from the Raspberry Pi. ```rasa-yaml -- rule: conversation id - steps: - - intent: ask_id - - action: action_tell_id rules: - rule: warn about dry plant steps: @@ -183,13 +133,6 @@ rules: - action: utter_warn_dry ``` -You'll need to add your custom action for telling the conversation ID to the domain too: - -```rasa-yaml -actions: - - action_tell_id -``` - #### Responses You'll need to define the response text for `utter_warn_dry`: @@ -214,41 +157,40 @@ See the [reminderbot README](https://github.com/RasaHQ/rasa/blob/master/examples for instructions on how to test your reminders locally. ::: -You'll also need to start the action server, since you need a custom action to tell you your conversation ID. - -Once you have retrained your model with the data above, you can try it out by -getting the conversation ID back from the assistant: +Run this POST request to simulate the external event, using your conversation ID: -```yaml -User: /ask_id - Bot: The ID of this conversation is user1234. - Trigger an intent with - curl -H "Content-Type: application/json" -X POST -d - '{"name": "EXTERNAL_dry_plant", "entities": {"plant": "Orchid"}}' - "http://localhost:5005/conversations/user1234/trigger_intent?output_channel=latest" +```shell +curl -H "Content-Type: application/json" -X POST -d \ +'{"name": "EXTERNAL_dry_plant", "entities": {"plant": "Orchid"}}' \ +"http://localhost:5005/conversations/user1234/trigger_intent?output_channel=latest" ``` -By running the returned POST request, -you should see the bot respond in your channel: +You should see the bot respond in your channel: ```yaml Bot: Your Orchid needs some water! ``` -## Reminders +## A Step-by-Step Guide on Reminders -You can have your assistant reach out to the user after a set amount of time by using **reminders**. +You can have your assistant reach out to the user after a set amount of time by using [Reminders](https://rasa.com/docs/action-server/events#ReminderScheduled). The examples below are from the [reminderbot example bot](https://github.com/RasaHQ/rasa/blob/master/examples/reminderbot). You can clone it and follow the instructions in `README` to try out the full version. ### Scheduling Reminders +#### 1. Define a Reminder + To schedule a reminder, you need to define a custom action that returns -the ReminderScheduled` event. For example, the following custom action +the `ReminderScheduled` event. For example, the following custom action schedules a reminder for five seconds from now: ```python +import datetime +from rasa_sdk.events import ReminderScheduled +from rasa_sdk import Action + class ActionSetReminder(Action): """Schedules a reminder, supplied with the last message's entities.""" @@ -277,11 +219,10 @@ class ActionSetReminder(Action): return [reminder] ``` -Note that this action requires the `datetime` and `rasa_sdk.events` packages. The first argument for the `ReminderScheduled` event is the reminder's name, in this case, `EXTERNAL_reminder`. The reminder name will be used later as an intent to trigger a reaction to the reminder. -As with external events, it's recommended to name the reminder name with the +Name the reminder name with the `EXTERNAL_` prefix to make it easier to see what's going on in your training data. You can see that the last messages' `entities` are also passed to the reminder. @@ -292,9 +233,62 @@ For example, if you want your assistant to remind you to call a friend, you coul send it a message like "Remind me to call Paul". If "Paul" is extracted as a `PERSON` entity, the action reacting to the reminder can use it to say "Remember to call Paul!" +#### 2. Add a Rule + +To schedule a reminder, add a rule: + +``` +rules: +- rule: Schedule a reminder + steps: + - intent: ask_remind_call + entities: + - PERSON + - action: action_schedule_reminder +``` + + +#### 3. Add Training Data + +You should add NLU training examples for scheduling the reminder: + +```yaml-rasa +nlu: +- intent: ask_remind_call + examples: | + - remind me to call John + - later I have to call Alan + - Please, remind me to call Vova + - please remind me to call Tanja + - I must not forget to call Juste +``` + +You should also add it to your domain: + +```yaml-rasa +intents: + - ask_remind_call +``` + +#### 4. Update your Pipeline + +By adding SpacyNLP and SpacyEntityExtractor to your pipeline in config.yml, you won't need to annotate any of the +names in your training data, since Spacy has a `PERSON` dimension: + +```yaml-rasa +pipeline: +# other components +- SpacyNLP +- SpacyEntityExtractor + dimensions: ["PERSON"] +``` + + ### Reacting to Reminders -As with external events, the bot reaches out to the user after receiving a +#### 1. Define a Reaction + +The bot reaches out to the user after receiving a POST request to the `trigger_intent` endpoint. Reminders, however, send the request to the right conversation ID automatically after a certain amount of time using the name that you define in the `ReminderScheduled` event. @@ -320,21 +314,45 @@ class ActionReactToReminder(Action): domain: Dict[Text, Any], ) -> List[Dict[Text, Any]]: - name = next(tracker.get_latest_entity_values("PERSON"), "someone") + name = next(tracker.get_slot("PERSON"), "someone") dispatcher.utter_message(f"Remember to call {name}!") return [] ``` +#### 2. Add a Rule + +To tell your bot what action to run when a reminder is triggered, add a rule. + +```yaml-rasa +- rule: Trigger `action_react_to_reminder` for `EXTERNAL_reminder` + steps: + - intent: EXTERNAL_reminder + - action: action_react_to_reminder +``` + +#### 3. Add Training Data + +You'll need to define the intent that triggers reacting to the reminder. You don't need to add any training examples, +since the intent is reserved for the reminder. + +``` +intents: +- intent: EXTERNAL_reminder +``` + + ### Cancelling Reminders +#### 1. Define an Action that Cancels a Reminder + To cancel a reminder that you've already scheduled, you need a custom action that returns the `ReminderCancelled()` event. Returning `ReminderCancelled()` cancels all the reminders that are currently scheduled. If you only want to cancel certain reminders, you can specify some parameters by which to narrow down the scheduled reminders: -* `ReminderCancelled(intent="greet")` cancels all reminders with intent `greet` +* `ReminderCancelled(intent="EXTERNAL_greet")` cancels all reminders with intent `EXTERNAL_greet` * `ReminderCancelled(entities={})` cancels all reminders with the given entities @@ -367,34 +385,25 @@ class ForgetReminders(Action): All reminders are cancelled whenever you shutdown your Rasa server. ::: -### Defining the Training Data +#### 2. Add a Rule for Cancelling a Reminder -#### Intents and Entities - -You'll need to define an intent that triggers setting the reminder and one that triggers cancelling the reminder. -The `ReminderScheduled` event -will automatically send the intent `EXTERNAL_reminder` to your bot after the amount of time specified, -so you also need to add this intent to your intents. You don't need to add any training examples, -since the intent is reserved for the reminder. +You'll need to add a rule for cancelling a reminder. +```yaml-rasa +- rule: Cancel a reminder + steps: + - intent: ask_forget_reminders + - action: action_forget_reminders ``` -intents: -- intent: EXTERNAL_reminder -- intent: ask_remind_call -- intent: ask_forget_reminders -``` -You should add NLU training examples for scheduling and cancelling the reminder: + +#### 3. Add Training Data + +You'll need to define an intent that triggers cancelling the reminder. + ```yaml-rasa nlu: -- intent: ask_remind_call - examples: | - - remind me to call John - - later I have to call Alan - - Please, remind me to call Vova - - please remind me to call Tanja - - I must not forget to call Juste - intent: ask_forget_reminders examples: | - Forget about the reminder @@ -403,48 +412,20 @@ nlu: - cancel all reminders please ``` -By adding SpacyNLP and SpacyEntityExtractor to your pipeline in your config file, you won't need to annotate any of the -names in your training data, since Spacy has a `PERSON` dimension: - -```yaml-rasa -pipeline: -# other components -- SpacyNLP -- SpacyEntityExtractor - dimensions: ["PERSON"] +You should also add it to domain.yml: ``` - -#### Rules - -You'll need to add three rules: One for scheduling a reminder, one for your assistant reacting to a reminder, -and one for cancelling a reminder. - -```yaml-rasa -rules: -- rule: Schedule a reminder - steps: - - intent: ask_remind_call - entities: - - name - - action: action_schedule_reminder - -- rule: Trigger `action_react_to_reminder` for `EXTERNAL_reminder` - steps: - - intent: EXTERNAL_reminder - - action: action_react_to_reminder - -- rule: Cancel a reminder - steps: - - intent: ask_forget_reminders - - action: action_forget_reminders +intents: +- intent: ask_forget_reminders ``` + ### Try it Out -As with the external events, to try out reminders you'll need to start either [Rasa X](https://rasa.com/docs/rasa-x/) +To try out reminders you'll need to start either [Rasa X](https://rasa.com/docs/rasa-x/) or a [CallbackChannel](./connectors/your-own-website.mdx#callbackchannel). You'll also need to start the action server to schedule, react to, and cancel your reminders. +See the [reminderbot README](https://github.com/RasaHQ/rasa/blob/master/examples/reminderbot) for details. Then, if you send the bot a message like `Remind me to call Paul Pots`, you should get a reminder back five seconds later that says `Remember to call Paul Pots!`. diff --git a/examples/reminderbot/actions/actions.py b/examples/reminderbot/actions/actions.py index d14b8e9d85ec..3894e30b0f6b 100644 --- a/examples/reminderbot/actions/actions.py +++ b/examples/reminderbot/actions/actions.py @@ -58,7 +58,7 @@ async def run( domain: Dict[Text, Any], ) -> List[Dict[Text, Any]]: - name = next(tracker.get_latest_entity_values("PERSON"), "someone") + name = next(tracker.get_slot("PERSON"), "someone") dispatcher.utter_message(f"Remember to call {name}!") return [] diff --git a/examples/reminderbot/domain.yml b/examples/reminderbot/domain.yml index 8ec81608ab45..c851a6e39548 100644 --- a/examples/reminderbot/domain.yml +++ b/examples/reminderbot/domain.yml @@ -15,6 +15,9 @@ intents: entities: - PERSON - plant +slots: + PERSON: + type: unfeaturized responses: utter_what_can_do: - text: What can I do for you?