Integrating a chatbot into your Nodejs API using Dialogflow
Tags: webdev, javascript, ai, google
Published: 2023-07-10 13:23:36

**INTRODUCTION**
Welcome. This tutorial will guide you through the process of integrating a chatbot into your Node.js API using Dialogflow. With the rapid advancement of conversational AI, chatbots have become an essential component for providing interactive and personalized experiences to users. By integrating a chatbot into your Node.js API, you can enhance the functionality and engagement of your application, allowing users to interact seamlessly with automated conversational agents.

Dialogflow, powered by Google Cloud, is a powerful natural language processing (NLP) platform that enables developers to build intelligent chatbots and virtual assistants. It offers a wide range of features, including language understanding, context management, and intent recognition, making it an ideal choice for creating conversational interfaces. By combining Dialogflow with your Node.js API, you can leverage its capabilities to understand user queries, provide accurate responses, and deliver a smooth conversational experience.

Throughout this tutorial, we will explore the step-by-step process of integrating Dialogflow into your Node.js API. We will cover the necessary setup, configuration, and implementation steps, allowing you to seamlessly connect your chatbot with your API endpoints. Whether you are building a customer support system, an e-commerce platform, or any other application that requires interactive communication, this tutorial will equip you with the knowledge and tools to integrate a chatbot effectively.

By the end of this tutorial, you will have a comprehensive understanding of how to integrate Dialogflow into your Node.js API, enabling your application to handle user queries, provide intelligent responses, and offer a more engaging and dynamic user experience. So, let's dive in and embark on this exciting journey.

**CREATING AN AGENT**
Before we use Dialogflow, we need to create an agent. So visit [Dialog flow](https://dialogflow.cloud.google.com/) to get started. 

Next, create an agent and assign a name to it e.g. my-first-chat-bot.

In the menu, that shows up, find and click on the gear icon - (Settings).

Under the general menu, scroll down to the project ID field and click on your project ID.

![project ID](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ka3bjnec9q4wcqxgk3ik.png) 

This action will redirect you to the google cloud console at [Google-cloud](https://console.cloud.google.com/).

Next, navigate to the IAM & Admin menu and locate the service accounts sub-menu. If you haven't registered a service account yet, you will need to create a new one. 

![Creating a service account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvzqcyeqy2us35b4s17h.png)

To create a new service account, enter a suitable name for your account. By default, a service ID will be automatically generated for you, but you have the option to modify it if needed. Once you have entered the necessary details, click on the "create" button to proceed. After creating the service account, the next step is to assign a role to it. This step is crucial for granting the necessary permissions. In the role selection process, search for "Dialogflow API client" under the Dialogflow section, and select it. Once you have selected the appropriate role, click on "continue" to proceed. Finally, click on "done" to complete the process. 

**Please note** that the images provided in this tutorial serve as a visual reference to assist you in locating the correct menu and sub-menu options. The actual appearance and arrangement of the interface may vary based on the version or configuration of the platform you are using.

Once you have successfully created a service account, the next step is to obtain your configuration keys for further integration.


![Manage keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uex88z3ilgv77ntlx5u9.png)

To download the configuration keys, click on the "Manage Keys" option. From the dropdown menu, select "Create new key". Choose the JSON format and click on the "create" button. This action will initiate the download of a JSON file containing all the necessary configuration properties required for the integration process.


![configuration file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zsrrd16ke5tb7xslec81.png)

It is crucial to note that the downloaded JSON file serves as your configuration file, holding essential information needed for successful integration. Therefore, it is vital to keep this file secure and not share its contents with anyone. Safeguarding this sensitive data ensures the integrity and security of your chatbot integration.

Great! now let's jump into our code.

Create a package.json file and initialize our Nodejs project by using this command :

`npm init -y`

Install the following packages 

`npm i express dotenv uuid dialogflow`

import the configuration file you downloaded earlier into your project. Now your project setup should look like this :

![Project set up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b65lil72rwx0rxwo7qhg.png)

Next, we set up our server and import the necessary dependencies.

```
const dotenv = require("dotenv").config()

const express = require("express")

const dialogflow = require("dialogflow")

const uuid = require('uuid');

const PORT = process.env.PORT || 7000


const projectId = process.env.PROJECT_ID || "small-talk-2-2-2-2"
const credentialsPath = process.env.CREDENTIALS_PATH || "./small-talk-2-2-2-2-5b3b3b3b3b3b.json"

process.env.GOOGLE_APPLICATION_CREDENTIALS = credentialsPath

const start = async () => {
    try {
        app.listen(PORT, () => {
            console.log(`Server has been started on port ${PORT}`)
        })
    } catch (error) {
      console.log(error)  
    }
}

start()

```
Now, lets explain what is happening here :

The **projectId** variable is being set to either the value of the `process.env.PROJECT_ID` environment variable or "small-talk-2-2-2-2" if the variable is not defined.

The **credentialsPath** variable is being set to either the value of the `process.env.CREDENTIALS_PATH` environment variable or "./small-talk-2-2-2-2-5b3b3b3b3b3b.json" if the variable is not defined.

The **GOOGLE_APPLICATION_CREDENTIALS** environment variable is being set to the value of credentialsPath. This variable is used to specify the path to the Google Cloud service account credentials JSON file that we downloaded and imported.

Now since we are loading the credentials from our `.env` file, it is important to copy and paste the credentials from our JSON file into the `.env` file and ensure to spread all the credential properties across one variable.

Spreading the credential properties across one variable, such as CREDENTIALS, in the .env file ensures that the credentials are assigned to a single environment variable. This approach simplifies the code and enhances readability. It also allows the application to access the credentials easily by referencing the CREDENTIALS environment variable, rather than handling each credential property individually.

Your `.env` file should now look like this : 


![env file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wcbfjdyzlengbxhi3v3j.png)

Now, we will establish a connection to Dialogflow by creating a function and configuring a route to handle incoming requests and responses.

```
async function runSample() {
  // A unique identifier for the given session
  const sessionId = uuid.v4();
 
  // Create a new session
  const sessionClient = new dialogflow.SessionsClient();
  const sessionPath = sessionClient.sessionPath(projectId, sessionId);
 
  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: 'Who are you?',
        // The language used by the client (en-US)
        languageCode: 'en-US',
      },
    },
  };
 
  // Send request and log result
  const responses = await sessionClient.detectIntent(request);
  const result = responses[0].queryResult.fulfillmentText;
  const queryText = responses[0].queryResult.queryText;

  if (result) {
        return {
            user: queryText,
            bot: result
        }
} else {
    return Error("No intent matched")
  }
}

const app = express()

app.get("/", async (req, res) => {
    try {
        const result = await runSample()
        return res.status(200).json({message: "Success", result})
    } catch (error) {
        console.log(error)
        return res.status(500).json({message: "Server error", error})
    }
})

```
 
In the code above, the following actions are taking place:

An asynchronous function named `runSample()` is defined. It performs the following tasks:

- 
Generates a unique identifier, sessionId, for the session.

- 
Creates a new session using dialogflow.SessionsClient().

- 
Constructs the session path using the projectId and sessionId.

- 
Defines a text query request containing the query to send to the 
Dialogflow agent and the language code.

- 
Sends the request to Dialogflow using sessionClient.detectIntent() and awaits the response.

- 
Extracts the fulfillment text and query text from the response.
Returns an object with the user query and the bot's response, if a fulfillment text is present. Otherwise, it returns an error indicating that no intent matched the query.

- 
An Express.js application is created using express() and stored in the app variable.

- 
A route is set up for the root URL ("/") using app.get(). The route is configured as an asynchronous function that performs the following tasks:

- 
Calls the **runSample()**

- 
Returns a JSON response with a success message and the result of the **runSample()** function if successful.

- 
Logs any errors that occur during the process and returns a JSON response with an error message if there's a server error.

Overall, this code sets up a route in an Express.js application that connects to Dialogflow, sends a query, and retrieves a response. The result is then returned as a JSON response to the client. Any errors that occur during the process are logged and returned as error messages.

Our app.js file should now look like this :

```
const dotenv = require("dotenv").config()

const express = require("express")

const dialogflow = require("dialogflow")

const uuid = require('uuid');

const PORT = process.env.PORT || 7000

const projectId = process.env.PROJECT_ID || "small-talk-2-2-2-2"
const credentialsPath = process.env.CREDENTIALS_PATH || "./small-talk-2-2-2-2-5b3b3b3b3b3b.json"

process.env.GOOGLE_APPLICATION_CREDENTIALS = credentialsPath

async function runSample() {
  // A unique identifier for the given session
  const sessionId = uuid.v4();
 
  // Create a new session
  const sessionClient = new dialogflow.SessionsClient();
  const sessionPath = sessionClient.sessionPath(projectId, sessionId);
 
  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: 'Who are you?',
        // The language used by the client (en-US)
        languageCode: 'en-US',
      },
    },
  };
 
  // Send request and log result
  const responses = await sessionClient.detectIntent(request);
  const result = responses[0].queryResult.fulfillmentText;
  const queryText = responses[0].queryResult.queryText;

  if (result) {
        return {
            user: queryText,
            bot: result
        }
} else {
    return Error("No intent matched")
  }
}

const app = express()

app.get("/", async (req, res) => {
    try {
        const result = await runSample()
        return res.status(200).json({message: "Success", result})
    } catch (error) {
        console.log(error)
        return res.status(500).json({message: "Server error", error})
    }
})

const start = async () => {
    try {
        app.listen(PORT, () => {
            console.log(`Server has been started on port ${PORT}`)
        })
    } catch (error) {
      console.log(error)  
    }
}

start()
```
Now let's start our server and test. If everything was set up correctly, we will get this response :

![API RESPONSE](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kk0ys2jkj5p63eqiioz2.png)

The response is a JSON object with two key-value pairs:

"**message**": "Success" - This indicates that the request to Dialogflow was successful and a response was received.

"**result**": This key holds another JSON object with two key-value pairs:

"**user**": "Who are you?" - This represents the user's query or input sent to Dialogflow. In this case, the user asked, "Who are you?"
"**bot**": "You can call me Sofia. How can I help you today?" - This is the response generated by Dialogflow's natural language processing. It indicates that the bot's name is Sofia and asks how it can assist the user.

Overall, the response demonstrates a successful interaction with Dialogflow, where the user's query is processed, and the bot responds with an appropriate answer. 

At this point, our API is fully functional and ready to be integrated with a user interface. However, to optimize the performance of our chatbot, continuous training is essential. This involves adding new intents and responses in the Dialogflow dashboard, allowing the chatbot to handle a wider range of queries and interactions.

let us change the user request and see what response we will receive from the agent.

**Request**
![request changed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwdqj41j3hcun1fhrrb0.png)

**Response**

![new response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zn3z1cxs8nvmeofksgf.png)

What happens when the user asks a question which our agent does not understand? 
Well, there are predefined fallback responses like this :


![unknown](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9my6e049cew7h1kggbf.png)

Dialogflow offers extensive possibilities for customization and integration. We have the flexibility to incorporate the chatbot into various platforms such as Facebook, WhatsApp, and more. By leveraging these integrations, we can reach users across different channels and provide them with personalized conversational experiences.

Additionally, Dialogflow supports multi-language capabilities, enabling us to serve users in their preferred languages. Activating multi-language support ensures that our chatbot can communicate effectively with users from diverse linguistic backgrounds.

It's crucial to emphasize that the effectiveness of our chatbot relies on the quality of information we provide. Regularly updating and refining the training data, intents, and responses helps our agent improve its understanding and accuracy in delivering meaningful and helpful interactions.

In summary, by continuously training our agent and exploring the extensive features of Dialogflow, we can unlock a multitude of possibilities to enhance the functionality and reach of our chatbot. Taking advantage of different integration options, such as social media platforms and multi-language support, allows us to create engaging user experiences and effectively address the needs of a diverse user base. Remember, the success of our chatbot lies in the knowledge and information we feed it, so ongoing improvement and adaptation are key.