Как использовать одну 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 ответа
У меня был тот же вопрос и та же мысль, но по мере того, как я продвигался дальше и дальше в реализации, я понял, что это было не совсем практично по одной большой причине:
Хотя большая часть моей логики должна была быть одинаковой - формат результатов был другим. Иногда даже детали или форматирование результатов могут отличаться.
Я вернулся к некоторым концепциям, знакомым в веб-программировании, разделив его на две части:
Внутренняя система, которая отвечала за выбор параметров и применение бизнес-логики для получения результатов. Эти результаты были бы довольно низкоуровневыми, а не целыми фразами, а скорее набором пар ключ / значение, которые указывали бы, какой результат дать и какие значения будут необходимы в этом результате.
Внешняя система, которая отвечала за обработку вещей, которые были специфичны для 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.