LambdaとAPI Gatewayを用いて, S3にpdfファイルをアップロード＆ BedRock ナレッジベースを同期

LambdとAPI Gatewayを用いて、S3にファイルをアップロードし、Amazon BedRockのナレッジベースの同期を行ったので、備忘録としてまとめます。クライアントがファイルをアップロードして、それを基にRAGできるようになります。

# ナレッジベースの作成
1. S3 > バケットを作成

1. AmazonBedRock > ナレッジベース > ナレッジベースを作成

1. Choose data sourceでAmazon S3を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/eaf70bc9-3ec9-e463-6e2f-1e0ae559b5ca.png)
1. 「s3を参照」から先ほど作成したS3をデータソースとして選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/efd4da91-7f34-3af7-352f-42036278530d.png)

    ![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333837393337342f62346430366363392d383238302d616163372d396661622d3831663633343236643462302e706e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/da8a8859-7c17-a2d9-ae84-652dadd5e576.png)
1. 適当な埋め込みモデルとベクトル次元を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/4ee06482-573e-4c64-13f3-79ab56a93fc0.png)
1. ナレッジベースを作成
ナレッジベースに戻って、作成できたことをチェック

 # Lambdaを作成
 1. Lambda > 関数作成
 1. - 適当な関数名
    - ランタイム：Python 3.8
    - 実行ロール：新しいロール作成
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/6c0487ce-273d-19d4-77b0-61a0923811a4.png)
1. ロールが自動で作成されるの、権限を付与します

# ロールに権限を付与
1. IAM > ロール > 先ほど作成したロールを選択
1. 許可を追加 > ポリシーをアタッチ
1. AmazonBedrockFullAccessとAmazonS3FullAccessを付与したロールを作成
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/80f82fa8-9663-7ddb-7776-fa509bdb7690.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/681a2570-b468-efe1-e5b0-7ab24d167dda.png)

# API Gatewayを作成
1. Lambda > 関数 > 作成した関数
1. トリガーを追加
1. トリガー設定
    - APIタイプ：REST API
    - セキュリティ：開く
    - バイナリメディアタイプ：multipart/formd-data
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/0cfec117-37a8-38a0-22b7-4a5be4093690.png)

# API Gatewayを作成
1. API Gateway > API > APIを作成
1. REST APIを選択
1. 任意のAPI名を入力
1. APIを作成
1. メソッドを作成
    - メソッドタイプ：POST
    - Lmabda関数：作成したLambda関数
1. メソッドを作成

# コードを編集
1. Lambda > 関数 > 作成した関数
1. コードは以下のものを使用します
```
import json
import boto3
import base64
import io
from datetime import datetime
import cgi

BUCKET_NAME = 'バケット名'
DIRECTORY = 'uploadedfiles/'

s3 = boto3.resource('s3')

def lambda_handler(event, context):
    bucket = s3.Bucket(BUCKET_NAME)

    body = base64.b64decode(event['body-json'])
    fp = io.BytesIO(body)

    environ = {'REQUEST_METHOD': 'POST'}
    headers = {
        'content-type': event['params']['header']['content-type'],
        'content-length': str(len(body))
    }

    fs = cgi.FieldStorage(fp=fp, environ=environ, headers=headers)
    for f in fs.list:
        print("filename=" + f.filename)
        bucket.put_object(Body=f.value, Key=DIRECTORY + f.filename)

    client = boto3.client('bedrock-agent')

    response = client.start_ingestion_job(
        dataSourceId='データソースID',
        knowledgeBaseId='ナレッジベースID'
    )

    return {
        "Access-Control-Allow-Headers": "Content-Type",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "POST",
        "Content-Type": "multipart/form-data",
        'statusCode': 200,
        'body': json.dumps('アップロード完了')
    }
```
# バケット名とナレッジベース
コードにS3のバケット名とナレッジベースのデータソースID, ナレッジベースIDを入力します

# APIの設定
1. 1. API Gateway > API >作成したAPI
1. APIの設定
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/56420cc8-d807-4087-b00f-d9623a4aba39.png)
1. バイナリメディアタイプを管理からmultipart/form-dataを追加
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/df3a5e67-3d3c-5a31-622b-9b1061ee066c.png)
このままだとCORSエラーになるのでCORSの設定をします
1. CORSを有効にする
1. Access-Control-Allow-MethodsでPOSTを選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/c575aeb1-c9d4-46d6-e32c-9bdd29f16e2b.png)
1. 保存
1. リソースからOPTIONを選択
1. 統合レスポンスを編集
1. マッピングテンプレート
    - コンテンツタイプ：multipart/form-data
    - テンプレートを作成からメソッドリクエストのパススルーを選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/6fba29cb-cefe-019b-0ea6-e36c3c38ea26.png)
1. 保存
1. メソッドレスポンス
    - レスポンス本文：multipart/formdata

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879374/4e685dee-5bb4-f75e-afee-e6e70c547543.png)
1. 保存
1. リソースからPOSTを選択
1. 同様に同号レスポンスを編集からmultipart/formを追加
1. 保存したらAPIをデプロイ

# あとがき
CORSのエラーに手を焼きました。

# 参考サイト
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors-console.html

https://qiita.com/nyaao/items/08e78c11b1ff2c366c0b

https://qiita.com/infra365/items/06b235be56e93ff45cdc