Search code examples
typescriptexpressgoogle-apidialogflow-esdialogflow-es-fulfillment

Dialogflow & Express -- Fulfilment


I'm having an issue getting responses from dialogflow, when other express calls are working fine.

I know it's an issue with the agents, but I'm unsure what that issue is or how to fix it, which is why I'm asking on here.

Key points to note.

  • This code is being added to a existing tested express application
  • Been testing using postman
  • Dialogflow fullfillment template webhook can be found here
  • console successfully outputs We got hours! then doesn't continue
  • if you comment line 57 through 62 (the if section) and uncomment line 56 code responds as expected
  • Issue expected to be within the agents.hours function
  • Have tried this.currentlyOpen() === true as well

Sooo many thanks in advance.

dialogflow.ts

// import { google } from 'googleapis';
const {WebhookClient} = require('dialogflow-fulfillment');
// import { Card, Suggestion } from 'dialogflow-fulfillment';
/**
 * @private
 * Initialise the ai assist api
 */
export class Agents {
  aiassist:any

  async initialize (message:any) {
    var aiassist = {
      info: {
        configsuccess: false,
        message: message,
        data: [],
      }
    }
    process.env.DEBUG = 'dialogflow:debug';
    const url = message.headers.configlocation;
    await message.core.request({url: url, json: true}, function (error: any, response: { statusCode: number; }, data: any) {
      aiassist.info.data = data
      if (!error && response.statusCode === 200) {
        aiassist.info.configsuccess = true
      }
      return aiassist
    })
    this.aiassist = aiassist
    this.WebhookProcessing();
  }

  /**
  * @private
  * Find the map the agent
  */
  WebhookProcessing () {
    const agent = new WebhookClient({request: this.aiassist.info.message.full, response: this.aiassist.info.message.res});

    let intentMap = new Map();
    intentMap.set('Hours', this.hours);

    agent.handleRequest(intentMap);
  }

  /****************
  * AGENT        *
  *  DECLARATION *
  ****************/
  /**
  * [hours description]
  * @param  agent [description]
  * @return       [description]
  */
  hours (agent:any) {
    console.log("We got hours!")
    // agent.add(`We're open now! We close at 17:00 today. Is there anything else I can help you with?`);
    if (currentlyOpen(this.aiassist)) { // TypeError: Cannot read property 'aiassist' of undefined
      console.log("open!")
      agent.add(`We're open now! We close at 17:00 today. Is there anything else I can help you with?`);
    } else {
      console.log("closed!")
    }
  }

}

/******************
* FUNCTIONS      *
*    DECLARATION *
******************/

//  Check if currently open - Issues getting "aiassist" into this function
function currentlyOpen (aiassist:any) {
  // Get current datetime with proper timezone
  console.log("We got currentlyOpen!")
  // const date = new Date()
  console.log(aiassist.info.data.timeZoneOffset)
  // console.log("We finished currentlyOpen")
  // date.setHours(date.getHours() + parseInt(agent.this.aiassist.info.data.timeZoneOffset.split(':')[0]));
  // date.setMinutes(date.getMinutes() + parseInt(agent.this.aiassist.info.data.timeZoneOffset.split(':')[0][0] + agent.this.aiassist.info.data.timeZoneOffset.split(':')[1]));
  // return date.getDay() >= 1 &&
  // date.getDay() <= 5 &&
  // date.getHours() >= agent.this.aiassist.info.data.businessSetings.openTime &&
  // date.getHours() <= agent.this.aiassist.info.data.businessSetings.closeTime;
  return true
}   
TypeError: Cannot read property 'aiassist' of undefined
  File "C:\Users\sjona\Desktop\TSC\repo\curr\built\routes\v1\dialogflow.js", line 53, col 32, in hours
    if (currentlyOpen(this.aiassist)) {
  File "C:\Users\sjona\Desktop\TSC\repo\curr\node_modules\dialogflow-fulfillment\src\dialogflow-fulfillment.js", line 313, col 44, in WebhookClient.handleRequest
    let result = handler.get(this.intent)(this);
  File "C:\Users\sjona\Desktop\TSC\repo\curr\built\routes\v1\dialogflow.js", line 39, col 15, in Agents.WebhookProcessing
    agent.handleRequest(intentMap);
  File "C:\Users\sjona\Desktop\TSC\repo\curr\built\routes\v1\dialogflow.js", line 29, col 14, in Agents.initialize
    this.WebhookProcessing();

EDIT: Updated code to match comment. Added note where issues arise.


Solution

  • The problem is that this isn't what you think it is (or want it to be) due to how hours() gets called and how this has different meanings depending how it is called. This page goes into the gory details, but in short (as it applies to you):

    • A function that gets called has this applied to the global object, not to the lexically bound version of this (ie - the value of this inside a class
    • To get the lexically bound version of this, you need to bind the value to the function using bind(), or use an arrow function to make the call.

    In your case, this means that you should be registering the Intent Handler with something like

    intentMap.set('Hours', agent => this.hours(agent));