【问题标题】:How to make http call on DialogFlow v2 using Javascript ajax call如何使用 Javascript ajax 调用在 DialogFlow v2 上进行 http 调用
【发布时间】:2018-11-10 15:06:39
【问题描述】:

我在使用 Node.js 的 DialogFlow 的官方网站上找到了这个示例,它运行良好,但我不知道如何将它集成到我的 Web 应用程序中。

我可以将它集成到我的其他 javascript jquery 代码中吗?在这里我需要运行 node index.js 但如果我与我的代码集成我还需要这样做吗?

const projectId = 'xxx'; //https://dialogflow.com/docs/agents#settings
const sessionId = 'xxxxx';
const query = 'Hello';
const languageCode = 'en-US';

// Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient();

// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
console.log(sessionPath);
// The text query request.
const request = {
  session: sessionPath,
  queryInput: {
    text: {
      text: query,
      languageCode: languageCode,
    },
  },
};

// Send request and log result
sessionClient
  .detectIntent(request)
  .then(responses => {
    console.log('Detected intent');
    const result = responses[0].queryResult;
    console.log(`  Query: ${result.queryText}`);
    console.log(`  Response: ${result.fulfillmentText}`);
    if (result.intent) {
      console.log(`  Intent: ${result.intent.displayName}`);
    } else {
      console.log(`  No intent matched.`);
    }
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

是否有任何替代方法可以让我们使用普通的 javascript jquery、ajax 来使用 DialogFlow v2,而无需每次我想使用 dialogflow 时都执行 node index.js。

DialogFlow v1 使用起来非常简单。我有这样的东西:

fetch(url, {
    body: JSON.stringify(data),
    // cache: 'no-cache',
    // credentials: 'same-origin',
    headers: {
        'content-type': 'application/json',
        "Authorization": "Bearer " + configs.accessToken,
    },
    method: 'POST',
    mode: 'cors',
    redirect: 'follow',
    referrer: 'no-referrer',
})
    .then(response => response.json()) // parses response to JSON

【问题讨论】:

  • 你想从 api 获取什么?
  • @Vivek 我想为聊天机器人使用 dialogflow api v2

标签: javascript google-cloud-platform google-cloud-datastore dialogflow-es


【解决方案1】:

正如其他人之前在这里所说,访问令牌的持续时间为一小时,在那之后它就变得无用了。因此,有必要对 API 进行调用(在我的情况下为 http 调用)以请求访问令牌,每小时一次,然后按照 Satheesh 的说明使用它。 https://developers.google.com/identity/protocols/OAuth2ServiceAccount 中提供了有关如何生成签名以进行调用并在以后使用它的说明。

一旦您使用私钥和您必须使用的电子邮件(不是您的电子邮件,而是由服务帐户生成的电子邮件)从服务帐户获取 json 文件,您就可以使用 jsrsasign 库(在纯 javascript 中) ,您可以在 https://github.com/kjur/jsrsasign 中找到,以生成 JSON Web 签名 (JWS) 和 JSON Web 令牌 (JWT),这将是进行 http 调用以获取访问令牌所必需的。

然后您按照 Satheesh 的描述使用它通过 jQuery 调用 Dialogflow V2。

我用来实现这个的代码是下一个:

生成 JWT(使用相关库):

function _genJWS() {
    var header = '{"alg":"RS256","typ":"JWT"}';
    var claimSet = jwtClaimSet();
    var privateKey = jwtPrivateKey();

    var sHead = newline_toDos(header);
    var head = KJUR.jws.JWS.readSafeJSONString(sHead);
    var sPayload = newline_toDos(claimSet);
    var sPemPrvKey = privateKey;

    var jws = new KJUR.jws.JWS();
    var sResult = null;
    try {
        prv = KEYUTIL.getKey(sPemPrvKey);

        sResult = KJUR.jws.JWS.sign(head.alg, sHead, sPayload, prv);
    } catch (ex) {
        alert("Error: " + ex);
    }
    return sResult;
}

请求访问令牌:

function _requestAccessToken() {
    var access_token = accessToken;
    var assertion = _genJWS();
    console.log('Assertion: ' + assertion);
    jQuery.ajax({
        type: "POST",
        url: "https://www.googleapis.com/oauth2/v4/token",
        contentType: "application/x-www-form-urlencoded",
        dataType: "json",
        data: "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + assertion,
        success: function(response) {
            console.log("success");
            console.log(response);
            access_token = response.access_token;
            console.log(access_token);
        },
        error: function() {
            console.log("Error");
        }
    });
    return access_token;
}

然后使用该访问令牌对 Dialogflow 进行 HTTP 调用。

希望对你有帮助。

【讨论】:

  • 如何实现jwtClaimSet函数?除了那个,我已经弄清楚了其他所有事情(我认为)。
  • 没关系,我想通了(根据您的回答),并在此处发布了解决方案:stackoverflow.com/a/57857698/2441655
  • 函数 jwtClaimSet() { var clst = ""; if (!Date.now) { Date.now = function() { return new Date().getTime(); } } timestampInSeconds = Math.floor(Date.now() / 1000); nextHourInSeconds = timestampInSeconds + (60*60); var iss = "your@gserviceaccount.com"; var scope = "googleapis.com/auth/dialogflow"; var aud = "googleapis.com/oauth2/v4/token"; var exp = nextHourInSeconds; var iat = timestampInSeconds; clst = JSON.stringify({ "iss":iss, "scope":scope, "aud":aud, "exp":exp, "iat":iat });返回 clst; }
  • 我已将所有 3 个函数复制到我的 javascript 文件中,并在 html 中包含 jsrsasign 库的脚本标记为
  • 我在浏览器/客户端本身上运行整个(完全是 javascript)代码。不涉及节点/服务器。
【解决方案2】:

您可以从 jQuery 轻松调用 Dialogflow 的 V2 API detectIntent 端点。

API docs 显示 URL 和请求格式:

POST https://dialogflow.googleapis.com/v2/{session=projects/*/agent/sessions/*}:detectIntent

{
  "queryParams": {
    object(QueryParameters)
  },
  "queryInput": {
    object(QueryInput)
  },
  "inputAudio": string
}

身份验证的工作方式略有不同;您将使用云仪表板创建服务帐户和密钥,而不是使用访问令牌。 This documentation page 解释了如何。

【讨论】:

  • 我已经创建了服务帐户和密钥,我如何使用它们从您展示的示例中发出 http/ajax 请求?授权:Bearer $(gcloud auth print-access-token) 这对我不起作用,你能举个例子吗?
  • 我看不到如何将我的服务帐户密钥与 jquery 一起使用,如何进行身份验证以便我可以使用 dialogflow api?
  • 同样的问题,没有关于使用 V2 api 的教程。极好的!已经失去了 2 周...
  • @Mizlul 和 Federico 我想通了(基于 JDE10 的回答),并在此处发布了解决方案:stackoverflow.com/a/57857698/2441655
【解决方案3】:

https://dialogflow.com/docs/reference/v2-auth-setup

通过上面的页面并创建服务密钥后,您必须有一个这样的json文件:

{
    "type": "",
    "project_id": "",
    "private_key_id": "",
    "private_key": "",
    "client_email": "",
    "client_id": "",
    "auth_uri": "",
    "token_uri": "",
    "auth_provider_x509_cert_url": "",
    "client_x509_cert_url": ""
  }  

使用此文件,执行以下两条命令(如果尚未安装gcloud CLI,则需要安装):

gcloud auth activate-service-account --key-file=<service-account-key-file.json>
gcloud auth print-access-token

之后,复制访问令牌并将其作为环境变量(或硬编码,如果您不关心)提供给您的程序。然后,您只需发出 HTTP 发布请求。我在我的 React 项目中使用 axios,这里是一个 detectIntent 的示例代码:

import axios from "axios";

const DIALOG_FLOW_TOKEN = process.env.REACT_APP_DIALOG_FLOW_TOKEN;
const DIALOG_FLOW_API_ROOT_URL = "https://dialogflow.googleapis.com/v2";
const YOUR_PROJECT_ID = <YOUR_PROJECT_ID>;
const SESSION_ID = <SESSION_ID>;
const URL = `${DIALOG_FLOW_API_ROOT_URL}/projects/${YOUR_PROJECT_ID}/agent/sessions/${SESSION_ID}:detectIntent`;

var config = {
    headers: {
        "Authorization": "Bearer " + DIALOG_FLOW_TOKEN,
        "Content-Type": "application/json"
    }
};

export function sendText(text) {
    var bodyParameters = {
        "queryInput": { "text": { "text": text, "languageCode": "en" } },
    };

    const request = axios.post(
        URL,
        bodyParameters,
        config
    );

    return request;
} 

【讨论】:

  • 访问令牌一个小时后过期,您如何处理?
  • 是的,你是对的,对不起我的错误。但是我发现这个答案可能会有所帮助,您检查过吗? stackoverflow.com/questions/47059976/…
【解决方案4】:

下面的 sn-p 解释了我们如何从 webapp 到 dialogflow NLU 进行通信。要获取访问令牌,我们可以使用谷歌云 SDK 来获取令牌,但它的有效期为一小时,因此在不同的服务中使用它并在调用 dialogflow 之前获取它会提供一种解决方法。

$(document).ready(function(){

$("button").click(function(){

    $.ajax({
        type: "POST",
        url: "https://dialogflow.googleapis.com/v2/projects/YOUR-PROJECT-NAME/agent/sessions/SESSIONIDOFYOURCHOICE:detectIntent",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        headers: {
            "Authorization": "Bearer " + "YOUR ACCESS TOKEN GOES HERE",
        },
        data: JSON.stringify({ "queryInput":{
            "text":{
                "text":"YOUR QUERY TO NLU",
                "languageCode":"en-US"
            }
        } }),
        success: function(data) {
            $("#div").html(data.queryResult.fulfillmentText);
        },
        error: function() {
            console.log("Internal Server Error");
        }
    });     

});

});

【讨论】:

  • 但是如何从像云功能这样的“不同服务”生成令牌呢? developers.google.com/identity/protocols/OAuth2ServiceAccount 和 googleapis npm 模块似乎是不错的起点,但我还没有找到关于如何生成这些访问令牌的明确说明。
  • 我还没有足够的互动来提高我的声誉并发表评论。这只是为了在 Doug 询问如何生成访问令牌时给他一个提示。在我的情况下,它位于 Dialogflow 控制台本身,在代理配置文件内 - 单击代理名称附近的齿轮 - 在“常规”选项卡下。我实际上有两个访问令牌,一个客户端访问令牌和一个开发人员访问令牌。我在某处读到我需要开发人员来解决检测意图问题。希望对您有所帮助。
  • @Doug 我想通了(基于 JDE10 的回答),并在此处发布了解决方案:stackoverflow.com/a/57857698/2441655
【解决方案5】:

我找到了一种完全从前端(浏览器)JavaScript 获取有效访问令牌的方法。

1) 从 npm 安装 npm 包 jsrsasign

2) 将此 Gist 中的文件添加到您的项目中:https://gist.github.com/Venryx/bfa9b69583638dfbf611a9f292721a75

3) 输入 DialogFlowExample.ts 开头的所有常量的值。

您的服务帐户信息可在以下位置找到:https://console.cloud.google.com/iam-admin/serviceaccounts

服务帐户的电子邮件在表中列出,其私钥(如果您已创建)可在下载的密钥 json 文件中找到。如果您不记得将密钥 json 文件放在哪里(或者您还没有创建一个),您可以使用“Actions->Create key”来创建一个新的。

4) 使用您的声明集和私钥调用 GetAccessToken(参见 Gist 示例)。它将返回一个承诺。

5) 一旦获取了访问令牌,promise 就会使用获取的访问令牌来解决。 (该函数将访问令牌缓存 60 分钟。在此之后,令牌已过期,因此再次调用该函数将使其检索一个新的。)

示例

linked Gist 包含一个几乎完整的使用示例,用于使用 DialogFlow 将一段音频转换为文本。它唯一没有显示的部分是如何获取“音频片段”。

为此,请在此处查看我的答案的第 1 部分:https://stackoverflow.com/a/57859776/2441655

【讨论】:

  • 这是否意味着您将服务帐户的私钥暴露给任何人的互联网浏览器?
  • @systemprogrammer 是的,没错。因此,我不建议将它用于生产中的大型项目,因为恶意行为者可能会使用您的服务密钥来创建伪造的转录调用,从而最大限度地利用您的配额。也就是说,这种浏览器内方法对于较小的项目(或不太可能吸引恶意用户的项目)很有帮助,在这些项目中,将服务器组件设置为中间人对于只有少数(或受信任的一群)人来说是不必要的麻烦。无论如何使用。 (如果发生这种情况,您需要使密钥无效,更改代码,然后创建一个新密钥)
【解决方案6】:

这种方式对我有用。

const dialogflow = require('dialogflow');
var projectId = ""; // your dialogflow project id when you click on settings of the DF agent
var sessionId = ""; // session ID
var config = {
// use credentials or keyFilename i'm using keyFile
    // credentials: {
        // private_key: privateKey,
        // client_email: clientEmail,
    // }
        keyFilename: './google.json'
};

var sessionClient = new dialogflow.SessionsClient(config);

async sendTextMessageToDialogFlow(textMessage) {
        // Define session path
        const sessionPath = sessionClient.sessionPath(projectId, sessionId);
        // The text query request.
        const request = {
            session: sessionPath,
            queryInput: {
                text: {
                    text: textMessage,
                    languageCode: 'en'
                }
            }
        }
        try {
            let [responses] = await sessionClient.detectIntent(request)
            console.log(responses);
        } catch (err) {
            console.error('DialogFlow.sendTextMessageToDialogFlow ERROR:', err);
            throw err
        }
    };

【讨论】:

    猜你喜欢
    • 2016-04-01
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 2016-12-19
    • 1970-01-01
    相关资源
    最近更新 更多