javascript - 谷歌助手的事实应用程序

标签 javascript firebase dialogflow-es actions-on-google google-home

我正在摆弄我的 Google Home,并创建了一个可以读取关于树懒的事实的应用程序。我使用 API.AI 创建了代理,我在 Firebase 上托管我的函数并通过 webhook 将它连接到 API.AI。你让谷歌告诉你一个关于树懒的事实,它会回答你是想听“有趣的事实”还是“科学事实”。您的回答决定了 Google 将为您读出什么样的事实。

在 API.AI 上进行测试时,我得到了默认的失败响应,但当我查看 JSON 时,它显然是在解析事实类别。我的 javascript 代码基于他们的教程正在使用的 Google 示例应用程序“Facts about Google”。下面是来自 API.AI 测试的 JSON 以及我的 tellFact() 函数。

如果 JSON 清楚地表明它正在解析正确的类别,为什么我会遇到失败子句?

JSON

{ “编号”:“2b920a5b-0d17-4c5a-9ac1-18071f078464”, “时间戳”:“2017-07-13T20:43:33.307Z”, "lang": "en", “结果”: { “来源”:“代理人”, "resolvedQuery": "告诉我一些关于树懒的科学知识", “行动”:“告诉事实”, “ Action 不完整”:假的, “参数”: { “事实类别”:“科学” }, “上下文”:[ { “名称”:“_actions_on_google_”, “参数”: { "fact-category.original": "科学", “事实类别”:“科学” }, “生命周期”:100 } ], “元数据”:{ “intentId”:“ca4fa7f1-aceb-4867-b7c3-cf16d1ce4d79”, “webhookUsed”:“真”, “webhookForSlotFillingUsed”:“假”, “webhookResponseTime”:195, “intentName”:“告诉事实” }, “履行”:{ "speech": "抱歉,我没听懂。我可以告诉你关于树懒的趣闻或科学知识。你想听哪一个?", “消息”:[ { “类型”:0, "speech": "抱歉,我没听懂。我可以告诉你关于树懒的趣闻或科学知识。你想听哪一个?" } ], ...

索引.js

const App = require('actions-on-google').ApiAiApp;
const functions = require('firebase-functions');
const TELL_FACT = 'tell.fact';

// API.AI parameter names
const CATEGORY_ARGUMENT = 'category';
const FACT_TYPE = {
  FUN: 'fun',
  SCIENCE: 'science'
};
const FUN_FACTS = new Set([...]);
const SCIENCE_FACTS = new Set([...]);

...

exports.factsAboutSloths = functions.https.onRequest((request, response) => {
  const app = new App({ request, response });
  console.log('Request headers: ' + JSON.stringify(request.headers));
  console.log('Request body: ' + JSON.stringify(request.body));

  // Greet the user and direct them to next turn
  function unhandledDeepLinks(app) {
    if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
      app.ask(app.buildRichResponse()
        .addSimpleResponse(`Welcome to Facts about Sloths! I'd really rather not talk about ${app.getRawInput()}.` +
        `Wouldn't you rather talk about Sloths? I can tell you a fun fact or a science fact about sloths.` +
        `Which do you want to hear about?`).addSuggestions(['Fun', 'Science']));
    } else {
      app.ask(`Welcome to Facts about Sloths! I'd really rather not talk about ${app.getRawInput()}.` +
      `Wouldn't you rather talk about Sloths? I can tell you a fun fact or a science fact about sloths.` +
      `Which do you want to hear about?`, NO_INPUTS);
    }
  }

  // Say a fact
  function tellFact(app) {
    let funFacts = app.data.funFacts ? new Set(app.data.funFacts) : FUN_FACTS;
    let scienceFacts = app.data.scienceFacts ? new Set(app.data.scienceFacts) : SCIENCE_FACTS;

    if (funFacts.size === 0 && scienceFacts.size === 0) {
      app.tell('Actually it looks like you heard it all. Thanks for listening!');

      return;
    }

    let factCategory = app.getArgument(CATEGORY_ARGUMENT);

    if (factCategory === FACT_TYPE.FUN) {
      let fact = getRandomFact(funFacts);
      if (fact === null) {
        if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
          let suggestions = ['Science'];

          app.ask(app.buildRichResponse()
            .addSimpleResponse(noFactsLeft(app, factCategory, FACT_TYPE.SCIENCE))
            .addSuggestions(suggestions));
        } else {
          app.ask(noFactsLeft(app, factCategory, FACT_TYPE.SCIENCE), NO_INPUTS);
        }
        return;
      }

      let factPrefix = 'Sure, here\'s a fun fact. ';
      app.data.funFacts = Array.from(funFacts);

      if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
        let image = getRandomImage(SLOTH_IMAGES);
        app.ask(app.buildRichResponse()
          .addSimpleResponse(factPrefix)
          .addBasicCard(app.buildBasicCard(fact)
            .addButton(LINK_OUT_TEXT, WIKI_LINK)
            .setImage(image[0], image[1]))
          .addSimpleResponse(NEXT_FACT_DIRECTIVE)
          .addSuggestions(CONFIRMATION_SUGGESTIONS));
      } else {
        app.ask(factPrefix + fact + NEXT_FACT_DIRECTIVE, NO_INPUTS);
      }
      return;

    } else if (factCategory === FACT_TYPE.SCIENCE) {
      let fact = getRandomFact(scienceFacts);

      if (fact === null) {
        if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
          let suggestions = ['Fun'];

          app.ask(app.buildRichResponse()
            .addSimpleResponse(noFactsLeft(app, factCategory, FACT_TYPE.FUN))
            .addSuggestions(suggestions));
        } else {
          app.ask(noFactsLeft(app, factCategory, FACT_TYPE.FUN), NO_INPUTS);
        }
        return;
      }

      let factPrefix = 'Okay, here\'s a science fact. ';
      app.data.scienceFacts = Array.from(scienceFacts);
      if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
        let image = getRandomImage(SLOTH_IMAGES);
        app.ask(app.buildRichResponse()
          .addSimpleResponse(factPrefix)
          .addBasicCard(app.buildBasicCard(fact)
            .setImage(image[0], image[1])
            .addButton(LINK_OUT_TEXT, WIKI_LINK))
          .addSimpleResponse(NEXT_FACT_DIRECTIVE)
          .addSuggestions(CONFIRMATION_SUGGESTIONS));
      } else {
        app.ask(factPrefix + fact + NEXT_FACT_DIRECTIVE, NO_INPUTS);
      }
      return;

    } else {
      // Conversation repair is handled in API.AI, but this is a safeguard
      if (app.hasSurfaceCapability(app.SurfaceCapabilities.SCREEN_OUTPUT)) {
        app.ask(app.buildRichResponse()
          .addSimpleResponse(`Sorry, I didn't understand. ` +
          `I can tell you fun facts or science facts about sloths. ` +
          `Which one do you want to hear about?`)
          .addSuggestions(['Fun', 'Science']));
      } else {
        app.ask(`Sorry, I didn't understand. ` +
        `I can tell you fun facts or science facts about sloths. ` +
        `Which one do you want to hear about?`, NO_INPUTS);
      }
    }
  }

  // Say they've heard it all about this category
  function noFactsLeft(app, currentCategory, redirectCategory) {
    let parameters = {};

    parameters[CATEGORY_ARGUMENT] = redirectCategory;
    // Replace the outgoing facts context with different parameters
    app.setContext(FACTS_CONTEXT, DEFAULT_LIFESPAN, parameters);
    let response = `Looks like you've heard all there is to know about the ${currentCategory} facts of sloths. ` +
    `I could tell you about its ${redirectCategory} instead. So what would you like to hear about?`;

    return response;
  }

  let actionMap = new Map();
  actionMap.set(UNRECOGNIZED_DEEP_LINK, unhandledDeepLinks);
  actionMap.set(TELL_FACT, tellFact);

  app.handleRequest(actionMap);
});

tell.fact 意图截图

tell.fact intent 1

tell.fact intent 2

最佳答案

啊哈!一个容易被忽视的偷偷摸摸的问题。

在 API.AI 中,您已将参数命名为“事实类别”。

你要求那个参数

 let factCategory = app.getArgument(CATEGORY_ARGUMENT);

并将 CATEGORY_ARGUMENT 定义为

 const CATEGORY_ARGUMENT = 'category';

所以它会陷入错误状态,因为您得到名为“category”的参数未设置,所以 factCategory 最终在每种情况下都未定义。

关于javascript - 谷歌助手的事实应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45090785/

相关文章:

javascript - AJAX 调用中的变量范围

javascript - 仅保存 HTML Canvas 的特定部分

javascript - 函数原型(prototype)对象在另一个实例上被更改

firebase - 使用 Firebase 通过 OAuth2 创建登录名时指定 UserId 格式

speech-recognition - 如何在将单词发送到 dialogflow 之前将单词拼写给 google assistant

javascript - 内容脚本可以设置 HTML 框架内文本框的值吗?使用 Google Chrome 扩展程序

android - 火力地堡 "Failed to convert a value of type java.util.HashMap to int"

firebase 仪表板不显示 admob 收入

python - 如何使用 python 在 Messenger-Dialogflow 聊天机器人中将 Mysql 查询结果作为 Excel 报告发送

node.js - 从上一个意图中获取后续意图中的参数