How to use one AWS Lambda for Alexa Skills Kit and API.AI?

In the past, I installed two separate AWB iamba written in Java. One for use with Alexa and one for use with Api.ai. They simply return "Hello world" to each helper api. Therefore, although they are simple, they work. As I started writing more and more code for each of them, I began to see how similar my Java code was, and I just repeated myself with two separate lambdas.

Fast Forward

Now I am working with a single AWS lambda that can handle input from both Alexa and Api.ai, but I have problems. Currently, I think that when starting lambda there will be a simple if statement:

The following code is not real, just what I can do in my head

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

Now I need to somehow say whether the function is called alexey or api.ai.

This is my actual java right now:

 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"; } 

Then I launched a lambda from Alexa and Api.ai to find out which object will be created in 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}}} 

So now I have both exits Alexa and Api.ai, and they are different. So good. I can tell which one. but i'm stuck. I'm not sure if I should try to create an AlexaInput object and an ApiAIinput object.

Am I doing all this wrong? Am I mistaken when trying to get one lambda to fulfill my β€œhelpers” requests from several services (Alexa and ApiAI)?

Any help would be greatly appreciated. Of course, someone else needs to write their helpers in AWS and wants to reuse their code for both of the "helpers" platforms.

+7
aws-lambda alexa-skills-kit alexa actions-on-google api-ai
source share
3 answers

I had the same question and the same thought, but as I progressed further and further, I realized that this was not entirely practical for one big reason:

While a lot of my logic should have been the same - the format of the results was different. Sometimes even the details or formatting of the results will be different.

What I did was return to some concepts that were familiar in web programming, dividing it into two parts:

  • A back-end , which was responsible for taking parameters and applying business logic to get results. These results would be rather low-level, not whole phrases, but more a set of key / value pairs that would indicate what result to give and what values ​​would be needed in this result.

  • A front-end system that was responsible for handling things that were specific to Alexa / Assistant. Thus, it will accept the request, retrieve the parameters and state, call the internal system using this information, return a result that would include which answer to send and the necessary values, and then format the exact phrase (and any other support information, such as a map or something else) and put it in a formatted answer.

Front-end components would be a different lambda function for each type of agent, mainly in order to make the logic a little cleaner. Internal components can be either a library function or another lambda function, which is most important for the task, but does not depend on the implementation of the interface.

I believe that this could also have an abstract parent class that implements the logic of the internal interface, and the front-end logic is subclasses of this. I would not do it this way, because it does not provide as a clear interface border between them, but it is also not unreasonable.

+2
source share

You can achieve the result (code reuse) in another way.

First, create a method for each type of event (Alexa, Gateway API, etc.) using the aws-lambda-java-events library. Some information here: http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-handler-types.html

Each entry point method must deal with the semantics of the event that triggers it (API Gateway), and call the common code to reuse the code.

Secondly, load the JAR / ZIP into the S3 bucket.

Thirdly, for each event that you want to handle, create a Lambda function, referencing the same ZIP / JAR in the S3 bucket and specifying the corresponding entry point.

This way you get code reuse without juggling multiple copies of AWS code, at least by defining multiple Lambdas.

There's a great tool that supports this work called Serverless Framework, which I highly recommend about: https://serverless.com/framework/docs/providers/aws/

+1
source share

I use one Lambda to handle Alexa ASK and Microsoft Luis.ai responses. I use Python instead of Java, but the idea is the same, and I believe that using an AlexaInput and ApiAIinput object as an extension of the same interface should be a way.

First, I use contextual information to determine where the request is coming from and analyze it in the corresponding object (I use a simple nested dictionary). Then pass this to my main processing function and finally pass the result back to the context based formatter. The formatter will know what you need to return. The only caveat is that processing session information; which in my case I am serializing to my DynamoDB table anyway.

0
source share

All Articles