Alexa,运行这个 JavaScript 应用程序

发布日期:2026-07-13 10:22:05   来源 : 杭州电子商务研究院    浏览量 :14
杭州电子商务研究院 发布日期:2026-07-13 10:22:05  
14

概括

因此,有两种类型的 Alexa 技能教程,一种有大量屏幕截图,向您展示如何创建 AWS lambda 函数、配置技能和部署一些任意代码……另一种向您展示如何开发技能、测试技能、部署技能并获得认证。前一类教程太多了(我推荐这个这个),所以我选择后者。

您将看到的许多 Alexa 代码示例将非常专注于快速设置某些意图,这是可以理解的。本文将重点介绍如何组合一个强大的应用程序,您可以放心地扩展复杂性。它将是模块化的,使用 TDD,经过 linted,具有 CI 管道和使用Gulp 的简单部署步骤。

一般情况下,我会假设您对 Alexa 技能有初步了解,如果没有,请先阅读这两个链接,然后再回来...拜托。哦,是的,这也与 JavaScript 有关(如果您对 Python 情有独钟的话)。

当前形势

开始使用 Alexa 进行开发时,您可能会觉得很难,这是可以理解的。虽然有大量的文档……但几乎没有关于如何真正构建技能的内容。如果您像我一样,您会一直绕圈子,最终来到这里试图了解技能套件是什么……而实际上它只是一个大的总称。然后您可能会找到他们的节点套件,或者至少您认为是他们的 Node SDK,但实际上不是……尽管它仍在积极维护。当您查看示例时,您会注意到一些您认为随着 ES2015 而消失的代码,如果您使用框架,可能已经好几年没有写过了:

      Fact.prototype = Object.create(AlexaSkill.prototype);
Fact.prototype.constructor = Fact;
    

...但是帮助就在眼前,因为你偶然发现了这个家伙,你会想,啊,太酷了,这个 API 好一点,然后开始尝试用它编写你的技能......尽管你仍然不完全确定如何去做,而且它也不完全像亚马逊官方的。

但是,有一个新的 SDK 发布了(你很难在网站上找到它,所以 repo 在这里)。这就是我们将在以下教程中使用的工具。

10 份入门套餐

我根据自己创建算术技能的经验创建了一个入门套件,请点击此处。最好使用教程和入门套件的分屏模式阅读本节。

结构

所有技能都将代码分为src语音资产- 我们不要逆潮流而行。除此之外,我还将徽标(在商店上线时需要)和我的circleci配置粘贴在这里。您可以使用任何 CI,但正如您从我的 CI 中看到的那样,您需要指定所有代码都在嵌套的src目录中,并且因为我们是使用 ES2015 编写测试的受虐狂,所以我们需要 Node 6.xx

言语资产

意图-schema.json

一个配置,基本上向 Alexa 解释了她应该期待的“人们说的话”(意图)以及插槽的类型(意图中的变量)。这将帮助她更轻松地弄清楚如何解释用户所说的话。

话语

完全令人费解的野兽试图驯服英语。这基本上是另一只援助之手,让 Alexa 有机会解读用户所说的话。如果他们说了这件事,他们的意思就是这样。花括号中的单词代表插槽,其类型在隔壁的 json 模式中定义。小心单词意图,对于 Arithlistic,我使用“pass”,当你期望它只在有人说“pass”时触发时,它会通过随机单词触发得有点太多了……

源码

在特殊src中您可以施展自己的技能。

在顶层

我们实际上拥有了开发资产和装置。您可能可以将它们拆分到自己的目录中,但感觉有点过头了。所以我们有:

  • 由于我们将要使用的 SDK,eslint 配置必须相当宽松
  • 你的秘密deploy.env.json(显然你会自己创建)看起来有点像这样:
      {
  "ROLE": "arn:aws:iam::[123456789012]:role/[the AWS lambda role you defined]",
  "ACCESS_KEY_ID": "ABCDEFGHIJKLMNOPQRST",
  "SECRET_ACCESS_KEY": "abcdefghijklmnopqrst/abcdefghijklmnopqrs"
}
    

这使我们能够使用 gulp 任务部署代码

  • enums.js帮助我们管理技能的状态,只是为了在 JavaScript 领域给我们一些类型安全的感觉
  • 一个gulpfile.js,详细说明了我们的部署任务。它删除了旧的dist内容,抓取了我们关心的所有内容并将其放入dist中,然后将其压缩,因为这是 AWS lambda 接收多个文件的方式,并使用node-aws-lambda使用 lambda-config 上传我们的文件,该lambda-config的值已替换为我们上面的秘密值
  • index.js - 我们的技能入口 - 它设置环境路径以帮助我们的 AWS lambda 遍历我们的文件,注册我们的appId处理程序(我们将介绍)并启动整个过程
  • lambda -config.js看起来和你的AWS lambda 控制台中的屏幕非常相似。根据需要设置这些值
  • package.json - 我假设您知道。唯一需要注意的是脚本:
  • 找到一个部署 Alexa 技能的好方法有点麻烦,这不是部署工作流程。我找到了这两个示例(Rick 的Thoughtworks 的),我从中大量借鉴了它们,用于我自己的gulpfile。然而,它们都喜欢PROD安装,而我采用了一种略有不同的方法,以避免每次部署时都进行安装。当你为你的技能执行 npm i时,它会将PROD依赖项直接粘贴到dist中
  • 我还在其中加入了iron-node,虽然我对它的使用体验褒贬不一,但当你想在 Chrome 的开发工具中轻松调试某些东西时,它实际上非常有用。不过,请随意以你喜欢的方式调试你的节点代码,例如通过你的 IDE
  • responses.js应该是你放置 Alexa 所说的任何内容的地方。我会将它们作为函数来使用一致的 API,以便你可以传递要动态构建的值。事实上,我重构了这些函数来调用 emit 方法,以便存储最后已知的响应和状态,帮助我们在“暂停”后继续。将所有响应放在一个地方可以使测试更容易(因为你可以在不破坏测试的情况下更改短语),当 i18n 出现时,你可以交换这个文件,而不是让硬编码的文本散落在你的代码库中

处理程序

这些人负责接收意图(Alexa 根据您的语音资产认为用户所说的内容)、执行某种业务逻辑、可能在会话状态(或 dynamo db)中存储一些内容并返回响应(Alexa 要回复的内容)。

状态内容是必需的,因为该技能非常愚蠢,它会接收一些 JSON,然后发送一些 JSON。正是由于这种纯粹的性质,TDD(以及一般的测试)才如此简单。当我们稍后看到事件示例时,将看到该 JSON 的样子。最好让您的处理程序尽可能精简,并将业务逻辑移到模块文件夹中。

我采用了一种相当严格的方法来注释每个处理程序的意图,以确保它在编辑时遵循相同的模式。模式是,设置、状态更改、响应。作为函数式编程教会的一员,最好在意图中获取一个不可变的模型,执行你的逻辑,更新它,然后将其与你的响应一起返回。然而,SDK 采用了更面向对象的方法,大量使用来触发事件和管理状态……这并不理想,并导致了一些不稳定的解决方法。

我建议尽可能多地管理小型处理程序,这将使处理“是”和“否”等模糊意图变得更加容易,并有助于组织代码和测试。

在入门套件中我们只有三个处理程序:

  • core.handlers.js - 我们最后会谈到“认证”,但现在你只需要知道这些是必需的,所以我们会将它们混合到我们所有其他处理程序中。AMAZON.StopIntent基本上是暂停,AMAZON.CancelIntent我离开这里”。SessionEndedRequest只是为了记录目的而准备的
  • new-session.handlers.js - 这是技能入口点(与代码入口点index.js相反),我们将在这里设置一些状态(决定要转到哪个处理程序)并告诉我们的技能要运行哪个意图。还有随机的“catch-all”,它将注销一些真正无用的东西……
  • checked.handlers.js - 因为StopIntentCancelIntent通常是必需的,理想情况下,我们希望有一个地方来管理“暂停”。在这里,如果用户希望继续,我们将状态设置回之前的状态;如果他们不想继续,则退出

模块

这是您的业务逻辑应该存在的地方。如上所述,所有繁重的工作都应该在这里进行。我们不希望意图变得太忙太脏,因为这会使它难以阅读和维护。我在utils模块中包含了一个小型的简单 mixin 实现,这样我们就不需要一遍又一遍地添加核心意图了。

测试

所有示例均未经过测试。我认为,不经过测试,您无法真正开发和发布 Alexa 技能。有如此多的路径、分支和意图,只要您在技能中增加一点点复杂性,就会出现错误。

在测试文件夹中,我们拥有称为事件样本的装置和一个巨大的测试文件。现在,您可能可以将其拆分,但感觉像是“预优化”。我非常喜欢将所有技能测试路径放在一起。

因此我们在顶部有一些助手:

  • 如果您使用了多行模板字符串并想在语音输出上进行断言,那么清理只是为了让生活更轻松
  • getOutputSpeech只是对响应进行解构,剥离所有内容(ssml 标签),并允许我们断言我们关心的内容,即 Alexa 说了什么
  • getAttribute也是一个很好的抽象,可以挑选出我们要测试的会话属性
  • 最后,但绝非最不重要的一点是runIntent ,它将使您的所有测试都成为梦想。它使用aws-lambda-mock-context来消除我们并不真正关心的所有上下文内容,并为我们提供流畅的 API 来轻松调用我们的意图

我采用了一种嵌套很深的方法,这样当你阅读输出时,它就会给人一种对话的感觉。因此,每个描述都是用户会说的话,然后测试名称是你认为你的技能应该做的事情。正如你所见,我们现在可以很好地解构并以相当干净的方式断言。此外,使用粗箭头意味着每个括号更少,这是获胜的关键。

我会根据处理程序状态拆分</font

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据