Google行动:意图相似吗? [英] Actions-on-Google: Similar intents?

查看:80
本文介绍了Google行动:意图相似吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过DialogFlow + Firebase修补Google上的操作。想法是为默认AoG不应使用的IoT设备进行自定义构建。

I'm tinkering with Actions on Google with DialogFlow + Firebase. The idea is to custom build for IoT devices not supposed by the default AoG.

对于广播和电视,目前有2种意图:

In the case of Radio and TV, there are 2 intents currently:

1)频道:它接受3个参数:device_name(自定义实体),device_action(自定义实体)和值。

1) Channel : It take in 3 parameters: device_name (custom entity), device_action (custom entity) and value.

例如:请将广播频道更改为22.3

或将电视频道更改为22

Eg: please change the radio channel to 22.3
OR change the channel of the tv to 22

2)音量:它包含3个参数:device_name (自定义实体),device_action(自定义实体)和值。

2) Volume : It take in 3 parameters: device_name (custom entity), device_action (custom entity) and value.

例如:请将广播音量更改为99
或将电视音量更改为22

Eg: please change the radio volume to 99 OR change the vol of the tv to 22

问题是代理似乎无法区分两者。

The problem is that the agent does not seem to be able to differentiate between the two well.

//编辑2018年5月9日:

// Edit 9 May 2018:

index.js

// Copyright 2016, 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.

'use strict';

const util = require('util');
const functions = require('firebase-functions');
const {
  dialogflow,
  Suggestions,
  BasicCard,
  Button,
  SimpleResponse,
} = require('actions-on-google');

const {values, concat, random, randomPop} = require('./util');
const responses = require('./responses');

/** Dialogflow Contexts {@link https://dialogflow.com/docs/contexts} */
const AppContexts = {
  FACT: 'choose_fact-followup',
  CATS: 'choose_cats-followup',
  XXX: 'choose_xxx-followup',

};

/** Dialogflow Context Lifespans {@link https://dialogflow.com/docs/contexts#lifespan} */
const Lifespans = {
  DEFAULT: 5,
};

const app = dialogflow({
  debug: true,
  init: () => ({
    data: {
      // Convert array of facts to map
      facts: responses.categories.reduce((o, c) => {
        o[c.category] = c.facts.slice();
        return o;
      }, {}),
      cats: responses.cats.facts.slice(), // copy cat facts
    },
  }),
});

/**
 * Greet the user and direct them to next turn
 * @param {DialogflowConversation} conv DialogflowConversation instance
 * @return {void}
 */
app.intent('Unrecognized Deep Link Fallback', (conv) => {
  const response = util.format(responses.general.unhandled, conv.query);
  const suggestions = responses.categories.map((c) => c.suggestion);
  conv.ask(response, new Suggestions(suggestions));
});

// redirect to the intent handler for tell_fact
app.intent('choose_fact', 'tell_fact');

// Say a fact
app.intent('tell_fact', (conv, {category}) => {
  const {facts, cats, xxx} = conv.data;
  if (values(facts).every((c) => !c.length)) {
    // If every fact category facts stored in conv.data is empty,
    // close the conversation
    return conv.close(responses.general.heardItAll);
  }
  const categoryResponse =
    responses.categories.find((c) => c.category === category);
  const fact = randomPop(facts[categoryResponse.category]);
  if (!fact) {
    const otherCategory =
      responses.categories.find((other) => other !== categoryResponse);
    const redirect = otherCategory.category;
    const parameters = {
      category: redirect,
    };
    // Add facts context to outgoing context list
    conv.contexts.set(AppContexts.FACT, Lifespans.DEFAULT, parameters);
    const response = [
      util.format(responses.transitions.content.heardItAll, category, redirect),
    ];
    // If cat facts not loaded or there still are cat facts left
    if (cats.length) {
      response.push(responses.transitions.content.alsoCats);
    }
    response.push(responses.general.wantWhat);
    conv.ask(concat(...response));
    conv.ask(new Suggestions(otherCategory.suggestion));
    if (cats.length) {
      conv.ask(new Suggestions(responses.cats.suggestion));
    }
    return;
  }
  const {factPrefix} = categoryResponse;
  // conv.ask can be called multiple times to have the library construct
  // a single response itself the response will get sent at the end of
  // the function or if the function returns a promise, after the promise
  // is resolved.
  conv.ask(new SimpleResponse({
    speech: concat(factPrefix, fact),
    text: factPrefix,
  }));
  conv.ask(responses.general.nextFact);
  conv.ask(new BasicCard({
    title: fact,
    image: random(responses.content.images),
    buttons: new Button({
      title: responses.general.linkOut,
      url: responses.content.link,
    }),
  }));
  console.log('hiwwxxxxxww thi is aaron');
  conv.ask(responses.general.suggestions.confirmation);
});

// Redirect to the intent handler for tell_cat_fact
app.intent('choose_cats', 'tell_cat_fact');

// Say a cat fact
app.intent('tell_cat_fact', (conv) => {
  const {cats} = conv.data;
  console.log('this is cats data' + {cats});
  const fact = randomPop(cats);
  if (!fact) {
    conv.contexts.delete(AppContexts.FACT);
    conv.contexts.delete(AppContexts.CATS);
    conv.ask(responses.transitions.cats.heardItAll);
    return conv.ask(responses.general.suggestions.confirmation);
  }
  const {factPrefix, audio} = responses.cats;
  // conv.ask can be called multiple times to have the library construct
  // a single response itself. The response will get sent at the end of
  // the function or if the function returns a promise, after the promise
  // is resolved.
  const sound = util.format(audio, random(responses.cats.sounds));
  conv.ask(new SimpleResponse({
    // <speak></speak> is needed here since factPrefix is a SSML string
    // and contains audio.
    speech: `<speak>${concat(factPrefix, sound, fact)}</speak>`,
    text: factPrefix,
  }));
  conv.ask(responses.general.nextFact);
  conv.ask(new BasicCard({
    title: fact,
    image: random(responses.cats.images),
    buttons: new Button({
      title: responses.general.linkOut,
      url: responses.cats.link,
    }),
  }));
  console.log('hiwwxxxxxww thi is aaron');
  conv.ask(responses.general.suggestions.confirmation);
});



//say a tv channel
app.intent('volume', (conv, {device_name,device_action, value}) => {

  var no_device_name = device_name;
  var no_value = value;
  var no_device_action = device_action;

  var this_device_value = util.inspect(value, false, null);
  var this_device_name = util.inspect(device_name, false, null);
  var this_device_action = util.inspect(device_action, false, null);
  console.log(this_device_action[0]);

  if (no_device_name[0] == 'channel'){
    console.log('inside tv but CHANNEL');



  }

  else{
    console.log('VOLUME');
  }
  console.log('THIS IS VOL');
  console.log(no_device_action[0]);
   conv.ask(`Alright, ${device_name} VOLUM is now ${value}! `);
  console.log('inside volume ' + value[0]);
  console.log('inside volume' + device_name[0]);
  console.log('inside volume' + device_action[0]);
  console.log('hiwwxxxxxww thi is aaron');


});

//say a tv channel
app.intent('channel', (conv, {device_channel_name, device_channel_action, channel_value}) => {


  console.log('THIS IS CHANNEL');



  conv.ask(`Alright, ${device_channel_name} CHANNEL is now ${channel_value}! `);
  console.log('inside CHANNEL ' + channel_value[0]);
  console.log('inside CHANNEL' + device_channel_name[0]);
  console.log('inside CHANNEL' + device_channel_action[0]);
  console.log('hiwwxxxxxww thi is aaron');


});



app.intent('no_input', (conv) => {
  const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
  if (repromptCount === 0) {
    conv.ask(`What was that?`);
  } else if (repromptCount === 1) {
    conv.ask(`Sorry I didn't catch that. Could you repeat yourself?`);
  } else if (conv.arguments.get('IS_FINAL_REPROMPT')) {
    conv.close(`Okay let's try this again later.`);
  }
});



// The entry point to handle a http request
exports.factsAboutGoogle = functions.https.onRequest(app);

推荐答案

如果您有一个示例短语,该短语的一部分设置为代表参数,则该短语的该部分可以采用参数定义为的 any 值。

If you have a sample phrase with a part of that phrase set to represent a parameter, that part of the phrase can take on any value the parameter is defined to be. The "resolved value" column just shows what it has resolved to in your sample phrase.

因此,在您的频道意图中,短语 tv channel to 3可以也将 radio volume to 4匹配,因为 tv和 radio都是 device_name 实体,而 channel和 volume都是 device_action 实体。

So in your "channel" Intent, the phrase "tv channel to 3" can also match "radio volume to 4" since "tv" and "radio" are both of the device_name entity, and "channel" and "volume" are both of the device_action entity.

您有一些解决方案:


  1. 您可以将它们转换为一个接受所有短语的Intent,并在您的Webhook中检查 device_action 的值以查看应执行的操作。

  1. You can turn them into one Intent that accepts all the phrases and in your webhook check the value of device_action to see what you should do.

您可以将它们保留为单独的Intent,并完全删除 device_action 参数。您不需要它们。只需在各种示例短语中使用同义词,即可使学习系统了解哪些同义词与哪种Intent配合使用。

You can keep them as separate Intents and remove the device_action parameter completely. You don't need them. Just use the synonyms in various sample phrases so the learning system gets trained about which synonyms work with which Intent.

如果您仍然担心同义词,或者

If you are still worried about synonyms, or if it makes sense still, make them different Entity types.

例如,您可能希望将 channel和 preset作为同一实体类型下的不同实体。您在乎差异,因为差异会改变您处理号码的方式,但您仍在更改频道。 音量将是一个不同的实体,因为它代表的是完全不同的东西。

For example, you may want to have "channel" and "preset" as different entities under the same Entity type. You care about the difference because it changes how you treat the number, but you're still changing the channel. "Volume" would be a different entity, since it represents something completely different.

在您的评论中,您询问了设备的个性化别名。您并没有询问多个具有不同名称的设备类型(因此,您希望使用相同的Intent处理 tv1和 tv2,但是能够检测出差异。这两种选项都可以通过选项(3 ),但方式略有不同。

In your comments, you asked about personalized aliases for devices. You didn't ask about more than one device type with different names (so you want to handle "tv1" and "tv2" with the same Intent, but be able to detect the difference. Both of these are handled best with option (3) above, but in slightly different ways.

如果您想要多个电视,则每个电视都应具有相同的实体类型(例如,设备电视),但每个实体的值都不同。

If you want more than one "tv", each of those would be of the same Entity Type (for example, "device tv"), but each one would be a different entity value. It might look something like this:

但是等等!我听到你说:如果用户有三台电视或九台电视该怎么办?我必须全部设置这些电视吗?如果他们想要称一个为卧室电视,另一个为 den电视?

"But wait!" I hear you saying "What if the user has three tvs? Or nine? Do I have to set all of these up? And what if they want to call one the 'bedroom tv' and another the 'den tv'?"

这表明您应将电视的数量及其别名保留在某种数据库中(无论如何,您都需要这样做-您可能需要将其电视映射到某个唯一的设备ID才能真正打开它们),并且当用户与您的代理进行对话时,请使用用户实体

That suggests that you would keep the number of TVs and their aliases in a database of some sort (which you need to do anyway - you probably need to map their TV into some unique device ID to actually turn them on) and, when the user talks to your agent, update this with a User Entity.

用户实体仅为该用户设置了特定于用户的名称和别名。当用户首次与您的代理进行对话时,您将使用Dialogflow API进行设置。如果您使用的是V1,则将使用 / userEntities 端点。如果您使用的是V2,则将使用 projects.agent.sessions.entityTypes 资源。

User Entities have user-specific names and aliases set for just that user. You'll set them using the Dialogflow API when the user first talks to your agent. If you're using V1, you'll use the /userEntities endpoint. If you're using V2, you'll use the projects.agent.sessions.entityTypes resource.

这篇关于Google行动:意图相似吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆