はじめに
皆さん、こんにちは。
私は業務でデータ利活用基盤を取り扱っていること、2024 AWS Japan Top Engineer に選出されたということから、AWS GenU およびそれに必要なデータ基盤の探求 (Snowflake, dbt, Iceberg, etc) に取り組む必要があると考えています。
本投稿では、GenU のバックエンドである CDK コードを詳細に解説します。
自身そして閲覧して頂いた皆様の GenU への理解が少しでも深まり、生成 AI の民主化につながっていければと考えています。
前回までのおさらい
前回までで、以下が完了しました。
- ①AWS CDK のセットアップ
- ②AWS CDK の動作確認
- ③GenU の概要
- ④GenU CDK スタックの概要
- ⑤CloudFrontWafStack スタックの解説
- ⑥RagKnowledgeBaseStack スタックの解説
- ⑦WebSearchAgentStack スタックの解説
- ⑧GuardrailStack スタックの解説
- ⑨GenerativeAiUseCasesStack > Auth スタックの解説
- ⑩GenerativeAiUseCasesStack > Database, Api スタックの解説
- ⑪GenerativeAiUseCasesStack > CommonWebAcl, Web, Rag スタックの解説
GenU の CDK は最大で以下の 6 つの子スタックを作成します。
CloudFrontWafStackRagKnowledgeBaseStackAgentStackGuardrailStack-
GenerativeAiUseCasesStack※メインスタック DashboardStack
第 9 回から GenU 内の本丸である GenerativeAiUseCasesStack スタックを解説しています。
GenerativeAiUseCasesStack スタック
GenerativeAiUseCasesStack スタックでは、以下のリソースを作成しています。
AuthDatabaseApiCommonWebAclWebRagRagKnowledgeBaseUseCaseBuilderTranscribe
今回は RagKnowledgeBase, UseCaseBuilder, Transcribe リソースを解説していきます。
GenerativeAiUseCasesStack > RagKnowledgeBase リソース
RagKnowledgeBase リソースは、アーキテクチャ図でいうと以下の赤枠の部分にあたります。
RagKnowledgeBase では ナレッジベースから情報を取得する API を定義しています。
以下のソースコードが RagKnowledgeBase の定義です。
// RAG Knowledge Base
if (params.ragKnowledgeBaseEnabled) {
const knowledgeBaseId =
params.ragKnowledgeBaseId || props.knowledgeBaseId;
if (knowledgeBaseId) {
new RagKnowledgeBase(this, 'RagKnowledgeBase', {
modelRegion: params.modelRegion,
knowledgeBaseId: knowledgeBaseId,
userPool: auth.userPool,
api: api.api,
});
// File API から data source の Bucket のファイルをダウンロードできるようにする
if (props.knowledgeBaseDataSourceBucketName) {
api.allowDownloadFile(props.knowledgeBaseDataSourceBucketName);
}
}
}
RagKnowledgeBase リソースの実体は packages/cdk/lib/construct/rag-knowledge-base-stack.ts にあります。
スタック作成時のパラメータ ragKnowledgeBaseEnabled (デフォルト値は false) が true の場合、以下のコードを実行し RagKnowledgeBase を作成します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import { UserPool } from 'aws-cdk-lib/aws-cognito';
import {
AuthorizationType,
CognitoUserPoolsAuthorizer,
LambdaIntegration,
RestApi,
} from 'aws-cdk-lib/aws-apigateway';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
export interface RagKnowledgeBaseProps {
// Context Params
modelRegion: string;
// Resource
knowledgeBaseId: string;
userPool: UserPool;
api: RestApi;
}
export class RagKnowledgeBase extends Construct {
constructor(scope: Construct, id: string, props: RagKnowledgeBaseProps) {
super(scope, id);
const { modelRegion } = props;
const retrieveFunction = new NodejsFunction(this, 'Retrieve', {
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/retrieveKnowledgeBase.ts',
timeout: cdk.Duration.minutes(15),
environment: {
KNOWLEDGE_BASE_ID: props.knowledgeBaseId,
MODEL_REGION: modelRegion,
},
});
retrieveFunction.role?.addToPrincipalPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [
`arn:aws:bedrock:${modelRegion}:${cdk.Stack.of(this).account}:knowledge-base/${props.knowledgeBaseId ?? ''}`,
],
actions: ['bedrock:Retrieve'],
})
);
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [props.userPool],
});
const commonAuthorizerProps = {
authorizationType: AuthorizationType.COGNITO,
authorizer,
};
const ragResource = props.api.root.addResource('rag-knowledge-base');
// POST: /rag-knowledge-base/retrieve
const retrieveResource = ragResource.addResource('retrieve');
retrieveResource.addMethod(
'POST',
new LambdaIntegration(retrieveFunction),
commonAuthorizerProps
);
}
}
この中では、ナレッジベースから情報を取得する API を生成しています。
-
NodejsFunctionのRetrieve関数- ランタイムは NodeJS の最新版
- ソースコードは
packages/cdk/lambda/retrieveKnowledgeBase.ts - タイムアウトは 15 分
- 環境変数
-
KNOWLEDGE_BASE_ID: 以下が設定されている場合、設定 (上が優先)- スタック作成時のパラメータ
ragKnowledgeBaseId(デフォルト値は null) -
RagKnowledgeBaseStackを作成している場合、そのknowledgeBaseIdを設定
- スタック作成時のパラメータ
-
MODEL_REGION: スタック作成時のパラメータmodelRegion(デフォルト値はus-east-1)
-
- ロール
- ナレッジベースリソースに対する
bedrock:Retrieveを許可
- ナレッジベースリソースに対する
- 処理概要
- ナレッジベースに対して取得コマンドを実行
-
knowledgeBaseId: 環境変数のKNOWLEDGE_BASE_ID -
retrievalQuery.text:event.body.query -
retrievalConfiguration.vectorSearchConfiguration:-
numberOfResults: 固定値10(取得するソースチャンクの数) -
overrideSearchType固定値'HYBRID'(ベクター埋め込みと生のテキストの両方を使用する HYBRID 検索)
-
-
- 戻り値に実行結果を設定して終了
- ナレッジベースに対して取得コマンドを実行
-
Apiリソースの API エンドポイントに上記関数の呼び出しを追加する- API GW オーソライザに
Authリソースの Cognito ユーザプールを指定 -
/rag-knowledge-base/retrieve(POST) =>RetrieveLambda 関数を呼び出し
- API GW オーソライザに
これで RagKnowledgeBase リソースの作成は完了です。
加えて、GenerativeAiUseCasesStack からallowDownloadFile関数 を呼び出し、ナレッジベースのデータソース (S3 バケット) 内のファイルの署名付き URL を作成できるようにしています。
GenerativeAiUseCasesStack > UseCaseBuilder リソース
UseCaseBuilder リソースは、アーキテクチャ図でいうと以下の赤枠の部分にあたります。
UseCaseBuilder は 生成 AI アプリケーションのユースケースを公開、利用できる機能です。
以下のソースコードが UseCaseBuilder の定義です。
// Usecase builder
if (params.useCaseBuilderEnabled) {
new UseCaseBuilder(this, 'UseCaseBuilder', {
userPool: auth.userPool,
api: api.api,
});
}
UseCaseBuilder リソースの実体は packages/cdk/lib/construct/use-case-builder.ts にあります。
スタック作成時のパラメータ useCaseBuilderEnabled (デフォルト値は true) が true の場合、以下のコードを実行し UseCaseBuilder を作成します。
import {
RestApi,
LambdaIntegration,
CognitoUserPoolsAuthorizer,
AuthorizationType,
} from 'aws-cdk-lib/aws-apigateway';
import { Construct } from 'constructs';
import {
NodejsFunction,
NodejsFunctionProps,
} from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import { Duration } from 'aws-cdk-lib';
import { UserPool } from 'aws-cdk-lib/aws-cognito';
import * as ddb from 'aws-cdk-lib/aws-dynamodb';
export interface UseCaseBuilderProps {
userPool: UserPool;
api: RestApi;
}
export class UseCaseBuilder extends Construct {
constructor(scope: Construct, id: string, props: UseCaseBuilderProps) {
super(scope, id);
const { userPool, api } = props;
const useCaseIdIndexName = 'UseCaseIdIndexName';
const useCaseBuilderTable = new ddb.Table(this, 'UseCaseBuilderTable', {
partitionKey: {
name: 'id',
type: ddb.AttributeType.STRING,
},
sortKey: {
name: 'dataType',
type: ddb.AttributeType.STRING,
},
billingMode: ddb.BillingMode.PAY_PER_REQUEST,
});
useCaseBuilderTable.addGlobalSecondaryIndex({
indexName: useCaseIdIndexName,
partitionKey: {
name: 'useCaseId',
type: ddb.AttributeType.STRING,
},
sortKey: {
name: 'dataType',
type: ddb.AttributeType.STRING,
},
projectionType: ddb.ProjectionType.ALL,
});
const commonProperty: NodejsFunctionProps = {
runtime: Runtime.NODEJS_LATEST,
timeout: Duration.minutes(15),
environment: {
USECASE_TABLE_NAME: useCaseBuilderTable.tableName,
USECASE_ID_INDEX_NAME: useCaseIdIndexName,
},
};
const commonPath = './lambda/useCaseBuilder';
// UseCaseBuilder 関連の API を追加する
const listUseCasesFunction = new NodejsFunction(this, 'ListUseCases', {
...commonProperty,
entry: `${commonPath}/listUseCases.ts`,
});
useCaseBuilderTable.grantReadData(listUseCasesFunction);
const listFavoriteUseCasesFunction = new NodejsFunction(
this,
'ListFavoriteUseCases',
{
...commonProperty,
entry: `${commonPath}/listFavoriteUseCases.ts`,
environment: {
...commonProperty.environment,
USECASE_ID_INDEX_NAME: useCaseIdIndexName,
},
}
);
useCaseBuilderTable.grantReadData(listFavoriteUseCasesFunction);
const getUseCaseFunction = new NodejsFunction(this, 'GetUseCase', {
...commonProperty,
entry: `${commonPath}/getUseCase.ts`,
});
useCaseBuilderTable.grantReadData(getUseCaseFunction);
const createUseCaseFunction = new NodejsFunction(this, 'CreateUseCase', {
...commonProperty,
entry: `${commonPath}/createUseCase.ts`,
});
useCaseBuilderTable.grantWriteData(createUseCaseFunction);
const updateUseCaseFunction = new NodejsFunction(this, 'UpdateUseCase', {
...commonProperty,
entry: `${commonPath}/updateUseCase.ts`,
});
useCaseBuilderTable.grantReadWriteData(updateUseCaseFunction);
const deleteUseCaseFunction = new NodejsFunction(this, 'DeleteUseCase', {
...commonProperty,
entry: `${commonPath}/deleteUseCase.ts`,
});
useCaseBuilderTable.grantReadWriteData(deleteUseCaseFunction);
const toggleFavoriteFunction = new NodejsFunction(this, 'ToggleFavorite', {
...commonProperty,
entry: `${commonPath}/toggleFavorite.ts`,
});
useCaseBuilderTable.grantReadWriteData(toggleFavoriteFunction);
const toggleSharedFunction = new NodejsFunction(this, 'ToggleShared', {
...commonProperty,
entry: `${commonPath}/toggleShared.ts`,
});
useCaseBuilderTable.grantReadWriteData(toggleSharedFunction);
const listRecentlyUsedUseCasesFunction = new NodejsFunction(
this,
'ListRecentlyUsedUseCases',
{
...commonProperty,
entry: `${commonPath}/listRecentlyUsedUseCases.ts`,
}
);
useCaseBuilderTable.grantReadData(listRecentlyUsedUseCasesFunction);
const updateRecentlyUsedUseCaseFunction = new NodejsFunction(
this,
'UpdateRecentlyUsedUseCase',
{
...commonProperty,
entry: `${commonPath}/updateRecentlyUsedUseCase.ts`,
}
);
useCaseBuilderTable.grantReadWriteData(updateRecentlyUsedUseCaseFunction);
// API Gateway
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [userPool],
});
const commonAuthorizerProps = {
authorizationType: AuthorizationType.COGNITO,
authorizer,
};
const useCasesResource = api.root.addResource('usecases');
// GET: /usecases
useCasesResource.addMethod(
'GET',
new LambdaIntegration(listUseCasesFunction),
commonAuthorizerProps
);
// POST: /usecases
useCasesResource.addMethod(
'POST',
new LambdaIntegration(createUseCaseFunction),
commonAuthorizerProps
);
const favoriteUseCaseResource = useCasesResource.addResource('favorite');
// GET: /usecases/favorite
favoriteUseCaseResource.addMethod(
'GET',
new LambdaIntegration(listFavoriteUseCasesFunction),
commonAuthorizerProps
);
const useCaseResource = useCasesResource.addResource('{useCaseId}');
// GET: /usecases/{useCaseId}
useCaseResource.addMethod(
'GET',
new LambdaIntegration(getUseCaseFunction),
commonAuthorizerProps
);
// PUT: /usecases/{useCaseId}
useCaseResource.addMethod(
'PUT',
new LambdaIntegration(updateUseCaseFunction),
commonAuthorizerProps
);
// DELETE: /usecases/{useCaseId}
useCaseResource.addMethod(
'DELETE',
new LambdaIntegration(deleteUseCaseFunction),
commonAuthorizerProps
);
const favoriteResource = useCaseResource.addResource('favorite');
// PUT: /usecases/{useCaseId}/favorite
favoriteResource.addMethod(
'PUT',
new LambdaIntegration(toggleFavoriteFunction),
commonAuthorizerProps
);
const sharedResource = useCaseResource.addResource('shared');
// PUT: /usecases/{useCaseId}/shared
sharedResource.addMethod(
'PUT',
new LambdaIntegration(toggleSharedFunction),
commonAuthorizerProps
);
const recentUseCasesResource = useCasesResource.addResource('recent');
// GET: /usecases/recent
recentUseCasesResource.addMethod(
'GET',
new LambdaIntegration(listRecentlyUsedUseCasesFunction),
commonAuthorizerProps
);
const recentUseCaseResource =
recentUseCasesResource.addResource('{useCaseId}');
// PUT: /usecases/recent/{useCaseId}
recentUseCaseResource.addMethod(
'PUT',
new LambdaIntegration(updateRecentlyUsedUseCaseFunction),
commonAuthorizerProps
);
}
}
この中では、ナレッジベースから情報を取得する API を生成しています。
GenerativeAiUseCasesStack > UseCaseBuilder > Table リソース
Table はユースケース用の DynamoDB テーブルのリソースです。
以下のソースコードが Table の定義です。
const useCaseIdIndexName = 'UseCaseIdIndexName';
const useCaseBuilderTable = new ddb.Table(this, 'UseCaseBuilderTable', {
partitionKey: {
name: 'id',
type: ddb.AttributeType.STRING,
},
sortKey: {
name: 'dataType',
type: ddb.AttributeType.STRING,
},
billingMode: ddb.BillingMode.PAY_PER_REQUEST,
});
useCaseBuilderTable.addGlobalSecondaryIndex({
indexName: useCaseIdIndexName,
partitionKey: {
name: 'useCaseId',
type: ddb.AttributeType.STRING,
},
sortKey: {
name: 'dataType',
type: ddb.AttributeType.STRING,
},
projectionType: ddb.ProjectionType.ALL,
});
ここでは、以下のリソースを生成しています。
-
UseCaseBuilderTableDynamoDB テーブル- パーティションキーに文字列型の
idを指定 - ソートキーに文字列型の
dataTypeを指定 - 請求モードに
PAY_PER_REQUEST: オンデマンドキャパシティモードを指定 - GSI (グローバルセカンダリインデックス)
UseCaseIdIndexName- GSI のパーティションキーに文字列型の
useCaseIdを指定 - GSI のソートキーに文字列型の
dataTypeを指定 - ProjectionType に
ALL: すべてのテーブル属性をインデックスに投影を指定
- GSI のパーティションキーに文字列型の
- パーティションキーに文字列型の
GenerativeAiUseCasesStack > UseCaseBuilder > NodejsFunction リソース
NodejsFunction はユースケース用の Lambda 関数のリソースです。
以下のソースコードが NodejsFunction の定義です。
const commonProperty: NodejsFunctionProps = {
runtime: Runtime.NODEJS_LATEST,
timeout: Duration.minutes(15),
environment: {
USECASE_TABLE_NAME: useCaseBuilderTable.tableName,
USECASE_ID_INDEX_NAME: useCaseIdIndexName,
},
};
const commonPath = './lambda/useCaseBuilder';
// UseCaseBuilder 関連の API を追加する
const listUseCasesFunction = new NodejsFunction(this, 'ListUseCases', {
...commonProperty,
entry: `${commonPath}/listUseCases.ts`,
});
useCaseBuilderTable.grantReadData(listUseCasesFunction);
const listFavoriteUseCasesFunction = new NodejsFunction(
this,
'ListFavoriteUseCases',
{
...commonProperty,
entry: `${commonPath}/listFavoriteUseCases.ts`,
environment: {
...commonProperty.environment,
USECASE_ID_INDEX_NAME: useCaseIdIndexName,
},
}
);
useCaseBuilderTable.grantReadData(listFavoriteUseCasesFunction);
const getUseCaseFunction = new NodejsFunction(this, 'GetUseCase', {
...commonProperty,
entry: `${commonPath}/getUseCase.ts`,
});
useCaseBuilderTable.grantReadData(getUseCaseFunction);
const createUseCaseFunction = new NodejsFunction(this, 'CreateUseCase', {
...commonProperty,
entry: `${commonPath}/createUseCase.ts`,
});
useCaseBuilderTable.grantWriteData(createUseCaseFunction);
const updateUseCaseFunction = new NodejsFunction(this, 'UpdateUseCase', {
...commonProperty,
entry: `${commonPath}/updateUseCase.ts`,
});
useCaseBuilderTable.grantReadWriteData(updateUseCaseFunction);
const deleteUseCaseFunction = new NodejsFunction(this, 'DeleteUseCase', {
...commonProperty,
entry: `${commonPath}/deleteUseCase.ts`,
});
useCaseBuilderTable.grantReadWriteData(deleteUseCaseFunction);
const toggleFavoriteFunction = new NodejsFunction(this, 'ToggleFavorite', {
...commonProperty,
entry: `${commonPath}/toggleFavorite.ts`,
});
useCaseBuilderTable.grantReadWriteData(toggleFavoriteFunction);
const toggleSharedFunction = new NodejsFunction(this, 'ToggleShared', {
...commonProperty,
entry: `${commonPath}/toggleShared.ts`,
});
useCaseBuilderTable.grantReadWriteData(toggleSharedFunction);
const listRecentlyUsedUseCasesFunction = new NodejsFunction(
this,
'ListRecentlyUsedUseCases',
{
...commonProperty,
entry: `${commonPath}/listRecentlyUsedUseCases.ts`,
}
);
useCaseBuilderTable.grantReadData(listRecentlyUsedUseCasesFunction);
const updateRecentlyUsedUseCaseFunction = new NodejsFunction(
this,
'UpdateRecentlyUsedUseCase',
{
...commonProperty,
entry: `${commonPath}/updateRecentlyUsedUseCase.ts`,
}
);
useCaseBuilderTable.grantReadWriteData(updateRecentlyUsedUseCaseFunction);
ここでは、以下のリソースを生成しています。
- 共通設定
- ランタイムは NodeJS の最新版
- タイムアウトは 15 分
- 環境変数
-
USECASE_TABLE_NAME: DynamoDB テーブルUseCaseBuilderTableのテーブル名 -
USECASE_ID_INDEX_NAME: GSI (グローバルセカンダリインデックス)UseCaseIdIndexNameのインデックス名
-
-
ListUseCases関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/listUseCases.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの listUseCases 関数を呼び出して DynamoDB テーブルからデータを取得- Cognito ユーザに紐づくユースケース一覧を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:useCaseで始まる -
取得件数 Limit: 30 件 (マイユースケースのページあたりの件数) -
ExclusiveStartKey:event.queryStringParameters.exclusiveStartKeyがあればそのキーから取得する
-
- Cognito ユーザに紐づくお気に入りを全取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:favoriteで始まる
-
- Cognito ユーザに紐づくユースケース一覧を取得
- 戻り値に取得したデータを設定
- ソースコードは
-
ListFavoriteUseCases関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/listFavoriteUseCases.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの listFavoriteUseCases 関数を呼び出して DynamoDB テーブルからデータを取得- Cognito ユーザに紐づくお気に入り一覧を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:favoriteで始まる -
取得件数 Limit: 20 件 (お気に入りのページあたりの件数) -
ExclusiveStartKey: クエリパラメータ文字列のexclusiveStartKeyがあればそのキーから取得する
-
- 取得したユースケース一覧の情報を繰り返し取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: 取得したユースケース ID -
dataType:useCaseで始まる
-
- 自分が作成したユースケースもしくはシェアされているユースケースに絞る (後から非公開となったユースケースを除外)
- Cognito ユーザに紐づくお気に入り一覧を取得
- 戻り値に取得したデータを設定
- ソースコードは
-
GetUseCase関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/getUseCase.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの getUseCase 関数を呼び出して DynamoDB テーブルからデータを取得- 指定したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: パスパラメータのuseCaseId -
dataType:useCaseで始まる
-
- 自分が作成したユースケースもしくはシェアされているユースケースでない場合、null にする (後から非公開となったユースケースを除外)
- 指定したユースケースの情報を取得
- 戻り値に取得したデータを設定
- ソースコードは
-
CreateUseCase関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/createUseCase.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの createUseCase 関数を呼び出して DynamoDB テーブルにデータを登録-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:useCase#+ 現在日時のミリ秒 -
useCaseId: ランダム生成した UUID -
title:event.body.title -
description:event.body.description -
promptTemplate:event.body.promptTemplate -
inputExamples:event.body.inputExamples -
fixedModelId:event.body.fixedModelId -
fileUpload:event.body.fileUpload -
isShared: 固定値false
-
- ソースコードは
-
UpdateUseCase関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/updateUseCase.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの updateUseCase 関数を呼び出して DynamoDB テーブルのデータを更新- 指定したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: パスパラメータのuseCaseId -
dataType:useCaseで始まる
-
- 存在チェックおよび自身のユースケースかをチェック
- ユースケースの情報を更新
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id: 取得したid -
dataType: 取得したdataType -
title:event.body.title -
description:event.body.description -
promptTemplate:event.body.promptTemplate -
inputExamples:event.body.inputExamples -
fixedModelId:event.body.fixedModelId -
fileUpload:event.body.fileUpload
-
- 指定したユースケースの情報を取得
- ソースコードは
-
DeleteUseCase関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/deleteUseCase.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの deleteUseCase 関数を呼び出して DynamoDB テーブルのデータを削除- 指定したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: パスパラメータのuseCaseId -
dataType:useCaseで始まる
-
- 存在チェックおよび自身のユースケースかをチェック
- 指定したユースケースの全情報を取得 (
dataTypeで絞り込まない)-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: パスパラメータのuseCaseId
-
- 取得したユースケースを削除
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id: 取得したid -
dataType:useCase#+ 現在日時のミリ秒
-
- 指定したユースケースの情報を取得
- ソースコードは
-
ToggleFavorite関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/toggleFavorite.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの toggleFavorite 関数を呼び出して DynamoDB テーブルのデータを更新- 指定したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
useCaseId: パスパラメータのuseCaseId -
dataType:favoriteで始まる
-
- ユースケースの情報が取得できた場合、お気に入りを解除 (データを削除)
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id: 取得したid -
dataType: 取得したdataType
-
- ユースケースの情報が取得できなかった場合、お気に入りを登録
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:favorite#+ 現在日時のミリ秒 -
useCaseId: 取得したuseCaseId
-
- 指定したユースケースの情報を取得
- ソースコードは
-
ToggleShared関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/toggleShared.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの toggleShared 関数を呼び出して DynamoDB テーブルのデータを更新- 指定したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
useCaseId: パスパラメータのuseCaseId -
dataType:favoriteで始まる
-
- 存在チェックおよび自身のユースケースかをチェックし、自身のものでない場合は
isShared: falseを返却 - ユースケースの情報が取得できなかった場合、お気に入りを登録
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id: 取得したid -
dataType: 取得したdataType -
isShared: 取得したisSharedを反転して登録
-
- 指定したユースケースの情報を取得
- ソースコードは
-
ListRecentlyUsedUseCases関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/listRecentlyUsedUseCases.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの listRecentlyUsedUseCases 関数を呼び出して DynamoDB テーブルからデータを取得- Cognito ユーザに紐づく利用履歴一覧を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:recentlyUsedで始まる -
取得件数 Limit: 20 件 (利用履歴のページあたりの件数) -
ExclusiveStartKey: クエリパラメータ文字列のexclusiveStartKeyがあればそのキーから取得する
-
- 取得したユースケースの情報を取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
IndexName: ユースケースビルダー用 DynamnoDB テーブル GSI 名 -
useCaseId: パスパラメータのuseCaseId -
dataType:useCaseで始まる
-
- Cognito ユーザに紐づくお気に入りを全取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:favoriteで始まる
-
- Cognito ユーザに紐づく利用履歴一覧を取得
- 戻り値に取得したデータを設定
- ソースコードは
-
UpdateRecentlyUsedUseCase関数- ソースコードは
packages/cdk/lambda/useCaseBuilder/updateRecentlyUsedUseCase.ts - 処理概要
- Cognito ユーザ ID を取得
-
packages/cdk/lambda/useCaseBuilder/useCaseBuilderRepository.tsの updateRecentlyUsedUseCase 関数を呼び出して DynamoDB テーブルのデータを更新- Cognito ユーザに紐づく利用履歴を全取得
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:recentlyUsedで始まる
-
- 既に利用履歴がリミット (100 件) を超えている場合、利用履歴を 100 件にスライス
- 利用履歴への登録対象のユースケースが既に利用履歴に含まれている場合、削除を行う
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id: 取得したid -
dataType: 取得したdataType
-
- 利用履歴への登録を行う
-
TableName: ユースケースビルダー用 DynamnoDB テーブル名 -
id:useCase#+ Cognito ユーザ ID -
dataType:recentlyUsed#+ 現在日時のミリ秒 -
useCaseId: パスパラメータのuseCaseId
-
- Cognito ユーザに紐づく利用履歴を全取得
- ソースコードは
GenerativeAiUseCasesStack > UseCaseBuilder > Lambda 関数を API に追加
続いて、Lambda 関数を Api リソースの API エンドポイントに追加します。
// API Gateway
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [userPool],
});
const commonAuthorizerProps = {
authorizationType: AuthorizationType.COGNITO,
authorizer,
};
const useCasesResource = api.root.addResource('usecases');
// GET: /usecases
useCasesResource.addMethod(
'GET',
new LambdaIntegration(listUseCasesFunction),
commonAuthorizerProps
);
// POST: /usecases
useCasesResource.addMethod(
'POST',
new LambdaIntegration(createUseCaseFunction),
commonAuthorizerProps
);
const favoriteUseCaseResource = useCasesResource.addResource('favorite');
// GET: /usecases/favorite
favoriteUseCaseResource.addMethod(
'GET',
new LambdaIntegration(listFavoriteUseCasesFunction),
commonAuthorizerProps
);
const useCaseResource = useCasesResource.addResource('{useCaseId}');
// GET: /usecases/{useCaseId}
useCaseResource.addMethod(
'GET',
new LambdaIntegration(getUseCaseFunction),
commonAuthorizerProps
);
// PUT: /usecases/{useCaseId}
useCaseResource.addMethod(
'PUT',
new LambdaIntegration(updateUseCaseFunction),
commonAuthorizerProps
);
// DELETE: /usecases/{useCaseId}
useCaseResource.addMethod(
'DELETE',
new LambdaIntegration(deleteUseCaseFunction),
commonAuthorizerProps
);
const favoriteResource = useCaseResource.addResource('favorite');
// PUT: /usecases/{useCaseId}/favorite
favoriteResource.addMethod(
'PUT',
new LambdaIntegration(toggleFavoriteFunction),
commonAuthorizerProps
);
const sharedResource = useCaseResource.addResource('shared');
// PUT: /usecases/{useCaseId}/shared
sharedResource.addMethod(
'PUT',
new LambdaIntegration(toggleSharedFunction),
commonAuthorizerProps
);
const recentUseCasesResource = useCasesResource.addResource('recent');
// GET: /usecases/recent
recentUseCasesResource.addMethod(
'GET',
new LambdaIntegration(listRecentlyUsedUseCasesFunction),
commonAuthorizerProps
);
const recentUseCaseResource =
recentUseCasesResource.addResource('{useCaseId}');
// PUT: /usecases/recent/{useCaseId}
recentUseCaseResource.addMethod(
'PUT',
new LambdaIntegration(updateRecentlyUsedUseCaseFunction),
commonAuthorizerProps
);
ここでは、Api リソースの API エンドポイントに上記関数の呼び出しを追加しています。
- API GW オーソライザに
Authリソースの Cognito ユーザプールを指定 -
/usecases(GET) =>ListUseCasesLambda 関数を呼び出し -
/usecases/favorite(GET) =>ListFavoriteUseCasesLambda 関数を呼び出し -
/usecases/{useCaseId}(GET) =>GetUseCaseLambda 関数を呼び出し -
/usecases(POST) =>CreateUseCaseLambda 関数を呼び出し -
/usecases/{useCaseId}(PUT) =>UpdateUseCaseLambda 関数を呼び出し -
/usecases/{useCaseId}(DELETE) =>DeleteUseCaseLambda 関数を呼び出し -
/usecases/{useCaseId}/favorite(PUT) =>ToggleFavoriteLambda 関数を呼び出し -
/usecases/{useCaseId}/shared(PUT) =>ToggleSharedLambda 関数を呼び出し -
/usecases/recent(GET) =>ListRecentlyUsedUseCasesLambda 関数を呼び出し -
/usecases/recent/{useCaseId}(PUT) =>UpdateRecentlyUsedUseCaseLambda 関数を呼び出し
GenerativeAiUseCasesStack > Transcribe リソース
Transcribe リソースは、アーキテクチャ図でいうと以下の赤枠の部分にあたります。
Transcribe は音声データの文字起こし機能です。
以下のソースコードが Transcribe の定義です。
// Transcribe
new Transcribe(this, 'Transcribe', {
userPool: auth.userPool,
idPool: auth.idPool,
api: api.api,
});
Transcribe リソースの実体は packages/cdk/lib/construct/transcribe.ts にあります。
import { Duration, RemovalPolicy } from 'aws-cdk-lib';
import {
AuthorizationType,
CognitoUserPoolsAuthorizer,
LambdaIntegration,
RestApi,
} from 'aws-cdk-lib/aws-apigateway';
import { UserPool } from 'aws-cdk-lib/aws-cognito';
import { IdentityPool } from '@aws-cdk/aws-cognito-identitypool-alpha';
import { Effect, Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import {
BlockPublicAccess,
Bucket,
BucketEncryption,
HttpMethods,
} from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export interface TranscribeProps {
userPool: UserPool;
idPool: IdentityPool;
api: RestApi;
}
export class Transcribe extends Construct {
constructor(scope: Construct, id: string, props: TranscribeProps) {
super(scope, id);
const audioBucket = new Bucket(this, 'AudioBucket', {
encryption: BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
enforceSSL: true,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
});
audioBucket.addCorsRule({
allowedOrigins: ['*'],
allowedMethods: [HttpMethods.PUT],
allowedHeaders: ['*'],
exposedHeaders: [],
maxAge: 3000,
});
const transcriptBucket = new Bucket(this, 'TranscriptBucket', {
encryption: BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
enforceSSL: true,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
});
const getSignedUrlFunction = new NodejsFunction(this, 'GetSignedUrl', {
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/getFileUploadSignedUrl.ts',
timeout: Duration.minutes(15),
environment: {
BUCKET_NAME: audioBucket.bucketName,
},
});
audioBucket.grantWrite(getSignedUrlFunction);
const startTranscriptionFunction = new NodejsFunction(
this,
'StartTranscription',
{
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/startTranscription.ts',
timeout: Duration.minutes(15),
environment: {
TRANSCRIPT_BUCKET_NAME: transcriptBucket.bucketName,
},
initialPolicy: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['transcribe:*'],
resources: ['*'],
}),
],
}
);
audioBucket.grantRead(startTranscriptionFunction);
transcriptBucket.grantWrite(startTranscriptionFunction);
const getTranscriptionFunction = new NodejsFunction(
this,
'GetTranscription',
{
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/getTranscription.ts',
timeout: Duration.minutes(15),
initialPolicy: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['transcribe:*'],
resources: ['*'],
}),
],
}
);
transcriptBucket.grantRead(getTranscriptionFunction);
// API Gateway
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [props.userPool],
});
const commonAuthorizerProps = {
authorizationType: AuthorizationType.COGNITO,
authorizer,
};
const transcribeResource = props.api.root.addResource('transcribe');
// POST: /transcribe/start
transcribeResource
.addResource('start')
.addMethod(
'POST',
new LambdaIntegration(startTranscriptionFunction),
commonAuthorizerProps
);
// POST: /transcribe/url
transcribeResource
.addResource('url')
.addMethod(
'POST',
new LambdaIntegration(getSignedUrlFunction),
commonAuthorizerProps
);
// GET: /transcribe/result/{jobName}
transcribeResource
.addResource('result')
.addResource('{jobName}')
.addMethod(
'GET',
new LambdaIntegration(getTranscriptionFunction),
commonAuthorizerProps
);
// add Policy for Amplify User
// grant access policy transcribe stream and translate
props.idPool.authenticatedRole.attachInlinePolicy(
new Policy(this, 'GrantAccessTranscribeStream', {
statements: [
new PolicyStatement({
actions: ['transcribe:StartStreamTranscriptionWebSocket'],
resources: ['*'],
}),
],
})
);
}
}
この中では、元となる音声データ用のバケットや、文字起こし処理および API エンドポイント、文字起こし結果を格納する S3 バケットを生成しています。
GenerativeAiUseCasesStack > Transcribe > Bucket リソース
Bucket は文字起こし用の S3 バケットのリソースです。
以下のソースコードが Bucket の定義です。
const audioBucket = new Bucket(this, 'AudioBucket', {
encryption: BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
enforceSSL: true,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
});
audioBucket.addCorsRule({
allowedOrigins: ['*'],
allowedMethods: [HttpMethods.PUT],
allowedHeaders: ['*'],
exposedHeaders: [],
maxAge: 3000,
});
const transcriptBucket = new Bucket(this, 'TranscriptBucket', {
encryption: BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
enforceSSL: true,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
});
ここでは、以下のリソースを生成しています。
-
AudioBucketS3 バケット- S3 マネージドキーでの暗号化
- スタック削除時はバケットを削除 (中に含まれるオブジェクトも削除)
- SSL 接続を強制する
- ブロックパブリックアクセスはブロック
-
CORS 設定を許可する
- すべてのオリジン
- PUT リクエストを許可
- すべての Access-Control-Request-Headers を許可
- アクセスできるヘッダ情報はなし
- ブラウザのキャッシュ時間は 50 分(3000 秒)
-
TranscriptBucketS3 バケット- S3 マネージドキーでの暗号化
- スタック削除時はバケットを削除 (中に含まれるオブジェクトも削除)
- SSL 接続を強制する
- ブロックパブリックアクセスはブロック
GenerativeAiUseCasesStack > Transcribe > NodejsFunction リソース
NodejsFunction は文字起こし用の Lambda 関数です。
const getSignedUrlFunction = new NodejsFunction(this, 'GetSignedUrl', {
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/getFileUploadSignedUrl.ts',
timeout: Duration.minutes(15),
environment: {
BUCKET_NAME: audioBucket.bucketName,
},
});
audioBucket.grantWrite(getSignedUrlFunction);
const startTranscriptionFunction = new NodejsFunction(
this,
'StartTranscription',
{
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/startTranscription.ts',
timeout: Duration.minutes(15),
environment: {
TRANSCRIPT_BUCKET_NAME: transcriptBucket.bucketName,
},
initialPolicy: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['transcribe:*'],
resources: ['*'],
}),
],
}
);
audioBucket.grantRead(startTranscriptionFunction);
transcriptBucket.grantWrite(startTranscriptionFunction);
const getTranscriptionFunction = new NodejsFunction(
this,
'GetTranscription',
{
runtime: Runtime.NODEJS_LATEST,
entry: './lambda/getTranscription.ts',
timeout: Duration.minutes(15),
initialPolicy: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['transcribe:*'],
resources: ['*'],
}),
],
}
);
transcriptBucket.grantRead(getTranscriptionFunction);
ここでは、以下のリソースを生成しています。
-
GetSignedUrl関数- ランタイムは NodeJS の最新版
- ソースコードは
packages/cdk/lambda/getFileUploadSignedUrl.ts - タイムアウトは 15 分
- 環境変数
-
BUCKET_NAME:AudioBucketS3 バケットのバケット名
-
- 処理概要
- オブジェクトアップロード用の署名付き URL を取得
-
Bucket: 環境変数のBUCKET_NAME -
Key: ユニーク ID +event.body.filename - 有効期限は 1 時間 (3600 秒)
-
- 戻り値にオブジェクトアップロード用の署名付き URL を設定して終了
- オブジェクトアップロード用の署名付き URL を取得
-
StartTranscription関数- ランタイムは NodeJS の最新版
- ソースコードは
packages/cdk/lambda/startTranscription.ts - タイムアウトは 15 分
- 環境変数
-
TRANSCRIPT_BUCKET_NAME:TranscriptBucketS3 バケットのバケット名
-
- ロール
- 全リソースへの
transcribe:*アクションを許可
- 全リソースへの
- 処理概要
-
文字起こしジョブの開始コマンドを作成する
-
IdentifyLanguage: 固定値true -
LanguageOptions: 固定値['ja-JP', 'en-US'] -
Media:-
MediaFileUri:event.body.audioUrl
-
-
TranscriptionJobName: ランダム ID, -
Settings:-
ShowSpeakerLabels:event.body.speakerLabel -
MaxSpeakerLabels:event.body.speakerLabelが設定されていればevent.body.maxSpeakersを設定
-
-
OutputBucketName: 環境変数のTRANSCRIPT_BUCKET_NAME -
Tags:-
Key: 固定値'userId' -
Value: オーソライザーの sub (ユーザごとのランダム ID) 値
-
-
- コマンドを実行する
- 文字起こしジョブ名を返却する
-
文字起こしジョブの開始コマンドを作成する
-
GetTranscription関数- ランタイムは NodeJS の最新版
- ソースコードは
packages/cdk/lambda/getTranscription.ts - タイムアウトは 15 分
- ロール
- 全リソースへの
transcribe:*アクションを許可
- 全リソースへの
- 処理概要
-
文字起こしジョブの情報取得コマンドを作成する
-
TranscriptionJobName: パスパラメータのjobName
-
- コマンドを実行する
- 取得したジョブ情報の
Tag.userIdがログインユーザと異なる場合は 403 エラーを返却 - ジョブステータスが
COMPLETEDの場合- ジョブ情報の
TranscriptFileUriから 文字起こし結果が格納されている S3 バケット名とキー値を取得する - S3 バケットからオブジェクトを取得する
- 文字起こし結果をフォーマットして返却
- ジョブ情報の
- ジョブステータスが
COMPLETED以外の場合- ジョブステータスを返却する
-
文字起こしジョブの情報取得コマンドを作成する
GenerativeAiUseCasesStack > Transcribe > Lambda 関数を API に追加
続いて、Lambda 関数を Api リソースの API エンドポイントに追加します。
// API Gateway
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [props.userPool],
});
const commonAuthorizerProps = {
authorizationType: AuthorizationType.COGNITO,
authorizer,
};
const transcribeResource = props.api.root.addResource('transcribe');
// POST: /transcribe/start
transcribeResource
.addResource('start')
.addMethod(
'POST',
new LambdaIntegration(startTranscriptionFunction),
commonAuthorizerProps
);
// POST: /transcribe/url
transcribeResource
.addResource('url')
.addMethod(
'POST',
new LambdaIntegration(getSignedUrlFunction),
commonAuthorizerProps
);
// GET: /transcribe/result/{jobName}
transcribeResource
.addResource('result')
.addResource('{jobName}')
.addMethod(
'GET',
new LambdaIntegration(getTranscriptionFunction),
commonAuthorizerProps
);
// add Policy for Amplify User
// grant access policy transcribe stream and translate
props.idPool.authenticatedRole.attachInlinePolicy(
new Policy(this, 'GrantAccessTranscribeStream', {
statements: [
new PolicyStatement({
actions: ['transcribe:StartStreamTranscriptionWebSocket'],
resources: ['*'],
}),
],
})
);
ここでは、以下のリソースを生成しています。
-
Apiリソースの API エンドポイントに上記関数の呼び出しを追加する- API GW オーソライザに
Authリソースの Cognito ユーザプールを指定 -
/transcribe/url(POST) =>GetSignedUrlLambda 関数を呼び出し -
/transcribe/start(POST) =>StartTranscriptionLambda 関数を呼び出し -
/transcribe/result/{jobName}(Get) =>GetTranscriptionLambda 関数を呼び出し
- API GW オーソライザに
GenerativeAiUseCasesStack > Transcribe > Cognito 認証済ユーザへの権限追加
最後に、Cognito 認証済ユーザにトランスクリプト権限を追加します。
// add Policy for Amplify User
// grant access policy transcribe stream and translate
props.idPool.authenticatedRole.attachInlinePolicy(
new Policy(this, 'GrantAccessTranscribeStream', {
statements: [
new PolicyStatement({
actions: ['transcribe:StartStreamTranscriptionWebSocket'],
resources: ['*'],
}),
],
})
);
ここでは、Cognito 認証済ユーザにトランスクリプト権限を追加しています。
-
GrantAccessTranscribeStreamポリシー- すべてのリソースに対し
transcribe:StartStreamTranscriptionWebSocketを許可
- すべてのリソースに対し
以上で RagKnowledgeBase, UseCaseBuilder, Transcribe リソースの解説は終了です。
これにて、GenerativeAiUseCasesStack スタックの解説が全て終わりました。
次回は最後のスタックである、GenU 内の DashboardStack スタックを解説したいと思います。
(参考) GenU のバックエンド (CDK) 詳細解説投稿一覧
- ①AWS CDK のセットアップ
- ②AWS CDK の動作確認
- ③GenU の概要
- ④GenU CDK スタックの概要
- ⑤CloudFrontWafStack スタックの解説
- ⑥RagKnowledgeBaseStack スタックの解説
- ⑦WebSearchAgentStack スタックの解説
- ⑧GuardrailStack スタックの解説
- ⑨GenerativeAiUseCasesStack > Auth スタックの解説
- ⑩GenerativeAiUseCasesStack > Database, Api スタックの解説
- ⑪GenerativeAiUseCasesStack > CommonWebAcl, Web, Rag スタックの解説
- ⑫GenerativeAiUseCasesStack > RagKnowledgeBase, UseCaseBuilder, Transcribe スタックの解説
- ⑬DashBoard スタックの解説
- ⑭GenU の Outputs の解説



