Skip to Content
Technical Articles
Author's profile photo Daniel Lorenz

Challenge Submission: Sicky – A chatbot to send out-of-office emails

Hello everyone!

Welcome to the step-by-step tutorial for building Sicky – a chatbot that can send out-of-office emails if you are sick (or just don’t want to work today 😉 ).

This tutorial is part of SAP CAI’s tutorial challenge, so feel free to give a Like if you like it!

Introduction

Our plan is to build a chatbot that can send out-of-office emails. We want to do this because it’s fun and we like to explore things.

However, if we want to convince the business people that this is a good idea, we better have some arguments! So we will start this tutorial by looking at the related business process and try to find reasonably good reasons to change this process (to introduce a chatbot 🙂 ). After we have conviced the business, we are starting with the actual implementation of the bot and the integration with Telegram. We will encounter some issues (with respect to buttons and Telegram) and learn how to analyze issues like this and find workarounds for them. At the end, we also take a look at possible extentions of our chatbot.

So without further ado, let’s go!

Changing a business process

The as-is business process

Let me introduce you to Barbara, the technical lead of our SAP CAI experts team. She is not feeling well today; indeed, she is feeling terrible and would very much like to stay in bed the whole day. Nevertheless, she has to get up, boot up her laptop and email Marc, our business unit assistant, telling him that she is ill and out of office today (and probably also tomorrow and the day after tomorrow). Then she can shut down her laptop and go back to bed.

Marc receives Barbara’s email and does a couple of things:

  • First, he writes an email to all members of Barbara’s team informing them that Barbara is out-of-office today.
  • Second, Marc forwards the out-offfice info to the payroll team.
  • Third, he reminds Barbara that she needs an official sick note from her doctor if she is out-of-office for more than two days.
  • And of course, he also whishes her a speedy recovery!

Why change this process?

If you have been in Barbara’s situation (I certainly have been there), you know that sometimes it is rather annoying to start up your laptop just to write that one teeny-tiny email to Marc. I mean its not suuuper annoying, but… you know, if something could be done about it, why not?

Additionally, have you tried writing an email while NOT checking your inbox? Sure, it’s no big thing – but Barbara would rather not have read her emails on that particular day.

One the other side, we have Marc. For him it is just a couple of simple, repetitive tasks. Receive an email, write some emails. Depending on the size of the business unit Marc is responsible for (and the season of the year, I guess), it maybe takes up 30-60 minutes per week.

Not too much time, you might think but it adds up. Maybe there are other similar tasks? Maybe reducing this repetitive workload on Marc allows him to take up other, additional roles (or just have a longer coffee break). In any case, I don’t think Marc would miss this particular task if it was taken from him.

How do we want to change the process?

What would be the ideal situation?

Barbara would like to not get up from here bed and to not accidentally read her email (physical and mental healthcare 😉 ). Ideally, she would just pick up her phone and message someone that she is out of office today. Maybe via Telegram or WhatsApp?

Marc doesn’t mind writing these out-of-office emails. It has been part of his job up until now but he also doesn’t care if this part of his job is taken over by somebody else.

Well, guess who this somebody could be?

Yep, it’s Sicky, our SAP Conversational AI chatbot for handling the whole reporting sick process.

Botbuilding

Planing the conversational flow

Let’s start by looking at the planned conversational flow.

Planned%20conversational%20flow

A few notes about this one:

  • Sicky immediately asks if Barbara wants to report sick. Why? Because we want to make it as easy as possible for Barbara to get things done. And at the moment Sicky can do one thing and one thing only. So why not directly ask if Barbara wants to do the only thing that Sicky can do? Ideally, we can show buttons for answering this question.
  • Why do we ask for the email address? Well, we need to somehow know who is reporting sick. The name might not be unique. And we can also use the email address to send a confirmation email to Barbara.
    Why would we want to that? Just to make sure that you at least get an email if somebody else reports you as out-of-office via Sicky 😉
  • Before Sicky sends all necessary emails, there is a small summary of all the information Sicky wants to send via email. This is just to make sure that Barbara has the chance to correct anything that might not be correct.

Building the conversational flow

There are couple of things that we have to do here:

  • first we need to create a bot
  • next we have to build our conversational flow in our new bot
  • third we have to integrate our bot with Telegram
  • and lastly, we should test if everything works as intend.

Creating the chatbot

Let’s go to www.cai.tools.sap sign in (or sign up) and hit the big blue button:
Big%20Blue%20Button

We want to create a chatbot that can Perform Actions and we equip Sicky with the Greetings and the Small Talk skills.

Creating%20Sicky%20Part%201

We give Sicky the correct name and enter a perfect description 😉

Creating%20Sicky%20Part%202

Continue by choosing the language that you want Sicky to understand initially. Support for multiple languages can be added later.

As for the Data Policy, we are going with Sensitive Personal and start with Storing the data. Later on, we can change this setting but it is helpful while we are still developing Sicky to see everything that is going on.

Finally, create your bot and we are ready to start training Sicky.

Building the flow

This is a (sort-of) long process, so let’s first get an overview of what we want to do.
Sicky should:

  1. respond with “Hi I’m Sicky” when someone says “hi”
  2. immediately ask if the user wants to report sick, ideally using pre-defined buttons
  3. ask for how long the user is out-of-office
  4. ask for the email address
  5. provide a summary
  6. send an email to Marc
Step 1 – “Hi I’m Sicky!”

Since we decided to equip Sicky with the Greetings and the Small Talk skills, we already see a lot of pre-defined intents.

List%20of%20pre-defined%20intents

Following our planned conversational flow, we don’t need to introduce a custom intent (for the moment). A conversation would always start by the user saying “hi” or something like this, which should be recognized as the @greetings intent. Meaning we don’t have to do anything here for now.

So let’s go directly to the Build tab and select the greetings skill.

The%20greetings%20skill

We want to modify the response that Sicky gives when somebody says “hi”. For this, we go to the Actions tab and edit the pre-defined responses to the @greetings intent.

Say%20Hi%2C%20Sicky%21

Don’t forget to click SAVE!

Hi%20Sicky%21

Let’s see if it works. Open the Chat Preview in the bottom right corner and say “HI”.

Testing%20HI

Step 2 – “Feeling sick?”

Next, we want Sicky to ask the user if they want to report sick.
For this, we go back to the Build tab (just click on the Build tab again) and create a new skill.

Adding%20a%20skill

Enter a reasonable name for the new skill and Add it to Sicky.

Sicky%20has%20a%20skill

Open the skill and go the Actions tab. There, we add a message group and choose to Send a Message.

As said earlier, we want the user to answer this question by pushing some buttons, so this is the option that we choose.

Let’s ask the user if they want to report sick and add a button that says “yes”. When creating the button, we have to choose what should happen when the button is pressed. Let’s go with Trigger Skill for the moment, since we want to redirect to another skill, when a user answers “yes”.

Buttons%20with%20Yes%20and%20No

Leave the “Select a skill to trigger” box empty (we have not create these skills yet) and create another button for “no”.

Buttons%20without%20linked%20skill

What’s next? We need to link the first skill (“Hi, I’m Sicky“) to the skill that we just created. For this, let’s go back to the greetings skill and select the actions tab. Right below the last greeting we can choose to update the conversation.

Redirecting%20to%20another%20skill

We select to Go To another skill and enter the name of the skill we just created. In my case, this is “wanna-report-sick”.

Redirecting%20to%20Wanna

Again, don’t forget to hit SAVE.
Let’s check again if it works.

Sicky%20with%20buttons

As we can clearly see, we are lacking the skills (hahaha) to continue after a user selected “yes” or “no”.

So let’s go to the Build tab and create two new skills (one for “yes” and one for “no”). And give them some reasonable names – I called them bye and ask-sick-period.

Next, we go to the wanna-report-sick skill, enter the actions tab and link the “yes” button to our ask-sick-period skill and the “no” button to the bye skill.

Now, these skills are automatically executed when the user selects “yes” or “no”
If the user selects “no”, then there is nothing left to do for them with this bot. So Sicky can kindly say bye and reset the conversation.

ByeBye

Step 3 – “How long are you OOO?”

If a user selects “yes”, Sicky should ask them for how long they want to report sick.
There are a number of different options we can choose from.

  1. We can add a Requirement for the entities #datetime and #duration and use SAP CAI’s built in NLP to determine one or the other from the user input.
  2. We can just take the raw user input and not rely on SAP CAI’s built in entities.

Which option you choose, highly depends on your language. I found that option one works nicely for English. However, for German I found a lot of typical examples that where not recognize as #datetime or #duration. So for German, I would go with option two.
Anyways, let’s quickly show both options.

Option 1

Go to the Requirements tab of your ask-sick-period skill. Add a requirement for the #datetime entity and another requirement for the #duration entity. Note that by default these requirements are linked by an AND. We don’t want that. For us it is sufficient (expected) that only one of them is filled. So just click on the AND to make it an OR.  Additionally, we want to add some user feedback so that they know what they are supposed to do.

Finally%2C%20some%20requirements

Add New Replies if both requirements are not satisfied and ask the user for how long they intend to be out of office.

Ask%20for%20OOO%20period

Try it out! You can examine the data which is picked up by Sicky by clicking on the small yellow icons in the chat.

Option 2

As said above, option 1 works nicely for English but there are examples in other langues that just don’t work. (Try out the German “bis übermorgen” for example 🙂 )
So instead of relying on SAP CAI’s pre-trained entities, we are just going to use the raw user input.

If you have not done this before with SAP CAI, you will probably find it a little cumbersome. But at the moment there is just no other way.
What’s the plan?

In the ask-sick-period skill we will ask the user for how long they plan to be out of office. The answer of the user is picked up in a second skill. We have to trigger that skill from ask-sick-period, For this to work properly, we have to define a custom memory field “waiting_for_sick_period” and set it in the ask-sick-period skill.

So let’s go to the action tab of the ask-sick-period skill. We ask the user for how long they expect to be sick and then choose to edit the memory.

Editing%20the%20memory

There, we define the waiting_for_sick_period memory field and set it to true.

Waiting%20for%20sick%20is%20true

Additionally, we want to Go To another skill (say read-sick-period) which picks up the user input and saves it to memory.
Go ahead and create the skill read-sick-period and link to it from the ask-sick-period skill. This time, we have to specify that we want to wait for user input.

Redirecting%20to%20read%20the%20sick%20period

SAVE and go to the read-sick-period skill (you can click on the skill name after saving) and open the triggers tab.
Here we specify that this skill should start, if the _memory.waiting_for_sick_period field is set to true.

Trigger%20reading%20the%20sick%20period

Next, we go to the actions tab and update the conversation by setting a memory field. Whatever the user has entered after Sicky asked them for how long they expect to be sick, is stored in the field nlp.source. We want to use this value and save it to a custom memory field, say sick-period. To do this, we have to use scripting to build the JSON and we have to put quotation marks around {{nlp.source}} (The curly brackets are there to tell SAP’s CAI that this is a variable and not a string).

Reading%20the%20sick%20period

Additionally, we unset the waiting_for_sick_period memory field, since we are no longer waiting for the user input.
Now we are done and can continue the flow of the conversation by redirecting to the next skill.

Step 4 – “What’s your email address?”

We create a new skill in the Build tab and call it ask-email. In this skill, we add a requirement for the #email entity. Also, we add some replies like “What’s your email?” to if #email is missing.

Ask%20for%20the%20email

Right now, Sicky should have collected all the information required to send the out-of-office-email to Marc. Before doing so, Sicky should confirm that the information that was picked up is correct.

Step 5 – Summary

Let’s create another skill and call it provide-summary.
If you chose Option 2 earlier, then this is straightforward: create a button and ask the user if they are happy with the data picked up by Sicky. If so, we continue to another skill, send-email. If the user is not happy with the data, we reset the conversation and start again from the beginning (of course, we could do better by asking which part is wrong and make the user only correct this one – but I will leave this as an exercise for you 😉 ).

If you chose Option 1 earlier, we don’t know in which memory field the input of the user is stored. Therefore, we have to distinguish between the two cases:

  1. the user wrote something like “for 2 weeks”
    In this case, the input is stored in the #duration entity. We can access this information via the memory.duration field and format the output to display the number of days.
    Showing%20the%20duration%20of%20your%20sick%20period
  2. the user wrote something like “until tomorrow”
    In that case, the information is stored in the #datetime entity. We access the information via memory.datetime and can choose if we want to display it formatted or in iso format.
    Show%20a%20formatted%20datetime
  3. the user wrote something like “until the end of the week”
    In this particular case, the information is stored again in the #datetime entity but only in the raw field of the #datetime entity. All the other fields are null.
    In this case, we want to display the raw user input.
    Show%20the%20raw%20datetime
  4. there are even more cases than this –  but I leave this part of breaking Sicky, then fixing Sicky to you 🙂

Again, if the user is not happy they can select “NO” and we redirect to a reset skill. There, we reset the conversation and redirect to the beginning.

Reset%20the%20conversation

If the user is happy, we redirect to the send-email skill.

Step 6 – Send an email to Marc

We create the send-email skill via the Build tab and add an action to connect to an external service and call a webhook. There, we just have to enter the URL of our email service and specify the JSON payload.

If you don’t want to send an email, just print a message that you got to that skill successfully.

If you want to send an email, you will need a web service that can do that for you.
On my GitHub, there is a very simple example email service that you can use for this. Check the readme on GitHub to see how to deploy it to the SAP Cloud Platform.
After deploying to the SAP CP, you can find the public route to your app in the application overview.

Route%20to%20your%20app%20on%20SAP%20CP

We take this URL and paste it into the webhook configuration. We specify the endpoint (“/send”) and adapt the JSON body to fit the expectation of the email service.

Linking%20the%20webhook

Again, we have to add conditions to format the message accordingly, basically the same as we did in Step 5.

And then, we are good to go!

Go ahead and test Sicky and see if you receive an email (assuming that you have put your email instead of Marc’s email 😛 ).

Integration with Telegram

Lastly, we want to integrate Sicky with Telegram.
Luckily, integrating bots with Telegram is not too complicated. Basically, we just follow the instructions given in the Connect tab.

Connecting%20to%20Telegram

When we are done with this, let’s go ahead and test it!

Testing

We start the bot in telegram (search for the bot handle) and START the conversation.
But what is this? oO

Oh%20NO

It appears that our button does not work with Telegram? What’s going on there?
Let’s have a look at the Monitor tab an see what we can see 🙂

Monitoring%20Telegram

Looks like Telegram is returning the id (?) of the “yes” button. But it worked with the integrated chat, right? So let’s check what the logs say for a conversation via the integrated chat.

Monitoring%20CAI

Looks like there is no logged interaction for the “yes” button press at all. So that doesn’t help.

Making buttons work with Telegram

Hm, what do we do?

Well, there were other options when we created these buttons (instead of trigger another skill).
It turns out that the postback button is the option that fixes our problem (albeit at the cost of some additional work).

Go to the first skill that uses buttons (in my case its the wanna-report-sick skill) and remove the old “yes” and “no” buttons. Instead create new postback buttons and put true and false (“yes” and “no” are also fine 😉 ) on the right.

Postback%20buttons

When you press a postback button, whatever you put in the box on the right side will be send to Sicky. If a user now presses the “yes” button we actually receive a true and can read it.

As for reading the result, we do the same as we did before:

  1. set a custom memory field (waiting_for_wanna) to true in the wanna-report-sick skill
  2. create a skill for reading the user input (read-wanna-report)
  3. redirect from the wanna-report-sick skill to the read-wanna-report skill and wait for user input

  4. choose to trigger the read-wanna-report skill if the waiting_for_wanna memory field is true
    Trigger%20on%20wanna%20report%20sick
  5. store the value of {{nlp.source}} into another custom memory field (wannareport)
    Read%20wanna%20report%20sickNote that there a no quotation marks on {{nlp.source}} because true and false don’t need quotation marks in JSON. If you decided to go with “yes” and “no” as postback answers, you need the quotation marks.
  6. redirect to ask-sick-period or bye based on the value of wannareport

redirect%20based%20on%20wanna-report

Now we are almost done. We just have to do the same for every trigger a skill button we have 🙂

Luckily, there is only on more button left (after the summary).

I’ll leave this to you as a lovely exercise 😛
And then we are done!

Our bot works with Telegram!

Time to tell all your friends that they can use this completely public bot to send out-of-office emails to poor Marc! 😉

Summary and look ahead

In this tutorial, we have seen

  • how to look at a business process and come up with an idea for automation
  • how to get from a conversation flow to the actual conversation
  • how to read generic input from the user
  • how to distinguish answers based on the format of data you have read
  • how to integrate with Telegram
  • how to test and track arising issues
  • how to make redirect-buttons work with Telegram

What else could be done by Sicky?

  • Of course, we could send out more emails to other people in the company. You already know how to do this 😉
    But this is not super interesting.
  • We should also introduce an intent for reporting sick. This would allow people who know Sicky to bypass some of the button clicking, by putting all necessary information in the first message to Sicky.
  • We could try to integrate with Outlook (Google, …) to decline/cancel all meetings that are happening during the out-of-office period.
  • Thinking about meetings: we could introduce the general usecase of canceling/declining meetings. This seems pretty sexy!
    If you are late for any meeting because of traffic or whatever, just take your phone and message Sicky to cancel your next meeting.

Feel free to get in touch with me, if you have any questions or suggestions!

Enjoy and have fun with Sicky!

Best regards,
Daniel

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.