We notice our bot(developed using actions-on-google sdk) show same response two times on some mobile devices - actions-on-google

We are building Chat Bot project using Actions on google SDK, we often face
one issue while testing our Bot on console it always show one response, but
on mobile sometime it shows double response for same Bot request response.
Attached are screen shots for same Bot flow, one is on mobile and other is
using console, please guide us what is wrong with it, we monitor our code again and again it send only one response.
index.js
const express = require('express');
const bodyParser = require('body-parser');
const routes = require('./app/router/routes');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(routes);
const PORT = 8080;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}...`);
});
routes.js
const express = require('express');
const router = new express.Router();
const {app} = require('../controller/googleAssistantSample');
router.post('/test12543/gooogleWebhook', app);
module.exports = router;
googleAssistantSample.js
const {
conversation,
Simple,
Suggestion,
} = require('#assistant/conversation');
const app = conversation();
app.handle('mainMenu', (conv) => {
conv.add(new Simple({
speech: 'Please select Informasi for producing issue.',
text: 'Please select Informasi for producing issue.',
}));
conv.add(new Suggestion({
title: 'Informasi',
}));
});
app.handle('information', (conv) => {
conv.add(new Simple({
speech: 'Next please select Safe Banking for producing issue.',
text: 'Next please select Safe Banking for producing issue.',
}));
conv.add(new Suggestion({
title: 'Safe Banking',
}));
});
app.handle('safeInfo', (conv) => {
conv.add(new Simple({
speech: 'Please check issue.',
text: 'Please check issue.',
}));
});
module.exports = {
app,
};
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"#assistant/conversation": "^3.7.1",
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
Testing on mobile image
Testing on Actions console image

Related

jest calls afterEach (teardown) before test finish only in debug mode

I am using nodejs, nestjs, supertest, mongodb, mongoose.
My tests run is completed successfully, using command
npm run test:e2e from default nestjs package.json config.
When I execute my separate test in debug mode, from vscode debug view it fails with error of disposed mongodb connection. The test has mutliple async requests calls which I await it returns after request is called and starts executing jest teardown afterEach and afterAll which is kinda strange for me.
My launch.json
{
"type": "node",
"request": "launch",
"name": "Jest Current File e2e tests",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"${fileBasenameNoExtension}",
"--config",
"${workspaceFolder}/test/jest-e2e.json"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
jest-e2e.json
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}
app.e2e-spec.ts
describe('app (e2e)', () => {
let app: INestApplication;
let connection: Connection;
let dbInitializer: DbInitializer;
beforeAll(async () => {
const moduleFixture: TestingModule = await createAndCompileTestingModule();
app = moduleFixture.createNestApplication();
await configApp(app);
await app.init();
});
afterAll(async () => {
await app.close();
});
beforeEach(async () => {
const configService = app.get(ConfigService);
const logger = new MyLogger(configService);
connection = app.get(CustomConnectionService).getConnection();
dbInitializer = new DbInitializer(connection, logger);
await dbInitializer.seedDb();
});
afterEach(async () => {
await connection.db.dropCollection(dbInitializer.articleCollectionName);
await connection.db.dropCollection(dbInitializer.userCollectionName);
});
it('/ (POST) creates article', async function () {
expect.assertions(9);
const userToLogin = {
username: 'leane1Gra',
password: 'cft0id32',
};
const httpServer = app.getHttpServer();
const responseLogin = await request(httpServer)
.post(`/${LoginEndPoint}`)
.set('Accept', 'application/json')
.send(userToLogin);
expect(responseLogin.statusCode).toBe(201);
const userLoginResponse = responseLogin.body as UserLoginResponse;
const resposeGetUser = await request(app.getHttpServer())
.get(`/${UsersEndpoint}/by-username`)
.query({ username: userToLogin.username });
expect(resposeGetUser.statusCode).toBe(200);
const userFindByUsernameResponse =
resposeGetUser.body as MappedUserResponse;
const articleToCreate = {
title: 'article a',
subtitle: 'subtitle a',
description: 'description a',
category: 'history',
ownerId: userFindByUsernameResponse.id,
};
const response = await request(httpServer)
.post(`/${ArticlesEndpoint}`)
.set('Authorization', `Bearer ${userLoginResponse.user_jwt}`)
.set('Accept', 'application/json')
.send(articleToCreate);
expect(response.statusCode).toBe(201);
expect(response.headers['content-type']).toMatch(/json/);
const { updatedUser, newArticle } = response.body as CreateArticleResponse;
expect(newArticle.id).toBeTruthy();
expect(newArticle.title).toBe(articleToCreate.title);
expect(updatedUser.id).toBeTruthy();
expect(updatedUser.articleIds).toContain(newArticle.id);
expect(updatedUser.numberOfArticles).toBe(
userFindByUsernameResponse.numberOfArticles + 1,
);
});
}
I am adding a video of test run in debug mode
Add the timeout after your it test. The max value for timeout is 32 bit signed integer.
You can debug your test during specified timeout without jest teardown called.
it('/ (POST) creates article', async function () {
//test body omitted
},147483647)

Puppeteer + Leaflet JS with Apple MapKit PDF Creation Issues

I'm having issues properly exporting a PDF when using Apple MapKit tiles. It works fine with Google Maps or Bing tiles.
Expected output:
Actual output:
Notice the tiles zoomed incorrectly.
How to reproduce the issue:
Use the following curl command with a local Puppeteer server:
curl -X GET -G "http://localhost:8080" --data-urlencode "url=https://en.mycoursewalk.com/coursewalks/18624/print?print_pdf=true&unlisted_id=e61d9b86d7" --data-urlencode "page_orientation=Landscape" --data-urlencode "paper_size=Letter" --output "test.pdf"
You can access the page in your browser at: https://en.mycoursewalk.com/coursewalks/18624/print?unlisted_id=e61d9b86d7
package.json
{
"name": "chrome-puppeteer-pdf-export",
"version": "1.0.1",
"description": "",
"engines": {
"node": "12.22.6"
},
"main": "app.js",
"directories": {
"doc": "doc",
"lib": "lib",
"test": "test"
},
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"express": "^4.17.1",
"valid-url": "^1.0.9",
"puppeteer": "10.4.0"
}
}
app.js
const express = require('express');
const app = express();
const puppeteer = require('puppeteer');
const port = process.env.PORT || 8080;
const validUrl = require('valid-url');
const parseUrl = function(url) {
url = decodeURIComponent(url);
if (!/^(?:f|ht)tps?\:\/\//.test(url)) {
url = 'http://' + url;
}
return url;
};
app.get('/', function(req, res) {
const urlToScreenshot = parseUrl(req.query.url);
if (validUrl.isWebUri(urlToScreenshot)) {
console.log('Screenshotting: ' + urlToScreenshot);
const page_orientation = req.query.page_orientation;
const paper_size = req.query.paper_size;
(async() => {
let browser;
try {
browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.emulateMediaType('print');
await page.setCacheEnabled(false);
await page.setViewport({ width: 1024, height: 768, deviceScaleFactor: 2 });
await page.goto(urlToScreenshot, { timeout: 30000, waitUntil: 'networkidle0' });
await page.waitFor(250);
await page.pdf({
format: paper_size,
landscape: (page_orientation === 'Landscape'),
margin: { top: 36, right: 36, bottom: 20, left: 36 },
printBackground: true
}).then(function(buffer) {
res.setHeader('Content-Disposition', 'attachment;filename="export.pdf"');
res.setHeader('Content-Type', 'application/pdf');
res.send(buffer)
});
} catch (err) {
console.log(err.message);
} finally {
if (browser) {
browser.close();
}
}
})();
} else {
res.send('Invalid url: ' + urlToScreenshot);
}
});
app.listen(port, function() {
console.log('App listening on port ' + port)
});
UPDATE
The problem is only happening for maps that end up on a fractional zoom level. I allow a zoom step of 0.25.
The problem only happens with the Apple MapKit tiles. It works fine with the Google Maps or Bing.
The expected output screenshot above is taken by printing to PDF from the Google Chrome browser. The map also displays correctly in the browser. The problem only happens when generating a PDF using Puppeteer

Why it is reflecting undefined in Mongodb server

I'm new to mongoDb and took one course but stuck at this point .I created this Index.js and here I'm inserting one data and using callbacks but after insertion it is reflecting undefined?
--indes.js
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const url = 'mongodb://localhost:27017/';
const dbname = 'conFusion';
MongoClient.connect(url, (err, client) => {
assert.equal(err, null);
console.log('Connected correctly to server');
const db = client.db(dbname);
const collection = db.collection('dishes');
collection.insertOne({ "name": "Uthappizza1", "description": "test" },
(err, result) => {
assert.equal(err, null);
console.log('After Insert:\n');
console.log(result.ops);
collection.find({}).toArray((err, docs) => {
assert.equal(err, null);
console.log('Found:\n');
console.log(docs);
db.dropCollection('dishes', (err, result) => {
assert.equal(err, null);
client.close();
});
});
});
});
also attaching the package.json for more clearilty
{
"name": "node-mongo",
"version": "1.0.0",
"description": "Node MongoDB Example",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index"
},
"author": "Shivam Singh",
"license": "ISC",
"dependencies": {
"assert": "^2.0.0",
"mongodb": "^4.0.1"
}
}
I'm also attaching the screenshot
It is because the insertOne method through the callback returns object of interface InsertOneResult, which according to the documentation only has 2 fields: acknowledged and insertedId. Due to this reason result.ops will always be undefined here because you do have result object, but it doesn't have the property ops.

adding custom JSON payloads for TELEGRAM in Dialogflow to get users to share their phone number

the function below is supposed to provides the fulfillment to the share_your_phone_number intent.
When the intent is invoked, the share your phone number keyboard is displayed for the user in telegram.
function share_your_phone_number(agent) {
agent.add(`Welcome.`);
agent.add(new Payload("telegram", {
"text": "Please click on button below to share your number",
"reply_markup": {
"one_time_keyboard": true,
"resize_keyboard": true,
"keyboard": [
[
{
"text": "Share my phone number",
"callback_data": "phone",
"request_contact": true
}
],
[
{
"text": "Cancel",
"callback_data": "Cancel"
}
]
]
}
}
));
}
When I deploy the API in the inline editor, only the "Welcome" string is returned in telegram bot chat. the key board buttons are not displayed.
I need a clue to fix fix this.
In creatin the Constructor for Payload object as documented [here]https://dialogflow.com/docs/reference/fulfillment-library/rich-responses#new_payloadplatform_payload, the platform and payload parameters are required.
new Payload(platform, payload)
The platform parameter is a property of WebhookClient object and should be defined as such (agent.SLACK, agent.TELEGRAM etc) assuming the webhookClient was instantiated and stored in agent
Examples:
agent.add(new Payload(agent.ACTIONS_ON_GOOGLE, {/*your Google payload here*/});
agent.add(new Payload(agent.SLACK, {/*your Slack payload here*/});
agent.add(new Payload(agent.TELEGRAM, {/*your telegram payload here*/});
ref: https://blog.dialogflow.com/post/fulfillment-library-beta/.
For my use-case outlined in the question this is my full solution:
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Text, Card, Image, Suggestion, Payload} = require('dialogflow-fulfillment');
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));
function welcome(agent) {
agent.add(new Payload(agent.TELEGRAM, {
"text": "Please click on button below to share your number",
"reply_markup": {
"one_time_keyboard": true,
"resize_keyboard": true,
"keyboard": [
[
{
"text": "Share my phone number",
"callback_data": "phone",
"request_contact": true
}
],
[
{
"text": "Cancel",
"callback_data": "Cancel"
}
]
]
}
}));
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
agent.handleRequest(intentMap);
});
Here is my result:
function welcome(agent) {
const payload = {
"text": "Pick a color",
"reply_markup": {
"inline_keyboard": [
[
{
"text": "Yellow",
"callback_data": "Yellow"
}
],
[
{
"text": "Blue",
"callback_data": "Blue"
}
]
]
}
};
console.log('queryText ' + JSON.stringify(agent.request_.body.queryResult.queryText));
console.log('displayName ' + JSON.stringify(agent.request_.body.queryResult.intent.displayName)
agent.add(
new Payload(agent.TELEGRAM, payload, {rawPayload: false, sendAsMessage: true})
);
}
Also you must update version of dialogflow-fulfillment in package.json to latest. Now I have this version - "dialogflow-fulfillment": "^0.6.1"

Simulator does not invoke other intents, like text and other custom intents for Actions SDK

I am using Actions SDK and I have different configurations to get the simulator to invoke my custom intent! It seems that the simulator refuses to trigger any action other than MAIN, not even TEXT. Below is my action.json:
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "SHOPPING"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
"Talk to stroller shopping expert"
]
}
}
},
{
"description": "Listing strollers for a specified age group",
"name": "SHOPPING",
"fulfillment": {
"conversationName": "SHOPPING"
},
"intent": {
"name": "SHOPPING",
"trigger": {
"queryPatterns": [
"I am looking for a jogging stroller",
"I am shopping for a jogging stroller"
]
}
}
}
],
"conversations": {
"SHOPPING": {
"name": "SHOPPING",
"url": "SOME_URL (I have a valid URL BTW)",
"fulfillmentApiVersion": 2
}
}
}
I am using firebase and in the firebase log I cannot see any logs from my custom or TEXT intent. Here are part of my index.json code:
'use strict';
process.env.DEBUG = 'actions-on-google:*';
const ActionsSdkApp = require('actions-on-google').ActionsSdkApp;
const functions = require('firebase-functions');
const NO_INPUTS = [
'Padon me, I didn\'t hear that.',
'If you\'re still there, would you please say that again.',
'We can stop here. Good luck with your shopping.'
];
const SHOPPING_INTENT = 'SHOPPING';
exports.shopStrollers = functions.https.onRequest((request, response) => {
const app = new ActionsSdkApp({request, response});
function handleMainInput(app) {
console.log('mainIntent is invoked!');
console.log("The input is %s", app.getRawInput());
console.log("It seems that %s is never invoked!", app.StandardIntents.TEXT)
let inputPrompt = app.buildInputPrompt(true, '<speak>Hi! <break time="1"/> ' +
'I can help with finding strollers. How old is your baby?</speak>', NO_INPUTS);
app.ask(inputPrompt);
}
function handleTextInput(app) {
console.log('TEXT is invoked!');
console.log("The input is %s", app.getRawInput());
console.log("Finally TEXT HANDLER got invoked")
if (app.getRawInput() === 'bye') {
app.tell('Hope you found the service helpful and best of luck with your shopping, please come back again, goodbye!');
} else {
let inputPrompt = app.buildInputPrompt(true, '<speak>Here is a list of top' +
' <say-as interpret-as="ordinal">10</say-as>strollers' +
', say next for the next batch</speak>', NO_INPUTS);
app.ask(inputPrompt);
}
}
let actionMap = new Map();
actionMap.set(SHOPPING_INTENT, handleTextInput);
actionMap.set(app.StandardIntents.MAIN, handleMainInput);
actionMap.set(app.StandardIntents.TEXT, handleTextInput);
app.handleRequest(actionMap);
});
Does anybody have a clue what might be wrong, I would appreciate any help.
Problem solved. I had to enable web history.
I was using a business email and I had to go through a convoluted configuration process to "turn on web history"! Now everything works fine through ngrok and my express app. I would imagine it should work on firebase as well. So, action.json and index.js were good, the issue was with incomplete configuration for the business email!
Here is the steps I followed: https://productforums.google.com/forum/#!msg/apps/-52VibOcvrY/wUow1QOJ3VQJ