Lambda から Lex Bot のDRAFT バージョンをビルドする

# はじめに
本記事では、AWS Lambda のスクリプトからLex Bot のビルド処理を実装していきます。


# 環境
- Python：3.12
- Lex：v2

# ゴール
- Lambda 関数を実行し Lex Bot の DRAFT バージョンをビルドする
- ビルド後にBotが使用可能な状態になっている事を確認する

# 前提
- Lexのボットは作成されてる事

# Lambdaの作成

- `get_draft_status`：describe_bot_locale API を使用して、Bot の現在のステータスを取得します。
- `wait_for_build_completion`：ビルドが完了するまで5秒ごとにステータスを確認し、"Built" または "Failed" になるまで待機します。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models/client/describe_bot_locale.html

```python:lex_utils.py
import time

# DRAFTステータスを取得
def get_draft_status(client, bot_id, locale_id):
    response = client.describe_bot_locale(
        botId=bot_id,
        botVersion='DRAFT',
        localeId=locale_id
    )
    return {
        'buildStatus': response['botLocaleStatus'],
        'lastBuildDateTime': str(response.get('lastBuildSubmittedDateTime'))
    }


# ビルドの完了を待機
def wait_for_build_completion(client, bot_id, bot_version, locale_id):
    while True:
        response = client.describe_bot_locale(
            botId=bot_id,
            botVersion=bot_version,
            localeId=locale_id
        )
        print(f"現在のビルドステータス: {response['botLocaleStatus']}")
        
        # ビルドが完了（成功 or 失敗）したかチェック
        if response['botLocaleStatus'] in ['Built', 'Failed']:
            break
        
        # 5秒待機してから再度ステータスをチェック
        time.sleep(5)
```

- `lambda_handler`：Lambda のエントリーポイント。詳細はコメントアウトの通りです。

:::note info
- 環境変数 `BOT_ID`（BotのID） と `LOCALE_ID`（日本語なら `ja_JP`） を設定
  - Supported languages and locales：https://docs.aws.amazon.com/lexv2/latest/dg/how-languages.html#supported-languages
- LexにアクセスするためのIAMの権限設定が必要です
:::

```python:lambda_function.py
import boto3
import json
import os
from lex_utils import get_draft_status, wait_for_build_completion

def lambda_handler(event, context):
    lex_client = boto3.client('lexv2-models')
    bot_id = os.environ['BOT_ID']
    locale_id = os.environ['LOCALE_ID']
    
    try:
        # ビルド前の DRAFT ステータスを取得
        pre_build_status = get_draft_status(lex_client, bot_id, locale_id)
        print(f"ビルド前の DRAFT ステータス: {json.dumps(pre_build_status)}")
        
        # DRAFT バージョンをビルド
        lex_client.build_bot_locale(
            botId=bot_id,
            botVersion='DRAFT',
            localeId=locale_id
        )
        
        # ビルドの完了を待機
        wait_for_build_completion(lex_client, bot_id, 'DRAFT', locale_id)
        
        # ビルド後の DRAFT ステータスを取得
        post_build_status = get_draft_status(lex_client, bot_id, locale_id)
        print(f"ビルド後の DRAFT ステータス: {json.dumps(post_build_status)}")
        
        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'ボットの DRAFT ビルドプロセスが完了しました',
                'preBuildStatus': pre_build_status,
                'postBuildStatus': post_build_status,
                'buildSuccess': post_build_status['buildStatus']
            }, ensure_ascii=False)
        }
    except Exception as e:
        print(f"Error during build process: {str(e)}")
        return {
            'statusCode': 500,
            'body': json.dumps({
                'message': 'ボットのビルド中にエラーが発生しました',
                'error': str(e)
            }, ensure_ascii=False)
        }
```

# 動かしてみる

:::note warn
Lambda 関数の実行時間
デフォルトだと3秒になっていますがそれ以上かかると思うので、本記事では `1分` と設定しています。
:::


Lambdaをテスト実行すると下記のように200でレスポンスが返ってきました。

```:レスポンス
{
  "statusCode": 200,
  "body": {
    "message": "ボットの DRAFT ビルドプロセスが完了しました",
    "preBuildStatus": {
      "buildStatus": "Built",
      "lastBuildDateTime": "2024-09-22 08:24:23.275000+00:00"
    },
    "postBuildStatus": {
      "buildStatus": "Built",
      "lastBuildDateTime": "2024-09-22 08:59:34.039000+00:00"
    },
    "buildSuccess": "Built"
  }
}
```

CloudWatchのログでは、BotのビルドステータスがBuilding⇒ReadyExpressTesting⇒Builtとなっている事を確認できます。ビルドが完了し使用可能な状態（Built）になっている事を確認できました。

https://docs.aws.amazon.com/lexv2/latest/APIReference/API_BuildBotLocale.html#API_BuildBotLocale_ResponseSyntax

```:CWログ
ビルド前の DRAFT ステータス: {"buildStatus": "Built", "lastBuildDateTime": "2024-09-22 08:24:23.275000+00:00"}
現在のビルドステータス: Building
現在のビルドステータス: Building
現在のビルドステータス: Building
現在のビルドステータス: ReadyExpressTesting
現在のビルドステータス: ReadyExpressTesting
現在のビルドステータス: ReadyExpressTesting
現在のビルドステータス: ReadyExpressTesting
現在のビルドステータス: Built
ビルド後の DRAFT ステータス: {"buildStatus": "Built", "lastBuildDateTime": "2024-09-22 08:59:34.039000+00:00"}
```

# 参考
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models/client/build_bot_locale.html
- https://docs.aws.amazon.com/lexv2/latest/APIReference/API_BuildBotLocale.html#API_BuildBotLocale_ResponseSyntax
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models/client/describe_bot_locale.html
- https://docs.aws.amazon.com/lexv2/latest/APIReference/API_BuildBotLocale.html#API_BuildBotLocale_ResponseSyntax
- https://docs.aws.amazon.com/lexv2/latest/dg/how-languages.html