Running API calls within FormPolicy

Hola!

I developed a scheduling bot (we call her Maria Luisa) that calls Google Calendar to make appointments at a centro de estética (dermatology, flebology,…etc) and it works! Each appointment requires five pieces of information from users: name, DNI (Argentine identification number), email, medical specialization (i.e. dermatology) and appointment time.

The two API calls I have to make, one for appointment times and the other for medical specialization, happen outside my Form Action. The other info is asked for using the form action. Is there a way to make this API call inside the form action?

The only way I know how to utter using Form Policy is by using this utter_ask{} format in domain.yml. Can I make those form utters using info from an API call?

Best!

PS. I looooove Rasa, and everything you guys do. Making new versions now with DIET and it has increased my accuracy more than 25%!!! :exploding_head:

Can’t you use required_slots function for calling your api before asking a slot? You would have to check which slot is empty now to understand which call you should make. You can read more in the Form docs and Tracker docs, what you will need is tracker.get_slot('name').

1 Like

Thanks @gsp0din! I assume that was a rhetorical question when you ask “Can’t you use required_slots function for calling your api before asking a slot?”, or were you genuinely asking?

It would be great and it seems feasible, but there is definately a gap in my understanding of how tracker is working. I’m sure if I study up I can figure it out. I could create buttons in there too, no?

You may add any kind of message to the bot from within your form action, wherever you have access to the dispatcher via dispatcher.utter_message(...)

Anyway, I dont really understand the purpose of the API calls yet. Can you give an example dialog? But dont worry, its possible for sure. We’ve been succesfully implementing way more complex stuff in our (Form-)Actions.

1 Like

Indeed it was. Probably, it might be hard to understand tracker and dispatcher stuff at first sight, but it should be useful in the end. Regarding buttons, I had to look through the source code, but probably somewhere you can see how to set up buttons in dispatcher.utter_message as mentioned above.

1 Like

Hi @bubjanes!

I think you can override the request_next_slot method of the FormAction. This is how the original definition looks:

def request_next_slot(
        self,
        dispatcher: "CollectingDispatcher",
        tracker: "Tracker",
        domain: Dict[Text, Any],
    ) -> Optional[List[EventType]]:
        """Request the next slot and utter template if needed,
            else return None"""

        for slot in self.required_slots(tracker):
            if self._should_request_slot(tracker, slot):
                logger.debug(f"Request next slot '{slot}'")
                dispatcher.utter_message(template=f"utter_ask_{slot}", **tracker.slots)
                return [SlotSet(REQUESTED_SLOT, slot)]

        # no more required slots to fill
        return None

See the line dispatcher.utter_message(template=f"utter_ask_{slot}", **tracker.slots). You can easily check the name of the requested_slot here and make your API calls accordingly and then utter whatever you want.

Hope that hepls.

1 Like

Hi @IgNoRaNt23! Thanks so much for your reply. I am starting to understand.

You asked to see an example dialogue. If I can just get action_agendar_turno and action_offer_dates inside the form action, my assistant would be a lot more fool proof. Here’s the story for my happy path:

Happy Path (full)

* greet
    - utter_greet
* consulta_services_type
    - action_agendar_turno    ## API call 1 verifies which "services" have available appointments 
* inform{"service": "estética"}
    - slot{"service": "estética"}
    - action_offer_dates      ## API call 2 provides the times of available appointments 
    - slot{"calendar_id": "amg4rsh4rn4dcsdo4fdb4sgu44@group.calendar.google.com"}
    - slot{"fechas_dict": {"15/01/2020 a las 04:00 hrs": "2020-01-15T04:00:00-03:00", "16/01/2020 a las 04:00 hrs": "2020-01-16T04:00:00-03:00", "17/01/2020 a las 00:30 hrs": "2020-01-17T00:30:00-03:00", "17/01/2020 a las 04:00 hrs": "2020-01-17T04:00:00-03:00"}}
* inform{"start_time": "2020-01-17T04:00:00-03:00"}
    - slot{"start_time": "2020-01-17T04:00:00-03:00"}
    - turno_form ## Form Action begins here ####################
    - form{"name": "turno_form"}
    - slot{"requested_slot": "name"}
* form: inform{"name": "esteban garcia"}
    - slot{"name": "esteban garcia"}
    - form: turno_form
    - slot{"name": "esteban garcia"}
    - slot{"requested_slot": "dni"}
* form: inform{"dni": "77.444.597"}
    - slot{"dni": "77.444.597"}
    - form: turno_form
    - slot{"dni": "77.444.597"}
    - slot{"requested_slot": "email"}
* form: inform{"email": "XXXX@gmail.com"}
    - slot{"email": "XXXX@gmail.com"}
    - form: turno_form
    - slot{"email": "XXXX@gmail.com"}
    - slot{"readable": "17/01/2020 a las 04:00 hrs"}
    - form{"name": null}
    - slot{"requested_slot": null}
* affirm
    - action_update_calendar
* thanks
    - utter_algo_mas

I was thinking about something like this on a way less abstract level

User: Hi

Bot: Hi, what you want to do?

User: XYZ

But if I understand correcty, you want to ask a user for a date for example and give possible choices as buttons?

Hola @IgNoRaNt23 ! The happy path looks something like this:

User: I want to make an appointment. (I want to start my form here)
Bot: Here are our available services: (API call 1 to fill buttons)
User: I choose dermatology.
Bot: Here are the dates available: (API call 2 uses buttons)
User: I’ll try 24/04/2020 a las 10:00 hrs
Bot: Your name please.
User: Esteban Garcia
Bot: Provide your DNI please.
User: 77.444.597
Bot: Your email address please.
User: name@gmail.com
Bot: Thanks! We have the following information for your appointment. Respond by saying “yes” or click the button for the info you would like to change.
Buttons: Esteban Garcia, 24/04/2020 a las 10:00 hrs, Dermatology, 77.444.579, name@gmail.com
User: Yes!
Bot: Thank you! Your dermatology appointment for Esteban Garcia is confirmed for 24/04/2020 a las 10:00 hrs.
User: Thanks!

If you can write in Spanish, you can make an appointment on your own by trying out the demo (the front is pretty ugly but we are working on a new version); not offended if you don’t. Jajaja.

Thanks again for the help!

Ok, like I thought.

So for this to work you will need to overwrite the requested slot method:

and call your API from there. The dispatcher.utter_message-method has an optional argument buttons, where you hand over a list of dictionaries (one for each button) with 2 keys, title and payload. Title is the text that appears on the button and payload is the text, that is entered for the user.

Ok, to go from there?

1 Like

Wonderful @IgNoRaNt23 ! Thanks so much everybody!

Hi, I am having a similar problem, and I am new to the rasa ecosystem. Can you explain to me a little more how would he need to overwrite the request next slot? Would it be needed to be re-define in actions.py? Any help is very appreciated it. Thank you

Just re-define that function in your custom FormAction-class just like you do it for the other methods.

See

1 Like