Dynamic buttons in Form Action

Hi All,

I came to know about Form Action through formbot example which I think is very helpful for me but I got an issue while dealing with the button. In my previous case, I defined various actions and added buttons in it and values of those buttons are extracted from API calling but in the formbot scenario action is called by utter_ask_{slot_name} for required slots only. For doing this I have to do buttons value static(because it is called through domain.yml) but I want to use buttons values dynamic(because of API calling). How can I do this in Form Action?

One more thing I want to know if I should use Form Action when I am taking input from user and after that validating each and every input taken from user.

@akelad @souvikg10 can you help me with this issue, I’ll be thankful to you.

Hi @abhishakskilrock you can override the request_next_slot function in your form action and specify how the bot should ask for the next slots

1 Like

For that I have to run my custom_actions through dispatcher like we do in dispatcher.utter_template for templates. Is there any method so that I can call custom_action through dispatcher?

you can also force a followup action with tracker.followup_action to do that.

Thanx @akelad I forgot to mention Resolved here. I used return[FollowupAction()] instead of tracker.followup_action.

Resolved!!!

can share the solution >?

When I return the slot Name.

return [FollowupAction('Name')]

I get this erorr

    if e['event'] == 'slot':
TypeError: 'FollowupAction' object is not subscriptable

and these

    tracker.followup_action('Name')
TypeError: 'NoneType' object is not callable

@akelad @Ghostvv

Example:

Bot: How may I assist you.
User: l want to book a restaurant.
Bot: May I know your name ?
Bot: May I know the location ?
 btn1(Location1), btn2(Location2), btn3(Location3)

I want to produce the dynamic button of locations. I do that. it has two reposes.

@azizullah2017 i’m not sure what you’re trying to do, could you clarify a little?

Can you show an example of how to override the request_next_slot function in order to make dynamic buttons inside FormAction?

I do not know what I am missing.
I am trying to unset the slot and force to listen.
@akelad @Ghostvv @amn41 @Tobias_Wochinger @erohmensing

i want force action_listen.
example:
bot: do you need something else?
user: yes.
bot: how may i help you?
user: ok. i need a fried fish.
bot: got it.
bot: do you need something else?

now it performing, does not wait for user:


now it is example:
bot: do you need something else?
user: yes.
bot: how may i help you?
bot: do you need something else?

def validate()...:

		for slot, value in slot_values.items():
			elif slot == 'extra_help':
				if value=='yes':
					dispatcher.utter_message('how may i help you?')
					return [SlotSet(slot, None),FollowupAction("action_listen")]
		return [SlotSet(slot, value) for slot, value in slot_values.items()]

Error

   if e["event"] == "slot":
if e["event"] == "slot":
TypeError: 'FollowupAction' object is not subscriptable

any update on this?i am also stuck in same issue?can you post the working code

Hi abhishakskilrock you can override the request_next_slot function in your form action and specify how the bot should ask for the next slots

@akelad Could you explain this a bit further? I can’t seem to find any code examples.

@ActuallyAcey what are you trying to do specifically?

By default, the form will ask the user for the next slot with a template utter_ask_{slot} (see code here). Say you wanted a custom action to ask that question instead or something, you would overwrite that function in your form class.

Thanks for responding, I did figure it out. I was looking to implement something very similar to OP.

I used return [FollowupAction()] instead of the regular return {} inside the validation function to set dynamic buttons using a custom action. But while testing the bot using rasa interactive here is the warning I am getting

Returning values in helper validation methods is deprecated. Your validate_fromloc_city_name() method should return a dict of {‘slot_name’: value} instead.

I am trying to build a flight search and booking bot. So for example when a user says I would like to travel from London to Paris. I want to validate what airport in London the user would like to depart from by further asking "

Did you mean:
button1: Heathrow Airport, London
button2: Gatwick Airport, London
button3: Stansted Airport, London

This would require dynamic buttons. It’s not just warning it is also ignoring the FollowUpAction and proceeding to the next utter_ask_{slot} question. I am not sure whether I can override request_next_slot in my code as I have written some custom conditional logic for required_slots.

if tracker.get_slot('child_passengers') and tracker.get_slot('infant_passengers') and tracker.get_slot("round_trip") == "round trip":

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "no_of_children", "infant_passengers", "no_of_infants", "class_type", "currency_code", "round_trip", "return_date", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif tracker.get_slot('child_passengers') and tracker.get_slot('infant_passengers') and not(tracker.get_slot("round_trip") == "round trip"):

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "no_of_children", "infant_passengers", "no_of_infants", "class_type", "currency_code", "round_trip", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif tracker.get_slot('child_passengers') and not(tracker.get_slot('infant_passengers')) and tracker.get_slot("round_trip") == "round trip":

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "no_of_children", "infant_passengers", "class_type", "currency_code", "round_trip", "return_date", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif not(tracker.get_slot('child_passengers')) and tracker.get_slot('infant_passengers') and tracker.get_slot("round_trip") == "round trip":

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "infant_passengers", "no_of_infants", "class_type", "currency_code", "round_trip", "return_date", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif tracker.get_slot('child_passengers') and not(tracker.get_slot('infant_passengers')) and not(tracker.get_slot("round_trip") == "round trip"):

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "no_of_children", "infant_passengers", "class_type", "currency_code", "round_trip", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif not(tracker.get_slot('child_passengers')) and tracker.get_slot('infant_passengers') and not(tracker.get_slot("round_trip") == "round trip"):

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "infant_passengers", "no_of_infants", "class_type", "currency_code", "round_trip", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

elif not(tracker.get_slot('child_passengers')) and not(tracker.get_slot('infant_passengers')) and tracker.get_slot("round_trip") == "round trip":

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "infant_passengers", "class_type", "currency_code", "round_trip", "return_date", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

else:

            return ["fromloc_city_name", "toloc_city_name", "depart_date", "no_of_adults", "child_passengers", "infant_passengers", "class_type", "currency_code", "round_trip", "flight_stop_check","email_id","title","user_name","mobile_no","country_code"]

Is there any fix you can suggest for this @akelad ,@abhishakskilrock