From action ask user to choose item from list

Hi I want to create a form which asks the user to choose a value from a list. This list is dynamic and is retrieved from another python call.

The flow would be something like this:

user: “Select filter”
background → retrieves list of filter options
bot: “These are the available filters:
1) country
2) date
…”
user: “by country please”
background → sets filter

I can get the flow to set the slots (as I´ve given it some examples) but I cannot get the bot to print the list of filters to the user. I believe its something to do with my action or story. Tbh I´m unsure how I should set up the story for a flow like this.

ACTION:

import requests
import json

from typing import Any, Text, Dict, List
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk import Action
from rasa_sdk.events import SlotSet


class ActionSelectFilters(Action):

    def name(self) -> Text:
        return "action_select_filters"

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

        URL = 'http://localhost:8082/process'
        HEADERS = {'content-type': 'application/json', 'charset': 'UTF-8'}

        # Retrieve slots
        selected_filter = tracker.get_slot("filter")

        data = {
            "action": "select_filter",
            "filter": selected_filter
        }

        try:
            if selected_filter is None:  # No filter specified
                r = requests.post(url=URL, headers=HEADERS, json=data, verify=False)
                output = json.loads(r.text)

                dispatcher.utter_message(response="utter_ask_for_filter")
                dispatcher.utter_message(response="\n".join(output["filter"]))

                return [SlotSet("filter", None)]

            else:  # Filter specified
                r = requests.post(url=URL, headers=HEADERS, json=data, verify=False)
                output = json.loads(r.text)

            if output and "type" in output and output["type"] == "error":
                print(f"Received exception from web service: {output['message']}")
                return []  # Finished --> error
            elif output["complete"]:
                dispatcher.utter_message(response="utter_filter_set")
                return []  # Finished

        except Exception as ex:
            print(f"Exception received: {ex}")

You’re on the right track :slight_smile: Just read Using a Custom Action to Ask For the Next Slot.

Basically, if you’re inside a form, you can use action_ask_myslot instead of utter_ask_myslot to make it dynamic.

I also suggest using buttons instead of displaying the options as text, it’s easier for both the user and the developer: The user will just have to click a button, while you can make sure the input (intent & entities) are forced by the buttons instead of guessed.

Also, you have a typo in utter_message, it should be response and not responce.


Assuming in your code, output["filter"] gives 'country\ndate\n...', you can create buttons as such:

if selected_filter is None:  # No filter specified
    r = requests.post(url=URL, headers=HEADERS, json=data, verify=False)
    output = json.loads(r.text)
    buttons = []

    for item in output["filter"]:
        buttons.append({
            'payload': '/inform{"filter": "' + item +'"}',
            'title': item
        })

    dispatcher.utter_message(
        text = "These are the available filters",
        buttons = buttons
    )

    return [SlotSet("filter", None)]
1 Like

Hi Chris, Thanks for the fast reply. Ok I have corrected my typo … whoops :sweat_smile: :joy:

I´ll give that a read and see if it helps, thank you!

(Due to the nature of the bot I cannot use buttons)

1 Like

Hi @ChrisRahme, So it solved the problem, somewhat. It is now responding to me with the list but it is resetting the slots after launching.

LARGE EDIT (deleted the rest)

I ended up redoing the whole thing in a new form and it worked a treat! Thanks Chris

1 Like

Awesome :slight_smile: Glad to be of help