How to store chat-conversation of chatbot(in aws lex) in DynamoDB - amazon-web-services

I am building a chatbot for a website that has lots of traffic
I decided to build chatbot in AWS lex
I want to save all chat conversation an single attribute in Dynamo DB for that I had chosen list data type for that attribute
and I am able to get all the slot data into different variables but how to save user entered utterance and prompts that we defined in lex console and how to arrange them like a conversation.
If is there any alternative for storing chat conversation?

Since it's your bot, you know the session timeout value. In your lambda function you can generate a session id (random UUID) and put that in session attribute (read more here). You can create a DDB table in your account and design it like this:
Hash Key: userId
Range Key: sessionId#timeStamp
Request (String attribute): JSON format of request structure that is sent to Lambda function
Now as long as the session is valid you can always retrieve the sessionId that you put in session attributes map. Using this you will always be able to create the range key (sessionId + "#" + currentTimeStamp). In every call that you get in your lambda you also get the user-id for your bot. You can all this information to store the utterances the way you might like.

Related

AppSync wrong id for schema in DynamoDB

I am using a graphql API with AppSync that receives post requests from a lambda function that is triggered by AWS IoT with sensor data in the following JSON format:
{
"scoredata": {
"id": "240",
"distance": 124,
"timestamp": "09:21:11",
"Date": "04/16/2022"
}
}
The lambda function uses this JSON object to perform a post request on the graphql API, and AppSync puts this data in DynamoDB to be stored. My issue is that whenever I parse the JSON object within my lambda function to retrieve the id value, the id value does not match with the id value stored in DynamoDB; appsync is seemingly automatically generating an id.
Here is a screenshot of the request made to the graphql api from cloudwatch:
Here is what DynamoDB is storing:
I would like to know why the id in DynamoDB is shown as 964a3cb2-1d3d-4f1e-a94a-9e4640372963" when the post request id value is "240" and if there is anything I can do to fix this.
I can’t tell for certain but i’m guessing that dynamo db schema is autogenerating the id field on insert and using a uuid as the id type. An alternative would be to introduce a new property like score_id to store this extraneous id.
If you are using amplify most likely the request mapping templates you are generating automatically identify the "id" field as a unique identifier to be generated at runtime.
I recommend you to take a look at your VTL request template, you will most likely find something like this:
$util.qr($context.args.input.put("id", $util.defaultIfNull($ctx.args.input.id, $util.autoId())))
Surely the self-generated id comes from $util.autoId()
Probably some older version of Amplify could omit the verification $util.defaultIfNull($ctx.args.input.id,... and always overwrite the id by self-generating it.

Get all items in DynamoDB with API Gateway's Mapping Template

Is there a simple way to retrieve all items from a DynamoDB table using a mapping template in an API Gateway endpoint? I usually use a lambda to process the data before returning it but this is such a simple task that a Lambda seems like an overkill.
I have a table that contains data with the following format:
roleAttributeName roleHierarchyLevel roleIsActive roleName
"admin" 99 true "Admin"
"director" 90 true "Director"
"areaManager" 80 false "Area Manager"
I'm happy with getting the data, doesn't matter the representation as I can later transform it further down in my code.
I've been looking around but all tutorials explain how to get specific bits of data through queries and params like roles/{roleAttributeName} but I just want to hit roles/ and get all items.
All you need to do is
create a resource (without curly braces since we dont need a particular item)
create a get method
use Scan instead of Query in Action while configuring the integration request.
Configurations as follows :
enter image description here
now try test...you should get the response.
to try it out on postman deploy the api first and then use the provided link into postman followed by your resource name.
API Gateway allows you to Proxy DynamoDB as a service. Here you have an interesting tutorial on how to do it (you can ignore the part related to index to make it work).
To retrieve all the items from a table, you can use Scan as the action in API Gateway. Keep in mind that DynamoDB limits the query sizes to 1MB either for Scan and Query actions.
You can also limit your own query before it is automatically done by using the Limit parameter.
AWS DynamoDB Scan Reference

how do i get inbound caller id info from aws connect and lex in my lambda function

I have connect and lex up and running and can customize my lex chatbot via a lambda that checks the incoming phone number.
I would like to use caller id info to look up customer info for the lambda to use.
How do i get the inbound caller id info ?
Thanks
Use Contact Attributes
Contact attributes let you store customer input or data about a customer, and then use it later in a contact flow.
Contact attributes let you pass data between Amazon Connect and other services, such as Amazon Lex and AWS Lambda. Contact attributes can be both set and consumed by each service. For example, you could use a Lambda function to look up customer information, such as their name or order number, and use contact attributes to store the values returned to Amazon Connect. You could then reference those attributes to include the customer's name in messages using text to speech, or store their order number so they do not have to enter it again.
How to set Contact Attributes
To set a contact attribute with a Set contact attributes block
In Amazon Connect, choose Routing, Contact flows.
Select an existing contact flow, or create a new one.
Add a Set contact attributes block.
Edit the Set contact attributes block, and choose Use text.
For the Destination key, provide a name for the attribute, such as Company. This is the value you use for the Attribute field when using or referencing attributes in other blocks. For the Value, use your company name.
You can also choose to use an existing attribute as the basis for creating the new attribute.
What customer data can you get from System Attributes?
Customer number
Dialed number
Customer callback number
Stored customer input
...and more
For anyone in the future having difficulty.
In Amazon Connect, you can pass contact attributes (Inbound Caller ID) from inside the customer input block where the Lex Bot exists to the Lambda that the bot calls.
Open up the Get customer input block where your Lex Bot gets the user's input and add in a session attribute.
Set the Destination Key to any name ( I set mine to InboundCallerID).
Set Type to System.
Set Attribute to Customer Number.
Now you can access the customer number via the event variable from inside your lambda.
Example:
def lambda_handler(event, context):
phone_number = event['sessionState']['sessionAttributes']['InboundCallerID']

Should I store failed login attempts in AWS Cognito or Dynamo DB?

I have a requirement to build a basic "3 failed login attempts and your account gets locked" functionality. The project uses AWS Cognito for Authentication, and the Cognito PreAuth and PostAuth triggers to run a Lambda function look like they will help here.
So the basic flow is to increment a counter in the PreAuth lambda, check it and block login there, or reset the counter in the PostAuth lambda (so successful logins dont end up locking the user out). Essentially it boils down to:
PreAuth Lambda
if failed-login-count > LIMIT:
block login
else:
increment failed-login-count
PostAuth Lambda
reset failed-login-count to zero
Now at the moment I am using a dedicated DynamoDB table to store the failed-login-count for a given user. This seems to work fine for now.
Then I figured it'd be neater to use a custom attribute in Cognito (using CognitoIdentityServiceProvider.adminUpdateUserAttributes) so I could throw away the DynamoDB table.
However reading https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-dg.pdf the section titled "Configuring User Pool Attributes" states:
Attributes are pieces of information that help you identify individual users, such as name, email, and phone number. Not all information about your users should be stored in attributes. For example, user data that changes frequently, such as usage statistics or game scores, should be kept in a separate data store, such as Amazon Cognito Sync or Amazon DynamoDB.
Given that the counter will change on every single login attempt, the docs would seem to indicate I shouldn't do this...
But can anyone tell me why? Or if there would be some negative consequence of doing so?
As far as I can see, Cognito billing is purely based on storage (i.e. number of users), and not operations, whereas Dynamo charges for read/write/storage.
Could it simply be AWS not wanting people to abuse Cognito as a storage mechanism? Or am I being daft?
We are dealing with similar problem and main reason why we have decided to store extra attributes in DB is that Cognito has quotas for all the actions and "AdminUpdateUserAttributes" is limited to 25 per second.
More information here:
https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html
So if you have a pool with 100k or more it can create a bottle neck if wanted to update a Cognito user records with every login etc.
Cognito UserAttributes are meant to store information about the users. This information can then be read from the client using the AWS Cognito SDK, or just by decoding the idToken on the client-side. Every custom attribute you add will be visible on the client-side.
Another downside of custom attributes is that:
You only have 25 values to set
They cannot be removed or changed once added to the user pool.
I have personally used custom attributes and the interface to manipulate them is not excellent. But that is just a personal thought.
If you want to store this information, and not depend on DynamoDB, you can use Amazon Cognito Sync. Besides the service, it offers a client with great features that you can incorporate to your app.
AWS DynamoDb appears to be your best option, it is commonly used for such use cases. Some of the benefits of using it:
You can store separate record for each login attempt with as much info as you want such as ip address, location, user-agent etc. You can also add datetime that can be used by pre-auth Lambda to query by time range for example failed attempt within last 30 minutes
You don't need to manage table because you can set TTL for DynamoDb record so that record will be deleted automatically after specified time.
You can also archive items in S3

Can you stop Alexa Skill session programmatically in lambda function?

Is it possible to stop a session from inside aws-lambda code if you run lambda seperately from skill.
I am trying to run aws-lambda function from SNS to stop skill session.
From what I've ready my interpretation is that you're interested in ending the session on your Amazon echo by sending an SNS message to an unrelated lambda function. If that is correct this is how I would proceed.
I have not tried this but having extensive experience with Amazon Alexa Skills in Node.js I would say this might be accomplished in a programmatic way as follows:
1) Enable a dynamodb table within your alexa app. (as seen in line 4)
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = `YOUR_ALEXA_SKILL_ID`;
alexa.dynamoDBTableName = 'NAME_OF_YOUR_DYNAMODB_TABLE'; //You literally dont need any other code it just does the saving and loading??!! WHAT?
alexa.registerHandlers(newSessionHandlers, newGameYesNoHandlers);
alexa.execute();
};
Alexa will then create a single datatable row for each unique user. Note you'll need to set up an IAm permission to allow lambda to access this data table.
2) When your session starts have it update a value in it's own data table row so that this.attributes['EXECUTING'] = True;
3) During each consecutive intent call within the session check the value of this.attributes['EXECUTING] if the value is True, Great, if it is False end the session by emitting this.emit(':tell', "Goodbye!");
4) Now, the data table rows are indexed by userId. This will be the tricky part that I have not personally tried. I suggest creating an intent where the user ask for their userId, then emit a card with the id value on it. This could then be copied into your own SMS lambda function or some other api. Alternatively amazon has recently released documentation on how to connect alexa users to your own API's.
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/linking-an-alexa-user-with-a-user-in-your-system
It really depends on what you're hoping the final product will look like.
5) Finally, use your external api or alternate lambda function along with the users userId to access the same dynamodb table and alter the value of ['EXECUTING'] to False. The next intent that is run will then check the database and cause the skill to exit.
Voila!
For more on specific code, account linking, and sms please ask additional questions. Thanks