3

I'm trying to implement a custom chat window for a DialogFlow chatbot. AFAIK, I need to create a server to handle requests from the chat window, forward them to DialogFlow for a response, and then return that response to the chat window. I followed the sample from the DialogFlow Node.js client SDK (step 6: "Try an example") and ended up with this:

require('dotenv').config()
const dialogflow = require('dialogflow');
const express = require('express');    

const app = express();
const PORT = process.env.PORT || 3000;    

app.use(express.json());    

const sessionClient = new dialogflow.SessionsClient({
  credentials: {
    client_email: process.env.CLIENT_EMAIL,
    private_key: process.env.PRIVATE_KEY
  }
});    

async function getResponse(req, res) {
  // A unique identifier for the given session
  console.log("body", req.body);
  const sessionId = req.body.session.split('/').pop();    

  // Create a new session
  console.log("session", sessionId)

  const sessionPath = sessionClient.sessionPath(process.env.PROJECT_ID, sessionId);    

  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: req.body.queryResult.queryText,
        // The language used by the client (en-US)
        languageCode: 'en-US',
      }
    }
  };    

  console.log("send request", request)
  // Send request and log result
  const responses = await sessionClient.detectIntent(req);
  const result = responses[0].queryResult;
  res.json(result);
}    

app.post('/', getResponse);
app.get('/', (req, res) => res.send('Use POST'));
app.listen(PORT, () => {
  console.log('Server is running on PORT:',PORT);
});

Although the original sample worked, sending a POST request to my server using Postman gives me this error:

(node:724) UnhandledPromiseRejectionWarning: Error: 3 INVALID_ARGUMENT: Resource name '' does not match 'projects/*/locations/*/agent/environments/*/users/*/sessions/*'.
    at Object.callErrorFromStatus (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\call.js:30:26)
    at Http2CallStream.call.on (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\client.js:96:33)
    at Http2CallStream.emit (events.js:194:15)
    at process.nextTick (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\call-stream.js:75:22)
    at process._tickCallback (internal/process/next_tick.js:61:11)
(node:724) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:724) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I'm not sure where this error is coming from, whether there's an issue with how I formatted the request in my getResponse function or if somehow it's related to Postman? The query I'm making (on the Postman side) is a POST to http://localhost:3000 with the Content-Type header set to application/json and the request body set as raw JSON (I pasted in this sample Webhook request). I'm leaning towards the issue being with the request to DialogFlow but I included the Postman info just in case.

ROODAY
  • 756
  • 1
  • 6
  • 23
  • Is the JSON you're trying to send being sent to... your server? To Dialogflow? You're trying to emulate what your web client needs to send? – Prisoner Oct 29 '19 at 02:19
  • @Prisoner from what I understand the issue is with this line: `const responses = await sessionClient.detectIntent(req);`, so it would be the JSON object constructed in the code, which is being sent to Dialogflow. Unless I'm mistaken, I need a webserver to sit between my client app and Dialogflow because of the credentials required to access Dialogflow, – ROODAY Nov 01 '19 at 19:40
  • You do, but you haven't made clear if that is what this code is, or where it runs. And you haven't made clear if the error you show was from this code or from your client code. There are a bunch of possible things it could be, but if you update your question to make it clear what is going on, we can probably help you narrow things down. – Prisoner Nov 01 '19 at 20:18
  • The thing is I'm not too sure myself what's going wrong, hence the question. My guess is that there's something wrong with the request object I'm creating in the getResponse function, as the error `INVALID_ARGUMENT: Resource name '' does not match 'projects/*/locations/*/agent/environments/*/users/*/sessions/*'.` sounds like something that would be surfaced by the DialogFlow SessionClient. I mentioned the surrounding context like using Postman etc. to provide more information in case it was helpful. – ROODAY Nov 04 '19 at 20:39

2 Answers2

4

I think the problem is that you're not sending what you think you're sending to detectIntent().

Assuming this code is meant to run on a server somewhere, take the request from the JavaScript client, and then create a request to Dialogflow - you're not actually doing that.

Although you are creating the request (in a constant named request) and logging it

  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: req.body.queryResult.queryText,
        // The language used by the client (en-US)
        languageCode: 'en-US',
      }
    }
  };    

  console.log("send request", request)

when you go to send this to Dialogflow you're not sending the request object, but rather the req object, which is what came from the client:

const responses = await sessionClient.detectIntent(req);

You should never pass something from a client without sanitizing it in your server first.

I suspect if you change it to something like this, it should work:

const responses = await sessionClient.detectIntent(request);
Prisoner
  • 49,922
  • 7
  • 53
  • 105
  • Ah, I must've changed the name and forgot to update the name passed to detectIntent. It's always something silly. – ROODAY Nov 06 '19 at 02:54
0

In my case, what was wrong, was the sessionPath variable, the code I had was:

const sessionPath = sessionClient.projectAgentEnvironmentPath(dialogProjectId, sessionId);

But the correct is:

const sessionPath = sessionClient.projectAgentSessionPath(dialogProjectId, sessionId);
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Fritsch
  • 59
  • 1
  • 2
  • 10