Over the last few years, voice assistants have changed the way we interact with our devices. To some, this was a somewhat strange experience, but many more felt that this was a more natural way of interacting with most services provided by our phones and computers.
Many companies took this as an opportunity to enhance the experience for their customers and provided some of their core functionality via a set of voice commands, thus becoming more customer-friendly and strengthening their brand.
Voice chatbots are not only popular because of the convenience of talking to a device, but they also come very handy, when your hands are busy (ex. when you are cooking) or more importantly when your eyes should be focused elsewhere (ex. when you are driving).
In this article, you will learn how to build your own voice assistant. You will use NativeChat to build an Alexa skill.
To build something worthwhile we need a "real" customer and a set of "real" scenarios.
A telecommunications company called C-Mobile provides various services to its customers. They identified a need to assist their pay-as-you-go customers with various services around topping up their accounts and buying data packages.
As a customer, I want to be able to ask my Alexa device to check my balance.
Alexa should respond with the amount of credit I have left on my account together with the remaining minutes, texts and data.
As a customer, I want to be able to top up my account.
Alexa should guide me through the required steps, provide with a list of options, and at the end provide the updated credit on the account.
As a customer, I want to be able to buy additional data packages.
Alexa should guide me through the required steps, provide me with a list of data packages, which should be paid for with the credits on the account.
Usually, when you build applications for services like this, you will have functionality that allows your user to log in to their specific account. In the case of voice assistants, this usually is handled through the admin portal, which then automatically associates the user account with their app.
This is a whole topic on its own, which I am planning to cover in another blog post. For the purposes of this demo, we will hardcode the user id in the project.
C-Mobiles provides you with a very simple API, which allows you to manage individual accounts.
You can access all of the calls from the following https://demoapis.com/cmobile/012345678/<function-name>
:
Please note that all API calls expect an id parameter. Please pick a number 9-11 digits long, and use it for all of your calls. This way when you top up an account and then ask for the account status, you will see the balance updated.
Also, if you happen to use a number that someone else is also using (this is not very likely unless you use the demo id), just pick a different number and you should be fine.
Here is the list of available functions:
getAccountStatus
allows you to ask for the Account balance, minutes, SMS, and data.
Signature:
/availableCards
You need to provide your selected account id.
Example:
Here is an example of how to get the account balance for id 012345678
https://demoapis.com/cmobile/012345678/getAccountStatus
Result:
{
"balance": 12,
"minutes": 100,
"SMS": 200,
"megabytes": 29,
"data": "29 MB"
}
topUp
allows you to top up your account balance, as a result, the balance will increase and you will receive an updated account status.
Signature:
/topUp?val={amount}&card={4-digits}
You need to provide your selected account id.
Additionally, you need to provide two query params:
val
— with the amount you want to top up.card
— last 4 digits of the card to use, this param is not used for anything, but it is here to simulate the scenario.Example:
Here is an example of how to top the account id 012345678 with 10 credits using the card ending with 9876 (don't worry no card payment will actually happen 😉).
https://demoapis.com/cmobile/012345678/topUp?val=10&card=9876
Result:
{
"SMS": 200,
"balance": 22,
"minutes": 100,
"data": "29 MB",
"megabytes": 29
}
availableCads
allows you to look up all associated payment cards with the account.
Signature:
/availableCards
You need to provide your selected account id.
Example:
Here is an example of how to check what payment cards are associated with the account id 012345678.
https://demoapis.com/cmobile/012345678/availableCards
Result:
[
{
"card": "6575",
"val": 6575
},
{
"card": "3688",
"val": 3688
}
]
resetAccount
allows you to reset your account. This can come useful when you want to start from scratch.
Signature:
/resetAccount
You need to provide your selected account id.
Example:
Here is an example of how to reset the account id 012345678.
https://demoapis.com/cmobile/012345678/resetAccount
Result:
{
"balance": 12,
"minutes": 100,
"SMS": 200,
"megabytes": 29,
"data": "29 MB"
}
dataPackages
allows you to view available data packages for purchase.
For each package, you will receive a name, formatted data size, megabytes, and a price.
Signature:
/dataPackages
No parameters are required.
Example:
Here is an example of how to view available data packages.
https://demoapis.com/cmobile/012345678/dataPackages
Result:
[
{
"name": "lite",
"data": "512 MB",
"megabytes": 512,
"price": 7
},
{
"name": "small",
"data": "1 GB",
"megabytes": 1024,
"price": 10
},
{
"name": "medium",
"data": "3 GB",
"megabytes": 3072,
"price": 20
},
{
"name": "big",
"data": "5 GB",
"megabytes": 5120,
"price": 25
}
]
buyData
allows you to purchase more data for your account. As a result, more data will be added to the account, and the price of the package will be deducted from the balance.
Signature:
/buyData?dataPack={name}
You need to provide your selected account id.
Additionally, you need to provide a query param dataPack
with the name of the package that you want to purchase.
Example:
Here is an example of how to buy a medium data pack for the account id 012345678.
https://demoapis.com/cmobile/012345678/buyData?dataPack=tiny
Result:
{
"SMS": 200,
"balance": 5,
"minutes": 100,
"data": "0.5 GB",
"megabytes": 541
}
We will tackle this project in two rounds.
The getting started is as simple as 1,2,3, which can be done in these really easy steps.
First, you need to sign in to NativeChat Console.
If you don't have an account yet, you can create it here. Don't worry, you can get started for free.
After you sign in you can create a new chatbot.
Press the [+ New bot] button:
This will create a simple chatbot, with a couple of super basic conversations.
To test it, press the [Test] button. Then when the chatbot loads:
Now that you have a working chatbot, it is time for you to implement the first conversation, which is for the check my balance scenario.
When the user says "Check my balance", the chatbot should call the getAccountStatus
function, and then print out the message with the status returned from the API.
Are you ready? Let's go.
In the Cognitive Flow tab (which is the tab you arrive by default), on the right-hand side, there is a list of all conversations in this project. Click on the conversationTwo, which will take you to that conversation.
At the end of the json
containing conversationTwo
add a comma, and in the new line start typing con
, this should trigger a little pop-up with a list of code snippets.
The code snippets are really useful in the process of constructing your chatbot, as they help you generate the JSON in the correct format, plus they save you a lot of time.
Select the conversation-goal
snippet and press enter. This should output the following code:
"conversation-name": {
"type": "goal",
"steps": [
]
}
Change "conversation-name"
to "check-my-balance"
.
Next, you need to add a message step to the conversation.
Hint: If you press tab, the cursor will jump inside the
steps[ ]
array.
From inside the steps[ ]
array, start typing step
(or stme
for step message) and select the step-message
snippet. This should produce the following code:
{
"type": "message",
"messages": [
"Your message"
]
}
Change "Your message"
to "I am checking your balance"
.
The check-my-balance
conversation should look like this:
"check-my-balance": {
"type": "goal",
"steps": [
{
"type": "message",
"messages": [
"I am checking your balance"
]
}
]
}
Here is how to do it:
Next, you need to train the chatbot to understand when to trigger this conversation.
Navigate to the Training tab, click on Conversation built-in, and then press the [Add value] button.
Set the value
to "check-my-balance"
— this how the chatbot engine knows which conversation to trigger
Add the following expressions
— this how you tell the chatbot engine when to trigger this conversation:
Press the [Save] button.
To test this new conversation, press the [Test] button and type: Check my balance
The chatbot should respond with your message.
Here is how to do it:
Now that you have the conversation working, it is time to change it so that it returns real data.
Remove the message step, so that the "steps": [ ]
array is empty.
Start typing stwe
and select step-webhook
. Remove all the properties in the data-source
, but keep the endpoint
.
Add an "entity"
property (it is best to place it below "type": "webhook",
) and call it "status"
— the result of the API call will be stored in status
.
Finally, you need to add a "messages"
property to this step, which will contain the message to be printed when the API returns the result, like this:
"messages": [
"Let's have a look at your account. You have {{status.balance}} dollars left."
]
Hint: You could also, make the response multiline — which is not very important with voice chatbots, as chatbots tend to read the whole output, as one line, but it looks better when we test it in the console.
To add a multiline response, we need to use an array of arrays.
Here are two examples:
One Array
"messages": [ "Line 1", "Line 2", "Line 3" ]
This will result in one of the lines printed (or spoken) at random.
Two Arrays
"messages": [ [ "Line 1", "Line 2", "Line 3" ] ]
This will result in all of the lines printed (or spoken).
Here are messages
containing all of the data returned from the getAccountStatus
API call:
"messages": [
[
"Let's have a look at your account. You have:",
"{{$currency status.balance 'USD'}}",
"{{status.minutes}} minutes, {{status.SMS}} text messages",
"and {{status.data}} left"
]
]
The whole check-my-balance
conversation should look like this:
"check-my-balance": {
"type": "goal",
"steps": [
{
"type": "webhook",
"entity": "status",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/getAccountStatus"
},
"messages": [
[
"Let's have a look at your account. You have:",
"{{$currency status.balance 'USD'}}",
"{{status.minutes}} minutes, {{status.SMS}} text messages",
"and {{status.data}} left"
]
]
}
]
}
To test this new conversation, press the [Test] button and type: What is my balance?
The chatbot should respond with your message.
Here is how to do it:
Before you move on, it is a good idea to tidy up the initial messages.
Your chatbot project has 3 support conversations:
welcome
— this conversation is triggered when you start talking with your chatbot. This conversation triggers the help
conversation.help
— this conversation is triggered when the chatbot believes that you might need help.restart
— this conversation is triggered when you type/say "restart". This conversation triggers the welcome
conversation.Update the welcome message
Find the welcome
conversation and change: "This is a welcome conversation for your chatbot"
text to "Welcome to the c-mobile self service."
Update the help message and the list of proposed actions
Find the help
conversation and remove the line "If you get stuck, you can always restart our conversation by typing 'restart'",
. This way the intro conversation will be a lot shorter.
Additionally, you should change the display
options from "Conversation 1", "Conversation 2"
to "Check my balance", "Top up", "Buy data"
. You will implement Top up
and Buy data
later, but it is good to already have these options.
Your welcome
and help
conversations should look like this:
"welcome": {
"type": "support",
"steps": [
{
"type": "message",
"messages": [
"Welcome to the c-mobile self-service."
]
},
{
"type": "conversation",
"conversation": "help",
"conditions": [
"{{$not ($has conversation) }}"
]
}
]
},
"help": {
"type": "support",
"steps": [
{
"type": "message",
"messages": [
[
"Here is what I can do for you:"
]
],
"display": {
"type": "quick-reply",
"data": [
"Check my balance",
"Top up",
"Buy data"
]
}
}
]
},
To test this new configuration, press the [Test] button and type: Hi
The welcome message should be different.
Additionally, you can remove ConversationOne
and ConversationTwo
, as these are not needed anymore.
This should be done in two steps:
json
from the Cognitive Flow — this can be done by clicking the little -
sign next to the conversation you want to remove, then highlight that line and the one below and delete.Conversation
then press the trash can icon next to ConversationOne
and ConversationTwo
.The whole cognitive flow should look like this:
{
"conversations": {
"welcome": {
"type": "support",
"steps": [
{
"type": "message",
"messages": [
"Welcome to the c-mobile self service."
]
},
{
"type": "conversation",
"conversation": "help",
"conditions": [
"{{$not ($has conversation) }}"
]
}
]
},
"help": {
"type": "support",
"steps": [
{
"type": "message",
"messages": [
[
"Here is what I can do for you:"
]
],
"display": {
"type": "quick-reply",
"data": [
"Check My Balance",
"Top up",
"Buy more data"
]
}
}
]
},
"restart": {
"type": "support",
"steps": [
{
"type": "message",
"messages": [
"Your conversation is restarted."
]
},
{
"type": "conversation",
"conversation": "welcome"
}
]
},
"check-my-balance": {
"type": "goal",
"steps": [
{
"type": "webhook",
"entity": "status",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/getAccountStatus"
},
"messages": [
[
"Let's have a look at your account. You have:",
"{{$currency status.balance 'USD'}}",
"{{status.minutes}} minutes, {{status.SMS}} text messages",
"and {{status.data}} left"
]
]
}
]
}
},
"settings": {
"invalid-replies": [
"I am not sure I understood what you said."
],
"general-failure": [
"We are experiencing technical difficulties at this moment."
],
"previous-conversation-messages": [
"I am going back to the {{ conversationDisplayName }} now."
]
},
"commands": {
"NEXT-PAGE": [
"Next 5"
],
"RESTART": [
"restart"
]
}
}
Now that you have a working chatbot, it is time to start talking to it with actual voice commands. The best thing is that you don't even need an Alexa device to do that.
All you need is a configured Alexa Developer Console and the NativeChat Proxy skill.
Next, you need to go to the Alexa Developer Console and open the Alexa Test simulator.
To open the simulator you need to use an Alexa skill. If you already have one, you can just go to the Test tab and you are good to go.
If you don't have an Alexa skill yet, here is what you need to do:
In the Alexa Developer Console, press the Create Skill button.
Note, you could use this skill later when you are ready to publish your chatbot as an Alexa skill.
Call the skill C Mobile, and select Custom model and Provision your own hosting method, and press the Create skill button.
Select the Start from scratch template, and press the Choose button.
Open the JSON Editor, and find "Amazon.FallbackIntent" and set the samples to "Sample" (at this stage it could be any word, we just need something in there), it should look like this:
{
"name": "AMAZON.FallbackIntent",
"samples": [
"Sample"
]
},
Press the Build Model button and wait for a little bit.
Finally, open the Test tab, and switch the skill testing from Off to Development.
Here is how to do it:
NativeChat Proxy is a skill, which is designed to easily connect with your NativeChat chatbots without having to publish a new skill. It works like a sandbox skill, which relays all messages from the user to the connected NativeChat chatbot.
You can install it using the Alexa Developer Console. Just type:
enable nativechat proxy
Note: the NativeChat Proxy skill, works with the following languages:
Now, to complete the loop, you just need to get the proxy id and pass it to the NativeChat Proxy skill.
In NativeChat, expand the Test options, and choose Test in Alexa Developer Console. This will provide you with instructions on how to make it work.
You should see something like this:
Copy the last message that contains the proxy id. (hint. you can click on the little icon next to it).
Go back to the Alexa Developer Console:
And voila, your chatbot is ready to listen and to speak back to you.
Here is how to do it:
There are two ways that you can interact your chatbots in Alexa Developer Console.
Note, if you reload the Alexa Developer Console page, or close it and open it again, then the console will disconnect from the NativeChat Proxy skill. All you need to do is say: "NativeChat Proxy", and you will be back where you left it (no need to provide the Proxy ID again).
To hear the welcome message, say: "hi"
Then say: "Check my balance"
And just like that, you have just talked to your first NativeChat chatbot through an Alexa skill.
Well done, you deserve a pat on the back:
The way this works is pretty straight forward.
One of the trickiest challenges you will face is with voice recognition.
There might be cases when your users will try to say things like: "Pay now", while Alexa might understand it as "Play now". This can be quite problematic when your chatbot expects a specific item.
To work around that, you should train your chatbot to understand different ways of saying the same thing — this includes different phrases, but also different words that sound similar — so that it would respond with the same action regardless of how someone might pronounce their commands.
In the case of this chatbot, a user could say: "Check my balance", which Alexa might understand as "Shake my balance". This is still close enough, so NativeChat might accept it.
However, if you are struggling with some voice commands, you can investigate what messages are sent to NativeChat, and how NativeChat interpreted them. This will come especially useful when you start using your chatbots outside of the Alexa Developer Console.
In NativeChat portal, navigate to the History tab. Find the conversation that was causing trouble and click on it.
Hint: you can add a filter to show only conversations for specific dates, or Alexa only.
From here, you can see all the messages sent and received. If you click on the user input, you will see how this was interpreted by NativeChat. In the case of "Shake my balance", NativeChat was 75% sure that you wanted to check your balance, so all is good.
To make it 100%, you would need to add "Shake my balance" to the Conversation training for check-my-balance.
Now that you have your chatbot connected with Alexa, you can proceed with implementation of the remaining conversations, "Top up" and "Buy data".
This time, you will be able to edit the conversations and test them straight away with voice commands. No need to configure the proxy id, or anything else. All changes will be available in Alexa as soon as you save them.
In this conversation the chatbot should ask the user:
Then finally, it should either execute the top up (if confirmed) or cancel the process (if confirmation rejected).
For this conversation, you should use the following API calls:
availableCards
— used to get a list of payment cards associated with the account
account id
topUp
— used to perform the top up
account id
and card number
Reminder: to avoid conflicting with other people using this API, please use a different account id to the one used in the example (012345678).
First, you need to create a new conversation called top-up
, which is done just like you did it with the check-my-balance
.
"check-my-balance"
code.con
, and select the conversation-goal
snippet and press enter. "conversation-name"
to "top-up"
.Add a sample step
Just to see that the conversation works, you should add a sample message step.
steps
array, start typing step
and select the step-message
snippet.Set the message to "top-up works"
.
The conversation should look like this:
"top-up": {
"type": "goal",
"steps": [
{
"type": "message",
"messages": [
"top-up works"
]
}
]
}
Train the chatbot to know when to use your new conversation
Finally, train the chatbot to understand when to trigger this conversation.
value
to "top-up"
Add the following expressions:
Press the [Save] button.
Test
To test this, go to Alexa Developer Console, and say Top up or Add more funds
Alexa should respond with your message.
Note #1
If Alexa doesn't understand your expressions, like when you say "top up" it might understand it as "top pop" then you can add this expression to the training.
Note #2
You should be able to continue to use your chatbot through the proxy app. But if not just say "NativeChat Proxy".
Now, that you have the top-up
conversation wired up, it is time to implement it with the proper logic.
Note, you should test the conversation each time you add a new step.
Clean up
Start by removing the sample message step, so that the steps
array is empty, like this
"top-up": {
"type": "goal",
"steps": [
]
}
The first step of this conversation is to ask the user how much they would like to top up.
In the steps
array, start typing step
and select the step-question
snippet.
You should be presented with the following code:
{
"type": "question",
"entity": "entity-name",
"entity-type": "",
"messages": [
"How to ask for entity?"
]
}
Here is what his all means:
entity
— the name of the variable where the user answer is going to be stored. Note this is not going to be the whole expression that the user will say, but the actual value that you are after
entity-type
— the type of the entity that you are after, this is how the chatbot will know what to find the value that you are after
messages
— the expression your chatbot will use to ask for user input
Your step should look like this:
{
"type": "question",
"entity": "top-up-value",
"entity-type": "Number",
"messages": [
"How much would you like to top up?"
]
}
Press the [Save] button and test.
Test
Now, when you say:
Alexa will not say anything after you provide the answer. Don't worry, that is OK, as you don't need to confirm the answers provided to the chatbot questions.
Adding a reaction
Note, that the chatbot can recognize entity values at any time during the conversation. For example, when you say "Top up twenty five", the chatbot will understand that:
top-up
top-up-value
is25
In this case, the chatbot should respond with a confirmation that it understood the extra entity value. This is done with acknowledgements.
After the end of messages array, add a comma, then add the following code:
"reactions": {
"acknowledgements": [
"I understand that you want to top up {{$currency top-up-value 'USD'}}"
]
}
Press the [Save] button and test.
Test
Now, when you say: "Top up twenty five"
Alexa should respond with: "I understand that you want to top up $25.00"
The full step should look like this:
{
"type": "question",
"entity": "top-up-value",
"entity-type": "Number",
"messages": [
"How much would you like to top up?"
],
"reactions": {
"acknowledgements": [
"I understand that you want to top up {{$currency top-up-value 'USD'}}"
]
}
},
The next step should be to ask the user to provide the payment card they want to use.
In the case of the c-mobile API, you only need to provide the last 4 digits of the card, which is already stored in the system. You can see all available cards by calling: https://demoapis.com/cmobile/012345678/availableCards.
Go to the Cognitive Flow tab, and find the end of the top-up-value
question step.
Add a comma, and start typing stq
and select the step-question
snippet.
Set the properties to:
entity
: cardentity-type
: Numbermessages
: Which card would you like to use?Make it explicit
Additionally, to avoid the number in the card ending clashing with the top-up-value
, you need to make this question explicit. This means that when the user is asked for the card number, no other entities of type Number can be updated.
Add a new line after entity-type
and add "is-explicit": true,
Provide possible values
To help the user choose the right value, you can call availableCards
, and provide the users with the possible values.
After the messages
array, add a comma and then add the following code:
Reminder: to avoid conflicting with other people using this API, please change account id
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards"
},
"template": "ending **{{card}}"
}
Press the [Save] button and test.
Test
Now try to say:
Alexa truncating leading zeroes
Note, when you tell Alexa a number that starts with leading zeroes, Alexa will skip these digits.
For example, input: Use card 0020, will be captured as Use card 20.
Make sure to be aware of this behavior, so that when you expect a 4 digits card or PIN, and if you receive less, you should be safe to assume that the missing digits are zeroes.
(Optional) Validation
If you would like to make this conversation more robust and make sure that the user always provides a card number that is actually stored on the system, you could use a validation.
There are various types of validations, which allow you to validate that a provided value is a telephone number, or that it matches a specific regular expression, and many more. You can read all about validation rules in the docs.
The validation that you need to use in this scenario is a custom
webhook
validation. This validation allows you to execute a query, then validate that the entity value matches the _response
returned from the query.
Add the following code after the display
section:
Reminder: remember to update your account id
"reactions": {
"validations": [
{
"type": "custom",
"parameters": {
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards",
"selector": "$[:].val"
},
"condition": "{{$in card _response}}",
},
"error-message": [
"Card number {{card}} not found on the system."
]
}
]
}
Here is how to understand this code:
data-source
endpoint
: contains the URL with a query
selector
: parses the response to a specific format, it uses JSON Path Expressions to do the job.
In this case, the response from /availableCards query will look something like this:
[
{
"card": "6575",
"val": 6575
},
{
"card": "3688",
"val": 3688
}
]
While you just want to check if the card
value matches one of the val
values.
To do that $.[:]
will give you all objects from the response, while .val
will return all values of val
. As a result $:[:].val
will return:
[
6575,
3688
]
condition
: the expression to test the validation.
$in card _response
checks if the value of card
exists in the parsed _response
error-message
: the error message, you can use {{card}}
to tell the user what card number doesn't seem to work.
Press the [Save] button and test.
Test
Now try to say:
The full step should look like this:
{
"type": "question",
"entity": "card",
"entity-type": "Number",
"is-explicit": true,
"messages": [
"Which card would you like to use? "
],
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards"
},
"template": "ending **{{card}}"
},
"reactions": {
"validations": [
{
"type": "custom",
"parameters": {
"condition": "{{$in card _response}}",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards",
"selector": "$[:].val"
}
},
"error-message": [
"Card number {{card}} not found on the system."
]
}
]
}
}
Before, the chatbot performs the top-up operation, it should ask the user to confirm the top-up-value and the card.
This can be done with a Confirmation step.
Go to the end of the card question step, add a comma and start typing stco
and select the step-confirmation
snippet. The snippet should look like this.
{
"type": "confirmation",
"entity": "result-entity-name",
"messages": [
"Confirm action?"
]
}
Set the properties to:
entity
: top-up-confirmation,messages
: Just to confirm. Do you want to top up {{$currency top-up-value 'USD'}} with the card ending with {{card}}?Press the [Save] button and test.
Test
Now try to say:
top-up-value
and the card
number.The full step should look like this:
{
"type": "confirmation",
"entity": "top-up-confirmation",
"messages": [
"Just to confirm. Do you want to top up {{$currency top-up-value 'USD'}} with the card ending with {{card}}?"
]
}
If the user rejects the confirmation, then the chatbot should respond with a message confirming the choice.
This can be done by simply adding a new message step.
However, you want this step to only trigger when top-up-confirmation
is false
. This can be done with the help of the conditions
property.
You can learn more about Conditions in the docs.
Add a new message step at the end of the conversation, start typing stme
and select the step-message
snippet.
Set the messages
to Top-up has been cancelled.
Add the conditions
property with the following (self-explanatory) condition:
"conditions": [
"{{$not top-up-confirmation}}"
]
Press the [Save] button and test.
Test
Start the chat, and say "No" when you get asked to confirm.
The chatbot should respond with the cancellation message.
The full step should look like this:
{
"type": "message",
"messages": [
"Top-up has been cancelled"
],
"conditions": [
"{{$not top-up-confirmation}}"
]
},
The final step is to execute the top-up call, by calling the cmobile API topUp
function. This operation can be done with a Webhook step.
However, once again you don't want this step to be executed every time. You want this step to be executed when top-up-confirmation
is true
.
Add a new Webhook step at the end of the conversation, start typing stwe
and select the step-webhook
snippet. The snippet should look like this:
{
"type": "webhook",
"data-source": {
"endpoint": "https://",
"method": "POST",
"headers": {
"header name": "header value"
},
"payload": {
"key": "value"
}
}
}
Data Source
You don't need the method
, headers
and payload
properties, so just delete them. Then update the endpoint
to call the topUp
API function and pass top-up-value
as val
, like this:
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/topUp?val={{top-up-value}}"
},
Condition
To make sure that this step is only triggered when the user confirms they want to proceed, add the following conditions
property to the step (not inside the data-source
):
"conditions": [
"{{top-up-confirmation}}"
]
Confirmation message
Finally, you need to display a message confirming that the transaction is complete.
To do that you need to add two properties: entity
and messages
.
Add an entity
property called top-up-response (it is best to add it below type
)
"entity": "top-up-response",
Add a messages
property with the following message (it is best to add it below conditions
:
"messages": [
"Your new balance is {{$currency top-up-response.balance 'USD'}}"
]
The full step should look like this:
{
"type": "webhook",
"entity": "top-up-response",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/topUp?val={{top-up-value}}"
},
"conditions": [
"{{top-up-confirmation}}"
],
"messages": [
"Your new balance is {{$currency top-up-response.balance 'USD'}}"
]
}
Press the [Save] button and test.
Test
Go through the chat conversation, and say "Yes" when you get asked to confirm. The chatbot should execute the Top-Up API call and respond with updated balance value. It should be increased by the amount specified in the first step.
The whole top-up conversation should look like this:
"top-up": {
"type": "goal",
"steps": [
{
"type": "question",
"entity": "top-up-value",
"entity-type": "Number",
"messages": [
"How much would you like to top up?"
],
"reactions": {
"acknowledgements": [
"I understand that you want to top up {{$currency top-up-value 'USD'}}"
]
}
},
{
"type": "question",
"entity": "card",
"entity-type": "Number",
"is-explicit": true,
"messages": [
"Which card would you like to use? "
],
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards"
},
"template": "ending **{{card}}"
},
"reactions": {
"validations": [
{
"type": "custom",
"parameters": {
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/availableCards",
"selector": "$[:].val"
},
"condition": "{{$in card _response}}"
},
"error-message": [
"Card number {{card}} not found on the system."
]
}
]
}
},
{
"type": "confirmation",
"entity": "top-up-confirmation",
"messages": [
"Just to confirm. Do want to top up {{$currency top-up-value 'USD'}} with the card ending with {{card}}?"
]
},
{
"type": "message",
"messages": [
"Top up has been cancelled"
],
"conditions": [
"{{$not top-up-confirmation}}"
]
},
{
"type": "webhook",
"entity": "top-up-response",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/topUp?val={{top-up-value}}"
},
"conditions": [
"{{top-up-confirmation}}"
],
"messages": [
"Your new balance is {{$currency top-up-response.balance 'USD'}}"
]
}
]
}
In this conversation the chatbot should:
For this conversation, you should use the following API calls:
dataPackages
— used to get a list of available data packs
buyData
— used to purchase the selected data pack
account id
and data-pack
Reminder: to avoid conflicting with other people using this API, please use a different account id to the one used in the example (012345678).
First, you need to create a new conversation called buy-data
, which is done just like you did it with the top-up
.
Go to the Cognitive Flow tab, and find the end of the "top-up"
code.
con
, and select the conversation-goal
snippet and press enter. "conversation-name"
to "buy-data"
."steps"
array empty.Train the chatbot to know when to use your new conversation
Finally, train the chatbot to understand when to trigger this conversation.
value
to "buy-data"
Add the following expressions:
Press the [Save] button.
For the chatbot to allow the user to select a Data Pack, you need to train it, so that it understands what Data Packs are available, and how to extract it from a sentence.
For example, when a user says: "I want a small data pack"
The chatbot should understand that small, is the name of the required Data Pack.
Add DataPack to the Entity training list
Creating new entities is quite simple.
Open the Training tab and press the [Add new] button and set:
name
to DataPack - this will be the name of your new Entity TypeLookup Strategy
to Keyword - this means that there is a specific list of expected valuesTraining data source
to Dynamic - this means that the list of values can be loaded dynamicallyEndpoint URL
to https://demoapis.com/cmobile/012345678/dataPackages - this is the URL where the data is coming fromValue template
to {{name}} - this indicates which field should be used for training of the Entity TypePress the [Test] button, which should display a list of possible values.
If everything looks fine, then press the [Create] button.
NativeChat will pull the data, and train the data model to understand the values for DataPack.
Now, that you have the buy-data
conversation wired up, and a data model for DataPack, it is time to implement the logic.
The first step should be to provide the user with the list of available data packs and ask them to select one.
In the steps
array, start typing stq
and select the step-question
snippet. Set:
entity
to data-packentity-type
to DataPackmessages
to "Which data pack would you like?"At this point, your code should look like this:
{
"type": "question",
"entity": "data-pack",
"entity-type": "DataPack",
"messages": [
"Which data pack would you like?"
]
},
This should be enough to let the user choose a Data Pack, however, we should let user what Data Packs are available.
Provide possible values
To help the user choose a DataPack, you can call dataPackages
, and provide the users with the possible values.
After the messages
array, add a comma and then add the following code:
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/dataPackages"
},
"template": "{{name}} {{data}} for {{$currency price 'USD'}}"
}
Press the [Save] button and test.
The full step should look like this:
{
"type": "question",
"entity": "data-pack",
"entity-type": "DataPack",
"messages": [
"Which data pack would you like?"
],
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/dataPackages"
},
"template": "{{name}} {{data}} for {{$currency price 'USD'}}"
}
},
The final step is to execute the buy data call, by calling the cmobile API buyData
function. This operation can be done with a Webhook step.
Add a new Webhook step at the end of the conversation, start typing stwe
and select the step-webhook
snippet.
Data Source
You don't need the method
, headers
and payload
properties, so just delete them.
Then update the endpoint
to call the buyData
API function and pass data-pack
as dataPack
, like this:
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/buyData?dataPack={{data-pack}}"
},
Confirmation message
Finally, you need to display a message confirming that the transaction is complete. To do that you need to add two properties: entity
and messages
.
Add an entity
property called buy-data-response (it is best to add it below type
)
"entity": "buy-data-response",
Add a messages
property with the following message (it is best to add it below conditions
:
"messages": [
"Your purchase is complete. You now have {{buy-data-response.data}}. Your balance is {{$currency buy-data-response.balance 'USD'}}"
]
The full step should look like this:
{
"type": "webhook",
"entity": "buy-data-response",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/buyData?dataPack={{data-pack}}"
},
"messages": [
"You now have {{buy-data-response.data}}. Your balance is {{$currency buy-data-response.balance 'USD'}}"
]
}
Press the [Save] button and test.
Test
Say: "Add Data"
The chatbot should list the available packages.
Say: "Lite"
The chatbot should execute the Buy Data API call and respond with updated data and balance values.
The whole buy-data conversation should look like this:
"buy-data": {
"type": "goal",
"steps": [
{
"type": "question",
"entity": "data-pack",
"entity-type": "DataPack",
"messages": [
"Which data pack would you like?"
],
"display": {
"type": "quick-reply",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/dataPackages"
},
"template": "{{name}} {{data}} for {{$currency price 'USD'}}"
}
},
{
"type": "webhook",
"entity": "buy-data-response",
"data-source": {
"endpoint": "https://demoapis.com/cmobile/012345678/buyData?dataPack={{data-pack}}"
},
"messages": [
"You now have {{buy-data-response.data}}. Your balance is {{$currency buy-data-response.balance 'USD'}}"
]
}
]
}
Just like that, you have created a fully functioning Alexa Skill! It can communicate using Natural Language Processing (NLP) while connecting with the cmobile API to provide the users with the ability to check their account status, top up and buy more data.
There is still more to learn. You can learn more from the NativeChat documentation.
Sebastian Witalec is a Senior Developer Advocate for Progress who specializes in Angular and NativeScript. He loves working on both serious and fun projects and one day he will use his robot army to conquer the world.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites