【AWS SAP 対策講座】Lambda関数のCORS設定を理解したので、Bedrockのチャットボット画面を作成したい～まだ会話蓄積できないよ～

# はじめに

https://qiita.com/Jasmine_teeeeee/items/b4973a40750348a0d0e3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/9401c45d-31b7-4165-8610-6fef27fe5f0c.png)

直接APIを実行できることが確認出来たら、画面を作ってみましょう。

こんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/0fffb576-739c-4e40-b790-9011e07ecce7.png)

以下コードの＜ここは自分の関数URLの値を入れてください＞をご自身の関数URLの値に書き換えてから、
ローカルの任意のフォルダに格納し、ブラウザで開いてみてください。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Lambda GET Request Form</title>
    <style>
        body {
            font-family: sans-serif;
            max-width: 800px;
            margin: 20px auto;
            padding: 0 20px;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
        }
        textarea {
            width: 100%;
            min-height: 100px;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }
        button {
            background-color: #007bff;
            color: white;
            padding: 12px 24px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #0056b3;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        #result {
            margin-top: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
            display: none;
            background-color: #f8f9fa;
        }
        .loader-container {
            display: none;
            text-align: center;
            margin-top: 20px;
        }
        .loader {
            border: 5px solid #f3f3f3;
            border-top: 5px solid #007bff;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 1.5s linear infinite;
            margin: 0 auto;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .loader-text {
            margin-top: 10px;
            font-size: 14px;
            color: #666;
        }
    </style>
</head>
<body>
    <h1>GET Request Formを作ってみた</h1>

    <p>以下のフォームからGETリクエストを送信して、Lambda関数を呼び出してみます。</p>
    
    <form id="getForm" onsubmit="sendGetRequest(event)">
        <div class="form-group">
            <label for="prompt">プロンプト:</label>
            <textarea id="prompt" name="prompt" required>ジャスミン茶の原料</textarea>
        </div>
        
        <button type="submit" id="submitButton">送信</button>
    </form>

    <div class="loader-container" id="loaderContainer">
        <div class="loader"></div>
        <div class="loader-text">APIリクエスト処理中...</div>
    </div>

    <div id="result"></div>

    <script>
        async function sendGetRequest(event) {
            event.preventDefault();
            
            // ローディング表示を開始
            const loaderContainer = document.getElementById('loaderContainer');
            const submitButton = document.getElementById('submitButton');
            const resultDiv = document.getElementById('result');
            
            // 以前の結果を非表示にする
            resultDiv.style.display = 'none';
            // ローダーを表示
            loaderContainer.style.display = 'block';
            // 送信ボタンを無効化
            submitButton.disabled = true;
            
            const prompt = document.getElementById('prompt').value;
            const escapedPrompt = encodeURIComponent(prompt);
            const url = `https://＜ここは自分の関数URLの値を入れてください＞.lambda-url.us-west-2.on.aws/?prompt=${escapedPrompt}`;

            try {
                const response = await fetch(url, {
                    method: 'GET',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    mode: 'cors', // CORSモードを明示的に設定
                });
                
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                
                const data = await response.json(); // JSONとしてパース
                
                // 結果を表示
                resultDiv.style.display = 'block';
                resultDiv.innerHTML = `
                    <h3>送信結果:</h3>
                    <p><strong>送信URL:</strong> ${url}</p>
                    <p><strong>プロンプト:</strong> ${prompt}</p>
                    <p><strong>エスケープ後:</strong> ${escapedPrompt}</p>
                    <h4>レスポンス:</h4>
                    <pre>${JSON.stringify(data, null, 2)}</pre>
                `;
            } catch (error) {
                resultDiv.style.display = 'block';
                resultDiv.innerHTML = `
                    <h3>エラー発生:</h3>
                    <p>送信URL: ${url}</p>
                    <p>エラー内容: ${error.message}</p>
                `;
            } finally {
                // ローディング表示を終了
                loaderContainer.style.display = 'none';
                // 送信ボタンを再度有効化
                submitButton.disabled = false;
            }
        }
    </script>
</body>
</html>
```

テキストエリアに任意のプロンプトを入力して、送信ボタンをクリックすると関数URLを実行します。
しかし以下のようなエラーが発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/33e6d4e7-5701-4a65-804e-91cf1d89a03e.png)

# 手順

## ローカルで実行

### Lambda関数のCORS設定

「Access-Control-Allow-Origin」が許可されてないと怒られているので、追加します

設定　＞　関数 URL　から編集をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/4237a6c5-6659-4f0c-a7ad-984f39f40784.png)

CORSの設定を変更します。
・公開ヘッダー：access-control-allow-origin
・許可ヘッダー：content-type
・許可メソッド：GET、POST

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/16acae6e-9c74-4b2f-8530-70b0ca8fdc28.png)

※こんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/d397f275-7c46-477c-84ff-5913ed0468d2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/3145daf5-e9e0-4145-bb48-f0285208aec1.png)

保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/06b49b68-333d-4868-9543-f04df5d9fc63.png)

再度画面から実行すると成功します！やったね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/5adcb66a-4c51-43f5-b69f-f3ad54422f4d.png)

### 500系エラーで失敗する場合

timeout時間が短い可能性があります。

以下手順で20秒くらいに増やしてみてください。

https://qiita.com/Jasmine_teeeeee/items/74eebc784da34c523d1f#timeout%E3%81%AE%E6%99%82%E9%96%93%E3%82%92%E5%BB%B6%E3%81%B0%E3%81%99

## S3に格納して公開してみる

今の状態ではローカルでしか画面が見れないので上司に自慢できません。
S3に配置して公開してみましょう。

S3を選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/14b9eca1-f129-4785-951c-74c68b98970f.png)

### バケットを作成

バケットを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/612a874c-ca2e-4c6b-81a0-53641accf1bc.png)

名前を入力して、アクセス設定を以下のように設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/a34b9f2c-9bb0-4b45-a3ca-f8ec8a5add30.png)

他はデフォルトのままで、バケットを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/81000926-e6c7-4a76-8147-81bf33969095.png)

### 静的ウェブサイトホスティングの設定

作成したバケットを検索して、クリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/3e73ca71-1f01-482b-85fb-b352066b4e7d.png)

プロパティページ一番下の「静的ウェブサイトホスティング」の編集をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/d16cf60e-134b-4b6b-9a8e-9e14184cc796.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/a376fbb5-5640-4b37-b55c-6961a7d63e02.png)

静的ウェブサイトホスティングのラジオボタンで有効にするを選択すると、いろいろ出てきます。
インデックスドキュメントに index.htmlをとりあえず設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/2fc49fcf-a9da-4bc6-874c-daa81d661539.png)

保存

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/ba123069-c9cb-4a33-b316-221f688ab663.png)

### バケットポリシーの設定

バケットポリシーの編集をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/19b6ded4-f681-4cbc-bfcb-5594ff8a81d8.png)

赤枠にポリシーを設定して保存

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/fa4e8c49-930b-44ca-993a-958168ebf2eb.png)

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3のPath>/*"
        }
    ]
}
```

### 画面のファイルをアップロード

オブジェクトのアップロードボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/35eed27d-c096-497d-b116-01da74ac2324.png)

ローカルで確認したHTMLファイルをドラッグアンドドロップでファイルを追加して、アップロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/04dc2e23-c65b-40df-9fbe-aa64021bc7ee.png)

完了画面を閉じます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/c0cb7912-ce84-4a16-be28-9dea4dbb3519.png)

プロパティページの一番したにURLがあるのでクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/8b957c45-baf0-4f35-8370-0ad41855c9cb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/88752ac8-6556-4984-8464-7d6288b8748c.png)

画面が開けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/26415e8a-ab59-44b6-bb11-02c68a7b958c.png)

送信ボタンを押してみると、APIが呼ばれたことが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/1fd6d176-0c94-4b41-8a0d-facd474dd389.png)

やったー！！！