Skip to content

Commit

Permalink
feat: use case builder toggle functionality & refactor huge component…
Browse files Browse the repository at this point in the history
…s to divided small components
  • Loading branch information
yuukiok committed Oct 24, 2024
1 parent c214e05 commit c24a17f
Show file tree
Hide file tree
Showing 20 changed files with 566 additions and 463 deletions.
2 changes: 2 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export VITE_APP_SAMLAUTH_ENABLED=<SAML 認証 Flag>
export VITE_APP_SAML_COGNITO_DOMAIN_NAME=<SAML Cognito Domain>
export VITE_APP_SAML_COGNITO_FEDERATED_IDENTITY_PROVIDER_NAME=<SAML Cognito Provider Name>
export VITE_APP_AGENT_NAMES=<Bedrock Agent Names の JSON Array>
export VITE_APP_USE_CASE_BUILDER_ENABLED=<UseCase Builder Flag>
```
具体例は以下です。
Expand All @@ -72,6 +73,7 @@ export VITE_APP_SAMLAUTH_ENABLED=true
export VITE_APP_SAML_COGNITO_DOMAIN_NAME=your-preferred-name.auth.ap-northeast-1.amazoncognito.com
export VITE_APP_SAML_COGNITO_FEDERATED_IDENTITY_PROVIDER_NAME=EntraID
export VITE_APP_AGENT_NAMES=["SearchEngine"]
export VITE_APP_USE_CASE_BUILDER_ENABLED=true
```

#### `.env` ファイルを利用する方法
Expand Down
1 change: 1 addition & 0 deletions packages/cdk/cdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"anonymousUsageTracking": true,
"guardrailEnabled" : false,
"crossAccountBedrockRoleArn": "",
"useCaseBuilderEnabled": false,
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/createUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { CreateUseCaseRequest } from 'generative-ai-use-cases-jp';
import { createUseCase } from './repository';
import { createUseCase } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/deleteUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { deleteUseCase } from './repository';
import { deleteUseCase } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/getUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { getUseCase } from './repository';
import { getUseCase } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/listFavoriteUseCases.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { listFavoriteUseCases } from './repository';
import { listFavoriteUseCases } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/listUseCases.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { listUseCases } from './repository';
import { listUseCases } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
280 changes: 0 additions & 280 deletions packages/cdk/lambda/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,20 @@ import {
UserIdAndChatId,
SystemContext,
UpdateFeedbackRequest,
CustomUseCaseMeta,
UseCaseId,
IsFavorite,
HasShared,
} from 'generative-ai-use-cases-jp';
import * as crypto from 'crypto';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
BatchWriteCommand,
DeleteCommand,
DynamoDBDocumentClient,
GetCommand,
PutCommand,
QueryCommand,
TransactWriteCommand,
UpdateCommand,
} from '@aws-sdk/lib-dynamodb';

const TABLE_NAME: string = process.env.TABLE_NAME!;
const USECASE_TABLE_NAME: string = process.env.USECASE_TABLE_NAME!;
const dynamoDb = new DynamoDBClient({});
const dynamoDbDocument = DynamoDBDocumentClient.from(dynamoDb);

Expand Down Expand Up @@ -524,277 +518,3 @@ export const deleteShareId = async (_shareId: string): Promise<void> => {
})
);
};

export const listUseCases = async (
_userId: string
): Promise<CustomUseCaseMeta[]> => {
const useCaseUserId = `user#useCase#${_userId}`;
const favoriteUserId = `user#favorite#${_userId}`;

const [useCaseRes, favoriteRes] = await Promise.all([
dynamoDbDocument.send(
new QueryCommand({
TableName: USECASE_TABLE_NAME,
KeyConditionExpression: '#id = :id',
ExpressionAttributeNames: {
'#id': 'id',
},
ExpressionAttributeValues: {
':id': useCaseUserId,
},
})
),

dynamoDbDocument.send(
new QueryCommand({
TableName: USECASE_TABLE_NAME,
KeyConditionExpression: '#id = :id',
ExpressionAttributeNames: {
'#id': 'id',
},
ExpressionAttributeValues: {
':id': favoriteUserId,
},
})
),
]);

const favoriteSet = new Set(
(favoriteRes.Items || []).map((item) => item.useCaseId)
);

return (useCaseRes.Items || []).map((item) => ({
useCaseId: item.useCaseId,
title: item.title,
isFavorite: favoriteSet.has(item.useCaseId),
hasShared: item.hasShared,
}));
};

export const listFavoriteUseCases = async (
_userId: string
): Promise<CustomUseCaseMeta[]> => {
const useCaseUserId = `user#useCase#${_userId}`;
const favoriteUserId = `user#favorite#${_userId}`;

const favoriteRes = await dynamoDbDocument.send(
new QueryCommand({
TableName: USECASE_TABLE_NAME,
KeyConditionExpression: '#id = :id',
ExpressionAttributeNames: {
'#id': 'id',
},
ExpressionAttributeValues: {
':id': favoriteUserId,
},
})
);

if (!favoriteRes.Items || favoriteRes.Items.length === 0) {
return [];
}

const favoriteUseCaseIds = favoriteRes.Items.map((item) => item.useCaseId);

const useCasePromises = favoriteUseCaseIds.map(async (favoriteUseCaseId) => {
const result = await dynamoDbDocument.send(
new GetCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: useCaseUserId,
useCaseId: favoriteUseCaseId,
},
})
);
return result.Item;
});

const useCases = await Promise.all(useCasePromises);

return useCases
.filter((item): item is NonNullable<typeof item> => item != null)
.map((item) => ({
useCaseId: item.useCaseId,
title: item.title,
isFavorite: true,
hasShared: item.hasShared,
isMyUseCase: item.id === useCaseUserId,
}));
};

export const getUseCase = async (
_userId: string,
useCaseId: string
): Promise<CustomUseCaseMeta | null> => {
const userId = `user#useCase#${_userId}`;
const res = await dynamoDbDocument.send(
new GetCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: userId,
useCaseId: useCaseId,
},
})
);
if (!res.Item) return null;
const item = res.Item;
return {
useCaseId: item.useCaseId,
title: item.title,
isFavorite: false,
hasShared: item.hasShared,
isMyUseCase: true,
};
};

export const createUseCase = async (
_userId: string,
title: string,
promptTemplate: string
): Promise<UseCaseId> => {
const userId = `user#useCase#${_userId}`;
const useCaseId = crypto.randomUUID();
const item = {
id: userId,
useCaseId: useCaseId,
title: title,
promptTemplate: promptTemplate,
hasShared: false,
};

await dynamoDbDocument.send(
new PutCommand({
TableName: USECASE_TABLE_NAME,
Item: item,
})
);

return { useCaseId: useCaseId };
};

export const updateUseCase = async (
_userId: string,
useCaseId: string,
title: string,
promptTemplate: string
): Promise<void> => {
const userId = `user#useCase#${_userId}`;
await dynamoDbDocument.send(
new UpdateCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: userId,
useCaseId: useCaseId,
},
UpdateExpression: 'set title = :title, promptTemplate = :promptTemplate',
ExpressionAttributeValues: {
':title': title,
':promptTemplate': promptTemplate,
},
})
);
};

export const deleteUseCase = async (
_userId: string,
useCaseId: string
): Promise<void> => {
const useCaseUserId = `user#useCase#${_userId}`;
const favoriteUserId = `user#favorite#${_userId}`;

// ユースケース削除
await dynamoDbDocument.send(
new DeleteCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: useCaseUserId,
useCaseId: useCaseId,
},
})
);

// お気に入り登録があれば削除
const result = await dynamoDbDocument.send(
new GetCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: favoriteUserId,
useCaseId: useCaseId,
},
})
);
if (result.Item) {
await dynamoDbDocument.send(
new DeleteCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: favoriteUserId,
useCaseId: useCaseId,
},
})
);
}
};

export const toggleFavorite = async (
_userId: string,
useCaseId: string
): Promise<IsFavorite> => {
const favoriteUserId = `user#favorite#${_userId}`;

const existingFavorite = await dynamoDbDocument.send(
new GetCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: favoriteUserId,
useCaseId: useCaseId,
},
})
);

if (existingFavorite.Item) {
await dynamoDbDocument.send(
new DeleteCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: favoriteUserId,
useCaseId: useCaseId,
},
})
);
return { isFavorite: false };
} else {
await dynamoDbDocument.send(
new PutCommand({
TableName: USECASE_TABLE_NAME,
Item: {
id: favoriteUserId,
useCaseId: useCaseId,
},
})
);
return { isFavorite: true };
}
};

export const toggleShared = async (
_userId: string,
useCase: CustomUseCaseMeta
): Promise<HasShared> => {
const useCaseUserId = `user#useCase#${_userId}`;
const newSharedState = !useCase.hasShared;
await dynamoDbDocument.send(
new UpdateCommand({
TableName: USECASE_TABLE_NAME,
Key: {
id: useCaseUserId,
useCaseId: useCase.useCaseId,
},
UpdateExpression: 'set hasShared = :hasShared',
ExpressionAttributeValues: {
':hasShared': newSharedState,
},
})
);
return { hasShared: newSharedState };
};
2 changes: 1 addition & 1 deletion packages/cdk/lambda/toggleFavorite.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { IsFavorite } from 'generative-ai-use-cases-jp';
import { toggleFavorite } from './repository';
import { toggleFavorite } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/toggleShared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { getUseCase, toggleShared } from './repository';
import { getUseCase, toggleShared } from './useCaseBuilderRepository';
import { CustomUseCaseMeta, HasShared } from 'generative-ai-use-cases-jp';

export const handler = async (
Expand Down
2 changes: 1 addition & 1 deletion packages/cdk/lambda/updateUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { UpdateUseCaseRequest } from 'generative-ai-use-cases-jp';
import { updateUseCase } from './repository';
import { updateUseCase } from './useCaseBuilderRepository';

export const handler = async (
event: APIGatewayProxyEvent
Expand Down
Loading

0 comments on commit c24a17f

Please sign in to comment.