How to get all the intents of the user in custom action

I am working on a rasa chatbot where the bot filters data from a database and returns the result based on user intent.

The user can ask 3 types of questions.

  1. question based on date
  2. question based on count
  3. other general questions

here is an example story

*greet
  - utter_greet
  - utter_question
*query_count{"Status":"pending"}
  - slot{"Status":"pending"}
  - utter_askUserId
*give_userId{"UserID":"1234"}
 - slot{"UserID":"1234"}
 - action_getName
 - action_getDetails

from the above story, the user asks a count based question. at that point the latest intent was query_count. But then the bot prompts for the UserID, and when the user gives the userID, the latest intent then becomes give_userId.

My custom action works based on the intent provided. If the intent is query_count run some code else if the intent is query_date run some other code and so on.

I get the latest intent with this code tracker.latest_message['intent'].get('name'). But according to my story, the latest intent is always give_userId and hence the action never runs the way it should.

here is my actions.py

class ActionGetDetails(Action):

    def name(self) -> Text:
        return "action_getDetails"

    def run(self, dispatcher, tracker, domain):
        intent = []
        if not tracker.latest_message['intent'].get('name') == 'give_userId':
            intent.append(tracker.latest_message['intent'].get('name'))

        user_id = tracker.get_slot('UserID')
        status = tracker.get_slot('Status')
        mode = tracker.get_slot('Mode')

        dispatcher.utter_message(intent)

        if intent[-1] == 'query_count':
            query = 'SELECT COUNT(*) FROM sales WHERE UserID=? AND Status=?'

            conn = sqlite3.connect("shipment.db")
            cursor = conn.cursor()
            cursor.execute(query, (user_id, status))
            count_items = cursor.fetchall()[0][0]
            msg = f"You have {count_items} {status} orders"
            dispatcher.utter_message(msg)

        elif intent[-1] == 'query_date':
            if mode == 'deliver':
                query = 'SELECT Delivery_date FROM sales WHERE UserID=?'

            elif mode == 'ship':
                query = 'SELECT Ship_date FROM sales WHERE UserID=?'

            else:
                query = 'SELECT Dispatch_date FROM sales WHERE UserID=?'

            conn = sqlite3.connect("shipment.db")
            cursor = conn.cursor()
            cursor.execute(query, (user_id,))
            items_date = cursor.fetchall()
            msg = f"{items_date}"
            dispatcher.utter_message(msg)

In this code the intent query_count is not appended to the list as that question was asked before the action even runs. And since, I am not appending give_userId to the list, the program returns a list index out of range error as the list is empty

Is there anyway to append all the intents given by the user into the intent list in my the custom action? Or is there a better way to run the above action?

This code will only give you the intent of the current message.

Solution:

You can make a small custom action that runs immediately after the intent "query_count/query_date" (This can be done by modifying the stories.)

Inside that custom action, fetch the intent name and store that in an "unfeaturized" slot called "intent_slot" (so that you can fetch this slot value later inside your custom action)

This way, you can access the "intent_slot" inside the "action_getDetails" using the code "tracker.get_slot("intent_slot")" and do the processing.

I hope this helps.:grinning:

I created another action called saveIntents. Now the action works. but I am not able to call this data from the other actions

this is my code

class ActionSaveIntent(Action):

    def name(self) -> Text:
        return "action_saveIntent"

    def run(self, dispatcher, tracker, domain):

        intent = tracker.latest_message['intent'].get('name')
        return [intent]

class ActionGetDetails(Action):

    def name(self) -> Text:
        return "action_getDetails"

    def run(self, dispatcher, tracker, domain):
        # CALLING THE ActionSaveIntent.run METHOD and storing the data in intent variable
        intent = ActionSaveIntent.run(self, dispatcher, tracker, domain)
        ...

This is the error I am getting

Your action's 'action_saveIntent' run method returned an invalid event. Event will be ignored. Event: 'query_count'.

The return value of any Action is a list of events, that get processed in the message processor. So, the error tells you that your return value (a string) is not an event.

how do I access the data of the ActionSaveIntent class in ActionGetDetails class then??

This is not how you set a slot.

To set a slot, "return [SlotSet('intent_slot', intent)]"

In your domain file make an "intent_slot" and set the type as "unfeaturized"

Now, in your "action_getDetails", use the code "intent= tracker.get_slot("intent_slot")" to get the intent back

thanks a ton. this works

1 Like