버전 비교

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

...

  1. IAM 서비스로 이동
  2. Lambda를 위한 Role을 만들기 위해서 좌측 메뉴의 Roles 를 클릭 합니다.
  3. Create Role 버튼을 클릭합니다.
  4. 이 역할을 사용하는 주체는 AWS ServiceLambda 를 선택하고 Next: Permissions 버큰을 클릭 합니다.
  5. Create policy 버튼을 클릭하여 정책을 새로 만듭니다. 새 탭(새 창)에 Create policy가 표시 됩니다.
  6. 탭 메뉴에 있는 Visual editorJSON으로 변경하여 사전에 준비해둔 JSON 데이터를 넣습니다.
  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 버튼을 클릭합니다.
  9. 정책 이름은 NewsPolicy 로 지정하고, 하단 우측의 Create policy 버튼을 클릭합니다.
  10. 아래와 같이 NewsPolicy 정책이 만들어 진 것을 알 수 있습니다.
  11. 원래 Role을 생성하는 탭(창)으로 돌아와서 NewsPolicy 를 검색합니다. 만약 보이지 않는다면, 우측 상단의 새로 고침 버튼을 클릭합니다. 좌측 체크 박스를 클릭 하고 태그를 입력하는 다음 단계로 이동합니다.
  12. (옵션) Role의 Tag를 입력합니다. NewsApp을 만들기 때문에 Key를 Name으로 Value를 NewsApp으로 정의합니다. 다음 작업을 위해 Next: Review 버튼을 클릭합니다.
  13. Role의 이름은 NewsRole 을 넣습니다. 우측 하단의 Create role 버튼을 클릭합니다.
    Image Modified
  14. NewsPolicy 정책이 할당되어 있는NewsRole 이 생성된 것을 확인할 수 있습니다.
    Image Modified

...


6. PostNews Lambda 함수 만들기

첫 번째로 만들 Lambda 함수는 이 애플리케이션의 시작점입니다. 오디오 파일로 변환해야하는 새 게시물에 대한 정보를 받습니다.

  1. AWS 관리 콘솔에서 Lambda 서비스로 이동합니다.
  2. Create a function 버튼을 클릭하여 Lambda 함수를 하나 만들겠습니다.
  3. 새로운 함수의 Name은 PostNews 라고 만듭니다. Runtime은 Python 2.7 을 선택합니다. Role은 Choose an existing role 을 선택하고, 위에서 생성한 IAM Role인 NewsRole 을 선택합니다. 그리고 우측 하단의 Create function 버튼을 클릭합니다.
  4. Lambda 함수가 정상적으로 만들어진 것을 확인할 수 있습니다. Lambda 함수 코드 편집기는 AWS Cloud9 IDE가 내장되어 있어서 코드 편집을 웹 브라우저에서도 쉽게 할 수 있는 환경을 제공합니다.

  5. 아래 코드를 이 Lambda 함수의 코드로 변경합니다. 해당 함수의 로직은 Polly에 TTS 작업을 요청하고, 요청 작업에 대한 ID 값을 DynamoDB에 등록합니다.

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


  6. 아래와 같이 함수 코드를 변경하고 나면 우측 상단의 Save 버튼을 눌러서 환경을 저장합니다.


  7. PostNews Lambda 함수는 메타 데이터가 저장될 DynamoDB 테이블(DB_TABLE_NAME), Polly가 작업을 완료하면 다음 Lambda 함수를 트리거 시키기 위한 SNS Topic(SNS_TOPIC), Polly에 의해서 만들어지는 mp3가 저장될 S3의 버켓(BUCKET_NAME)의 이름을 알아야 합니다. 이 값을 환경 변수로 함수에 전달할 수 있는 기능을 사용하기 위하여 Environment variables를 사용할 수 있습니다. 아래와 같이 S3 버킷 이름(polly-mp3.studydev.com)과, NewsTopic의 ARN 값(, DynamoDB 테이블의 NewsTable 값을 아래와 같이 입력합니다.
    추가로 하단의 Basic settings에서 Lambda의 실행 시간을 지정할 수 있습니다. Timeout 값을 1 min 으로 수정합니다. Tags에는 Key 값으로 Name을 NameValue 값을 NewsApp을 NewsApp 입력합니다.

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

...


7. GetNews Lambda 함수 만들기

  1. PostNews와 같이 Create function 버튼을 클릭해서 새로운 함수를 생성합니다.
    Image Modified
  2. GetNews 함수를 생성합니다. Runtime과 Role 설정은 기존과 동일합니다.
    Image Modified
  3. 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


  4. Environment variables는 DB_TABLE_NAME에 NewsTable 값을 입력하고, Tags에 Name과 NewsApp을 입력하고, Timeout을 1 min으로 수정합니다.
    Image Modified


8. UpdateNews

...

Lambda 함수 만들기

  1. PostNews와 같이 Create function 버튼을 클릭해서 UpdateNews 함수를 생성합니다. Runtime과 Role 설정은 기존과 동일합니다.
    Image Modified

...

  1. 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


  2. 코드 및 환경 변수 설정

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

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

...