Caller ID & Sending SMS via Dialogflow
Generally, DialogFlow is not an SMS interactive platform, but it is more designed for accepting incoming audio, and making machine learning decisions based on audio input.
However, DialogFlow can interact with NodeJS, and therefore can utilize CPaaS’s NodeJS libraries. DialogFlow is able to send outbound GET/POST requests, but in order to enable this, a credit card must be on file in the DialogFlow account (the pay-as-you-go plan is a good option)
By default, Google does not allow outbound requests outside of the Google network to enable outbound API calls to other platforms unless on a paid plan and have a credit card on file for charges. High thresholds must be passed before being billed (charged) as there are a certain amount of requests that are allowed for free. Therefore, during testing, charges should not be accumulated from DialogFlow but be sure to research this fully as CPaaS isn’t responsible for any additional charges acquired while using the DialogFlow interface and making additional outbound requests.
Some things to keep in mind:
- CPaaS appears to be able to send calls to Dialogflow then get audio input from the user, make decisions and then send an outgoing SMS during the ‘fulfillment’ stage
- Once calls leave CPaaS and go to DialogFlow, the call is not able to return back to CPaaS and it will end in DialogFlow.
After setting up intents and entities to gather info from the customer, the call then goes to a fulfillment webhook. In the fulfillment area on "Inline Editor" in the "packages.json" add the CPaaS library.
Full contents of example Fulfillment inline editor "package.json"
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "8"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^5.13.1",
"firebase-functions": "^2.0.2",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0",
"@signalwire/compatibility-api": "^3.0.2",
"https": "^1.0.0",
"util": "^0.12.2"
}
}
This CPaaS dependency declaration will allow GET and POST requests using the CPaaS XML library. So essentially follow-up SMS messages could be sent to customers after the call to DialogFlow has been fulfilled (as seen in the index.js file below).
Full contents of example Fulfillment inline editor "index.js"
"use strict";
const functions = require("firebase-functions");
const { WebhookClient } = require("dialogflow-fulfillment");
const { Card, Suggestion } = require("dialogflow-fulfillment");
const util = require("util");
const { RestClient } = require("@signalwire/compatibility-api");
const clientRest = RestClient("f3dfXXX", "PTXXX", {
signalwireSpaceUrl: "joshebosh.signalwire.com",
});
process.env.DEBUG = "dialogflow:debug"; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
console.log('CPaaS Object: ' + util.inspect(request.body.originalDetectIntentRequest, false, null, false));
console.log('CPaaS To Number: ' + util.inspect(request.body.originalDetectIntentRequest.payload.signalwire.to, false, null, false));
console.log('CPaaS From Number: ' + util.inspect(request.body.originalDetectIntentRequest.payload.signalwire.from, false, null, false));
console.log('Telephony CID Number: ' + util.inspect(request.body.originalDetectIntentRequest.payload.telephony.caller_id, false, null, false));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function CIDHandler(agent) {
console.log("joshebosh reached the CIDHander function");
console.log("agent:\n" + util.inspect(agent, false, null, true));
console.log("agent.parameters:\n" + util.inspect(agent.parameters));
clientRest.messages
.create({
body:
"Signalwire Payload:\n" +
JSON.stringify(request.body.originalDetectIntentRequest) +
"\n\nDialogflow Agent Parameters:\n" +
JSON.stringify(agent.parameters),
to: request.body.originalDetectIntentRequest.payload.signalwire.from, // Send SMS to this number
from: request.body.originalDetectIntentRequest.payload.signalwire.to, // From a valid CPaaS number
})
.then((message) => {
console.log("Message ID: " + message.sid);
})
.catch(console.error);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set("Default Welcome Intent", welcome);
intentMap.set("Default Fallback Intent", fallback);
intentMap.set("caller id", CIDHandler);
agent.handleRequest(intentMap);
}
);
As per the CPaaS docs, setup the credentials for the library:
const { RestClient } = require("@signalwire/compatibility-api");
const clientRest = RestClient("f3dffdbf-XXX", "PTXXX", {
signalwireSpaceUrl: "EXAMPLE-SPACE.signalwire.com",
});
Then near the bottom is the intent handler declared for the "caller id" intent which point to "CIDhandler" function:
intentMap.set("caller id", CIDHandler);
Then somewhere in the middle is the “CIDHandler” function which is responsible for sending out an SMS including the payload, and agent parameters:
function CIDHandler(agent) {
console.log("joshebosh reached the CIDHander function");
console.log("agent:\n" + util.inspect(agent, false, null, true));
console.log("agent.parameters:\n" + util.inspect(agent.parameters));
clientRest.messages
.create({
body:
"CPaaS Payload:\n" +
JSON.stringify(request.body.originalDetectIntentRequest) +
"\n\nDialogflow Agent Parameters:\n" +
JSON.stringify(agent.parameters),
to: request.body.originalDetectIntentRequest.payload.signalwire.from, // Send SMS to this number
from: request.body.originalDetectIntentRequest.payload.signalwire.to, // From a valid CPaaS number
})
.then((message) => {
console.log("Message ID: " + message.sid);
})
.catch(console.error);
}
This caller id object is being used to send SMS back to the original caller. Within the create message object, the "from" object contains the number used to send confirmation "to". Check out how this "to" is formatted in the code above.
to: request.body.originalDetectIntentRequest.payload.signalwire.from;
Use the original CPaaS number that was dialed as the number so that it appears "to" be sending the SMS "from" a valid CPaaS number on the account. Looks at how the "from" parameter was defined to perform this.
from: request.body.originalDetectIntentRequest.payload.signalwire.to;
Finally for this tutorial purposes, include both the CPaaS caller id object, and the agent derived response parameters in the body of the text message. Notice what this looks like for the "body" parameter that was in the above code.
body: "CPaaS Payload:\n" +
JSON.stringify(request.body.originalDetectIntentRequest) +
"\n\nDialogflow Agent Parameters:\n" +
JSON.stringify(agent.parameters);
Sign Up Here
If you would like to test this example out, you can create a CPaaS account and Space here.
Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!