AWS AI Services にハンズオンで入門してみた

# はじめに
4月22日に行われたAWS主催の「さぁ！サーバーレスを始めよう！サーバーレスハンズオンもくもく会」に参加し、その際に行ったハンズオン「[音声文字起こし & 感情分析 パイプライン編](https://pages.awscloud.com/event_JAPAN_Ondemand_Hands-on-for-Beginners-Serverless-3_LP.html)」の備忘録となります。

# 目的
AWSは触らないと忘れる！だから触る！！うおおおおおおお！！

# ハンズオンの内容
>AWS Hands-on for Beginners - Serverless #3 では、AWS Lambda と AWS の各種 AI サービスを組み合わせて、“音声ファイルがアップロードされると文字起こしと感情分析を自動的に行う” パイプラインを構築していきます。これまでのハンズオンでは、Amazon API Gateway と AWS Lambda との組み合わせを試してきましたが、AWS Lambda は他にも多くの AWS サービスと連携できます。このハンズオンでは、Amazon S3 へのファイルアップロードをトリガーに Lambda Function を実行する機能を利用し、パイプラインを構築します。また、AWS には多くの AI サービスがあり、このハンズオンをきっかけに、皆様のプロダクト開発に活かせる AI サービス群を知っていただければと考えています。

SUGOSUGI⭐️
これが無料で受けれるなんて・・・

# やってみた
## AWS Lambda と他の AWS サービスとの連携パターン
**Lambdaの使われ方**
1. Lambda関数を同期的に呼び出す
　　- 実行が終わるのを待つ
　　- イベントソースに実行結果返される（WebAPIとか）
2. Lambda関数を非同期的に呼び出す
　　- イベントソースに実行結果は返されない
　　- エラー時
　　　　- 実行時：リトライ回数指定可能
　　　　- 同時実行数不足：リトライ期間を設定可能
　　- 利用ケース
　　　　- Lambda側が処理を待つ必要がない時
　　　　- Lambda川の処理に時間がかかる時
3. Lambdaがイベントを読み取る（ポーリングする）
　　- ストリームベース
　　　　- DynamoDB Streams/Kinesis Data Streams
　　　　- イベントソースに対して、新しいレコードがないかをポーリング
　　　　- 失敗レコードの有効期限切れ・処理が成功するまでそのシャードからの読み込みが行われない
　　- ストリームベースでない
　　　　- SQS
　　　　- Lambdaがイベントソースに対して、新しいレコードがないかをポーリング
　　　　- 失敗した場合、メーセージはキューに戻り、Visibility Timeout後に再度処理が行われる

[上記はこちら参照すると良さげ](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-services.html)

## S3 トリガーで Lambda ファンクションを起動する

1. S3でインプット用のバケットを作成する
2. Lambdaを作成する
    1. 設計図の使用からs3で検索してs3-get-object-python を選択する
    2. Name等を入力してS3トリガーの設定を行う（トリガーの有効化をONに）
    3. 関数の作成をクリック
3. さっき作ったS3バケットのプロパティを開きEventを確認する

## Amazon Transcribe を使って文字起こしを試してみる

Amazon Transcribeの特徴
1. 音声をテキストに変換する文字起こしサービス
　　- 保存されたファイルに加えて、リアルタイムでも可能
2. ユースケース
　　- 記者会見やインタビュー
　　- 動画コンテンツ
　　- コールセンター業務の通話の文字起こし
 
Handson
1. S3でアウトプット用のバケットを作成
2. Amazon TranscribeでJobを作成する
　　- inputdataをS3のコピーパスで入力
　　- Outputdataを先ほど作成したバケットを指定
3. 完了まで待機
4. Outputバケットに結果が格納されていることを確認する

## S3 への音声ファイルアップロードをトリガに Lambda を起動し Transcribe するパイプラインを作る

handson
1. Lambdaの設定を修正する
　　1. 画面上のアクセス権限から既存のロール名をクリック
　　2. ポリシーをアタッチからAmazonTranscribeFullAccess、AmazonS3FullAccessをアタッチ
2. Lambdaのスクリプトを下記に修正する（保存を忘れないように！）

```python:lambda_function.py
import json
import urllib.parse
import boto3
import datetime

s3 = boto3.client('s3')
transcribe = boto3.client('transcribe')

def lambda_handler(event, context):

    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        transcribe.start_transcription_job(
            TranscriptionJobName=datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '_transcription',
            LanguageCode='ja-JP',
            Media={
                'MediaFileUri': 'https://s3.ap-northeast-1.amazonaws.com/' + bucket + '/' + key
            },
            OutputBucketName='*マイバケットネーム*'
        )

    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
```

## パイプラインで文字起こししたテキストを Comprehend で感情分析する
Amazon Comprehendの特徴
1. 機械学習を使用した自然言語処理サービス
　　1. テキストの中の有用情報を発見・分析
　　2. キーフレーズやエンティティ（場所・日付）の取得、感情分析
2. ユースケース
　　1. 社内ドキュメントのキーフレーズやエンティティを検索エンジンでインデックス
　　2. レビューやアンケート結果、ソーシャルメディアからのFeedbackを感情分析


handson
1. output用のバケットから発火するComprehend使う用のLambdaを作成
　　1. IAMroleを新規作成
　　2. S3トリガーでサフィックスを.jsonで設定する
　　3. IAMroleにComprehendFullAccess,AmazonS3FullAccessをアタッチする
2. 作成したLambdaのスクリプトを下記に修正する（保存を忘れないように！）

```python:lambda_function.py
import json
import urllib.parse
import boto3

s3 = boto3.client('s3')
comprehend = boto3.client('comprehend')

def lambda_handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        body = json.load(response['Body'])
        transcript = body['results']['transcripts'][0]['transcript']
        
        sentiment_response = comprehend.detect_sentiment(
            Text=transcript,
            LanguageCode='ja'
        )
        
        sentiment_score = sentiment_response.get('SentimentScore')
        print(sentiment_score)

    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
```

インプット用のS3バケットにファイルを置いて、結果をCloudWatchから確認する。

## [Option] Amazon Polly で作成した音声ファイルをパイプラインに投入する
Amazon Pollyの特徴
1. テキストを音声に変換するサービス
　　1. 複数言語サポート（日本語OK）
　　2. SSMLやLexiconが可能！
2. ユースケース
　　1. カスタマーセンターの自動音声応答
　　2. テキストを音声に変換する

handson
1. Amazon Pollyを開く
2. テキスト読み上げ機能のプレーンテキストに好きな文字列を記入してS3にむけて合成をクリック
3. 先ほど作成したインプット用のS3を出力バケットに設定する
4. comprehendのLambdaのCloudwatchLogsを確認する

# 感想
こんな短時間で、音声ファイルの文字起こしや感情分析などのパイプラインを作成できることに感動した。
ちょっとした遊びでも使いやすいし、サーベイなどを分析したいときに是非参考にしたい。
すぐに自分のプロジェクトに組み込めるイメージを得れたので、AWSに触れる全員におすすめしたハンズオンだった