diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 367784c5acf..d8ef6fab656 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -48,7 +48,11 @@ import Locale, { changeLang, getLang, } from "../locales"; -import { copyToClipboard } from "../utils"; +import { + copyToClipboard, + downloadAs, + readFromFile, +} from "../utils"; import Link from "next/link"; import { Azure, @@ -569,6 +573,154 @@ function SyncConfigModal(props: { onClose?: () => void }) { ); } +/** + * Manage Local Data + * Author : @H0llyW00dzZ + * WIP + **/ + +function LocalDataModal(props: { onClose?: () => void }) { + const syncStore = useSyncStore(); + const [showLocalData, setShowLocalData] = useState(false); + const [exporting, setExporting] = useState(false); + const chatStore = useChatStore(); + const promptStore = usePromptStore(); + const maskStore = useMaskStore(); + const stateOverview = useMemo(() => { + const sessions = chatStore.sessions; + const messageCount = sessions.reduce((p, c) => p + c.messages.length, 0); + + return { + chat: sessions.length, + message: messageCount, + prompt: Object.keys(promptStore.prompts).length, + mask: Object.keys(maskStore.masks).length, + }; + }, [chatStore.sessions, maskStore.masks, promptStore.prompts]); + + const handleExportChat = async () => { + if (exporting) return; + setExporting(true); + const currentDate = new Date(); + const sessions = chatStore.sessions; + const totalMessageCount = sessions.reduce((count, session) => count + session.messages.length, 0); + const datePart = getClientConfig()?.isApp + ? `${currentDate.toLocaleDateString().replace(/\//g, '_')} ${currentDate.toLocaleTimeString().replace(/:/g, '_')}` + : `${currentDate.toLocaleString().replace(/:/g, '_')}`; + const formattedMessageCount = Locale.ChatItem.ChatItemCount(totalMessageCount); + const fileName = `(${formattedMessageCount})-${datePart}.json`; + await downloadAs(sessions, fileName); + setExporting(false); + }; + const handleImportChat = async () => { + if (exporting) return; + setExporting(true); + try { + const rawContent = await readFromFile(); // Read the file content using the appropriate function + + const importedData = JSON.parse(rawContent); + // Process the imported chat data and update the chat store + chatStore.newSession(importedData.sessions); + } catch (e) { + showToast(Locale.Settings.Sync.ImportFailed); + console.error(e); + } + setExporting(false); + }; + + return ( +
+ props.onClose?.()} + actions={[ + , + } + bordered + text={Locale.UI.Confirm} + />, + ]} + > + + +
+ } + text={Locale.UI.Export} + onClick={handleExportChat} + /> + } + text={Locale.UI.Import} + onClick={handleImportChat} + /> + } + text={Locale.Settings.Danger.Clear.Action} + onClick={async () => { + if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) { + chatStore.clearChatData(); + } + }} + /> +
+
+ +
+ } + text={Locale.UI.Export} + onClick={() => { + showToast(Locale.WIP); + }} + /> + } + text={Locale.UI.Import} + onClick={() => { + showToast(Locale.WIP); + }} + /> +
+
+ +
+ } + text={Locale.UI.Export} + onClick={() => { + showToast(Locale.WIP); + }} + /> + } + text={Locale.UI.Import} + onClick={() => { + showToast(Locale.WIP); + }} + /> +
+
+
+ {showLocalData && ( + setShowLocalData(false)} /> + )} +
+
+ ); +} function SyncItems() { const syncStore = useSyncStore(); @@ -580,6 +732,7 @@ function SyncItems() { }, [syncStore]); const [showSyncConfigModal, setShowSyncConfigModal] = useState(false); + const [showLocalData, setShowLocalData] = useState(false); const stateOverview = useMemo(() => { const sessions = chatStore.sessions; @@ -637,6 +790,13 @@ function SyncItems() { subTitle={Locale.Settings.Sync.Overview(stateOverview)} >
+ } + text={Locale.UI.Manage} + onClick={() => { + setShowLocalData(true); + }} + /> } text={Locale.UI.Export} @@ -658,6 +818,10 @@ function SyncItems() { {showSyncConfigModal && ( setShowSyncConfigModal(false)} /> )} + + {showLocalData && ( + setShowLocalData(false)} /> + )} ); } diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 7378f05fbcf..19974231b23 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -287,6 +287,23 @@ const cn = { Overview: (overview: any) => { return `${overview.chat} 次对话,${overview.message} 条消息,${overview.prompt} 条提示词,${overview.mask} 个面具`; }, + Description: { + Chat: (overview: any) => { + const title = "次对话"; + const description = `${overview.chat} 次对话,, ${overview.message} 条消息`; + return { title, description }; + }, + Prompt: (overview: any) => { + const title = "条提示词"; + const description = `${overview.prompt} 条提示词`; + return { title, description }; + }, + Masks: (overview: any) => { + const title = "个面具"; + const description = `${overview.mask} 个面具`; + return { title, description }; + }, + }, ImportFailed: "导入失败", }, Mask: { @@ -530,6 +547,7 @@ const cn = { Import: "导入", Sync: "同步", Config: "配置", + Manage: "管理", }, Exporter: { Model: "模型", diff --git a/app/locales/en.ts b/app/locales/en.ts index 8714c5bcb79..1df0dc08c50 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -292,6 +292,23 @@ const en: LocaleType = { Overview: (overview: any) => { return `${overview.chat} chats,${overview.message} messages,${overview.prompt} prompts,${overview.mask} masks`; }, + Description: { + Chat: (overview: any) => { + const title = "Chats"; + const description = `${overview.chat} chats, ${overview.message} messages`; + return { title, description }; + }, + Prompt: (overview: any) => { + const title = "Prompts"; + const description = `${overview.prompt} prompts`; + return { title, description }; + }, + Masks: (overview: any) => { + const title = "Masks"; + const description = `${overview.mask} masks`; + return { title, description }; + }, + }, ImportFailed: "Failed to import from file", }, Mask: { @@ -533,6 +550,7 @@ const en: LocaleType = { Import: "Import", Sync: "Sync", Config: "Config", + Manage: "Manage", }, Exporter: { Model: "Model", diff --git a/app/locales/id.ts b/app/locales/id.ts index ce8fb986aff..9352294dcee 100644 --- a/app/locales/id.ts +++ b/app/locales/id.ts @@ -263,6 +263,28 @@ const id: PartialLocaleType = { }, }, }, + LocalState: "Data Lokal", + Overview: (overview: any) => { + return `${overview.chat} percakapan, ${overview.message} pesan, ${overview.prompt} prompt, ${overview.mask} masks`; + }, + Description: { + Chat: (overview: any) => { + const title = "Percakapan"; + const description = `${overview.chat} percakapan, ${overview.message} pesan`; + return { title, description }; + }, + Prompt: (overview: any) => { + const title = "Prompts"; + const description = `${overview.prompt} Prompts`; + return { title, description }; + }, + Masks: (overview: any) => { + const title = "Masks"; + const description = `${overview.mask} masks`; + return { title, description }; + }, + }, + ImportFailed: "Gagal mengimpor dari file", }, SendKey: "Kirim", Theme: "Tema", @@ -456,6 +478,7 @@ const id: PartialLocaleType = { Close: "Tutup", Create: "Buat", Edit: "Edit", + Manage: "Kelola", }, Exporter: { Model: "Model", diff --git a/app/store/chat.ts b/app/store/chat.ts index c38054ad8ce..f4003f6fae3 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -583,6 +583,13 @@ export const useChatStore = createPersistStore( set(() => ({ sessions })); }, + clearChatData() { + set(() => ({ + sessions: [createEmptySession()], + currentSessionIndex: 0, + })); + }, + clearAllData() { localStorage.clear(); location.reload();