...
2. Application 및 "PostNews" Lambda 함수 생성
코드 블럭 | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
# -*- coding: utf-8 -*-
from __future__ import print_function
import boto3
import os
import json
import uuid
import datetime
def lambda_handler(event, context):
if "body" in event:
event = json.loads(event['body'])
print (event)
recordId = str(uuid.uuid4())
voice = event["voice"]
originText = event["text"]
timbre = event["timbre"]
pitch = event["pitch"]
updateDate = datetime.datetime.now().strftime("%Y%m%d")
print('Generating new DynamoDB record, with ID: ' + recordId)
# Create the item in DynamoDB table
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['DB_TABLE_NAME'])
table.put_item(
Item={
'id' : recordId,
'originText': originText,
'postDate': int(updateDate),
'pollyVoice' : voice,
'pollyStatus' : "PROCESSING",
'pollyTimbre': timbre,
'pollyPitch': pitch
}
)
# Sending notification about new post to SNS
client = boto3.client('sns')
client.publish(
TopicArn = os.environ['SNS_TOPIC'],
Message = recordId
)
response = {
'statusCode': 200,
'body': json.dumps({'recordId': recordId}),
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
}
return response |
코드 블럭 | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: >-
Building Serverless development environment and CI/CD process for DevOps based
on Cloud9
Globals:
Function:
Runtime: python2.7
Handler: lambda_function.lambda_handler
MemorySize: 128
Timeout: 60
Resources:
PostNews:
Type: 'AWS::Serverless::Function'
Properties:
CodeUri: PostNews
Description: Post news text to convert from text to speech
Events:
PostNewsApi:
Type: Api
Properties:
Path: /news
Method: POST
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'logs:PutLogEvents'
- 'logs:CreateLogStream'
- 'dynamodb:PutItem'
- 'sns:Publish'
Resource: '*'
|
코드 블럭 | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: >-
Building Serverless development environment and CI/CD process for DevOps based
on Cloud9
Globals:
Function:
Runtime: python2.7
Handler: lambda_function.lambda_handler
MemorySize: 128
Timeout: 60
Environment:
Variables:
DB_TABLE_NAME:
Ref: NewsTable
SNS_TOPIC:
Ref: NewsTopic
BUCKET_NAME:
Ref: PollyMp3Bucket
Resources:
NewsTable:
Type: 'AWS::Serverless::SimpleTable'
Properties:
PrimaryKey:
Name: id
Type: String
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
NewsTopic:
Type: 'AWS::SNS::Topic'
Properties:
DisplayName: NewsTopic
PollyMp3Bucket:
Type: 'AWS::S3::Bucket'
StaticWebBucket:
Type: 'AWS::S3::Bucket'
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
PostNews:
Type: 'AWS::Serverless::Function'
Properties:
CodeUri: PostNews
Description: Post news text to convert from text to speech
Events:
PostNewsApi:
Type: Api
Properties:
Path: /news
Method: POST
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'logs:PutLogEvents'
- 'logs:CreateLogStream'
- 'dynamodb:PutItem'
- 'sns:Publish'
Resource: '*'
|
코드 블럭 | ||||||
---|---|---|---|---|---|---|
| ||||||
# -*- coding: utf-8 -*-
from __future__ import print_function
import boto3
import os
from contextlib import closing
from boto3.dynamodb.conditions import Key, Attr
import re
def lambda_handler(event, context):
postId = event["Records"][0]["Sns"]["Message"]
print ("Text to Speech function. Post ID in DynamoDB: ", postId)
# Retrieving information about the post from DynamoDB table
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['DB_TABLE_NAME'])
postItem = table.query(
KeyConditionExpression=Key('id').eq(postId)
)
text = postItem["Items"][0]["originText"]
voice = postItem["Items"][0]["pollyVoice"]
timbre = postItem["Items"][0]["pollyTimbre"]
pitch = postItem["Items"][0]["pollyPitch"]
rest = text
# Because single invocation of the polly synthesize_speech api can
# transform text with about 3,000 characters, we are dividing the
# post into blocks of approximately 2,900 characters.
textBlocks = []
while (len(rest) > 3000):
begin = 0
end = rest.find(".", 2900)
if (end == -1):
end = rest.find(" ", 2900)
textBlock = rest[begin:end]
rest = rest[end:]
textBlocks.append(textBlock)
textBlocks.append(rest)
#For each block, invoke Polly API, which will transform text into audio
polly = boto3.client('polly')
for textBlock in textBlocks:
removeBrackets = re.sub(r'\([^)]*\)', '', textBlock)
repTextBlock = re.sub('[·…]', '<break time="100ms"/>', removeBrackets)
#repTextBlock = re.sub('["·\'…]', '<break time="100ms"/>', removeBrackets)
ssmlBlock = "<speak><amazon:effect vocal-tract-length=\"" + timbre + "\"><prosody pitch=\"" + pitch + "\">" + repTextBlock + "</prosody></amazon:effect></speak>"
#print (ssmlBlock)
response = polly.synthesize_speech(OutputFormat='mp3', Text = ssmlBlock, VoiceId = voice, TextType = 'ssml')
#Save the audio stream returned by Amazon Polly on Lambda's temp
# directory. If there are multiple text blocks, the audio stream
# will be combined into a single file.
if "AudioStream" in response:
with closing(response["AudioStream"]) as stream:
output = os.path.join("/tmp/", postId)
with open(output, "a") as file:
file.write(stream.read())
s3 = boto3.client('s3')
s3.upload_file('/tmp/' + postId,
os.environ['BUCKET_NAME'],
postId + ".mp3")
s3.put_object_acl(ACL='public-read',
Bucket=os.environ['BUCKET_NAME'],
Key= postId + ".mp3")
location = s3.get_bucket_location(Bucket=os.environ['BUCKET_NAME'])
region = location['LocationConstraint']
if region is None:
url_begining = "https://s3.amazonaws.com/"
else:
url_begining = "https://s3-" + str(region) + ".amazonaws.com/" \
url = url_begining \
+ str(os.environ['BUCKET_NAME']) \
+ "/" \
+ str(postId) \
+ ".mp3"
#Updating the item in DynamoDB
response = table.update_item(
Key={'id':postId},
UpdateExpression=
"SET #statusAtt = :statusValue, #urlAtt = :urlValue",
ExpressionAttributeValues=
{':statusValue': 'UPDATED', ':urlValue': url},
ExpressionAttributeNames=
{'#statusAtt': 'pollyStatus', '#urlAtt': 'mp3Url'},
)
return |
SAM(template.yml)에 DynamoDB, SNS, S3(Web, Mp3) 리소스 추가하기
...