How to repeat the last bot utterance

For a bot which is used mainly via voice, I would like to be able to repeat the last message the bot said. So for example:

Bot: I found contact ABC with phone number 123456 User: Could you please repeat that? Bot: I found contact ABC with phone number 123456

I do not want to repeat the whole action (searching in the database for the contact information), but only repeat the output of the bot again.

I thought I could create a slot “last_message” and fill that slot always in all my custom actions. However maintaining this slot manually is quite tedious. Is there a more elegant solution to simply repeat the last message the bot said?

1 Like

You could make an action like this:

class ActionRepeat(Action):
def name(self) -> Text:
    return "action_repeat"

def run(self, dispatcher, tracker, domain):
    if len(tracker.events) >= 3:
        dispatcher.utter_message(tracker.events[-3].get('text'))
    return [UserUtteranceReverted()]

Regards,

Thanks, but what does the function UserUtteranceReverted() do in your example?

@custodio I extended your solution to also repeat button messages. My solution now looks like

class ActionRepeat(Action):
def name(self):
    return "action_repeat"

def run(self, dispatcher, tracker, domain):
    if len(tracker.events) >= 3:
        dispatcher.utter_message(tracker.events[-3].get('text'))
        data = tracker.events[-3].get('data')
        if data:
            if "buttons" in data:
                dispatcher.utter_button_message(text=None, buttons=data["buttons"])
    return []
1 Like

Hi, I face the same problem, but the solution “dispatcher.utter_message(tracker.events[-3].get(‘text’))” doesn’t work for all the situations. Depending on the custom actions and other parameters, it can be tracker.events[-5] or tracker.events[-7] or any other number. So I am looking for another better solution: continuously get and copy on a slot the messages from the bot (every new message replaces the previous one on the slot). I am thinking about a customized pipeline. Have you found any good solution to your problem? And if yes, could you share it? Thanks.

Here is a code that repeats all the messages till the last user input without any hardcoding. This works well for text and buttons. You can do the same for images.

class ActionRepeat(Action): def name(self): return “action_repeat”

def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

    user_ignore_count = 2
    count = 0
    tracker_list = []

    while user_ignore_count > 0:
        event = tracker.events[count].get('event')
        if event == 'user':
            user_ignore_count = user_ignore_count - 1
        if event == 'bot':
            tracker_list.append(tracker.events[count])
        count = count - 1

    i = len(tracker_list) - 1
    while i >= 0:
        data = tracker_list[i].get('data')
        if data:
            if "buttons" in data:
                dispatcher.utter_message(text=tracker_list[i].get('text'), buttons=data["buttons"])
            else:
                dispatcher.utter_message(text=tracker_list[i].get('text'))
        i -= 1

    return []

I dug this up because I realized that the provided example does not work with conditional responses in Rasa 2.8.x. To get it working (so far), I simplified the second while-loop to this:

while i >= 0:
            dispatcher.utter_message(response=tracker_list[i].get('metadata').get('utter_action'))
            i -= 1

Another reason why I changed it is that the condition ‘if “buttons” in data’ does not trigger properly, since the “buttons” key is now in all bot events (it is None at least). The tracker list elements look like this:

{
  'event': 'bot', 
  'timestamp': 1637768897.3518603, 
  'metadata': {'utter_action': 'utter_greet'}, 
  'text': 'Hey! How are you?', 
  'data': {'elements': None, 'quick_replies': None, 'buttons': None, 'attachment': None, 'image': None,   'custom': None}
}

Any thoughts if these changes break something that I overlooked?

1 Like