继续使用客户端或服务器端执行方式进行构建

至此你已经了解了基础知识,现在可以改进和自定义你的 Action 自定义画布你可以选择使用 客户端执行模型 或服务器端执行方式模型。对于 请参阅 启用 Interactive Canvas

如果您选择客户端执行方式模型选项,则可以在 您的 Action:

如果您选择“服务器执行方式模型”选项,则可以在 您的 Action:

有些 Interactive Canvas API 不建议用于 执行模式下表显示了在您选择 客户端执行方式选项,以及这些 API 是推荐使用还是 建议以下做法:

API 名称 服务器执行模型是否支持? 在客户端履单模型中是否支持?
sendTextQuery() 支持但不建议(请参阅 sendtextQuery()
outputTts()
triggerScene()
createIntentHandler(), expect(), clearExpectations(), prompt()
createNumberSlot(),createTextSlot, createConfirmationSlot, createOptionsSlot()
setHomeParam(), getHomeParam(), setUserParam(), getUserParam()

以下部分介绍了如何为客户端和 服务器端执行方式模型。

使用客户端执行方式构建

您可以在 Web 应用逻辑中实现以下 Interactive Canvas API:

outputTts()

借助此 API,您可以从设备输出文字转语音 (TTS),而无需发送 显示来自 Actions Builder 的静态提示或调用 webhook。如果没有服务器端 需要与 TTS 关联的逻辑,您可以使用 outputTts() 从而跳过访问服务器的步骤,以更快的速度响应 。

客户端 outputTts() 可以中断或取消服务器端 TTS。您可以避免 采取以下预防措施来中断服务器端 TTS:

  • 避免在会话开始时调用 outputTts();请在 Action 的第一轮对话中使用服务器端 TTS。
  • 请避免在用户未执行操作的间隙连续调用 outputTts()

以下代码段展示了如何使用 outputTts() 从 客户端:

interactiveCanvas.outputTts(
      '<speak>This is an example response.</speak>', true);

您还可以将 outputTts()onTtsMark() 搭配使用 将 SSML 标记置于文本序列中。使用 onTtsMark() 同步您的网页 SSML TTS 字符串中特定点的应用动画或游戏状态,如下所示 在以下代码段中:

interactiveCanvas.outputTts(
      '<speak>Speak as <mark name="number" /> number <break time="700ms"/>' +
      '<say-as interpret-as="cardinal">12345</say-as> <break time="300ms"/> ' +
      'Speak as <mark name="digits" /> digits <break time="700ms"/>' +
      '<say-as interpret-as="characters">12345</say-as></speak>', true);

在前面的示例中,两个标记 会使用 TTS 发送到 Web 应用。

在客户端上处理 intent 执行方式

在 Interactive Canvas 的服务器执行方式模型中,所有 intent 必须由网络钩子处理,这会增加 Action 的延迟时间。改为 与调用 webhook 一样,您可以在 Web 应用中处理 intent 的执行情况。

如需在客户端处理 intent,您可以使用以下 API:

  • createIntentHandler():一种可用于在 API 中定义 intent 处理程序的方法。 Actions Builder 中定义的自定义 intent 的 Web 应用代码。
  • expect():用于激活/注册 intent 处理程序以便 可以匹配 intent。
  • clearExpectations():此方法可清除所有 当前已激活的意图,因此,即使这些意图 当用户说出与意图匹配的话语。
  • deleteHandler():此方法停用单个 intent 处理程序, 无法匹配这些意图。

借助这些 API,您可以针对不同的 Interactive Canvas Action 的您必须对 intent 使用 expect() 处理程序激活这些意图。

激活 intent 处理程序

激活 intent 处理程序分为两个步骤。首先,您必须定义 在 Actions Builder 中使用 intent。接下来,要使 intent 可匹配,您需要 对 intent 处理程序调用 expect()

如需在客户端配置和激活 intent 处理程序,请按照下列步骤操作: 具体步骤:

  1. 在 Actions 控制台中打开您的项目,然后添加 Custom intent
  2. 针对“这是全局意图吗?”选择

  3. 配置 intent,然后点击 Save

  4. 在 Web 应用逻辑中定义 intent 的处理程序,如以下代码段所示:

    /**
    * Define handler for intent.
    */
    const bookTableIntent = interactiveCanvas.createIntentHandler('reserveTable',
      matchedIntent => {
        console.log("Intent match handler to reserve a table was triggered!");
      });
    
    /**
    * Define handler for intent with an argument.
    */
    const bookTableIntent = interactiveCanvas.createIntentHandler('reserveTable',
      matchedIntent => {
        const numberOfPeople = matchedIntent.getIntentArg('numberOfPeople');
        console.log(`Intent match handler to reserve a table for ${number of people} was triggered!`);
      });
    
  5. 调用 expect() 方法以注册 intent 处理程序,如 以下代码段:

    /**
    * Define handler for intent and expect() it.
    */
    const bookTableIntent = interactiveCanvas.createIntentHandler('reserveTable',
      matchedIntent => {
        console.log("Intent match handler to reserve a table was triggered!");
      });
    var handler = interactiveCanvas.expect(bookTableIntent);
    

停用 intent 处理程序

定义 intent 处理程序后,您可以启用或停用 您的 Action 需要的 intent。当您调用 expect() 以激活 intent 会返回一个包含 deleteHandler() 方法的对象,您可以使用该方法 停用新创建的处理程序。intent 处理程序定义即使 如果 intent 当前未处于活动状态,您可以在以下情况下重新激活 intent: 所需的资源。

如需停用 intent 处理程序,请对 intent 处理程序调用 deleteHandler(), 如以下代码段所示:

    /**
    * Define handler for intent and expect() it.
    */
    const bookTableIntent = interactiveCanvas.createIntentHandler('reserveTable',
      matchedIntent => {
        console.log("Intent match handler to reserve a table was triggered!");
      });
    var handler = interactiveCanvas.expect(bookTableIntent);
    
    // Delete the handler for `bookTableIntent`.
    handler.deleteHandler();
    

您可以调用 expect() 来重新添加已停用的 intent 处理程序,如 以下代码段:

    // Re-add the `bookTableIntent` handler.
    handler = interactiveCanvas.expect(bookTableIntent);

如需批量停用 intent,您可以使用 clearExpectations() 方法, 停用当前激活的所有 intent。以下代码段展示了如何 明确对所有 intent 处理程序的预期:

interactiveCanvas.clearExpectations();

在客户端上处理槽填充

您无需在 Actions Builder 中向场景添加槽位填充,而是可以执行以下操作: 处理槽填充。

如需在客户端处理槽位填充,您必须先使用 以下 API 之一:

  • createNumberSlot(callback, hints):一种可用于定义 数字槽。用于提示用户输入号码。
  • createTextSlot(callback, hints):一种可用于定义文本的方法 插入您的 Web 应用代码中用于提示用户输入字词。
  • createConfirmationSlot(callback, hints):此方法可用于 在您的 Web 应用代码中定义一个确认槽。用于提示用户 进行确认(是/否)。
  • createOptionsSlot(options, callback, hints):此方法可用于 定义一个选项槽位。用于提示用户 从预定义选项列表中进行选择。

创建槽时,您可以选择定义 triggerHints, 可改进自然语言理解 (NLU) 系统的关键字, 行动。这些关键字应该是用户 来填充广告位例如,数字槽的 triggerHints 关键字可以 为 years。当用户在对话中回复了与其年龄相关的问题时 收到“I am thirty years old”的回复,您的 Action 更有可能会 确保用户以恰当的方式填充广告位

创建槽后,您可以使用 prompt API 提示用户获取槽:

  • prompt(tts, slot):此方法将向用户输出 TTS,提示用户填充预期的槽位。

调用 prompt() 会返回一个 promise,其中包含 填充的广告位。

创建数字槽

借助号码槽,您可以在 对话。如需详细了解槽位填充,请参阅 槽填充部分 Actions Builder 文档。

如需在客户端提示用户填充号码位置,请按以下步骤操作:

  1. 调用 createNumberSlot() 方法以在您的网页中创建号码槽 应用逻辑:

    /**
     * Create number slot.
     */
    const triggerHints = { associatedWords: ['guess number', 'number'] };
    const slot = interactiveCanvas.createNumberSlot(
      number => {
        console.log(`Number guessed: ${number}.`);
      }, triggerHints);
    
  2. 调用 prompt() 方法以提示用户进入槽,并处理 所返回的 promise 中的 slot 值,如以下代码段所示:

    const promptPromise = interactiveCanvas.prompt(
      { text: 'What number am I thinking of between 1 and 10?' }, slot);
    
    promptPromise.then(
      answer => {
        if (answer.status == interactiveCanvas.AnswerStatus.ANSWERED) {
          // answer === {value: 5, status: ANSWERED}
          // Do something with answer.value
        } else {
          console.error('Promise returned unsuccessful status ' + answer.status);
        }
      });
    

创建文本槽

通过文本位置,您可以在 对话。如需详细了解槽位填充,请参阅 槽填充部分 Actions Builder 文档。

如需提示用户填充客户端上的文本槽,请按以下步骤操作:

  1. 调用 createTextSlot() 方法,在您的 Web 应用逻辑中创建文本槽:

    /**
     * Create text slot.
     */
    const triggerHints = { associatedWords: ['favorite color', 'color'] };
    const slot = interactiveCanvas.createTextSlot(
      text => {
        console.log(`Favorite color: ${text}.`);
      }, triggerHints);
    
  2. 调用 prompt() 方法以提示用户进入槽,并处理 所返回的 promise 中的 slot 值,如以下代码段所示:

    const promptPromise = interactiveCanvas.prompt(
      { text: 'What is your favorite color?' }, slot);
    
    promptPromise.then(
      answer => {
        if (answer.status == interactiveCanvas.AnswerStatus.ANSWERED) {
          // answer === {value: "red", status: ANSWERED}
          // Do something with answer.value
        } else {
          console.error('Promise returned unsuccessful status ' + answer.status);
        }
      });
    

创建确认槽

利用确认槽,您可以提示用户进行确认(用户可以 回复“是”或“否”以填充广告位)。如需详细了解槽位填充,请参阅 槽填充部分 Actions Builder 文档。

如需提示用户填充客户端的确认槽,请按照下列步骤操作: 具体步骤:

  1. 调用 createConfirmationSlot() 方法在其中创建一个确认槽 您的 Web 应用逻辑:

    /**
     * Create confirmation slot (boolean).
     */
    const triggerHints = { associatedWords: ['user confirmation', 'confirmation'] };
    const slot = interactiveCanvas.createConfirmationSlot(
      yesOrNo => {
        console.log(`Confirmation: ${yesOrNo}`);
      }, triggerHints);
    
  2. 调用 prompt() 方法以提示用户进入槽,并处理 所返回的 promise 中的 slot 值,如以下代码段所示:

    const promptPromise = interactiveCanvas.prompt(
      { text: 'Do you agree to the Terms of Service?' }, slot);
    
    promptPromise.then(
      answer => {
        if (answer.status == interactiveCanvas.AnswerStatus.ANSWERED) {
          // answer === {value: true, status: ANSWERED}
          // Do something with answer.value
        } else {
          console.error('Promise returned unsuccessful status ' + answer.status);
        }
      });
    

创建选项槽

通过选项槽,您可以提示用户 预定义选项如需详细了解槽位填充,请参阅 槽填充部分 Actions Builder 文档。

如需提示用户填充客户端上的选项槽位,请按以下步骤操作:

  1. 调用 createOptionsSlot() 方法,在您的 Web 应用逻辑:

    /**
     * Create options slot (list selection).
     */
    const triggerHints = { associatedWords: ['select fruit', 'choose fruit'] };
    // Define selectable options
    const options = [{
      key: 'apple',
      synonyms: ['apple', 'large apple', 'gala apple'],
    }, {
      key: 'banana',
      synonyms: ['banana', 'green banana', 'plantain'],
    }];
    const slot = interactiveCanvas.createOptionsSlot(
      options,
      selectedOption => {
        console.log(`You have selected ${selectedOption} as your fruit.`);
      }, triggerHints);
    
  2. 调用 prompt() 方法以提示用户进入槽,并处理 所返回的 promise 中的 slot 值,如以下代码段所示:

    const promptPromise = interactiveCanvas.prompt(
      { text: 'Would you like a banana or an apple?' }, slot);
    
    promptPromise.then(
      answer => {
        if (answer.status == interactiveCanvas.AnswerStatus.ANSWERED) {
          // answer === {value: 'apple', status: ANSWERED}
          // Do something with answer.value
        } else {
          console.error('Promise returned unsuccessful status ' + answer.status);
        }
      });
    

triggerScene()

借助 triggerScene() API,您可以过渡到 来自客户端执行方式的 Interactive Canvas Action。包含 triggerScene(),您还可以从客户端执行方式切换到服务器端执行方式 在用户需要访问 Actions Builder 中的系统场景 需要网络钩子的场景例如,当用户执行以下操作时,您可以调用 triggerScene() 需要关联账号或接收通知;您便可从 通过 Canvas 提示将该场景传递给客户端执行方式。

以下代码段展示了如何在 Action 中实现 triggerScene()

interactiveCanvas.triggerScene('SceneName').then((status) => {
  console.log("sent the request to trigger scene.");
}).catch(e => {
  console.log("Failed to trigger a scene.");
})

客户端上的主屏幕和用户存储空间

您无需使用网络钩子来获取和设置住址值和用户存储空间值,而是可以 调用客户端 API 来处理网页应用中的主屏幕和用户存储空间。您的网络 然后应用就可以在多个会话中使用这些存储的值(例如,在 提示和条件),并可以访问特定家庭或 用户。使用这些 API 可以缩短 Interactive Canvas 中的延迟时间 此操作,因为您不再需要调用网络钩子来获取和设置 storage 值。

Web 应用中的主屏幕和用户存储空间遵循与 存储在 webhook 中。如需详细了解家庭存储空间和用户存储空间,请参阅 参阅家庭存储空间文档 和用户存储空间

客户端家庭存储空间

借助家庭存储空间,您可以根据家庭用户的 Home Graph,并在所有虚拟机中共享 家庭会话例如,如果用户播放的是 Interactive Canvas 游戏的得分可以存储在家庭存储空间中,以及 其他家庭成员可以用存储的得分继续玩游戏。

如需让 Action 支持家庭存储空间,请按以下步骤操作:

  1. 在 Actions 控制台中,前往 Deploy >目录信息 > 其他信息
  2. 针对您的 Action 会使用家庭存储空间吗?勾选复选框。

如需将值写入 Web 应用中的家庭存储空间,请调用 setHomeParam() 方法,如以下代码段所示:

interactiveCanvas.setHomeParam('familySize',  10).then(
      result => {
        console.log('Set home param success');
      },
      fail => {
        console.error(err);
      });

如需在 Web 应用中从主存储空间中读取值,请调用 getHomeParam() 方法,如以下代码段所示:

interactiveCanvas.getHomeParam('familySize').then(
      value => {
        console.log(JSON.stringify(result));
      },
      err => {
        console.error(err);
      }
  );

如需清除所有现有的住宅存储空间,请调用 resetHomeParam() 方法,如下所示 在以下代码段中:

interactiveCanvas.resetHomeParam();

客户端用户存储空间

借助用户存储空间,您可以存储经过验证的特定用户的参数值 多个会话中。例如,如果用户正在玩游戏, 即可为该用户存储游戏在随后的游戏会话中,用户 可以继续以相同的得分继续玩游戏。

如需将值写入 Web 应用中的用户存储空间,请调用 setUserParam() 方法,如以下代码段所示:

interactiveCanvas.setUserParam('color',  'blue').then(
      result => {
        console.log('Set user param success');
      },
      err => {
        console.error(err);
      });

如需从 Web 应用的用户存储空间中读取值,请调用 getUserParam() 方法,如以下代码段所示:

interactiveCanvas.getUserParam('color').then(
      value => {
        console.log(JSON.stringify(result));
      },
      err => {
        console.error(err);
      }
  );

如需清除所有现有用户存储空间,请调用 resetUserParam() 方法,如下所示 在以下代码段中:

interactiveCanvas.resetUserParam();

setCanvasState()

借助 setCanvasState() 方法,您可以从 Interactive Canvas Web 应用添加到您的执行方式,并通知 Google 助理该 Web 应用已 已更新其状态。Web 应用会以 JSON 对象的形式发送更新后的状态。

调用 setCanvasState() 不会调用 intent。更新后 调用 setCanvasState()(如果调用了 sendTextQuery() 或用户查询) 与对话中的 intent 匹配,使用 setCanvasState() 设置的数据 这样,在上一轮对话中, 对话。

在以下代码段中,Web 应用使用 setCanvasState() 设置画布状态 数据:

JavaScript

this.action.canvas.setCanvasState({ score: 150 })
    

通过 webhook 引用 Canvas 状态

您可以在执行方式代码中引用存储的 Canvas 状态值。要引用 值,请使用 conv.context.canvas.state.KEY 语法,其中 KEY 是设置画布状态值时指定的键。

例如,如果您之前在 Canvas 中存储了某个游戏的最高得分值, 将状态指定为参数 score,请使用以下代码引用该值: 使用 conv.context.canvas.state.score 访问 fulfillment 中的该值:

Node.js

app.handle('webhook-name', conv => {
    console.log(conv.context.canvas.state.score);
})
    

在提示中引用 Canvas 状态

您可以在提示中引用存储的 Canvas 状态值。要引用 值,请使用 $canvas.state.KEY 语法,其中 KEY 是设置画布状态值时指定的键。

例如,如果您之前在 Canvas 中存储了某个游戏的最高得分值, 将状态指定为参数 score,请使用 $canvas.state.score 引用该值 以在提示中访问该值:

JSON

{
  "candidates": [{
    "first_simple": {
      "variants": [{
        "speech": "Your high score is $canvas.state.score."
      }]
    }
  }]
}
    

条件内的参考画布状态

您还可以在条件中引用存储的 Canvas 状态值。接收者 引用该值,请使用 canvas.state.KEY 语法,其中 KEY 是画布 状态值已设置。

例如,如果您之前在 Canvas 中存储了某个游戏的最高得分值, 状态指定为参数 score,并希望将其与999 条件,您可以使用 canvas.state.score。您的条件表达式如下所示:

条件语法

canvas.state.score >= 999
    

sendTextQuery()

sendTextQuery() 方法将文本查询发送到对话型 Action, 以编程方式匹配意图此示例使用 sendTextQuery() 重启 会在用户点击按钮时旋转三角形的游戏。当用户点击 “重新开始游戏”按钮,sendTextQuery() 会发送一条文本查询, 匹配 Restart game intent 并返回 promise。这个 promise 可生成 如果 intent 被触发,则为 SUCCESS,如果未触发 intent,则为 BLOCKED。以下 代码段与意图匹配,并处理 promise:

JavaScript


/**
* Handle game restarts
*/
async handleRestartGame() {
    console.log(`Request in flight`);
    this.button.texture = this.button.textureButtonDisabled;
    this.sprite.spin = false;
    const res = await this.action.canvas.sendTextQuery('Restart game');
    if (res.toUpperCase() !== 'SUCCESS') {
        console.log(`Request in flight: ${res}`);
        return;
    }
    console.log(`Request in flight: ${res}`);
    this.button.texture = this.button.textureButtonDisabled;
    this.sprite.spin = false;
}

    

如果 promise 导致 SUCCESS,则 Restart game 网络钩子处理程序会发送 Canvas 响应:

JavaScript


app.handle('restart', conv => {
  conv.add(new Canvas({
    data: {
      command: 'RESTART_GAME'
    }
  }));
});

    

Canvas 响应会触发 onUpdate() 回调,该回调会执行 添加到以下代码 RESTART_GAME 代码段中:

JavaScript


RESTART_GAME: (data) => {
    this.scene.button.texture = this.scene.button.textureButton;
    this.scene.sprite.spin = true;
    this.scene.sprite.tint = 0x00FF00; // green
    this.scene.sprite.rotation = 0;
},

    

使用服务器端执行方式进行构建

您可以在网络钩子中实现以下 Interactive Canvas API:

启用全屏模式

默认情况下,Interactive Canvas Web 应用包含一个 header 显示相应操作的名称您可以使用 enableFullScreen 移除标题,并将其替换为 这样用户就可以获得全屏体验 同时与您的 Action 交互。消息框消息显示了 Action 的显示画面 名称、开发者名称、退出操作的说明以及消息框 颜色会根据用户在其设备上选择的主题而变化。

图 1. 加载界面上某个 Action 的消息框消息。

如果用户频繁与您的 Action 互动,则消息框消息会暂时显示 停止在加载屏幕上显示。如果用户不与您的 操作一段时间后,消息框消息会在用户启动该操作后重新出现。

您可以在网络钩子或 Actions Builder。

如需在 webhook 中启用全屏模式,请按以下步骤操作:

  1. 在第一个 canvas 响应中将 enableFullScreen 字段设置为 true 会话返回的值以下代码段是一个示例 使用 Node.js 客户端库实现以下功能:

     const { conversation, Canvas } = require('@assistant/conversation');
     const functions = require('firebase-functions');
    
     const app = conversation();
    
     app.handle('invocation_fullscreen', conv => {
       conv.add(new Canvas(
         {
           url: 'https://example-url.com',
           enableFullScreen: true
         }));
     });
    
     exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
    

如需在 Actions Builder 中的静态提示中启用全屏模式,请按以下步骤操作:

  1. Actions 控制台中打开您的项目。
  2. 点击导航栏中的开发,然后打开包含 第一个 canvas 响应。
  3. enable_full_screen 设置为 true,如以下代码段所示:

     {
      "candidates": [
        {
          "canvas": {
            "url": "https://example-url.com",
            "enable_full_screen": true
          }
        }
      ]
    }
    

continueTtsDuringTouch

默认情况下,当用户在使用 Interactive Canvas 时点按屏幕 操作,TTS 停止播放。您可以启用文字转语音 (TTS) 功能以继续播放 当用户使用 continueTtsDuringTouch 轻触屏幕时触发。此行为不能 可以在同一个会话中开启和关闭。

您可以在网络钩子或静态提示中实现此行为 在 Actions Builder 中运行。

如需使 TTS 在用户点按网络钩子中的屏幕后继续,请按照下列步骤操作: 这一步:

  • 在第一个 canvas 响应中将 continueTtsDuringTouch 字段设置为 true 会话返回的值以下代码段是一个示例 使用 Node.js 客户端库实现以下功能:

    const { conversation, Canvas } = require('@assisant/conversation');
    const functions = require('firebase-functions');
    
    const app = conversation();
    
    app.handle('intent-name', conv => {
      conv.add(new Canvas(
        {
          url: 'https://example-url.com',
          continueTtsDuringTouch: true
        }));
    });
    
    exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
    

为了让 TTS 在用户点按屏幕以进入静态提示后继续 Actions Builder,请按以下步骤操作:

  1. Actions 控制台中打开您的项目。
  2. 点击导航栏中的 开发,然后打开包含 第一个 canvas 响应。
  3. continue_tts_during_touch 设置为 true,如以下代码段所示:

      {
       "candidates": [
         {
           "canvas": {
             "url": "https://example-url.com",
             "continue_tts_during_touch": true
           }
         }
       ]
     }