画面のモックができたので、AWSと接続していきましょう。
これから説明する手順で進めると、ソースコード中にAWSの認証情報を含めずにBedrockにアクセスできます。
認証情報をベタ書きしてBedrockを呼び出したいところですがグッとこらえて順に進めてください。
目次
全3回に分けて投稿しています。
- 新年なのでLLMとのチャットアプリをイチから作ってみた①
- 新年なのでLLMとのチャットアプリをイチから作ってみた② ←このページ
- 新年なのでLLMとのチャットアプリをイチから作ってみた③
アーキテクチャの検討
フロントエンドからAWSのバックエンドのBedrockを呼ぶ場合、こういった構成を思い浮かべるのではないでしょうか?
この構成でも良いのですが、Amplifyを使うともっとシンプルな構成にすることができます。
Amplifyの認証機能はCognitoの機能で実現されています。Cognitoには、IDプールの認証情報からIAMの一時クレデンシャルを生成する機能があります。この機能を使うことでフロントエンド(ブラウザ)が一時クレデンシャルをもっている状態になり、ブラウザから直接AWSサービスを呼ぶことが可能になります。
ビジネスロジックをバックエンド側で実装したい場合など、API GatewayとLambdaを使用するケースももちろんあると思いますが、単純にAWSサービスを呼ぶだけであれば、Amplifyを使うと便利です。(API Gatewayにはペイロードサイズやタイムアウトの制限があるので、これらを回避するためにも有効です)
参考:Accessing AWS services using an identity pool after sign-in
他の応用例としてはこのようなものも考えられます。
- S3に直接ファイルをアップロードする。署名付きURLを都度発行する必要なし。
- API Gatewayを挟まず、Lambdaの関数URLを直接呼び出す。最大15分のバックエンド処理が可能。
Amplifyを導入
2024/01/05時点でv5/v6/Gen2と3バージョン混在状態ですが、v6ですすめます。
Amplify Documentation、Set up Amplify CLI、Create your applicationを参考に進めていきましょう。
-
Amplify CLIをインストール
npm install -g @aws-amplify/cli
-
Amplify CLIの設定
ウィザードを進めていきます。
- AWSのマネジメントコンソールが表示されるのでログインします。
- リージョンを選択(ap-northeast-1)
- ドキュメントが開きます。
- IAMのユーザー作成画面が開きます。ドキュメントに従い
AdministratorAccess-Amplify
ポリシーをアタッチしたユーザーを作成し、認証情報を生成します。 - Access KeyとSecret access keyをウィザードに入力します。
- プロファイル名を入力(またはdefaultのまま)します。
-
Amplify Backendの作成
amplify init
- プロジェクト名を入力します。
- プロジェクトの設定を検知してくれるので、そのままYで進めます。
- 先程設定したプロファイルを指定します
-
Amplifyライブラリーのインストール
npm install aws-amplify
-
+page.svelte
のScriptタグ内に以下のコードを追加します。import { Amplify } from "aws-amplify"; import amplifyconfig from "../amplifyconfiguration.json"; Amplify.configure(amplifyconfig);
これでAmplifyの導入は完了です。
Amplifyの認証機能(Cognito)を追加
Cognitoの認証機能を有効化します。Cognitoにはログイン画面が予め用意されているのでこの機能を活用します。
参考:
Add social provider sign-in
AmplifyでCognitoのHosted UIを利用した認証を最低限の実装で動かしてみて動作を理解する
Setting up and using the Amazon Cognito hosted UI and federation endpoints
参考URLはソーシャルログインを使用する感じになってますが、Cognitoのユーザー管理機能だけをでも利用可能です。
-
Amplify Authを追加
amplify add auth
サインインのリダイレクトURLとサインアウトのリダイレクトURLは、どちらも
http://localhost:5173/
と入力します。(末尾は必ず/
で終わる必要があります)Using service: Cognito, provided by: awscloudformation The current configured provider is Amazon Cognito. Do you want to use the default authentication and security configuration? Default configuration with Social Provider (Federation) Warning: you will not be able to edit these selections. How do you want users to be able to sign in? Username Do you want to configure advanced settings? No, I am done. What domain name prefix do you want to use? myskeletonapp77ad9d4f-77ad9d4f Enter your redirect signin URI: http://localhost:5173/ ? Do you want to add another redirect signin URI No Enter your redirect signout URI: http://localhost:5173/ ? Do you want to add another redirect signout URI No Select the social providers you want to configure for your user pool: ✅ Successfully added auth resource myskeletonapp77ad9d4f locally ✅ Some next steps: "amplify push" will build all your local backend resources and provision it in the cloud "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
設定した内容を、AWS環境に反映します。
amplify push
-
ログインボタン、ログアウトボタンを追加
Hubというユーティリティが用意されており、Hosted UIからのリダイレクトを上手に処理してくれます。
以下をScriptタグ内に追加
import { Hub } from "aws-amplify/utils"; import { getCurrentUser, signInWithRedirect, signOut, } from "aws-amplify/auth"; Hub.listen("auth", async ({ payload }) => { console.log(payload); switch (payload.event) { case "signInWithRedirect": getUser(); break; } }); function handleSignInClick() { signInWithRedirect(); } function handleSignOutClick() { signOut(); } let isAuthorizedUser = false; async function getUser() { try { const user = await getCurrentUser(); if (user.userId) { isAuthorizedUser = true; } } catch (Exception) { isAuthorizedUser = false; } } getUser();
HTML部分にヘッダーを追加し、ボタンを配置します。
<AppBar gridColumns="grid-cols-2" slotDefault="place-self-left" slotTrail="place-content-end" > チャットアプリ <svelte:fragment slot="trail"> <button type="button" class="btn btn-sm variant-filled-primary" on:click={handleSignOutClick}>ログアウト</button > <button type="button" class="btn btn-sm variant-filled-primary" on:click={handleSignInClick}>ログイン</button > </svelte:fragment> </AppBar>
-
サインアップしてユーザーを作成
devサーバーを起動して確認してみましょう。
ログインボタンを押すと、Cognitoが用意したログイン画面に遷移します。
Sign up
リンクからユーザーの作成ができます。ログインが成功すると、元の画面に戻ってきます。
このままでは誰でもサインアップできる状態なので、テストで使用するユーザーが作成できたら、セルフサインアップの機能を無効化することをおすすめします。
Amplifyから設定変更する方法が分からなかったので、マネジメントコンソールでの無効化手順です。- Cognito User Poolの管理画面を開きます。
- 対象のユーザープール(おそらく最終更新時刻が最近のもの)を選択します。
-
サインアップエクスペリエンス
タブを選択します。 - セルフサービスのサインアップセクションの編集ボタンから、自己登録の無効化を行います。
ログイン状態によってチャット欄を非表示にしたりするコードを追加しました。(ヘッダー追加によるレイアウト崩れなどにも対応しました。)
認証されたユーザーにBedrockへのアクセス権限を付与
Amplifyで作成されるCognitoのリソースはユーザープールだけでなく、IDプールも作成されます。 CognitoのIDプールの機能で、認証済みユーザーに対してIAMロールが付与されます。(未認証ユーザーにも付与されます。)
このIAMロールにBedrockへアクセスするポリシーを追加します。
参考:Override Amplify-generated project-level IAM resources
-
Amplifyプロジェクトを上書きするファイルを生成
以下のコマンドで
my-skeleton-app/amplify/backend/awscloudformation/override.ts
が生成されます。amplify override project
-
認証ユーザーのロールに、マネージドポリシーを追加します。
override.ts
に以下のコードを記述します。const authRole = resources.authRole; const baseManagedPolicy = Array.isArray(authRole.managedPolicyArns) ? authRole.managedPolicyArns : [authRole.managedPolicyArns]; authRole.managedPolicyArns = [ ...baseManagedPolicy, "arn:aws:iam::aws:policy/AmazonBedrockFullAccess" ]
-
AWS側に反映します。
amplify push
これでCognitoでログインしたユーザーに、Bedrockへのアクセス権限が付与されます。
Bedrockとの統合
いよいよBedrockの出番です。
-
AWS SDKを追加します。
Bedrock RuntimeのSDKを追加します。(
client-bedrock
ではなく、client-bedrock-runtime
です。)npm i @aws-sdk/client-bedrock-runtime
-
Bedrockアクセス部分のコードを追加します。
import { BedrockRuntimeClient, InvokeModelCommand, } from "@aws-sdk/client-bedrock-runtime";
aws-amplify/auth
ライブラリーのfetchAuthSession関数を使用することで、credentialsが取得できます。async function invokeBedrock(prompt: string): Promise<string> { const client = new BedrockRuntimeClient({ region: amplifyconfig.aws_project_region, credentials: (await fetchAuthSession()).credentials, }); const params = { modelId: "anthropic.claude-instant-v1", contentType: "application/json", accept: "*/*", body: JSON.stringify({ prompt: `\n\nHuman: ${prompt}\n\nAssistant:`, max_tokens_to_sample: 1000, temperature: 0.5, top_k: 250, top_p: 1, stop_sequences: ["\n\nHuman:"], }), }; const command = new InvokeModelCommand(params); const response = await client.send(command); return JSON.parse(response.body.transformToString("utf-8"))["completion"]; }
これで認証情報をベタ書きする必要がなくなりました
-
呼び出し元のaddMessageやaddAiMessageを合わせて修正します。
Bedrockとチャットができました!!
Amplifyでホスティング
Amplifyには、フロントエンドのコードをホスティングする機能もあります。作成したチャットアプリをAmplifyにホスティングしてみましょう。
SvelteKitのプロジェクトをAmplifyでホストするために、adapter-static
を使用する必要があるようです。
-
adapter-static
をインストールnpm i -D @sveltejs/adapter-static
-
svelte.config.js
に設定を追加1行目のimport文を、
adapter-static
を参照するように変更します。- import adapter from '@sveltejs/adapter-auto'; + import adapter from '@sveltejs/adapter-static';
adapter()
を変更します。pagesとassetsの値は、amplify init
の際にしれっと設定されていたdistを指定しましょう。- adapter: adapter() + adapter: adapter({ + pages: 'dist', + assets: 'dist', + fallback: 'index.html', + })
-
ソースコードをビルド
buildコマンドでビルドします。
npm run build
dist
ディレクトリにビルド結果が出力されます。 -
Amplify Hostingの設定
Amplify Hostingの設定を行います。ウィザードに従うだけです。
amplify add hosting
✔ Select the plugin module to execute · Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment) ? Choose a type Manual deployment You can now publish your app using the following command: Command: amplify publish
-
公開する
ソースをアップロードして公開します。
amplify publish
✓ built in 9.75s ✔ Zipping artifacts completed. ✔ Deployment complete! https://dev.d2kjvugewtnasz.amplifyapp.com
これで公開されますが、ログインするために、まだもうちょっとやることがあります。
-
サインイン/サインアウト時のドメイン登録
サインイン、サインアウトは事前に登録したドメインからでないと実施できません。Amplify Hostingで発行したドメインを追加します。
amplify update auth
ウィザードに従いながら、サインインとサインアウトにそれぞれドメインを登録します。(ドメインの末尾に
/
を付ける必要があるので注意)Please note that certain attributes may not be overwritten if you choose to use defaults settings. Using service: Cognito, provided by: awscloudformation What do you want to do? Add/Edit signin and signout redirect URIs Which redirect signin URIs do you want to edit? Do you want to add redirect signin URIs? Yes Enter your new redirect signin URI: https://dev.d2kjvugewtnasz.amplifyapp.com/ ? Do you want to add another redirect signin URI No Which redirect signout URIs do you want to edit? Do you want to add redirect signout URIs? Yes Enter your new redirect signout URI: https://dev.d2kjvugewtnasz.amplifyapp.com/ ? Do you want to add another redirect signout URI No ✅ Successfully updated auth resource myskeletonapp77ad9d4f locally ✅ Some next steps: "amplify push" will build all your local backend resources and provision it in the cloud "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud ✅ Successfully updated resource update locally ✅ Some next steps: "amplify push" will build all your local backend resources and provision it in the cloud "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
-
pushとpublish
Cognitoのリソースを更新するために
amplify push
を、ソースコードを更新するためにamplify publish
を実行します。amplify push amplify publish
これで完成です。スマートフォンからも見れます!
単一ページの場合は問題ありませんが、複数ページ構成にした場合、トップページ以外にアクセスすると、エラーになります。
リダイレクト設定を行うことで、複数ページでも動作するようになります。
最低限のチャットが作成できました。次回はもう少し見た目や使い勝手が良くなるように調整していきます。
ソースコードの全体はこちらで確認可能です。
- 該当のソースコード