Skip properly an action_ask when the entity is known

Hi all,

I have a question regarding skipping the action listen when the slot is filled during the action_ask. I am building a quite complex chatbot managing 20+ intents, which all start forms for slot mapping. Once all slots are filled, the bot is supposed to display solutions. I am using a dataframe (a knowledge base of some sort) in my action.py to check for the different entity values options.

Here is an example of action_ask. I have similar ones for all slots that need to be filled by the forms. I am using the dataframe filtered by the intents and the slots previously informed by the user. When several entity values are possible, the action_ask displays them as buttons. When there are fewer than 2 options (1 or 0), I would like to set the slot and skip to the next requested slot.

Atm the only option I found to skip the action_listen following the action_ask is to call again the current active_loop, using FollowupAction(tracker.active_loop.get('name')) However, sometimes this works half of the time, and the chatbot can get stuck in an infinite loop of actions. :face_vomiting:

class AskForSituationParents(Action):
   def name(self) -> Text:
      return "action_ask_situation_parents"

   def run(self,
           dispatcher: CollectingDispatcher,
           tracker: Tracker,
           domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
      buttons = []
      print(filt_tot)
      print(tracker.active_loop.get('requested_slot'))
      ### Use loaded filter and dataframe to filter right possibilites.
      current_situation_parents = df.loc[filt_tot,'Situation_parents'].unique()
      if debug: 
        print('Running ask categories', current_situation_parents)
      # If unique or null, set slot and return without asking the question.
      if len(current_situation_parents) < 2:
          if debug: 
            print('Unique situation parent')
          curr_no_nan = df.loc[filt_tot,['Situation_parents']]
          curr_no_nan.dropna(axis=0, inplace=True)
          if curr_no_nan.values.any():
            if debug: 
                print('1 only')
            return [SlotSet("situation_parents", current_situation_parents[0] \
                if current_situation_parents[0] is not None else "Not applicable"),FollowupAction(tracker.active_loop.get('name'))]
          else:
            if debug: 
                print('0 only')
            return [SlotSet("situation_parents", "Not applicable"),FollowupAction(tracker.active_loop.get('name'))]
      if debug: 
          print('Printing buttons situation parent')
      for situation_parents in current_situation_parents: 
        buttons.append({"title": situation_parents , "payload": \
            '/inform{\"situation_parents\":\"' + situation_parents + '\"}'})

      dispatcher.utter_message(text= "Pour vous aider plus efficacement, pouvez-\
          vous m'indiquer quel categorie concerne votre demande" , buttons=buttons)

Any suggestions? I am thinking that it might be possible to call the action_ask for the next requested slot, but I am not managing to find how to get the next requested slot…

Thanks in advance :slight_smile: :v:

Why are you making these FollowUp action calls? FollowupAction(tracker.active_loop.get('name')

I assume this is to control which slots are required in which case you should review the docs on Dynamic Form Behavior and manage this with the required_slots method.

1 Like

Hi @stephens , thanks for your response.

I couldn’t find my solution in Dynamic Forms Behavior. From what I understand, this method helps with adding or removing slots to the requested slots list. Additionally, this method is only available if you are using the FormValidationAction class, but I need to use the regular Validation classes since my slots can be filled from several forms.

As mentioned, I am making the FollowUp call as an attempt to jump the action_list following the action_ask when I am able to deduce the entity value from the knowledge base and the entity previously fed. Essentially, I would need to either call for the action_ask_<next_slot>, or action_deactivate_loop, but I am unable to find how to get the next required slot. FYI, I am using 3.0, but any fix available in previous versions could push me to switch.

Thank you for taking the time to answer and please, let me know if you have any further ideas. :slight_smile:

Once all slots are filled, the bot is supposed to display solutions.

Something like this?

rules:
- rule: Submit form
  condition:
  - active_loop: restaurant_form
  steps:
  - action: restaurant_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: action_display_solutions
  wait_for_user_input: false

Hi Stephens, My issue doesn’t concern displaying solutions. This works rather well.

I am going to try to explain in more detail how I use the action_ask and action_validation functions in my case.

In my action_ask, using a dataframe, filtered by the remaining possibilities in my knowledge base to know which entities values to expect for the current intents and entites already picked up during the session.

This helps doing two things: 1 - Display the buttons only for the remaining possibilities.

for situation_parents in current_situation_parents: 
        buttons.append({"title": situation_parents , "payload": \
            '/inform{\"situation_parents\":\"' + situation_parents + '\"}'})

2- Not even ask the question, and skip to the next slot if only 1 entity value is available at this point.

if len(current_situation_parents) < 2:
          if debug: 
            print('Unique situation parent')
          curr_no_nan = df.loc[filt_tot,['Situation_parents']]
          curr_no_nan.dropna(axis=0, inplace=True)
          if curr_no_nan.values.any():
            if debug: 
                print('1 only')
            return [SlotSet("situation_parents", current_situation_parents[0] \
                if current_situation_parents[0] is not None else "Not applicable"),FollowupAction(tracker.active_loop.get('name'))]
          else:
            if debug: 
                print('0 only')
            return [SlotSet("situation_parents", "Not applicable"),FollowupAction(tracker.active_loop.get('name'))]

The issue is about skipping the action_listen in case number 2.

You can accomplish this with your stories and a featurized slot.

1 Like

Thanks, will try this out

Hi @Edunston , I have the exact same problem, but your solutions looks working all the times to me. I am on Rasa 3.0.9 with rasa_sdk 3.0.6. Did you find another more stable solution? I don’t think stories are very useful in this case.

1 Like

Hi Max, sorry for not updating earlier. Actually, my solution is working, except in the rasa interactive mode. I have to select action_listen in interactive mode.

Indeed stories don’t help, since I have 100s of stories showing the right examples, without a change of behaviour in the interactive mode. I think it’s just a weird bug of the interactive mode.

1 Like

Nice, so I will use your solution too, thank you Eric!

1 Like