Documentation

Powered by Algolia

Creating a voice-enabled food delivery app: complete tutorial

In this tutorial, we will create a completely voice-enabled food delivery application. The application users will be able to run the following voice commands:

  • Add items to the cart
  • Remove items
  • Check out items
  • Check order details
  • Check the balance
  • Set delivery time

What you will learn

While going through this tutorial, we will cover the Alan essentials: intents, alternatives, variables, contexts and so on. On completing, you will learn how to use them to add a voice experience to your application.

What you will need

This is a getting started tutorial. No prior knowledge is required.

Step 1: Try voice interaction

Before we start creating a voice interface, let's try a finished sample. This will give you an idea of what you are building.

Open the application, at the bottom right corner click the Alan button, enable microphone access if required and try saying the following commands:

  • 'I want pepperoni'
  • 'What is my order?'
  • 'Checkout'

Then provide your delivery address and delivery time.

Step 2: Create the application

Now let's start. We will first create an HTML webpage.

tutorial.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Food Delivery Example</title>
    <link href="https://storage.googleapis.com/alan-tutorial/web-sdk/styles.css" rel="stylesheet">
</head>

<body>
    <h1>Food Delivery</h1>
    <h3>Menu</h3>
    <div class="menu">
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/pepperoni.jpg"/>
            Pepperoni
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/margherita.jpg"/>
            Margherita
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burrito.jpg"/>
            Burrito
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burger.jpg"/>
            Burger
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/taco.jpg"/>
            Taco
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/applepie.jpg"/>
            Apple Pie
        </div>
    </div>

    <ul id="order"></ul>
    <div id="address"></div>
</body>

</html>

We can open this file in the browser:

Step 3: Create an Alan Studio project

To add a voice interface to the application, we need to create a project in the Alan Studio. In the project, we will write a voice script with commands for our application.

In the Alan Studio, click Create New Project, specify the project name and click Create.

Step 4: Add the Alan button

To let users send voice commands to our application, we need to add the Alan button to it.

In the Alan Studio, click Embed code (</>). Here we can see a snippet with the button code. Click Copy all and paste the code to the webpage.

Now we have a webpage with the Alan button:

tutorial.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Food Delivery Example</title>
    <link href="https://storage.googleapis.com/alan-tutorial/web-sdk/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,400i,700,700i,900,900i" rel="stylesheet" />
</head>

<body>
    <h1>Food Delivery</h1>
    <h3>Menu</h3>
    <div class="menu">
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/pepperoni.jpg"/>
            Pepperoni
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/margherita.jpg"/>
            Margherita
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burrito.jpg"/>
            Burrito
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burger.jpg"/>
            Burger
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/taco.jpg"/>
            Taco
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/applepie.jpg"/>
            Apple Pie
        </div>
    </div>

    <ul id="order"></ul>
    <div id="address"></div>
	// Alan button contaner
    <div class="alan-btn"></div>
	// Link to Alan SDK library
    <script type="text/javascript" src="https://tutor.alan.app/web/lib/alan_lib.js"></script>
	// Script section for Alan button
    <script>
        alanBtn({
            key: "3bfbf8d2a24e47b23446ed6112aad3fd2e956eca572e1d8b807a3e2338fdd0dc/stage",
            onCommand: function (commandData) {
            },
            rootEl: document.getElementById("alan-btn"),
        });
    </script>
</body>


</html>

The Alan Button key is unique to every project.

We can now refresh the page and use voice commands with Alan. Try pressing the Alan button and saying “Hello”.

The page works in the latest versions of Chrome, Firefox, Safari and Microsoft Edge. After pressing the Alan button, you need to give microphone access. Some browsers may block microphone access on unsecure pages or allow it only during the current session.

Step 5: Create an Alan script

Let's create a voice script and add a simple voice command, or intent, to it.

In the Alan Studio, open the project, click Add Script, specify the script name and click Add New Script. In the editor, enter the following intent and save the script.

tutorial script:

intent(`I want pepperoni`, reply(`adding pepperoni`));

Now we can check how our command works in the Debug Chat in the right pane of the Alan Studio or directly in the webpage. Click the Alan button and say to Alan 'I want pepperoni'. It should answer 'adding pepperoni'. If you are using the Debug Chat, you can also type the command.

Step 6: Specify alternatives

What if the user instead says 'add pepperoni' or 'pepperoni'? To be sure that the intent works properly, let's add some alternatives using brackets and the | delimiter:

tutorial script:

intent(`(add|I want|) pepperoni`, reply(`adding pepperoni`));

Now 'add pepperoni' or just 'pepperoni' will work.

Step 7: Set the command handler

In the page, we want to not only get a reply but also send a command to add the item to the cart. To do this, let's first add the addItemToCart() function to the webpage.

function addItemToCart(name) {
            var li = document.createElement("li");
            var text = document.createTextNode(name);
            li.appendChild(text);
            document.getElementById("order").appendChild(li);
        }

Now we need to make sure this function is invoked when the user says the necessary command. Let's modify the script in the Alan Studio.

At the previous step, we used the reply() function in the intent to return a response. We can also use an anonymous arrow function to return a response or send a command to our application.

tutorial script:

intent(`(add|I want|) pepperoni`, p => {
    p.play({command: 'addItem', item: 'pepperoni'});
    p.play(`adding pepperoni`);
});

The p variable here references an internal object that we can use to call the Alan Studio SDK methods. We will call the play() method of this object. This method can generate voice responses or send JSON commands to the application. To send a command, we will pass the following JSON object to it: {command: 'addItem', item: 'pepperoni'}.

Now let's change the onCommand function for the Alan button in the webpage so that the addItemToCart() function is invoked once the page receives this command:

tutorial.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Food Delivery Example</title>
    <link href="https://storage.googleapis.com/alan-tutorial/web-sdk/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,400i,700,700i,900,900i" rel="stylesheet" />
</head>

<body>
    <h1>Food Delivery</h1>
    <h3>Menu</h3>
    <div class="menu">
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/pepperoni.jpg"/>
            Pepperoni
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/margherita.jpg"/>
            Margherita
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burrito.jpg"/>
            Burrito
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burger.jpg"/>
            Burger
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/taco.jpg"/>
            Taco
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/applepie.jpg"/>
            Apple Pie
        </div>
    </div>

    <ul id="order"></ul>
    <div id="address"></div>
    <div class="alan-btn"></div>
    <script type="text/javascript" src="https://tutor.alan.app/web/lib/alan_lib.js"></script>
    <script>
	// Adding items to cart
        function addItemToCart(name) {
            var li = document.createElement("li");
            var text = document.createTextNode(name);
            li.appendChild(text);
            document.getElementById("order").appendChild(li);
        }

        alanBtn({
            key: "3bfbf8d2a24e47b23446ed6112aad3fd2e956eca572e1d8b807a3e2338fdd0dc/stage",
			// Invoking addItemToCart when addItem command is received from the voice script
            onCommand: function (commandData) {
                if (commandData.command == "addItem") {
                    addItemToCart(commandData.item);
                }
            },
            rootEl: document.getElementById("alan-btn"),
        });
    </script>
</body>

</html>

Here is how it works: Alan returns a voice response and the command JSON object. We then check if the command is addItem, and if so, invoke the addItemToCart() function and pass item to it.

Now the user can ask 'add pepperoni', which will then be added to the order.

Step 8: Add more items

We can add pepperoni to the order, but we have other items. Let's add a variable to our intent. A variable is defined with $ followed by brackets. In brackets, we provide the variable name and value, and then we can use the variable in the intent.

tutorial script:

const itemList = "pepperoni|margherita|burrito|burger|taco|apple pie";

intent(`(add|I want|) $(ITEM ${itemList})`, p => {
    p.play({command: 'addItem', item: p.ITEM});
    p.play('adding ' + p.ITEM);
});

Now the user can add a burger or burrito or other items from itemList to the order.

Step 9: Perform checkout

We want to have the ability to checkout, ask users for their address and deliver the food. For the checkout intent, we will use a context.

In Alan, a voice script can include one or more contexts. In the context, you can put a part of the dialog that can occur only in specific circumstances (within a context). For example, in our voice script asking for the user address makes sense only if the user has initiated the checkout process. Without checkout, getting the address would be meaningless.

Let's modify our script:

tutorial script:

const itemList = "pepperoni|margherita|burrito|burger|taco|apple pie";

intent(`(add|I want|) $(ITEM ${itemList})`, p => {
    p.play({command: 'addItem', item: p.ITEM});
    p.play('adding ' + p.ITEM);
});

var whatAddress = context(() => {
    follow('$(LOC)', p => {
        p.play({command: "address", address: p.LOC});
        p.play("We will deliver your order to " + p.LOC);
    });
});

intent(`that's (all|it)`, '(ready to|) checkout', p => {
    p.play('What is delivery address?');
    p.then(whatAddress);
});

Here we create a context and assign it to the whatAddress variable.

To let the user run commands placed in the context, we must activate this context. The context is activated by a matching intent (a phrase that the user says), or manually with the then() function. Here we use the latter variant: we create a new intent for checkout and add to it the then() function activating the whatAddress context.

In the context, we use the follow() function for user commands. Just like intents, follows can be used to give a response or send a command. Follows, however, are context-dependent: they work only after the context has been activated.

We also use here the predefined ($LOC) variable. This variable interprets the user input as a location.

Now we need to modify our webpage and add the new command to the Alan button section:

tutorial.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Food Delivery Example</title>
    <link href="https://storage.googleapis.com/alan-tutorial/web-sdk/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,400i,700,700i,900,900i" rel="stylesheet" />
</head>

<body>
    <h1>Food Delivery</h1>
    <h3>Menu</h3>
    <div class="menu">
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/pepperoni.jpg"/>
            Pepperoni
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/margherita.jpg"/>
            margherita
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burrito.jpg"/>
            Burrito
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/burger.jpg"/>
            Burger
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/taco.jpg"/>
            Taco
        </div>
        <div class="menu-item">
            <img src="https://storage.googleapis.com/alan-tutorial/web-sdk/applepie.jpg"/>
            Apple Pie
        </div>
    </div>

    <ul id="order"></ul>
    <div id="address"></div>
    <div class="alan-btn"></div>
    <script type="text/javascript" src="https://tutor.alan.app/web/lib/alan_lib.js"></script>
    <script>
        function addItemToCart(name) {
            var li = document.createElement("li");
            var text = document.createTextNode(name);
            li.appendChild(text);
            document.getElementById("order").appendChild(li);
        }

	    // Setting the user address
        function setAddress(address) {
            document.getElementById("address").innerHTML = "Address: " + address;
        }

        alanBtn({
            key: "3bfbf8d2a24e47b23446ed6112aad3fd2e956eca572e1d8b807a3e2338fdd0dc/stage",
            onCommand: function (commandData) {
                if (commandData.command == "addItem") {
                    addItemToCart(commandData.item);
				// Handling the address command
                } else if (commandData.command == "address") {
                    setAddress(commandData.address);
                }
            },
            rootEl: document.getElementById("alan-btn"),
        });
    </script>
</body>

</html>

Here is how it works: after adding the food, the user says checkout. We answer with What is delivery address? and then activate the whatAddress context. The context sends the address command to the webpage and the address is set.

Step 10: Add several items

What if the user wants to add several items at the same time? To enable this, let's modify our webpage first:

...
    <div id="order"></div>
...
        let order = {};

        function updateCart() {
            let html = "";
            for (let key in order) {
                html += `<tr><td>${key}</td><td>${order[key]}</td>`;
            }
            html = `<table border="0">${html}</table>`;
            document.getElementById("order").innerHTML = html;
        }

        function changeOrder(item, quantity) {
            let number = (order[item] ? order[item] : 0) + quantity;
            if (number <= 0) {
                delete order[item];
            } else {
                order[item] = number;
            }
            updateCart();
        }
...
        alanBtn({
            key: "a3e24e9d94d2e5aa3446ed6112aad3fd2e956eca572e1d8b807a3e2338fdd0dc/stage",
            onCommand: function (commandData) {
                if (data.command === "changeOrder") {
                    changeOrder(commandData.item, commandData.quantity);
                } else if (commandData.command == "address") {
                    setAddress(commandData.address);
                }
            },
            rootEl: document.getElementById("alan-btn"),
        });
...

see full source | try in browser | try in jsfiddle

Now the page accepts the changeOrder command, and we can pass the quantity to it. Let's modify our script:

...
// add items to order
intent(`(add|I want|order) $(ITEM ${itemList})`,
       `(add|I want|order) $(NUMBER) $(ITEM ${itemList})`, p => {
    let number = p.NUMBER ? p.NUMBER.number : 1;
    p.play({command: 'changeOrder', item: p.ITEM, quantity: number});
    p.play(`adding ${number} ${p.ITEM}`);
});
...

see full source | try in browser | try in jsfiddle

We have added the predefined $(NUMBER) variable to the intent. It is a special variable that can interpret the user input as a number. We can now say 'add five burrito':

However, our script won't accept 'add five burritos'. To fix this, we have two options:

  • We can add plural alternatives like burrito|burritos in the intent.
  • We can just use an underscore on items: burrito_.

Let's add the underscore to all of our items:

// menu items
const items = ['pepperoni', 'margherita', 'burrito', 'burger', 'taco', 'apple pie'];

// itemList = "pepperoni_|margherita_|burrito_|burger_|taco_|apple pie_";
const itemList = items.map(i => i + '_').join('|');

// add items to order
intent(`(add|I want|order) $(ITEM ${itemList})`,
       `(add|I want|order) $(NUMBER) $(ITEM ${itemList})`, p => {
    let number = p.NUMBER ? p.NUMBER.number : 1;
    const item = items.find(i => p.ITEM.startsWith(i));
    p.play(`adding ${number} ${p.ITEM}`);
    p.play({command: 'changeOrder', item: item, quantity: number});
});
...

see full source | try in browser | try in jsfiddle

Now we can say 'add five burgers':

Step 11: Remove items

Now we will implement removing items. To remove items, we just need to pass negative numbers to the changeOrder() function:

...
// remove or update order items
follow(`(remove|delete) $(ITEM ${itemList})`,
       `(remove|delete) $(NUMBER) $(ITEM ${itemList})`, p => {
    const item = items.find(i => p.ITEM.startsWith(i));
    let deleteQnty = p.NUMBER ? p.NUMBER.number : 1;

    p.play('removing ' + p.ITEM);
    p.play({command: 'changeOrder', item: item, quantity: -deleteQnty});
});
...

see full source | try in browser | try in jsfiddle

Now we can add and remove items.

Step 12: Remove items - improvements we can make

We can remove items, but have another requirement: if the user tries to remove an item that is not present in the order, we need to answer This item isn’t in your order. To implement this, we need to know the state of the order on the script side.

To pass some information from a website or app to the Alan script, we have two options:

  • Invoke a script function using projectAPI and pass parameters to it (projectAPI is described later in this tutorial)
  • Pass visualState

With visualState, we can pass to the Alan script some object that describes our application state. On the webpage side, we will add the sendVisualState() function that will get the order state. Let's modify the webpage:

...     // Sending visual state to voice script
        function sendVisualState() {
            alanBtnInstance.setVisualState({order});
        }

        function updateCart() {
            let html = "";
            for (let key in order) {
                html += `<tr><td>${key}</td><td>${order[key]}</td>`;
            }
            html = `<table border="0">${html}</table>`;
            document.getElementById("order").innerHTML = html;
			// Calling sendVisualState() function
            sendVisualState();
        }
...

see full source | try in browser | try in jsfiddle

In the voice script, passed objects are available in the p.visual runtime variable. We can use p.visual.order in our script to check if we have ordered anything or not:

...
follow(`(remove|delete) $(ITEM ${itemList})`,
       `(remove|delete) $(NUMBER) $(ITEM ${itemList})`, p => {
    let order = p.visual.order || {};
    const item = items.find(i => p.ITEM.startsWith(i));
    if (!order[item]) {
        p.play(`${p.ITEM} has not been ordered yet`);
    } else {
        let quantity = order[item] ? order[item] : 0;
        let deleteQnty = p.NUMBER ? p.NUMBER.number : quantity;

        if (quantity - deleteQnty <= 0) {
            p.play('removing all ' + p.ITEM);
        } else {
            p.play('updating ' + p.ITEM);
        }
        p.play({command: 'changeOrder', item: item, quantity: -deleteQnty});
    }
});
...

see full source | try in browser | try in jsfiddle

Step 13: Check order details

We want Alan to describe what we have now in our order. Let's add a new intent:

...
// play order details
intent(`(my order|order details|details)`, p => {
    p.play("You have ordered:");
    for (let product in p.visual.order) {
        p.play(p.visual.order[product] + " " + product);
    }
});
...

see full source | try in browser | try in jsfiddle

Now users can get information about their order. But what if the user hasn't ordered anything yet? In this case, we can do either of the following:

  • Add an if statement in the function and check the size of p.visual.order
  • Add another intent and filter the intents by visual state
...
// play order details
intent((v) => !_.isEmpty(v.order), `(my order|order details|details)`, p => {
    p.play("You have ordered:");
    for (let product in p.visual.order) {
        p.play(p.visual.order[product] + " " + product);
    }
});

intent((v) => _.isEmpty(v.order), `(my order|order details|details)`, p => {
    p.play('You have not ordered anything.');
});
...

see full source | try in browser | try in jsfiddle

The filter function is passed as the first parameter to the intent. We have added a function that accepts the visual state as the parameter. Now users will get the correct answer if they have empty orders.

Step 14: Get the balance

Every user of our application has a dollar balance for their order. We need to show it on the page when they log in and allow them to ask about their balance with voice.

To do this, let's modify our webpage:

...
    <div id="login">
        <form onSubmit="login()">
            <label for="username">Username</label>
            <input id="username" type="text" placeholder="Enter Username">
            <label for="password">Password</label>
            <input id="password" type="password" placeholder="Enter Password">
            <input type="submit" value="Login" />
        </form>
    </div>
...
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
...
        function serverRequest(method, data, callback) {
            $.ajax({
                type: 'POST',
                url: 'https://tutor.alan.app/api_playground/' + method,
                crossDomain: true,
                data: JSON.stringify(data),
                dataType: 'json',
                success: callback,
                error: () => alert('POST failed')
            });
        }

        function login() {
            event.preventDefault();
            var username = document.getElementById('username').value;
            var password = document.getElementById('password').value;
            serverRequest(
                'tutorialLogin',
                {username: username, password: password},
                function(res) {
                    if (res.error) {
                        alert(res.error);
                        return;
                    }
                    let token = res.token;
                    document.getElementById('login').innerHTML = 'Hello, ' + username;
                }
            );
        }

        let alanBtnInstance = alanBtn({
...

see full source | try in browser | try in jsfiddle

Now we can log in with the 'alan' username and 'alan' password.

To get the balance from our Alan script, we need to pass an access token from the page to the script. We can make it by using a visual state or projectAPI. Let's implement a function in projectAPI. As well as visualState, projectAPI allows you to provide some data from the application to the Alan script.

...
projectAPI.setToken = function(p, param, callback) {
    if (!param || !param.token) {
        callback("error: token undefined");
    }
    p.userData.token = param.token;
    callback();
};
...

see full source | try in browser | try in jsfiddle

Let's add invocation of the projectAPI function from the webpage:

...
    <div id="balance"></div>
...
        function login() {
            event.preventDefault();
            var username = document.getElementById('username').value;
            var password = document.getElementById('password').value;
            serverRequest(
                'tutorialLogin',
                {username: username, password: password},
                function(res) {
                    if (res.error) {
                        alert(res.error);
                        return;
                    }
                    let token = res.token;
                    alanBtnInstance.callProjectApi("setToken", {token: token}, (err) => { if (err) alert(err)});
                    document.getElementById('login').innerHTML = 'Hello, ' + username;
                }
            );
        }
...

see full source | try in browser | try in jsfiddle

Here we require the NodeJS library. It's available through api.request.

We set the token to the p.userData object. In addition to visualState, we can store the state of the application in this object. With the token in our script, we can now request the balance from the script:

...
function getBalanceFromServer(token, callback) {
    let req = {
        url: "https://tutor.alan.app/api_playground/tutorialBalance",
        method: 'POST',
        json: {
        "token": token
        }
    };
    api.request(req, (err, res, body) => {
        const error = err || body.error;
        if (error) {
            callback(error);
        }
        callback(null, body.balance);
    });
}

projectAPI.getBalance = function(p, param, callback) {
    getBalanceFromServer(p.userData.token, callback);
}

intent('(what is my|) balance', p => {
    if (!p.userData.token) {
        p.play("Please login to get balance");
        return;
    }
    getBalanceFromServer(p.userData.token, (err, balance) => {
        if (err) {
            p.error(err);
            p.play('error');
            return;
        }
        p.play("Your balance is " + balance);
    });
});

see full source | try in browser | try in jsfiddle

We have also added the projectAPI.getBalance function to request the balance from the webpage. Let's add the balance to the webpage:

...
        function login() {
            event.preventDefault();
            var username = document.getElementById('username').value;
            var password = document.getElementById('password').value;
            serverRequest(
                'tutorialLogin',
                {username: username, password: password},
                function(res) {
                    if (res.error) {
                        alert(res.error);
                        return;
                    }
                    let token = res.token;
                    alanBtnInstance.callProjectApi("setToken", {token: token}, (err) => { if (err) alert(err)});
                    requestBalance();
                    document.getElementById('login').innerHTML = 'Hello, ' + username;
                }
            );
        }

        function requestBalance() {
            alanBtnInstance.callProjectApi("getBalance", {}, (err, balance) => {
                if (err) {
                    alert(err);
                    return;
                }
                document.getElementById('balance').innerHTML = "Your balance is: " + balance;
            });
        }
...

see full source | try in browser | try in jsfiddle

Now we can see the balance on the page and can ask for it with voice:

Step 15: Set the delivery time

What if the user wants to have a delivery at specific time? Let's modify our page to add a command for setting the time:

...
        let address, time;
...
        function sendVisualState() {
            alanBtnInstance.setVisualState({order, address, time});
        }
...
        function setAddress(deliveryAddress) {
            address = deliveryAddress;
            document.getElementById("address").innerHTML = "Address: " + address;
            sendVisualState();
        }

        function setTime(deliveryTime) {
            time = deliveryTime;
            document.getElementById("time").innerHTML = "Delivery time: " + time;
            sendVisualState();
        }
...
            onCommand: function (commandData) {
                if (commandData.command === "changeOrder") {
                    changeOrder(commandData.item, commandData.quantity);
                } else if (commandData.command === "address") {
                    setAddress(commandData.address);
                } else if (commandData.command === "time") {
                    setTime(commandData.date + " at " + commandData.time);
                }
            },
...

see full source | try in browser | try in jsfiddle

And a script to add a new context for the delivery time:

...
// request delivery time
let whatTime = context(() => {
    follow('$(TIME)', '$(T now|asap|right now|as soon as possible)', '$(DATE)', p => {
        let time, date;
        if (p.T) {
            // deliver in 30 minutes
            date = api.moment().tz(p.timeZone).format("MMMM Do");
            time = api.moment().tz(p.timeZone).add(30, 'minutes').format("h:mm a");
        } else if (p.TIME) {
            p.state.time = time = p.TIME;
            if (p.state.date) {
                date = p.state.date;
            } else {
                p.play("What date?");
                return;
            }
        } else if (p.DATE) {
            p.state.date = date = p.DATE.moment.format("MMMM Do");
            if (p.state.time) {
                time = p.state.time;
            } else {
                p.play("What time?");
                return;
            }
        }
        if (date && time) {
            p.play({command: "time", time: time, date: date});
            p.play(`We will deliver your order to ${p.visual.address}. Delivery date is ${date} at ${time}`);
        }
    });
});

// request delivery address
let whatAddress = context(() => {
    follow('$(LOC)', p => {
        p.play({command: "address", address: p.LOC});
        p.play("What is delivery time?");
        p.then(whatTime);
    });
});
...

see full source | try in browser | try in jsfiddle

Here we add one more context - whatTime - and activate it from whatAddress. In Alan, this is the recommended activation flow: rather than putting several then() functions in one intent, you should activate one context from another one.

To parse the date and time from the user request, we use the $(TIME) and $(DATE) predefined variables. Also we use api.moment - the moment NodeJS library.

In your application, you can make an order, add or delete from it, or ask Alan to describe what is in the order. Then, our dialog flow allows us to check your balance and select a delivery address and time.

Congratulations! You have created a Food Delivery application and added a Conversational Voice Experience to it!