如何为 Alexa Skills Kit 和 API.AI 使用单个 AWS Lambda?

Posted

技术标签:

【中文标题】如何为 Alexa Skills Kit 和 API.AI 使用单个 AWS Lambda?【英文标题】:How to use a single AWS Lambda for both Alexa Skills Kit and API.AI? 【发布时间】:2018-01-05 05:30:59 【问题描述】:

过去,我设置了两个用 Java 编写的独立 AWS lambda。一种用于 Alexa,一种用于 Api.ai。他们只是将“Hello world”返回给每个助手 api。因此,尽管它们很简单,但它们可以工作。随着我开始为每个代码编写越来越多的代码,我开始看到我的 java 代码有多么相似,我只是通过使用两个单独的 lambdas 来重复自己。

快进到今天。

我现在正在做的是拥有一个单个 AWS lambda,它可以处理来自两个 Alexa 和Api.ai 的输入,但我遇到了一些麻烦。目前,我的想法是,当 lambda 运行时,会有一个简单的 if 语句,如下所示:

以下不是真正的代码,只是我认为我能做的事

if (figureOutIfInputType.equals("alexa"))
runAlexaCode();
 else if (figureOutIfInputType.equals("api.ai"))
runApiAiCode();

现在我需要以某种方式判断该函数是由 alexa 还是 api.ai 调用的。

这是我现在真正的 java:

public class App implements RequestHandler<Object, String> 

  @Override
  public String handleRequest(Object input, Context context) 
    System.out.println("myLog: " + input.toString());

      return "Hello from AWS";
  

然后我从 Alexa 和 Api.ai 运行 lambda,以查看在 java 中会生成什么对象输入。

API.ai

id=asdf-6801-4a9b-a7cd-asdffdsa, timestamp=2017-07-
28T02:21:15.337Z, lang=en, result=source=agent, resolvedQuery=hi how 
are you, action=, actionIncomplete=false, parameters=, contexts=[], 
metadata=intentId=asdf-3a2a-49b6-8a45-97e97243b1d7, 
webhookUsed=true, webhookForSlotFillingUsed=false, 
webhookResponseTime=182, intentName=myIntent, fulfillment=
messages=[type=0, speech=I have failed], score=1, status=
code=200, errorType=success, sessionId=asdf-a7ac-43c8-8ae8-
bc1bf5ecaad0

Alexa

version=1.0, session=new=true, sessionId=amzn1.echo-api.session.asdf-
7e03-4c35-9d98-d416eefc5b23, application=    
applicationId=amzn1.ask.skill.asdf-a02e-4938-a747-109ea09539aa, user=        
userId=amzn1.ask.account.asdf, context=AudioPlayer=
playerActivity=IDLE, System=application=
applicationId=amzn1.ask.skill.07c854eb-a02e-4938-a747-109ea09539aa, 
user=userId=amzn1.ask.account.asdf, device=
deviceId=amzn1.ask.device.asdf, supportedInterfaces=AudioPlayer=, 
apiEndpoint=https://api.amazonalexa.com, request=type=IntentRequest, 
requestId=amzn1.echo-api.request.asdf-5de5-4930-8f04-9acf2130e6b8, 
timestamp=2017-07-28T05:07:30Z, locale=en-US, intent=
name=HelloWorldIntent, confirmationStatus=NONE

所以现在我有我的 Alexa 和 Api.ai 输出,它们是不同的。所以这很好。我将能够分辨出哪个是哪个。但我被困住了。我不确定是否应该尝试创建一个 AlexaInput 对象和一个 ApiAIinput 对象。

我做错了吗?试图让一个 lambda 满足来自多个服务(Alexa 和 ApiAI)的“助手”请求,我错了吗?

任何帮助将不胜感激。当然,其他人一定是在 AWS 中编写他们的助手功能,并希望在两个“助手”平台上重用他们的代码。

【问题讨论】:

【参考方案1】:

我有同样的问题和同样的想法,但随着我越来越深入地实施,我意识到它不太实用,主要原因有一个:

虽然我的很多逻辑都需要相同,但结果的格式却不同。有时,甚至结果的细节或格式也会有所不同。

我所做的是通过将其分为两部分来回到 Web 编程中熟悉的一些概念:

    一个后端系统,负责获取参数并应用业务逻辑来产生结果。这些结果将是相当低级的,不是整个短语,而是一组键/值对,指示要给出什么样的结果以及该结果需要什么值。

    一个前端系统,负责处理特定于 Alexa/Assistant 的事情。所以它会接受请求,提取参数和状态,用这个信息调用后端系统,得到一个结果,其中包括要发送什么样的回复和需要的值,然后格式化确切的短语(以及任何其他支持信息,例如卡片或其他)并将其放入格式正确的响应中。

对于每种代理类型,前端组件将是不同的 lambda 函数,主要是为了使逻辑更简洁。后端组件可以是库函数或另一个 lambda 函数,只要对任务最有意义,但独立于前端实现。

我想人们也可以通过拥有一个实现后端逻辑的抽象父类并将前端逻辑作为它的子类来实现这一点。我不会这样做,因为它没有在两者之间提供清晰的接口边界,但它并非不合理。

【讨论】:

那么您是否将 AWS (java) 用于 alexa 和 api.ai?在这一点上,我可以使用两个独立的代码库以及我可能会创建的共享库,但我不知道如何实际解析/获取输入。 也许我误解了你的问题。您是否想弄清楚如何解析request 参数并针对这两种情况区别对待? 我认为您正确回答了我最初的问题,但此时我主要是进行了跟进。我不确定如何读取 api.ai 的结果。我从 api.ai 获得的输出(如上所示)只是通过对传入的“对象”类型调用 toString() 来实现。传入的只是Json吗?如果是这样,我该如何得到它,以便我可以打电话给if (input.lang.equals("en")) 虽然这听起来像是“后续行动”,但我建议在 *** 中将其作为一个单独的问题提出并发布,因为它适用于广泛的 AWS Lambda 任务。 是的,你是对的。我想我也许可以把它挤在这里。 =) 谢谢! (此外,我将提供赏金以引起更多关注这个问题。我非常渴望听到其他人在这种情况下做了什么。【参考方案2】:

您可以通过不同的方式实现结果(代码重用)。

首先,使用aws-lambda-java-events 库为每种类型的事件(Alexa、API 网关等)创建一个方法。这里的一些信息: http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-handler-types.html

每个入口点方法都应处理触发它的事件的语义(API 网关),并调用通用代码以提供代码重用。

其次,将您的 JAR/ZIP 上传到 S3 存储桶。

第三,对于您要处理的每个事件 - 创建一个 Lambda 函数,引用 S3 存储桶中的相同 ZIP/JAR 并指定相关入口点。

这样,您将获得代码重用,而无需在 AWS 上处理多个代码副本,尽管代价是定义了多个 Lambda。

有一个很棒的工具可以支持这种工作方式,称为无服务器框架,我强烈建议您查看: https://serverless.com/framework/docs/providers/aws/

【讨论】:

【参考方案3】:

我一直在使用单个 Lambda 来处理 Alexa ASK 和 Microsoft Luis.ai 响应。我使用 Python 而不是 Java,但想法是一样的,我相信使用 AlexaInput 和 ApiAIinput 对象,都应该扩展相同的接口。

我首先使用上下文信息来识别请求来自何处并将其解析为适当的对象(我使用一个简单的嵌套字典)。然后将其传递给我的主要处理函数,最后,根据上下文再次将输出传递给格式化程序。格式化程序将知道您需要返回什么。唯一需要注意的是处理会话信息;在我的情况下,无论如何我都会序列化到我自己的 DynamoDB 表中。

【讨论】:

以上是关于如何为 Alexa Skills Kit 和 API.AI 使用单个 AWS Lambda?的主要内容,如果未能解决你的问题,请参考以下文章

Alexa Skills Kit:如何使用 JS 将图像添加到标准卡片

如何向 Amazon Alexa Skills Kit (ASK) 混合字符串和数字提供输入?

仅从 Alexa Skills Kit 获取单个单词参数

最简单的方法是将现有的 AWS Lex 和 Lambda 部署为 Alexa Skills Kit (ASK)?

Amazon Alexa Skills Kit:如何与外部应用程序帐户/用户 ID 关联

如何为 Alexa 技能意图响应获取和使用确认“是”或“否”