버전 비교

  • 이 줄이 추가되었습니다.
  • 이 줄이 삭제되었습니다.
  • 서식이 변경되었습니다.

...

draw.io Diagram
bordertrue
viewerToolbartrue
fitWindowfalse
diagramNameServerless101HOL
simpleViewerfalse
width
diagramWidth1182
revision23

이 애플리케이션은 크게 세 가지 서비스를 제공합니다.

...

  1. DynamoDB 서비스로 이동합니다.
  2. Create Table 버튼을 클릭합니다.
    Image Modified
  3. DynamoDB 콘솔에서 NewsTable 라고 하는 단일 테이블을 만듭니다. 기본 키 id 는 문자열이고, PostNews Lambda 함수에 의해 새 레코드는 NewsTable 에 자동으로 추가 생성합니다.
  4. NoSQL인 DynamoDB를 사용하므로 스키마를 사전에 정의하지는 않겠지만, 사용하게 될 어트리뷰트가 어떤 것이 있는지 살펴 보겠습니다.

    keyvalue
    id게시물 ID (UUID로 자동 생성)
    voice오디오 파일을 생성하는데 사용된 Amazon Polly 음성
    pollyStatus처리 상태에 따라서 PROCESSING 또는 UPDATED로 구분
    originText원문 텍스트
    RequestCharacters요청한 문자 개수
    mp3UrlPolly에 의해서 생성된 mp3 접근 URL
    updateDate수정된 시간
    timbre음색 (소리의 파형)
    pitch음조 (소리의 높낮이)

    5. 테이블 생성 확인
    Image Modified


3. SNS Topic 만들기

...

  1. 그렇기에 간단한 SNS 주제를 만들어 보겠습니다. SNS 서비스로 이동합니다.
    Image Modified
  2. Create topic 메뉴를 눌러서 Topic을 생성합니다.
    Image Modified
  3. 아래와 같이 NewsTopic 이라는 새로운 Topic을 생성합니다.
    Image Modified
  4. 생성된 SNS는 Amazon Polly가 작업이 완료되면 알려주기 위해서 해당 Topic을 호출해야 합니다. 따라서 Topic에 대한 아마존 고유 리소스 이름을 알아야 합니다.

    정보

    아래와 같이 생성된 Topic을 클릭하여 Topic의 ARN을 복사하여 메모장에 기록해 둡니다. (사용자 별로 다르게 나옵니다. 본인의 ARN을 복사합니다.)
    Topic ARN 복사 하기: 

    Image Modified

4. mp3 저장을 위한 S3 버킷 만들기

...

  1. S3 콘솔로 이동하여 새로운 버킷을 생성합니다. 예제에서는 
    아래 이미지에서는 polly-mp3.studydev.com 이라는 버킷 이름으로 작성하지만, 실습에서는 전 세계적으로 고유한 다른 이름으로 작성해야 합니다. 작성후 Next 버튼을 클릭 합니다.
  2. (옵션) Tags 정보에 Key에는 Name을 NameValue에는 WebApp 을 추가합니다.
  3. 외부에서 퍼블릭하게 접속해서 mp3 재생이 되도록 체크 박스를 모두 해지 합니다. (기본은 체크되어 안전하게 막혀 있음)
  4. 모든 설정이 완료되면 Create Bucket 버튼을 클릭하고 S3 버킷을 생성합니다.


5. IAM 역할 만들기

Lambda 함수를 만들기 전에 함수에 대한 IAM 역할을 만들어야 합니다. 역할은 함수가 상호 작용할 수 있는 AWS 서비스(API)를 지정합니다. 세 가지 Lambda 함수 모두에 대해 하나의 역할을 만듭니다. (원래 기능별로 역할을 만들지만, 예제 구현을 위해 하나로 만듭니다.)
역할을 생성하기 위해서 역할에 부여될 정책을 JSON 포맷으로 생성하고, 생성한 정책을 해당 역할에 부여합니다.

  1. 콘솔의 서비스에서 IAM을 찾은 다음 역할 메뉴를 선택하고, 역할 만들기 버튼을 눌러 새 역할을 만들기 위한 마법사를 엽니다. 이 역할을 사용할 서비스인  AWS 서비스 의  Lambda 를 선택하고 다음:권한 버튼을 클릭합니다.

Lambda 4개를 위한 Role을 한 개 생성(가능하면 다른 Lambda의 용도에 맞추어서 따로 만드는걸 추천하지만 실습에서는 1개로 진행)

IAM 서비스로 이동

Image Removed

Lambda를 위한 Role을 생성하기 위해 이동

Image Removed

Role을 생성

Image Removed

이 역할을 사용하는 주체는 AWS Service의 Lambda입니다.

Image Removed

정책을 새로 만듭니다.

Image Removed

...

  1. IAM 서비스로 이동
    Image Added
  2. Lambda를 위한 Role을 만들기 위해서 좌측 메뉴의 Roles 를 클릭 합니다.
    Image Added
  3. Create Role 버튼을 클릭합니다.
    Image Added
  4. 이 역할을 사용하는 주체는 AWS ServiceLambda 를 선택하고 Next: Permissions 버큰을 클릭 합니다.
    Image Added
  5. Create policy 버튼을 클릭하여 정책을 새로 만듭니다. 새 탭(새 창)에 Create policy가 표시 됩니다.
    Image Added
  6. 탭 메뉴에 있는 Visual editorJSON으로 변경하여 사전에 준비해둔 JSON 데이터를 넣습니다.
    Image Modified
  7. 아래 리소스에 대한 접근 정책을 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":[ 
            "*"
          ]
        }
      ]
    }


  8. 하단과 같이 JSON 데이터를 입력하고, 우측 하단의 Review policy 버튼을 클릭합니다.
    Image Modified
  9. 정책

...

  1. 이름은 NewsPolicy 지정하고, 하단

...

  1. 우측의 Create policy 버튼을 클릭합니다.
    Image Modified
  2. 아래와 같이 NewsPolicy 정책이 만들어

...

  1. 진 것을 알 수 있습니다.
    Image Modified
  2. 원래

...

Image Removed

...

  1. Role을 생성하는 탭(창)으로 돌아와서 NewsPolicy 를 검색합니다. 만약 보이지 않는다면, 우측 상단의 새로 고침 버튼을 클릭합니다. 좌측 체크 박스를 클릭하고 태그를 입력하는 다음 단계로 이동합니다.
    Image Modified
  2. (옵션) Role의 Tag를 입력합니다. NewsApp을 만들기 때문에

...

  1. Key를 Name으로 Value를 NewsApp으로 정의합니다. 다음 작업을 위해 Next: Review 버튼을 클릭합니다.
    Image Modified

...

  1. Role의 이름은 NewsRole 을 넣습니다.
    Image Modified

NewsRole이 생성된 것을 확인할 수 있습니다. 클릭해서 ARN 정보를 기록합니다.

Image Modified

arn:aws:iam::551374826607:role/NewsRole


S3 폴더 만들기

S3 서비스 이동

Image Modified

현재 만들어진 버킷을 볼 수 있습니다.

Image Modified


S3 정적 웹 호스팅용 버킷 만들기

Image Modified

Image Modified

Image Modified

Image Modified




S3 버킷 정적 웹 호스팅 기능 활성화

정적 웹 호스팅을 제공할 버킷을 클릭합니다.

Image Modified

2번째 Properties 탭에서 Static Web Hosting 기능을 클릭합니다.

Image Modified

정적 웹 호스팅 기능이 비활성화 되어 있습니다.

Image Modified

Static Website hosting 기능을 켜 주고, index와 error 문서를 지정하고 저장합니다.

Image Modified

정적 웹 호스팅 기능이 활성화 된 것을 볼 수 있습니다.

Image Modified

버켓 접근에 대한 정책을 설정 할 수 있습니다.

Image Modified

코드 블럭
titleS3 버켓에 대한 접근 권한 설정
{ 
  "Version":"2012-10-17",
  "Statement":[ 
    { 
      "Sid":"PublicReadGetObject",
      "Effect":"Allow",
      "Principal":"*",
      "Action":[ 
        "s3:GetObject"
      ],
      "Resource":[ 
        "arn:aws:s3:::BUCKET_NAME/*"
      ]
    }
  ]
}


버켓 정책을 설정하고 저장 합니다.

Image Modified

S3 Bucket이 Public 접근이 가능하다는 메시지가 출력됩니다.

Image Modified


S3 버켓 컨텐츠 업로드 (API 수정)

...

Lambda 4개 생성 (환경변수 고려)

Lambda 서비스로 이동

Image Modified


Lambda 서비스에서 Function을 하나 생성합니다.

Image Modified


Scratch로 PostNews 이름으로 Lambda 함수를 생성합니다. Runtime은  Python 2.7이고 Role은 이미 만들어둔 NewsRole을 선택하고 Create function 버튼을 클릭 합니다.

Image Modified


Lambda 함수가 정상적으로 만들어진 것을 확인할 수 있습니다.

Image RemovedImage Added

함수 코드를 입력합니다.

코드 블럭
# -*- 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

Image RemovedImage Added


함수 환경 변수, 실행 시간, Tag를 설정합니다.

Image Modified

아래 Function code 영역에 코드를 다음과 같이 수정합니다.

...

Create function 버튼을 클릭해서 새로운 함수를 생성합니다.

Image Modified

GetNews 함수를 생성합니다.

Image Modified

코드 블럭
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

Image RemovedImage Added


UpdateNews 함수 생성

Image Modified

코드

코드 블럭
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

코드 및 환경 변수 설정

Image RemovedImage Added

Lambda 함수가 기동되는 이벤트 등록

Image RemovedImage Added

저장하고 나면 NewsTopic에 의해서 트리거가 활성화 된 것을 볼 수 있습니다.

Image Modified


DeleteNews 함수 등록

Image Modified

함수 생성

Image Modified

Image RemovedImage Added

4개 람다 함수.

Image Modified


API Gateway 생성 및 배포

Image Modified

API Gateway 

Image Modified


생성 화면

Image Modified


Image Modified


Image Modified

Image Modified

Image Modified

Image Modified

Image Modified


Image Modified


Image Modified

Image Modified

Image Modified

Image Modified

Image Modified

Image Modified

Image Modified

Image Modified

Image Modified

Image Modified










S3 버켓 컨텐츠 업로드 (API 수정)


테스트

Image Modified