Different custom actions for different slots in same form

I’m having difficulty calling different custom actions within the same form.

In a form with a series of slots to be filled, some slots call different custom actions. for example, when the slot is asking for a task name, it will call an API.

Then, when a different slot is requested, a custom function will extract the latest text and call a different API.

But, it’s not working.

I tried two different strategies in the action below.

  1. I tried tracker.get_slot, but this triggered the custom action each time. I only wanted this if statement to be triggered on the latest slot requested, but it’s triggering it every time the validation form is run.

  2. I tried validate_ within the validate_form, but this did not run the custom action I needed.

In the action below, you’ll see that when asana_task_name is requested, it should run an api call.

Then, when the next slot is requested, it should also call the action associated with the next slot.

how do I do this?

Thanks and let me know if I can clarify this question

class ValidateAsanaForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_asana_form"
    
    def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Create an incident and return details or
        if localmode return incident details as if incident
        was created
        """
        
    def validate_asana_task_name(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        print ('validation run')






        if tracker.get_slot('asana_task_name'):
            print ('triggered asana task name')
            text_of_last_user_message = tracker.latest_message.get("text")

            print ('last user message', text_of_last_user_message)

            tasklist = list_tasks_numbered_names(text_of_last_user_message)

            resp = "Here is your task list: \n"+str(tasklist)
        
            print ('DEBUG: which task would you like to select from this list?', tasklist)
            dispatcher.utter_message(resp)
            return [SlotSet('asana_select_options_slot', tasklist)]
        else:
            pass

        if tracker.get_slot('asana_number_select'):
            print ('asana number select triggered')
            text_of_last_user_message = tracker.latest_message.get("text")
            print ('this the last text sent from number', text_of_last_user_message)

@travelmail26 Are you sure, It’s a complete code?

for the custom function? yes. I was just testing whether I can get different slots to trigger different functions. I was doing it all under a validate_form function. happy to provide any other data

@travelmail26 I can not see last (if) return statement (for asana_number_select ) that’s why I asked, and you said you calling API, which one is your API function?

Ah, sure!

1). list_tasks_numbered_names is the function that calls the api

2). the end of the last “if” the function is just a print statement to see if i could trigger it with the next slot. Unfortunately, it calls when asana_task_name is also True

@travelmail26 Well, What I understand by your code and your use case, please correct me if I am wrong ok.

  1. You want to fetch the value of 2 different slots from same custom action
  2. A-slot will fetch the value from API and other B-slot as regular process?
  3. Also, want to validate the slots? or its not mandatory @travelmail26

Is that right?

Not quite and sorry for being unclear. Within the same form, I want different slots to trigger different functions. That’s it. Some of those slots will come from information from an API calls. Others will not.

I just want the ability to call a function depending on the slot being filled. Does this make more sense?

@travelmail26 Yeps, that’s what I mean :slight_smile: I will find your solution tomorrow.

1 Like

amazing! look forward to your suggestion. thanks for the help!

@koaning i’m told that you understand forms better. any ideas on this problem? thanks

I’m not sure I’m an expert on forms, but let’s have a look at your code. I refactored it a little bit by removing the print statements. I also removed the else: pass part because it’s un-needed.

class ValidateAsanaForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_asana_form"
        
    def validate_asana_task_name(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:

        if tracker.get_slot('asana_task_name'):
            text_of_last_user_message = tracker.latest_message.get("text")

            tasklist = list_tasks_numbered_names(text_of_last_user_message)
            resp = "Here is your task list: \n"+str(tasklist)
        
            dispatcher.utter_message(resp)
            return [SlotSet('asana_select_options_slot', tasklist)]

        if tracker.get_slot('asana_number_select'):
            text_of_last_user_message = tracker.latest_message.get("text")


I’m a bit confused about what this code is trying to do. The validate_asana_task_name method adheres to the validate_<slot_name> standard. So this method will only trigger whenever we’re trying to validate the asana_task_name slot. Given that logic … what is the purposes of this bit of code:

        if tracker.get_slot('asana_number_select'):
            text_of_last_user_message = tracker.latest_message.get("text")

I’m unsure what you’re trying to do, mainly because text_of_last_user_message = tracker.latest_message.get("text") is declared earlier in the method as well.

1 Like

@travelmail26 I hope Vincent suggestion helped you? and you solved the issue?, if not please do let him know your issue in brief.