Webhook

为了让您在构建 Action 时拥有更大的灵活性,您可以将逻辑委托给 HTTPS 网络服务(执行方式)。您的 Action 可以触发向 HTTPS 端点发出请求的网络钩子。以下列举了一些您可以在执行方式中执行的操作:

  • 根据用户提供的信息生成动态提示。
  • 在外部系统中下单并确认成功。
  • 使用后端数据验证槽。
图 1.调用 intent 和场景可以触发 网络钩子。

网络钩子触发器和处理程序

您的 Action 可以在调用 intent 或场景中触发网络钩子,从而向执行方式端点发送请求。执行方式包含用于处理请求中的 JSON 载荷的网络钩子处理程序。您可以在以下情况下触发网络钩子:

  • 调用 intent 匹配后
  • 在场景的“进入”阶段
  • 在场景的“条件”阶段中,条件评估为 true 后
  • 在场景的“槽填充”阶段
  • 在场景的“输入”阶段中,发生 intent 匹配后

当您在 Action 中触发网络钩子时,Google 助理会向执行方式发送一个 请求 包含 JSON 载荷,其中包含用于处理事件的 处理程序的名称。执行方式端点可以将事件路由到相应的处理程序,以执行逻辑并返回包含 JSON 载荷的相应响应。

载荷

以下代码段展示了 Action 发送给执行方式的示例请求,以及执行方式发回的响应。如需了解详情,请参阅 参考文档

示例请求

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "example_session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

示例响应

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello World.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

运行时互动

以下各部分介绍了您可以在网络钩子处理程序中执行的常见任务。

发送提示

您可以创建包含简单文本、富文本、卡片,甚至是包含由 Interactive Canvas 提供支持的 Web 应用 的完整 HTML 提示。提示文档中提供了 有关如何在处理网络钩子事件时创建提示的完整信息。 以下代码段展示了一个卡片提示:

Node.js

app.handle('rich_response', conv => {
  conv.add('This is a card rich response.');
  conv.add(new Card({
    title: 'Card Title',
    subtitle: 'Card Subtitle',
    text: 'Card Content',
    image: new Image({
      url: 'https://developers.google.com/assistant/assistant_96.png',
      alt: 'Google Assistant logo'
    })
  }));
});

响应 JSON

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "content": {
      "card": {
        "title": "Card Title",
        "subtitle": "Card Subtitle",
        "text": "Card Content",
        "image": {
          "alt": "Google Assistant logo",
          "height": 0,
          "url": "https://developers.google.com/assistant/assistant_96.png",
          "width": 0
        }
      }
    },
    "firstSimple": {
      "speech": "This is a card rich response.",
      "text": ""
    }
  }
}

读取 intent 参数

当助理运行时匹配 intent 时,它会提取所有已定义的参数。original 属性是用户提供的输入,而 resolved 属性是 NLU 根据类型规范将输入解析为的内容。

Node.js

conv.intent.params['param_name'].original
conv.intent.params['param_name'].resolved

请求 JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "intent_name",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

读取用户语言区域

此值对应于用户为 Google 助理设置的语言区域。

Node.js

conv.user.locale

JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

读取和写入存储空间

如需全面了解如何 使用各种存储功能,请参阅存储文档。

Node.js

//read
conv.session.params.key
conv.user.params.key
conv.home.params.key

// write
conv.session.params.key = value
conv.user.params.key = value
conv.home.params.key = value 

请求 JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    },
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

响应 JSON

{
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello world.",
      "text": ""
    }
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  }
}

检查设备功能

您可以检查设备的功能,以提供不同的体验或对话流程。

Node.js

const supportsRichResponse = conv.device.capabilities.includes("RICH_RESPONSE");
const supportsLongFormAudio = conv.device.capabilities.includes("LONG_FORM_AUDIO");
const supportsSpeech = conv.device.capabilities.includes("SPEECH");
const supportsInteractiveCanvas = conv.device.capabilities.includes("INTERACTIVE_CANVAS");

请求 JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO",
      "INTERACTIVE_CANVAS"
    ]
  }
}

如需查看界面功能的完整列表,请参阅 Capability 参考文档。

运行时类型替换

借助运行时类型,您可以在运行时修改类型规范。您可以使用此功能从其他来源加载数据,以填充类型的有效值。例如,您可以使用运行时类型替换向调查问题添加动态选项,或向菜单添加每日项。

如需使用运行时类型,您可以从 Action 触发网络钩子,以调用执行方式中的处理程序。然后,您可以在发回给 Action 的响应中填充 session.typeOverrides 参数。可用模式包括 TYPE_MERGE(用于保留现有类型条目)或 TYPE_REPLACE(用于将现有条目替换为替换项)。

Node.js

conv.session.typeOverrides = [{
    name: type_name,
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item']
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item']
       },
       {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item']
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item']
        },
    ]
  }
}];

响应 JSON

{
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [
      {
        "name": "type_name",
        "synonym": {
          "entries": [
            {
              "name": "ITEM_1",
              "synonyms": [
                "Item 1",
                "First item"
              ]
            },
            {
              "name": "ITEM_2",
              "synonyms": [
                "Item 2",
                "Second item"
              ]
            },
            {
              "name": "ITEM_3",
              "synonyms": [
                "Item 3",
                "Third item"
              ]
            },
            {
              "name": "ITEM_4",
              "synonyms": [
                "Item 4",
                "Fourth item"
              ]
            }
          ]
        },
        "typeOverrideMode": "TYPE_REPLACE"
      }
    ]
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  }
}

提供语音偏向

借助语音偏向,您可以为 NLU 指定提示,以改进 intent 匹配。您最多可以指定 1000 个条目。

Node.js

conv.expected.speech = ['value_1', 'value_2']
conv.expected.language = 'locale_string'

响应 JSON

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  },
  "expected": {
    "speech": "['value_1', 'value_2']",
    "language": "locale_string"
  }
}

转场

除了在 Actions 项目中定义静态转换之外,您还可以让场景转换在运行时发生。

Node.js

app.handle('transition_to_hidden_scene', conv => {
  // Dynamic transition
  conv.scene.next.name = "HiddenScene";
});

响应 JSON

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "HiddenScene"
    }
  }
}

读取场景槽

在槽填充期间,您可以使用执行方式来验证槽或检查 槽填充的状态 (SlotFillingStatus)。

Node.js

conv.scene.slotFillingStatus  // FINAL means all slots are filled
conv.scene.slots  // Object that contains all the slots
conv.scene.slots['slot_name'].<property_name> // Accessing a specific slot's properties

例如,假设您要从响应中提取时区。在此示例中,槽名称为 datetime1。如需获取时区,您可以使用:

conv.scene.slots['datetime1'].value.time_zone.id

请求 JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "FINAL",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "SLOT_UNSPECIFIED",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    },
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

使场景槽失效

您可以使槽失效,并让用户提供新值。

Node.js

conv.scene.slots['slot_name'].status = 'INVALID'

响应 JSON

{
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "INVALID",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

开发选项

Actions Builder 提供了一个名为 Cloud Functions 编辑器 的内嵌编辑器, 借助该编辑器,您可以直接在 控制台中构建和部署 Cloud Functions for Firebase。您还可以构建执行方式并将其部署到您选择的托管服务,并将 HTTPS 执行方式端点注册为网络钩子处理程序。

内嵌编辑器

如需使用 Cloud Functions 编辑器进行开发,请执行以下操作:

  1. 打开您的 Actions 项目,然后依次前往“Develop”标签页 >“Webhook”>“Change fulfillment method” 。此时将显示执行方式方法 窗口。
  2. 选择 Inline Cloud Functions ,然后点击 Confirm

外部 HTTPS 端点

本部分介绍如何将 Cloud Functions for Firebase 设置为对话 Action 的执行方式服务。不过,您可以将执行方式部署到您选择的托管服务。

设置环境

如需设置您的环境,请按以下步骤操作:

  1. 下载并安装 Node.js
  2. 设置并初始化 Firebase CLI。如果以下命令失败并显示 一个 EACCES 错误,您可能需要更改 npm 权限

    npm install -g firebase-tools
    
  3. 使用您的 Google 账号对 firebase 工具进行身份验证:

    firebase login
    
  4. 启动您保存 Actions 项目的项目目录。 系统会要求您选择要为 Actions 项目设置的 Firebase CLI 功能。选择 Functions 和您可能想要使用的其他功能(例如 Firestore),然后按 Enter 键确认并继续:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. 将 Firebase 工具与您的 Actions 项目相关联,方法是使用箭头键在项目列表中选择该项目:

  6. 选择项目后,Firebase 工具会启动 Functions 设置,并询问您要使用的语言。使用箭头键进行选择,然后按 Enter 键继续。

    === Functions Setup
    A functions directory will be created in your project with a Node.js
    package pre-configured. Functions can be deployed with firebase deploy.
    
    ? What language would you like to use to write Cloud Functions? (Use arrow keys)
    > JavaScript
    TypeScript
    
  7. 选择是否要使用 ESLint 捕获可能出现的 bug 并强制执行样式,方法是输入 YN

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. 输入 Y 以获取项目依赖项:

    ? Do you want to install dependencies with npm now? (Y/n)

    设置完成后,您将看到类似于以下内容的输出:

    ✔  Firebase initialization complete!
    
  9. 安装 @assistant/conversation 依赖项:

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. 获取执行方式依赖项并部署执行方式函数:

    $ npm install
    $ firebase deploy --only functions
    

    部署需要几分钟时间。完成后,您将看到类似于以下内容的输出。您需要 Function 网址 才能在 Dialogflow 中输入。

    ✔  Deploy complete!
    Project Console: https://console.firebase.google.com/project/<PROJECT_ID>/overview Function URL (<FUNCTION_NAME>): https://us-central1-<PROJECT_ID>.cloudfunctions.net/<FUNCTION_NAME>
  11. 复制执行方式网址,以便在下一部分中使用。

注册网络钩子处理程序

如需将 Cloud Functions 端点注册为网络钩子处理程序,请执行以下操作:

  1. 在 Actions 控制台中,依次点击 Develop > Webhook
  2. 点击 Change fulfillment method 。此时将显示执行方式方法 窗口。
  3. 选择 Webhook ,然后点击 Confirm
  4. 将您的网络服务网址粘贴到 Webhook 字段中。
  5. 点击保存