how to integrate dialogflow result to linebot (Node.js)? - javascript

I am creating the chatbot(Line) integrate the Google Dialogflow using node.js.
I can create the line chatbot from user input the text and echo some text, only.
And I can create the code from user input send command to Google Dialogflow, and dialogflow using
the NLU tech response text to the user.
But I need user input the text send to the dialogflow and response the text(A) , then send the text(A)(after code add some template button's code) to Line bot create show some template button to user.
How can I integrate two part code achieve user input text and through dialogflow result , using the result send to the line bot server?
user input -> dialogflow ->mycode(add some template button call line) ->linbot ->bot show template button to user
Thank you.
//----------------------------------
My dialogflow code:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(
bodyParser.urlencoded({
extended: true
})
)
app.use(
bodyParser.json()
)
app.post("/webhook", function(req,res){
console.log(JSON.stringify(req.body, null, 2))
var intent = req.body.queryResult.intent.displayName;
var entityCity = req.body.queryResult.parameters["geo-city"];
if(intent === 'myIntent')
{
// here I need call bot.on method, but I don't known how to do.
// return res.json({
fulfillmentText: `I known your mean.`
});
}
else
{
return res.json({
fulfillmentText: `i am not sure your mean`
});
}
})
app.listen(process.env.PORT || 5566, function(){
console.log('server start ...');
})
//----------------------------------
My Line chatbot code:
var linebot = require('linebot');
var express = require('express');
var app = express();
const bot = linebot({
channelId: 'mychannelId',
channelSecret: 'mychannelSecret',
channelAccessToken: 'mychannelAccessToken'
});
bot.on('message',function(event) {
console.log('bot');
console.log(event);
var msg = event.message.text;
// here can add some template button code and reply to user.
});
const linebotParser = bot.parser();
app.post('/webhook', linebotParser);
var server = app.listen(process.env.PORT || 8080, function() {
var port = server.address().port;
});
//--------------------
My Line chatbot code other version:
const line = require('#line/bot-sdk');
const express = require('express');
const lineConfig = {
channelAccessToken: process.env.HEROKU_LINE_CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.HEROKU_LINE_CHANNEL_SECRET
};
const client = new line.Client(lineConfig);
const app = express();
app.post('/webhook', line.middleware(lineConfig), function(req, res) {
Promise
.all(req.body.events.map(handleEvent))
.then(function(result) {
res.json(result);
});
});
function handleEvent(event) {
switch (event.type) {
case 'join':
case 'follow':
return client.replyMessage(event.replyToken, {
type: 'text',
text: 'hello~'
});
case 'message':
switch (event.message.type) {
case 'text':
return client.replyMessage(event.replyToken, {
type: 'text',
text: (event.message.text+'~yu')
});
}
}
}
app.listen(process.env.PORT || 3000, function(){
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});

const line = require('#line/bot-sdk');
const express = require('express');
const dialogflow = require('dialogflow');
const uuid = require('uuid');
const lineConfig = {
channelAccessToken: process.env.HEROKU_LINE_CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.HEROKU_LINE_CHANNEL_SECRET
};
const client = new line.Client(lineConfig);
const app = express();
app.post('/webhook', line.middleware(lineConfig), function(req, res) {
Promise
.all(req.body.events.map(handleEvent))
.then(function(result) {
res.json(result);
});
});
async function handleEvent(event) {
switch (event.type) {
case 'join':
case 'follow':
return client.replyMessage(event.replyToken, {
type: 'text',
text: 'hello~'
});
case 'message':
switch (event.message.type) {
case 'text':
const response = await queryDF(event.message.text)
// you will get response from DF here
return client.replyMessage(event.replyToken, {
type: 'text',
text: (event.message.text+'~yu')
});
}
}
}
async function queryDF(message, projectId = 'your-project-id') {
// 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: message,
// 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;
}
app.listen(process.env.PORT || 3000, function(){
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});
You need to user dialogflow npm detect Intent method

Related

Send data from script.js to Node.js file (Using Sendgrid API)

Trying to insert data into a node.js server file from a submit event on another js.file client.
But it wont work could you see if there is any wrong with code? Looks kinda good to me but ofcourse something is wrong.
Client submit event code
`window.onload = function() {
document.getElementById('contact-form').addEventListener('submit', function(event) {
event.preventDefault();
const customMessage = document.getElementById('contact-form');
$.post("/request", {
mes: customMessage
}, function(data, status) {
console.log(data);
});
});
}`
Server node js code
// require necessary modules
`const express = require('express');
const bodyParser = require('body-parser');
const sgMail = require("#sendgrid/mail");
require('dotenv').config({ path: './dist/sendgrid/.env' });`
// set up the express app
`const app = express();
const port = process.env.PORT || 3000;`
// use body-parser middleware to parse request body
`app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());`
// set up the SendGrid API key
`sgMail.setApiKey(process.env.SENDGRID_API_KEY);`
// define route to handle POST request from client
`app.post('/request', async (req, res) =\> {
try {
// extract message from request body
const { mes } = req.body;
`
// send email using SendGrid
` await sgMail.send({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text not working',
text: mes
});
console.log('Email sent successfully');
res.status(200).send('Email sent successfully');`
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
res.status(500).send('Internal server error');
}
});`
// start the server
`app.listen(port, () =\> {
console.log(`Server started on port ${port}`);
});
`
This is basic code that is working on single execute:
`
require("dotenv").config();
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const sendMail = async(msg) =\> {
try{
await sgMail.send(msg);
console.log("message sent succes");
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
}
};
sendMail({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text',
text: "this test works"
});`

I don't know why my get request sometimes works but sometimes doesn't (404 not found)

I'm currently learning angular and working on a project with a mongoDB database and express for my APIs. I want to fetch the comments of a post by the post ID,
The get request returns me a list of comments. the problem is when I first run node js the get request doesn't work, it only works when I first post a new comment and then run the get request for the comments again.
And as long as node is running the get request will continue to work whenever it's called for, until I restart node once again for the error to happen again.
it returns a 404 not found error.
This error doesn't happen with any other route, but my code is the same in all of them.
PS : I Have made sure that the function is getting the post id before the get request is made.
this is my server.js file
let express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
cors = require('cors'),
bodyParser = require('body-parser'),
dbConfig = require('./database/db');
//create Error definition
const createError = require('http-errors');
// Connecting with mongo db
mongoose.Promise = global.Promise;
mongoose.connect(dbConfig.db, {
useNewUrlParser: true
}).then(() => {
console.log('Database sucessfully connected')
},
error => {
console.log('Database could not connected: ' + error)
}
)
const userRoute = require('./routes/user.route');
const postRoute = require('./routes/post.route');
const galleryRoute = require('./routes/Gallery.route');
const likeRoute = require('./routes/Like.Route');
const commentRoute = require('./routes/Comment.route');
const shareRoute = require('./routes/Share.route');
const profilePicRoute = require('./routes/ProfilePic.route');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cors());
app.use(express.static(path.join(__dirname, 'dist/mean-stack-crud-app')));
app.use('/', express.static(path.join(__dirname, 'dist/mean-stack-crud-app')));
app.use('/api/users', userRoute);
app.use('/api/posts', postRoute);
app.use('/api/likes', likeRoute);
app.use('/api/profilePics', profilePicRoute);
app.use('/api/comments', commentRoute);
app.use('/api/shares', shareRoute);
app.use('/api/gallery', galleryRoute);
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
// Find 404 and hand over to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.message); // Log error message in our server's console
if (!err.statusCode) err.statusCode = 500; // If err has no specified error code, set error code to 'Internal Server Error (500)'
res.status(err.statusCode).send(err.message); // All HTTP requests must have a response, so let's send back an error with its status code and message
});
this is my commentRoute.js
const express = require('express');
const commentRoute = express.Router();
// Comment model
let Comment = require('../models/Comment');
const createError = require('http-errors');
//multer for pic upload
const uploadMedia = require('../middleware/picUpload')
// Add Comment
commentRoute.route('/create').post((req, res, next) => {
// if(req?.files[0]){
// newComment.media = req?.files[0]
// }
let newComment = req.body;
newComment.creationDate = new Date(req.body.creationDate)
console.log(newComment)
Comment.create(newComment, (error, data) => {
// if (error instanceof multer.MulterError ) {
// error.message += "\nmulter Error";
// return next(error)
// }else
if (error){
return next(error)
}
else {
res.json(data);
}
})
//Get comments by parent ID
commentRoute.route('/read/byParentId/:idParent').get( async (req, res, next) => {
await Comment.find({idParent : req.params.idParent}, (error, data) => {
if(error){
return next(error)
}else{
res.json(data)
}
})
})
})
module.exports = commentRoute;
this is my mongoose comment schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema
let Comment = new Schema({
idUser: {
type : String
},
idParent : {
type : String
},
text : {
type : String
},
media : {
fieldname : { type : String },
originalname : { type : String },
encoding : { type : String },
mimetype : { type : String },
buffer : { type : Buffer },
},
creationDate : {
type : Date
}
},
{
collection: 'comments'
})
module.exports = mongoose.model('Comment', Comment);
this is my client side http get request
baseUrl = 'http://localhost:4000/api/comments';
headers = new HttpHeaders().set('Content-Type', 'application/json');
constructor(private http : HttpClient) { }
getCommentsByParentId(idParent : any){
return this.http.get(`${this.baseUrl}/read/byParentId/${idParent}`);
}
this is how I consume the api in the client side
getComments(){
this.commentService.getCommentsByParentId(this.idPost).subscribe({
next : (res : any) => {
this.comments = res
this.commentsCount = res.length
},
error : (err : any) => {
console.log("error getting comment list for post "+this.idPost)
}
})
}
client side error :
server side error :
thank you.
Edit :
post without the list of comments before I post a new comment
post after I post a new comment
Well, that's very obvious that the server can't find the entity in the DB.
You need to check one of the following:
Maybe when you restart the node server, you restart the db too. that can happen if you're using docker-compose locally. then when you run your node server again your DB starts but there's no data in the DB, therefore the service can't find any data.
After service restart you're using non-existing ID because of wrong UI flow.
I would guess that you're facing the first option.

Agenad job is not getting start again after nodejs (express) server restart

I am using node agenda while scheduling I am able to successfully save job and its running fine. But while restarting the server the previous jobs are not getting start again. Not sure why, I tried few solutions found online but unable to make it work.
Can anyone help me with this.
I am using Nodemon with node express.
I am creating schedule using API calls
Below is app.js file
'use strict';
require('dotenv').config();
const express = require('express');
const { initialize_mongodb_database_connection } = require('./helpers/mongodb_database');
const bodyParser = require('body-parser');
const Agenda = require('agenda');
const app = express();
let logger = require('logger');
let chalk = require('chalk');
let moment = require('moment');
let mongoose = require('mongoose');
const agenda = new Agenda({
db: {address: process.env.MONGODB_URI, collection: 'scheduled_reports'},
processEvery: '30 seconds'
});
app.use(bodyParser.json());
//
// Parse application/x-www-form-urlencoded
//
app.use(bodyParser.urlencoded({extended: false}));
app.use(require('./routes/v1/schedule_report/schedule_report_routes'));
initialize_mongodb_database_connection();
sequr_app(app, [dummy_routes], {
staticDir: true,
});
let gracefulExit = function() {
if (mongoose.connection.readyState === 0) {
return process.exit(0);
}
mongoose.connection.close(function() {
return agenda.stop(function() {
logger.info({});
logger.info(chalk.bold("---------------------[ Server stopped at %s Uptime: %s ]---------------------------"), moment().format("YYYY-MM-DD HH:mm:ss.SSS"), moment.duration(process.uptime() * 1000).humanize());
return process.exit(0);
});
});
};
process.on("SIGINT", gracefulExit).on("SIGTERM", gracefulExit);
And this is my agenda file where I am routing API calls to create schedule
const Agenda = require('agenda');
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
host: 'smtp.gmail.com',
auth: {
user: 'xx-xx#gmail.com',
pass: 'xx-xx-xx'
}
});
var mailOptions = {
from: 'example#example.com',
to: 'Example#gmail.com',
subject: 'Sending Email using Node.js',
text: 'Agenda Test'
};
const agenda = new Agenda({
db: {address: process.env.MONGODB_URI, collection: 'agendaJobs'},
processEvery: '30 seconds'
});
agenda.start();
agenda.defaultConcurrency(5);
const scheduleReport = async(report_data) => {
// HERE SCHEDULING/CREATING AGENDA SCHEDULE
agenda.on('start', job => {
console.log('-------------------------------------STARTED-----------------------------------------------');
console.log('Job %s starting', job.attrs.name);
console.log('-------------------------------------------------------------------------------------------');
});
const {
report_name,
priority
} = report_data;
agenda.define(report_name, {priority: priority, concurrency: 10}, (job, done) => {
const dateNow = new Date();
const data = job.attrs.data;
// The job.attrs.data is stored in our MongoDB collection so that it can be used to run the jobs.
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
//const date = new Date.now();
console.log('Email sent: ' + info.response + dateNow);
console.log(`Job ${job.attrs.name} finished`);
}
},done());
});
// HERE CREATING SCHEUDLE
await createWeeklySchedule(report_data);
agenda.on('complete', job => {
console.log('---------------------------------------FINISHED---------------------------------------------');
console.log(`Job ${job.attrs.name} completed succesfully...`);
console.log('--------------------------------------------------------------------------------------------');
});
}
const createWeeklySchedule = async(data) => {
const {
report_name,
schedule_info,
scheduled_timezone,
time_cron
} = data;
const weeklyReport = agenda.create(report_name, {data: schedule_info});
await agenda.start();
await agenda.every(time_cron,report_name);
console.log('Job successfully saved');
}
module.exports = scheduleReport;
Also I am starting app with app.js as main

Use Express JS to block unwanted requests from the Client SIde

Consider the Express router :
const express = require("express");
const router = express.Router();
const DUMMY_PLACES = [
{
id: "p1",
title: "Empire State Building",
description: "One of the most famous sky scrapers in the world!",
location: {
lat: 40.7484474,
lng: -73.9871516
},
address: "20 W 34th St, New York, NY 10001",
creator: "u1"
}
];
// # http://localhost:5000/api/places/user/u1
router.get("/user/:uid", (req, res, next) => {
const user_id = req.params.uid;
const place = DUMMY_PLACES.find(p => {
return p.creator === user_id;
});
return res.status(200).json({
place
});
});
module.exports = router;
And the Server :
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const placesRoutes = require("./routes/places-routes");
app.use("/api/places", placesRoutes);
const PORT = 5000;
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
When clients hit the request http://localhost:5000/api/places/user/u1 , they get the dummy object ... however when hitting the request
http://localhost:5000/api/places/user
... it produces an empty object.
How can I return something like NOT ALLOWED instead of the empty object ?
Maybe you could check for the existence of a user_id and send an error response if there isn't one?
router.get('/user/:uid', (req, res, next) => {
const user_id = req.params.uid
if (!user_id) {
return res.status(400).json({
error: 'User ID required'
})
}
const place = DUMMY_PLACES.find((p) => {
return p.creator === user_id
})
return res.status(200).json({
place
})
})
The HTTP status codes are born to handle a lot of situation. In your case, there is a client error: the resource requested has not been found on the server (error 404).
In this case, your API can change in this way:
router.get("/user/:uid", (req, res, next) => {
const user_id = req.params.uid;
const place = DUMMY_PLACES.find(p => {
return p.creator === user_id;
});
if (!place) { // if the place does not exist
return res.status(404).json({
message: 'The requested resource has not been found in the server.'
});
}
return res.status(200).json({
place
});
});

Why don't I get the push notification pop up?

I have the following code for handling & subscribing to the push notification on front-end which runs on port 4000:
var endpoint;
var key;
var authSecret;
// We need to convert the VAPID key to a base64 string when we subscribe
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function determineAppServerKey() {
var vapidPublicKey = 'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY';
return urlBase64ToUint8Array(vapidPublicKey);
}
export default function registerServiceWorker() {
if('serviceWorker' in navigator) {
navigator.serviceWorker.register(`${process.env.PUBLIC_URL}\sw.js`).then(function(register){
console.log("worked", register)
return register.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
// We already have a subscription, let's not add them again
return;
}
return register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: determineAppServerKey()
})
.then(function(subscription) {
var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
authSecret = rawAuthSecret ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
endpoint = subscription.endpoint;
alert("came here")
return fetch('http://localhost:3111/register', {
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify({
endpoint: subscription.endpoint,
key: key,
authSecret: authSecret,
}),
})
});
});
}).catch(function(err){
console.log("Error",err)
})
}
}
and the server code looks like this:
const webpush = require('web-push');
const express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
const app = express();
// Express setup
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
function saveRegistrationDetails(endpoint, key, authSecret) {
// Save the users details in a DB
}
webpush.setVapidDetails(
'mailto:contact#deanhume.com',
'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY',
'p6YVD7t8HkABoez1CvVJ5bl7BnEdKUu5bSyVjyxMBh0'
);
// Home page
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
// Article page
app.get('/article', function (req, res) {
res.sendFile(path.join(__dirname + '/article.html'));
});
// Register the user
app.post('/register', function (req, res) {
var endpoint = req.body.endpoint;
var authSecret = req.body.authSecret;
var key = req.body.key;
// Store the users registration details
saveRegistrationDetails(endpoint, key, authSecret);
const pushSubscription = {
endpoint: req.body.endpoint,
keys: {
auth: authSecret,
p256dh: key
}
};
var body = 'Thank you for registering';
var iconUrl = 'https://raw.githubusercontent.com/deanhume/progressive-web-apps-book/master/chapter-6/push-notifications/public/images/homescreen.png';
webpush.sendNotification(pushSubscription,
JSON.stringify({
msg: body,
url: 'https://localhost:3111',
icon: iconUrl,
type: 'register'
}))
.then(result => {
console.log("came here ")
console.log(result);
res.sendStatus(201);
})
.catch(err => {
console.log(err);
});
});
// The server
app.listen(3111, function () {
console.log('Example app listening on port 3111!')
});
server runs on 3111. When I navigate to 4000 port, I could able to see the Allow/Block pop up comes up and if I give Allow, I expect the server sends Thank you for registering messages as I have done in the server. However the Thank you for registering pop up doesn't comes up and there are no error in the console.
Note: I'm hitting 3111 by enabling CORS using chrome-extension.
I think that that could depend on your server, as i have a python server at home, and when i use the notification api it doesn't notify, unless I am on https sites. If that is not the problem then i would assume there is a code error, but I believe that you could use the broadcast channels and xhr such as : let b = new BroadcastChannel;b.onmessage(function(){XmlHTTPRequest('POST', {Data: "yes"})}; ) and use the xhr to push notifications.

Categories