Nodejs-dialogflow: Send parameters to webhook on dialogflow sdk v2

Created on 1 Dec 2017  路  11Comments  路  Source: googleapis/nodejs-dialogflow

I'm trying to send some parameters to dialogflow (api.ai) such as username, email, etc but I couldn't figure it out. The problem is I cannot get/set any specific data (such as username, email, etc.) with Dialogflow v2 Nodejs SDK. I tried to use queryParams.payload (v1: originalRequest) but It didn't work somehow. Also, I tried to trigger custom event with data but I couldn't get any event data on the response. Does someone know how to send some specific data for session talk on dialogFlow?

EXAMPLE OF PAYLOAD

  const projectId = 'test-bot-test-1111';
  const sessionId = user.uuid;
  const languageCode = 'en-GB';

  const sessionClient = new dialogFlow.SessionsClient();
  const sessionPath = sessionClient.sessionPath(projectId, sessionId);

  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        text: query,
        languageCode
      }
    },
    queryParams: {
      payload: {
        data: {
           username: 'bob',
           email: '[email protected]'
        }
      }
    }
  };

  let resultReq;

  console.log('request :: ', request, '\n\n');

  try {
    resultReq = await sessionClient.detectIntent(request);
  } catch (err) {
    // eslint-disable-next-line no-console
    return console.error('ERROR:', err);
  }

EXAMPLE OF EVENT

  const projectId = 'test-bot-test-1111';
  const sessionId = user.uuid;
  const languageCode = 'en-GB';

  const sessionClient = new dialogFlow.SessionsClient();
  const sessionPath = sessionClient.sessionPath(projectId, sessionId);

const request = {
    session: sessionPath,
    queryInput: {
      event: {
        name: 'custom_event',
        languageCode,
        parameters: {
          name: 'sam',
          user_name: 'sam',
          a: 'saaaa'
        }
      }
    },
    queryParams: {
      payload: {
        data: user
      }
    }
  };

  let resultReq;

  console.log('request :: ', request, '\n\n');

  try {
    resultReq = await sessionClient.detectIntent(request);
  } catch (err) {
    // eslint-disable-next-line no-console
    return console.error('ERROR:', err);
  }
question dialogflow

Most helpful comment

Hey @mtalebi, you can try the answer that I got on StackOverflow. It works in my scenario. https://stackoverflow.com/questions/47583996/send-parameters-to-webhook-on-dialogflow-sdk-v2

All 11 comments

I'm curious about the same thing myself. I pass values I need for my fulfillment through request.queryParams.payload when I try to run sessionClient.detectIntent, but I am not seeing them come through when I review the Firebase Functions logs.

When I log request in the detectIntent method (src/v2beta1/sessions_clients.js), I do see my custom payload. This line also makes it seem like it's a supported feature. I don't see the gax calls stripping this out, so my guess is DialogFlow is not passing it along to fulfillment when it receives the request?

Hey @mtalebi, you can try the answer that I got on StackOverflow. It works in my scenario. https://stackoverflow.com/questions/47583996/send-parameters-to-webhook-on-dialogflow-sdk-v2

@ilkerguller - this did the trick for queryParams.payload. Many thanks!

Still getting empty parameters after adding structjson.

queryInput: {
  event: {
    name: 'FIRST_CHAT',
    parameters: structjson.jsonToStructProto({name: 'bar'}),
    languageCode: languageCode,
  }
}

Does it have something to do with the dialogflow settings?

settings

I seem to have the same issue. Used to be able to pass parameters to DialogFlow inside of events (without the structjson module) but now all my responses show none of the parameters being filled. I've tried making the parameters required, changing the parameter names, creating new intents, in addition to the suggestions above. I've even tried replicating the functionality of the code found in samples with no such luck.

Since I can't wait for a fix and I already developed around this feature I'm working on a hack to use a normal text query to 'manually' trigger the intent and pass the desired parameters. As you may guess this solution is unreliable at best.

I just tried, following the SO answer:

const parameters = structjson.jsonToStructProto({
    source: PLATFORM_WEB_UNLY,
  });

  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        text: query,
        parameters,
        languageCode: lang,
      },
    },
  };

parameters is properly constructed using the protobuff format, but I still get empty parameters in my webhook. Any idea?

console.log(JSON.stringify(request))
{"session":"projects/xxx","queryInput":{"text":{"text":"test","parameters":{"fields":{"source":{"kind":"stringValue","stringValue":"web_unly"}}},"languageCode":"fr-FR"}}}


Solution:

const parameters = structjson.jsonToStructProto({
    source: PLATFORM_WEB_UNLY,
  });

  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        text: query,
        languageCode: lang,
      },
    },
    queryParams: {
      payload: parameters,
    },
  };

See https://github.com/googleapis/nodejs-dialogflow/issues/9#issuecomment-514065923 for structjson

This appears to have been solved, please feel free to reopen if that is not the case. Thanks
:)

For me, the above technique works for passing payload to the webhook, but not for matching dialogflow parameters when using queryInput: { event: ... }. Anyone have a solution for that use case? I have tried all the suggestions above.

@qhua360 You have to use event name to access parameter

image

Replace "custom_event" with your event name.

Then you can use parameter in text response
image

@Vadorequest what is structjson in your sample code?

@Shajeel-Afzal It's something I found online, I believe it's from Google's.

structjson.js

/**
 * Copyright 2017, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Utilities for converting between JSON and goog.protobuf.Struct
 * proto.
 */

'use strict';

function jsonToStructProto(json) {
  const fields = {};
  for (const k in json) {
    fields[k] = jsonValueToProto(json[k]);
  }

  return { fields };
}

const JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP = {
  [typeof 0]: 'numberValue',
  [typeof '']: 'stringValue',
  [typeof false]: 'boolValue',
};

const JSON_SIMPLE_VALUE_KINDS = new Set([
  'numberValue',
  'stringValue',
  'boolValue',
]);

function jsonValueToProto(value) {
  const valueProto = {};

  if (value === null) {
    valueProto.kind = 'nullValue';
    valueProto.nullValue = 'NULL_VALUE';
  } else if (value instanceof Array) {
    valueProto.kind = 'listValue';
    valueProto.listValue = { values: value.map(jsonValueToProto) };
  } else if (typeof value === 'object') {
    valueProto.kind = 'structValue';
    valueProto.structValue = jsonToStructProto(value);
  } else if (typeof value in JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP) {
    const kind = JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP[typeof value];
    valueProto.kind = kind;
    valueProto[kind] = value;
  } else {
    console.warn('Unsupported value type ', typeof value);
  }
  return valueProto;
}

function structProtoToJson(proto) {
  if (!proto || !proto.fields) {
    return {};
  }
  const json = {};
  for (const k in proto.fields) {
    json[k] = valueProtoToJson(proto.fields[k]);
  }
  return json;
}

function valueProtoToJson(proto) {
  if (!proto || !proto.kind) {
    return null;
  }

  if (JSON_SIMPLE_VALUE_KINDS.has(proto.kind)) {
    return proto[proto.kind];
  } else if (proto.kind === 'nullValue') {
    return null;
  } else if (proto.kind === 'listValue') {
    if (!proto.listValue || !proto.listValue.values) {
      console.warn('Invalid JSON list value proto: ', JSON.stringify(proto));
    }
    return proto.listValue.values.map(valueProtoToJson);
  } else if (proto.kind === 'structValue') {
    return structProtoToJson(proto.structValue);
  } else {
    console.warn('Unsupported JSON value proto kind: ', proto.kind);
    return null;
  }
}

module.exports = {
  jsonToStructProto,
  structProtoToJson,
};

Was this page helpful?
0 / 5 - 0 ratings