I'm currently using Glitch's(Glitch.com) node.js to connect Dialogflow to code and I'm running into a problem. As you can see below; I have two intents I'm trying to pass values to, characterHandler and openHandler.
Now the weird thing is that it does execute the web hook correctly if I trigger the intent on Dialogflow corresponding to "characterHandler", but it returns "UnhandledPromiseRejectionWarning: Error: no matching intent handler for: null" in the console and fails while triggering "openHandler" and I have no clue why.
Does anyone know what I'm doing wrong?
'use strict';
process.env.DEBUG = 'actions-on-google:*';
const express = require('express');
const bodyParser = require('body-parser');
const request = require("request");
const { DialogflowApp } = require('actions-on-google');
const Map = require('es6-map');
const app = express();
app.use(bodyParser.json());
let characters = ['The Pied Piper', 'Red Riding Hood', 'The Big Bad Wolf'];
// [START Action]
app.post('/', function (request, response) {
const assistant = new DialogflowApp({request, response});
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body: ' + JSON.stringify(request.body));
const CHARACTERS = 'story.characters';
const OPENINGTIMES = 'openingTimes';
function characterHandler (assistant) {
let responseText = "How about";
responseText = characters[Math.floor(Math.random() * characters.length)];
assistant.tell(responseText);
}
function openHandler (assistant) {
assistant.tell('This attraction is currently full');
}
const actionMap = new Map();
actionMap.set(CHARACTERS, characterHandler);
actionMap.set(OPENINGTIMES, openHandler);
assistant.handleRequest(actionMap);
});
// [END Action]
// Renders the homepage
app.get('/', function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('');
res.end();
});
if (module === require.main) {
// [START server]
// Start the server
let server = app.listen(process.env.PORT || 3000, function () {
let port = server.address().port;
console.log('App listening on port %s', port);
});
// [END server]
}
module.exports = app;
Your open handler function is mapped to 'openingTimes'. Make sure that exactly matches the intent name and make sure that the intent was actually saved correctly.
Related
I am trying to integrate IBM Watson bot with twilio, whatsapp using IBM cloud functions using Nodejs. I followed the following to come up with this code https://github.com/ChaitanyaGhantasala/Whatsapp/blob/master/app.js
Please find below the Code:
// Import Modules
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
var AssistantV1 = require('ibm-watson/assistant/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
// Twilio Credentials
var accountSid = '';
var authToken = '';
var client = require('twilio')(accountSid, authToken);
app.use(bodyParser.urlencoded({ entended: false }));
var env= require('dotenv').config()
// Watson Credentials
var assistant = new AssistantV1({
version: '2018-09-20',
authenticator: new IamAuthenticator({
apikey: '',
}),
url: '',
});
var context1 = {};
app.get('/test', function (req, res) {
})
// API
app.post('/api', function (req, res) {
console.log("Request Object");
var From = req.body.From;
console.log(From);
assistant.message({
skill_id: '',
input: { 'text': req.body.Body },
context: context1
}, function (err, response) {
if (err)
console.log('error:', err);
else {
context1 = response.context;
var msg = response.output.text[0];
console.log("message", msg);
client.messages
.create({
body: msg,
from:'whatsapp:+14155238886',
to: 'From',
}).then(message = console.log(msg))
.done();
}
})
});
//PORT Listen
app.listen(process.env.PORT||8000, function () {
console.log("Server is running at 8000");
});
This line shows an error
const { IamAuthenticator } = require('ibm-watson/auth');
Also, i have no idea how the integration work
Can you please help me with any resources?
This does not work with me,
I am basing this answer on you not being able to format code. The code you show is basic / simple, yet you have made it undecipherable by not formatting it.
You say your error is on the line:
const { IamAuthenticator } = require('ibm-watson/auth');
This is a simple import of a pre-requisite module, which suggests that you have not imported the module ibm-watson, however, if that were the case then the line above it should also fail.
var AssistantV1 = require('ibm-watson/assistant/v1');
In which case you are hitting a version problem, either in your version of Node.js that is not recognising the const format, or in the version of ibm-watson that is not exporting ibm-watson/auth.
Based on your lack of basic code formatting, I am guessing that it is the version of Node.js. The current version of ibm-watson : 5.6.0 requires "node": ">=10.0.0".
My twilio code is:
const express = require('express');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/health', (req, res) => {
res.send('ok')
})
// Returns TwiML which prompts the caller to record a message
app.post('/record', (request, response) => {
// Use the Twilio Node.js SDK to build an XML response
const twiml = new VoiceResponse();
twiml.say("Hi!");
// Use <Record> to record the caller's message
twiml.record();
console.log(twiml.toString())
response.send(twiml.toString());
});
// Create an HTTP server and listen for requests on port 3000
app.listen(PORT);
But I want to know the recording ID so I can access the raw file programatically. How would I do that?
To get the recording ID, (RecordingSid), you need to tell Twilio an action URL, with something like this:
twiml.record({
action: '/finished'
});
You can read more here: (https://www.twilio.com/docs/voice/twiml/record#attributes). Also, read about the recordingStatusCallback URL attribute, maybe that's something you need too.
Then, you need to parse the body of this second request Twilio will make to your app.
You can read more about this here: (https://www.twilio.com/blog/2016/07/how-to-receive-a-post-request-in-node-js.html).
For this you can use body-parser, which you can get with npm install body-parser.
The recording ID will be part of the parameters under body.RecordingSid.
Anyway, here is a rough modification of your code, to get started:
// npm install express body-parser
const express = require('express');
const bodyParser = require('body-parser');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const app = express();
// Tell express to use the body-parser middleware and to not parse extended bodies
app.use(bodyParser.urlencoded({
extended: false
}))
const PORT = process.env.PORT || 3000;
app.get('/health', (req, res) => {
res.send('ok')
})
// Returns TwiML which prompts the caller to record a message
app.post('/record', (request, response) => {
// Use the Twilio Node.js SDK to build an XML response
const twiml = new VoiceResponse();
twiml.say("Hi!");
// Use <Record> to record the caller's message
twiml.record({
action: '/finished'
});
console.log(twiml.toString())
response.send(twiml.toString());
});
app.post('/finished', function (req, res) {
const body = req.body;
res.set('Content-Type', 'text/plain');
res.send(``);
console.log(body);
console.log(body.RecordingSid);
});
// Create an HTTP server and listen for requests on port 3000
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
I hope this helps.
I have a node js API built with express. In one of my http endpoints, I would like to accept the request and send it over websockets to another server, and then return a reply. I'm using the ws library. The problem is that the websockets communication is not synchronous, so I don't know how to return an answer to the API client. Anyway, this is what I tried but it's not complete:
const express = require('express');
const app = express();
const WebSocket = require('ws');
const uuid = require('uuid');
const bodyParser = require('body-parser');
const ws = new WebSocket('ws://localhost:7465/');
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ extended: false }));
ws.on('open', function open() {
console.log('connected');
});
ws.on('close', function close() {
console.log('disconnected');
});
ws.on('message', function incoming(data) {
console.log('Got data from server:');
console.log(data);
});
app.post('/my-http-endpoint', function (req, res) {
var payload = JSON.stringify({ body: req.body, requestID: uuid.v4() });
ws.send(Buffer.from(payload));
// How to send a reply?
})
app.listen(1337);
You will need to introduce message IDs. Generate them by counting up a number.
Add the following dictionary to your code:
let nextMessageId = 1;
const responseCallbacks = {};
When you send something (in the app.post callback in your case), do the following:
const messageId = obtainFreeMessageId(); // see below
ws.send(Buffer.from({ messageId, payload }));
responseCallbacks[messageId] = function(data) {
// make use of the response message data here
};
On message do the following (the response must contain messageId as well):
const messageId = message.messageId; // message has a message ID
const responseCallback = responseCallbacks[messageId];
if(responseCallback) {
responseCallback(message.data); // message contains your data
delete responseCallbacks[messageId];
}
Helper function for message ID generation which helps prevent possible overflow:
const MaximumMessageId = 0xFFFFFFFFFFFF; // 48-bit integer (64-bit is too much for javascript, 32-bit is a little bit too stingy)
function obtainFreeMessageId() {
const messageId = nextMessageId;
nextMessageId++;
if(nextMessageId > MaximumMessageId) {
nextMessageId = 1;
}
return messageId;
}
Consider setting a timeout which calls the response callback after a certain amount of time if you want to make sure the request comes to an end. Clear the timeout in the response callback.
I am wondering about how it might be possible to deploy a Node.js app on Azure Functions.
Basically, I have a function setup and running a basic hello world http example that looks like:
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + req.params.name
};
context.done();
};
The app I am trying to deploy into a function is a simple moc client that uses swagger (basically takes a request and returns some xml). The app.js looks like:
const SwaggerExpress = require('swagger-express-mw');
const app = require('express')();
const compression = require('compression');
const configSwagger = {
appRoot: __dirname, // required config
};
SwaggerExpress.create(configSwagger, (err, swaggerExpress) => {
if (err) {
throw err;
}
// install middleware
swaggerExpress.register(app);
// server configuration
const serverPort = process.env.PORT || 3001;
app.listen(serverPort, () => {
//logger.info('Listening on port %s', serverPort);
});
app.use(compression());
});
module.exports = app; // for testing
The thing I am not sure about is how to handle module.exports = app when modeul.exports is used to establish the function (i.e. module.exports = function (context, req))
You can try to use azure-function-express to enable your swagger middleware.
Note that certain middleware will not function correctly (for example, body-parser). This is because the functions req is not a stream - it is injected into the function with a 'body' property already populated.
I have this basic express app:
var express = require('express');
var app = express();
var PORT = 3000;
var through = require('through');
function write(buf) {
console.log('writing...');
this.queue('okkkk');
}
function end() {
this.queue(null);
}
var str = through(write, end);
/* routes */
app.get('/', function(req, res){
res.send("Hello!");
})
app.post('/stream', function(req, res){
var s = req.pipe(str).pipe(res);
s.on('finish', function() {
console.log('all writes are now complete.'); // printed the first time
});
});
/* listen */
app.listen(PORT, function () {
console.log('listening on port ' + PORT + '...');
});
When I post some data to /stream endpoint for the first time after starting the server I get okkk as the response which is what I expect. However, after that, any requests to /stream endpoint just timeout and not return any response.
Why is it so? What's exactly happening here?
I had this same problem and looks like res was not being finished properly. So I added a callback to my stream and ended que res myself. That fixed my problem:
stream.on('end', () => res.end());
stream.pipe(res);
It worked when I replaced req.pipe(str).pipe(res) with req.pipe(through(write, end)).pipe(res) which essentially makes sure that a new instance of through stream is created for every request.