How to make time depending response

Hi

Can anybody explain me, how I can make time depending responses?

My problem in detail:

If the user starts the chatbot in the night (let’s say between 1 am and 6 am), I want the bot to response with: “Sorry my dear customer. Our service time starts at 7am and ends at 7 pm.”

It the user starts talking to the bot in between the working time, the bot resopnses with: “My dear customer. How can I help you?”

How can I do this?

My guess would be to implement some logic prior to sending the message to Rasa.

The problem is, I do not know where to implement the logic. Should I implement it directly into the story-file or domain-file? Or would it be better to define a logic in the action-file?

Is it a new class or a new function that I need?

The logic I can think of would be sth. like this:

if time_is_night==True:
     use story(“Sorry my dear customer. Our service time starts at 7am and ends at 7 pm")
else:
     use story("How can I help you")

Hi @Chatbot_Ra

how about a ScheduledAction Event?

evt={
      "event": "reminder",
      "action": "my_action",
      "date_time": "2018-09-03T11:41:10.128172",
      "name": "my_reminder",
      "kill_on_user_msg": True,
    } 

documented here:

Does this fit your case?

Regards

Hey, thanks a lot. With this there comes many new questions.

  1. I don’t think that I can shedule an event for a specific time range (between 1 am and 6 am). All I can do is to set a specific time in the future.

  2. What is my_action? I assum it is a class that I need in my actions.py file. How does the class look like?

  3. Where exactly do I set my ScheduledAction?

Hi,

you’re welcome.

  1. As of now it seems to be fixed. Keep in mind that it is OpenSource meaning that you could do whatever you want - if an idea comes up. If this functionality is crucial for you, let’s think about a solution.

  2. my_action is a action you defined in domain.yml meaning an action rasa has learned, e.g. “action_get_projects”

  3. Events can be returned in any kind of CustomAction or FormAction, e.g.:

return [ReminderScheduled(<data>)]

To be more precise, I’ll need more information about your story.

Rasa Core version : 0.13.2

Python version : 3.6.8

Operating system (windows, osx, …): Windows

stories.md

## story_greet      
* greet 
 - utter_introduction
 - utter_how_can_I_help_you 

*how_much
- utter_money

domain.yml

intents:
 - greet
 - how_much

actions:
 - utter_introduction
 - utter_how_can_I_help_you 
 - utter_money

templates:

utter_introduction:
- text: "hi, I am your bot."

utter_how_can_I_help_you 
- text: "My dear customer. How can I help you?"

utter_money:
- text: "the price is only 1 Dollar"

-utter_night:
- text: "Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later."

Of course the story is much more complex, but I think this is a good example.

I have also an actions.py file in which I have defined some classes such as e.g. ActionDefaultFallback and AuthenticateForm.

Maybe the best way is to create a new action class, which checks the current time. If the current time is in between a specific time range (between 1 am and 6 am) return some slot. But I do not know how to do this. Would be great if you can help me.

Thank you very much in advance!!!

Okay, what about:

  1. Design a custom action like this one

class CheckWorkingHours(Action): def name(self): # type: () -> Text return “action_check_working_hours”

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

    now = datetime.datetime.now()
    today18pm = now.replace(hour=18, minute=0, second=0, microsecond=0)
    today13am = now.replace(hour=13, minute=0, second=0, microsecond=0)
    if today13am > now < today18pm
        message = 'Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later.'
    else:
        message = 'How can I help you?'
    
        dispatcher.utter_message(message)
    return []
  1. Design your story accordingl - after every intent that you want to, first start this action. If you want the action to create follow up actions that differ from your story, you can do that with:

tracker.followup_action()

or any other event, meaning that you could modify the story programmatically. A slot however can only be returned in a FormAction - based on what exactly you want to achieve.

This looks great, but I think I still need some help to implement it in the right way. Please check the format of my class CheckWorkingHours!

This is what I have done:

stories.md

## story_greet      
* greet 
 - action_check_working_hours
 - utter_introduction
 - utter_how_can_I_help_you 

*how_much
- action_check_working_hours
- utter_money

domain.yml

intents:
 - greet
 - how_much

actions:
 - utter_introduction
 - utter_how_can_I_help_you 
 - utter_money
-  action_check_working_hours

templates:

utter_introduction:
- text: "hi, I am your bot."

utter_how_can_I_help_you 
- text: "My dear customer. How can I help you?"

utter_money:
- text: "the price is only 1 Dollar"

-utter_night:
- text: "Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later."

actions.py

from datetime import datetime
import datetime as dt

class CheckWorkingHours(Action): 
    def name(self): # type: () -> Text 
        return "action_check_working_hours"

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

        now = datetime.datetime.now()
        today18pm = now.replace(hour=18, minute=0, second=0, microsecond=0)
        today13am = now.replace(hour=13, minute=0, second=0, microsecond=0)
        if today13am > now < today18pm:
            message = 'Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later.'
        else:
            message = 'How can I help you?'
    
        dispatcher.utter_message(message)
        return []

I have also changed the story in order to call the action class. Is this the correct way?

Note, I know for sure, that the customer will always start with the intent greet. This is for sure due to some other reasons. Would it be enough, if my action class will be called only at this point? If the time is in between service time, the chatbot will run as usuall. Otherwise the chatbot will ask the customer to come back later. Done!

At the moment I get the following error message:

 rasa_core.actions.action  - Failed to run custom action 'action_check_working_hours'. Action server responded with a non 200 status code of 500. Make sure your action server properly runs actions and returns a 200 once the action is executed. Error: 500 Server Error: INTERNAL SERVER ERROR for url: http://localhost:5055/webhook
2019-06-13 14:28:51 ERROR    rasa_core.processor  - Encountered an exception while running action 'action_check_working_hours'. Bot will continue, but the actions events are lost. Make sure to fix the exception in your custom code.

@Chatbot_Ra seems like there is an issue on your action server. What are the logs on that server saying?

Also, I guess you want to do: if today13am **<** now < today18pm: since you want to check if ‘now’ is in between the two timestamps.

Last thing, the way your stories are defined now, it will check the working hours, and utter 'Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later.' But it will then continue with utter_introduction. You should do something there to make sure the bot stops. I suggest to fill a slot in your custom action with either ‘online’ of ‘offline’ or something, and define in your stories.md two possible stories. One when the slot is filled with online and one when the slot is filled with offline.

However, I’m not sure how you can make sure that the bot also won’t respond to anything else the user says outside of your defined service hours.

@Chatbot_Ra

Please try to start a separate action server by using:

rasa run actions -vv

and post the output after executing the action here.

@rbossie

Correct - my comparison was wrong at that point.

However, you could, for example, just define the stories the way @Chatbot_Ra did and if the service is what you call offline, one could invoke /action_restart as next action such that the bot only proceeds to

utter_introduction

if the time is right.

Hey @JulianGerhard and @rbossie. Thanks for your great input and sorry for my late response. Meeanwhile everythink ist working (no error message). I just had to replace datetime with dt. This is what I have now:

stories.md

## story_greet      
* greet 
 - action_check_working_hours
 - utter_introduction
 - utter_how_can_I_help_you 

*how_much
- utter_money

domain.yml

intents:
 - greet
 - how_much

actions:
 - utter_introduction
 - utter_how_can_I_help_you 
 - utter_money
-  action_check_working_hours

templates:

utter_introduction:
- text: "hi, I am your bot."

utter_how_can_I_help_you 
- text: "My dear customer. How can I help you?"

utter_money:
- text: "the price is only 1 Dollar"

-utter_night:
- text: "Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later."

actions.py

from datetime import datetime
import datetime as dt

class CheckWorkingHours(Action): 
    def name(self): # type: () -> Text 
        return "action_check_working_hours"

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

        now = dt.datetime.now()
        today18pm = now.replace(hour=18, minute=0, second=0, microsecond=0)
        today13am = now.replace(hour=13, minute=0, second=0, microsecond=0)
        if today13am < now < today18pm:
            message = 'Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later.'
        else:
            message = 'How can I help you?'
    
        dispatcher.utter_message(message)
        return []

Good news, the class seems to work. Depending on the current time, the response of the chatbot changes. That’s great! However, this doesn’t solve my problem yet. I want the bot only to proceed if the current time is in between the service time. If this is the case, everything behaves as usual. If this is not the case, the chatbot outputs: “Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later”

I guess I have to create 2 stories.

First story: The class CheckWorkingHours is activated in between service time. Then the story will proceed with utter_introduction.

Second story: The class CheckWorkingHours is activated out of service time. Then the chatbot outputs: “Sorry my dear customer. Our service time starts at 7am and ends at 7 pm. This chat will end now. Please contact us later”. Afterwards the sory is over and does not proceed to utter_introduction.

How would you do this?

How about my previous suggestion:

Check if you want to answer the way you now implemented it. The normal story is:

## story_greet      
* greet 
 - action_check_working_hours
 - utter_introduction
 - utter_how_can_I_help_you 

But - as you mentioned - you only want to go beyond action_check_working_hours if the time is right.

I’d suggest to invoke “action_restart” with tracker.followup_action() such that the current storyline is interrupted as long as the time is NOT right.

You are right, I only want to go beyond action_check_working_hours if the time is right.

I kind of get what you say, but I am not sure how to do this.

Where can I find more information about the class action_restart ? At the moment I have no idea how to write and implement it. Maybe you have an example or link for me?

This traker is sth. I do not realy get. If I get it right, this tracker is INSIDE my class action_restart.

Let me show you what I do not understand:

stories.md

## story_greet      
* greet 
 - action_check_working_hours   # if time time is right, go beyond. If time is wrong stop story and say sorry
 - utter_introduction
 - utter_how_can_I_help_you 

*how_much
- utter_money

Would be great if you have an example for me! I think its easy, but I am not sure how to start it

Let me re-phrase my question. You said:

Let’s assume I have a class action_restart with tracker.followup_action() (which I don’t have yet). If I get it right, I have to invoke this action when the service is offline. If the service is online I have to invoke the tracker.followup_action(). Is this understanding correct?

If yes, I see following steps for me to do?

  1. Define action_restart
  2. Define tracker.followup_action()
  3. Call the action in the right moment. --> where in the code do I call the action? This is not clear to me.

Hi,

I am on vacation until wednesday. If not already obsolet, I will take a look upon after returning!

Regards

1 Like

Since my question has a different topic now (the time-depending problem is solved), I have started a new question building up on this post. You can answer either here or there: link to new question