From 602b44871be9f496b54fdcce55f95fdb9322f375 Mon Sep 17 00:00:00 2001 From: Keisuke Minami Date: Sun, 9 Nov 2025 17:42:53 +0700 Subject: [PATCH 1/2] delete all talk history --- packages/cdk/lambda/repository.ts | 36 +++++++++++-------- .../web/public/locales/translation/en.yaml | 6 ++++ .../web/public/locales/translation/ja.yaml | 6 ++++ .../web/public/locales/translation/ko.yaml | 6 ++++ .../web/public/locales/translation/th.yaml | 6 ++++ .../web/public/locales/translation/vi.yaml | 6 ++++ .../web/public/locales/translation/zh.yaml | 6 ++++ .../DialogConfirmDeleteAllChats.tsx | 36 +++++++++++++++++++ packages/web/src/hooks/useChatApi.ts | 22 ++++++++++++ packages/web/src/hooks/useChatList.ts | 28 ++++++++++++++- packages/web/src/pages/Setting.tsx | 31 +++++++++++++++- 11 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 packages/web/src/components/DialogConfirmDeleteAllChats.tsx diff --git a/packages/cdk/lambda/repository.ts b/packages/cdk/lambda/repository.ts index f7b0e574e..9493da0ea 100644 --- a/packages/cdk/lambda/repository.ts +++ b/packages/cdk/lambda/repository.ts @@ -461,22 +461,28 @@ export const deleteChat = async ( // Delete Messages const messageItems = await listMessages(_chatId); - await dynamoDbDocument.send( - new BatchWriteCommand({ - RequestItems: { - [TABLE_NAME]: messageItems.map((m) => { - return { - DeleteRequest: { - Key: { - id: m.id, - createdDate: m.createdDate, + + // Split into chunks of 25 (DynamoDB BatchWrite limit) + const chunkSize = 25; + for (let i = 0; i < messageItems.length; i += chunkSize) { + const chunk = messageItems.slice(i, i + chunkSize); + await dynamoDbDocument.send( + new BatchWriteCommand({ + RequestItems: { + [TABLE_NAME]: chunk.map((m) => { + return { + DeleteRequest: { + Key: { + id: m.id, + createdDate: m.createdDate, + }, }, - }, - }; - }), - }, - }) - ); + }; + }), + }, + }) + ); + } }; export const updateSystemContextTitle = async ( diff --git a/packages/web/public/locales/translation/en.yaml b/packages/web/public/locales/translation/en.yaml index 5913519d5..9ca77c541 100644 --- a/packages/web/public/locales/translation/en.yaml +++ b/packages/web/public/locales/translation/en.yaml @@ -955,6 +955,12 @@ setting: please refer to <1>generative-ai-use-cases. items: agent_enabled: Agent Enabled + delete_all_chats: Delete All Conversation History + delete_all_chats_button: Delete All History + delete_all_chats_confirmation: Are you sure you want to delete all conversation history? This action cannot be undone. + delete_all_chats_deleting: Deleting... + delete_all_chats_failed: Failed to delete + delete_all_chats_success: All conversation history has been deleted language: Language language_help: Change display language line_break_enter: Press Enter to create new line diff --git a/packages/web/public/locales/translation/ja.yaml b/packages/web/public/locales/translation/ja.yaml index e805726ea..ecb8e83bf 100644 --- a/packages/web/public/locales/translation/ja.yaml +++ b/packages/web/public/locales/translation/ja.yaml @@ -781,6 +781,12 @@ setting: <1>generative-ai-use-cases をご参照ください。 items: agent_enabled: Agent 有効 + delete_all_chats: すべての会話履歴を削除 + delete_all_chats_button: 全会話履歴削除 + delete_all_chats_confirmation: すべての会話履歴を削除しますか?この操作は取り消すことができません。 + delete_all_chats_deleting: 削除中... + delete_all_chats_failed: 削除に失敗しました + delete_all_chats_success: すべての会話履歴を削除しました language: 言語設定 language_help: 表示言語を変更できます line_break_enter: Enter で改行 diff --git a/packages/web/public/locales/translation/ko.yaml b/packages/web/public/locales/translation/ko.yaml index fa8085479..1edcca5db 100644 --- a/packages/web/public/locales/translation/ko.yaml +++ b/packages/web/public/locales/translation/ko.yaml @@ -544,6 +544,12 @@ setting: <1>generative-ai-use-cases를 참조하세요. items: agent_enabled: 에이전트 활성화 + delete_all_chats: 모든 대화 기록 삭제 + delete_all_chats_button: 전체 대화 기록 삭제 + delete_all_chats_confirmation: 모든 대화 기록을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다. + delete_all_chats_deleting: 삭제 중... + delete_all_chats_failed: 삭제에 실패했습니다 + delete_all_chats_success: 모든 대화 기록이 삭제되었습니다 language: 언어 language_help: 표시 언어 변경 line_break_enter: Enter로 줄바꿈 diff --git a/packages/web/public/locales/translation/th.yaml b/packages/web/public/locales/translation/th.yaml index 24081da89..aa12ef406 100644 --- a/packages/web/public/locales/translation/th.yaml +++ b/packages/web/public/locales/translation/th.yaml @@ -689,6 +689,12 @@ setting: การตั้งค่าสามารถเปลี่ยนแปลงได้โดยใช้ <0>AWS CDK ไม่ใช่บนหน้าจอนี้ หากคุณพบข้อผิดพลาดเมื่อใช้ use cases โปรดตรวจสอบว่าคุณได้เปิดใช้งานโมเดลที่ระบุใน {{region}} สำหรับรายละเอียดเกี่ยวกับวิธีการทำเช่นนี้ โปรดดูที่ <1>generative-ai-use-cases items: agent_enabled: เปิดใช้งานตัวแทน + delete_all_chats: ลบประวัติการสนทนาทั้งหมด + delete_all_chats_button: ลบประวัติทั้งหมด + delete_all_chats_confirmation: คุณแน่ใจหรือไม่ว่าต้องการลบประวัติการสนทนาทั้งหมด? การกระทำนี้ไม่สามารถยกเลิกได้ + delete_all_chats_deleting: กำลังลบ... + delete_all_chats_failed: การลบล้มเหลว + delete_all_chats_success: ลบประวัติการสนทนาทั้งหมดแล้ว language: ภาษา language_help: เปลี่ยนภาษาที่แสดง line_break_enter: กด Enter เพื่อขึ้นบรรทัดใหม่ diff --git a/packages/web/public/locales/translation/vi.yaml b/packages/web/public/locales/translation/vi.yaml index 93eb56931..3d6c0117b 100644 --- a/packages/web/public/locales/translation/vi.yaml +++ b/packages/web/public/locales/translation/vi.yaml @@ -667,6 +667,12 @@ setting: <1>generative-ai-use-cases. items: agent_enabled: Agent được bật + delete_all_chats: Xóa tất cả lịch sử hội thoại + delete_all_chats_button: Xóa tất cả lịch sử + delete_all_chats_confirmation: Bạn có chắc chắn muốn xóa tất cả lịch sử hội thoại không? Hành động này không thể hoàn tác. + delete_all_chats_deleting: Đang xóa... + delete_all_chats_failed: Xóa thất bại + delete_all_chats_success: Đã xóa tất cả lịch sử hội thoại language: Cài đặt ngôn ngữ language_help: Có thể thay đổi ngôn ngữ hiển thị line_break_enter: Nhấn Enter để xuống dòng diff --git a/packages/web/public/locales/translation/zh.yaml b/packages/web/public/locales/translation/zh.yaml index 3b91e5780..9a0e9abb2 100644 --- a/packages/web/public/locales/translation/zh.yaml +++ b/packages/web/public/locales/translation/zh.yaml @@ -563,6 +563,12 @@ setting: 请务必确认您是否在{{region}}中启用了指定的模型。有关各种方法, 请参考<1>generative-ai-use-cases。 items: agent_enabled: Agent已启用 + delete_all_chats: 删除所有对话历史 + delete_all_chats_button: 删除全部历史 + delete_all_chats_confirmation: 您确定要删除所有对话历史吗?此操作无法撤消。 + delete_all_chats_deleting: 删除中... + delete_all_chats_failed: 删除失败 + delete_all_chats_success: 已删除所有对话历史 language: 语言设置 language_help: 可以更改显示语言 rag_enabled: RAG (Amazon Kendra)已启用 diff --git a/packages/web/src/components/DialogConfirmDeleteAllChats.tsx b/packages/web/src/components/DialogConfirmDeleteAllChats.tsx new file mode 100644 index 000000000..6860dfef6 --- /dev/null +++ b/packages/web/src/components/DialogConfirmDeleteAllChats.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { BaseProps } from '../@types/common'; +import Button from './Button'; +import ModalDialog from './ModalDialog'; +import { useTranslation } from 'react-i18next'; + +type Props = BaseProps & { + isOpen: boolean; + onDelete: () => void; + onClose: () => void; +}; + +const DialogConfirmDeleteAllChats: React.FC = (props) => { + const { t } = useTranslation(); + + return ( + +
{t('setting.items.delete_all_chats_confirmation')}
+ +
+ + +
+
+ ); +}; + +export default DialogConfirmDeleteAllChats; diff --git a/packages/web/src/hooks/useChatApi.ts b/packages/web/src/hooks/useChatApi.ts index 7273947ca..7511b9508 100644 --- a/packages/web/src/hooks/useChatApi.ts +++ b/packages/web/src/hooks/useChatApi.ts @@ -49,6 +49,28 @@ const useChatApi = () => { deleteChat: async (chatId: string) => { return http.delete(`chats/${chatId}`); }, + deleteAllChats: async (): Promise => { + let exclusiveStartKey: string | undefined = undefined; + let hasMore = true; + + while (hasMore) { + const url = exclusiveStartKey + ? `chats?exclusiveStartKey=${exclusiveStartKey}` + : 'chats'; + const res = await http.api.get(url); + const chats = res.data.data; + + // Delete all chats in this page + await Promise.all( + chats.map((chat) => + http.delete(`chats/${decomposeId(chat.chatId)}`) + ) + ); + + exclusiveStartKey = res.data.lastEvaluatedKey; + hasMore = !!exclusiveStartKey; + } + }, listChats: () => { const getKey = ( pageIndex: number, diff --git a/packages/web/src/hooks/useChatList.ts b/packages/web/src/hooks/useChatList.ts index d368d53bf..434de94c2 100644 --- a/packages/web/src/hooks/useChatList.ts +++ b/packages/web/src/hooks/useChatList.ts @@ -4,7 +4,12 @@ import { Chat } from 'generative-ai-use-cases'; import usePagination from './usePagination'; const useChatList = () => { - const { listChats, deleteChat: deleteChatApi, updateTitle } = useChatApi(); + const { + listChats, + deleteChat: deleteChatApi, + deleteAllChats: deleteAllChatsApi, + updateTitle, + } = useChatApi(); const { data, flattenData: chats, @@ -40,6 +45,26 @@ const useChatList = () => { }); }; + const deleteAllChats = async () => { + // Clear all chats from cache optimistically + mutate( + produce(data, (draft) => { + if (data && draft) { + for (const d in data) { + draft[d].data = []; + } + } + }), + { + revalidate: false, + } + ); + + return deleteAllChatsApi().finally(() => { + mutate(); + }); + }; + const updateChatTitle = async (chatId: string, title: string) => { mutate( produce(data, (draft) => { @@ -83,6 +108,7 @@ const useChatList = () => { mutate, updateChatTitle, deleteChat, + deleteAllChats, getChatTitle, canLoadMore, loadMore, diff --git a/packages/web/src/pages/Setting.tsx b/packages/web/src/pages/Setting.tsx index 0bf348401..9abf603b9 100644 --- a/packages/web/src/pages/Setting.tsx +++ b/packages/web/src/pages/Setting.tsx @@ -9,10 +9,12 @@ import { MODELS } from '../hooks/useModel'; import useGitHub, { PullRequest } from '../hooks/useGitHub'; import { PiGithubLogoFill, PiArrowSquareOut } from 'react-icons/pi'; import { useAuthenticator } from '@aws-amplify/ui-react'; -import { useCallback } from 'react'; +import { useCallback, useState } from 'react'; import { useSWRConfig } from 'swr'; import { useTranslation, Trans } from 'react-i18next'; import { supportedLngs } from '../i18n/config'; +import useChatList from '../hooks/useChatList'; +import DialogConfirmDeleteAllChats from '../components/DialogConfirmDeleteAllChats'; const ragEnabled: boolean = import.meta.env.VITE_APP_RAG_ENABLED === 'true'; const ragKnowledgeBaseEnabled: boolean = @@ -52,6 +54,8 @@ const Setting = () => { const { getClosedPullRequests } = useGitHub(); const { signOut } = useAuthenticator(); const { i18n, t } = useTranslation(); + const { deleteAllChats } = useChatList(); + const [isDeleteAllDialogOpen, setIsDeleteAllDialogOpen] = useState(false); const localVersion = getLocalVersion(); const hasUpdate = getHasUpdate(); @@ -77,6 +81,15 @@ const Setting = () => { signOut(); }, [cache, signOut]); + const onClickDeleteAllChats = useCallback(async () => { + try { + await deleteAllChats(); + setIsDeleteAllDialogOpen(false); + } catch (error) { + console.error('Failed to delete all chats:', error); + } + }, [deleteAllChats]); + return (
{hasUpdate && ( @@ -169,6 +182,16 @@ const Setting = () => { /> }> + setIsDeleteAllDialogOpen(true)} + className="bg-red-500 text-white"> + {t('setting.items.delete_all_chats_button')} + + }> + {
+ + setIsDeleteAllDialogOpen(false)} + /> ); }; From c946e3dc3e0079ad11992c7f6584717e0bfc54b9 Mon Sep 17 00:00:00 2001 From: Keisuke Minami Date: Sun, 9 Nov 2025 22:45:06 +0700 Subject: [PATCH 2/2] fix lint --- packages/web/src/hooks/useChatApi.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/web/src/hooks/useChatApi.ts b/packages/web/src/hooks/useChatApi.ts index 7511b9508..2a8e83f63 100644 --- a/packages/web/src/hooks/useChatApi.ts +++ b/packages/web/src/hooks/useChatApi.ts @@ -18,6 +18,7 @@ import { CreateShareIdResponse, FindShareIdResponse, GetSharedChatResponse, + Chat, } from 'generative-ai-use-cases'; import { LambdaClient, @@ -54,15 +55,16 @@ const useChatApi = () => { let hasMore = true; while (hasMore) { - const url = exclusiveStartKey + const url: string = exclusiveStartKey ? `chats?exclusiveStartKey=${exclusiveStartKey}` : 'chats'; - const res = await http.api.get(url); + const res: AxiosResponse = + await http.api.get(url); const chats = res.data.data; // Delete all chats in this page await Promise.all( - chats.map((chat) => + chats.map((chat: Chat) => http.delete(`chats/${decomposeId(chat.chatId)}`) ) );