+6

[AWS Serverless] - Sử dụng Step Function để xây dựng API xác định cảm xúc của khách hàng trong feedback

Serverless là gì

Hãy xem lại bài viết này của mình để nắm căn bản phần Serverless này.

Mô hình hệ thống chúng ta sẽ xây dựng hôm nay

lhjaslqwe.jpg

Giới thiệu AWS Step function - Hỗ trợ Lowcode và Workflow trên AWS

AWS Step function hỗ trợ chúng ta xây dựng các workflow kết nối nhiều service của AWS lại trên một giao diện trực quan và dễ hiểu. Dễ dàng trình bày và trực quan khi trao đổi và thể thiện trên tài liệu. Như hình bên dưới:

image.png

Theo mình thấy điểm mạnh của dịch vụ này so với các dịch vụ tương đương trên thị trường và nó cho phép tích hợp nhanh với các dịch vụ khác trên AWS nhanh, thậm chí không cần đến ngôn ngữ lập trình. Trong bài viết này mình cũng chỉ sử dụng Serverless Framework để provision các resource của AWS chứ cũng không dùng ngôn ngữ lập trình khi xử lý business.

Các bạn có thể vào link Workshop này để xem thêm các showcase và tutorial nhé. https://catalog.workshops.aws/stepfunctions/en-US

Chuẩn bị môi trường

  1. Cài đặt Nodejs(Vì mục 2 cài bằng NPM), chi tiết ở link này
  2. Cài đặt Serverless Framework, chi tiết ở link này
  3. Cài đặt AWS CLI, chi tiết ở link này
  4. Do ví dụ sử dụng lệnh make nên mình sử dụng Ubuntu/MacOS.

Cài đặt AWS CLI để kết nối tài khoản AWS của bạn

aws configure

Các bạn cài đặt Client ID và Client Secret như bên dưới, 2 thông số còn lại optional bạn không cài cũng được.

AWS Access Key ID [****]:
AWS Secret Access Key [****]:
Default region name [us-west-1]: 
Default output format [None]:

Chúng ta hãy xem trước Workflow mà chúng ta sẽ xây dựng hôm nay

image.png

Trong mô hình trên chúng ta sẽ đi qua các bước:

  1. Chúng ta sẽ dịch từ tiếng việt qua tiếng anh thông qua Amazon Translate, một AI dịch thuật của AWS. (bởi vì AI detect cảm xúc chỉ hiểu tiếng anh nên mình tạo ra work-around chỗ này)
  2. Chúng ta sẽ dùng Amazon Comprehend để đọc đoạn message (feedback của khách hàng) để xác định cảm xúc của khách hàng là tiêu cực hay tích cực, hoặc bình thường.
  3. Nếu chúng ta phát hiện cảm xúc tiêu cực trong message (NEGATIVE) thì chúng ta sẽ insert vào DynamoDB (Giả định sẽ có một bộ phận chăm sóc khách hàng sẽ vào kiểm tra các feedback đó)
  4. Nếu cảm xúc là tích cực (POSITIVE) hoặc bình thường (NEUTRAL) thì chúng ta kết thúc flow, không xử lý gì thêm.

Hãy xem cấu trúc chính của sourcecode nào !

Các bạn clone sourcecode mình viết về máy bằng lệnh bên dưới (hãy cho mình một star để ủng hộ mình ra thêm nhiều bài viết và source mẫu nhé):

git clone https://github.com/tanthanhkid/serverless-aws-golang-boilerplate-stepfunction.git

Đầu tiên chúng ta xem file serverless.yml để xem các thành phần mà source Serverless này sẽ tạo trên account AWS của chúng ta.

serverless.yml

Đoạn này nói cho chúng ta biết sourcecode này sẽ deploy lên tài khoản AWS với runtime của Golang và version 1.x ở Region ap-southeast-1 (Singapore). Ngoài ra, bên dưới còn cho chúng ta điền thêm một biến môi trường của Lambda, nơi chúng ta sẽ để connection string và để khi code chạy sẽ lấy connection string từ đây ra để kết nối vào DB Instance.

provider:
  name: aws
  runtime: go1.x
  region: ap-southeast-1 

Đoạn code bên dưới mình có bổ sung thêm phần bảo mật, Bởi vì API của chúng ta public internet, nên việc vô tình lộ URL và Request có thể dẫn tới bị tấn công từ các bên có chủ đích phá hoại. Hậu quả có thể xảy ra là dịch vụ của chúng ta bị dừng hoạt động hoặc quá tải, bill AWS tăng đột biến.

Cách xử lý là chúng ta phải có một x-api-key(được in ra trong console sau khi deploy serverless hoặc các bạn vào AWS Console để lấy) gắn vào header như sau:

image.png

plugins:
  - serverless-add-api-key  # plugin này cho phép chúng ta tạo thêm apikey và usageplan để bảo vệ API khi public
  - serverless-step-functions # plugin này hỗ trợ chúng ta tạo step function

custom:
  apiKeys:
    dev:
    - name: stepfunction-viblo
      usagePlan:
        name: "stepfunction-viblo" 
        description: "stepfunction-viblo usage plan demo"
        quota:
          limit: 10000
          period: MONTH
        throttle:
          burstLimit: 100
          rateLimit: 20

Chúng ta sẽ cần DynamoDB để lưu trữ các feedback tiêu cực từ khách hàng, sau khi Amazon Comprehend chạy xong.

# từ dòng 87

NEGATIVEFEEDBACK:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: NEGATIVE_FEEDBACK # Tên table của chúng ta là NEGATIVE_FEEDBACK
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: ID # Đây chúng ta sẽ lưu UUID của các lần chạy Step Function 
            AttributeType: S
        KeySchema:
          - AttributeName: ID
            KeyType: HASH

Tiếp theo, chúng ta sẽ tạo IAM Role và đính kèm các Policy cần thiết để Step Function của chúng ta có đủ các quyền để sử dụng các dịch vụ có liên quan trong Workflow.

# từ dòng 98

    StateMachineRole:
      Type: AWS::IAM::Role
      Properties:
        RoleName: CustomerFeedbackSentimentRole
        Path: /path_of_state_machine_roles/
        AssumeRolePolicyDocument:
          Statement:
          - Effect: Allow
            Principal:
              Service:
                - states.amazonaws.com
            Action:
              - sts:AssumeRole
        Policies:
          - PolicyName: statePolicy
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action: # ở môi trường prod đừng cho quyền fullaccess như bên dưới, chỉ áp dụng ở môi trường lab
                    - 's3:*' 
                    - 'dynamodb:*'
                    - 'translate:*'
                    - 'comprehend:*' 
                  Resource: "*"

Tới nhân vật chính của chúng ta là Step Function.

# từ dòng 124

stepFunctions:
  stateMachines:
    myStateMachine:
      name: CustomerFeedbackSentiment # Đây là tên mà mình chọn
      role:
        Fn::GetAtt: ["StateMachineRole", "Arn"] # Ở đây chỉ định là Step Function này sẽ có Role mới tạo phía trên
      events:
        - http:
            path: action/detectsentiment # Phần này giúp tạo ra một API Public ra ngoài để chúng ta test bằng Postman cho tiện, cũng dùng để cho các hệ thống khác gọi được
            method: POST
            private: true # Bật cờ này lên thì API này sẽ yêu cầu API Key để xác thực trước khi cho phép xử lý tiếp (an toàn tí)
      definition: # Phần này là phần chính của Workflow
        StartAt: TranslateText
        States:
          TranslateText: # Ở đây chúng ta sẽ gọi Amazon Translate để dịch từ VI -> EN
            Type: Task
            Resource:
              arn:aws:states:::aws-sdk:translate:translateText
            Parameters:
              SourceLanguageCode: vi
              TargetLanguageCode: en
              Text.$: $.Comment # Input của chúng ta sẽ truyền vào đây, lưu ý các biến nhớ có "$." phía trước
            ResultPath: $.translatedOutput # Output của bước này sẽ tên là translatedOutput
            Next: DetectSentiment
          DetectSentiment: # Ở đây mình gọi tiếp tới Amazon Comprehend để lấy kết quả dịch ra tiếng anh phía trên để cho AI đoán xem cảm xúc trong câu nói này là gì
            Type: Task
            Resource:
              arn:aws:states:::aws-sdk:comprehend:detectSentiment
            Parameters:
              LanguageCode: en
              Text.$: $.translatedOutput # truyền đoạn tiếng anh vừa dịch phía trên ra vào đây
            ResultPath: $.translatedOutput
            Next: Is this a Negative feedback ?
          Is this a Negative feedback ?:  # Phần này mình sẽ kiểm tra kết quả, bạn hiểu nó như IF/ELSE trong lập trình bình thường cũng được
            Type: Choice
            Choices: 
            - Variable: "$.translatedOutput.Sentiment"
              StringMatches: 'NEGATIVE'   # Mình kiểm tra nếu kết quả khớp chuỗi "NEGATIVE" hay không
              Next: DynamoDB PutItem # Nếu khớp mình sẽ insert vào DB
            Default: Success # Không khớp mình kết thúc flow
          Success:
            Type: Succeed
          DynamoDB PutItem: # Ở đây mô tả Task insert dữ liệu mới vào DB
            Type: Task
            Resource:
              arn:aws:states:::dynamodb:putItem
            Parameters:
              TableName: NEGATIVE_FEEDBACK # Tên table mình chỉ định ở đây
              Item: # các cột và dữ liệu mình mô tả ở trường Item này
                ID:
                  S.$: $$.Execution.Name # mình dùng UUID của step function cho mỗi lần chạy làm ID của DB luôn
                COMMENT:
                  S.$: $.Comment # mình đưa lại input ban đầu vào đây để bộ phận chăm sóc khách hàng đọc lại
            End: true

Chạy thôi nào!

Nếu các bạn sử dụng Ubuntu và MacOS thì chỉ cần chạy lệnh bên dưới ở ngoài root:

make deploy

Các bạn truy cập vào tài khoản AWS của mình, sau đó vào Cloudformation và chọn stack có tên bắt đầu bằng "goservice-stepfunction-viblo".

Vào tab Output để lấy API Endpoint.

image.png

Hãy thử nào dùng AI của chúng ta nào !

image.png

Chúng ta lên xem Step Function của chúng ta xử lý như thế nào bên dưới nhé.

image.png

Đi đúng luồng mong muốn rồi. Chúng ta kiểm tra DynamoDB xem được insert chưa:

image.png

Bây giờ cùng thử một câu feedback vui vẻ.

image.png

Vào Step function kiểm tra thì kết quả như mong đợi, POSITIVE sẽ không insert vào DB.

image.png

Chúc các bạn thành công !


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.