Documentation

Powered by Algolia

Food Delivery app tutorial

For this example application, we will create a completely voice-enabled Food Delivery application. Let's start by creating 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 browser:

Creating Alan Studio project

Let's create a project in Alan Studio:

Adding Alan button

To add Alan button to our webpage, we'll click on "Embed code" (</>). There we have a snippet that we can paste in our page.

Now we have webpage with 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>
    <div class="alan-btn"></div>
    <script type="text/javascript" src="https://tutor.alan.app/web/lib/alan_lib.js"></script>
    <script>
        alanBtn({
            key: "3bfbf8d2a24e47b23446ed6112aad3fd2e956eca572e1d8b807a3e2338fdd0dc/stage",
            onCommand: function (commandData) {
            },
            rootEl: document.getElementById("alan-btn"),
        });
    </script>
</body>


</html>

Your Alan Key will be unique to your own project.

Now we can refresh the page and use voice commands with Alan. Try pressing the Alan button and say “Hello”.

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

Creating Alan script

Let's now create the script and add simple intent to it.

tutorial script:

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

Save the script and say to Alan 'I want pepperoni'. It should answer 'adding pepperoni'. We can try it in the Debug Chat on the right side of Alan Studio or directly in our page.

Alternatives

What if the user instead says 'add pepperoni' or 'pepperoni'? To be sure that the intent will work properly let's add some alternatives:

tutorial script:

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

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

Command handler

On our page, we want to return not only voice but also information about what item should be added to order. Let's modify our script:

tutorial script:

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

Let's add the function addItemToCart to our page and change onCommand function:

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);
        }

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

</html>

Alan now returns the voice response and the command's JSON object. We then check if the command is 'addItem', and if so will invoke the addItemToCart function.

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

More items

Now we can add pepperoni to order, but we have another items. Let's add parameter to our 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 you can add a burger or burrito or other items from itemList to your order.

Follow

We want the ability to checkout, ask user for their address, and deliver the food.

Let's modify script and webpage:

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);
});

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);
        }

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

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

</html>

After adding food, say 'checkout' and your address.

How it works: when we ask for checkout, we answer the user with 'What is the delivery address?' and then activate the context whatAddress. This context has one follow. A follow is similar to an intent but will work only after an initial intent has been matched or the context has been activated.

Visual hints

Now we want to help our users understand what our voice experience can do. Let's add some hints:

tutorial script:

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

visualHints(
    `(add|I want|) (${itemList})`,
    "I'm ready to checkout"
);

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);
});

Now that we've finished with the basics of our application, we can add more complex functions.

Adding several items

What if 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(data.item, data.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 command changeOrder and we can pass a 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: item,
        quantity: number
    });
    p.play(`adding ${number} ${p.ITEM}`);
});
...

see full source | try in browser | try in jsfiddle

We've added $(NUMBER) parameter to the intent. It’s a special parameter, that accepts numbers. We can now say 'add five burrito':

But it won't accept 'add five burritos'. To fix this we have two options: we can add plural alternatives like 'burrito|burritos' in the intent, or we can just use an underscore on one of the 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('|');

visualHints(
    `(add|I want|) (${items.join('|')})`,
    "I'm ready to checkout"
);

// 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':

Removing items

Now we'll 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 deteleQnty = p.NUMBER ? p.NUMBER.number : 1;

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

see full source | try in browser | try in jsfiddle

Now we can add and remove items.

Removing items - improvements we can make

We can remove items, but have another requirement: if the user tries to remove an item that isn’t present in the order we need to answer 'This item isn’t in your order'. To implement this we need the order state on the script side. To pass some information from a website(or app) to the Alan script we have two options: invoke the script function using projectAPI and pass the parameters to it(projectAPI will be described later) or pass visualState. Using visualState we can pass some object to Alan script that describe our application state. Let's modify the webpage:

...
        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;
            sendVisualState();
        }
...

see full source | try in browser | try in jsfiddle

Now we can use this visualState in our script:

...
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 deteleQnty = p.NUMBER ? p.NUMBER.number : quantity;

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

see full source | try in browser | try in jsfiddle

Order detail

We want Alan to describe what do we have now in our order. Let's add 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 the user can get information about their order. But what if the user hasn't ordered anything yet? In this case we can add an if statement in the function and check the size of p.visual.order, or we can add another intent and filter the intent 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

We've added a function as a first argument of the intent that accepts a visual state as the parameter. Now the user will get the correct answer if they have an empty order.

Balance

Every user of our application has a dollar balance for their order. We need to show it on the page when they login 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 login using username alan and password alan.

To get the balance from our Alan script we need to pass an access token to script. We can make it using a visual state or using projectAPI. Let's implement a function in projectAPI:

...
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

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

Let's add invocation of projectAPI function from 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

We set the token to p.state object. We can store the state in this object in addition to p.visualState. 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've 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:

Time of delivery

What if the user wants to have delivery at specific time? Let's modify our page and script:

...
        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

...
// 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 use $(TIME) and $(DATE) parameters. These parameters can parse time and date from the user request. Also we use api.moment - 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've created a Food Delivery application and added a Conversational Voice Experience to it!