Adding Chatbots to Your Stream Chat App Using Google’s Dialogflow
Tags: chatbots, dialogflow, stream, vue
Published: 2019-05-27 20:42:49

---
title: Adding Chatbots to Your Stream Chat App Using Google’s Dialogflow
published: true
description: A tutorial guide on how to add Chatbots to Your Stream Chat App Using Google’s Dialogflow
tags: chatbots, dialogflow, stream, vue
canonical_url: 
cover_image: https://paper-attachments.dropbox.com/s_B578722B01C0E1C3073BF987721389E92E15239445247C20BFF11F9031F040D5_1558623527614_Streamcheese.png
---


# Adding Chatbots to Your Stream Chat App Using Google’s Dialogflow


*Originally published at [https://getstream.io](https://getstream.io/blog/adding-chatbots-to-your-stream-chat-app-using-googles-dialogflow/).*


Most tasks are repetitive and time-consuming. What if we could use a bot to help in doing the tasks instead? This will hugely increase productivity. Chatbots are fantastic for this. 

In this tutorial, I’ll walk you through steps to adding a chatbot to your Stream Chat app using Dialogflow and Vue. At the end of this tutorial, you will build a frequently asked questions (FAQs) bot, be more familiar with Stream Chat API, and the webhook system provided by Stream.

Here is a preview of what we’ll be building:

![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558082207354_getsreamChat.gif)

## Prerequisites

To follow along with this tutorial comfortably, the following are expected:

- A basic understanding of JavaScript
- A basic understanding of [Vue.js](https://vuejs.org/)
- You should also have [Node](http://Node.js) installed on your system (version 8.9 or above – preferably the latest 12.x)
- You should have npm or yarn installed on your system
- Have [ngrok](https://ngrok.com/) installed on your system

If you have all the above ready, then let’s get started!

## Set up the Client App – Create a New Vue App

Vue provides a [CLI](https://cli.vuejs.org/guide/creating-a-project.html#installation) for scaffolding a new Vue project. First, you'll need to install the Vue CLI globally on your system (if you don't have it installed already). After that, we’ll create a new Vue project with CLI commands.

Next, create a new Vue project by running the following commands in any convenient location on your system:

```
    # Install Vue CLI globally on your system
    $ yarn global add @vue/cli
    
    # Create a new Vue project (for the prompt that appears, press enter to select the default preset.)
    $ vue create faqx
    
    # Change your directory to the project directory
    $ cd faqx
    
    # Install Stream Chat client SDK
    $ yarn add stream-chat
    
    # Install axios - a library for making request
    $ yarn add axios
    
    # Run the app!
    $ yarn serve

```

Accessing the [URL](http://localhost:8080) displayed on your terminal will take you to a Vue default page.

## Get Your Stream Chat Keys

To start using the Stream Chat API, you need to have an API key. 

Create an account [here](https://getstream.io/accounts/signup/) or [log in](https://getstream.io/accounts/login/) if you already have an account. 

Then, from your [dashboard](https://getstream.io/dashboard): 


- Create a new app using any convenient name. I will call mine “FAQ”
- Fill in the **App Name** as “FAQx" or any name you wish
- Finally, submit the form by clicking on the **Submit** button to create the app


![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558025079426_Screenshot+2019-05-16+at+5.36.10+PM.png)

## 

Once the app is created, you will be provided with some options on your dashboard. Select **Chat** to go the Stream Chat dashboard.


![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558025492908_Screenshot+2019-05-16+at+5.50.06+PM.png)


Next, check **Disable Permissions Checks** and then click on the **Save** button.

Then, scroll to the bottom of the page and take note of your App Access Keys – **Key** and **Secret.**


![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558025727418_Screenshot+2019-05-16+at+5.52.26+PM.png)


Next, create a `.env` file in the root directory of the project and update your Stream keys to it:


```
    VUE_APP_PORT=3000
    VUE_APP_SERVER=http://localhost:3000
    
    VUE_APP_KEY=<YOUR KEY>
    APP_SECRET=<YOUR SECRET>
    
    DIALOGFLOW_PROJECT_ID=<YOUR DIALOGFLOW PROJECT ID>
    GOOGLE_APPLICATION_CREDENTIALS=<GOOGLE SERVICE FILE>
```

Remember to replace `<YOUR KEY>` and `<YOUR SECRET>` with the correct app keys you have noted above.

## Set up the Server

Next, create a new directory named `server` in the root directory of the project. Then open up a new terminal and then change your current directory to the `server` directory. Then install the following dependencies that we’ll need for the server:

```
    $ yarn add express cors body-parser dialogflow path uuid dotenv
```

The above dependencies include:

- `express` – A Node framework we are using to build our server
- `dialogflow` – Dialogflow’s Node SDK
- `dotenv` – An npm package for parsing configs from `.env` files
- [cors](https://www.npmjs.com/package/cors), [body-parser](https://www.npmjs.com/package/body-parser), [uuid](https://www.npmjs.com/package/uuid) and [dotenv](https://www.npmjs.com/package/dotenv) (all excellent npm packages)

Next, create an Express app by creating a new file named `app.js` to the `server` directory and then add the following code to it:

```
    // ./server/app.js
    
    const express = require("express");
    const cors = require("cors");
    const bodyParser = require("body-parser");
    const StreamChat = require('stream-chat').StreamChat;
    const dialogflow = require('dialogflow').v2beta1;
    const uuid = require('uuid');
    
    require('dotenv').config({path:  "../.env"})
    
    const app = express();
    const port = process.env.VUE_APP_PORT || 3000
    
    app.use(cors());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    
    // Initialize Stream Chat SDK
    const serverSideClient = new StreamChat(
        process.env.VUE_APP_KEY, 
        process.env.APP_SECRET
    );
    
    app.get("/", async (req, res) => {
        res.send({ hello: "World!" });
    });
    
    app.listen(port, () => {
        console.log(`Node app listening on port ${port}!`)
    });
```

In the code above, after importing the packages that we have installed,

- We created an [Express](https://expressjs.com/) app using `const app = express();`
- Next, we initialize the Stream Chat SDK
- Then finally, we created an endpoint - `/` (`app.get('/',…`) for testing to know if the app works. So, if you visit `http://localhost:3000/`, you will get a message - `{ hello: 'World!'}`

Next, create a new endpoint for creating a token.


```
    // ./server/app.js
    
    app.post('/login', async (req, res) => {
        const userId = req.body.userId
    
        if (!userId) {
            return res.status(400).send({
                status: "error",
                message: "username and name is required"
            })
        } 
    
        return res.status(200).send({
            status: "success",
            token: serverSideClient.createToken(userId)
        })
    });
```

The token is required for initializing the Stream Chat SDK.

Finally, start up the server:

```
    node app.js
```

If it starts successfully, you will see a message printed to the terminal - “Node app listening on port 3000!”


## Set up Dialogflow

[Dialogflow](https://dialogflow.com/) is a Google-owned developer of human-computer interaction technologies based on natural language conversations. Before you can start using the service of Dialogflow, you need to have an account with them.

Now head to Dialogflow’s website and create a free [account](https://console.dialogflow.com/api-client/#/login) if you don’t have one already. You’ll need a google account to be able to create an account. Once you are on the page, click on the sign in with **Google** button.

From your dashboard,

- Create an agent by selecting **Create Agent.**
- Type in the Agent name as **FAQX.**
- Click the **Create** button to processes the form.


![Creating an Agent](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558051874504_Screenshot+2019-05-17+at+1.05.48+AM.png)


Next, 

1. Click on the gear icon, to the right of the agent name.
2. Enable beta features and APIs.
3. Copy your project ID and update the .env file with it:
    DIALOGFLOW_PROJECT_ID=<YOUR DIALOGFLOW PROJECT ID>
4. Click the **Save** button to save your changes
5. Under the **GOOGLE PROJECT** section, click on the name of the **Service Account**. 


![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558079212528_Screenshot+2019-05-17+at+1.18.00+AM.png)


This will take you to the Google Cloud Platform Service Accounts page, but you first need to update the Service Account's role.

Once the page finishes loading:


1. Click on the menu button in the upper left-hand corner and click on **IAM & admin**.
2. Click on **Service Accounts** in the left-hand menu.
3. Click on the **Create Service Account** button at the top of the page.
4. In the next page, enter a name for the service account and then click on the **CREATE** button to submit the form.
5. Click on **Role** and select **Owner** as the role.


![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558054021559_Screenshot+2019-05-17+at+1.45.23+AM.png)


Then click on the **CONTINUE** Button.


6. Click on the **+ CREATE KEY** button. Click the **CREATE** to download your service key.

A download of the JSON file will start. Copy the download file to the `server` directory of the project.

Then update the `.env` file to reflect the name of the JSON file you just downloaded:

```

    GOOGLE_APPLICATION_CREDENTIALS=<GOOGLE SERVICE FILE>
```

**Prepare Your FAQ Data**

Here is where we prepare our frequently asked questions. Create a new file in any location on your system as `faq.csv`. Then, copy the below FAQ samples to it and save.

```
How can I place orders?, "There are two ways to place orders for our services:"
What does an order cost?, "The costs are calculated according to the amount of time involved and the quality requirements. These vary from project to project. Therefore, per project, you will receive an individual offer on demand."
```

The above is just an example for our testing. Feel free to replace with yours. The first column is the question, while the second column is the answer. The data are comma-separated and no empty rows are expected, else, you will get an error.

Here is a simple example of the format:

```
    An example question 1, An answer 1
    An example auestion 2, An answer 2
```

From the data on the `faq.csv` file, when a user sends in a query as - “**How can I place orders?**”. The expected output from Dialogflow will be - “**here are two ways to place orders for our services:**” and so on.

Next, go back to your Dialogflow dashboard, 


1. Click on the **Knowledge** tab on the left the page
2. Click on the **CREATE KNOWLEDGE BASE** button
3. Type in **FAQ** as the name of the knowledge
4. Click on the **Create the first one** link

![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558055148291_Screenshot+2019-05-17+at+2.03.54+AM.png)


On the popup that appears, 

1. Enter the **Document Name** as “FAQ” 
2. Choose “FAQ" as the **knowledge type**
3. Choose `txt/csv` as the **Mime Type** 
4. Choose **Upload file from your computer** as the **DATA SOURCE**
5. Click on the **SELECT FILE** button and browse through to the CSV file you created above and upload it
6. Then, click the **CREATE** button
7. Click on **ADD RESPONSE**
8. Finally, click the **SAVE** button to register your changes


## Building the App Interface

Now that we have both our client and server apps running, the next thing we’ll do is to create a simple chat interface so we can integrate Dialogflow. 

Vue enables us to build reusable components which make up our app user interface. We’ll split the app UI into smaller components so we can build them separately:

For brevity’s sake, we’ll divide the app into two components:

- `Messages.vue` ****- ****for listing messages and a form input
- `Login.vue` - displays the login form

Create the `Messages.vue` and `Login.vue` files inside the `src/components` directory.

To keep the component file as minimal as possible, I have added all the CSS of the components to a single CSS file. Create the CSS file as  `App.css` in the `src` directory of the project and then add the below styles to it:

```
    /* ./App.css */
    
    html,body{
        width: 100%;
        height: 99vh;
        overflow: hidden;
    }
    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
    }
    .login-container {
        display: grid; 
        grid-template-rows: 4fr 1fr;
        max-height: 320px;
        min-height: 320px;
    }
    input[type="text"] {
        padding: 10px 8px;
        margin-top: 10px;
        border-radius: 2px;
        border: 1px solid darkgray;
        font-size: 16px;
        box-sizing: border-box;
        display: block;
    }
    .inputs {
        text-align: center;
        align-self: center;
        justify-self: center;
    }
    .submit {
        margin-top: 9px;
        padding: 20px;
        background: rgb(99, 99, 212);
        color: white;
        font-size: 16px;
    }
    .chat-message {
        width: 70%;
        margin-top: 4px;
        padding: 4px;
        text-align: left;
        word-wrap: break-word;
        margin: 5px;
    }
    .from-admin {
        background: rgb(150, 178, 183);
        color: rgb(39, 37, 37);
        float: left;
    }
    .from-client {
        background: rgb(48, 13, 79);
        color: white;
        float: right;
    }
    .input-container {
        margin: 0px;
    }
    .chat-input {
        width: 99%; 
        margin-bottom: 0px;
    }
    .client-messages {
        overflow-y: scroll; 
        height: 320px;
    }
    .chat-container {
        position: fixed; 
        right: 0px; 
        bottom: 0px; 
        width: 400px; 
        z-index: 100000; 
        box-sizing: border-box;
    }
    .head {
        padding: 9px; 
        display: grid; 
        background-color: rgb(48, 13, 79); 
        color: white; 
        border-top-left-radius: 5px; 
        border-top-right-radius: 5px;
    }
    .chat-box {
        border-left: 1px solid rgb(48, 13, 79);
        border-right: 1px solid rgb(48, 13, 79);
        background: lightgray;
    }
```

**The Login Component**

We’ll be using the [Single File Component](https://vuejs.org/v2/guide/single-file-components.html) structure for our components.

Add the mark-up for the Login component:

```
    <!-- ./src/components/Login.vue -->
    
    <template>
        <div class="login-container chat-box">
            <div class="inputs">
                <input type="text" placeholder="your username" v-model="username">
            </div>
            <button type="submit" class="submit" v-on:click="login"> Submit </button>
        </div>
    </template>
```

In the preceding code, we added an input form that captures the user username. Also, we added a click event that calls the `login` function when the form is submitted.

Next, add the script section for the Login component.

```
    <!-- ./src/components/Login.vue -->
    
    <script>
    export default {
        data: function () {
            return {
                username: "",
            }
        },
        methods: {
            login() {
                this.$emit("authenticated", this.username);
            }
        }
    }
    </script>
```

Here, we defined the login function that will be called on the mark-up file. In the function, we emit a custom event named `authenticated` to the parent component passing the username along.

**The Messages Component**

Define the messages component that lists messages and holds the form input for adding new messages:

```
    <!-- ./src/components/Messages.vue -->
    
    <template> 
        <div class="chat-box">
            <div class="client-messages ">
                <div
                    class="chat-message" 
                    v-for="message in messages" 
                    v-bind:key="message.id"
                    v-bind:class="[(message.user.id == userId) ? 'from-client' : 'from-admin']"
                >
                    {{ message.text }}
                </div>
            </div>
            <div class="input-container">
                <input
                    class="chat-input" 
                    type="text" 
                    placeholder="enter message..." 
                    v-model="message"
                    v-on:keyup.enter="addMessage"
                >
            </div>
        </div>
    </template>
```

Then add the script section for the messages component:

```
    <!-- ./src/components/Messages.vue -->
    
    <script>
    export default {
        props: ['messages', 'userId'],
        data() {
            return {
                message: ""
            }
        },
        methods: {
            addMessage() {
                this.$emit('new-message', this.message);
                this.message = "";
            }
        }
    }
    </script>
```

## **The App Component**

Now let’s bring all the other component into a single component to build up the interface. Replace the code in the `src/App.vue` file with the below mark-up:

```
    <!-- ./src/App.vue -->
    
    <template>
      <div id="app">
        <div>
          <img alt="Vue logo" src="./assets/logo.png">
        </div>
        <div class="chat-container">
          <div class="head" @click="displayChatArea=!displayChatArea">
            <div style="justify-self: center;"> FAQx </div>
          </div>
          <div v-if="displayChatArea">
            <login
              v-if="!authenticated" 
              v-on:authenticated="setAuthenticated" 
            />
            <messages 
              v-else 
              v-on:new-message="sendMessage"
              :messages="messages"
              :userId="userId"
            />
          </div>
        </div>
      </div>
    </template>
```

Then add the script section to the `src/App.vue` file:

```
    <!-- ./src/App.vue -->
    
    <script>
    import { StreamChat } from 'stream-chat';
    import axios from 'axios';
    
    import Messages from '@/components/Messages.vue';
    import Login from '@/components/Login.vue';
    
    import './App.css';
    
    export default {
      name: 'app',
      components: {
        Messages,
        Login
      },
      data: function () {
        return {
          authenticated: false,
          roomId: "",
          messages: [],
          userId: "",
          displayChatArea: false,
          channel: null,
          token: null,
          client: null
        }
      },
      methods: {
      },
    }
    </script>
```

The Vue app should look like below at this point:

![](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558079976925_Screenshot+2019-05-17+at+8.58.52+AM.png)

## 
## Making Chat Work

So far, we have our chat interface ready but we still can’t converse because we are yet to connect the app to Stream Chat. We’ll be doing so next.

To start using the SDK, we first need to initialize it. Do so by adding the below function in the `methods: {…}`  block in the `App.vue` file:

```
    // ./src/App.vue
    
    // [...]
        async initializeClient () {
          // Initialize the StreamChat SDK
          const client = new StreamChat(process.env.VUE_APP_KEY);
    
          await client.setUser(
            {
              id: this.userId,
              name: this.userId,
            },
            this.token,
          );
    
          this.client = client
        },
    // [...]
```

Next, add a function for creating a new channel for the user that just logs in to the `methods: {…}` block of `App.vue`:

```
    // ./src/App.vue
    
    // [...]
        async initializeChannel () {
          const channel = this.client.channel('commerce', this.userId, {
            name: 'Customer Support',
          });
    
          this.channel = channel
    
          // fetch the channel state, subscribe to future updates
          let state = await channel.watch();
    
          this.messages = state.messages
          
          // Listen for new messages
          channel.on('message.new', event => {
            this.messages.push(event.message)
          });
        },
    // [...]
```

Here, we are creating a new channel for every user that logs in so that their messages are sperate from other users. Then we started listening for new messages on that channel using - `channel.on('message.new...'`.

Next, add a function for logging the user into the `methods: {…}` block of `App.vue`:

```
    // ./src/App.vue
    
    // [...]  
       async setAuthenticated(userId) {
          const response = await axios.post(`${process.env.VUE_APP_SERVER}/login`, {userId})
          
          if (response.data.status === 'success') {
            this.authenticated = true
            this.token = response.data.token
            this.userId = userId
    
            await this.initializeClient()
    
            await this.initializeChannel()
          }
        },
    // [...] 
```

In the proceeding code, we make a post request to the `/login` endpoint on the server to generate a token for the user. The token is required for initializing the StreamChat SDK.

Finally, add a function for sending messages into the `methods: {…}` block of `App.vue`:

```
    // ./src/App.vue
    
    // [...] 
       async sendMessage (message) {
          this.channel && await this.channel.sendMessage({
            text: message
          });
        },
    // [...]
```

When the user submits the message form, we’ll call this function to send a message to the channel.

## Set up the Webhook

For now, we can send a message from to channels but we don’t get a reply because there is no one on the other end to reply. We’ll now employ the service of a chatbot to reply to those messages.

Next, create a function to query Dialogflow for an answer to a given input:

```
    // ./server/app.js
    
    // [...]
    async function getAnswer (question) {
        const sessionId = uuid.v4();
    
        // Create a new session
        const sessionClient = new dialogflow.SessionsClient();
        const sessionPath = sessionClient.sessionPath(
            process.env.DIALOGFLOW_PROJECT_ID, 
            sessionId
        );
    
        // The text query request.
        const request = {
          session: sessionPath,
          queryInput: {
            text: {
              // The query to send to the dialogflow agent
              text: question,
              // The language used by the client (en-US)
              languageCode: 'en-US',
            },
          },
        };
    
        // Send request and log result
        const responses = await sessionClient.detectIntent(request);
    
        return responses[0].queryResult.fulfillmentText;
    }
    // [...]

```

By using [webhooks](https://getstream.io/chat/docs/#webhooks), you can receive all events within your application. When configured, every event happening on Stream Chat will propagate to your webhook endpoint via an HTTP POST request. For our use-case, we are most interested in the `"message.new"` event.

Next, create an endpoint for our [webhook](https://getstream.io/chat/docs/#webhooks). Stream will make a request to this endpoint for every new message sent to the channel.

Add the below code to the `server/app.js` file:

```
    // ./server/app.js
    
    // [...]
    app.post('/webhook', async (req, res) => {
        // extract data from the POST payload
        const { cid, type, message, user } = req.body
       // Get the organization and channel from the cid param
        const [org, chan] = cid.split(':')
        
        res.status(200).send({
            status: "success"
        })
        
        // Make sure the new message is not comming form the bot
        // We are using 'bandit' as a username for our bot
        if (type === "message.new" && user.id !== 'bendit') {
            const channel = serverSideClient.channel(org, chan);
    
            const messagePayload = {
                text: await getAnswer(message.text),
                user: {id: 'bendit'},
            }
    
            try {
                await channel.sendMessage(messagePayload);
            } catch(e) {
                console.log(e.message)
            }
        }
    });
    // [...]
```

In the proceeding code:


- After extracting the data from the POST request, we check the type of the event if it’s a "**message.new**" event.  Also, we want to make sure that the message is not coming from the bot - 'bendit'. ‘bandit’ is just a generic username we want to use as our bot. It can be any name you like.
- Next, we call the getAnswer function to query Dialogflow for an answer to the new message that just came in.
- Then finally, we call the `channel.sendMessage(…` function to send the result from Dialogflow to the channel so that the user can see the reply.

**Enable the Webhook** 

Although we now have our webhook ready which can be accessed from http://localhost:3000/webhook. It is only accessible from your local system. We need to expose the URL so it can be accessible by Stream which we can do using ngrok.

Open up ngrok and expose the URL:

```
    ./ngrok http 3000
```

![](https://paper-attachments.dropbox.com/s_F0CE8A6AF29682CF11AEC325A5576A989C8113A90BEDEF3E681135BEE78087B8_1557343069346_image_preview9.png)


Now note any of the Forwarding URLs which can now be accessed from anywhere.

Head to your Stream [Dashboard](https://getstream.io/dashboard) and enable the webhook option:


- Scroll down to the **Chat Event** section
- Enable the webhook by selecting the **Active** selection
- Enter the ngrok generated URL in the **URL** input form
- Click the **Save** button to save your changes
![Enabling webhook](https://paper-attachments.dropbox.com/s_BC3401DD7DD2340BE6F9C669BE5C841F9F4C705937943E31239A7EE029F285F1_1558049319059_Screenshot+2019-05-17+at+12.26.40+AM.png)



## Testing Chat

Good job! you have successfully built a FAQ bot. Now let’s test the app to see that it works:


- Restart the Node server terminal
- Open the Vue app on your browser 
- Now, ask a user for a given question and see the response from the bot


## Final Thoughts

In this tutorial, you have successfully built a FAQ bot . We explored a way in which you can add bots to your Stream app using the webhook feature provided by the Stream Chat infrastructure.

The sky is the limit for what you can build from here. What we've built is just a tip of the iceberg in terms of what you can do with bots. You can extend the functionality of the bot by adding more [intents](https://dialogflow.com/docs/intents) with [Dialogflow](https://dialogflow.com/).

You can find the complete code of this tutorial on [GitHub](https://github.com/dongido001/getstream-chat-dialogflow-faq-bot.git). For more information on Stream Chat, have a look [here](https://getstream.io/chat/).