Как использовать одну AWS Lambda для комплекта Alexa Skills Kit и API.AI?

В прошлом я настраивал две отдельные лямбды AWS, написанные на Java. Один для использования с Alexa и один для использования с Api.ai. Они просто возвращают "Hello world" каждому помощнику API. Поэтому, хотя они просты, они работают. Когда я начал писать все больше и больше кода для каждого из них, я начал понимать, насколько похож мой код Java, и я просто повторял себя, имея две отдельные лямбды.

Перенесемся в сегодня.

Сейчас я работаю над тем, чтобы у меня была одна лямбда AWS, которая могла бы обрабатывать данные как от Alexa, так и от Api.ai, но у меня возникли некоторые проблемы. В настоящее время я думаю, что при запуске лямбда-выражения будет простое выражение 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, чтобы посмотреть, какой ввод объекта будет генерироваться в 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.

Я делаю все это неправильно? Неправильно ли я пытаюсь, чтобы одна лямбда выполняла мои "ассистентские" запросы из более чем одного сервиса (Alexa и ApiAI)?

Любая помощь будет оценена. Конечно, кто-то еще должен писать свои функции помощника в AWS и хочет повторно использовать свой код для обеих "вспомогательных" платформ.

3 ответа

У меня был тот же вопрос и та же мысль, но по мере того, как я продвигался дальше и дальше в реализации, я понял, что это было не совсем практично по одной большой причине:

Хотя большая часть моей логики должна была быть одинаковой - формат результатов был другим. Иногда даже детали или форматирование результатов могут отличаться.

Я вернулся к некоторым концепциям, знакомым в веб-программировании, разделив его на две части:

  1. Внутренняя система, которая отвечала за выбор параметров и применение бизнес-логики для получения результатов. Эти результаты были бы довольно низкоуровневыми, а не целыми фразами, а скорее набором пар ключ / значение, которые указывали бы, какой результат дать и какие значения будут необходимы в этом результате.

  2. Внешняя система, которая отвечала за обработку вещей, которые были специфичны для Alexa/Assistant. Таким образом, он будет принимать запрос, извлекать параметры и состояние, вызывать внутреннюю систему с этой информацией, возвращать результат, который включает в себя, какой ответ отправить, и необходимые значения, а затем форматировать точную фразу (и любую другую поддержку информацию, такую ​​как карточка или что-то еще) и поместите ее в правильно отформатированный ответ.

Внешние компоненты будут разными лямбда-функциями для каждого типа агента, в основном, чтобы сделать логику немного чище. Внутренние компоненты могут быть либо библиотечной функцией, либо другой лямбда-функцией, независимо от того, что имеет наибольшее значение для задачи, но не зависит от реализации интерфейса.

Я полагаю, что это также можно сделать, если иметь абстрактный родительский класс, который реализует внутреннюю логику, а логика внешнего интерфейса будет подклассами этого. Я бы так не поступил, потому что он не обеспечивает столь четкую границу интерфейса между ними, но это не является необоснованным.

Вы можете достичь результата (повторное использование кода) другим способом.

Во-первых, создайте метод для каждого типа события (Alexa, API Gateway и т. Д.), Используя aws-lambda-java-events библиотека. Некоторая информация здесь: http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-handler-types.html

Каждый метод точки входа должен иметь дело с семантикой инициирующего его события (API Gateway) и вызывать общий код для повторного использования кода.

Во-вторых, загрузите свой JAR/ZIP в корзину S3.

В-третьих, для каждого события, которое вы хотите обработать - создайте функцию Lambda, ссылаясь на тот же ZIP/JAR в корзине S3 и указав соответствующую точку входа.

Таким образом, вы получите повторное использование кода без необходимости манипулирования несколькими копиями кода в AWS, хотя и за счет определения нескольких лямбда-выражений.

Есть отличный инструмент, который поддерживает работу таким способом, называемый Serverless Framework, который я очень рекомендую посмотреть: https://serverless.com/framework/docs/providers/aws/

Я использовал одну лямбду для обработки ответов Alexa ASK и Microsoft Luis.ai. Я использую Python вместо Java, но идея та же самая, и я считаю, что с использованием объектов AlexaInput и ApiAIinput, расширение обоих интерфейсов должно быть подходящим способом.

Сначала я использую контекстную информацию, чтобы определить, откуда поступает запрос, и проанализировать его в соответствующем объекте (я использую простой вложенный словарь). Затем передайте это моей основной функции обработки и, наконец, снова передайте вывод в средство форматирования на основе контекста. Форматировщик будет знать, что вам нужно вернуть. Единственное предостережение - это обработка информации о сеансе; который в моем случае я в любом случае сериализовать в свою собственную таблицу DynamoDB.

Другие вопросы по тегам