Skip to content

Commit 183f5fc

Browse files
committed
Initial commit
Initial commit
0 parents  commit 183f5fc

7 files changed

+263
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# AWS Step Function Example
2+
3+
This repository serves as an example use-case of AWS Step Functions, through the use of AWS Lambda and integration with various other AWS products.

lambda-SNS.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import boto3
2+
3+
def lambda_handler(event, context):
4+
'''
5+
Sends notification of negative results from sentiment analysis via SNS
6+
'''
7+
8+
#construct message from input data and publish via SNS
9+
sns = boto3.client('sns')
10+
sns.publish(
11+
TopicArn = 'arn:aws:sns:XXXXXXXXXXXXXXXX:my-SNS-topic',
12+
Subject = 'Negative Review Received',
13+
Message = 'Review (ID = %i) of %s (ID = %i) received with negative results from sentiment analysis. Feedback from Customer (ID = %i): "%s"' % (int(event['reviewID']),
14+
event['reviewType'], int(event['productID']), int(event['customerID']), event['feedback'])
15+
)
16+
17+
#pass through values
18+
return {
19+
'sentiment': event['sentiment'],
20+
'reviewType': event['reviewType'],
21+
'reviewID': event['reviewID'],
22+
'customerID': event['customerID'],
23+
'productID': event['productID'],
24+
'feedback': event['feedback'],
25+
}

lambda-invoke-step-function.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import json
2+
import boto3
3+
import pprint
4+
5+
#initialize
6+
pp = pprint.PrettyPrinter(indent=4)
7+
8+
def lambda_handler(event, context):
9+
'''
10+
triggers a step function from the S3 landing event,
11+
passing along the S3 file info
12+
'''
13+
14+
#Fallback tests for initializations outside scope
15+
try:
16+
pp
17+
except NameError:
18+
pp = pprint.PrettyPrinter(indent=4)
19+
20+
bucket_name = event['Records'][0]['s3']['bucket']['name']
21+
file_key = event['Records'][0]['s3']['object']['key']
22+
23+
24+
input= {
25+
'bucket_name': bucket_name,
26+
'file_key': file_key
27+
}
28+
29+
stepFunction = boto3.client('stepfunctions')
30+
response = stepFunction.start_execution(
31+
stateMachineArn='arn:aws:states:XXXXXXXXXXXXXXXX:stateMachine:my-state-machine',
32+
input = json.dumps(input, indent=4)
33+
)
34+
35+
return pp.pprint(response)

lambda-read-CSV.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import boto3
2+
import csv
3+
import json
4+
5+
#initialize
6+
s3 = boto3.client('s3')
7+
8+
def lambda_handler(event, context):
9+
'''
10+
reads the .csv from the S3 landing event, returns a json-formatted
11+
dict formed from the first line (and column headers)
12+
'''
13+
14+
#Fallback tests for initializations outside scope
15+
try:
16+
s3
17+
except NameError:
18+
s3 = boto3.client('s3')
19+
20+
21+
#read s3 object
22+
bucket_name = event['bucket_name']
23+
file_key = event['file_key']
24+
response = s3.get_object(Bucket=bucket_name, Key=file_key)
25+
26+
#convert response to lines of CSV
27+
lines = response['Body'].read().decode('utf-8').split('\n')
28+
29+
#DictReader -> convert lines of CSV to OrderedDict
30+
for row in csv.DictReader(lines):
31+
#return just the first loop (row) results!
32+
return json.loads(json.dumps(row))

lambda-sentiment.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import os, boto3
2+
3+
client = boto3.client('comprehend')
4+
5+
def lambda_handler(event, context):
6+
'''
7+
perform sentiment analysis on the input feedback
8+
'''
9+
10+
#use comprehend to perform sentiment analysis
11+
feedback = event['feedback']
12+
sentiment=client.detect_sentiment(Text=feedback,LanguageCode='en')['Sentiment']
13+
14+
#pass through values
15+
return {
16+
'sentiment': sentiment,
17+
'reviewType': event['reviewType'],
18+
'reviewID': event['reviewID'],
19+
'customerID': event['customerID'],
20+
'productID': event['productID'],
21+
'feedback': event['feedback'],
22+
}

lambda-write-db.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import boto3
2+
3+
def lambda_handler(event, context):
4+
'''
5+
Adds the review data to the review database table
6+
'''
7+
8+
#select correct table based on input data
9+
dynamodb = boto3.client('dynamodb')
10+
if event['reviewType'] == 'Product':
11+
tableName = 'my-products-table'
12+
elif event['reviewType'] == 'Service':
13+
tableName = 'my-services-table'
14+
else:
15+
raise Exception("Input review is neither Product nor Service")
16+
17+
#construct response to put data in table
18+
response = dynamodb.put_item(
19+
TableName=tableName,
20+
Item={
21+
'reviewID': {"N": event['reviewID'] },
22+
'customerID': {"N": event['customerID'] },
23+
'productID': {"N": event['productID'] },
24+
'feedback': {"S": event['feedback'] },
25+
'sentiment': {"S": event['sentiment'] }
26+
},
27+
)
28+
29+
#pass through values
30+
response['reviewType'] = event['reviewType']
31+
response['reviewID'] = event['reviewID']
32+
response['customerID'] = event['customerID']
33+
response['productID'] = event['productID']
34+
response['feedback'] = event['feedback']
35+
response['sentiment'] = event['sentiment']
36+
37+
return response

state-machine

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"StartAt": "ReadCSV",
3+
"States": {
4+
"ReadCSV": {
5+
"Type": "Task",
6+
"Resource": "arn:aws:lambda:XXXXXXXXXXXXXXXX:function:lambda-read-CSV",
7+
"Next": "ProductOrServiceChoice"
8+
},
9+
"ProductOrServiceChoice": {
10+
"Type": "Choice",
11+
"Choices": [
12+
{
13+
"Variable": "$.reviewType",
14+
"StringEquals": "Product",
15+
"Next": "ProductSentimentAnalysis"
16+
},
17+
{
18+
"Variable": "$.reviewType",
19+
"StringEquals": "Service",
20+
"Next": "ServiceSentimentAnalysis"
21+
}
22+
],
23+
"Default": "CategorisationFail"
24+
},
25+
"CategorisationFail": {
26+
"Type": "Fail",
27+
"Cause": "Input CSV could not be categorised into 'Product' or 'Service'."
28+
},
29+
"ProductSentimentAnalysis": {
30+
"Type" : "Task",
31+
"Resource": "arn:aws:lambda:XXXXXXXXXXXXXXXX:function:lambda-sentiment",
32+
"Next": "ProductResultChoice"
33+
},
34+
35+
"ServiceSentimentAnalysis": {
36+
"Type" : "Task",
37+
"Resource": "arn:aws:lambda:XXXXXXXXXXXXXXXX:function:lambda-sentiment",
38+
"Next": "ServiceResultChoice"
39+
},
40+
"ProductResultChoice": {
41+
"Type": "Choice",
42+
"Choices": [
43+
{
44+
"Or": [
45+
{
46+
"Variable": "$.sentiment",
47+
"StringEquals": "POSITIVE"
48+
},
49+
{
50+
"Variable": "$.sentiment",
51+
"StringEquals": "NEUTRAL"
52+
}
53+
],
54+
"Next": "WriteToDB"
55+
},
56+
{
57+
"Variable": "$.sentiment",
58+
"StringEquals": "NEGATIVE",
59+
"Next": "PublishToSNS"
60+
}
61+
],
62+
"Default": "SentimentFail"
63+
},
64+
"SentimentFail": {
65+
"Type": "Fail",
66+
"Cause": "Sentiment Analysis Failed!"
67+
},
68+
"ServiceResultChoice": {
69+
"Type": "Choice",
70+
"Choices": [
71+
{
72+
"Or": [
73+
{
74+
"Variable": "$.sentiment",
75+
"StringEquals": "POSITIVE"
76+
},
77+
{
78+
"Variable": "$.sentiment",
79+
"StringEquals": "NEUTRAL"
80+
}
81+
],
82+
"Next": "WriteToDB"
83+
},
84+
{
85+
"Variable": "$.sentiment",
86+
"StringEquals": "NEGATIVE",
87+
"Next": "PublishToSNS"
88+
}
89+
],
90+
"Default": "SentimentFail"
91+
},
92+
"PublishToSNS":
93+
{
94+
"Type": "Task",
95+
"Resource": "arn:aws:lambda:XXXXXXXXXXXXXXXX:function:lambda-SNS",
96+
"Next": "WriteToDB"
97+
},
98+
"WriteToDB":
99+
{
100+
"Type": "Task",
101+
"Resource": "arn:aws:lambda:XXXXXXXXXXXXXXXX:function:lambda-write-db",
102+
"Next": "Success"
103+
},
104+
"Success":
105+
{
106+
"Type": "Succeed"
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)