This repository contains a backend service for an intelligent chatbot that onboards clients, answers questions, and sets up appointments on a retail website. The purpose of the backend service is to improve the customer experience that users have when interacting with a Dialogflow chatbot.
- Create a Cloud Platform project
- Enable Project Billing
- Enable the Dialogflow API
- Authentication - Service Accounts
Node.js is an open-source, server-side runtime environment that allows you to create backend applications by writing JavaScript code. This repository uses Node to connect to 3rd party services such as Google Maps API, Google Sheets, Google Calendar, and Twilio in order to provide our Dialogflow agent the ability to schedule appointments on a corporate webiste for one of our clients.
constexpress=require('express')constapp=express()$ npm install express
$ node service.js
$ ngrok http <port>
- For this particular service, the public endpoint is: https://d81c-2601-1c2-8100-6540-5ddd-a1c3-a27f-aeaf.ngrok.io
app.post('/webhook',async(request,response)=>{- Navigate to https://dialogflow.cloud.google.com
- On the left side of the page, click the 'Fulfillment' tab
- In the 'Webhook' section, click 'Enable'
- Enter your public endpoint in the 'URL' field
- Click 'Save' at the bottom of the page
- You can define when you want to send webhooks to this public endpoint in the DialogFlow console
constdialogflow=require('dialogflow');constsessionClient=newdialogflow.SessionsClient({
projectId,
credentials,});Define Project ID and Session ID in Application
- You can find your project ID in your Dialogflow Agent Settings
constprojectId='<project-id-here>';constsessionId='<put-chat-session-id-here>';https://docs.redis.com/latest/rs/references/client_references/client_nodejs/
To use Redis with Node.js, you need to install a Node.js Redis client. The following sections explain how to use node_redis, a community-recommended Redis client for Node.js.
Another community-recommended client for Node.js developers is ioredis. You can find additional Node.js clients for Redis in the Node.js section of the Redis Clients page.
$ npm install node_redis
- Run the following code in your service.js backend file to create a Redis Instance:
constredis=require('redis');constclient=redis.createClient({socket: {host: '<hostname>',port: <port>},password: '<password>'});client.on('error',err=>{console.log('Error '+err);});https://www.sitepoint.com/using-redis-node-js/
- For Mac and Linux users, the Redis installation is pretty straightforward. Open your terminal and type the following commands:
$ wget https://download.redis.io/releases/redis-6.2.4.tar.gz
$ tar xzf redis-6.2.4.tar.gz
$ cd redis-6.2.4
$ make
$ redis-server
$ src/redis-server First you have to create a service account and download a .JSON format file of credentials on your local system. Now, there are three ways to use that credentials for authentication/authorisation in dialogflow library.
- Create an environment variable named 'GOOGLE_APPLICATION_CREDENTIALS'
- Set the value equal to the absolute path of that JSON credentials file.
$ export GOOGLE_APPLICATION_CREDENTIALS="<absolute-path-of-json-file>"
- Then, run your code. Google library will automatically load your credentials file
- Assume that you know the absolute path of your JSON file and put that as value in below snippet of credentials_file_path variable.
- You can find your project ID in your Dialogflow agent settings
constprojectId='<project-id-here>';constsessionId='<put-chat-session-id-here>';constcredentials_file_path='<absolute-file-path-of-JSON-file>';// Instantiate a DialogFlow client.constdialogflow=require('dialogflow');constsessionClient=newdialogflow.SessionsClient({
projectId,keyFilename: credentials_file_path,});- The body of the request contains relevant information such as the user query, action, and parameters from the client-side.
constquery=request.body.queryResultconstintent=request.body.queryResult.intent.displayName;constscore=request.body.queryResult.intentDetectionConfidence;constfulfillmentText=request.body.queryResult.fulfillmentText;constsession_path=request.body.session;constparameters=request.body.queryResult.parametersconstaction=request.body.queryResult.action;constsession_path=request.body.session;constsession_array=session_path.split('/')constsession_id=session_array[session_array.length-1]varFirstName=awaitparameters["first-name"]varLastName=awaitparameters["last-name"]try{constclient=newRedis()consthashMap={"FirstName": FirstName,"LastName": LastName}awaitclient.hmset(session_id,hashMap)constsessData=awaitclient.hgetall(session_id)}catch(err){}- Use Redis client to get information about the customer from the session cache, such as their first and last name, in order to personalize the interaction between the chatbot and the user.
if(action=="input.welcome"){constclient=newRedis()constsessData=awaitclient.hgetall(session_id)if(sessData.FirstName&&sessData.LastName){varagentResponse={"fulfillmentText": `Hey, what's up ${sessData.FirstName}! What could I help you with today?`}response.json(agentResponse)}}- This feature maps the distance between a customer pickup location and a corporate business address in order to check whether the pickup distance falls within the range of 100 miles
if(context_name==session_path+'/contexts/'+'appointment-booking-create'){console.log("Calculating distance of the destination from driver location...")varAPI_KEY=process.env.DIRECTIONS_API_KEY;varaxios=require('axios')varconfig={method: 'get',url: `https://maps.googleapis.com/maps/api/directions/json?origin=${Origin}&destination=${Destination}&key=${API_KEY}`}axios(config).then(asyncfunction(res){data=res.datadistance=data["routes"][0]["legs"][0]["distance"]["text"]kilometers=data["routes"][0]["legs"][0]["distance"]["value"]console.log(`The distance between origin and destination is: ${distance}`)if(kilometers<160394){console.log("The destination is within range!")varjsonResponse={"fulfillmentText" : `Perfect! I just looked up the address, it's only ${distance} away, which meets the fundraiser requirements. How many bags do you plan on selling?`}console.log("Attempting to store DestinationAddress in memory...")redis_client.set("DestinationAddress",Destination,function(err,response){if(err){console.log(err)}})console.log("Saved destination address to session cache...")consthashMap={"DestinationAddress": Destination}try{constclient=newRedis()awaitclient.hmset(session_id,hashMap)constsessData=awaitclient.hgetall(session_id)console.log(sessData)}catch(err){console.log(err)}}else{console.log("The destination is out of range")varjsonResponse={"fulfillmentText" : "I'm so sorry, I just looked up the address on the map. It looks like that address is out of driving range, we're only allowed to book appointments that are within 100 miles of the corporate office. Would you prefer to book the appointment at a different location?"}console.log("Sent response from server to customer...")}response.send(jsonResponse)}).catch(function(error){console.log(error)})}- This feature uses regex to validate the phone number that a customer provided to the Dialogflow agent
if(action=="appointment-booking-getphone"){constPhone=parameters["phone-number"]if(Phone.replace(/\D/g,'').length!==10){varjsonResponse={"fulfillmentText": "Sorry, it looks like that phone number is invalid, could you tell me the full phone number, please?"}response.json(jsonResponse)}else{varjsonResponse={"fulfillmentText": "Thanks! And the address of the location for the pick-up?"}try{constclient=newRedis()consthashData={"Phone": Phone}awaitclient.hmset(session_id,hashData)constsessData=awaitclient.hgetall(session_id)redis_client.set("Phone",Phone,function(err,response){if(err){console.log(err)}})}catch(err){console.log("Error:",err)}}}