...
draw.io Diagram | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
이 애플리케이션은 크게 세 가지 서비스를 제공합니다.
...
- DynamoDB 서비스로 이동합니다.
- Create Table 버튼을 클릭합니다.
- DynamoDB 콘솔에서 NewsTable 라고 하는 단일 테이블을 만듭니다. 기본 키 id 는 문자열이고, PostNews Lambda 함수에 의해 새 레코드는 NewsTable 에 자동으로 추가 생성합니다.
NoSQL인 DynamoDB를 사용하므로 스키마를 사전에 정의하지는 않겠지만, 사용하게 될 어트리뷰트가 어떤 것이 있는지 살펴 보겠습니다.
key value id 게시물 ID (UUID로 자동 생성) voice 오디오 파일을 생성하는데 사용된 Amazon Polly 음성 pollyStatus 처리 상태에 따라서 PROCESSING 또는 UPDATED로 구분 originText 원문 텍스트 RequestCharacters 요청한 문자 개수 mp3Url Polly에 의해서 생성된 mp3 접근 URL updateDate 수정된 시간 timbre 음색 (소리의 파형) pitch 음조 (소리의 높낮이) 5. 테이블 생성 확인
3. SNS Topic 만들기
...
- 그렇기에 간단한 SNS 주제를 만들어 보겠습니다. SNS 서비스로 이동합니다.
- Create topic 메뉴를 눌러서 Topic을 생성합니다.
- 아래와 같이 NewsTopic 이라는 새로운 Topic을 생성합니다.
생성된 SNS는 Amazon Polly가 작업이 완료되면 알려주기 위해서 해당 Topic을 호출해야 합니다. 따라서 Topic에 대한 아마존 고유 리소스 이름을 알아야 합니다.
정보 아래와 같이 생성된 Topic을 클릭하여 Topic의 ARN을 복사하여 메모장에 기록해 둡니다. (사용자 별로 다르게 나옵니다. 본인의 ARN을 복사합니다.)
Topic ARN 복사 하기:
4. mp3 저장을 위한 S3 버킷 만들기
...
- S3 콘솔로 이동하여 새로운 버킷을 생성합니다. 예제에서는
아래 이미지에서는 polly-mp3.studydev.com 이라는 버킷 이름으로 작성하지만, 실습에서는 전 세계적으로 고유한 다른 이름으로 작성해야 합니다. 작성후 Next 버튼을 클릭 합니다. - (옵션) Tags 정보에 Key에는 Name을 Name을 Value에는 WebApp 을 추가합니다.
- 외부에서 퍼블릭하게 접속해서 mp3 재생이 되도록 체크 박스를 모두 해지 합니다. (기본은 체크되어 안전하게 막혀 있음)
- 모든 설정이 완료되면 Create Bucket 버튼을 클릭하고 S3 버킷을 생성합니다.
5. IAM 역할 만들기
Lambda 함수를 만들기 전에 함수에 대한 IAM 역할을 만들어야 합니다. 역할은 함수가 상호 작용할 수 있는 AWS 서비스(API)를 지정합니다. 세 가지 Lambda 함수 모두에 대해 하나의 역할을 만듭니다. (원래 기능별로 역할을 만들지만, 예제 구현을 위해 하나로 만듭니다.)
역할을 생성하기 위해서 역할에 부여될 정책을 JSON 포맷으로 생성하고, 생성한 정책을 해당 역할에 부여합니다.
- 콘솔의 서비스에서 IAM을 찾은 다음 역할 메뉴를 선택하고, 역할 만들기 버튼을 눌러 새 역할을 만들기 위한 마법사를 엽니다. 이 역할을 사용할 서비스인 AWS 서비스 의 Lambda 를 선택하고 다음:권한 버튼을 클릭합니다.
Lambda 4개를 위한 Role을 한 개 생성(가능하면 다른 Lambda의 용도에 맞추어서 따로 만드는걸 추천하지만 실습에서는 1개로 진행)
IAM 서비스로 이동
Lambda를 위한 Role을 생성하기 위해 이동
Role을 생성
이 역할을 사용하는 주체는 AWS Service의 Lambda입니다.
정책을 새로 만듭니다.
...
- IAM 서비스로 이동
- Lambda를 위한 Role을 만들기 위해서 좌측 메뉴의 Roles 를 클릭 합니다.
- Create Role 버튼을 클릭합니다.
- 이 역할을 사용하는 주체는 AWS Service의 Lambda 를 선택하고 Next: Permissions 버큰을 클릭 합니다.
- Create policy 버튼을 클릭하여 정책을 새로 만듭니다. 새 탭(새 창)에 Create policy가 표시 됩니다.
- 탭 메뉴에 있는 Visual editor를 JSON으로 변경하여 사전에 준비해둔 JSON 데이터를 넣습니다.
아래 리소스에 대한 접근 정책을 JSON으로 추가합니다.
코드 블럭 { "Version":"2012-10-17", "Statement":[ { "Effect":"Allow", "Action":[ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "polly:StartSpeechSynthesisTask", "dynamodb:Query", "dynamodb:Scan", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "sns:Publish", "s3:PutObject", "s3:PutObjectAcl", "s3:DeleteObject", "s3:GetBucketLocation" ], "Resource":[ "*" ] } ] }
- 하단과 같이 JSON 데이터를 입력하고, 우측 하단의 Review policy 버튼을 클릭합니다.
- 정책
...
- 이름은 NewsPolicy 로 지정하고, 하단
...
- 우측의 Create policy 버튼을 클릭합니다.
- 아래와 같이 NewsPolicy 정책이 만들어
...
- 진 것을 알 수 있습니다.
- 원래
...
...
- Role을 생성하는 탭(창)으로 돌아와서 NewsPolicy 를 검색합니다. 만약 보이지 않는다면, 우측 상단의 새로 고침 버튼을 클릭합니다. 좌측 체크 박스를 클릭하고 태그를 입력하는 다음 단계로 이동합니다.
- (옵션) Role의 Tag를 입력합니다. NewsApp을 만들기 때문에
...
- Key를 Name으로 Value를 NewsApp으로 정의합니다. 다음 작업을 위해 Next: Review 버튼을 클릭합니다.
...
- Role의 이름은 NewsRole 을 넣습니다.
NewsRole이 생성된 것을 확인할 수 있습니다. 클릭해서 ARN 정보를 기록합니다.
arn:aws:iam::551374826607:role/NewsRole
S3 폴더 만들기
S3 서비스 이동
현재 만들어진 버킷을 볼 수 있습니다.
S3 정적 웹 호스팅용 버킷 만들기
S3 버킷 정적 웹 호스팅 기능 활성화
정적 웹 호스팅을 제공할 버킷을 클릭합니다.
2번째 Properties 탭에서 Static Web Hosting 기능을 클릭합니다.
정적 웹 호스팅 기능이 비활성화 되어 있습니다.
Static Website hosting 기능을 켜 주고, index와 error 문서를 지정하고 저장합니다.
정적 웹 호스팅 기능이 활성화 된 것을 볼 수 있습니다.
버켓 접근에 대한 정책을 설정 할 수 있습니다.
코드 블럭 | ||
---|---|---|
| ||
{ "Version":"2012-10-17", "Statement":[ { "Sid":"PublicReadGetObject", "Effect":"Allow", "Principal":"*", "Action":[ "s3:GetObject" ], "Resource":[ "arn:aws:s3:::BUCKET_NAME/*" ] } ] } |
버켓 정책을 설정하고 저장 합니다.
S3 Bucket이 Public 접근이 가능하다는 메시지가 출력됩니다.
S3 버켓 컨텐츠 업로드 (API 수정)
...
Lambda 4개 생성 (환경변수 고려)
Lambda 서비스로 이동
Lambda 서비스에서 Function을 하나 생성합니다.
Scratch로 PostNews 이름으로 Lambda 함수를 생성합니다. Runtime은 Python 2.7이고 Role은 이미 만들어둔 NewsRole을 선택하고 Create function 버튼을 클릭 합니다.
Lambda 함수가 정상적으로 만들어진 것을 확인할 수 있습니다.
함수 코드를 입력합니다.
코드 블럭 |
---|
# -*- coding: utf-8 -*- from __future__ import print_function import boto3 import os import json import uuid import datetime import re def lambda_handler(event, context): if "body" in event: parmas = json.loads(event['body']) voice = parmas["voice"] originText = parmas["text"] timbre = parmas["timbre"] pitch = parmas["pitch"] updateDate = datetime.datetime.now().strftime("%Y%m%d") polly = boto3.client('polly') removeBrackets = re.sub(r'\([^)]*\)', '', originText) repTextBlock = re.sub('[·…]', '<break time="100ms"/>', removeBrackets) ssmlBlock = "<speak><amazon:effect vocal-tract-length=\"" + timbre + "\"><prosody pitch=\"" + pitch + "\">" + repTextBlock + "</prosody></amazon:effect></speak>" ssmlBlock = ssmlBlock.replace('철수', '<amazon:effect vocal-tract-length="+80%"><prosody pitch="-70%">안녕하세요? 저는 서연 친구 철수에요.</prosody></amazon:effect>') ssmlBlock = ssmlBlock.replace('귀신', '<amazon:effect name="whispered"><amazon:effect vocal-tract-length="-30%"><prosody volume="loud">나 꿍꼬또, 기싱꿍꼬또</prosody></amazon:effect></amazon:effect>') print (ssmlBlock) response = polly.start_speech_synthesis_task( OutputFormat= 'mp3', OutputS3BucketName= os.environ['BUCKET_NAME'], # OutputS3KeyPrefix='polly/', SampleRate='22050', SnsTopicArn=os.environ['SNS_TOPIC'], Text=ssmlBlock, TextType='ssml', VoiceId=voice ) print (response) data = response['SynthesisTask'] # Creating new record in DynamoDB table dynamodb = boto3.resource('dynamodb') table = dynamodb.Table(os.environ['DB_TABLE_NAME']) table.put_item( Item = { 'id' : data['TaskId'], 'updateDate': data['CreationTime'].strftime("%Y-%m-%d %H:%M:%S"), 'voice' : voice, 'originText': originText, 'pollyStatus' : data['TaskStatus'], 'timbre': timbre, 'pitch': pitch, 'mp3Url': data['OutputUri'], 'RequestCharacters': data['RequestCharacters'] } ) result = { 'statusCode': 200, 'body': json.dumps({'recordId': data['TaskId']}), 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } } return result |
함수 환경 변수, 실행 시간, Tag를 설정합니다.
아래 Function code 영역에 코드를 다음과 같이 수정합니다.
...
Create function 버튼을 클릭해서 새로운 함수를 생성합니다.
GetNews 함수를 생성합니다.
코드 블럭 |
---|
from __future__ import print_function import boto3 import os import json import decimal from boto3.dynamodb.conditions import Key, Attr # https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/GettingStarted.Python.04.html # Helper class to convert a DynamoDB item to JSON. class DecimalEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, decimal.Decimal): if o % 1 > 0: return float(o) else: return int(o) return super(DecimalEncoder, self).default(o) def lambda_handler(event, context): if "queryStringParameters" in event: parmas = event['queryStringParameters'] print (parmas) postId = parmas["postId"] dynamodb = boto3.resource('dynamodb') table = dynamodb.Table(os.environ['DB_TABLE_NAME']) if postId == "*": items = table.scan() else: items = table.query(KeyConditionExpression=Key('id').eq(postId)) response = { 'statusCode': 200, 'body': json.dumps(items["Items"], cls=DecimalEncoder), 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } } return response |
UpdateNews 함수 생성
코드
코드 블럭 |
---|
from __future__ import print_function import boto3 import os import json from contextlib import closing from boto3.dynamodb.conditions import Key, Attr import re def lambda_handler(event, context): polly_message = event["Records"][0]["Sns"]["Message"] print (polly_message) polly_response = json.loads(polly_message) # Updating the item in DynamoDB dynamodb = boto3.resource('dynamodb') table = dynamodb.Table(os.environ['DB_TABLE_NAME']) response = table.update_item( Key={ 'id': polly_response["taskId"] }, UpdateExpression="set pollyStatus = :s", ExpressionAttributeValues={ ':s': polly_response['taskStatus'] } ) print(response) s3 = boto3.client('s3') s3.put_object_acl( ACL = 'public-read', Bucket = os.environ['BUCKET_NAME'], Key = polly_response["taskId"] + ".mp3" ) return |
코드 및 환경 변수 설정
Lambda 함수가 기동되는 이벤트 등록
저장하고 나면 NewsTopic에 의해서 트리거가 활성화 된 것을 볼 수 있습니다.
DeleteNews 함수 등록
함수 생성
4개 람다 함수.
API Gateway 생성 및 배포
API Gateway
생성 화면
S3 버켓 컨텐츠 업로드 (API 수정)
테스트