RASA custom action which returns utter depending on stopword

Hi

Problem (short): Depending on specific stopwords I want my custom action to return either utter_cancel or utter_happy.

Problem (long): The user is asked to fill out the slots (name, name_last and street name). I have a list of stopwords stopword_list. If the user uses any of the words, my action form gets deactivated and the user directly jumps to the end of the form:

story.md:

* greet
- authenticate_form
form{"name": authenticate_form}
slot{"name": "John"}
slot{"name_last": "Doe"}
slot{"street_name": "Elm Street"}
form{"name": null}
- action_ask_if_you_want_change
- utter_bye

If the user uses a stopword, the form gets deactivated and he directly jumps to action_ask_if_you_want_change. That means one of the slots is filled with the stopword.

If this is the case I want my custom action to return utter_cancel. In the other case, the user did not use the stopword, therefore he filled out the slots completely. The I want my custom action to return utter_happy.

How do I write this custom action?

My approach:

class AskIfYouWantChange(Action):
    def name(self): #type: () -> Text 
        return "action_ask_if_you_want_change"
    
    def run(self, dispatcher, tracker, domain):
        
        # type: (CollectingDispatcher, Tracker, Dict[Text, Any]) -> List[Dict[Text, Any]]
        
        # get value of the slots
        value_name = tracker.get_slot('name')
        value_name_last = tracker.get_slot('name_last')
        value_street_name = tracker.get_slot('street_name')
        
        # The user deactivated the form by one the the following stopwords
        # We check each word to be a match and return True if any are matches
        
        stopword_list = ['stop!', 'Stop!']
        found_stopword_name = any(value_name in word for word in stopword_list)
        found_stopword_name_last = any(value_name_last in word for word in stopword_list)
        found_stopword_street_name = any(value_street_name in word for word in stopword_list)
        
        if found_stopword_name == True:
            dispatcher.utter_template('utter_cancel')
        else:
            dispatcher.utter_template('utter_happy')
        
        return []

This obviously is NOT a working example. This just gives you a feeling about what I want to achieve. I do not know, how to check ALL slots for a list of stopwords. Also I am not sure how this class should be structured. I think I need some help here!!!

Hope you can help me with this :slight_smile:

Hello @Chatbot_Ra,

If i understand correctly, you want to deactivate the currently executing form if the user uses a stopword. I’m thinking about creating a separate intent ‘cancel’ or something like that to handle the situation, rather than trying to handle it in each of your form.

## intent:cancel
- stop
- i want to stop
- i don't want to do this anymore
- cancel
- abort
- i want to do other actions
- i changed my mind
....

You create an action called ActionCancel, something like:

    class ActionCancel(Action):
        def name(self):
            return "action_cancel"

        def run(self, dispatcher, tracker, domain):
            dispatcher.utter_template("utter_cancel", tracker)

            return [FollowupAction("action_deactivate_form")]

Add it in stories.md:

* cancel
    - action_cancel

Hope that helps :smiley:

Hey

Thank you very much for your reply.

Unfortunately I can’t use your approach. Due to different reasons, I have to set the slots hard. This means, whatever the user writes into the slots, it gets into the slots. Sure, there is a validation before, but there is no natural language understanding.

In detail: In your case, RASA has to understand the meaning of what the user writes. For example, if the user writes “I want to stop” in the slot name, then the slot will be set to I want to stop. Of course, this is not a name, but let’s keep it this way. If the user writes “I want to stop 2” in the slot name, the bot will ask for his name again, because names with numbers do obviously not exist therefore it does not pass the validation that I do.

Yes and no. I know how to deactivate the current form if the user uses a stopword. The problem I have starts afterwards. Since the form will be deactivated, the user directly jumps to the end, which is action_ask_if_you_want_change (see story.md in post 1). My problem is all about this particular custom action. Since the slots are set hard, one out of my 3 slots (name, name_last, name_street) is filled with the stopword --> see stopword_list in post 1!

If this is the case I want my custom action action_ask_if_you_want_change to return utter_cancel . In the second case the user did not use the stopword, therefore he filled out the slots completely. Then I want my custom action to return utter_happy .

My question: How does custom action action_ask_if_you_want_change look like?

I think we first have to check if one slot is filled with a stopword. Afterwards return the specific utter.

Hope you or anybody can help :slight_smile:

Yeah, seems like a simple way to do it. You only have to check for 3 slots. But it seems to me that the action_ask_if_you_want_change doesn’t ask the user anything or take any input. It just checks if one of the slot contains the stop words or not, and utter message correspondingly. What if we remove this action ? I have a solution like this:

You mentioned validating the slots, so i guess you check for the stop words and deactivate the form in there. So why not just utter the cancel message in there ? And if there is no stop word, the slots is filled correctly, just utter happy message in the submit function of the form.